aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--angular-minified.js198
-rw-r--r--angular.js4140
-rw-r--r--src/Binder.js595
-rw-r--r--src/ControlBar.js106
-rw-r--r--src/DataStore.js604
-rw-r--r--src/Filters.js2
-rw-r--r--src/JSON.js10
-rw-r--r--src/Loader.js4
-rw-r--r--src/Model.js82
-rw-r--r--src/Parser.js1292
-rw-r--r--src/Scope.js295
-rw-r--r--src/Server.js44
-rw-r--r--src/Users.js11
-rw-r--r--src/Validators.js2
-rw-r--r--src/Widgets.js972
-rw-r--r--src/angular-bootstrap.js25
-rw-r--r--src/angular.prefix23
-rw-r--r--test/DataStoreTest.js3
18 files changed, 4261 insertions, 4147 deletions
diff --git a/angular-minified.js b/angular-minified.js
index 9b4eec6e..2c702b48 100644
--- a/angular-minified.js
+++ b/angular-minified.js
@@ -1,99 +1,99 @@
-function p(){return function(){}}function A(n){return function(r){this[n]=r}}function E(n){return function(){return n}}
-(function(n,r){function x(){}function M(a,b){var c=r.createElement("div");c.className=a;for(var d=a="",e=0;e<b.length;e++){var f=b[e];a+=d+(typeof f=="string"?f:toJson(f));d=" "}c.appendChild(r.createTextNode(a));F.appendChild(c)}function N(a){switch(a.nodeName){case "OPTION":case "PRE":case "TITLE":return true;default:return false}}function O(a,b){if(N(a))if(G)a.innerText=b;else a.textContent=b;else a.innerHTML=b}function C(a){if(!a||!a.replace)return a;return a.replace(/&/g,"&amp;").replace(/</g,
-"&lt;").replace(/>/g,"&gt;")}function X(a){if(!a||!a.replace)return a;return a.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\"/g,"&quot;")}function P(a,b){if(!a)throw"Missing this";if(!_.isFunction(b))throw"Missing function";return function(){return b.apply(a,arguments)}}function Y(a,b){return function(){for(var c=[this],d=0;d<arguments.length;d++)c.push(arguments[d]);return b.apply(a,c)}}function Q(a){var b=r.createElement("div");b.appendChild(a);var c=b.innerHTML;b.removeChild(a);return c}
-function R(a){var b=(""+a).toLowerCase();if(b=="f"||b=="0"||b=="false"||b=="no")a=false;return!!a}function S(a,b){for(var c in a){var d=b[c],e=typeof d;if(e=="undefined")b[c]=fromJson(toJson(a[c]));else e=="object"&&d.constructor!=array&&c.substring(0,1)!="$"&&S(a[c],d)}}function T(a,b,c){this.document=i(a);this.head=i(b);this.i=c;this.location=n.location}function U(a){this.location=a;this.delay=25;this.setTimeout=function(b,c){n.setTimeout(b,c)};this.Ua=function(b){return b};this.N=a.href}var H=
-{u:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",Tb:function(a){var b="",c,d,e,f,g,h,j=0;for(a=H.yb(a);j<a.length;){c=a.charCodeAt(j++);d=a.charCodeAt(j++);e=a.charCodeAt(j++);f=c>>2;c=(c&3)<<4|d>>4;g=(d&15)<<2|e>>6;h=e&63;if(isNaN(d))g=h=64;else if(isNaN(e))h=64;b=b+this.u.charAt(f)+this.u.charAt(c)+this.u.charAt(g)+this.u.charAt(h)}return b},sd:function(a){var b="",c,d,e,f,g,h=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");h<a.length;){c=this.u.indexOf(a.charAt(h++));d=this.u.indexOf(a.charAt(h++));
-f=this.u.indexOf(a.charAt(h++));g=this.u.indexOf(a.charAt(h++));c=c<<2|d>>4;d=(d&15)<<4|f>>2;e=(f&3)<<6|g;b+=String.fromCharCode(c);if(f!=64)b+=String.fromCharCode(d);if(g!=64)b+=String.fromCharCode(e)}return b=H.xb(b)},yb:function(a){a=a.replace(/\r\n/g,"\n");for(var b="",c=0;c<a.length;c++){var d=a.charCodeAt(c);if(d<128)b+=String.fromCharCode(d);else{if(d>127&&d<2048)b+=String.fromCharCode(d>>6|192);else{b+=String.fromCharCode(d>>12|224);b+=String.fromCharCode(d>>6&63|128)}b+=String.fromCharCode(d&
-63|128)}}return b},xb:function(a){for(var b="",c=0,d=c1=c2=0;c<a.length;){d=a.charCodeAt(c);if(d<128){b+=String.fromCharCode(d);c++}else if(d>191&&d<224){c2=a.charCodeAt(c+1);b+=String.fromCharCode((d&31)<<6|c2&63);c+=2}else{c2=a.charCodeAt(c+1);c3=a.charCodeAt(c+2);b+=String.fromCharCode((d&15)<<12|(c2&63)<<6|c3&63);c+=3}}return b}};if(typeof r.getAttribute=="undefined")r.getAttribute=p();if(typeof Node=="undefined")Node={ELEMENT_NODE:1,ATTRIBUTE_NODE:2,TEXT_NODE:3,CDATA_SECTION_NODE:4,ENTITY_REFERENCE_NODE:5,
-ENTITY_NODE:6,PROCESSING_INSTRUCTION_NODE:7,COMMENT_NODE:8,DOCUMENT_NODE:9,DOCUMENT_TYPE_NODE:10,DOCUMENT_FRAGMENT_NODE:11,NOTATION_NODE:12};var F,o=_.each,V=_.extend,I=n.console||{log:x,error:x},i=n.jQuery,G=i.browser.msie;function q(){I.log.apply(this,arguments)}function J(){I.error.apply(this,arguments)}var m=n.angular||(n.angular={}),W=m.validator||(m.validator={}),s=m.filter||(m.filter={}),K=m.callbacks||(m.callbacks={});m.alert||(m.alert=function(){q(arguments);n.alert.apply(n,arguments)});
-T.prototype={load:function(){this.Lb();this.Wa("/stylesheets/jquery-ui/smoothness/jquery-ui-1.7.1.css");this.Wa("/stylesheets/css");q("Server: "+this.i.z);this.Kb();this.Jb();this.Gb()},Kb:function(){q("Loader.configureJQueryPlugins()");i.fn.scope=function(){for(var a=this;a&&a.get(0);){var b=a.data("scope");if(b)return b;a=a.parent()}return null};i.fn.controller=function(){return this.data("controller")||NullController.cc}},Kc:function(){return""+(new Date).getTime()},Jb:function(){var a=this.i;
-if(!a.G){var b=a.z.match(/https?:\/\/([\w]*)/);a.G=b?b[1]:"$MEMORY"}},Gb:function(){function a(){g.Ma(function(l){!l&&c.find("[ng-auth=eager]").length&&g.ba()})}q("Loader.bindHtml()");var b=new U(this.location),c=this.document,d=new WidgetFactory(this.i.z,this.i.G),e=new Binder(c[0],d,b,this.i);d.wc=Y(e,e.e);d=new ControlBar(c.find("body"),this.i.z);var f=this.i.G=="$MEMORY"?new FrameServer(this.window):new Server(this.i.z,i.getScript);f=new VisualServer(f,new Status(i(c.body)),function(){e.c()});
-var g=new Users(f,d),h="/data/"+this.i.G,j=new DataStore(function(l,y){f.P("POST",h,l,y)},g,e.anchor);e.lb.push(function(){j.Oa()});var k=new Scope({$anchor:e.anchor,$binder:e,$config:this.i,$console:n.console,$datastore:j,$save:function(l){j.Ec(k.s,l,e.anchor)},$window:n,$uid:this.Kc,$users:g},"ROOT");c.data("scope",k);q("$binder.entity()");e.M(k);q("$binder.compile()");e.compile();q("ControlBar.bind()");d.bind();q("$users.fetchCurrentUser()");a();q("PopUp.bind()");(new PopUp(c)).bind();q("$binder.parseAnchor()");
-e.db();q("$binder.executeInit()");e.Xb();q("$binder.updateView()");e.c();b.Ua=P(e,e.yc,b);b.zd=function(){alert("update")};b.watch();c.find("body").show();q("ready()")},Lb:function(){var a=n.location.href+"#";a=a.split("#")[1];var b={Qb:null};a=a.split("&");for(var c=0;c<a.length;c++){var d=(a[c]+"=").split("=");b[d[0]]=d[1]}if(b.Qb=="console"){F=r.createElement("div");F.id="ng-console";r.getElementsByTagName("body")[0].appendChild(F);q=function(){M("ng-console-info",arguments)};I.error=function(){M("ng-console-error",
-arguments)}}},Wa:function(a){var b=r.createElement("link");b.rel="stylesheet";b.type="text/css";a.match(/^http:/)||(a=this.i.z+a);b.href=a;this.head[0].appendChild(b)}};U.prototype={watch:function(){var a=this;function b(){if(a.N!==a.location.href){var c=a.location.hash.match(/^#\$iframe_notify=(.*)$/);if(c){a.N.match(/#/)||(a.N+="#");a.location.href=a.N;c="_iframe_notify_"+c[1];var d=K[c];delete K[c];try{(d||x)()}catch(e){alert(e)}}else{a.Ua(a.location.href);a.N=a.location.href}}a.setTimeout(b,a.delay)}
-b()},Hc:function(a){var b=n.location.href;b.match(/#/)||(b+="#");if(b!=a)n.location.href=a;this.ud=a},Qa:function(){return n.location.href}};m.compile=function(a,b){b=b||{};(new T(a,i("head"),_({z:""}).extend(b))).load();var c=i(a).scope();return{updateView:function(){return c.c.apply(c,arguments)},set:function(){return c.j.apply(c,arguments)},get:function(){return c.get.apply(c,arguments)}}};var D={typeOf:function(a){if(a===null)return"null";var b=typeof a;if(b=="object"){if(a instanceof Array)return"array";
-if(a instanceof Date)return"date";if(a.nodeType==1)return"element"}return b}},L={};(function(){function a(b,c,d){o(c,function(e){V(m[b],e)});o(d,function(e){m[b][e]=_[e]})}a("Global",[D],["extend","clone","isEqual","isElement","isArray","isFunction","isUndefined"]);a("Collection",[D,L],["each","map","reduce","reduceRight","detect","select","reject","all","any","include","invoke","pluck","max","min","sortBy","sortedIndex","toArray","size"]);a("Array",[D,L],["first","last","compact","flatten","without",
-"uniq","intersect","zip","indexOf","lastIndexOf"]);a("Object",[D,L],["keys","values"]);a("String",[D]);a("Function",[D],["bind","bindAll","delay","defer","wrap","compose"])})();Binder=function(a,b,c,d){this.B=a;this.va=c;this.anchor={};this.Rc=b;this.i=d||{};this.lb=[]};Binder.da=function(a){for(var b=[],c=0,d;(d=a.indexOf("{{",c))>-1;){c<d&&b.push(a.substr(c,d-c));c=d;d=a.indexOf("}}",d);d=d<0?a.length:d+2;b.push(a.substr(c,d-c));c=d}c!=a.length&&b.push(a.substr(c,a.length-c));return b.length===
-0?[a]:b};Binder.bc=function(a){a=Binder.da(a);return a.length>1||Binder.L(a[0])!==null};Binder.L=function(a){return(a=a.replace(/\n/gm," ").match(/^\{\{(.*)\}\}$/))?a[1]:null};Binder.prototype.zc=function(a){var b={};a.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,function(c,d,e){if(d)b[decodeURIComponent(d)]=decodeURIComponent(e)});return b};Binder.prototype.db=function(a){var b=this;a=a||this.va.Qa();var c=a.indexOf("#");if(!(c<0)){a=this.zc(a.substring(c+1));o(b.anchor,function(d,e){delete b.anchor[e]});
-o(a,function(d,e){b.anchor[e]=d})}};Binder.prototype.yc=function(a){q("URL change detected",a);this.db(a);this.c()};Binder.prototype.Lc=function(){var a=this.va.Qa(),b=a.indexOf("#");if(b>-1)a=a.substring(0,b);a+="#";b="";for(var c in this.anchor){var d=this.anchor[c];if(typeof d==="undefined"||d===null)delete this.anchor[c];else{a+=b+encodeURIComponent(c);if(d!==true)a+="="+encodeURIComponent(d);b="&"}}this.va.Hc(a);return a};Binder.prototype.c=function(){(new Date).getTime();var a=i(this.B).scope();
-a.j("$invalidWidgets",[]);a.c();(new Date).getTime();this.Lc();_.each(this.lb,function(b){b()})};Binder.prototype.W=function(a){var b=i(this.B),c=b.find(a);if(b.is(a))c=c.andSelf();return c};Binder.prototype.Xb=function(){this.W("[ng-init]").each(function(){var a=i(this),b=a.scope();try{b.eval(a.attr("ng-init"))}catch(c){alert("EVAL ERROR:\n"+a.attr("ng-init")+"\n"+toJson(c,true))}})};Binder.prototype.M=function(a){this.W("[ng-entity]").attr("ng-watch",function(){try{var b=i(this);return a.M(b.attr("ng-entity"))+
-(b.attr("ng-watch")||"")}catch(c){alert(c)}})};Binder.prototype.compile=function(){var a=i(this.B),b=this;if(this.i.$c){var c=this.W(":submit").not("[ng-action]");c.attr("ng-action","$save()");c.not(":disabled").not("ng-bind-attr").attr("ng-bind-attr",'{disabled:"{{$invalidWidgets}}"}')}this.eb(this.B)(this.B,a.scope(),"");this.W("a[ng-action]").live("click",function(){var d=i(this);try{d.scope().eval(d.attr("ng-action"));d.removeAttr("ng-error");d.removeClass("ng-exception")}catch(e){d.addClass("ng-exception");
-d.attr("ng-error",toJson(e,true))}b.c();return false})};Binder.prototype.Jc=function(a,b,c){b=b.concat();var d=b.pop(),e=Binder.da(a.nodeValue);if(e.length>1||Binder.L(e[0])){var f=a.parentNode;if(N(f)){f.setAttribute("ng-bind-template",a.nodeValue);c.push({path:b,b:function(l){return new BindUpdater(l,l.getAttribute("ng-bind-template"))}})}else for(var g=0;g<e.length;g++){var h=e[g],j=Binder.L(h),k;if(j){k=r.createElement("span");i(k).attr("ng-bind",j);g===0&&c.push({path:b.concat(d+g),b:Binder.prototype.cb})}else if(G&&
-h.charAt(0)==" "){k=r.createElement("span");k.innerHTML="&nbsp;"+h.substring(1)}else k=r.createTextNode(h);f.insertBefore(k,a)}f.removeChild(a)}};Binder.prototype.eb=function(a){var b=[];this.fb(a,[],b);return function(c,d,e){for(var f=b.length,g=0;g<f;g++){for(var h=b[g],j=c,k=h.path,l=0;l<k.length;l++)j=j.childNodes[k[l]];try{d.Bb(h.b(j,d,e))}catch(y){alert(y)}}}};Binder.prototype.fb=function(a,b,c){var d=a.nodeType;if(d==Node.TEXT_NODE)this.Jc(a,b,c);else if(!(d!=Node.ELEMENT_NODE&&d!=Node.DOCUMENT_NODE))if(a.getAttribute){d=
-a.getAttribute("ng-non-bindable");if(!(d||d==="")){if(d=a.attributes){var e=a.getAttribute("ng-bind-attr");a.removeAttribute("ng-bind-attr");e=e?fromJson(e):{};for(var f=d.length,g=0;g<f;g++){var h=d[g],j=h.name;h=G&&j=="href"?decodeURI(a.getAttribute(j,2)):h.value;if(Binder.bc(h))e[j]=h}d=toJson(e);d.length>2&&a.setAttribute("ng-bind-attr",d)}a.getAttribute||q(a);var k=a.getAttribute("ng-repeat");if(k){a.removeAttribute("ng-repeat");var l=this.eb(a);d=r.createComment("ng-repeat: "+k);e=a.parentNode;
-e.insertBefore(d,a);e.removeChild(a);var y=function(t,u,w){var B=i(a).clone();B.css("display","");B.attr("ng-repeat-index",""+w);B.data("scope",t);l(B[0],t,u+w+":");return B};c.push({path:b,b:function(t,u,w){return new RepeaterUpdater(i(t),k,y,w)}})}else{a.getAttribute("ng-eval")&&c.push({path:b,b:this.qc});a.getAttribute("ng-bind")&&c.push({path:b,b:this.cb});a.getAttribute("ng-bind-attr")&&c.push({path:b,b:this.mc});a.getAttribute("ng-hide")&&c.push({path:b,b:this.rc});a.getAttribute("ng-show")&&
-c.push({path:b,b:this.sc});a.getAttribute("ng-class")&&c.push({path:b,b:this.nc});a.getAttribute("ng-class-odd")&&c.push({path:b,b:this.pc});a.getAttribute("ng-class-even")&&c.push({path:b,b:this.oc});a.getAttribute("ng-style")&&c.push({path:b,b:this.tc});a.getAttribute("ng-watch")&&c.push({path:b,b:this.uc});d=a.nodeName;if(d=="INPUT"||d=="TEXTAREA"||d=="SELECT"||d=="BUTTON"){var z=this;c.push({path:b,b:function(t,u,w){t.name=w+t.name.split(":").pop();return z.Rc.Mb(i(t),u)}})}if(d=="OPTION")if(!i("<select/>").append(i(a).clone()).html().match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi))a.value=
-a.text;d=a.childNodes;for(e=0;e<d.length;e++)this.fb(d[e],b.concat(e),c)}}}};Binder.prototype.qc=function(a){return new EvalUpdater(a,a.getAttribute("ng-eval"))};Binder.prototype.cb=function(a){return new BindUpdater(a,"{{"+a.getAttribute("ng-bind")+"}}")};Binder.prototype.mc=function(a){return new BindAttrUpdater(a,fromJson(a.getAttribute("ng-bind-attr")))};Binder.prototype.rc=function(a){return new HideUpdater(a,a.getAttribute("ng-hide"))};Binder.prototype.sc=function(a){return new ShowUpdater(a,
-a.getAttribute("ng-show"))};Binder.prototype.nc=function(a){return new ClassUpdater(a,a.getAttribute("ng-class"))};Binder.prototype.oc=function(a){return new ClassEvenUpdater(a,a.getAttribute("ng-class-even"))};Binder.prototype.pc=function(a){return new ClassOddUpdater(a,a.getAttribute("ng-class-odd"))};Binder.prototype.tc=function(a){return new StyleUpdater(a,a.getAttribute("ng-style"))};Binder.prototype.uc=function(a,b){b.watch(a.getAttribute("ng-watch"))};ControlBar=function(a,b){this.document=
-a;this.ha=b;this.window=n;this.F=[]};ControlBar.prototype.bind=p();ControlBar.Wc='<div><div class="ui-widget-overlay"></div><div id="ng-login" ng-non-bindable="true"><div class="ng-login-container"></div></div></div>';ControlBar.prototype.ba=function(a){this.F.push(a);this.F.length==1&&this.Ka("/user_session/new.mini?return_url="+encodeURIComponent(this.mb()))};ControlBar.prototype.ab=function(a){this.F.push(a);this.F.length==1&&this.Ka("/user_session/do_destroy.mini")};ControlBar.prototype.mb=function(){return this.window.location.href.split("#")[0]};
-ControlBar.prototype.Ka=function(a){var b=this,c=(new Date).getTime(),d=this.mb();d+="#$iframe_notify="+c;var e=i('<div style="overflow:hidden; padding:2px 0 0 0;"><iframe name="'+d+'" src="'+this.ha+a+'" width="500" height="330"/></div>');this.document.append(e);e.Ja({height:363,width:500,Fd:false,jc:true,title:'Authentication: <a href="http://www.getangular.com"><tt>&lt;angular/&gt;</tt></a>'});callbacks["_iframe_notify_"+c]=function(){e.Ja("destroy");e.remove();o(b.F,function(f){f()});b.F=[]}};
-ControlBar.ub='<div ng-non-bindable="true" title="Permission Error:">Sorry, you do not have permission for this!</div>';ControlBar.prototype.ra=function(){if(!this.Pa){this.Pa=i(ControlBar.ub);this.Pa.Ja({ed:true,height:70,jc:true})}};DataStore=function(a,b,c){this.post=a;this.nb=b;this.A={S:[]};this.anchor=c;this.U=[]};DataStore.prototype.V=function(a){if(a.constructor!=Model)throw"Parameter must be an instance of Entity! "+toJson(a);var b=a.T+"/"+a.C,c=this.A[b];if(c)Model.la(a,c);else c=this.A[b]=
-a;return c};DataStore.prototype.load=function(a,b,c,d){if(b&&b!=="*"){var e=this;this.D(["GET",a.T+"/"+b],function(f){a.I(f);a.za();f=a.R(a);e.V(f);(c||x)(a)},d)}return a};DataStore.prototype.oa=function(a,b,c){var d=this,e=[],f=0;o(b,function(g){e.push(d.load(a(),g,function(){f++;if(f==b.length)(c||x)(e)}))});return e};DataStore.prototype.Xa=function(a,b,c){return this.load(a,b,c,function(d){if(d.ja==404){a.C=b;(c||x)(a)}else throw d;})};DataStore.prototype.hc=function(a,b){var c=this,d=[];d.xa=
-function(e){return e.T==a.title};this.A.S.push(d);this.D(["GET",a.title],function(e){for(var f=0;f<e.length;f++){var g=a();g.I(e[f]);d.push(c.V(g))}(b||x)(d)});return d};DataStore.prototype.save=function(a,b){var c=this,d={};a.Aa(d);this.D(["POST","",d],function(e){a.I(e);var f=c.V(a);_.each(c.A.S,function(g){g.xa(a)&&m.Array.includeIf(g,f,true)});if(a.ya)c.anchor[a.ya]=a.C;b&&b(a)})};DataStore.prototype.remove=function(a,b){var c=this,d={};a.Aa(d);this.D(["DELETE","",d],function(e){delete c.A[a.T+
-"/"+a.C];_.each(c.A.S,function(f){for(var g=0;g<f.length;g++)f[g].C==a.C&&f.splice(g,1)});(b||x)(e)})};DataStore.prototype.D=function(a,b,c){a.pb=b;a.rb=c||function(d){throw d;};this.U.push(a)};DataStore.prototype.Oa=function(){function a(d,e){q("RESPONSE["+d+"]: ",e);if(e.ja==401)b.nb.ba(function(){b.post(c,a)});else if(e.ja)alert(toJson(e));else for(var f=0;f<e.length;f++){var g=e[f],h=c[f];if(d=g.ja)d==403?b.nb.ra():h.rb(g);else h.pb(g)}}if(this.U.length!==0){var b=this,c=this.U;this.U=[];q("REQUEST:",
-c);this.post(c,a)}};DataStore.prototype.Ec=function(a,b){function c(){d--;d===0&&b&&b()}var d=1;for(var e in a){var f=a[e];if(f&&f.ia==Model.prototype.ia){d++;f.ia(c)}}c()};DataStore.prototype.O=function(a,b,c,d){var e=this,f=[];f.xa=E(false);this.A.S.push(f);this.D(["GET",a.title+"/"+b+"="+c],function(g){for(var h=0;h<g.length;h++){var j=(new a).I(g[h]);f.push(e.V(j))}d&&d(f)});return f};DataStore.J=p();DataStore.J.all=function(){return[]};DataStore.J.O=function(){return[]};DataStore.J.load=function(){return{}};
-DataStore.J.title=undefined;DataStore.prototype.M=function(a,b){if(!a)return DataStore.J;var c=this;function d(e){return new Model(d,e)}d.title=a;d.qb=true;d.Ia=this;d.Rb=b||{};d.load=function(e,f){return c.load(d(),e,f)};d.oa=function(e,f){return c.oa(d,e,f)};d.Xa=function(e,f){return c.Xa(d(),e,f)};d.all=function(e){return c.hc(d,e)};d.O=function(e,f,g){return c.O(d,e,f,g)};d.Ed=function(e){c.D(["GET",a+"/$properties"],e)};return d};DataStore.prototype.join=function(a){function b(){throw"Joined entities can not be instantiated into a document.";
-}var c=_(a).fd().map(function(d,e){return e}).sortBy(function(d){var e=[];do{if(_(e).include(d))throw"Infinite loop in join: "+e.join(" -> ");e.push(d);if(!a[d])throw _("Named entity '<%=name%>' is undefined.").template({name:d});d=a[d].ca?a[d].ca.substring(0,a[d].ca.indexOf(".")):undefined}while(d);return e.length}).value();if(_(c).select(function(d){return a[d].ca}).length!=c.length-1)throw"Exactly one entity needs to be primary.";b.O=function(d,e){var f=[],g=d?d.substring(0,d.indexOf(".")):undefined;
-if(g!=c[0])throw _("Named entity '<%=name%>' is not a primary entity.").template({name:g});var h=1;a[g].join.O(d.substring(d.indexOf(".")+1),e,function(j){var k=c[h++],l=a[k],y=l.ca,z={};_(j).each(function(t){var u={};f.push(u);u[g]=t;t=Scope.Y(u,y);z[t]=t});l.join.oa(_.toArray(z),function(t){var u={};_(t).each(function(w){u[w.C]=w});_(f).each(function(w){var B=Scope.Y(w,y);w[k]=u[B]})})});return f};return b};s.h=function(a){if(a)for(var b in a)this[b]=a[b]};s.h.get=function(a,b){b=b||"text";switch(typeof a){case "string":return b==
-"text"?a:undefined;case "object":if(a&&typeof a[b]!=="undefined")return a[b];return;default:return a}};var v;o({currency:function(a){i(this.element).toggleClass("ng-format-negative",a<0);return"$"+s.number.apply(this,[a,2])},number:function(a,b){if(isNaN(a)||!isFinite(a))return"";b=typeof b=="undefined"?2:b;var c=a<0;a=Math.abs(a);var d=Math.pow(10,b);a=""+Math.round(a*d);var e=a.substring(0,a.length-b);e=e||"0";d=a.substring(a.length-b);a=c?"-":"";for(c=0;c<e.length;c++){if((e.length-c)%3===0&&c!==
-0)a+=",";a+=e.charAt(c)}if(b>0){for(c=d.length;c<b;c++)d+="0";a+="."+d.substring(0,b)}return a},date:p(),json:function(a){i(this.element).addClass("ng-monospace");return toJson(a,true)},trackPackage:function(){var a=[{name:"UPS",url:"http://wwwapps.ups.com/WebTracking/processInputRequest?sort_by=status&tracknums_displayed=1&TypeOfInquiryNumber=T&loc=en_US&track.x=0&track.y=0&InquiryNumber1=",ta:[/^1Z[0-9A-Z]{16}$/i]},{name:"FedEx",url:"http://www.fedex.com/Tracking?tracknumbers=",ta:[/^96\d{10}?$/i,
-/^96\d{17}?$/i,/^96\d{20}?$/i,/^\d{15}$/i,/^\d{12}$/i]},{name:"USPS",url:"http://trkcnfrm1.smi.usps.com/PTSInternetWeb/InterLabelInquiry.do?origTrackNum=",ta:[/^(91\d{20})$/i,/^(91\d{18})$/i]}];return function(b,c){b=b.replace(/^ */,"").replace(/ *$/,"");var d=b.replace(/ /g,""),e;o(a,function(f){o(f.ta,function(g){if(g.test(d)){g=f.name+": "+b;var h=f.url+b;e=new s.h({text:g,url:h,html:'<a href="'+X(h)+'">'+g+"</a>",Jd:b});_.breakLoop()}});e&&_.breakLoop()});return e?e:b?c||new s.h({text:b+" is not recognized"}):
-null}}(),link:function(a,b){b=b||s.h.get(a);var c=s.h.get(a,"url")||s.h.get(a);if(c){if(m.Q.td(c)===null)c="mailto:"+c;a='<a href="'+C(c)+'">'+b+"</a>";return new s.h({text:b,url:c,html:a})}return a},bytes:function(){var a=["bytes","KB","MB","GB","TB","PB"];return function(b){if(b===null)return"";for(var c=0;b>1E3;){b/=1024;c++}b=""+b;var d=b.indexOf(".");if(d>-1&&d+2<b.length)b=b.substring(0,d+2);return b+" "+a[c]}}(),image:function(a,b,c){if(a&&a.url){var d="";if(b)d=' style="max-width: '+b+"px; max-height: "+
-(c||b)+'px;"';return new s.h({url:a.url,text:a.url,html:'<img src="'+a.url+'"'+d+"/>"})}return null},lowercase:function(a){return(a=s.h.get(a))?(""+a).toLowerCase():a},uppercase:function(a){return(a=s.h.get(a))?(""+a).toUpperCase():a},linecount:function(a){a=s.h.get(a);if(a===""||!a)return 1;return a.split(/\n|\f/).length},"if":function(a,b){return b?a:undefined},unless:function(a,b){return b?undefined:a},googleChartApi:V(function(a,b,c,d){b=b||{};a={Hb:a,gd:v.Ib(b,"color"),nd:v.title(b),jd:v.Ib(b,
-"label"),hd:v.values(b),kd:"bg,s,FFFFFF00"};if(_.isArray(b.Sc)){a.pd="x";a.od="0:|"+b.Sc.join("|")}return v.encode(a,c,d)},{values:function(a){var b=[];o(a.Gc||[],function(c){var d=[];o(c.values||[],function(e){d.push(e)});b.push(d.join(","))});a=b.join("|");return a===""?null:"t:"+a},title:function(a){var b=[];a=a.title||[];o(_.isArray(a)?a:[a],function(c){b.push(encodeURIComponent(c))});return b.join("|")},collect:function(a,b){var c=[],d=0;o(a.Gc||[],function(e){var f=[];e=e[b]||[];o(_.isArray(e)?
-e:[e],function(g){f.push(encodeURIComponent(g));d++});c.push(f.join("|"))});return d?c.join(","):null},encode:function(a,b,c){b=b||200;c=c||b;var d="http://chart.apis.google.com/chart?",e=[];a.md=b+"x"+c;o(a,function(f,g){f&&e.push(g+"="+f)});e.sort();d+=e.join("&");return new s.h({url:d,html:'<img width="'+b+'" height="'+c+'" src="'+d+'"/>'})}}),qrcode:function(a,b,c){return v.encode({Hb:"qr",ld:encodeURIComponent(a)},b,c)},chart:{Bd:function(a,b,c){return v("p",a,b,c)},Cd:function(a,b,c){return v("p3",
-a,b,c)},Dd:function(a,b,c){return v("pc",a,b,c)},bd:function(a,b,c){return v("bhs",a,b,c)},ad:function(a,b,c){return v("bhg",a,b,c)},dd:function(a,b,c){return v("bvs",a,b,c)},cd:function(a,b,c){return v("bvg",a,b,c)},xd:function(a,b,c){return v("lc",a,b,c)},Hd:function(a,b,c){return v("ls",a,b,c)},Gd:function(a,b,c){return v("s",a,b,c)}},html:function(a){return new s.h({html:a})}},function(a,b){s[b]=a});v=s.googleChartApi;array=[].constructor;toJson=function(a,b){var c=[];toJsonArray(c,a,b?"\n ":
-null);return c.join("")};toPrettyJson=function(a){return toJson(a,true)};fromJson=function(a){try{var b=new Parser(a,true),c=b.fa();b.K();return c()}catch(d){J("fromJson error: ",a,d);throw d;}};toJsonArray=function(a,b,c){var d=typeof b;if(b===null)a.push("null");else if(d!=="function")if(d==="boolean")a.push(""+b);else if(d==="number")isNaN(b)?a.push("null"):a.push(""+b);else if(d==="string")return a.push(m.String.quoteUnicode(b));else if(d==="object")if(b instanceof Array){a.push("[");var e=b.length;
-d=false;for(var f=0;f<e;f++){var g=b[f];d&&a.push(",");typeof g=="function"||typeof g=="undefined"?a.push("null"):toJsonArray(a,g,c);d=true}a.push("]")}else if(b instanceof Date)a.push(m.String.quoteUnicode(m.Date.toString(b)));else{a.push("{");c&&a.push(c);d=false;f=c?c+" ":false;g=[];for(var h in b)h.indexOf("$$")!==0&&g.push(h);g.sort();for(h=0;h<g.length;h++){var j=g[h];try{e=b[j];if(typeof e!="function"){if(d){a.push(",");c&&a.push(c)}a.push(m.String.quote(j));a.push(":");toJsonArray(a,e,f);
-d=true}}catch(k){}}a.push("}")}};Model=function(a,b){this.R=a;this.I(b||{});this.T=a.title;this.za()};Model.la=function(a,b){if(!(a===b||!a||!b)){var c=function(e,f,g){return g.substring(0,2)!=="$$"&&typeof e[g]!=="function"&&typeof f[g]!=="function"};for(var d in b)c(a,b,d)&&delete b[d];for(d in a)if(c(a,b,d))b[d]=a[d]}};Model.prototype.za=function(){S(this.R.Rb,this);return this};Model.prototype.ia=function(a){this.R.Ia.save(this,a===true?undefined:a);a===true&&this.R.Ia.Oa();return this};Model.prototype.I=
-function(a){Model.la(a,this);return this};Model.prototype.Aa=function(a){Model.la(this,a);return this};Lexer=function(a,b){this.text=a;this.Pb=b?20:-1;this.g=[];this.index=0};Lexer.Ba={"null":E(null),"true":E(true),"false":E(false),"+":function(a,b,c){return(b||0)+(c||0)},"-":function(a,b,c){return(b||0)-(c||0)},"*":function(a,b,c){return b*c},"/":function(a,b,c){return b/c},"%":function(a,b,c){return b%c},"^":function(a,b,c){return b^c},"=":function(a,b,c){return a.scope.j(b,c)},"==":function(a,
-b,c){return b==c},"!=":function(a,b,c){return b!=c},"<":function(a,b,c){return b<c},">":function(a,b,c){return b>c},"<=":function(a,b,c){return b<=c},">=":function(a,b,c){return b>=c},"&&":function(a,b,c){return b&&c},"||":function(a,b,c){return b||c},"&":function(a,b,c){return b&c},"|":function(a,b,c){return c(a,b)},"!":function(a,b){return!b}};Lexer.prototype.H=function(){return this.index+1<this.text.length?this.text.charAt(this.index+1):false};Lexer.prototype.parse=function(){for(var a=this.g,
-b=Lexer.Ba,c=true;this.index<this.text.length;){var d=this.text.charAt(this.index);if(d=='"'||d=="'"){this.Cc(d);c=true}else if(d=="("||d=="["){a.push({index:this.index,text:d});this.index++}else if(d=="{"){c=this.H();if(c==":"||c=="("){a.push({index:this.index,text:d+c});this.index++}else a.push({index:this.index,text:d});this.index++;c=true}else if(d==")"||d=="]"||d=="}"){a.push({index:this.index,text:d});this.index++;c=false}else if(d==":"||d=="."||d==","||d==";"){a.push({index:this.index,text:d});
-this.index++;c=true}else if(c&&d=="/"){this.Bc();c=false}else if(this.ma(d)){this.Ac();c=false}else if(this.$(d)){this.gb();c=false}else if(this.ec(d))this.index++;else{c=d+this.H();var e=b[d],f=b[c];if(f){a.push({index:this.index,text:c,b:f});this.index+=2}else if(e){a.push({index:this.index,text:d,b:e});this.index+=1}else throw"Lexer Error: Unexpected next character ["+this.text.substring(this.index)+"] in expression '"+this.text+"' at column '"+(this.index+1)+"'.";c=true}}return a};Lexer.prototype.ma=
-function(a){return"0"<=a&&a<="9"};Lexer.prototype.ec=function(a){return a==" "||a=="\r"||a=="\t"||a=="\n"||a=="\u000b"};Lexer.prototype.$=function(a){return"a"<=a&&a<="z"||"A"<=a&&a<="Z"||"_"==a||a=="$"};Lexer.prototype.Ac=function(){for(var a="",b=this.index;this.index<this.text.length;){var c=this.text.charAt(this.index);if(c=="."||this.ma(c))a+=c;else break;this.index++}a=1*a;this.g.push({index:b,text:a,b:function(){return a}})};Lexer.prototype.gb=function(){for(var a="",b=this.index;this.index<
-this.text.length;){var c=this.text.charAt(this.index);if(c=="."||this.$(c)||this.ma(c))a+=c;else break;this.index++}c=Lexer.Ba[a];if(!c){c=function(d){return d.scope.get(a)};c.Z=a}this.g.push({index:b,text:a,b:c})};Lexer.tb={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'};Lexer.prototype.Cc=function(a){var b=this.index,c=this.Pb;this.index++;for(var d="",e=false;this.index<this.text.length;){var f=this.text.charAt(this.index);if(e){if(f=="u"){f=this.text.substring(this.index+1,this.index+
-5);this.index+=4;d+=String.fromCharCode(parseInt(f,16))}else{e=Lexer.tb[f];d+=e?e:f}e=false}else if(f=="\\")e=true;else if(f==a){this.index++;this.g.push({index:b,text:d,b:function(){return d.length==c?m.String.toDate(d):d}});return}else d+=f;this.index++}throw"Lexer Error: Unterminated quote ["+this.text.substring(b)+"] starting at column '"+(b+1)+"' in expression '"+this.text+"'.";};Lexer.prototype.Bc=function(){var a=this.index;this.index++;for(var b="",c=false;this.index<this.text.length;){var d=
-this.text.charAt(this.index);if(c){b+=d;c=false}else if(d==="\\"){b+=d;c=true}else if(d==="/"){this.index++;c="";if(this.$(this.text.charAt(this.index))){this.gb();c=this.g.pop().text}var e=new RegExp(b,c);this.g.push({index:a,text:b,vd:c,b:function(){return e}});return}else b+=d;this.index++}throw"Lexer Error: Unterminated RegExp ["+this.text.substring(a)+"] starting at column '"+(a+1)+"' in expression '"+this.text+"'.";};Parser=function(a,b){this.text=a;this.g=(new Lexer(a,b)).parse();this.index=
-0};Parser.vb=E(0);Parser.prototype.error=function(a,b){throw"Token '"+b.text+"' is "+a+" at column='"+(b.index+1)+"' of expression '"+this.text+"' starting at '"+this.text.substring(b.index)+"'.";};Parser.prototype.ea=function(){if(this.g.length===0)throw"Unexpected end of expression: "+this.text;return this.g[0]};Parser.prototype.H=function(a,b,c,d){var e=this.g;if(e.length>0){e=e[0];var f=e.text;if(f==a||f==b||f==c||f==d||!a&&!b&&!c&&!d)return e}return false};Parser.prototype.a=function(a,b,c,d){if(a=
-this.H(a,b,c,d)){this.g.shift();return this.qd=a}return false};Parser.prototype.k=function(a){if(!this.a(a)){var b=this.H();throw"Expecting '"+a+"' at column '"+(b.index+1)+"' in '"+this.text+"' got '"+this.text.substring(b.index)+"'.";}};Parser.prototype.wb=function(a,b){var c=b.apply(this);return function(d){return a(d,c(d))}};Parser.prototype.q=function(a,b,c){var d=c.apply(this);return function(e){return b(e,a(e),d(e))}};Parser.prototype.Ra=function(){return this.g.length>0};Parser.prototype.K=
-function(){if(this.g.length!==0)throw"Did not understand '"+this.text.substring(this.g[0].index)+"' while evaluating '"+this.text+"'.";};Parser.prototype.ua=function(){for(var a=[];;){this.g.length>0&&!this.H("}",")",";","]")&&a.push(this.Na());if(!this.a(";"))return function(b){for(var c,d=0;d<a.length;d++){var e=a[d];if(e)c=e(b)}return c}}};Parser.prototype.Na=function(){for(var a=this.o(),b;;)if(b=this.a("|"))a=this.q(a,b.b,this.filter);else return a};Parser.prototype.filter=function(){return this.Da(m.filter)};
-Parser.prototype.Q=function(){return this.Da(m.validator)};Parser.prototype.Da=function(a){for(var b=this.ac(a),c=[];;)if(this.a(":"))c.push(this.o());else{var d=function(e,f){f=[f];for(var g=0;g<c.length;g++)f.push(c[g](e));return b.apply(e,f)};return function(){return d}}};Parser.prototype.o=function(){return this.Ic()};Parser.prototype.Ic=function(){if(this.a("throw")){var a=this.Fa();return function(b){throw a(b);}}else return this.Fa()};Parser.prototype.Fa=function(){var a=this.$a(),b;if(b=this.a("=")){if(!a.Z)throw"Left hand side '"+
-this.text.substring(0,b.index)+"' of assignment '"+this.text.substring(b.index)+"' is not assignable.";return this.q(function(){return a.Z},b.b,this.$a)}else return a};Parser.prototype.$a=function(){for(var a=this.Za(),b;;)if(b=this.a("||"))a=this.q(a,b.b,this.Za);else return a};Parser.prototype.Za=function(){for(var a=this.bb(),b;;)if(b=this.a("&&"))a=this.q(a,b.b,this.bb);else return a};Parser.prototype.bb=function(){var a;return(a=this.a("!"))?this.wb(a.b,this.La):this.La()};Parser.prototype.La=
-function(){for(var a=this.hb(),b;;)if(b=this.a("==","!="))a=this.q(a,b.b,this.hb);else return a};Parser.prototype.hb=function(){for(var a=this.Ea(),b;;)if(b=this.a("<",">","<=",">="))a=this.q(a,b.b,this.Ea);else return a};Parser.prototype.Ea=function(){for(var a=this.qa(),b;b=this.a("+","-");)a=this.q(a,b.b,this.qa);return a};Parser.prototype.qa=function(){for(var a=this.kb(),b;b=this.a("*","/","%");)a=this.q(a,b.b,this.kb);return a};Parser.prototype.kb=function(){var a;return this.a("+")?this.fa():
-(a=this.a("-"))?this.q(Parser.vb,a.b,this.qa):this.fa()};Parser.prototype.ac=function(a){var b=this.a(),c=b.text.split(".");a=a;for(var d,e=0;e<c.length;e++){d=c[e];if(a)a=a[d]}if(typeof a!="function")throw"Function '"+b.text+"' at column '"+(b.index+1)+"' in '"+this.text+"' is not defined.";return a};Parser.prototype.fa=function(){var a;if(this.a("(")){a=this.Na();this.k(")");a=a}else if(this.a("["))a=this.Cb();else if(this.a("{"))a=this.object();else if(this.a("{:"))a=this.Ga(false);else if(this.a("{("))a=
-this.Ga(true);else{var b=this.a();(a=b.b)||this.error("not a primary expression",b)}for(;b=this.a("(","[",".");)if(b.text==="(")a=this.$b(a);else if(b.text==="[")a=this.vc(a);else if(b.text===".")a=this.Yb(a);else throw"IMPOSSIBLE";return a};Parser.prototype.Ga=function(a){var b=[];if(a){if(!this.a(")")){for(b.push(this.a().text);this.a(",");)b.push(this.a().text);this.k(")")}this.k(":")}var c=this.ua();this.k("}");return function(d){return function(e){var f=new Scope(d.scope.s);f.j("$",e);for(var g=
-0;g<b.length;g++)f.j(b[g],arguments[g]);return c({scope:f})}}};Parser.prototype.Yb=function(a){var b=this.a().text;function c(d){return Scope.Y(a(d),b)}c.Z=b;return c};Parser.prototype.vc=function(a){var b=this.o();this.k("]");if(this.a("=")){var c=this.o();return function(d){return a(d)[b(d)]=c(d)}}else return function(d){var e=a(d);d=b(d);return e?e[d]:undefined}};Parser.prototype.$b=function(a){var b=[];if(this.ea().text!=")"){do b.push(this.o());while(this.a(","))}this.k(")");return function(c){for(var d=
-[],e=0;e<b.length;e++)d.push(b[e](c));e=a(c);if(typeof e==="function")return e.apply(c,d);else throw"Expression '"+a.Z+"' is not a function.";}};Parser.prototype.Cb=function(){var a=[];if(this.ea().text!="]"){do a.push(this.o());while(this.a(","))}this.k("]");return function(b){for(var c=[],d=0;d<a.length;d++)c.push(a[d](b));return c}};Parser.prototype.object=function(){var a=[];if(this.ea().text!="}"){do{var b=this.a().text;this.k(":");var c=this.o();a.push({fc:b,value:c})}while(this.a(","))}this.k("}");
-return function(d){for(var e={},f=0;f<a.length;f++){var g=a[f],h=g.value(d);e[g.fc]=h}return e}};Parser.prototype.Wb=function(){for(var a=[];this.Ra();){a.push(this.Vb());this.a(";")||this.K()}return function(b){for(var c="",d=0;d<a.length;d++)c+=a[d](b);return c}};Parser.prototype.Vb=function(){var a=this.a().text,b,c;if(this.a("=")){b=a;a=this.a().text}if(this.a(":"))c=this.fa()(null);return function(d){var e=d.scope.get("$datastore").M(a,c);d.scope.j(a,e);if(b){e=e();e.ya=b;d.scope.j(b,e);return"$anchor."+
-b+":{"+b+"="+a+".load($anchor."+b+");"+b+".$$anchor="+m.String.quote(b)+";};"}else return""}};Parser.prototype.watch=function(){for(var a=[];this.Ra();){a.push(this.Qc());this.a(";")||this.K()}this.K();return function(b){for(var c=0;c<a.length;c++){var d=a[c](b);b.zb(d.name,d.b)}}};Parser.prototype.Qc=function(){var a=this.a().text;this.k(":");var b;if(this.ea().text=="{"){this.k("{");b=this.ua();this.k("}")}else b=this.o();return function(){return{name:a,b:b}}};Scope=function(a,b){this.ob=[];this.wa=
-{};this.name=b;a=a||{};function c(){}c.prototype=a;this.s=new c;this.s.Uc=a;if(b=="ROOT")this.s.Vc=this.s};Scope.X={};Scope.prototype.c=function(){var a=this;this.Zb();_.each(this.ob,function(b){a.l(b,"",{},function(){this.c(a)})})};Scope.prototype.Bb=function(a){a&&this.ob.push(a)};Scope.prototype.dc=function(a){for(var b=0;b<a.length;b++){var c=a.charAt(b);if(c!="."&&!Lexer.prototype.$(c))return false}return true};Scope.Y=function(a,b){if(!b)return a;for(var c=b.split("."),d,e=a,f=c.length,g=0;g<
-f;g++){d=c[g];if(!d.match(/^[\$\w][\$\w\d]*$/))throw"Expression '"+b+"' is not a valid expression for accesing variables.";if(a){e=a;a=a[d]}if(_.isUndefined(a)&&d.charAt(0)=="$"){var h=m.Global.typeOf(e);if(d=(h=m[h.charAt(0).toUpperCase()+h.substring(1)])?h[[d.substring(1)]]:undefined)return a=_.bind(d,e,e)}}if(typeof a==="function"&&!a.qb)return P(e,a);return a};Scope.prototype.get=function(a){return Scope.Y(this.s,a)};Scope.prototype.j=function(a,b){a=a.split(".");for(var c=this.s,d=0;a.length>
-1;d++){var e=a.shift(),f=c[e];if(!f){f={};c[e]=f}c=f}return c[a.shift()]=b};Scope.prototype.m=function(a,b){this.eval(a+"="+toJson(b))};Scope.prototype.eval=function(a,b){var c=Scope.X[a];if(!c){var d=new Parser(a);c=d.ua();d.K();Scope.X[a]=c}b=b||{};b.scope=this;return c(b)};Scope.prototype.l=function(a,b,c,d,e){try{var f=this.eval(b,c);if(a.w){a.w=false;i(a.view).removeClass("ng-exception").removeAttr("ng-error")}d&&d.apply(a,[f]);return true}catch(g){J("Eval Widget Error:",g);b=toJson(g,true);
-a.w=true;i(a.view).addClass("ng-exception").attr("ng-error",b);e&&e.apply(a,[g,b]);return false}};Scope.prototype.Oc=function(a,b){var c=Scope.X[a];if(!c){c=(new Parser(a)).Q();Scope.X[a]=c}a={scope:this};return c(a)(a,b)};Scope.prototype.M=function(a){return(new Parser(a)).Wb()({scope:this})};Scope.prototype.ic=function(a){this.s.Tc.push(a)};Scope.prototype.watch=function(a){var b=this;(new Parser(a)).watch()({scope:this,zb:function(c,d){b.Ab(c,function(e,f){try{return d({scope:b},e,f)}catch(g){alert(g)}})}})};
-Scope.prototype.Ab=function(a,b){var c=this.wa[a];if(!c){c={Va:[],o:a};this.wa[a]=c}c.Va.push(b)};Scope.prototype.Zb=function(){var a=this,b=false;o(this.wa,function(c){var d=a.eval(c.o);if(d!==c.d){o(c.Va,function(e){e(d,c.d);b=true});c.d=d}});return b};Server=function(a,b){this.url=a;this.kc=0;this.getScript=b;this.Nc="_"+(""+Math.random()).substr(2)+"_";this.pa=1800};Server.prototype.Eb=function(a){return H.Tb(a)};Server.prototype.P=function(a,b,c,d){var e=this.Nc+this.kc++;K[e]=function(h){delete m[e];
-d(200,h)};a={Kd:b,yd:a,Ad:c};a=this.Eb(toJson(a));b=Math.ceil(a.length/this.pa);c=this.url+"/$/"+e+"/"+b+"/";for(var f=0;f<b;f++){var g=a.substr(f*this.pa,this.pa);this.getScript(c+(f+1)+"?h="+g,x)}};FrameServer=A("frame");FrameServer.Xc="$DATASET:";FrameServer.prototype={P:p()};VisualServer=function(a,b,c){this.Sb=a;this.update=c;this.status=b};VisualServer.prototype={P:function(a,b,c,d){var e=this;this.status.Fb(c);this.Sb.P(a,b,c,function(){e.status.Ub();try{d.apply(this,arguments)}catch(f){alert(toJson(f))}e.update()})}};
-Users=function(a,b){this.z=a;this.ka=b};Users.prototype={Ma:function(a){var b=this;this.z.P("GET","/account.json",{},function(c,d){b.Ob=d.Mc;a(d.Mc)})},ab:function(a){var b=this;this.ka.ab(function(){delete b.Ob;(a||x)()})},ba:function(a){var b=this;this.ka.ba(function(){b.Ma(function(){(a||x)()})})},ra:function(){this.ka.ra()}};o({regexp:function(a,b,c){return a.match(b)?null:c||"Value does not match expected format "+b+"."},number:function(a,b,c){var d=1*a;if(d==a){if(typeof b!="undefined"&&d<b)return"Value can not be less than "+
-b+".";if(typeof b!="undefined"&&d>c)return"Value can not be greater than "+c+".";return null}else return"Value is not a number."},integer:function(a,b,c){b=W.number(a,b,c);if(b===null&&a!=Math.round(a))return"Value is not a whole number.";return b},date:function(a){if(a.match(/^\d\d?\/\d\d?\/\d\d\d\d$/))return null;return"Value is not a date. (Expecting format: 12/31/2009)."},ssn:function(a){if(a.match(/^\d\d\d-\d\d-\d\d\d\d$/))return null;return"SSN needs to be in 999-99-9999 format."},email:function(a){if(a.match(/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/))return null;
-return"Email needs to be in username@host.com format."},phone:function(a){if(a.match(/^1\(\d\d\d\)\d\d\d-\d\d\d\d$/))return null;if(a.match(/^\+\d{2,3} (\(\d{1,5}\))?[\d ]+\d$/))return null;return"Phone number needs to be in 1(987)654-3210 format in North America or +999 (123) 45678 906 internationaly."},url:function(a){if(a.match(/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/))return null;return"URL needs to be in http://server[:port]/path format."},json:function(a){try{fromJson(a);
-return null}catch(b){return b.toString()}}},function(a,b){W[b]=a});WidgetFactory=function(a,b){this.lc=0;this.ha=a;this.G=b;this.Ha=n.Id?swfobject.Ha:function(){alert("ERROR: swfobject not loaded!")};this.wc=p()};WidgetFactory.prototype.Mb=function(a,b){var c,d=a.attr("type").toLowerCase(),e=a.attr("name");if(e)e=e.split(":").pop();var f="change",g=true;if(d=="button"||d=="submit"||d=="reset"||d=="image"){c=new ButtonController(a[0],e);f="click";g=false}else if(d=="text"||d=="textarea"||d=="hidden"||
-d=="password"){c=new TextController(a[0],e);f="keyup change"}else if(d=="checkbox"){c=new CheckboxController(a[0],e);f="click"}else if(d=="radio"){c=new RadioController(a[0],e);f="click"}else if(d=="select-one")c=new SelectController(a[0],e);else if(d=="select-multiple")c=new MultiSelectController(a[0],e);else if(d=="file")c=this.Nb(a,e);else throw"Unknown type: "+d;a.data("controller",c);var h=b.get("$binder");i(c.view,":input").bind(f,function(){if(c.e(b)){var j=i(c.view).attr("ng-action")||"";
-b.l(c,j)&&h.c(b)}return g});return c};WidgetFactory.prototype.Nb=function(a){var b="__uploadWidget_"+this.lc++,c=FileController.template(b);a.after(c);b=this.Ha({data:this.ha+"/admin/ServerAPI.swf",width:"95",height:"20",align:"top",Md:"transparent"},{wd:"uploadWidgetId="+b,Yc:"always"},b);a.remove();a=new FileController(c,a[0].name,b,this.ha+"/data/"+this.G);i(b).data("controller",a);return a};FileController=function(a,b,c,d){this.view=a;this.Ld=c;this.ib=b;this.Zc=d+"/_attachments";this.value=null;
-this.d=undefined};FileController.dispatchEvent=function(a,b,c){a=r.getElementById(a);a=i(a).data("controller");FileController.prototype["_on_"+b].apply(a,c)};FileController.template=function(a){return i('<span class="ng-upload-widget"><input type="checkbox" ng-non-bindable="true"/><object id="'+a+'" /><a></a><span/></span>')};FileController.prototype.e=function(a){var b=this.view.find("input").attr("checked")?this.value:null;if(this.d===b)return false;else{a.j(this.ib,b);return true}};FileController.prototype.c=
-function(a){if((a=a.get(this.ib))&&this.value!==a){this.value=a;this.view.find("a").attr("href",this.value.url).text(this.value.text);this.view.find("span").text(m.filter.bytes(this.value.size))}this.view.find("input").attr("checked",!!a)};NullController=A("view");NullController.prototype.e=E(true);NullController.prototype.c=p();NullController.cc=new NullController;ButtonController=A("view");ButtonController.prototype.e=E(true);ButtonController.prototype.c=p();TextController=function(a,b){this.view=
-a;this.exp=b;this.Q=a.getAttribute("ng-validate");this.Dc=typeof a.attributes["ng-required"]!="undefined";this.Ta=null;this.d=undefined;this.p=a.value;a.getAttribute("ng-widget")==="datepicker"&&i(a).rd()};TextController.prototype.e=function(a){var b=this.view.value;if(this.d===b)return false;else{a.m(this.exp,b);this.d=b;return true}};TextController.prototype.c=function(a){var b=this.view,c=a.get(this.exp);if(typeof c==="undefined"){c=this.p;a.m(this.exp,c)}c=c?c:"";if(this.d!=c)this.d=b.value=c;
-var d=false;b.removeAttribute("ng-error");if(this.Dc)d=!(c&&c.length>0);var e=d?"Required Value":null;if(!d&&this.Q&&c){e=a.Oc(this.Q,c);d=!!e}if(this.Ta!==e){this.Ta=d;if(e!==null){b.setAttribute("ng-error",e);a.ic(this)}i(b).toggleClass("ng-validation-error",d)}};CheckboxController=function(a,b){this.view=a;this.exp=b;this.d=undefined;this.p=a.checked?a.value:""};CheckboxController.prototype.e=function(a){var b=this.view;b=b.checked?b.value:"";if(this.d===b)return false;else{a.m(this.exp,b);this.d=
-b;return true}};CheckboxController.prototype.c=function(a){var b=this.view,c=a.eval(this.exp);if(typeof c==="undefined"){c=this.p;a.m(this.exp,c)}b.checked=b.value==""+c};SelectController=function(a,b){this.view=a;this.exp=b;this.d=undefined;this.p=a.value};SelectController.prototype.e=function(a){if(this.view.selectedIndex<0)a.m(this.exp,null);else{var b=this.view.value;if(this.d===b)return false;else{a.m(this.exp,b);this.d=b;return true}}};SelectController.prototype.c=function(a){var b=this.view,
-c=a.get(this.exp);if(typeof c==="undefined"){c=this.p;a.m(this.exp,c)}if(c!==this.d){b.value=c?c:"";this.d=c}};MultiSelectController=function(a,b){this.view=a;this.exp=b;this.d=undefined;this.p=this.selected()};MultiSelectController.prototype.selected=function(){for(var a=[],b=this.view.options,c=0;c<b.length;c++){var d=b[c];d.selected&&a.push(d.value)}return a};MultiSelectController.prototype.e=function(a){var b=this.selected();if(this.d===b)return false;else{a.m(this.exp,b);this.d=b;return true}};
-MultiSelectController.prototype.c=function(a){var b=this.view,c=a.get(this.exp);if(typeof c==="undefined"){c=this.p;a.m(this.exp,c)}if(c!==this.d){a=b.options;for(b=0;b<a.length;b++){var d=a[b];d.selected=_.include(c,d.value)}this.d=c}};RadioController=function(a,b){this.view=a;this.exp=b;this.d=this.na=undefined;this.Sa=a.value;this.p=a.checked?a.value:null};RadioController.prototype.e=function(a){var b=this.view;if(this.na)return false;else{b.checked=true;this.d=a.m(this.exp,this.Sa);return this.na=
-true}};RadioController.prototype.c=function(a){var b=this.view,c=a.get(this.exp);if(this.p&&typeof c==="undefined"){c=this.p;a.m(this.exp,c)}if(this.d!=c){this.na=b.checked=this.Sa==""+c;this.d=c}};BindUpdater=function(a,b){this.view=a;this.exp=Binder.da(b);this.w=false;this.Fc={element:a}};BindUpdater.jb=function(a){switch(typeof a){case "string":case "boolean":case "number":return C(a);case "function":return BindUpdater.jb(a());case "object":if(a&&a.tagName&&a.nodeName&&a.ownerDocument&&a.removeAttribute)return Q(a);
-else if(a instanceof m.filter.h){switch(typeof a.html){case "string":case "number":return a.html;case "function":return a.html();case "object":if(a.html&&a.html.tagName&&a.html.nodeName&&a.html.ownerDocument&&a.html.removeAttribute)return Q(a.html);default:break}switch(typeof a.text){case "string":case "number":return C(a.text);case "function":return C(a.text());default:break}}if(a===null)return"";return C(toJson(a,true));default:return""}};BindUpdater.prototype.e=p();BindUpdater.prototype.c=function(a){for(var b=
-[],c=this.exp,d=c.length,e=0;e<d;e++){var f=c[e],g=Binder.L(f);if(g){a.l(this,g,this.Fc,function(h){b.push(BindUpdater.jb(h))},function(h,j){O(this.view,j)});if(this.w)return}else b.push(C(f))}O(this.view,b.join(""))};BindAttrUpdater=function(a,b){this.view=a;this.Db=b};BindAttrUpdater.prototype.e=p();BindAttrUpdater.prototype.c=function(a){var b=i(this.view),c=this.Db;if(this.w){this.w=false;b.removeClass("ng-exception").removeAttr("ng-error")}var d=b.is("img");for(var e in c){for(var f=Binder.da(c[e]),
-g=[],h=0;h<f.length;h++){var j=Binder.L(f[h]);if(j)try{var k=a.eval(j,{element:b[0],attrName:e});if(k&&(k.constructor!==array||k.length!==0))g.push(k)}catch(l){this.w=true;J("BindAttrUpdater",l);j=toJson(l,true);g.push("["+j+"]");b.addClass("ng-exception").attr("ng-error",j)}else g.push(f[h])}f=g.length?g.join(""):null;if(d&&e=="src"&&!f)f=a.get("config.server")+"/images/blank.gif";b.attr(e,f)}};EvalUpdater=function(a,b){this.view=a;this.exp=b;this.w=false};EvalUpdater.prototype.e=p();EvalUpdater.prototype.c=
-function(a){a.l(this,this.exp)};HideUpdater=function(a,b){this.view=a;this.exp=b};HideUpdater.prototype.e=p();HideUpdater.prototype.c=function(a){a.l(this,this.exp,{},function(b){var c=i(this.view);R(b)?c.hide():c.show()})};ShowUpdater=function(a,b){this.view=a;this.exp=b};ShowUpdater.prototype.e=p();ShowUpdater.prototype.c=function(a){a.l(this,this.exp,{},function(b){var c=i(this.view);R(b)?c.show():c.hide()})};ClassUpdater=function(a,b){this.view=a;this.exp=b};ClassUpdater.prototype.e=p();ClassUpdater.prototype.c=
-function(a){a.l(this,this.exp,{},function(b){if(b!==null&&b!==undefined)this.view.className=b})};ClassEvenUpdater=function(a,b){this.view=a;this.exp=b};ClassEvenUpdater.prototype.e=p();ClassEvenUpdater.prototype.c=function(a){a.l(this,this.exp,{},function(b){var c=a.get("$index");i(this.view).toggleClass(b,c%2===1)})};ClassOddUpdater=function(a,b){this.view=a;this.exp=b};ClassOddUpdater.prototype.e=p();ClassOddUpdater.prototype.c=function(a){a.l(this,this.exp,{},function(b){var c=a.get("$index");
-i(this.view).toggleClass(b,c%2===0)})};StyleUpdater=function(a,b){this.view=a;this.exp=b};StyleUpdater.prototype.e=p();StyleUpdater.prototype.c=function(a){a.l(this,this.exp,{},function(b){i(this.view).attr("style","").css(b)})};RepeaterUpdater=function(a,b,c,d){this.view=a;this.template=c;this.prefix=d;this.children=[];a=b.match(/^\s*(.+)\s+in\s+(.*)\s*$/);if(!a)throw"Expected ng-repeat in form of 'item in collection' but got '"+b+"'.";b=a[1];this.aa=a[2];a=b.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
-if(!a)throw"'item' in 'item in collection' should be identifier or (key, value) but get '"+b+"'.";this.Pc=a[3]||a[1];this.gc=a[2]};RepeaterUpdater.prototype.e=p();RepeaterUpdater.prototype.c=function(a){a.l(this,this.aa,{},function(b){var c=this;if(!b){b=[];a.dc(this.aa)&&a.j(this.aa,b)}var d=b.length,e=this.children.length,f=this.view,g=0,h=null,j=this.gc,k=this.Pc,l=0;o(b,function(z,t){if(l<e){h=c.children[l];h.scope.j(k,z)}else{var u=new Scope(a.s,c.prefix+k+" in "+c.aa+"["+l+"]");u.j("$index",
-l);j&&u.j(j,t);u.j(k,z);h={scope:u,element:c.template(u,c.prefix,l)};f.after(h.element);c.children.push(h)}f=h.element;z=(new Date).getTime();h.scope.c();g+=(new Date).getTime()-z;l++});for(b=e;b>d;--b){var y=this.children.pop().element[0];y.parentNode.removeChild(y)}if(h&&h.element[0].nodeName==="OPTION")if(d=i(h.element[0].parentNode).data("controller")){d.d=undefined;d.c(a)}})};PopUp=A("B");PopUp.Ca="mouseleave mouseout click dblclick keypress keyup";PopUp.prototype.bind=function(){this.B.find(".ng-validation-error,.ng-exception").live("mouseover",
-PopUp.xc)};PopUp.xc=function(){PopUp.sa();var a=i(this);a.bind(PopUp.Ca,PopUp.sa);var b=a.position(),c=r.documentElement,d=(self.innerWidth||c&&c.clientWidth||r.body.clientWidth)-b.left;c=a.hasClass("ng-exception")?"EXCEPTION:":"Validation error...";a=a.attr("ng-error");d=d>375?"left":"right";c=i("<div id='ng-callout' style='width:300px'><div class='ng-arrow-"+d+"'/><div class='ng-title'>"+c+"</div><div class='ng-content'>"+a+"</div></div>");i("body").append(c);if(d==="left")a=b.left+this.offsetWidth+
-11;else{a=b.left-315;c.find(".ng-arrow-right").css({left:301})}c.css({left:a+"px",top:b.top-3+"px"});return true};PopUp.sa=function(){i("#ng-callout").unbind(PopUp.Ca,PopUp.sa).remove();return true};Status=function(a){this.Ya=a.append(Status.sb).find("#ng-loading");this.ga=0};Status.sb='<div id="ng-spacer"></div><div id="ng-loading">loading....</div>';Status.prototype.Fb=function(){this.ga===0&&this.Ya.show();this.ga++};Status.prototype.Ub=function(){this.ga--;this.ga===0&&this.Ya.hide("fold")}})(window,
-document);
+function J(){return function(){}}function K(o){return function(){return o}}
+(function(o,x){function n(){}function da(a,b){var c=x.createElement("div");c.className=a;for(var d=a="",e=0;e<b.length;e++){var f=b[e];a+=d+(typeof f=="string"?f:y(f));d=" "}c.appendChild(x.createTextNode(a));R.appendChild(c)}function ea(a){switch(a.nodeName){case "OPTION":case "PRE":case "TITLE":return true;default:return false}}function fa(a,b){if(ea(a))if(W)a.innerText=b;else a.textContent=b;else a.innerHTML=b}function L(a){if(!a||!a.replace)return a;return a.replace(/&/g,"&amp;").replace(/</g,
+"&lt;").replace(/>/g,"&gt;")}function Da(a){if(!a||!a.replace)return a;return a.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\"/g,"&quot;")}function ga(a,b){if(!a)throw"Missing this";if(!_.isFunction(b))throw"Missing function";return function(){return b.apply(a,arguments)}}function Ea(a,b){return function(){for(var c=[this],d=0;d<arguments.length;d++)c.push(arguments[d]);return b.apply(a,c)}}function ha(a){var b=x.createElement("div");b.appendChild(a);var c=b.innerHTML;b.removeChild(a);return c}
+function X(a){var b=(""+a).toLowerCase();if(b=="f"||b=="0"||b=="false"||b=="no")a=false;return!!a}function Y(a,b){for(var c in a){var d=b[c],e=typeof d;if(e=="undefined")b[c]=O(y(a[c]));else e=="object"&&d.constructor!=array&&c.substring(0,1)!="$"&&Y(a[c],d)}}function ia(a,b,c){this.document=k(a);this.head=k(b);this.i=c;this.location=o.location}function ja(a){this.location=a;this.delay=25;this.setTimeout=function(b,c){o.setTimeout(b,c)};this.La=function(b){return b};this.L=a.href}function G(a,b,c){var d=
+_.last(b);q(c,function(e){d[e]=_[e]});m[a]=m[a]||{};q(b,function(e){S(m[a],e)})}function z(a,b,c,d){this.C=a;this.pa=c;this.anchor={};this.Pc=b;this.i=d||{};this.cb=[]}function P(a,b){this.document=a;this.da=b;this.window=o;this.F=[]}function T(a,b,c){this.post=a;this.eb=b;this.B={P:[]};this.anchor=c;this.S=[]}function y(a,b){var c=[];Z(c,a,b?"\n ":null);return c.join("")}function O(a){try{var b=new D(a,true),c=b.ba();b.I();return c()}catch(d){$("fromJson error: ",a,d);throw d;}}function Z(a,b,c){var d=
+typeof b;if(b===null)a.push("null");else if(d!=="function")if(d==="boolean")a.push(""+b);else if(d==="number")isNaN(b)?a.push("null"):a.push(""+b);else if(d==="string")return a.push(m.String.quoteUnicode(b));else if(d==="object")if(b instanceof Array){a.push("[");var e=b.length;d=false;for(var f=0;f<e;f++){var g=b[f];d&&a.push(",");typeof g=="function"||typeof g=="undefined"?a.push("null"):Z(a,g,c);d=true}a.push("]")}else if(b instanceof Date)a.push(m.String.quoteUnicode(m.Date.toString(b)));else{a.push("{");
+c&&a.push(c);d=false;f=c?c+" ":false;g=[];for(var h in b)h.indexOf("$$")!==0&&g.push(h);g.sort();for(h=0;h<g.length;h++){var i=g[h];try{e=b[i];if(typeof e!="function"){if(d){a.push(",");c&&a.push(c)}a.push(m.String.quote(i));a.push(":");Z(a,e,f);d=true}}catch(j){}}a.push("}")}}function E(a,b){this.$$entity=a;this.R(b||{});this.Q=a.title;this.ib()}function F(a,b){this.text=a;this.Kb=b?20:-1;this.g=[];this.index=0}function D(a,b){this.text=a;this.g=(new F(a,b)).parse();this.index=0}function w(a,b){this.fb=
+[];this.qa={};this.name=b;a=a||{};function c(){}c.prototype=a;this.q=new c;this.q.Vc=a;if(b=="ROOT")this.q.Wc=this.q}function ka(a,b){this.url=a;this.hc=0;this.getScript=b;this.Lc="_"+(""+Math.random()).substr(2)+"_";this.ka=1800}function aa(a){this.frame=a}function la(a,b,c){this.Mb=a;this.update=c;this.status=b}function ma(a,b){this.z=a;this.fa=b}function na(a,b){this.ic=0;this.da=a;this.G=b;this.Aa=o.Kd?swfobject.Aa:function(){alert("ERROR: swfobject not loaded!")};this.tc=J()}function M(a,b,c,
+d){this.view=a;this.Nd=c;this.$a=b;this.ad=d+"/_attachments";this.value=null;this.d=undefined}function Q(a){this.view=a}function oa(a,b){this.view=a;this.exp=b;this.O=a.getAttribute("ng-validate");this.Bc=typeof a.attributes["ng-required"]!="undefined";this.Ka=null;this.d=undefined;this.p=a.value;a.getAttribute("ng-widget")==="datepicker"&&k(a).td()}function pa(a,b){this.view=a;this.exp=b;this.d=undefined;this.p=a.checked?a.value:""}function qa(a,b){this.view=a;this.exp=b;this.d=undefined;this.p=
+a.value}function ra(a,b){this.view=a;this.exp=b;this.d=undefined;this.p=this.selected()}function sa(a,b){this.view=a;this.exp=b;this.d=this.ia=undefined;this.Ja=a.value;this.p=a.checked?a.value:null}function N(a,b){this.view=a;this.exp=z.$(b);this.w=false;this.Dc={element:a}}function ta(a,b){this.view=a;this.wb=b}function ua(a,b){this.view=a;this.exp=b;this.w=false}function va(a,b){this.view=a;this.exp=b}function wa(a,b){this.view=a;this.exp=b}function xa(a,b){this.view=a;this.exp=b}function ya(a,
+b){this.view=a;this.exp=b}function za(a,b){this.view=a;this.exp=b}function Aa(a,b){this.view=a;this.exp=b}function Ba(a,b,c,d){this.view=a;this.template=c;this.prefix=d;this.children=[];a=b.match(/^\s*(.+)\s+in\s+(.*)\s*$/);if(!a)throw"Expected ng-repeat in form of 'item in collection' but got '"+b+"'.";b=a[1];this.Y=a[2];a=b.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);if(!a)throw"'item' in 'item in collection' should be identifier or (key, value) but get '"+b+"'.";this.Nc=a[3]||a[1];this.bc=
+a[2]}function B(a){this.C=a}function U(a){this.Pa=a.append(U.kb).find("#ng-loading");this.ca=0}var ba={u:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",Nb:function(a){var b="",c,d,e,f,g,h,i=0;for(a=ba.rb(a);i<a.length;){c=a.charCodeAt(i++);d=a.charCodeAt(i++);e=a.charCodeAt(i++);f=c>>2;c=(c&3)<<4|d>>4;g=(d&15)<<2|e>>6;h=e&63;if(isNaN(d))g=h=64;else if(isNaN(e))h=64;b=b+this.u.charAt(f)+this.u.charAt(c)+this.u.charAt(g)+this.u.charAt(h)}return b},ud:function(a){var b="",c,d,e,
+f,g,h=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");h<a.length;){c=this.u.indexOf(a.charAt(h++));d=this.u.indexOf(a.charAt(h++));f=this.u.indexOf(a.charAt(h++));g=this.u.indexOf(a.charAt(h++));c=c<<2|d>>4;d=(d&15)<<4|f>>2;e=(f&3)<<6|g;b+=String.fromCharCode(c);if(f!=64)b+=String.fromCharCode(d);if(g!=64)b+=String.fromCharCode(e)}return b=ba.qb(b)},rb:function(a){a=a.replace(/\r\n/g,"\n");for(var b="",c=0;c<a.length;c++){var d=a.charCodeAt(c);if(d<128)b+=String.fromCharCode(d);else{if(d>127&&d<2048)b+=
+String.fromCharCode(d>>6|192);else{b+=String.fromCharCode(d>>12|224);b+=String.fromCharCode(d>>6&63|128)}b+=String.fromCharCode(d&63|128)}}return b},qb:function(a){for(var b="",c=0,d=c1=c2=0;c<a.length;){d=a.charCodeAt(c);if(d<128){b+=String.fromCharCode(d);c++}else if(d>191&&d<224){c2=a.charCodeAt(c+1);b+=String.fromCharCode((d&31)<<6|c2&63);c+=2}else{c2=a.charCodeAt(c+1);c3=a.charCodeAt(c+2);b+=String.fromCharCode((d&15)<<12|(c2&63)<<6|c3&63);c+=3}}return b}};if(typeof x.getAttribute=="undefined")x.getAttribute=
+J();if(typeof Node=="undefined")Node={ELEMENT_NODE:1,ATTRIBUTE_NODE:2,TEXT_NODE:3,CDATA_SECTION_NODE:4,ENTITY_REFERENCE_NODE:5,ENTITY_NODE:6,PROCESSING_INSTRUCTION_NODE:7,COMMENT_NODE:8,DOCUMENT_NODE:9,DOCUMENT_TYPE_NODE:10,DOCUMENT_FRAGMENT_NODE:11,NOTATION_NODE:12};o.console||(o.console={log:n,error:n});var R,q=_.each,S=_.extend,k=o.jQuery,W=k.browser.msie;function r(){o.console.log.apply(this,arguments)}function $(){o.console.error.apply(this,arguments)}var m=o.angular||(o.angular={}),Ca=m.validator||
+(m.validator={}),s=m.filter||(m.filter={}),ca=m.callbacks||(m.callbacks={});m.alert||(m.alert=function(){r(arguments);o.alert.apply(o,arguments)});ia.prototype={load:function(){this.Fb();this.Na("/stylesheets/jquery-ui/smoothness/jquery-ui-1.7.1.css");this.Na("/stylesheets/css");r("Server: "+this.i.z);this.Eb();this.Db();this.zb()},Eb:function(){r("Loader.configureJQueryPlugins()");k.fn.scope=function(){for(var a=this;a&&a.get(0);){var b=a.data("scope");if(b)return b;a=a.parent()}return null};k.fn.controller=
+function(){return this.data("controller")||Q.Yb}},Ic:function(){return""+(new Date).getTime()},Db:function(){var a=this.i;if(!a.G){var b=a.z.match(/https?:\/\/([\w]*)/);a.G=b?b[1]:"$MEMORY"}},zb:function(){function a(){g.Sb(function(l){!l&&c.find("[ng-auth=eager]").length&&g.ja()})}r("Loader.bindHtml()");var b=new ja(this.location),c=this.document,d=new na(this.i.z,this.i.G),e=new z(c[0],d,b,this.i);d.tc=Ea(e,e.e);d=new P(c.find("body"),this.i.z);var f=this.i.G=="$MEMORY"?new aa(this.window):new ka(this.i.z,
+k.getScript);f=new la(f,new U(k(c.body)),function(){e.c()});var g=new ma(f,d),h="/data/"+this.i.G,i=new T(function(l,p){f.N("POST",h,l,p)},g,e.anchor);e.cb.push(function(){i.Fa()});var j=new w({$anchor:e.anchor,$binder:e,$config:this.i,$console:o.console,$datastore:i,$save:function(l){i.Cc(j.q,l,e.anchor)},$window:o,$uid:this.Ic,$users:g},"ROOT");c.data("scope",j);r("$binder.entity()");e.K(j);r("$binder.compile()");e.compile();r("ControlBar.bind()");d.bind();r("$users.fetchCurrentUser()");a();r("PopUp.bind()");
+(new B(c)).bind();r("$binder.parseAnchor()");e.Va();r("$binder.executeInit()");e.Rb();r("$binder.updateView()");e.c();b.La=ga(e,e.vc,b);b.Cd=function(){alert("update")};b.watch();c.find("body").show();r("ready()")},Fb:function(){var a=o.location.href+"#";a=a.split("#")[1];var b={Lb:null};a=a.split("&");for(var c=0;c<a.length;c++){var d=(a[c]+"=").split("=");b[d[0]]=d[1]}if(b.Lb=="console"){R=x.createElement("div");R.id="ng-console";x.getElementsByTagName("body")[0].appendChild(R);r=function(){da("ng-console-info",
+arguments)};console.error=function(){da("ng-console-error",arguments)}}},Na:function(a){var b=x.createElement("link");b.rel="stylesheet";b.type="text/css";a.match(/^http:/)||(a=this.i.z+a);b.href=a;this.head[0].appendChild(b)}};ja.prototype={watch:function(){var a=this;function b(){if(a.L!==a.location.href){var c=a.location.hash.match(/^#\$iframe_notify=(.*)$/);if(c){a.L.match(/#/)||(a.L+="#");a.location.href=a.L;c="_iframe_notify_"+c[1];var d=ca[c];delete ca[c];try{(d||n)()}catch(e){alert(e)}}else{a.La(a.location.href);
+a.L=a.location.href}}a.setTimeout(b,a.delay)}b()},Fc:function(a){var b=o.location.href;b.match(/#/)||(b+="#");if(b!=a)o.location.href=a;this.xd=a},Ha:function(){return o.location.href}};m.compile=function(a,b){b=b||{};(new ia(a,k("head"),_({z:""}).extend(b))).load();var c=k(a).scope();return{updateView:function(){return c.c.apply(c,arguments)},set:function(){return c.j.apply(c,arguments)},get:function(){return c.get.apply(c,arguments)}}};var H={typeOf:function(a){if(a===null)return"null";var b=typeof a;
+if(b=="object"){if(a instanceof Array)return"array";if(a instanceof Date)return"date";if(a.nodeType==1)return"element"}return b}},V={},Fa={includeIf:function(a,b,c){var d=_.indexOf(a,b);if(c)d==-1&&a.push(b);else a.splice(d,1);return a},sum:function(a,b){b=m.Function.compile(b);for(var c=0,d=0;d<a.length;d++){var e=1*b(a[d]);isNaN(e)||(c+=e)}return c},remove:function(a,b){var c=_.indexOf(a,b);c>=0&&a.splice(c,1);return b},find:function(a,b,c){if(b){var d=m.Function.compile(b);_.detect(a,function(e){if(d(e)){c=
+e;return true}});return c}},findById:function(a,b){return m.Xc.find(a,function(c){return c.A==b},null)},filter:function(a,b){var c=[];c.Ab=function(j){for(var l=0;l<c.length;l++)if(!c[l](j))return false;return true};var d=w.M;function e(j,l){if(l.charAt(0)==="!")return!e(j,l.substr(1));switch(typeof j){case "boolean":case "number":case "string":return(""+j).toLowerCase().indexOf(l)>-1;case "object":for(var p in j)if(p.charAt(0)!=="$"&&e(j[p],l))return true;return false;case "array":for(p=0;p<j.length;p++)if(e(j[p],
+l))return true;return false;default:return false}}switch(typeof b){case "boolean":case "number":case "string":b={Rc:b};case "object":for(var f in b)f=="$"?function(){var j=(""+b[f]).toLowerCase();j&&c.push(function(l){return e(l,j)})}():function(){var j=f,l=(""+b[f]).toLowerCase();l&&c.push(function(p){return e(d(p,j),l)})}();break;case "function":c.push(b);break;default:return a}for(var g=[],h=0;h<a.length;h++){var i=a[h];c.Ab(i)&&g.push(i)}return g},add:function(a,b){a.push(_.isUndefined(b)?{}:
+b);return a},count:function(a,b){if(!b)return a.length;var c=m.Function.compile(b);return _.reduce(a,0,function(d,e){return d+(c(e)?1:0)})},orderBy:function(a,b,c){function d(f,g){return X(g)?function(h,i){return f(i,h)}:f}function e(f,g){var h=typeof f,i=typeof g;if(h==i){if(h=="string")f=f.toLowerCase();if(h=="string")g=g.toLowerCase();if(f===g)return 0;return f<g?-1:1}else return h<i?-1:1}b=_.isArray(b)?b:[b];b=_.map(b,function(f){var g=false;if(typeof f=="string"&&(f.charAt(0)=="+"||f.charAt(0)==
+"-")){g=f.charAt(0)=="-";f=f.substring(1)}var h=f?m.Function.compile(f):_.identity;return d(function(i,j){return e(h(i),h(j))},g)});return _.clone(a).sort(d(function(f,g){for(var h=0;h<b.length;h++){var i=b[h](f,g);if(i!==0)return i}return 0},c))},orderByToggle:function(a,b){var c=false,d=-1;_.detect(a,function(e,f){if(e==b){c=true;d=f;return true}if((e.charAt(0)=="+"||e.charAt(0)=="-")&&e.substring(1)==b){c=e.charAt(0)=="+";d=f;return true}});d>=0&&a.splice(d,1);a.unshift((c?"-":"+")+b);return a},
+orderByDirection:function(a,b,c,d){c=c||"ng-ascend";d=d||"ng-descend";a=a[0]||"";var e=true;if(a.charAt(0)=="-"){a=a.substring(1);e=false}else if(a.charAt(0)=="+")a=a.substring(1);return a==b?e?c:d:""},merge:function(a,b,c){var d=a[b];if(!d){d={};a[b]=d}Y(c,d);return a}},Ga={quote:function(a){return'"'+a.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/\t/g,"\\t").replace(/\v/g,"\\v")+'"'},quoteUnicode:function(a){a=m.String.quote(a);
+for(var b=[],c=0;c<a.length;c++){var d=a.charCodeAt(c);if(d<128)b.push(a.charAt(c));else{d="000"+d.toString(16);b.push("\\u"+d.substring(d.length-4))}}return b.join("")},toDate:function(a){var b;if(typeof a=="string"&&(b=a.match(/^(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z$/))){a=new Date(0);a.setUTCFullYear(b[1],b[2]-1,b[3]);a.setUTCHours(b[4],b[5],b[6],0);return a}return a}},Ha={toString:function(a){function b(c){return c<10?"0"+c:c}return a.getUTCFullYear()+"-"+b(a.getUTCMonth()+1)+"-"+b(a.getUTCDate())+
+"T"+b(a.getUTCHours())+":"+b(a.getUTCMinutes())+":"+b(a.getUTCSeconds())+"Z"}},Ia={compile:function(a){if(_.isFunction(a))return a;else if(a){var b=new w;return function(c){b.q=c;return b.eval(a)}}else return function(c){return c}}};G("Global",[H],["extend","clone","isEqual","isElement","isArray","isFunction","isUndefined"]);G("Collection",[H,V],["each","map","reduce","reduceRight","detect","select","reject","all","any","include","invoke","pluck","max","min","sortBy","sortedIndex","toArray","size"]);
+G("Array",[H,V,Fa],["first","last","compact","flatten","without","uniq","intersect","zip","indexOf","lastIndexOf"]);G("Object",[H,V,{}],["keys","values"]);G("String",[H,Ga],[]);G("Date",[H,Ha],[]);G("Function",[H,V,Ia],["bind","bindAll","delay","defer","wrap","compose"]);z.$=function(a){for(var b=[],c=0,d;(d=a.indexOf("{{",c))>-1;){c<d&&b.push(a.substr(c,d-c));c=d;d=a.indexOf("}}",d);d=d<0?a.length:d+2;b.push(a.substr(c,d-c));c=d}c!=a.length&&b.push(a.substr(c,a.length-c));return b.length===0?[a]:
+b};z.Xb=function(a){a=z.$(a);return a.length>1||z.J(a[0])!==null};z.J=function(a){return(a=a.replace(/\n/gm," ").match(/^\{\{(.*)\}\}$/))?a[1]:null};z.prototype={wc:function(a){var b={};a.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,function(c,d,e){if(d)b[decodeURIComponent(d)]=decodeURIComponent(e)});return b},Va:function(a){var b=this;a=a||this.pa.Ha();var c=a.indexOf("#");if(!(c<0)){a=this.wc(a.substring(c+1));q(b.anchor,function(d,e){delete b.anchor[e]});q(a,function(d,e){b.anchor[e]=d})}},vc:function(a){r("URL change detected",
+a);this.Va(a);this.c()},Jc:function(){var a=this.pa.Ha(),b=a.indexOf("#");if(b>-1)a=a.substring(0,b);a+="#";b="";for(var c in this.anchor){var d=this.anchor[c];if(typeof d==="undefined"||d===null)delete this.anchor[c];else{a+=b+encodeURIComponent(c);if(d!==true)a+="="+encodeURIComponent(d);b="&"}}this.pa.Fc(a);return a},c:function(){(new Date).getTime();var a=k(this.C).scope();a.j("$invalidWidgets",[]);a.c();(new Date).getTime();this.Jc();_.each(this.cb,function(b){b()})},U:function(a){var b=k(this.C),
+c=b.find(a);if(b.is(a))c=c.andSelf();return c},Rb:function(){this.U("[ng-init]").each(function(){var a=k(this),b=a.scope();try{b.eval(a.attr("ng-init"))}catch(c){alert("EVAL ERROR:\n"+a.attr("ng-init")+"\n"+y(c,true))}})},K:function(a){this.U("[ng-entity]").attr("ng-watch",function(){try{var b=k(this);return a.K(b.attr("ng-entity"))+(b.attr("ng-watch")||"")}catch(c){alert(c)}})},compile:function(){var a=k(this.C),b=this;if(this.i.bd){var c=this.U(":submit").not("[ng-action]");c.attr("ng-action","$save()");
+c.not(":disabled").not("ng-bind-attr").attr("ng-bind-attr",'{disabled:"{{$invalidWidgets}}"}')}this.Wa(this.C)(this.C,a.scope(),"");this.U("a[ng-action]").live("click",function(){var d=k(this);try{d.scope().eval(d.attr("ng-action"));d.removeAttr("ng-error");d.removeClass("ng-exception")}catch(e){d.addClass("ng-exception");d.attr("ng-error",y(e,true))}b.c();return false})},Hc:function(a,b,c){b=b.concat();var d=b.pop(),e=z.$(a.nodeValue);if(e.length>1||z.J(e[0])){var f=a.parentNode;if(ea(f)){f.setAttribute("ng-bind-template",
+a.nodeValue);c.push({path:b,b:function(l){return new N(l,l.getAttribute("ng-bind-template"))}})}else for(var g=0;g<e.length;g++){var h=e[g],i=z.J(h),j;if(i){j=x.createElement("span");k(j).attr("ng-bind",i);g===0&&c.push({path:b.concat(d+g),b:this.Ta})}else if(W&&h.charAt(0)==" "){j=x.createElement("span");j.innerHTML="&nbsp;"+h.substring(1)}else j=x.createTextNode(h);f.insertBefore(j,a)}f.removeChild(a)}},Wa:function(a){var b=[];this.Xa(a,[],b);return function(c,d,e){for(var f=b.length,g=0;g<f;g++){for(var h=
+b[g],i=c,j=h.path,l=0;l<j.length;l++)i=i.childNodes[j[l]];try{d.ub(h.b(i,d,e))}catch(p){alert(p)}}}},Xa:function(a,b,c){var d=a.nodeType;if(d==Node.TEXT_NODE)this.Hc(a,b,c);else if(!(d!=Node.ELEMENT_NODE&&d!=Node.DOCUMENT_NODE))if(a.getAttribute){d=a.getAttribute("ng-non-bindable");if(!(d||d==="")){if(d=a.attributes){var e=a.getAttribute("ng-bind-attr");a.removeAttribute("ng-bind-attr");e=e?O(e):{};for(var f=d.length,g=0;g<f;g++){var h=d[g],i=h.name;h=W&&i=="href"?decodeURI(a.getAttribute(i,2)):h.value;
+if(z.Xb(h))e[i]=h}d=y(e);d.length>2&&a.setAttribute("ng-bind-attr",d)}a.getAttribute||r(a);var j=a.getAttribute("ng-repeat");if(j){a.removeAttribute("ng-repeat");var l=this.Wa(a);d=x.createComment("ng-repeat: "+j);e=a.parentNode;e.insertBefore(d,a);e.removeChild(a);function p(t,u,A){var I=k(a).clone();I.css("display","");I.attr("ng-repeat-index",""+A);I.data("scope",t);l(I[0],t,u+A+":");return I}c.push({path:b,b:function(t,u,A){return new Ba(k(t),j,p,A)}})}else{a.getAttribute("ng-eval")&&c.push({path:b,
+b:this.nc});a.getAttribute("ng-bind")&&c.push({path:b,b:this.Ta});a.getAttribute("ng-bind-attr")&&c.push({path:b,b:this.jc});a.getAttribute("ng-hide")&&c.push({path:b,b:this.oc});a.getAttribute("ng-show")&&c.push({path:b,b:this.pc});a.getAttribute("ng-class")&&c.push({path:b,b:this.kc});a.getAttribute("ng-class-odd")&&c.push({path:b,b:this.mc});a.getAttribute("ng-class-even")&&c.push({path:b,b:this.lc});a.getAttribute("ng-style")&&c.push({path:b,b:this.qc});a.getAttribute("ng-watch")&&c.push({path:b,
+b:this.rc});d=a.nodeName;if(d=="INPUT"||d=="TEXTAREA"||d=="SELECT"||d=="BUTTON"){var C=this;c.push({path:b,b:function(t,u,A){t.name=A+t.name.split(":").pop();return C.Pc.Gb(k(t),u)}})}if(d=="OPTION")if(!k("<select/>").append(k(a).clone()).html().match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi))a.value=a.text;d=a.childNodes;for(e=0;e<d.length;e++)this.Xa(d[e],b.concat(e),c)}}}},nc:function(a){return new ua(a,a.getAttribute("ng-eval"))},Ta:function(a){return new N(a,"{{"+a.getAttribute("ng-bind")+
+"}}")},jc:function(a){return new ta(a,O(a.getAttribute("ng-bind-attr")))},oc:function(a){return new va(a,a.getAttribute("ng-hide"))},pc:function(a){return new wa(a,a.getAttribute("ng-show"))},kc:function(a){return new xa(a,a.getAttribute("ng-class"))},lc:function(a){return new ya(a,a.getAttribute("ng-class-even"))},mc:function(a){return new za(a,a.getAttribute("ng-class-odd"))},qc:function(a){return new Aa(a,a.getAttribute("ng-style"))},rc:function(a,b){b.watch(a.getAttribute("ng-watch"))}};P.Yc=
+'<div><div class="ui-widget-overlay"></div><div id="ng-login" ng-non-bindable="true"><div class="ng-login-container"></div></div></div>';P.mb='<div ng-non-bindable="true" title="Permission Error:">Sorry, you do not have permission for this!</div>';P.prototype={bind:J(),ja:function(a){this.F.push(a);this.F.length==1&&this.Ca("/user_session/new.mini?return_url="+encodeURIComponent(this.db()))},ec:function(a){this.F.push(a);this.F.length==1&&this.Ca("/user_session/do_destroy.mini")},db:function(){return this.window.location.href.split("#")[0]},
+Ca:function(a){var b=this,c=(new Date).getTime(),d=this.db();d+="#$iframe_notify="+c;var e=k('<div style="overflow:hidden; padding:2px 0 0 0;"><iframe name="'+d+'" src="'+this.da+a+'" width="500" height="330"/></div>');this.document.append(e);e.Ba({height:363,width:500,Hd:false,gc:true,title:'Authentication: <a href="http://www.getangular.com"><tt>&lt;angular/&gt;</tt></a>'});callbacks["_iframe_notify_"+c]=function(){e.Ba("destroy");e.remove();q(b.F,function(f){f()});b.F=[]}},Ua:function(){if(!this.Ga){this.Ga=
+k(P.mb);this.Ga.Ba({gd:true,height:70,gc:true})}}};T.nb=S(J(),{all:function(){return[]},query:function(){return[]},load:function(){return{}},title:undefined});T.prototype={T:function(a){if(!a instanceof E)throw"Parameter must be an instance of Entity! "+y(a);var b=a.Q+"/"+a.A,c=this.B[b];if(c)E.ga(a,c);else c=this.B[b]=a;return c},load:function(a,b,c,d){if(b&&b!=="*"){var e=this;this.D(["GET",a.Q+"/"+b],function(f){a.R(f);a.ib();f=a.Sc(a);e.T(f);(c||n)(a)},d)}return a},Oa:function(a,b,c){var d=this,
+e=[],f=0;q(b,function(g){e.push(d.load(a(),g,function(){f++;if(f==b.length)(c||n)(e)}))});return e},dc:function(a,b,c){return this.load(a,b,c,function(d){if(d.ea==404){a.A=b;(c||n)(a)}else throw d;})},cc:function(a,b){var c=this,d=[];d.ra=function(e){return e.Q==a.title};this.B.P.push(d);this.D(["GET",a.title],function(e){for(var f=0;f<e.length;f++){var g=a();g.R(e[f]);d.push(c.T(g))}(b||n)(d)});return d},save:function(a,b){var c=this,d={};a.jb(d);this.D(["POST","",d],function(e){a.R(e);var f=c.T(a);
+_.each(c.B.P,function(g){g.ra(a)&&m.Array.includeIf(g,f,true)});if(a.sa)c.anchor[a.sa]=a.A;b&&b(a)})},remove:function(a,b){var c=this,d={};a.jb(d);this.D(["DELETE","",d],function(e){delete c.B[a.Q+"/"+a.A];_.each(c.B.P,function(f){for(var g=0;g<f.length;g++)f[g].A==a.A&&f.splice(g,1)});(b||n)(e)})},D:function(a,b,c){a.gb=b;a.hb=c||function(d){throw d;};this.S.push(a)},Fa:function(){function a(d,e){r("RESPONSE["+d+"]: ",e);if(e.ea==401)b.eb.ja(function(){b.post(c,a)});else if(e.ea)alert(y(e));else for(d=
+0;d<e.length;d++){var f=e[d],g=c[d],h=f.ea;if(h)h==403?b.eb.Ua():g.hb(f);else g.gb(f)}}if(this.S.length!==0){var b=this,c=this.S;this.S=[];r("REQUEST:",c);this.post(c,a)}},Cc:function(a,b){function c(){d--;d===0&&b&&b()}var d=1;for(var e in a){var f=a[e];if(f&&f.ta==E.prototype.ta){d++;f.ta(c)}}c()},xc:function(a,b,c,d){var e=this,f=[];f.ra=K(false);this.B.P.push(f);this.D(["GET",a.title+"/"+b+"="+c],function(g){for(var h=0;h<g.length;h++){var i=(new a).R(g[h]);f.push(e.T(i))}d&&d(f)});return f},
+K:function(a,b){if(!a)return T.nb;var c=this,d=S(function(e){return new E(d,e)},{title:a,$$factory:true,datastore:this,defaults:b||{},load:function(e,f){return c.load(d(),e,f)},loadMany:function(e,f){return c.Oa(d,e,f)},loadOrCreate:function(e,f){return c.dc(d(),e,f)},all:function(e){return c.cc(d,e)},query:function(e,f,g){return c.xc(d,e,f,g)},properties:function(e){c.D(["GET",a+"/$properties"],e)}});return d},join:function(a){function b(){throw"Joined entities can not be instantiated into a document.";
+}var c=_(a).hd().map(function(d,e){return e}).sortBy(function(d){var e=[];do{if(_(e).include(d))throw"Infinite loop in join: "+e.join(" -> ");e.push(d);if(!a[d])throw _("Named entity '<%=name%>' is undefined.").template({name:d});d=a[d].Z?a[d].Z.substring(0,a[d].Z.indexOf(".")):undefined}while(d);return e.length}).value();if(_(c).select(function(d){return a[d].Z}).length!=c.length-1)throw"Exactly one entity needs to be primary.";b.query=function(d,e){var f=[],g=d?d.substring(0,d.indexOf(".")):undefined;
+if(g!=c[0])throw _("Named entity '<%=name%>' is not a primary entity.").template({name:g});var h=1;a[g].join.query(d.substring(d.indexOf(".")+1),e,function(i){var j=c[h++],l=a[j],p=l.Z,C={};_(i).each(function(t){var u={};f.push(u);u[g]=t;t=w.M(u,p);C[t]=t});l.join.Oa(_.toArray(C),function(t){var u={};_(t).each(function(A){u[A.A]=A});_(f).each(function(A){var I=w.M(A,p);A[j]=u[I]})})});return f};return b}};s.h=function(a){if(a)for(var b in a)this[b]=a[b]};s.h.get=function(a,b){b=b||"text";switch(typeof a){case "string":return b==
+"text"?a:undefined;case "object":if(a&&typeof a[b]!=="undefined")return a[b];return;default:return a}};var v;q({currency:function(a){k(this.element).toggleClass("ng-format-negative",a<0);return"$"+s.number.apply(this,[a,2])},number:function(a,b){if(isNaN(a)||!isFinite(a))return"";b=typeof b=="undefined"?2:b;var c=a<0;a=Math.abs(a);var d=Math.pow(10,b);a=""+Math.round(a*d);var e=a.substring(0,a.length-b);e=e||"0";d=a.substring(a.length-b);a=c?"-":"";for(c=0;c<e.length;c++){if((e.length-c)%3===0&&c!==
+0)a+=",";a+=e.charAt(c)}if(b>0){for(c=d.length;c<b;c++)d+="0";a+="."+d.substring(0,b)}return a},date:J(),json:function(a){k(this.element).addClass("ng-monospace");return y(a,true)},trackPackage:function(){var a=[{name:"UPS",url:"http://wwwapps.ups.com/WebTracking/processInputRequest?sort_by=status&tracknums_displayed=1&TypeOfInquiryNumber=T&loc=en_US&track.x=0&track.y=0&InquiryNumber1=",na:[/^1Z[0-9A-Z]{16}$/i]},{name:"FedEx",url:"http://www.fedex.com/Tracking?tracknumbers=",na:[/^96\d{10}?$/i,/^96\d{17}?$/i,
+/^96\d{20}?$/i,/^\d{15}$/i,/^\d{12}$/i]},{name:"USPS",url:"http://trkcnfrm1.smi.usps.com/PTSInternetWeb/InterLabelInquiry.do?origTrackNum=",na:[/^(91\d{20})$/i,/^(91\d{18})$/i]}];return function(b,c){b=b.replace(/^ */,"").replace(/ *$/,"");var d=b.replace(/ /g,""),e;q(a,function(f){q(f.na,function(g){if(g.test(d)){g=f.name+": "+b;var h=f.url+b;e=new s.h({text:g,url:h,html:'<a href="'+Da(h)+'">'+g+"</a>",Ld:b});_.breakLoop()}});e&&_.breakLoop()});return e?e:b?c||new s.h({text:b+" is not recognized"}):
+null}}(),link:function(a,b){b=b||s.h.get(a);var c=s.h.get(a,"url")||s.h.get(a);if(c){if(m.O.wd(c)===null)c="mailto:"+c;a='<a href="'+L(c)+'">'+b+"</a>";return new s.h({text:b,url:c,html:a})}return a},bytes:function(){var a=["bytes","KB","MB","GB","TB","PB"];return function(b){if(b===null)return"";for(var c=0;b>1E3;){b/=1024;c++}b=""+b;var d=b.indexOf(".");if(d>-1&&d+2<b.length)b=b.substring(0,d+2);return b+" "+a[c]}}(),image:function(a,b,c){if(a&&a.url){var d="";if(b)d=' style="max-width: '+b+"px; max-height: "+
+(c||b)+'px;"';return new s.h({url:a.url,text:a.url,html:'<img src="'+a.url+'"'+d+"/>"})}return null},lowercase:function(a){return(a=s.h.get(a))?(""+a).toLowerCase():a},uppercase:function(a){return(a=s.h.get(a))?(""+a).toUpperCase():a},linecount:function(a){a=s.h.get(a);if(a===""||!a)return 1;return a.split(/\n|\f/).length},"if":function(a,b){return b?a:undefined},unless:function(a,b){return b?undefined:a},googleChartApi:S(function(a,b,c,d){b=b||{};a={Bb:a,jd:v.Cb(b,"color"),pd:v.title(b),ld:v.Cb(b,
+"label"),kd:v.values(b),md:"bg,s,FFFFFF00"};if(_.isArray(b.Qc)){a.rd="x";a.qd="0:|"+b.Qc.join("|")}return v.encode(a,c,d)},{values:function(a){var b=[];q(a.Ec||[],function(c){var d=[];q(c.values||[],function(e){d.push(e)});b.push(d.join(","))});a=b.join("|");return a===""?null:"t:"+a},title:function(a){var b=[];a=a.title||[];q(_.isArray(a)?a:[a],function(c){b.push(encodeURIComponent(c))});return b.join("|")},collect:function(a,b){var c=[],d=0;q(a.Ec||[],function(e){var f=[];e=e[b]||[];q(_.isArray(e)?
+e:[e],function(g){f.push(encodeURIComponent(g));d++});c.push(f.join("|"))});return d?c.join(","):null},encode:function(a,b,c){b=b||200;c=c||b;var d="http://chart.apis.google.com/chart?",e=[];a.od=b+"x"+c;q(a,function(f,g){f&&e.push(g+"="+f)});e.sort();d+=e.join("&");return new s.h({url:d,html:'<img width="'+b+'" height="'+c+'" src="'+d+'"/>'})}}),qrcode:function(a,b,c){return v.encode({Bb:"qr",nd:encodeURIComponent(a)},b,c)},chart:{Ed:function(a,b,c){return v("p",a,b,c)},Fd:function(a,b,c){return v("p3",
+a,b,c)},Gd:function(a,b,c){return v("pc",a,b,c)},dd:function(a,b,c){return v("bhs",a,b,c)},cd:function(a,b,c){return v("bhg",a,b,c)},fd:function(a,b,c){return v("bvs",a,b,c)},ed:function(a,b,c){return v("bvg",a,b,c)},Ad:function(a,b,c){return v("lc",a,b,c)},Jd:function(a,b,c){return v("ls",a,b,c)},Id:function(a,b,c){return v("s",a,b,c)}},html:function(a){return new s.h({html:a})}},function(a,b){s[b]=a});v=s.googleChartApi;array=[].constructor;m.toJson=y;m.fromJson=O;E.ga=function(a,b){if(!(a===b||
+!a||!b)){var c=function(e,f,g){return g.substring(0,2)!=="$$"&&typeof e[g]!=="function"&&typeof f[g]!=="function"};for(var d in b)c(a,b,d)&&delete b[d];for(d in a)if(c(a,b,d))b[d]=a[d]}};E.prototype={$migrate:function(){Y(this.$$entity.vd,this);return this},$save:function(a){this.$$entity.Jb.save(this,a===true?undefined:a);a===true&&this.$$entity.Jb.Fa();return this},$loadFrom:function(a){E.ga(a,this);return this},$saveTo:function(a){E.ga(this,a);return this}};F.ua={"null":K(null),"true":K(true),
+"false":K(false),"+":function(a,b,c){return(b||0)+(c||0)},"-":function(a,b,c){return(b||0)-(c||0)},"*":function(a,b,c){return b*c},"/":function(a,b,c){return b/c},"%":function(a,b,c){return b%c},"^":function(a,b,c){return b^c},"=":function(a,b,c){return a.scope.j(b,c)},"==":function(a,b,c){return b==c},"!=":function(a,b,c){return b!=c},"<":function(a,b,c){return b<c},">":function(a,b,c){return b>c},"<=":function(a,b,c){return b<=c},">=":function(a,b,c){return b>=c},"&&":function(a,b,c){return b&&
+c},"||":function(a,b,c){return b||c},"&":function(a,b,c){return b&c},"|":function(a,b,c){return c(a,b)},"!":function(a,b){return!b}};F.lb={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'};F.prototype={H:function(){return this.index+1<this.text.length?this.text.charAt(this.index+1):false},parse:function(){for(var a=this.g,b=F.ua,c=true;this.index<this.text.length;){var d=this.text.charAt(this.index);if(d=='"'||d=="'"){this.Ac(d);c=true}else if(d=="("||d=="["){a.push({index:this.index,text:d});
+this.index++}else if(d=="{"){c=this.H();if(c==":"||c=="("){a.push({index:this.index,text:d+c});this.index++}else a.push({index:this.index,text:d});this.index++;c=true}else if(d==")"||d=="]"||d=="}"){a.push({index:this.index,text:d});this.index++;c=false}else if(d==":"||d=="."||d==","||d==";"){a.push({index:this.index,text:d});this.index++;c=true}else if(c&&d=="/"){this.zc();c=false}else if(this.ha(d)){this.yc();c=false}else if(this.X(d)){this.Ya();c=false}else if(this.$b(d))this.index++;else{c=d+
+this.H();var e=b[d],f=b[c];if(f){a.push({index:this.index,text:c,b:f});this.index+=2}else if(e){a.push({index:this.index,text:d,b:e});this.index+=1}else throw"Lexer Error: Unexpected next character ["+this.text.substring(this.index)+"] in expression '"+this.text+"' at column '"+(this.index+1)+"'.";c=true}}return a},ha:function(a){return"0"<=a&&a<="9"},$b:function(a){return a==" "||a=="\r"||a=="\t"||a=="\n"||a=="\u000b"},X:function(a){return"a"<=a&&a<="z"||"A"<=a&&a<="Z"||"_"==a||a=="$"},yc:function(){for(var a=
+"",b=this.index;this.index<this.text.length;){var c=this.text.charAt(this.index);if(c=="."||this.ha(c))a+=c;else break;this.index++}a=1*a;this.g.push({index:b,text:a,b:function(){return a}})},Ya:function(){for(var a="",b=this.index;this.index<this.text.length;){var c=this.text.charAt(this.index);if(c=="."||this.X(c)||this.ha(c))a+=c;else break;this.index++}c=F.ua[a];if(!c){c=function(d){return d.scope.get(a)};c.W=a}this.g.push({index:b,text:a,b:c})},Ac:function(a){var b=this.index,c=this.Kb;this.index++;
+for(var d="",e=false;this.index<this.text.length;){var f=this.text.charAt(this.index);if(e){if(f=="u"){f=this.text.substring(this.index+1,this.index+5);this.index+=4;d+=String.fromCharCode(parseInt(f,16))}else{e=F.lb[f];d+=e?e:f}e=false}else if(f=="\\")e=true;else if(f==a){this.index++;this.g.push({index:b,text:d,b:function(){return d.length==c?m.String.toDate(d):d}});return}else d+=f;this.index++}throw"Lexer Error: Unterminated quote ["+this.text.substring(b)+"] starting at column '"+(b+1)+"' in expression '"+
+this.text+"'.";},zc:function(){var a=this.index;this.index++;for(var b="",c=false;this.index<this.text.length;){var d=this.text.charAt(this.index);if(c){b+=d;c=false}else if(d==="\\"){b+=d;c=true}else if(d==="/"){this.index++;c="";if(this.X(this.text.charAt(this.index))){this.Ya();c=this.g.pop().text}var e=new RegExp(b,c);this.g.push({index:a,text:b,yd:c,b:function(){return e}});return}else b+=d;this.index++}throw"Lexer Error: Unterminated RegExp ["+this.text.substring(a)+"] starting at column '"+
+(a+1)+"' in expression '"+this.text+"'.";}};D.ob=K(0);D.prototype={error:function(a,b){throw"Token '"+b.text+"' is "+a+" at column='"+(b.index+1)+"' of expression '"+this.text+"' starting at '"+this.text.substring(b.index)+"'.";},aa:function(){if(this.g.length===0)throw"Unexpected end of expression: "+this.text;return this.g[0]},H:function(a,b,c,d){var e=this.g;if(e.length>0){e=e[0];var f=e.text;if(f==a||f==b||f==c||f==d||!a&&!b&&!c&&!d)return e}return false},a:function(a,b,c,d){if(a=this.H(a,b,c,
+d)){this.g.shift();return this.sd=a}return false},k:function(a){if(!this.a(a)){var b=this.H();throw"Expecting '"+a+"' at column '"+(b.index+1)+"' in '"+this.text+"' got '"+this.text.substring(b.index)+"'.";}},pb:function(a,b){var c=b.apply(this);return function(d){return a(d,c(d))}},s:function(a,b,c){var d=c.apply(this);return function(e){return b(e,a(e),d(e))}},Ia:function(){return this.g.length>0},I:function(){if(this.g.length!==0)throw"Did not understand '"+this.text.substring(this.g[0].index)+
+"' while evaluating '"+this.text+"'.";},oa:function(){for(var a=[];;){this.g.length>0&&!this.H("}",")",";","]")&&a.push(this.Ea());if(!this.a(";"))return function(b){for(var c,d=0;d<a.length;d++){var e=a[d];if(e)c=e(b)}return c}}},Ea:function(){for(var a=this.o(),b;;)if(b=this.a("|"))a=this.s(a,b.b,this.filter);else return a},filter:function(){return this.wa(m.filter)},O:function(){return this.wa(m.validator)},wa:function(a){for(var b=this.Wb(a),c=[];;)if(this.a(":"))c.push(this.o());else{var d=function(e,
+f){f=[f];for(var g=0;g<c.length;g++)f.push(c[g](e));return b.apply(e,f)};return function(){return d}}},o:function(){return this.Gc()},Gc:function(){if(this.a("throw")){var a=this.ya();return function(b){throw a(b);}}else return this.ya()},ya:function(){var a=this.Ra(),b;if(b=this.a("=")){if(!a.W)throw"Left hand side '"+this.text.substring(0,b.index)+"' of assignment '"+this.text.substring(b.index)+"' is not assignable.";return this.s(function(){return a.W},b.b,this.Ra)}else return a},Ra:function(){for(var a=
+this.Qa(),b;;)if(b=this.a("||"))a=this.s(a,b.b,this.Qa);else return a},Qa:function(){for(var a=this.Sa(),b;;)if(b=this.a("&&"))a=this.s(a,b.b,this.Sa);else return a},Sa:function(){var a;return(a=this.a("!"))?this.pb(a.b,this.Da):this.Da()},Da:function(){for(var a=this.Za(),b;;)if(b=this.a("==","!="))a=this.s(a,b.b,this.Za);else return a},Za:function(){for(var a=this.xa(),b;;)if(b=this.a("<",">","<=",">="))a=this.s(a,b.b,this.xa);else return a},xa:function(){for(var a=this.la(),b;b=this.a("+","-");)a=
+this.s(a,b.b,this.la);return a},la:function(){for(var a=this.bb(),b;b=this.a("*","/","%");)a=this.s(a,b.b,this.bb);return a},bb:function(){var a;return this.a("+")?this.ba():(a=this.a("-"))?this.s(D.ob,a.b,this.la):this.ba()},Wb:function(a){var b=this.a(),c=b.text.split(".");a=a;for(var d,e=0;e<c.length;e++){d=c[e];if(a)a=a[d]}if(typeof a!="function")throw"Function '"+b.text+"' at column '"+(b.index+1)+"' in '"+this.text+"' is not defined.";return a},ba:function(){var a;if(this.a("(")){a=this.Ea();
+this.k(")");a=a}else if(this.a("["))a=this.vb();else if(this.a("{"))a=this.object();else if(this.a("{:"))a=this.za(false);else if(this.a("{("))a=this.za(true);else{var b=this.a();(a=b.b)||this.error("not a primary expression",b)}for(;b=this.a("(","[",".");)if(b.text==="(")a=this.Vb(a);else if(b.text==="[")a=this.sc(a);else if(b.text===".")a=this.Tb(a);else throw"IMPOSSIBLE";return a},za:function(a){var b=[];if(a){if(!this.a(")")){for(b.push(this.a().text);this.a(",");)b.push(this.a().text);this.k(")")}this.k(":")}var c=
+this.oa();this.k("}");return function(d){return function(e){var f=new w(d.scope.q);f.j("$",e);for(var g=0;g<b.length;g++)f.j(b[g],arguments[g]);return c({scope:f})}}},Tb:function(a){var b=this.a().text;function c(d){return w.M(a(d),b)}c.W=b;return c},sc:function(a){var b=this.o();this.k("]");if(this.a("=")){var c=this.o();return function(d){return a(d)[b(d)]=c(d)}}else return function(d){var e=a(d);d=b(d);return e?e[d]:undefined}},Vb:function(a){var b=[];if(this.aa().text!=")"){do b.push(this.o());
+while(this.a(","))}this.k(")");return function(c){for(var d=[],e=0;e<b.length;e++)d.push(b[e](c));e=a(c);if(typeof e==="function")return e.apply(c,d);else throw"Expression '"+a.W+"' is not a function.";}},vb:function(){var a=[];if(this.aa().text!="]"){do a.push(this.o());while(this.a(","))}this.k("]");return function(b){for(var c=[],d=0;d<a.length;d++)c.push(a[d](b));return c}},object:function(){var a=[];if(this.aa().text!="}"){do{var b=this.a().text;this.k(":");var c=this.o();a.push({ac:b,value:c})}while(this.a(","))
+}this.k("}");return function(d){for(var e={},f=0;f<a.length;f++){var g=a[f],h=g.value(d);e[g.ac]=h}return e}},Qb:function(){for(var a=[];this.Ia();){a.push(this.Pb());this.a(";")||this.I()}return function(b){for(var c="",d=0;d<a.length;d++)c+=a[d](b);return c}},Pb:function(){var a=this.a().text,b,c;if(this.a("=")){b=a;a=this.a().text}if(this.a(":"))c=this.ba()(null);return function(d){var e=d.scope.get("$datastore").K(a,c);d.scope.j(a,e);if(b){e=e();e.sa=b;d.scope.j(b,e);return"$anchor."+b+":{"+b+
+"="+a+".load($anchor."+b+");"+b+".$$anchor="+m.String.quote(b)+";};"}else return""}},watch:function(){for(var a=[];this.Ia();){a.push(this.Oc());this.a(";")||this.I()}this.I();return function(b){for(var c=0;c<a.length;c++){var d=a[c](b);b.sb(d.name,d.b)}}},Oc:function(){var a=this.a().text;this.k(":");var b;if(this.aa().text=="{"){this.k("{");b=this.oa();this.k("}")}else b=this.o();return function(){return{name:a,b:b}}}};w.V={};w.M=function(a,b){if(!b)return a;for(var c=b.split("."),d,e=a,f=c.length,
+g=0;g<f;g++){d=c[g];if(!d.match(/^[\$\w][\$\w\d]*$/))throw"Expression '"+b+"' is not a valid expression for accesing variables.";if(a){e=a;a=a[d]}if(_.isUndefined(a)&&d.charAt(0)=="$"){var h=m.Global.typeOf(e);if(d=(h=m[h.charAt(0).toUpperCase()+h.substring(1)])?h[[d.substring(1)]]:undefined)return a=_.bind(d,e,e)}}if(typeof a==="function"&&!a.Tc)return ga(e,a);return a};w.prototype={c:function(){var a=this;this.Ub();_.each(this.fb,function(b){a.l(b,"",{},function(){this.c(a)})})},ub:function(a){a&&
+this.fb.push(a)},Zb:function(a){for(var b=0;b<a.length;b++){var c=a.charAt(b);if(c!="."&&!F.prototype.X(c))return false}return true},get:function(a){return w.M(this.q,a)},j:function(a,b){a=a.split(".");for(var c=this.q,d=0;a.length>1;d++){var e=a.shift(),f=c[e];if(!f){f={};c[e]=f}c=f}return c[a.shift()]=b},m:function(a,b){this.eval(a+"="+y(b))},eval:function(a,b){var c=w.V[a];if(!c){var d=new D(a);c=d.oa();d.I();w.V[a]=c}b=b||{};b.scope=this;return c(b)},l:function(a,b,c,d,e){try{var f=this.eval(b,
+c);if(a.w){a.w=false;k(a.view).removeClass("ng-exception").removeAttr("ng-error")}d&&d.apply(a,[f]);return true}catch(g){$("Eval Widget Error:",g);b=y(g,true);a.w=true;k(a.view).addClass("ng-exception").attr("ng-error",b);e&&e.apply(a,[g,b]);return false}},Mc:function(a,b){var c=w.V[a];if(!c){c=(new D(a)).O();w.V[a]=c}a={scope:this};return c(a)(a,b)},K:function(a){return(new D(a)).Qb()({scope:this})},fc:function(a){this.q.Uc.push(a)},watch:function(a){var b=this;(new D(a)).watch()({scope:this,sb:function(c,
+d){b.tb(c,function(e,f){try{return d({scope:b},e,f)}catch(g){alert(g)}})}})},tb:function(a,b){var c=this.qa[a];if(!c){c={Ma:[],o:a};this.qa[a]=c}c.Ma.push(b)},Ub:function(){var a=this,b=false;q(this.qa,function(c){var d=a.eval(c.o);if(d!==c.d){q(c.Ma,function(e){e(d,c.d);b=true});c.d=d}});return b}};ka.prototype={xb:function(a){return ba.Nb(a)},N:function(a,b,c,d){var e=this.Lc+this.hc++;ca[e]=function(h){delete m[e];d(200,h)};a={Md:b,Bd:a,Dd:c};a=this.xb(y(a));b=Math.ceil(a.length/this.ka);c=this.url+
+"/$/"+e+"/"+b+"/";for(var f=0;f<b;f++){var g=a.substr(f*this.ka,this.ka);this.getScript(c+(f+1)+"?h="+g,n)}}};aa.Zc="$DATASET:";aa.prototype={N:J()};la.prototype={N:function(a,b,c,d){var e=this;this.status.yb(c);this.Mb.N(a,b,c,function(){e.status.Ob();try{d.apply(this,arguments)}catch(f){alert(y(f))}e.update()})}};ma.prototype={fetchCurrentUser:function(a){var b=this;this.z.N("GET","/account.json",{},function(c,d){b.Ib=d.Kc;a(d.Kc)})},logout:function(a){var b=this;this.fa.ec(function(){delete b.Ib;
+(a||n)()})},login:function(a){var b=this;this.fa.ja(function(){b.Sb(function(){(a||n)()})})},notAuthorized:function(){this.fa.Ua()}};q({regexp:function(a,b,c){return a.match(b)?null:c||"Value does not match expected format "+b+"."},number:function(a,b,c){var d=1*a;if(d==a){if(typeof b!="undefined"&&d<b)return"Value can not be less than "+b+".";if(typeof b!="undefined"&&d>c)return"Value can not be greater than "+c+".";return null}else return"Value is not a number."},integer:function(a,b,c){b=Ca.number(a,
+b,c);if(b===null&&a!=Math.round(a))return"Value is not a whole number.";return b},date:function(a){if(a.match(/^\d\d?\/\d\d?\/\d\d\d\d$/))return null;return"Value is not a date. (Expecting format: 12/31/2009)."},ssn:function(a){if(a.match(/^\d\d\d-\d\d-\d\d\d\d$/))return null;return"SSN needs to be in 999-99-9999 format."},email:function(a){if(a.match(/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/))return null;return"Email needs to be in username@host.com format."},phone:function(a){if(a.match(/^1\(\d\d\d\)\d\d\d-\d\d\d\d$/))return null;
+if(a.match(/^\+\d{2,3} (\(\d{1,5}\))?[\d ]+\d$/))return null;return"Phone number needs to be in 1(987)654-3210 format in North America or +999 (123) 45678 906 internationaly."},url:function(a){if(a.match(/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/))return null;return"URL needs to be in http://server[:port]/path format."},json:function(a){try{O(a);return null}catch(b){return b.toString()}}},function(a,b){Ca[b]=a});na.prototype={Gb:function(a,b){var c,d=a.attr("type").toLowerCase(),
+e=a.attr("name");if(e)e=e.split(":").pop();var f="change",g=true;if(d=="button"||d=="submit"||d=="reset"||d=="image"){c=new Ja(a[0],e);f="click";g=false}else if(d=="text"||d=="textarea"||d=="hidden"||d=="password"){c=new oa(a[0],e);f="keyup change"}else if(d=="checkbox"){c=new pa(a[0],e);f="click"}else if(d=="radio"){c=new sa(a[0],e);f="click"}else if(d=="select-one")c=new qa(a[0],e);else if(d=="select-multiple")c=new ra(a[0],e);else if(d=="file")c=this.Hb(a,e);else throw"Unknown type: "+d;a.data("controller",
+c);var h=b.get("$binder");k(c.view,":input").bind(f,function(){if(c.e(b)){var i=k(c.view).attr("ng-action")||"";b.l(c,i)&&h.c(b)}return g});return c},Hb:function(a){var b="__uploadWidget_"+this.ic++,c=M.template(b);a.after(c);b=this.Aa({data:this.da+"/admin/ServerAPI.swf",width:"95",height:"20",align:"top",Od:"transparent"},{zd:"uploadWidgetId="+b,$c:"always"},b);a.remove();a=new M(c,a[0].name,b,this.da+"/data/"+this.G);k(b).data("controller",a);return a}};M.dispatchEvent=function(a,b,c){a=x.getElementById(a);
+a=k(a).data("controller");M.prototype["_on_"+b].apply(a,c)};M.template=function(a){return k('<span class="ng-upload-widget"><input type="checkbox" ng-non-bindable="true"/><object id="'+a+'" /><a></a><span/></span>')};M.prototype={e:function(a){var b=this.view.find("input").attr("checked")?this.value:null;if(this.d===b)return false;else{a.j(this.$a,b);return true}},c:function(a){if((a=a.get(this.$a))&&this.value!==a){this.value=a;this.view.find("a").attr("href",this.value.url).text(this.value.text);
+this.view.find("span").text(m.filter.bytes(this.value.size))}this.view.find("input").attr("checked",!!a)}};Q.prototype={e:K(true),c:n};Q.Yb=new Q;var Ja=Q;oa.prototype={e:function(a){var b=this.view.value;if(this.d===b)return false;else{a.m(this.exp,b);this.d=b;return true}},c:function(a){var b=this.view,c=a.get(this.exp);if(typeof c==="undefined"){c=this.p;a.m(this.exp,c)}c=c?c:"";if(this.d!=c)this.d=b.value=c;var d=false;b.removeAttribute("ng-error");if(this.Bc)d=!(c&&c.length>0);var e=d?"Required Value":
+null;if(!d&&this.O&&c){e=a.Mc(this.O,c);d=!!e}if(this.Ka!==e){this.Ka=d;if(e!==null){b.setAttribute("ng-error",e);a.fc(this)}k(b).toggleClass("ng-validation-error",d)}}};pa.prototype={e:function(a){var b=this.view;b=b.checked?b.value:"";if(this.d===b)return false;else{a.m(this.exp,b);this.d=b;return true}},c:function(a){var b=this.view,c=a.eval(this.exp);if(typeof c==="undefined"){c=this.p;a.m(this.exp,c)}b.checked=b.value==""+c}};qa.prototype={e:function(a){if(this.view.selectedIndex<0)a.m(this.exp,
+null);else{var b=this.view.value;if(this.d===b)return false;else{a.m(this.exp,b);this.d=b;return true}}},c:function(a){var b=this.view,c=a.get(this.exp);if(typeof c==="undefined"){c=this.p;a.m(this.exp,c)}if(c!==this.d){b.value=c?c:"";this.d=c}}};ra.prototype={selected:function(){for(var a=[],b=this.view.options,c=0;c<b.length;c++){var d=b[c];d.selected&&a.push(d.value)}return a},e:function(a){var b=this.selected();if(this.d===b)return false;else{a.m(this.exp,b);this.d=b;return true}},c:function(a){var b=
+this.view,c=a.get(this.exp);if(typeof c==="undefined"){c=this.p;a.m(this.exp,c)}if(c!==this.d){a=b.options;for(b=0;b<a.length;b++){var d=a[b];d.selected=_.include(c,d.value)}this.d=c}}};sa.prototype={e:function(a){var b=this.view;if(this.ia)return false;else{b.checked=true;this.d=a.m(this.exp,this.Ja);return this.ia=true}},c:function(a){var b=this.view,c=a.get(this.exp);if(this.p&&typeof c==="undefined"){c=this.p;a.m(this.exp,c)}if(this.d!=c){this.ia=b.checked=this.Ja==""+c;this.d=c}}};N.ab=function(a){switch(typeof a){case "string":case "boolean":case "number":return L(a);
+case "function":return N.ab(a());case "object":if(a&&a.tagName&&a.nodeName&&a.ownerDocument&&a.removeAttribute)return ha(a);else if(a instanceof m.filter.h){switch(typeof a.html){case "string":case "number":return a.html;case "function":return a.html();case "object":if(a.html&&a.html.tagName&&a.html.nodeName&&a.html.ownerDocument&&a.html.removeAttribute)return ha(a.html);default:break}switch(typeof a.text){case "string":case "number":return L(a.text);case "function":return L(a.text());default:break}}if(a===
+null)return"";return L(y(a,true));default:return""}};N.prototype={e:n,c:function(a){for(var b=[],c=this.exp,d=c.length,e=0;e<d;e++){var f=c[e],g=z.J(f);if(g){a.l(this,g,this.Dc,function(h){b.push(N.ab(h))},function(h,i){fa(this.view,i)});if(this.w)return}else b.push(L(f))}fa(this.view,b.join(""))}};ta.prototype={e:n,c:function(a){var b=k(this.view),c=this.wb;if(this.w){this.w=false;b.removeClass("ng-exception").removeAttr("ng-error")}var d=b.is("img");for(var e in c){for(var f=z.$(c[e]),g=[],h=0;h<
+f.length;h++){var i=z.J(f[h]);if(i)try{var j=a.eval(i,{element:b[0],attrName:e});if(j&&(j.constructor!==array||j.length!==0))g.push(j)}catch(l){this.w=true;$("BindAttrUpdater",l);i=y(l,true);g.push("["+i+"]");b.addClass("ng-exception").attr("ng-error",i)}else g.push(f[h])}f=g.length?g.join(""):null;if(d&&e=="src"&&!f)f=a.get("config.server")+"/images/blank.gif";b.attr(e,f)}}};ua.prototype={e:n,c:function(a){a.l(this,this.exp)}};va.prototype={e:n,c:function(a){a.l(this,this.exp,{},function(b){var c=
+k(this.view);X(b)?c.hide():c.show()})}};wa.prototype={e:n,c:function(a){a.l(this,this.exp,{},function(b){var c=k(this.view);X(b)?c.show():c.hide()})}};xa.prototype={e:n,c:function(a){a.l(this,this.exp,{},function(b){if(b!==null&&b!==undefined)this.view.className=b})}};ya.prototype={e:n,c:function(a){a.l(this,this.exp,{},function(b){var c=a.get("$index");k(this.view).toggleClass(b,c%2===1)})}};za.prototype={e:n,c:function(a){a.l(this,this.exp,{},function(b){var c=a.get("$index");k(this.view).toggleClass(b,
+c%2===0)})}};Aa.prototype={e:n,c:function(a){a.l(this,this.exp,{},function(b){k(this.view).attr("style","").css(b)})}};Ba.prototype={e:n,c:function(a){a.l(this,this.Y,{},function(b){var c=this;if(!b){b=[];a.Zb(this.Y)&&a.j(this.Y,b)}var d=b.length,e=this.children.length,f=this.view,g=0,h=null,i=this.bc,j=this.Nc,l=0;q(b,function(C,t){if(l<e){h=c.children[l];h.scope.j(j,C)}else{var u=new w(a.q,c.prefix+j+" in "+c.Y+"["+l+"]");u.j("$index",l);i&&u.j(i,t);u.j(j,C);h={scope:u,element:c.template(u,c.prefix,
+l)};f.after(h.element);c.children.push(h)}f=h.element;C=(new Date).getTime();h.scope.c();g+=(new Date).getTime()-C;l++});for(b=e;b>d;--b){var p=this.children.pop().element[0];p.parentNode.removeChild(p)}if(h&&h.element[0].nodeName==="OPTION")if(d=k(h.element[0].parentNode).data("controller")){d.d=undefined;d.c(a)}})}};B.va="mouseleave mouseout click dblclick keypress keyup";B.uc=function(){B.ma();var a=k(this);a.bind(B.va,B.ma);var b=a.position(),c=x.documentElement,d=(self.innerWidth||c&&c.clientWidth||
+x.body.clientWidth)-b.left;c=a.hasClass("ng-exception")?"EXCEPTION:":"Validation error...";a=a.attr("ng-error");d=d>375?"left":"right";c=k("<div id='ng-callout' style='width:300px'><div class='ng-arrow-"+d+"'/><div class='ng-title'>"+c+"</div><div class='ng-content'>"+a+"</div></div>");k("body").append(c);if(d==="left")a=b.left+this.offsetWidth+11;else{a=b.left-315;c.find(".ng-arrow-right").css({left:301})}c.css({left:a+"px",top:b.top-3+"px"});return true};B.ma=function(){k("#ng-callout").unbind(B.va,
+B.ma).remove();return true};B.prototype={bind:function(){this.C.find(".ng-validation-error,.ng-exception").live("mouseover",B.uc)}};U.kb='<div id="ng-spacer"></div><div id="ng-loading">loading....</div>';U.prototype={yb:function(){this.ca===0&&this.Pa.show();this.ca++},Ob:function(){this.ca--;this.ca===0&&this.Pa.hide("fold")}}})(window,document);
diff --git a/angular.js b/angular.js
index bea8200d..6450f438 100644
--- a/angular.js
+++ b/angular.js
@@ -1,3 +1,26 @@
+/**
+ * The MIT License
+ *
+ * Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
(function(window, document){
/**
*
@@ -140,11 +163,7 @@ var Base64 = {
return string;
}
-};// Copyright (C) 2008,2009 BRAT Tech LLC
-
-// IE compatibility
-
-if (typeof document.getAttribute == 'undefined')
+};if (typeof document.getAttribute == 'undefined')
document.getAttribute = function() {};
if (typeof Node == 'undefined') {
Node = {
@@ -163,16 +182,16 @@ if (typeof Node == 'undefined') {
};
}
-function noop() {};
+function noop() {}
+if (!window['console']) window['console']={'log':noop, 'error':noop};
var consoleNode,
foreach = _.each,
extend = _.extend,
- console = window['console'] || ({'log':noop, 'error':noop }),
jQuery = window['jQuery'],
msie = jQuery['browser']['msie'],
- log = function(){console.log.apply(this, arguments);},
- error = function(){console.error.apply(this, arguments);},
+ log = function(){window['console']['log'].apply(this, arguments);},
+ error = function(){window['console']['error'].apply(this, arguments);},
angular = window['angular'] || (window['angular'] = {}),
angularValidator = angular['validator'] || (angular['validator'] = {}),
angularFilter = angular['filter'] || (angular['filter'] = {}),
@@ -180,6 +199,7 @@ var consoleNode,
angularAlert = angular['alert'] || (angular['alert'] = function(){
log(arguments); window.alert.apply(window, arguments);
});
+
function consoleLog(level, objs) {
var log = document.createElement("div");
@@ -212,7 +232,7 @@ function isLeafNode (node) {
default:
return false;
}
-};
+}
function setHtml(node, html) {
if (isLeafNode(node)) {
@@ -233,14 +253,14 @@ function escapeHtml(html) {
replace(/&/g, '&amp;').
replace(/</g, '&lt;').
replace(/>/g, '&gt;');
-};
+}
function escapeAttr(html) {
if (!html || !html.replace)
return html;
return html.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g,
'&quot;');
-};
+}
function bind(_this, _function) {
if (!_this)
@@ -250,7 +270,7 @@ function bind(_this, _function) {
return function() {
return _function.apply(_this, arguments);
};
-};
+}
function shiftBind(_this, _function) {
return function() {
@@ -260,7 +280,7 @@ function shiftBind(_this, _function) {
}
return _function.apply(_this, args);
};
-};
+}
function outerHTML(node) {
var temp = document.createElement('div');
@@ -268,18 +288,18 @@ function outerHTML(node) {
var outerHTML = temp.innerHTML;
temp.removeChild(node);
return outerHTML;
-};
+}
function trim(str) {
return str.replace(/^ */, '').replace(/ *$/, '');
-};
+}
function toBoolean(value) {
var v = ("" + value).toLowerCase();
if (v == 'f' || v == '0' || v == 'false' || v == 'no')
value = false;
return !!value;
-};
+}
function merge(src, dst) {
for ( var key in src) {
@@ -292,7 +312,7 @@ function merge(src, dst) {
merge(src[key], value);
}
}
-};
+}
// ////////////////////////////
// Loader
@@ -303,7 +323,7 @@ function Loader(document, head, config) {
this.head = jQuery(head);
this.config = config;
this.location = window.location;
-};
+}
Loader.prototype = {
load: function() {
@@ -479,7 +499,7 @@ function UrlWatcher(location) {
return url;
};
this.expectedUrl = location.href;
-};
+}
UrlWatcher.prototype = {
watch: function() {
@@ -836,40 +856,41 @@ var angularFunction = {
}
};
-(function(){
- function define(dst, chain, names){
- foreach(chain, function(parent){
- extend(angular[dst], parent);
- });
- foreach(names, function(name){
- angular[dst][name] = _[name];
- });
- }
- define('Global', [angularGlobal],
- ['extend', 'clone','isEqual',
- 'isElement', 'isArray', 'isFunction', 'isUndefined']);
- define('Collection', [angularGlobal, angularCollection],
- ['each', 'map', 'reduce', 'reduceRight', 'detect',
- 'select', 'reject', 'all', 'any', 'include',
- 'invoke', 'pluck', 'max', 'min', 'sortBy',
- 'sortedIndex', 'toArray', 'size']);
- define('Array', [angularGlobal, angularCollection],
- ['first', 'last', 'compact', 'flatten', 'without',
- 'uniq', 'intersect', 'zip', 'indexOf', 'lastIndexOf']);
- define('Object', [angularGlobal, angularCollection],
- ['keys', 'values']);
- define('String', [angularGlobal]);
- define('Function', [angularGlobal],
- ['bind', 'bindAll', 'delay', 'defer', 'wrap', 'compose']);
-})();// Copyright (C) 2009 BRAT Tech LLC
-Binder = function(doc, widgetFactory, urlWatcher, config) {
+function defineApi(dst, chain, underscoreNames){
+ var lastChain = _.last(chain);
+ foreach(underscoreNames, function(name){
+ lastChain[name] = _[name];
+ });
+ angular[dst] = angular[dst] || {};
+ foreach(chain, function(parent){
+ extend(angular[dst], parent);
+ });
+}
+defineApi('Global', [angularGlobal],
+ ['extend', 'clone','isEqual',
+ 'isElement', 'isArray', 'isFunction', 'isUndefined']);
+defineApi('Collection', [angularGlobal, angularCollection],
+ ['each', 'map', 'reduce', 'reduceRight', 'detect',
+ 'select', 'reject', 'all', 'any', 'include',
+ 'invoke', 'pluck', 'max', 'min', 'sortBy',
+ 'sortedIndex', 'toArray', 'size']);
+defineApi('Array', [angularGlobal, angularCollection, angularArray],
+ ['first', 'last', 'compact', 'flatten', 'without',
+ 'uniq', 'intersect', 'zip', 'indexOf', 'lastIndexOf']);
+defineApi('Object', [angularGlobal, angularCollection, angularObject],
+ ['keys', 'values']);
+defineApi('String', [angularGlobal, angularString], []);
+defineApi('Date', [angularGlobal, angularDate], []);
+defineApi('Function', [angularGlobal, angularCollection, angularFunction],
+ ['bind', 'bindAll', 'delay', 'defer', 'wrap', 'compose']);
+function Binder(doc, widgetFactory, urlWatcher, config) {
this.doc = doc;
this.urlWatcher = urlWatcher;
this.anchor = {};
this.widgetFactory = widgetFactory;
this.config = config || {};
this.updateListeners = [];
-};
+}
Binder.parseBindings = function(string) {
var results = [];
@@ -902,327 +923,323 @@ Binder.binding = function(string) {
};
-Binder.prototype.parseQueryString = function(query) {
- var params = {};
- query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,
- function (match, left, right) {
- if (left) params[decodeURIComponent(left)] = decodeURIComponent(right);
- });
- return params;
-};
-
-Binder.prototype.parseAnchor = function(url) {
- var self = this;
- url = url || this.urlWatcher.getUrl();
-
- var anchorIndex = url.indexOf('#');
- if (anchorIndex < 0) return;
- var anchor = url.substring(anchorIndex + 1);
-
- var anchorQuery = this.parseQueryString(anchor);
- foreach(self.anchor, function(newValue, key) {
- delete self.anchor[key];
- });
- foreach(anchorQuery, function(newValue, key) {
- self.anchor[key] = newValue;
- });
-};
-
-Binder.prototype.onUrlChange = function (url) {
- log("URL change detected", url);
- this.parseAnchor(url);
- this.updateView();
-};
-
-Binder.prototype.updateAnchor = function() {
- var url = this.urlWatcher.getUrl();
- var anchorIndex = url.indexOf('#');
- if (anchorIndex > -1)
- url = url.substring(0, anchorIndex);
- url += "#";
- var sep = '';
- for (var key in this.anchor) {
- var value = this.anchor[key];
- if (typeof value === 'undefined' || value === null) {
- delete this.anchor[key];
- } else {
- url += sep + encodeURIComponent(key);
- if (value !== true)
- url += "=" + encodeURIComponent(value);
- sep = '&';
- }
- }
- this.urlWatcher.setUrl(url);
- return url;
-};
-
-Binder.prototype.updateView = function() {
- var start = new Date().getTime();
- var scope = jQuery(this.doc).scope();
- scope.set("$invalidWidgets", []);
- scope.updateView();
- var end = new Date().getTime();
- this.updateAnchor();
- _.each(this.updateListeners, function(fn) {fn();});
-};
-
-Binder.prototype.docFindWithSelf = function(exp){
- var doc = jQuery(this.doc);
- var selection = doc.find(exp);
- if (doc.is(exp)){
- selection = selection.andSelf();
- }
- return selection;
-};
-
-Binder.prototype.executeInit = function() {
- this.docFindWithSelf("[ng-init]").each(function() {
- var jThis = jQuery(this);
- var scope = jThis.scope();
- try {
- scope.eval(jThis.attr('ng-init'));
- } catch (e) {
- alert("EVAL ERROR:\n" + jThis.attr('ng-init') + '\n' + toJson(e, true));
+Binder.prototype = {
+ parseQueryString: function(query) {
+ var params = {};
+ query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,
+ function (match, left, right) {
+ if (left) params[decodeURIComponent(left)] = decodeURIComponent(right);
+ });
+ return params;
+ },
+
+ parseAnchor: function(url) {
+ var self = this;
+ url = url || this.urlWatcher.getUrl();
+
+ var anchorIndex = url.indexOf('#');
+ if (anchorIndex < 0) return;
+ var anchor = url.substring(anchorIndex + 1);
+
+ var anchorQuery = this.parseQueryString(anchor);
+ foreach(self.anchor, function(newValue, key) {
+ delete self.anchor[key];
+ });
+ foreach(anchorQuery, function(newValue, key) {
+ self.anchor[key] = newValue;
+ });
+ },
+
+ onUrlChange: function (url) {
+ log("URL change detected", url);
+ this.parseAnchor(url);
+ this.updateView();
+ },
+
+ updateAnchor: function() {
+ var url = this.urlWatcher.getUrl();
+ var anchorIndex = url.indexOf('#');
+ if (anchorIndex > -1)
+ url = url.substring(0, anchorIndex);
+ url += "#";
+ var sep = '';
+ for (var key in this.anchor) {
+ var value = this.anchor[key];
+ if (typeof value === 'undefined' || value === null) {
+ delete this.anchor[key];
+ } else {
+ url += sep + encodeURIComponent(key);
+ if (value !== true)
+ url += "=" + encodeURIComponent(value);
+ sep = '&';
+ }
}
- });
-};
-
-Binder.prototype.entity = function (scope) {
- this.docFindWithSelf("[ng-entity]").attr("ng-watch", function() {
- try {
- var jNode = jQuery(this);
- var decl = scope.entity(jNode.attr("ng-entity"));
- return decl + (jNode.attr('ng-watch') || "");
- } catch (e) {
- alert(e);
+ this.urlWatcher.setUrl(url);
+ return url;
+ },
+
+ updateView: function() {
+ var start = new Date().getTime();
+ var scope = jQuery(this.doc).scope();
+ scope.set("$invalidWidgets", []);
+ scope.updateView();
+ var end = new Date().getTime();
+ this.updateAnchor();
+ _.each(this.updateListeners, function(fn) {fn();});
+ },
+
+ docFindWithSelf: function(exp){
+ var doc = jQuery(this.doc);
+ var selection = doc.find(exp);
+ if (doc.is(exp)){
+ selection = selection.andSelf();
}
- });
-};
-
-Binder.prototype.compile = function() {
- var jNode = jQuery(this.doc);
- var self = this;
- if (this.config.autoSubmit) {
- var submits = this.docFindWithSelf(":submit").not("[ng-action]");
- submits.attr("ng-action", "$save()");
- submits.not(":disabled").not("ng-bind-attr").attr("ng-bind-attr", '{disabled:"{{$invalidWidgets}}"}');
- }
- this.precompile(this.doc)(this.doc, jNode.scope(), "");
- this.docFindWithSelf("a[ng-action]").live('click', function (event) {
- var jNode = jQuery(this);
- try {
- jNode.scope().eval(jNode.attr('ng-action'));
- jNode.removeAttr('ng-error');
- jNode.removeClass("ng-exception");
- } catch (e) {
- jNode.addClass("ng-exception");
- jNode.attr('ng-error', toJson(e, true));
+ return selection;
+ },
+
+ executeInit: function() {
+ this.docFindWithSelf("[ng-init]").each(function() {
+ var jThis = jQuery(this);
+ var scope = jThis.scope();
+ try {
+ scope.eval(jThis.attr('ng-init'));
+ } catch (e) {
+ alert("EVAL ERROR:\n" + jThis.attr('ng-init') + '\n' + toJson(e, true));
+ }
+ });
+ },
+
+ entity: function (scope) {
+ this.docFindWithSelf("[ng-entity]").attr("ng-watch", function() {
+ try {
+ var jNode = jQuery(this);
+ var decl = scope.entity(jNode.attr("ng-entity"));
+ return decl + (jNode.attr('ng-watch') || "");
+ } catch (e) {
+ alert(e);
+ }
+ });
+ },
+
+ compile: function() {
+ var jNode = jQuery(this.doc);
+ var self = this;
+ if (this.config.autoSubmit) {
+ var submits = this.docFindWithSelf(":submit").not("[ng-action]");
+ submits.attr("ng-action", "$save()");
+ submits.not(":disabled").not("ng-bind-attr").attr("ng-bind-attr", '{disabled:"{{$invalidWidgets}}"}');
}
- self.updateView();
- return false;
- });
-};
-
-Binder.prototype.translateBinding = function(node, parentPath, factories) {
- var path = parentPath.concat();
- var offset = path.pop();
- var parts = Binder.parseBindings(node.nodeValue);
- if (parts.length > 1 || Binder.binding(parts[0])) {
- var parent = node.parentNode;
- if (isLeafNode(parent)) {
- parent.setAttribute('ng-bind-template', node.nodeValue);
- factories.push({path:path, fn:function(node, scope, prefix) {
- return new BindUpdater(node, node.getAttribute('ng-bind-template'));
- }});
- } else {
- for (var i = 0; i < parts.length; i++) {
- var part = parts[i];
- var binding = Binder.binding(part);
- var newNode;
- if (binding) {
- newNode = document.createElement("span");
- var jNewNode = jQuery(newNode);
- jNewNode.attr("ng-bind", binding);
- if (i === 0) {
- factories.push({path:path.concat(offset + i), fn:Binder.prototype.ng_bind});
+ this.precompile(this.doc)(this.doc, jNode.scope(), "");
+ this.docFindWithSelf("a[ng-action]").live('click', function (event) {
+ var jNode = jQuery(this);
+ try {
+ jNode.scope().eval(jNode.attr('ng-action'));
+ jNode.removeAttr('ng-error');
+ jNode.removeClass("ng-exception");
+ } catch (e) {
+ jNode.addClass("ng-exception");
+ jNode.attr('ng-error', toJson(e, true));
+ }
+ self.updateView();
+ return false;
+ });
+ },
+
+ translateBinding: function(node, parentPath, factories) {
+ var path = parentPath.concat();
+ var offset = path.pop();
+ var parts = Binder.parseBindings(node.nodeValue);
+ if (parts.length > 1 || Binder.binding(parts[0])) {
+ var parent = node.parentNode;
+ if (isLeafNode(parent)) {
+ parent.setAttribute('ng-bind-template', node.nodeValue);
+ factories.push({path:path, fn:function(node, scope, prefix) {
+ return new BindUpdater(node, node.getAttribute('ng-bind-template'));
+ }});
+ } else {
+ for (var i = 0; i < parts.length; i++) {
+ var part = parts[i];
+ var binding = Binder.binding(part);
+ var newNode;
+ if (binding) {
+ newNode = document.createElement("span");
+ var jNewNode = jQuery(newNode);
+ jNewNode.attr("ng-bind", binding);
+ if (i === 0) {
+ factories.push({path:path.concat(offset + i), fn:this.ng_bind});
+ }
+ } else if (msie && part.charAt(0) == ' ') {
+ newNode = document.createElement("span");
+ newNode.innerHTML = '&nbsp;' + part.substring(1);
+ } else {
+ newNode = document.createTextNode(part);
}
- } else if (msie && part.charAt(0) == ' ') {
- newNode = document.createElement("span");
- newNode.innerHTML = '&nbsp;' + part.substring(1);
- } else {
- newNode = document.createTextNode(part);
+ parent.insertBefore(newNode, node);
}
- parent.insertBefore(newNode, node);
}
+ parent.removeChild(node);
}
- parent.removeChild(node);
- }
-};
-
-Binder.prototype.precompile = function(root) {
- var factories = [];
- this.precompileNode(root, [], factories);
- return function (template, scope, prefix) {
- var len = factories.length;
- for (var i = 0; i < len; i++) {
- var factory = factories[i];
- var node = template;
- var path = factory.path;
- for (var j = 0; j < path.length; j++) {
- node = node.childNodes[path[j]];
+ },
+
+ precompile: function(root) {
+ var factories = [];
+ this.precompileNode(root, [], factories);
+ return function (template, scope, prefix) {
+ var len = factories.length;
+ for (var i = 0; i < len; i++) {
+ var factory = factories[i];
+ var node = template;
+ var path = factory.path;
+ for (var j = 0; j < path.length; j++) {
+ node = node.childNodes[path[j]];
+ }
+ try {
+ scope.addWidget(factory.fn(node, scope, prefix));
+ } catch (e) {
+ alert(e);
+ }
}
- try {
- scope.addWidget(factory.fn(node, scope, prefix));
- } catch (e) {
- alert(e);
+ };
+ },
+
+ precompileNode: function(node, path, factories) {
+ var nodeType = node.nodeType;
+ if (nodeType == Node.TEXT_NODE) {
+ this.translateBinding(node, path, factories);
+ return;
+ } else if (nodeType != Node.ELEMENT_NODE && nodeType != Node.DOCUMENT_NODE) {
+ return;
+ }
+
+ if (!node.getAttribute) return;
+ var nonBindable = node.getAttribute('ng-non-bindable');
+ if (nonBindable || nonBindable === "") return;
+
+ var attributes = node.attributes;
+ if (attributes) {
+ var bindings = node.getAttribute('ng-bind-attr');
+ node.removeAttribute('ng-bind-attr');
+ bindings = bindings ? fromJson(bindings) : {};
+ var attrLen = attributes.length;
+ for (var i = 0; i < attrLen; i++) {
+ var attr = attributes[i];
+ var attrName = attr.name;
+ // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
+ var attrValue = msie && attrName == 'href' ?
+ decodeURI(node.getAttribute(attrName, 2)) : attr.value;
+ if (Binder.hasBinding(attrValue)) {
+ bindings[attrName] = attrValue;
+ }
+ }
+ var json = toJson(bindings);
+ if (json.length > 2) {
+ node.setAttribute("ng-bind-attr", json);
}
}
- };
-};
-
-Binder.prototype.precompileNode = function(node, path, factories) {
- var nodeType = node.nodeType;
- if (nodeType == Node.TEXT_NODE) {
- this.translateBinding(node, path, factories);
- return;
- } else if (nodeType != Node.ELEMENT_NODE && nodeType != Node.DOCUMENT_NODE) {
- return;
- }
-
- if (!node.getAttribute) return;
- var nonBindable = node.getAttribute('ng-non-bindable');
- if (nonBindable || nonBindable === "") return;
-
- var attributes = node.attributes;
- if (attributes) {
- var bindings = node.getAttribute('ng-bind-attr');
- node.removeAttribute('ng-bind-attr');
- bindings = bindings ? fromJson(bindings) : {};
- var attrLen = attributes.length;
- for (var i = 0; i < attrLen; i++) {
- var attr = attributes[i];
- var attrName = attr.name;
- // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
- var attrValue = msie && attrName == 'href' ?
- decodeURI(node.getAttribute(attrName, 2)) : attr.value;
- if (Binder.hasBinding(attrValue)) {
- bindings[attrName] = attrValue;
- }
- }
- var json = toJson(bindings);
- if (json.length > 2) {
- node.setAttribute("ng-bind-attr", json);
+
+ if (!node.getAttribute) log(node);
+ var repeaterExpression = node.getAttribute('ng-repeat');
+ if (repeaterExpression) {
+ node.removeAttribute('ng-repeat');
+ var precompiled = this.precompile(node);
+ var view = document.createComment("ng-repeat: " + repeaterExpression);
+ var parentNode = node.parentNode;
+ parentNode.insertBefore(view, node);
+ parentNode.removeChild(node);
+ function template(childScope, prefix, i) {
+ var clone = jQuery(node).clone();
+ clone.css('display', '');
+ clone.attr('ng-repeat-index', "" + i);
+ clone.data('scope', childScope);
+ precompiled(clone[0], childScope, prefix + i + ":");
+ return clone;
+ }
+ factories.push({path:path, fn:function(node, scope, prefix) {
+ return new RepeaterUpdater(jQuery(node), repeaterExpression, template, prefix);
+ }});
+ return;
}
- }
-
- if (!node.getAttribute) log(node);
- var repeaterExpression = node.getAttribute('ng-repeat');
- if (repeaterExpression) {
- node.removeAttribute('ng-repeat');
- var precompiled = this.precompile(node);
- var view = document.createComment("ng-repeat: " + repeaterExpression);
- var parentNode = node.parentNode;
- parentNode.insertBefore(view, node);
- parentNode.removeChild(node);
- var template = function(childScope, prefix, i) {
- var clone = jQuery(node).clone();
- clone.css('display', '');
- clone.attr('ng-repeat-index', "" + i);
- clone.data('scope', childScope);
- precompiled(clone[0], childScope, prefix + i + ":");
- return clone;
- };
- factories.push({path:path, fn:function(node, scope, prefix) {
- return new RepeaterUpdater(jQuery(node), repeaterExpression, template, prefix);
- }});
- return;
- }
-
- if (node.getAttribute('ng-eval')) factories.push({path:path, fn:this.ng_eval});
- if (node.getAttribute('ng-bind')) factories.push({path:path, fn:this.ng_bind});
- if (node.getAttribute('ng-bind-attr')) factories.push({path:path, fn:this.ng_bind_attr});
- if (node.getAttribute('ng-hide')) factories.push({path:path, fn:this.ng_hide});
- if (node.getAttribute('ng-show')) factories.push({path:path, fn:this.ng_show});
- if (node.getAttribute('ng-class')) factories.push({path:path, fn:this.ng_class});
- if (node.getAttribute('ng-class-odd')) factories.push({path:path, fn:this.ng_class_odd});
- if (node.getAttribute('ng-class-even')) factories.push({path:path, fn:this.ng_class_even});
- if (node.getAttribute('ng-style')) factories.push({path:path, fn:this.ng_style});
- if (node.getAttribute('ng-watch')) factories.push({path:path, fn:this.ng_watch});
- var nodeName = node.nodeName;
- if ((nodeName == 'INPUT' ) ||
- nodeName == 'TEXTAREA' ||
- nodeName == 'SELECT' ||
- nodeName == 'BUTTON') {
- var self = this;
- factories.push({path:path, fn:function(node, scope, prefix) {
- node.name = prefix + node.name.split(":").pop();
- return self.widgetFactory.createController(jQuery(node), scope);
- }});
- }
- if (nodeName == 'OPTION') {
- var html = jQuery('<select/>').append(jQuery(node).clone()).html();
- if (!html.match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi)) {
- node.value = node.text;
+
+ if (node.getAttribute('ng-eval')) factories.push({path:path, fn:this.ng_eval});
+ if (node.getAttribute('ng-bind')) factories.push({path:path, fn:this.ng_bind});
+ if (node.getAttribute('ng-bind-attr')) factories.push({path:path, fn:this.ng_bind_attr});
+ if (node.getAttribute('ng-hide')) factories.push({path:path, fn:this.ng_hide});
+ if (node.getAttribute('ng-show')) factories.push({path:path, fn:this.ng_show});
+ if (node.getAttribute('ng-class')) factories.push({path:path, fn:this.ng_class});
+ if (node.getAttribute('ng-class-odd')) factories.push({path:path, fn:this.ng_class_odd});
+ if (node.getAttribute('ng-class-even')) factories.push({path:path, fn:this.ng_class_even});
+ if (node.getAttribute('ng-style')) factories.push({path:path, fn:this.ng_style});
+ if (node.getAttribute('ng-watch')) factories.push({path:path, fn:this.ng_watch});
+ var nodeName = node.nodeName;
+ if ((nodeName == 'INPUT' ) ||
+ nodeName == 'TEXTAREA' ||
+ nodeName == 'SELECT' ||
+ nodeName == 'BUTTON') {
+ var self = this;
+ factories.push({path:path, fn:function(node, scope, prefix) {
+ node.name = prefix + node.name.split(":").pop();
+ return self.widgetFactory.createController(jQuery(node), scope);
+ }});
}
+ if (nodeName == 'OPTION') {
+ var html = jQuery('<select/>').append(jQuery(node).clone()).html();
+ if (!html.match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi)) {
+ node.value = node.text;
+ }
+ }
+
+ var children = node.childNodes;
+ for (var k = 0; k < children.length; k++) {
+ this.precompileNode(children[k], path.concat(k), factories);
+ }
+ },
+
+ ng_eval: function(node) {
+ return new EvalUpdater(node, node.getAttribute('ng-eval'));
+ },
+
+ ng_bind: function(node) {
+ return new BindUpdater(node, "{{" + node.getAttribute('ng-bind') + "}}");
+ },
+
+ ng_bind_attr: function(node) {
+ return new BindAttrUpdater(node, fromJson(node.getAttribute('ng-bind-attr')));
+ },
+
+ ng_hide: function(node) {
+ return new HideUpdater(node, node.getAttribute('ng-hide'));
+ },
+
+ ng_show: function(node) {
+ return new ShowUpdater(node, node.getAttribute('ng-show'));
+ },
+
+ ng_class: function(node) {
+ return new ClassUpdater(node, node.getAttribute('ng-class'));
+ },
+
+ ng_class_even: function(node) {
+ return new ClassEvenUpdater(node, node.getAttribute('ng-class-even'));
+ },
+
+ ng_class_odd: function(node) {
+ return new ClassOddUpdater(node, node.getAttribute('ng-class-odd'));
+ },
+
+ ng_style: function(node) {
+ return new StyleUpdater(node, node.getAttribute('ng-style'));
+ },
+
+ ng_watch: function(node, scope) {
+ scope.watch(node.getAttribute('ng-watch'));
}
-
- var children = node.childNodes;
- for (var k = 0; k < children.length; k++) {
- this.precompileNode(children[k], path.concat(k), factories);
- }
-};
-
-Binder.prototype.ng_eval = function(node) {
- return new EvalUpdater(node, node.getAttribute('ng-eval'));
-};
-
-Binder.prototype.ng_bind = function(node) {
- return new BindUpdater(node, "{{" + node.getAttribute('ng-bind') + "}}");
-};
-
-Binder.prototype.ng_bind_attr = function(node) {
- return new BindAttrUpdater(node, fromJson(node.getAttribute('ng-bind-attr')));
-};
-
-Binder.prototype.ng_hide = function(node) {
- return new HideUpdater(node, node.getAttribute('ng-hide'));
-};
-
-Binder.prototype.ng_show = function(node) {
- return new ShowUpdater(node, node.getAttribute('ng-show'));
-};
-
-Binder.prototype.ng_class = function(node) {
- return new ClassUpdater(node, node.getAttribute('ng-class'));
-};
-
-Binder.prototype.ng_class_even = function(node) {
- return new ClassEvenUpdater(node, node.getAttribute('ng-class-even'));
-};
-
-Binder.prototype.ng_class_odd = function(node) {
- return new ClassOddUpdater(node, node.getAttribute('ng-class-odd'));
-};
-
-Binder.prototype.ng_style = function(node) {
- return new StyleUpdater(node, node.getAttribute('ng-style'));
-};
-
-Binder.prototype.ng_watch = function(node, scope) {
- scope.watch(node.getAttribute('ng-watch'));
-};
-// Copyright (C) 2008,2009 BRAT Tech LLC
-
-ControlBar = function (document, serverUrl) {
+};function ControlBar(document, serverUrl) {
this.document = document;
this.serverUrl = serverUrl;
this.window = window;
this.callbacks = [];
};
-ControlBar.prototype.bind = function () {
-};
-
ControlBar.HTML =
'<div>' +
'<div class="ui-widget-overlay"></div>' +
@@ -1231,60 +1248,64 @@ ControlBar.HTML =
'</div>' +
'</div>';
-ControlBar.prototype.login = function (loginSubmitFn) {
- this.callbacks.push(loginSubmitFn);
- if (this.callbacks.length == 1) {
- this.doTemplate("/user_session/new.mini?return_url=" + encodeURIComponent(this.urlWithoutAnchor()));
- }
-};
-
-ControlBar.prototype.logout = function (loginSubmitFn) {
- this.callbacks.push(loginSubmitFn);
- if (this.callbacks.length == 1) {
- this.doTemplate("/user_session/do_destroy.mini");
- }
-};
-
-ControlBar.prototype.urlWithoutAnchor = function (path) {
- return this.window.location.href.split("#")[0];
-};
-
-ControlBar.prototype.doTemplate = function (path) {
- var self = this;
- var id = new Date().getTime();
- var url = this.urlWithoutAnchor();
- url += "#$iframe_notify=" + id;
- var iframeHeight = 330;
- var loginView = jQuery('<div style="overflow:hidden; padding:2px 0 0 0;"><iframe name="'+ url +'" src="'+this.serverUrl + path + '" width="500" height="'+ iframeHeight +'"/></div>');
- this.document.append(loginView);
- loginView.dialog({
- height:iframeHeight + 33, width:500,
- resizable: false, modal:true,
- title: 'Authentication: <a href="http://www.getangular.com"><tt>&lt;angular/&gt;</tt></a>'
- });
- callbacks["_iframe_notify_" + id] = function() {
- loginView.dialog("destroy");
- loginView.remove();
- foreach(self.callbacks, function(callback){
- callback();
- });
- self.callbacks = [];
- };
-};
-
ControlBar.FORBIDEN =
'<div ng-non-bindable="true" title="Permission Error:">' +
'Sorry, you do not have permission for this!'+
'</div>';
-ControlBar.prototype.notAuthorized = function () {
- if (this.forbidenView) return;
- this.forbidenView = jQuery(ControlBar.FORBIDEN);
- this.forbidenView.dialog({bgiframe:true, height:70, modal:true});
-};
-// Copyright (C) 2009 BRAT Tech LLC
-DataStore = function(post, users, anchor) {
+
+ControlBar.prototype = {
+ bind: function () {
+ },
+
+ login: function (loginSubmitFn) {
+ this.callbacks.push(loginSubmitFn);
+ if (this.callbacks.length == 1) {
+ this.doTemplate("/user_session/new.mini?return_url=" + encodeURIComponent(this.urlWithoutAnchor()));
+ }
+ },
+
+ logout: function (loginSubmitFn) {
+ this.callbacks.push(loginSubmitFn);
+ if (this.callbacks.length == 1) {
+ this.doTemplate("/user_session/do_destroy.mini");
+ }
+ },
+
+ urlWithoutAnchor: function (path) {
+ return this.window.location.href.split("#")[0];
+ },
+
+ doTemplate: function (path) {
+ var self = this;
+ var id = new Date().getTime();
+ var url = this.urlWithoutAnchor();
+ url += "#$iframe_notify=" + id;
+ var iframeHeight = 330;
+ var loginView = jQuery('<div style="overflow:hidden; padding:2px 0 0 0;"><iframe name="'+ url +'" src="'+this.serverUrl + path + '" width="500" height="'+ iframeHeight +'"/></div>');
+ this.document.append(loginView);
+ loginView.dialog({
+ height:iframeHeight + 33, width:500,
+ resizable: false, modal:true,
+ title: 'Authentication: <a href="http://www.getangular.com"><tt>&lt;angular/&gt;</tt></a>'
+ });
+ callbacks["_iframe_notify_" + id] = function() {
+ loginView.dialog("destroy");
+ loginView.remove();
+ foreach(self.callbacks, function(callback){
+ callback();
+ });
+ self.callbacks = [];
+ };
+ },
+
+ notAuthorized: function () {
+ if (this.forbidenView) return;
+ this.forbidenView = jQuery(ControlBar.FORBIDEN);
+ this.forbidenView.dialog({bgiframe:true, height:70, modal:true});
+ }
+};function DataStore(post, users, anchor) {
this.post = post;
this.users = users;
this._cache = {$collections:[]};
@@ -1292,331 +1313,332 @@ DataStore = function(post, users, anchor) {
this.bulkRequest = [];
};
-DataStore.prototype.cache = function(document) {
- if (document.constructor != Model) {
- throw "Parameter must be an instance of Entity! " + toJson(document);
- }
- var key = document.$entity + '/' + document.$id;
- var cachedDocument = this._cache[key];
- if (cachedDocument) {
- Model.copyDirectFields(document, cachedDocument);
- } else {
- this._cache[key] = document;
- cachedDocument = document;
- }
- return cachedDocument;
-};
+DataStore.NullEntity = extend(function(){}, {
+ 'all': function(){return [];},
+ 'query': function(){return [];},
+ 'load': function(){return {};},
+ 'title': undefined
+});
-DataStore.prototype.load = function(instance, id, callback, failure) {
- if (id && id !== '*') {
- var self = this;
- this._jsonRequest(["GET", instance.$entity + "/" + id], function(response) {
- instance.$loadFrom(response);
- instance.$migrate();
- var clone = instance.$$entity(instance);
- self.cache(clone);
- (callback||noop)(instance);
- }, failure);
- }
- return instance;
-};
-
-DataStore.prototype.loadMany = function(entity, ids, callback) {
- var self=this;
- var list = [];
- var callbackCount = 0;
- foreach(ids, function(id){
- list.push(self.load(entity(), id, function(){
- callbackCount++;
- if (callbackCount == ids.length) {
- (callback||noop)(list);
- }
- }));
- });
- return list;
-}
-
-DataStore.prototype.loadOrCreate = function(instance, id, callback) {
- var self=this;
- return this.load(instance, id, callback, function(response){
- if (response.$status_code == 404) {
- instance.$id = id;
- (callback||noop)(instance);
+DataStore.prototype = {
+ cache: function(document) {
+ if (! document instanceof Model) {
+ throw "Parameter must be an instance of Entity! " + toJson(document);
+ }
+ var key = document.$entity + '/' + document.$id;
+ var cachedDocument = this._cache[key];
+ if (cachedDocument) {
+ Model.copyDirectFields(document, cachedDocument);
} else {
- throw response;
+ this._cache[key] = document;
+ cachedDocument = document;
}
- });
-};
-
-DataStore.prototype.loadAll = function(entity, callback) {
- var self = this;
- var list = [];
- list.$$accept = function(doc){
- return doc.$entity == entity.title;
- };
- this._cache.$collections.push(list);
- this._jsonRequest(["GET", entity.title], function(response) {
- var rows = response;
- for ( var i = 0; i < rows.length; i++) {
- var document = entity();
- document.$loadFrom(rows[i]);
- list.push(self.cache(document));
- }
- (callback||noop)(list);
- });
- return list;
-};
-
-DataStore.prototype.save = function(document, callback) {
- var self = this;
- var data = {};
- document.$saveTo(data);
- this._jsonRequest(["POST", "", data], function(response) {
- document.$loadFrom(response);
- var cachedDoc = self.cache(document);
- _.each(self._cache.$collections, function(collection){
- if (collection.$$accept(document)) {
- angular['Array']['includeIf'](collection, cachedDoc, true);
+ return cachedDocument;
+ },
+
+ load: function(instance, id, callback, failure) {
+ if (id && id !== '*') {
+ var self = this;
+ this._jsonRequest(["GET", instance.$entity + "/" + id], function(response) {
+ instance.$loadFrom(response);
+ instance.$migrate();
+ var clone = instance.$$entity(instance);
+ self.cache(clone);
+ (callback||noop)(instance);
+ }, failure);
+ }
+ return instance;
+ },
+
+ loadMany: function(entity, ids, callback) {
+ var self=this;
+ var list = [];
+ var callbackCount = 0;
+ foreach(ids, function(id){
+ list.push(self.load(entity(), id, function(){
+ callbackCount++;
+ if (callbackCount == ids.length) {
+ (callback||noop)(list);
+ }
+ }));
+ });
+ return list;
+ },
+
+ loadOrCreate: function(instance, id, callback) {
+ var self=this;
+ return this.load(instance, id, callback, function(response){
+ if (response.$status_code == 404) {
+ instance.$id = id;
+ (callback||noop)(instance);
+ } else {
+ throw response;
}
});
- if (document.$$anchor) {
- self.anchor[document.$$anchor] = document.$id;
- }
- if (callback)
- callback(document);
- });
-};
-
-DataStore.prototype.remove = function(document, callback) {
- var self = this;
- var data = {};
- document.$saveTo(data);
- this._jsonRequest(["DELETE", "", data], function(response) {
- delete self._cache[document.$entity + '/' + document.$id];
- _.each(self._cache.$collections, function(collection){
- for ( var i = 0; i < collection.length; i++) {
- var item = collection[i];
- if (item.$id == document.$id) {
- collection.splice(i, 1);
+ },
+
+ loadAll: function(entity, callback) {
+ var self = this;
+ var list = [];
+ list.$$accept = function(doc){
+ return doc.$entity == entity.title;
+ };
+ this._cache.$collections.push(list);
+ this._jsonRequest(["GET", entity.title], function(response) {
+ var rows = response;
+ for ( var i = 0; i < rows.length; i++) {
+ var document = entity();
+ document.$loadFrom(rows[i]);
+ list.push(self.cache(document));
+ }
+ (callback||noop)(list);
+ });
+ return list;
+ },
+
+ save: function(document, callback) {
+ var self = this;
+ var data = {};
+ document.$saveTo(data);
+ this._jsonRequest(["POST", "", data], function(response) {
+ document.$loadFrom(response);
+ var cachedDoc = self.cache(document);
+ _.each(self._cache.$collections, function(collection){
+ if (collection.$$accept(document)) {
+ angular['Array']['includeIf'](collection, cachedDoc, true);
}
+ });
+ if (document.$$anchor) {
+ self.anchor[document.$$anchor] = document.$id;
}
+ if (callback)
+ callback(document);
});
- (callback||noop)(response);
- });
-};
-
-DataStore.prototype._jsonRequest = function(request, callback, failure) {
- request.$$callback = callback;
- request.$$failure = failure||function(response){
- throw response;
- };
- this.bulkRequest.push(request);
-};
-
-DataStore.prototype.flush = function() {
- if (this.bulkRequest.length === 0) return;
- var self = this;
- var bulkRequest = this.bulkRequest;
- this.bulkRequest = [];
- log('REQUEST:', bulkRequest);
- function callback(code, bulkResponse){
- log('RESPONSE[' + code + ']: ', bulkResponse);
- if(bulkResponse.$status_code == 401) {
- self.users.login(function(){
- self.post(bulkRequest, callback);
+ },
+
+ remove: function(document, callback) {
+ var self = this;
+ var data = {};
+ document.$saveTo(data);
+ this._jsonRequest(["DELETE", "", data], function(response) {
+ delete self._cache[document.$entity + '/' + document.$id];
+ _.each(self._cache.$collections, function(collection){
+ for ( var i = 0; i < collection.length; i++) {
+ var item = collection[i];
+ if (item.$id == document.$id) {
+ collection.splice(i, 1);
+ }
+ }
});
- } else if(bulkResponse.$status_code) {
- alert(toJson(bulkResponse));
- } else {
- for ( var i = 0; i < bulkResponse.length; i++) {
- var response = bulkResponse[i];
- var request = bulkRequest[i];
- var code = response.$status_code;
- if(code) {
- if(code == 403) {
- self.users.notAuthorized();
+ (callback||noop)(response);
+ });
+ },
+
+ _jsonRequest: function(request, callback, failure) {
+ request.$$callback = callback;
+ request.$$failure = failure||function(response){
+ throw response;
+ };
+ this.bulkRequest.push(request);
+ },
+
+ flush: function() {
+ if (this.bulkRequest.length === 0) return;
+ var self = this;
+ var bulkRequest = this.bulkRequest;
+ this.bulkRequest = [];
+ log('REQUEST:', bulkRequest);
+ function callback(code, bulkResponse){
+ log('RESPONSE[' + code + ']: ', bulkResponse);
+ if(bulkResponse.$status_code == 401) {
+ self.users.login(function(){
+ self.post(bulkRequest, callback);
+ });
+ } else if(bulkResponse.$status_code) {
+ alert(toJson(bulkResponse));
+ } else {
+ for ( var i = 0; i < bulkResponse.length; i++) {
+ var response = bulkResponse[i];
+ var request = bulkRequest[i];
+ var responseCode = response.$status_code;
+ if(responseCode) {
+ if(responseCode == 403) {
+ self.users.notAuthorized();
+ } else {
+ request.$$failure(response);
+ }
} else {
- request.$$failure(response);
+ request.$$callback(response);
}
- } else {
- request.$$callback(response);
}
}
}
- }
- this.post(bulkRequest, callback);
-};
-
-DataStore.prototype.saveScope = function(scope, callback) {
- var saveCounter = 1;
- function onSaveDone() {
- saveCounter--;
- if (saveCounter === 0 && callback)
- callback();
- }
- for(var key in scope) {
- var item = scope[key];
- if (item && item.$save == Model.prototype.$save) {
- saveCounter++;
- item.$save(onSaveDone);
- }
- }
- onSaveDone();
-};
-
-DataStore.prototype.query = function(type, query, arg, callback){
- var self = this;
- var queryList = [];
- queryList.$$accept = function(doc){
- return false;
- };
- this._cache.$collections.push(queryList);
- var request = type.title + '/' + query + '=' + arg;
- this._jsonRequest(["GET", request], function(response){
- var list = response;
- for(var i = 0; i < list.length; i++) {
- var document = new type().$loadFrom(list[i]);
- queryList.push(self.cache(document));
- }
- if (callback)
- callback(queryList);
- });
- return queryList;
-};
-
-DataStore.prototype.entities = function(callback) {
- var entities = [];
- var self = this;
- this._jsonRequest(["GET", "$entities"], function(response) {
- for (var entityName in response) {
- entities.push(self.entity(entityName));
+ this.post(bulkRequest, callback);
+ },
+
+ saveScope: function(scope, callback) {
+ var saveCounter = 1;
+ function onSaveDone() {
+ saveCounter--;
+ if (saveCounter === 0 && callback)
+ callback();
+ }
+ for(var key in scope) {
+ var item = scope[key];
+ if (item && item.$save == Model.prototype.$save) {
+ saveCounter++;
+ item.$save(onSaveDone);
+ }
}
- entities.sort(function(a,b){return a.title > b.title ? 1 : -1;});
- if (callback) callback(entities);
- });
- return entities;
-};
-
-DataStore.prototype.documentCountsByUser = function(){
- var counts = {};
- var self = this;
- self.post([["GET", "$users"]], function(code, response){
- foreach(response[0], function(value, key){
- counts[key] = value;
+ onSaveDone();
+ },
+
+ query: function(type, query, arg, callback){
+ var self = this;
+ var queryList = [];
+ queryList.$$accept = function(doc){
+ return false;
+ };
+ this._cache.$collections.push(queryList);
+ var request = type.title + '/' + query + '=' + arg;
+ this._jsonRequest(["GET", request], function(response){
+ var list = response;
+ for(var i = 0; i < list.length; i++) {
+ var document = new type().$loadFrom(list[i]);
+ queryList.push(self.cache(document));
+ }
+ if (callback)
+ callback(queryList);
});
- });
- return counts;
-};
-
-DataStore.prototype.userDocumentIdsByEntity = function(user){
- var ids = {};
- var self = this;
- self.post([["GET", "$users/" + user]], function(code, response){
- foreach(response[0], function(value, key){
- ids[key] = value;
+ return queryList;
+ },
+
+ entities: function(callback) {
+ var entities = [];
+ var self = this;
+ this._jsonRequest(["GET", "$entities"], function(response) {
+ for (var entityName in response) {
+ entities.push(self.entity(entityName));
+ }
+ entities.sort(function(a,b){return a.title > b.title ? 1 : -1;});
+ if (callback) callback(entities);
});
- });
- return ids;
-};
-
-DataStore.NullEntity = function(){};
-DataStore.NullEntity.all = function(){return [];};
-DataStore.NullEntity.query = function(){return [];};
-DataStore.NullEntity.load = function(){return {};};
-DataStore.NullEntity.title = undefined;
-
-DataStore.prototype.entity = function(name, defaults){
- if (!name) {
- return DataStore.NullEntity;
- }
- var self = this;
- var entity = function(initialState){
- return new Model(entity, initialState);
- };
- // entity.name does not work as name seems to be reserved for functions
- entity.title = name;
- entity.$$factory = true;
- entity.datastore = this;
- entity.defaults = defaults || {};
- entity.load = function(id, callback){
- return self.load(entity(), id, callback);
- };
- entity.loadMany = function(ids, callback){
- return self.loadMany(entity, ids, callback);
- };
- entity.loadOrCreate = function(id, callback){
- return self.loadOrCreate(entity(), id, callback);
- };
- entity.all = function(callback){
- return self.loadAll(entity, callback);
- };
- entity.query = function(query, queryArgs, callback){
- return self.query(entity, query, queryArgs, callback);
- };
- entity.properties = function(callback) {
- self._jsonRequest(["GET", name + "/$properties"], callback);
- };
- return entity;
-};
-
-DataStore.prototype.join = function(join){
- var fn = function(){
- throw "Joined entities can not be instantiated into a document.";
- };
- function base(name){return name ? name.substring(0, name.indexOf('.')) : undefined;}
- function next(name){return name.substring(name.indexOf('.') + 1);}
- var joinOrder = _(join).chain().
- map(function($, name){
- return name;}).
- sortBy(function(name){
- var path = [];
- do {
- if (_(path).include(name)) throw "Infinite loop in join: " + path.join(" -> ");
- path.push(name);
- if (!join[name]) throw _("Named entity '<%=name%>' is undefined.").template({name:name});
- name = base(join[name].on);
- } while(name);
- return path.length;
- }).
- value();
- if (_(joinOrder).select(function($){return join[$].on;}).length != joinOrder.length - 1)
- throw "Exactly one entity needs to be primary.";
- fn.query = function(exp, value) {
- var joinedResult = [];
- var baseName = base(exp);
- if (baseName != joinOrder[0]) throw _("Named entity '<%=name%>' is not a primary entity.").template({name:baseName});
- var Entity = join[baseName].join;
- var joinIndex = 1;
- Entity.query(next(exp), value, function(result){
- var nextJoinName = joinOrder[joinIndex++];
- var nextJoin = join[nextJoinName];
- var nextJoinOn = nextJoin.on;
- var joinIds = {};
- _(result).each(function(doc){
- var row = {};
- joinedResult.push(row);
- row[baseName] = doc;
- var id = Scope.getter(row, nextJoinOn);
- joinIds[id] = id;
+ return entities;
+ },
+
+ documentCountsByUser: function(){
+ var counts = {};
+ var self = this;
+ self.post([["GET", "$users"]], function(code, response){
+ foreach(response[0], function(value, key){
+ counts[key] = value;
});
- nextJoin.join.loadMany(_.toArray(joinIds), function(result){
- var byId = {};
+ });
+ return counts;
+ },
+
+ userDocumentIdsByEntity: function(user){
+ var ids = {};
+ var self = this;
+ self.post([["GET", "$users/" + user]], function(code, response){
+ foreach(response[0], function(value, key){
+ ids[key] = value;
+ });
+ });
+ return ids;
+ },
+
+ entity: function(name, defaults){
+ if (!name) {
+ return DataStore.NullEntity;
+ }
+ var self = this;
+ var entity = extend(function(initialState){
+ return new Model(entity, initialState);
+ }, {
+ // entity.name does not work as name seems to be reserved for functions
+ 'title': name,
+ '$$factory': true,
+ 'datastore': this,
+ 'defaults': defaults || {},
+ 'load': function(id, callback){
+ return self.load(entity(), id, callback);
+ },
+ 'loadMany': function(ids, callback){
+ return self.loadMany(entity, ids, callback);
+ },
+ 'loadOrCreate': function(id, callback){
+ return self.loadOrCreate(entity(), id, callback);
+ },
+ 'all': function(callback){
+ return self.loadAll(entity, callback);
+ },
+ 'query': function(query, queryArgs, callback){
+ return self.query(entity, query, queryArgs, callback);
+ },
+ 'properties': function(callback) {
+ self._jsonRequest(["GET", name + "/$properties"], callback);
+ }
+ });
+ return entity;
+ },
+
+ join: function(join){
+ function fn(){
+ throw "Joined entities can not be instantiated into a document.";
+ };
+ function base(name){return name ? name.substring(0, name.indexOf('.')) : undefined;}
+ function next(name){return name.substring(name.indexOf('.') + 1);}
+ var joinOrder = _(join).chain().
+ map(function($, name){
+ return name;}).
+ sortBy(function(name){
+ var path = [];
+ do {
+ if (_(path).include(name)) throw "Infinite loop in join: " + path.join(" -> ");
+ path.push(name);
+ if (!join[name]) throw _("Named entity '<%=name%>' is undefined.").template({name:name});
+ name = base(join[name].on);
+ } while(name);
+ return path.length;
+ }).
+ value();
+ if (_(joinOrder).select(function($){return join[$].on;}).length != joinOrder.length - 1)
+ throw "Exactly one entity needs to be primary.";
+ fn['query'] = function(exp, value) {
+ var joinedResult = [];
+ var baseName = base(exp);
+ if (baseName != joinOrder[0]) throw _("Named entity '<%=name%>' is not a primary entity.").template({name:baseName});
+ var Entity = join[baseName].join;
+ var joinIndex = 1;
+ Entity['query'](next(exp), value, function(result){
+ var nextJoinName = joinOrder[joinIndex++];
+ var nextJoin = join[nextJoinName];
+ var nextJoinOn = nextJoin.on;
+ var joinIds = {};
_(result).each(function(doc){
- byId[doc.$id] = doc;
- });
- _(joinedResult).each(function(row){
+ var row = {};
+ joinedResult.push(row);
+ row[baseName] = doc;
var id = Scope.getter(row, nextJoinOn);
- row[nextJoinName] = byId[id];
+ joinIds[id] = id;
+ });
+ nextJoin.join.loadMany(_.toArray(joinIds), function(result){
+ var byId = {};
+ _(result).each(function(doc){
+ byId[doc.$id] = doc;
+ });
+ _(joinedResult).each(function(row){
+ var id = Scope.getter(row, nextJoinOn);
+ row[nextJoinName] = byId[id];
+ });
});
});
- });
- return joinedResult;
- };
- return fn;
-};
-// Copyright (C) 2009 BRAT Tech LLC
-
-angularFilter.Meta = function(obj){
+ return joinedResult;
+ };
+ return fn;
+ }
+};angularFilter.Meta = function(obj){
if (obj) {
for ( var key in obj) {
this[key] = obj[key];
@@ -1917,17 +1939,17 @@ foreach({
angularFilterGoogleChartApi = angularFilter['googleChartApi'];
array = [].constructor;
-toJson = function(obj, pretty){
+function toJson(obj, pretty){
var buf = [];
toJsonArray(buf, obj, pretty ? "\n " : null);
return buf.join('');
};
-toPrettyJson = function(obj) {
+function toPrettyJson(obj) {
return toJson(obj, true);
};
-fromJson = function(json) {
+function fromJson(json) {
try {
var parser = new Parser(json, true);
var expression = parser.primary();
@@ -1939,8 +1961,10 @@ fromJson = function(json) {
}
};
+angular['toJson'] = toJson;
+angular['fromJson'] = fromJson;
-toJsonArray = function(buf, obj, pretty){
+function toJsonArray(buf, obj, pretty){
var type = typeof obj;
if (obj === null) {
buf.push("null");
@@ -2007,15 +2031,13 @@ toJsonArray = function(buf, obj, pretty){
}
}
};
-// Copyright (C) 2009 BRAT Tech LLC
-
// Single $ is special and does not get searched
// Double $$ is special an is client only (does not get sent to server)
-Model = function(entity, initial) {
- this.$$entity = entity;
+function Model(entity, initial) {
+ this['$$entity'] = entity;
this.$loadFrom(initial||{});
- this.$entity = entity.title;
+ this.$entity = entity['title'];
this.$migrate();
};
@@ -2036,43 +2058,44 @@ Model.copyDirectFields = function(src, dst) {
}
};
-Model.prototype.$migrate = function() {
- merge(this.$$entity.defaults, this);
- return this;
-};
-
-Model.prototype.$merge = function(other) {
- merge(other, this);
- return this;
-};
-
-Model.prototype.$save = function(callback) {
- this.$$entity.datastore.save(this, callback === true ? undefined : callback);
- if (callback === true) this.$$entity.datastore.flush();
- return this;
-};
-
-Model.prototype.$delete = function(callback) {
- this.$$entity.datastore.remove(this, callback === true ? undefined : callback);
- if (callback === true) this.$$entity.datastore.flush();
- return this;
-};
-
-Model.prototype.$loadById = function(id, callback) {
- this.$$entity.datastore.load(this, id, callback);
- return this;
-};
-
-Model.prototype.$loadFrom = function(other) {
- Model.copyDirectFields(other, this);
- return this;
-};
-
-Model.prototype.$saveTo = function(other) {
- Model.copyDirectFields(this, other);
- return this;
-};
-Lexer = function(text, parsStrings){
+Model.prototype = {
+ '$migrate': function() {
+ merge(this['$$entity'].defaults, this);
+ return this;
+ },
+
+ '$merge': function(other) {
+ merge(other, this);
+ return this;
+ },
+
+ '$save': function(callback) {
+ this['$$entity'].datastore.save(this, callback === true ? undefined : callback);
+ if (callback === true) this['$$entity'].datastore.flush();
+ return this;
+ },
+
+ '$delete': function(callback) {
+ this['$$entity'].datastore.remove(this, callback === true ? undefined : callback);
+ if (callback === true) this['$$entity'].datastore.flush();
+ return this;
+ },
+
+ '$loadById': function(id, callback) {
+ this['$$entity'].datastore.load(this, id, callback);
+ return this;
+ },
+
+ '$loadFrom': function(other) {
+ Model.copyDirectFields(other, this);
+ return this;
+ },
+
+ '$saveTo': function(other) {
+ Model.copyDirectFields(this, other);
+ return this;
+ }
+};function Lexer(text, parsStrings){
this.text = text;
// UTC dates have 20 characters, we send them through parser
this.dateParseLength = parsStrings ? 20 : -1;
@@ -2104,210 +2127,214 @@ Lexer.OPERATORS = {
'|':function(self, a,b){return b(self, a);},
'!':function(self, a){return !a;}
};
+Lexer.ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
-Lexer.prototype.peek = function() {
- if (this.index + 1 < this.text.length) {
- return this.text.charAt(this.index + 1);
- } else {
- return false;
- }
-};
-
-Lexer.prototype.parse = function() {
- var tokens = this.tokens;
- var OPERATORS = Lexer.OPERATORS;
- var canStartRegExp = true;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (ch == '"' || ch == "'") {
- this.readString(ch);
- canStartRegExp = true;
- } else if (ch == '(' || ch == '[') {
- tokens.push({index:this.index, text:ch});
- this.index++;
- } else if (ch == '{' ) {
- var peekCh = this.peek();
- if (peekCh == ':' || peekCh == '(') {
- tokens.push({index:this.index, text:ch + peekCh});
+Lexer.prototype = {
+ peek: function() {
+ if (this.index + 1 < this.text.length) {
+ return this.text.charAt(this.index + 1);
+ } else {
+ return false;
+ }
+ },
+
+ parse: function() {
+ var tokens = this.tokens;
+ var OPERATORS = Lexer.OPERATORS;
+ var canStartRegExp = true;
+ while (this.index < this.text.length) {
+ var ch = this.text.charAt(this.index);
+ if (ch == '"' || ch == "'") {
+ this.readString(ch);
+ canStartRegExp = true;
+ } else if (ch == '(' || ch == '[') {
+ tokens.push({index:this.index, text:ch});
this.index++;
- } else {
+ } else if (ch == '{' ) {
+ var peekCh = this.peek();
+ if (peekCh == ':' || peekCh == '(') {
+ tokens.push({index:this.index, text:ch + peekCh});
+ this.index++;
+ } else {
+ tokens.push({index:this.index, text:ch});
+ }
+ this.index++;
+ canStartRegExp = true;
+ } else if (ch == ')' || ch == ']' || ch == '}' ) {
tokens.push({index:this.index, text:ch});
+ this.index++;
+ canStartRegExp = false;
+ } else if ( ch == ':' || ch == '.' || ch == ',' || ch == ';') {
+ tokens.push({index:this.index, text:ch});
+ this.index++;
+ canStartRegExp = true;
+ } else if ( canStartRegExp && ch == '/' ) {
+ this.readRegexp();
+ canStartRegExp = false;
+ } else if ( this.isNumber(ch) ) {
+ this.readNumber();
+ canStartRegExp = false;
+ } else if (this.isIdent(ch)) {
+ this.readIdent();
+ canStartRegExp = false;
+ } else if (this.isWhitespace(ch)) {
+ this.index++;
+ } else {
+ var ch2 = ch + this.peek();
+ var fn = OPERATORS[ch];
+ var fn2 = OPERATORS[ch2];
+ if (fn2) {
+ tokens.push({index:this.index, text:ch2, fn:fn2});
+ this.index += 2;
+ } else if (fn) {
+ tokens.push({index:this.index, text:ch, fn:fn});
+ this.index += 1;
+ } else {
+ throw "Lexer Error: Unexpected next character [" +
+ this.text.substring(this.index) +
+ "] in expression '" + this.text +
+ "' at column '" + (this.index+1) + "'.";
+ }
+ canStartRegExp = true;
}
- this.index++;
- canStartRegExp = true;
- } else if (ch == ')' || ch == ']' || ch == '}' ) {
- tokens.push({index:this.index, text:ch});
- this.index++;
- canStartRegExp = false;
- } else if ( ch == ':' || ch == '.' || ch == ',' || ch == ';') {
- tokens.push({index:this.index, text:ch});
- this.index++;
- canStartRegExp = true;
- } else if ( canStartRegExp && ch == '/' ) {
- this.readRegexp();
- canStartRegExp = false;
- } else if ( this.isNumber(ch) ) {
- this.readNumber();
- canStartRegExp = false;
- } else if (this.isIdent(ch)) {
- this.readIdent();
- canStartRegExp = false;
- } else if (this.isWhitespace(ch)) {
- this.index++;
- } else {
- var ch2 = ch + this.peek();
- var fn = OPERATORS[ch];
- var fn2 = OPERATORS[ch2];
- if (fn2) {
- tokens.push({index:this.index, text:ch2, fn:fn2});
- this.index += 2;
- } else if (fn) {
- tokens.push({index:this.index, text:ch, fn:fn});
- this.index += 1;
+ }
+ return tokens;
+ },
+
+ isNumber: function(ch) {
+ return '0' <= ch && ch <= '9';
+ },
+
+ isWhitespace: function(ch) {
+ return ch == ' ' || ch == '\r' || ch == '\t' ||
+ ch == '\n' || ch == '\v';
+ },
+
+ isIdent: function(ch) {
+ return 'a' <= ch && ch <= 'z' ||
+ 'A' <= ch && ch <= 'Z' ||
+ '_' == ch || ch == '$';
+ },
+
+ readNumber: function() {
+ var number = "";
+ var start = this.index;
+ while (this.index < this.text.length) {
+ var ch = this.text.charAt(this.index);
+ if (ch == '.' || this.isNumber(ch)) {
+ number += ch;
} else {
- throw "Lexer Error: Unexpected next character [" +
- this.text.substring(this.index) +
- "] in expression '" + this.text +
- "' at column '" + (this.index+1) + "'.";
+ break;
}
- canStartRegExp = true;
+ this.index++;
}
- }
- return tokens;
-};
-
-Lexer.prototype.isNumber = function(ch) {
- return '0' <= ch && ch <= '9';
-};
-
-Lexer.prototype.isWhitespace = function(ch) {
- return ch == ' ' || ch == '\r' || ch == '\t' ||
- ch == '\n' || ch == '\v';
-};
-
-Lexer.prototype.isIdent = function(ch) {
- return 'a' <= ch && ch <= 'z' ||
- 'A' <= ch && ch <= 'Z' ||
- '_' == ch || ch == '$';
-};
-
-Lexer.prototype.readNumber = function() {
- var number = "";
- var start = this.index;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (ch == '.' || this.isNumber(ch)) {
- number += ch;
- } else {
- break;
+ number = 1 * number;
+ this.tokens.push({index:start, text:number,
+ fn:function(){return number;}});
+ },
+
+ readIdent: function() {
+ var ident = "";
+ var start = this.index;
+ while (this.index < this.text.length) {
+ var ch = this.text.charAt(this.index);
+ if (ch == '.' || this.isIdent(ch) || this.isNumber(ch)) {
+ ident += ch;
+ } else {
+ break;
+ }
+ this.index++;
}
- this.index++;
- }
- number = 1 * number;
- this.tokens.push({index:start, text:number,
- fn:function(){return number;}});
-};
-
-Lexer.prototype.readIdent = function() {
- var ident = "";
- var start = this.index;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (ch == '.' || this.isIdent(ch) || this.isNumber(ch)) {
- ident += ch;
- } else {
- break;
+ var fn = Lexer.OPERATORS[ident];
+ if (!fn) {
+ fn = function(self){
+ return self.scope.get(ident);
+ };
+ fn.isAssignable = ident;
}
+ this.tokens.push({index:start, text:ident, fn:fn});
+ },
+
+ readString: function(quote) {
+ var start = this.index;
+ var dateParseLength = this.dateParseLength;
this.index++;
- }
- var fn = Lexer.OPERATORS[ident];
- if (!fn) {
- fn = function(self){
- return self.scope.get(ident);
- };
- fn.isAssignable = ident;
- }
- this.tokens.push({index:start, text:ident, fn:fn});
-};
-Lexer.ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
-Lexer.prototype.readString = function(quote) {
- var start = this.index;
- var dateParseLength = this.dateParseLength;
- this.index++;
- var string = "";
- var escape = false;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (escape) {
- if (ch == 'u') {
- var hex = this.text.substring(this.index + 1, this.index + 5);
- this.index += 4;
- string += String.fromCharCode(parseInt(hex, 16));
- } else {
- var rep = Lexer.ESCAPE[ch];
- if (rep) {
- string += rep;
+ var string = "";
+ var escape = false;
+ while (this.index < this.text.length) {
+ var ch = this.text.charAt(this.index);
+ if (escape) {
+ if (ch == 'u') {
+ var hex = this.text.substring(this.index + 1, this.index + 5);
+ this.index += 4;
+ string += String.fromCharCode(parseInt(hex, 16));
} else {
- string += ch;
+ var rep = Lexer.ESCAPE[ch];
+ if (rep) {
+ string += rep;
+ } else {
+ string += ch;
+ }
}
+ escape = false;
+ } else if (ch == '\\') {
+ escape = true;
+ } else if (ch == quote) {
+ this.index++;
+ this.tokens.push({index:start, text:string,
+ fn:function(){
+ return (string.length == dateParseLength) ?
+ angular['String']['toDate'](string) : string;
+ }});
+ return;
+ } else {
+ string += ch;
}
- escape = false;
- } else if (ch == '\\') {
- escape = true;
- } else if (ch == quote) {
this.index++;
- this.tokens.push({index:start, text:string,
- fn:function(){
- return (string.length == dateParseLength) ?
- angular['String']['toDate'](string) : string;
- }});
- return;
- } else {
- string += ch;
}
+ throw "Lexer Error: Unterminated quote [" +
+ this.text.substring(start) + "] starting at column '" +
+ (start+1) + "' in expression '" + this.text + "'.";
+ },
+
+ readRegexp: function(quote) {
+ var start = this.index;
this.index++;
- }
- throw "Lexer Error: Unterminated quote [" +
- this.text.substring(start) + "] starting at column '" +
- (start+1) + "' in expression '" + this.text + "'.";
-};
-
-Lexer.prototype.readRegexp = function(quote) {
- var start = this.index;
- this.index++;
- var regexp = "";
- var escape = false;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (escape) {
- regexp += ch;
- escape = false;
- } else if (ch === '\\') {
- regexp += ch;
- escape = true;
- } else if (ch === '/') {
- this.index++;
- var flags = "";
- if (this.isIdent(this.text.charAt(this.index))) {
- this.readIdent();
- flags = this.tokens.pop().text;
+ var regexp = "";
+ var escape = false;
+ while (this.index < this.text.length) {
+ var ch = this.text.charAt(this.index);
+ if (escape) {
+ regexp += ch;
+ escape = false;
+ } else if (ch === '\\') {
+ regexp += ch;
+ escape = true;
+ } else if (ch === '/') {
+ this.index++;
+ var flags = "";
+ if (this.isIdent(this.text.charAt(this.index))) {
+ this.readIdent();
+ flags = this.tokens.pop().text;
+ }
+ var compiledRegexp = new RegExp(regexp, flags);
+ this.tokens.push({index:start, text:regexp, flags:flags,
+ fn:function(){return compiledRegexp;}});
+ return;
+ } else {
+ regexp += ch;
}
- var compiledRegexp = new RegExp(regexp, flags);
- this.tokens.push({index:start, text:regexp, flags:flags,
- fn:function(){return compiledRegexp;}});
- return;
- } else {
- regexp += ch;
+ this.index++;
}
- this.index++;
+ throw "Lexer Error: Unterminated RegExp [" +
+ this.text.substring(start) + "] starting at column '" +
+ (start+1) + "' in expression '" + this.text + "'.";
}
- throw "Lexer Error: Unterminated RegExp [" +
- this.text.substring(start) + "] starting at column '" +
- (start+1) + "' in expression '" + this.text + "'.";
};
+/////////////////////////////////////////
-Parser = function(text, parseStrings){
+function Parser(text, parseStrings){
this.text = text;
this.tokens = new Lexer(text, parseStrings).parse();
this.index = 0;
@@ -2317,505 +2344,505 @@ Parser.ZERO = function(){
return 0;
};
-Parser.prototype.error = function(msg, token) {
- throw "Token '" + token.text +
- "' is " + msg + " at column='" +
- (token.index + 1) + "' of expression '" +
- this.text + "' starting at '" + this.text.substring(token.index) + "'.";
-};
-
-Parser.prototype.peekToken = function() {
- if (this.tokens.length === 0)
- throw "Unexpected end of expression: " + this.text;
- return this.tokens[0];
-};
-
-Parser.prototype.peek = function(e1, e2, e3, e4) {
- var tokens = this.tokens;
- if (tokens.length > 0) {
- var token = tokens[0];
- var t = token.text;
- if (t==e1 || t==e2 || t==e3 || t==e4 ||
- (!e1 && !e2 && !e3 && !e4)) {
+Parser.prototype = {
+ error: function(msg, token) {
+ throw "Token '" + token.text +
+ "' is " + msg + " at column='" +
+ (token.index + 1) + "' of expression '" +
+ this.text + "' starting at '" + this.text.substring(token.index) + "'.";
+ },
+
+ peekToken: function() {
+ if (this.tokens.length === 0)
+ throw "Unexpected end of expression: " + this.text;
+ return this.tokens[0];
+ },
+
+ peek: function(e1, e2, e3, e4) {
+ var tokens = this.tokens;
+ if (tokens.length > 0) {
+ var token = tokens[0];
+ var t = token.text;
+ if (t==e1 || t==e2 || t==e3 || t==e4 ||
+ (!e1 && !e2 && !e3 && !e4)) {
+ return token;
+ }
+ }
+ return false;
+ },
+
+ expect: function(e1, e2, e3, e4){
+ var token = this.peek(e1, e2, e3, e4);
+ if (token) {
+ this.tokens.shift();
+ this.currentToken = token;
return token;
}
- }
- return false;
-};
-
-Parser.prototype.expect = function(e1, e2, e3, e4){
- var token = this.peek(e1, e2, e3, e4);
- if (token) {
- this.tokens.shift();
- this.currentToken = token;
- return token;
- }
- return false;
-};
-
-Parser.prototype.consume = function(e1){
- if (!this.expect(e1)) {
- var token = this.peek();
- throw "Expecting '" + e1 + "' at column '" +
- (token.index+1) + "' in '" +
- this.text + "' got '" +
- this.text.substring(token.index) + "'.";
- }
-};
-
-Parser.prototype._unary = function(fn, parse) {
- var right = parse.apply(this);
- return function(self) {
- return fn(self, right(self));
- };
-};
-
-Parser.prototype._binary = function(left, fn, parse) {
- var right = parse.apply(this);
- return function(self) {
- return fn(self, left(self), right(self));
- };
-};
-
-Parser.prototype.hasTokens = function () {
- return this.tokens.length > 0;
-};
-
-Parser.prototype.assertAllConsumed = function(){
- if (this.tokens.length !== 0) {
- throw "Did not understand '" + this.text.substring(this.tokens[0].index) +
- "' while evaluating '" + this.text + "'.";
- }
-};
-
-Parser.prototype.statements = function(){
- var statements = [];
- while(true) {
- if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
- statements.push(this.filterChain());
- if (!this.expect(';')) {
- return function (self){
- var value;
- for ( var i = 0; i < statements.length; i++) {
- var statement = statements[i];
- if (statement)
- value = statement(self);
- }
- return value;
- };
+ return false;
+ },
+
+ consume: function(e1){
+ if (!this.expect(e1)) {
+ var token = this.peek();
+ throw "Expecting '" + e1 + "' at column '" +
+ (token.index+1) + "' in '" +
+ this.text + "' got '" +
+ this.text.substring(token.index) + "'.";
}
- }
-};
-
-Parser.prototype.filterChain = function(){
- var left = this.expression();
- var token;
- while(true) {
- if ((token = this.expect('|'))) {
- left = this._binary(left, token.fn, this.filter);
- } else {
- return left;
+ },
+
+ _unary: function(fn, parse) {
+ var right = parse.apply(this);
+ return function(self) {
+ return fn(self, right(self));
+ };
+ },
+
+ _binary: function(left, fn, parse) {
+ var right = parse.apply(this);
+ return function(self) {
+ return fn(self, left(self), right(self));
+ };
+ },
+
+ hasTokens: function () {
+ return this.tokens.length > 0;
+ },
+
+ assertAllConsumed: function(){
+ if (this.tokens.length !== 0) {
+ throw "Did not understand '" + this.text.substring(this.tokens[0].index) +
+ "' while evaluating '" + this.text + "'.";
}
- }
-};
-
-Parser.prototype.filter = function(){
- return this._pipeFunction(angular['filter']);
-};
-
-Parser.prototype.validator = function(){
- return this._pipeFunction(angular['validator']);
-};
-
-Parser.prototype._pipeFunction = function(fnScope){
- var fn = this.functionIdent(fnScope);
- var argsFn = [];
- var token;
- while(true) {
- if ((token = this.expect(':'))) {
- argsFn.push(this.expression());
- } else {
- var fnInvoke = function(self, input){
- var args = [input];
- for ( var i = 0; i < argsFn.length; i++) {
- args.push(argsFn[i](self));
- }
- return fn.apply(self, args);
- };
- return function(){
- return fnInvoke;
- };
+ },
+
+ statements: function(){
+ var statements = [];
+ while(true) {
+ if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
+ statements.push(this.filterChain());
+ if (!this.expect(';')) {
+ return function (self){
+ var value;
+ for ( var i = 0; i < statements.length; i++) {
+ var statement = statements[i];
+ if (statement)
+ value = statement(self);
+ }
+ return value;
+ };
+ }
}
- }
-};
-
-Parser.prototype.expression = function(){
- return this.throwStmt();
-};
-
-Parser.prototype.throwStmt = function(){
- if (this.expect('throw')) {
- var throwExp = this.assignment();
- return function (self) {
- throw throwExp(self);
- };
- } else {
- return this.assignment();
- }
-};
-
-Parser.prototype.assignment = function(){
- var left = this.logicalOR();
- var token;
- if (token = this.expect('=')) {
- if (!left.isAssignable) {
- throw "Left hand side '" +
- this.text.substring(0, token.index) + "' of assignment '" +
- this.text.substring(token.index) + "' is not assignable.";
+ },
+
+ filterChain: function(){
+ var left = this.expression();
+ var token;
+ while(true) {
+ if ((token = this.expect('|'))) {
+ left = this._binary(left, token.fn, this.filter);
+ } else {
+ return left;
+ }
}
- var ident = function(){return left.isAssignable;};
- return this._binary(ident, token.fn, this.logicalOR);
- } else {
- return left;
- }
-};
-
-Parser.prototype.logicalOR = function(){
- var left = this.logicalAND();
- var token;
- while(true) {
- if ((token = this.expect('||'))) {
- left = this._binary(left, token.fn, this.logicalAND);
+ },
+
+ filter: function(){
+ return this._pipeFunction(angular['filter']);
+ },
+
+ validator: function(){
+ return this._pipeFunction(angular['validator']);
+ },
+
+ _pipeFunction: function(fnScope){
+ var fn = this.functionIdent(fnScope);
+ var argsFn = [];
+ var token;
+ while(true) {
+ if ((token = this.expect(':'))) {
+ argsFn.push(this.expression());
+ } else {
+ var fnInvoke = function(self, input){
+ var args = [input];
+ for ( var i = 0; i < argsFn.length; i++) {
+ args.push(argsFn[i](self));
+ }
+ return fn.apply(self, args);
+ };
+ return function(){
+ return fnInvoke;
+ };
+ }
+ }
+ },
+
+ expression: function(){
+ return this.throwStmt();
+ },
+
+ throwStmt: function(){
+ if (this.expect('throw')) {
+ var throwExp = this.assignment();
+ return function (self) {
+ throw throwExp(self);
+ };
} else {
- return left;
+ return this.assignment();
}
- }
-};
-
-Parser.prototype.logicalAND = function(){
- var left = this.negated();
- var token;
- while(true) {
- if ((token = this.expect('&&'))) {
- left = this._binary(left, token.fn, this.negated);
+ },
+
+ assignment: function(){
+ var left = this.logicalOR();
+ var token;
+ if (token = this.expect('=')) {
+ if (!left.isAssignable) {
+ throw "Left hand side '" +
+ this.text.substring(0, token.index) + "' of assignment '" +
+ this.text.substring(token.index) + "' is not assignable.";
+ }
+ var ident = function(){return left.isAssignable;};
+ return this._binary(ident, token.fn, this.logicalOR);
} else {
- return left;
+ return left;
}
- }
-};
-
-Parser.prototype.negated = function(){
- var token;
- if (token = this.expect('!')) {
- return this._unary(token.fn, this.equality);
- } else {
- return this.equality();
- }
-};
-
-Parser.prototype.equality = function(){
- var left = this.relational();
- var token;
- while(true) {
- if ((token = this.expect('==','!='))) {
- left = this._binary(left, token.fn, this.relational);
+ },
+
+ logicalOR: function(){
+ var left = this.logicalAND();
+ var token;
+ while(true) {
+ if ((token = this.expect('||'))) {
+ left = this._binary(left, token.fn, this.logicalAND);
+ } else {
+ return left;
+ }
+ }
+ },
+
+ logicalAND: function(){
+ var left = this.negated();
+ var token;
+ while(true) {
+ if ((token = this.expect('&&'))) {
+ left = this._binary(left, token.fn, this.negated);
+ } else {
+ return left;
+ }
+ }
+ },
+
+ negated: function(){
+ var token;
+ if (token = this.expect('!')) {
+ return this._unary(token.fn, this.equality);
} else {
- return left;
+ return this.equality();
}
- }
-};
-
-Parser.prototype.relational = function(){
- var left = this.additive();
- var token;
- while(true) {
- if ((token = this.expect('<', '>', '<=', '>='))) {
- left = this._binary(left, token.fn, this.additive);
+ },
+
+ equality: function(){
+ var left = this.relational();
+ var token;
+ while(true) {
+ if ((token = this.expect('==','!='))) {
+ left = this._binary(left, token.fn, this.relational);
+ } else {
+ return left;
+ }
+ }
+ },
+
+ relational: function(){
+ var left = this.additive();
+ var token;
+ while(true) {
+ if ((token = this.expect('<', '>', '<=', '>='))) {
+ left = this._binary(left, token.fn, this.additive);
+ } else {
+ return left;
+ }
+ }
+ },
+
+ additive: function(){
+ var left = this.multiplicative();
+ var token;
+ while(token = this.expect('+','-')) {
+ left = this._binary(left, token.fn, this.multiplicative);
+ }
+ return left;
+ },
+
+ multiplicative: function(){
+ var left = this.unary();
+ var token;
+ while(token = this.expect('*','/','%')) {
+ left = this._binary(left, token.fn, this.unary);
+ }
+ return left;
+ },
+
+ unary: function(){
+ var token;
+ if (this.expect('+')) {
+ return this.primary();
+ } else if (token = this.expect('-')) {
+ return this._binary(Parser.ZERO, token.fn, this.multiplicative);
} else {
- return left;
+ return this.primary();
}
- }
-};
-
-Parser.prototype.additive = function(){
- var left = this.multiplicative();
- var token;
- while(token = this.expect('+','-')) {
- left = this._binary(left, token.fn, this.multiplicative);
- }
- return left;
-};
-
-Parser.prototype.multiplicative = function(){
- var left = this.unary();
- var token;
- while(token = this.expect('*','/','%')) {
- left = this._binary(left, token.fn, this.unary);
- }
- return left;
-};
-
-Parser.prototype.unary = function(){
- var token;
- if (this.expect('+')) {
- return this.primary();
- } else if (token = this.expect('-')) {
- return this._binary(Parser.ZERO, token.fn, this.multiplicative);
- } else {
- return this.primary();
- }
-};
-
-Parser.prototype.functionIdent = function(fnScope) {
- var token = this.expect();
- var element = token.text.split('.');
- var instance = fnScope;
- var key;
- for ( var i = 0; i < element.length; i++) {
- key = element[i];
- if (instance)
- instance = instance[key];
- }
- if (typeof instance != 'function') {
- throw "Function '" + token.text + "' at column '" +
- (token.index+1) + "' in '" + this.text + "' is not defined.";
- }
- return instance;
-};
-
-Parser.prototype.primary = function() {
- var primary;
- if (this.expect('(')) {
- var expression = this.filterChain();
- this.consume(')');
- primary = expression;
- } else if (this.expect('[')) {
- primary = this.arrayDeclaration();
- } else if (this.expect('{')) {
- primary = this.object();
- } else if (this.expect('{:')) {
- primary = this.closure(false);
- } else if (this.expect('{(')) {
- primary = this.closure(true);
- } else {
+ },
+
+ functionIdent: function(fnScope) {
var token = this.expect();
- primary = token.fn;
- if (!primary) {
- this.error("not a primary expression", token);
- }
- }
- var next;
- while (next = this.expect('(', '[', '.')) {
- if (next.text === '(') {
- primary = this.functionCall(primary);
- } else if (next.text === '[') {
- primary = this.objectIndex(primary);
- } else if (next.text === '.') {
- primary = this.fieldAccess(primary);
+ var element = token.text.split('.');
+ var instance = fnScope;
+ var key;
+ for ( var i = 0; i < element.length; i++) {
+ key = element[i];
+ if (instance)
+ instance = instance[key];
+ }
+ if (typeof instance != 'function') {
+ throw "Function '" + token.text + "' at column '" +
+ (token.index+1) + "' in '" + this.text + "' is not defined.";
+ }
+ return instance;
+ },
+
+ primary: function() {
+ var primary;
+ if (this.expect('(')) {
+ var expression = this.filterChain();
+ this.consume(')');
+ primary = expression;
+ } else if (this.expect('[')) {
+ primary = this.arrayDeclaration();
+ } else if (this.expect('{')) {
+ primary = this.object();
+ } else if (this.expect('{:')) {
+ primary = this.closure(false);
+ } else if (this.expect('{(')) {
+ primary = this.closure(true);
} else {
- throw "IMPOSSIBLE";
+ var token = this.expect();
+ primary = token.fn;
+ if (!primary) {
+ this.error("not a primary expression", token);
+ }
}
- }
- return primary;
-};
-
-Parser.prototype.closure = function(hasArgs) {
- var args = [];
- if (hasArgs) {
- if (!this.expect(')')) {
- args.push(this.expect().text);
- while(this.expect(',')) {
+ var next;
+ while (next = this.expect('(', '[', '.')) {
+ if (next.text === '(') {
+ primary = this.functionCall(primary);
+ } else if (next.text === '[') {
+ primary = this.objectIndex(primary);
+ } else if (next.text === '.') {
+ primary = this.fieldAccess(primary);
+ } else {
+ throw "IMPOSSIBLE";
+ }
+ }
+ return primary;
+ },
+
+ closure: function(hasArgs) {
+ var args = [];
+ if (hasArgs) {
+ if (!this.expect(')')) {
args.push(this.expect().text);
+ while(this.expect(',')) {
+ args.push(this.expect().text);
+ }
+ this.consume(')');
}
- this.consume(')');
+ this.consume(":");
}
- this.consume(":");
- }
- var statements = this.statements();
- this.consume("}");
- return function(self){
- return function($){
- var scope = new Scope(self.scope.state);
- scope.set('$', $);
- for ( var i = 0; i < args.length; i++) {
- scope.set(args[i], arguments[i]);
- }
- return statements({scope:scope});
- };
- };
-};
-
-Parser.prototype.fieldAccess = function(object) {
- var field = this.expect().text;
- var fn = function (self){
- return Scope.getter(object(self), field);
- };
- fn.isAssignable = field;
- return fn;
-};
-
-Parser.prototype.objectIndex = function(obj) {
- var indexFn = this.expression();
- this.consume(']');
- if (this.expect('=')) {
- var rhs = this.expression();
- return function (self){
- return obj(self)[indexFn(self)] = rhs(self);
+ var statements = this.statements();
+ this.consume("}");
+ return function(self){
+ return function($){
+ var scope = new Scope(self.scope.state);
+ scope.set('$', $);
+ for ( var i = 0; i < args.length; i++) {
+ scope.set(args[i], arguments[i]);
+ }
+ return statements({scope:scope});
+ };
};
- } else {
- return function (self){
- var o = obj(self);
- var i = indexFn(self);
- return (o) ? o[i] : undefined;
+ },
+
+ fieldAccess: function(object) {
+ var field = this.expect().text;
+ var fn = function (self){
+ return Scope.getter(object(self), field);
};
- }
-};
-
-Parser.prototype.functionCall = function(fn) {
- var argsFn = [];
- if (this.peekToken().text != ')') {
- do {
- argsFn.push(this.expression());
- } while (this.expect(','));
- }
- this.consume(')');
- return function (self){
- var args = [];
- for ( var i = 0; i < argsFn.length; i++) {
- args.push(argsFn[i](self));
- }
- var fnPtr = fn(self);
- if (typeof fnPtr === 'function') {
- return fnPtr.apply(self, args);
+ fn.isAssignable = field;
+ return fn;
+ },
+
+ objectIndex: function(obj) {
+ var indexFn = this.expression();
+ this.consume(']');
+ if (this.expect('=')) {
+ var rhs = this.expression();
+ return function (self){
+ return obj(self)[indexFn(self)] = rhs(self);
+ };
} else {
- throw "Expression '" + fn.isAssignable + "' is not a function.";
+ return function (self){
+ var o = obj(self);
+ var i = indexFn(self);
+ return (o) ? o[i] : undefined;
+ };
}
- };
-};
-
-// This is used with json array declaration
-Parser.prototype.arrayDeclaration = function () {
- var elementFns = [];
- if (this.peekToken().text != ']') {
- do {
- elementFns.push(this.expression());
- } while (this.expect(','));
- }
- this.consume(']');
- return function (self){
- var array = [];
- for ( var i = 0; i < elementFns.length; i++) {
- array.push(elementFns[i](self));
+ },
+
+ functionCall: function(fn) {
+ var argsFn = [];
+ if (this.peekToken().text != ')') {
+ do {
+ argsFn.push(this.expression());
+ } while (this.expect(','));
}
- return array;
- };
-};
-
-Parser.prototype.object = function () {
- var keyValues = [];
- if (this.peekToken().text != '}') {
- do {
- var key = this.expect().text;
- this.consume(":");
- var value = this.expression();
- keyValues.push({key:key, value:value});
- } while (this.expect(','));
- }
- this.consume('}');
- return function (self){
- var object = {};
- for ( var i = 0; i < keyValues.length; i++) {
- var keyValue = keyValues[i];
- var value = keyValue.value(self);
- object[keyValue.key] = value;
- }
- return object;
- };
-};
-
-Parser.prototype.entityDeclaration = function () {
- var decl = [];
- while(this.hasTokens()) {
- decl.push(this.entityDecl());
- if (!this.expect(';')) {
- this.assertAllConsumed();
+ this.consume(')');
+ return function (self){
+ var args = [];
+ for ( var i = 0; i < argsFn.length; i++) {
+ args.push(argsFn[i](self));
+ }
+ var fnPtr = fn(self);
+ if (typeof fnPtr === 'function') {
+ return fnPtr.apply(self, args);
+ } else {
+ throw "Expression '" + fn.isAssignable + "' is not a function.";
+ }
+ };
+ },
+
+ // This is used with json array declaration
+ arrayDeclaration: function () {
+ var elementFns = [];
+ if (this.peekToken().text != ']') {
+ do {
+ elementFns.push(this.expression());
+ } while (this.expect(','));
}
- }
- return function (self){
- var code = "";
- for ( var i = 0; i < decl.length; i++) {
- code += decl[i](self);
+ this.consume(']');
+ return function (self){
+ var array = [];
+ for ( var i = 0; i < elementFns.length; i++) {
+ array.push(elementFns[i](self));
+ }
+ return array;
+ };
+ },
+
+ object: function () {
+ var keyValues = [];
+ if (this.peekToken().text != '}') {
+ do {
+ var key = this.expect().text;
+ this.consume(":");
+ var value = this.expression();
+ keyValues.push({key:key, value:value});
+ } while (this.expect(','));
}
- return code;
- };
-};
-
-Parser.prototype.entityDecl = function () {
- var entity = this.expect().text;
- var instance;
- var defaults;
- if (this.expect('=')) {
- instance = entity;
- entity = this.expect().text;
- }
- if (this.expect(':')) {
- defaults = this.primary()(null);
- }
- return function(self) {
- var datastore = self.scope.get('$datastore');
- var Entity = datastore.entity(entity, defaults);
- self.scope.set(entity, Entity);
- if (instance) {
- var document = Entity();
- document.$$anchor = instance;
- self.scope.set(instance, document);
- return "$anchor." + instance + ":{" +
- instance + "=" + entity + ".load($anchor." + instance + ");" +
- instance + ".$$anchor=" + angular['String']['quote'](instance) + ";" +
- "};";
- } else {
- return "";
+ this.consume('}');
+ return function (self){
+ var object = {};
+ for ( var i = 0; i < keyValues.length; i++) {
+ var keyValue = keyValues[i];
+ var value = keyValue.value(self);
+ object[keyValue.key] = value;
+ }
+ return object;
+ };
+ },
+
+ entityDeclaration: function () {
+ var decl = [];
+ while(this.hasTokens()) {
+ decl.push(this.entityDecl());
+ if (!this.expect(';')) {
+ this.assertAllConsumed();
+ }
}
- };
-};
-
-Parser.prototype.watch = function () {
- var decl = [];
- while(this.hasTokens()) {
- decl.push(this.watchDecl());
- if (!this.expect(';')) {
- this.assertAllConsumed();
+ return function (self){
+ var code = "";
+ for ( var i = 0; i < decl.length; i++) {
+ code += decl[i](self);
+ }
+ return code;
+ };
+ },
+
+ entityDecl: function () {
+ var entity = this.expect().text;
+ var instance;
+ var defaults;
+ if (this.expect('=')) {
+ instance = entity;
+ entity = this.expect().text;
+ }
+ if (this.expect(':')) {
+ defaults = this.primary()(null);
+ }
+ return function(self) {
+ var datastore = self.scope.get('$datastore');
+ var Entity = datastore.entity(entity, defaults);
+ self.scope.set(entity, Entity);
+ if (instance) {
+ var document = Entity();
+ document.$$anchor = instance;
+ self.scope.set(instance, document);
+ return "$anchor." + instance + ":{" +
+ instance + "=" + entity + ".load($anchor." + instance + ");" +
+ instance + ".$$anchor=" + angular['String']['quote'](instance) + ";" +
+ "};";
+ } else {
+ return "";
+ }
+ };
+ },
+
+ watch: function () {
+ var decl = [];
+ while(this.hasTokens()) {
+ decl.push(this.watchDecl());
+ if (!this.expect(';')) {
+ this.assertAllConsumed();
+ }
}
- }
- this.assertAllConsumed();
- return function (self){
- for ( var i = 0; i < decl.length; i++) {
- var d = decl[i](self);
- self.addListener(d.name, d.fn);
+ this.assertAllConsumed();
+ return function (self){
+ for ( var i = 0; i < decl.length; i++) {
+ var d = decl[i](self);
+ self.addListener(d.name, d.fn);
+ }
+ };
+ },
+
+ watchDecl: function () {
+ var anchorName = this.expect().text;
+ this.consume(":");
+ var expression;
+ if (this.peekToken().text == '{') {
+ this.consume("{");
+ expression = this.statements();
+ this.consume("}");
+ } else {
+ expression = this.expression();
}
- };
-};
-
-Parser.prototype.watchDecl = function () {
- var anchorName = this.expect().text;
- this.consume(":");
- var expression;
- if (this.peekToken().text == '{') {
- this.consume("{");
- expression = this.statements();
- this.consume("}");
- } else {
- expression = this.expression();
+ return function(self) {
+ return {name:anchorName, fn:expression};
+ };
}
- return function(self) {
- return {name:anchorName, fn:expression};
- };
};
-// Copyright (C) 2009 BRAT Tech LLC
-
-Scope = function(initialState, name) {
+function Scope(initialState, name) {
this.widgets = [];
this.watchListeners = {};
this.name = name;
@@ -2830,31 +2857,6 @@ Scope = function(initialState, name) {
};
Scope.expressionCache = {};
-
-Scope.prototype.updateView = function() {
- var self = this;
- this.fireWatchers();
- _.each(this.widgets, function(widget){
- self.evalWidget(widget, "", {}, function(){
- this.updateView(self);
- });
- });
-};
-
-Scope.prototype.addWidget = function(controller) {
- if (controller) this.widgets.push(controller);
-};
-
-Scope.prototype.isProperty = function(exp) {
- for ( var i = 0; i < exp.length; i++) {
- var ch = exp.charAt(i);
- if (ch!='.' && !Lexer.prototype.isIdent(ch)) {
- return false;
- }
- }
- return true;
-};
-
Scope.getter = function(instance, path) {
if (!path) return instance;
var element = path.split('.');
@@ -2885,135 +2887,158 @@ Scope.getter = function(instance, path) {
return instance;
};
-Scope.prototype.get = function(path) {
- return Scope.getter(this.state, path);
-};
-
-Scope.prototype.set = function(path, value) {
- var element = path.split('.');
- var instance = this.state;
- for ( var i = 0; element.length > 1; i++) {
- var key = element.shift();
- var newInstance = instance[key];
- if (!newInstance) {
- newInstance = {};
- instance[key] = newInstance;
- }
- instance = newInstance;
- }
- instance[element.shift()] = value;
- return value;
-};
-
-Scope.prototype.setEval = function(expressionText, value) {
- this.eval(expressionText + "=" + toJson(value));
-};
-
-Scope.prototype.eval = function(expressionText, context) {
- var expression = Scope.expressionCache[expressionText];
- if (!expression) {
- var parser = new Parser(expressionText);
- expression = parser.statements();
- parser.assertAllConsumed();
- Scope.expressionCache[expressionText] = expression;
- }
- context = context || {};
- context.scope = this;
- return expression(context);
-};
-
-//TODO: Refactor. This function needs to be an execution closure for widgets
-// move to widgets
-// remove expression, just have inner closure.
-Scope.prototype.evalWidget = function(widget, expression, context, onSuccess, onFailure) {
- try {
- var value = this.eval(expression, context);
- if (widget.hasError) {
- widget.hasError = false;
- jQuery(widget.view).
- removeClass('ng-exception').
- removeAttr('ng-error');
- }
- if (onSuccess) {
- value = onSuccess.apply(widget, [value]);
+Scope.prototype = {
+ updateView: function() {
+ var self = this;
+ this.fireWatchers();
+ _.each(this.widgets, function(widget){
+ self.evalWidget(widget, "", {}, function(){
+ this.updateView(self);
+ });
+ });
+ },
+
+ addWidget: function(controller) {
+ if (controller) this.widgets.push(controller);
+ },
+
+ isProperty: function(exp) {
+ for ( var i = 0; i < exp.length; i++) {
+ var ch = exp.charAt(i);
+ if (ch!='.' && !Lexer.prototype.isIdent(ch)) {
+ return false;
+ }
}
return true;
- } catch (e){
- error('Eval Widget Error:', e);
- var jsonError = toJson(e, true);
- widget.hasError = true;
- jQuery(widget.view).
- addClass('ng-exception').
- attr('ng-error', jsonError);
- if (onFailure) {
- onFailure.apply(widget, [e, jsonError]);
+ },
+
+ get: function(path) {
+ return Scope.getter(this.state, path);
+ },
+
+ set: function(path, value) {
+ var element = path.split('.');
+ var instance = this.state;
+ for ( var i = 0; element.length > 1; i++) {
+ var key = element.shift();
+ var newInstance = instance[key];
+ if (!newInstance) {
+ newInstance = {};
+ instance[key] = newInstance;
+ }
+ instance = newInstance;
}
- return false;
- }
-};
-
-Scope.prototype.validate = function(expressionText, value) {
- var expression = Scope.expressionCache[expressionText];
- if (!expression) {
- expression = new Parser(expressionText).validator();
- Scope.expressionCache[expressionText] = expression;
- }
- var self = {scope:this};
- return expression(self)(self, value);
-};
-
-Scope.prototype.entity = function(entityDeclaration) {
- var expression = new Parser(entityDeclaration).entityDeclaration();
- return expression({scope:this});
-};
-
-Scope.prototype.markInvalid = function(widget) {
- this.state.$invalidWidgets.push(widget);
-};
-
-Scope.prototype.watch = function(declaration) {
- var self = this;
- new Parser(declaration).watch()({
- scope:this,
- addListener:function(watch, exp){
- self.addWatchListener(watch, function(n,o){
- try {
- return exp({scope:self}, n, o);
- } catch(e) {
- alert(e);
- }
- });
+ instance[element.shift()] = value;
+ return value;
+ },
+
+ setEval: function(expressionText, value) {
+ this.eval(expressionText + "=" + toJson(value));
+ },
+
+ eval: function(expressionText, context) {
+ var expression = Scope.expressionCache[expressionText];
+ if (!expression) {
+ var parser = new Parser(expressionText);
+ expression = parser.statements();
+ parser.assertAllConsumed();
+ Scope.expressionCache[expressionText] = expression;
+ }
+ context = context || {};
+ context.scope = this;
+ return expression(context);
+ },
+
+ //TODO: Refactor. This function needs to be an execution closure for widgets
+ // move to widgets
+ // remove expression, just have inner closure.
+ evalWidget: function(widget, expression, context, onSuccess, onFailure) {
+ try {
+ var value = this.eval(expression, context);
+ if (widget.hasError) {
+ widget.hasError = false;
+ jQuery(widget.view).
+ removeClass('ng-exception').
+ removeAttr('ng-error');
+ }
+ if (onSuccess) {
+ value = onSuccess.apply(widget, [value]);
+ }
+ return true;
+ } catch (e){
+ error('Eval Widget Error:', e);
+ var jsonError = toJson(e, true);
+ widget.hasError = true;
+ jQuery(widget.view).
+ addClass('ng-exception').
+ attr('ng-error', jsonError);
+ if (onFailure) {
+ onFailure.apply(widget, [e, jsonError]);
+ }
+ return false;
}
- });
-};
-
-Scope.prototype.addWatchListener = function(watchExpression, listener) {
- var watcher = this.watchListeners[watchExpression];
- if (!watcher) {
- watcher = {listeners:[], expression:watchExpression};
- this.watchListeners[watchExpression] = watcher;
- }
- watcher.listeners.push(listener);
-};
-
-Scope.prototype.fireWatchers = function() {
- var self = this;
- var fired = false;
- foreach(this.watchListeners, function(watcher) {
- var value = self.eval(watcher.expression);
- if (value !== watcher.lastValue) {
- foreach(watcher.listeners, function(listener){
- listener(value, watcher.lastValue);
- fired = true;
- });
- watcher.lastValue = value;
+ },
+
+ validate: function(expressionText, value) {
+ var expression = Scope.expressionCache[expressionText];
+ if (!expression) {
+ expression = new Parser(expressionText).validator();
+ Scope.expressionCache[expressionText] = expression;
+ }
+ var self = {scope:this};
+ return expression(self)(self, value);
+ },
+
+ entity: function(entityDeclaration) {
+ var expression = new Parser(entityDeclaration).entityDeclaration();
+ return expression({scope:this});
+ },
+
+ markInvalid: function(widget) {
+ this.state.$invalidWidgets.push(widget);
+ },
+
+ watch: function(declaration) {
+ var self = this;
+ new Parser(declaration).watch()({
+ scope:this,
+ addListener:function(watch, exp){
+ self.addWatchListener(watch, function(n,o){
+ try {
+ return exp({scope:self}, n, o);
+ } catch(e) {
+ alert(e);
+ }
+ });
+ }
+ });
+ },
+
+ addWatchListener: function(watchExpression, listener) {
+ var watcher = this.watchListeners[watchExpression];
+ if (!watcher) {
+ watcher = {listeners:[], expression:watchExpression};
+ this.watchListeners[watchExpression] = watcher;
}
- });
- return fired;
-};
-// Copyright (C) 2008,2009 BRAT Tech LLC
-
-Server = function(url, getScript) {
+ watcher.listeners.push(listener);
+ },
+
+ fireWatchers: function() {
+ var self = this;
+ var fired = false;
+ foreach(this.watchListeners, function(watcher) {
+ var value = self.eval(watcher.expression);
+ if (value !== watcher.lastValue) {
+ foreach(watcher.listeners, function(listener){
+ listener(value, watcher.lastValue);
+ fired = true;
+ });
+ watcher.lastValue = value;
+ }
+ });
+ return fired;
+ }
+};function Server(url, getScript) {
this.url = url;
this.nextId = 0;
this.getScript = getScript;
@@ -3021,27 +3046,29 @@ Server = function(url, getScript) {
this.maxSize = 1800;
};
-Server.prototype.base64url = function(txt) {
- return Base64.encode(txt);
-};
-
-Server.prototype.request = function(method, url, request, callback) {
- var requestId = this.uuid + (this.nextId++);
- angularCallbacks[requestId] = function(response) {
- delete angular[requestId];
- callback(200, response);
- };
- var payload = {u:url, m:method, p:request};
- payload = this.base64url(toJson(payload));
- var totalPockets = Math.ceil(payload.length / this.maxSize);
- var baseUrl = this.url + "/$/" + requestId + "/" + totalPockets + "/";
- for ( var pocketNo = 0; pocketNo < totalPockets; pocketNo++) {
- var pocket = payload.substr(pocketNo * this.maxSize, this.maxSize);
- this.getScript(baseUrl + (pocketNo+1) + "?h=" + pocket, noop);
+Server.prototype = {
+ base64url: function(txt) {
+ return Base64.encode(txt);
+ },
+
+ request: function(method, url, request, callback) {
+ var requestId = this.uuid + (this.nextId++);
+ angularCallbacks[requestId] = function(response) {
+ delete angular[requestId];
+ callback(200, response);
+ };
+ var payload = {u:url, m:method, p:request};
+ payload = this.base64url(toJson(payload));
+ var totalPockets = Math.ceil(payload.length / this.maxSize);
+ var baseUrl = this.url + "/$/" + requestId + "/" + totalPockets + "/";
+ for ( var pocketNo = 0; pocketNo < totalPockets; pocketNo++) {
+ var pocket = payload.substr(pocketNo * this.maxSize, this.maxSize);
+ this.getScript(baseUrl + (pocketNo+1) + "?h=" + pocket, noop);
+ }
}
};
-FrameServer = function(frame) {
+function FrameServer(frame) {
this.frame = frame;
};
FrameServer.PREFIX = "$DATASET:";
@@ -3059,7 +3086,7 @@ FrameServer.prototype = {
};
-VisualServer = function(delegate, status, update) {
+function VisualServer(delegate, status, update) {
this.delegate = delegate;
this.update = update;
this.status = status;
@@ -3080,14 +3107,13 @@ VisualServer.prototype = {
});
}
};
-// Copyright (C) 2008,2009 BRAT Tech LLC
-Users = function(server, controlBar) {
+function Users(server, controlBar) {
this.server = server;
this.controlBar = controlBar;
};
Users.prototype = {
- fetchCurrentUser:function(callback) {
+ 'fetchCurrentUser':function(callback) {
var self = this;
this.server.request("GET", "/account.json", {}, function(code, response){
self.current = response.user;
@@ -3095,7 +3121,7 @@ Users.prototype = {
});
},
- logout: function(callback) {
+ 'logout': function(callback) {
var self = this;
this.controlBar.logout(function(){
delete self.current;
@@ -3103,7 +3129,7 @@ Users.prototype = {
});
},
- login: function(callback) {
+ 'login': function(callback) {
var self = this;
this.controlBar.login(function(){
self.fetchCurrentUser(function(){
@@ -3112,12 +3138,10 @@ Users.prototype = {
});
},
- notAuthorized: function(){
+ 'notAuthorized': function(){
this.controlBar.notAuthorized();
}
};
-// Copyright (C) 2009 BRAT Tech LLC
-
foreach({
'regexp': function(value, regexp, msg) {
if (!value.match(regexp)) {
@@ -3198,10 +3222,7 @@ foreach({
}
}
}, function(v,k) {angularValidator[k] = v;});
-// Copyright (C) 2009 BRAT Tech LLC
-
-
-WidgetFactory = function(serverUrl, database) {
+function WidgetFactory(serverUrl, database) {
this.nextUploadId = 0;
this.serverUrl = serverUrl;
this.database = database;
@@ -3215,80 +3236,81 @@ WidgetFactory = function(serverUrl, database) {
this.onChangeListener = function(){};
};
-WidgetFactory.prototype.createController = function(input, scope) {
- var controller;
- var type = input.attr('type').toLowerCase();
- var exp = input.attr('name');
- if (exp) exp = exp.split(':').pop();
- var event = "change";
- var bubbleEvent = true;
- if (type == 'button' || type == 'submit' || type == 'reset' || type == 'image') {
- controller = new ButtonController(input[0], exp);
- event = "click";
- bubbleEvent = false;
- } else if (type == 'text' || type == 'textarea' || type == 'hidden' || type == 'password') {
- controller = new TextController(input[0], exp);
- event = "keyup change";
- } else if (type == 'checkbox') {
- controller = new CheckboxController(input[0], exp);
- event = "click";
- } else if (type == 'radio') {
- controller = new RadioController(input[0], exp);
- event="click";
- } else if (type == 'select-one') {
- controller = new SelectController(input[0], exp);
- } else if (type == 'select-multiple') {
- controller = new MultiSelectController(input[0], exp);
- } else if (type == 'file') {
- controller = this.createFileController(input, exp);
- } else {
- throw 'Unknown type: ' + type;
- }
- input.data('controller', controller);
- var binder = scope.get('$binder');
- var action = function() {
- if (controller.updateModel(scope)) {
- var action = jQuery(controller.view).attr('ng-action') || "";
- if (scope.evalWidget(controller, action)) {
- binder.updateView(scope);
+WidgetFactory.prototype = {
+ createController: function(input, scope) {
+ var controller;
+ var type = input.attr('type').toLowerCase();
+ var exp = input.attr('name');
+ if (exp) exp = exp.split(':').pop();
+ var event = "change";
+ var bubbleEvent = true;
+ if (type == 'button' || type == 'submit' || type == 'reset' || type == 'image') {
+ controller = new ButtonController(input[0], exp);
+ event = "click";
+ bubbleEvent = false;
+ } else if (type == 'text' || type == 'textarea' || type == 'hidden' || type == 'password') {
+ controller = new TextController(input[0], exp);
+ event = "keyup change";
+ } else if (type == 'checkbox') {
+ controller = new CheckboxController(input[0], exp);
+ event = "click";
+ } else if (type == 'radio') {
+ controller = new RadioController(input[0], exp);
+ event="click";
+ } else if (type == 'select-one') {
+ controller = new SelectController(input[0], exp);
+ } else if (type == 'select-multiple') {
+ controller = new MultiSelectController(input[0], exp);
+ } else if (type == 'file') {
+ controller = this.createFileController(input, exp);
+ } else {
+ throw 'Unknown type: ' + type;
+ }
+ input.data('controller', controller);
+ var binder = scope.get('$binder');
+ var action = function() {
+ if (controller.updateModel(scope)) {
+ var action = jQuery(controller.view).attr('ng-action') || "";
+ if (scope.evalWidget(controller, action)) {
+ binder.updateView(scope);
+ }
}
- }
- return bubbleEvent;
- };
- jQuery(controller.view, ":input").
- bind(event, action);
- return controller;
-};
-
-WidgetFactory.prototype.createFileController = function(fileInput) {
- var uploadId = '__uploadWidget_' + (this.nextUploadId++);
- var view = FileController.template(uploadId);
- fileInput.after(view);
- var att = {
- data:this.serverUrl + "/admin/ServerAPI.swf",
- width:"95", height:"20", align:"top",
- wmode:"transparent"};
- var par = {
- flashvars:"uploadWidgetId=" + uploadId,
- allowScriptAccess:"always"};
- var swfNode = this.createSWF(att, par, uploadId);
- fileInput.remove();
- var cntl = new FileController(view, fileInput[0].name, swfNode, this.serverUrl + "/data/" + this.database);
- jQuery(swfNode).data('controller', cntl);
- return cntl;
-};
-
-WidgetFactory.prototype.createTextWidget = function(textInput) {
- var controller = new TextController(textInput);
- controller.onChange(this.onChangeListener);
- return controller;
+ return bubbleEvent;
+ };
+ jQuery(controller.view, ":input").
+ bind(event, action);
+ return controller;
+ },
+
+ createFileController: function(fileInput) {
+ var uploadId = '__uploadWidget_' + (this.nextUploadId++);
+ var view = FileController.template(uploadId);
+ fileInput.after(view);
+ var att = {
+ data:this.serverUrl + "/admin/ServerAPI.swf",
+ width:"95", height:"20", align:"top",
+ wmode:"transparent"};
+ var par = {
+ flashvars:"uploadWidgetId=" + uploadId,
+ allowScriptAccess:"always"};
+ var swfNode = this.createSWF(att, par, uploadId);
+ fileInput.remove();
+ var cntl = new FileController(view, fileInput[0].name, swfNode, this.serverUrl + "/data/" + this.database);
+ jQuery(swfNode).data('controller', cntl);
+ return cntl;
+ },
+
+ createTextWidget: function(textInput) {
+ var controller = new TextController(textInput);
+ controller.onChange(this.onChangeListener);
+ return controller;
+ }
};
-
/////////////////////
// FileController
///////////////////////
-FileController = function(view, scopeName, uploader, databaseUrl) {
+function FileController(view, scopeName, uploader, databaseUrl) {
this.view = view;
this.uploader = uploader;
this.scopeName = scopeName;
@@ -3312,99 +3334,89 @@ FileController.template = function(id) {
'</span>');
};
-FileController.prototype._on_cancel = function() {
-};
-
-FileController.prototype._on_complete = function() {
-};
-
-FileController.prototype._on_httpStatus = function(status) {
- alert("httpStatus:" + this.scopeName + " status:" + status);
-};
-
-FileController.prototype._on_ioError = function() {
- alert("ioError:" + this.scopeName);
-};
-
-FileController.prototype._on_open = function() {
- alert("open:" + this.scopeName);
-};
-
-FileController.prototype._on_progress = function(bytesLoaded, bytesTotal) {
-};
-
-FileController.prototype._on_securityError = function() {
- alert("securityError:" + this.scopeName);
-};
-
-FileController.prototype._on_uploadCompleteData = function(data) {
- var value = fromJson(data);
- value.url = this.attachmentsPath + '/' + value.id + '/' + value.text;
- this.view.find("input").attr('checked', true);
- var scope = this.view.scope();
- this.value = value;
- this.updateModel(scope);
- this.value = null;
- scope.get('$binder').updateView();
-};
-
-FileController.prototype._on_select = function(name, size, type) {
- this.name = name;
- this.view.find("a").text(name).attr('href', name);
- this.view.find("span").text(angular['filter']['bytes'](size));
- this.upload();
-};
-
-FileController.prototype.updateModel = function(scope) {
- var isChecked = this.view.find("input").attr('checked');
- var value = isChecked ? this.value : null;
- if (this.lastValue === value) {
- return false;
- } else {
- scope.set(this.scopeName, value);
- return true;
- }
-};
-
-FileController.prototype.updateView = function(scope) {
- var modelValue = scope.get(this.scopeName);
- if (modelValue && this.value !== modelValue) {
- this.value = modelValue;
- this.view.find("a").
- attr("href", this.value.url).
- text(this.value.text);
- this.view.find("span").text(angular['filter']['bytes'](this.value.size));
- }
- this.view.find("input").attr('checked', !!modelValue);
-};
-
-FileController.prototype.upload = function() {
- if (this.name) {
- this.uploader.uploadFile(this.attachmentsPath);
+FileController.prototype = {
+ '_on_cancel': noop,
+ '_on_complete': noop,
+ '_on_httpStatus': function(status) {
+ alert("httpStatus:" + this.scopeName + " status:" + status);
+ },
+ '_on_ioError': function() {
+ alert("ioError:" + this.scopeName);
+ },
+ '_on_open': function() {
+ alert("open:" + this.scopeName);
+ },
+ '_on_progress':noop,
+ '_on_securityError': function() {
+ alert("securityError:" + this.scopeName);
+ },
+ '_on_uploadCompleteData': function(data) {
+ var value = fromJson(data);
+ value.url = this.attachmentsPath + '/' + value.id + '/' + value.text;
+ this.view.find("input").attr('checked', true);
+ var scope = this.view.scope();
+ this.value = value;
+ this.updateModel(scope);
+ this.value = null;
+ scope.get('$binder').updateView();
+ },
+ '_on_select': function(name, size, type) {
+ this.name = name;
+ this.view.find("a").text(name).attr('href', name);
+ this.view.find("span").text(angular['filter']['bytes'](size));
+ this.upload();
+ },
+
+ updateModel: function(scope) {
+ var isChecked = this.view.find("input").attr('checked');
+ var value = isChecked ? this.value : null;
+ if (this.lastValue === value) {
+ return false;
+ } else {
+ scope.set(this.scopeName, value);
+ return true;
+ }
+ },
+
+ updateView: function(scope) {
+ var modelValue = scope.get(this.scopeName);
+ if (modelValue && this.value !== modelValue) {
+ this.value = modelValue;
+ this.view.find("a").
+ attr("href", this.value.url).
+ text(this.value.text);
+ this.view.find("span").text(angular['filter']['bytes'](this.value.size));
+ }
+ this.view.find("input").attr('checked', !!modelValue);
+ },
+
+ upload: function() {
+ if (this.name) {
+ this.uploader.uploadFile(this.attachmentsPath);
+ }
}
};
-
///////////////////////
// NullController
///////////////////////
-NullController = function(view) {this.view = view;};
-NullController.prototype.updateModel = function() { return true; };
-NullController.prototype.updateView = function() { };
+function NullController(view) {this.view = view;};
+NullController.prototype = {
+ updateModel: function() { return true; },
+ updateView: noop
+};
NullController.instance = new NullController();
///////////////////////
// ButtonController
///////////////////////
-ButtonController = function(view) {this.view = view;};
-ButtonController.prototype.updateModel = function(scope) { return true; };
-ButtonController.prototype.updateView = function(scope) {};
+var ButtonController = NullController;
///////////////////////
// TextController
///////////////////////
-TextController = function(view, exp) {
+function TextController(view, exp) {
this.view = view;
this.exp = exp;
this.validator = view.getAttribute('ng-validate');
@@ -3418,175 +3430,183 @@ TextController = function(view, exp) {
}
};
-TextController.prototype.updateModel = function(scope) {
- var value = this.view.value;
- if (this.lastValue === value) {
- return false;
- } else {
- scope.setEval(this.exp, value);
- this.lastValue = value;
- return true;
- }
-};
-
-TextController.prototype.updateView = function(scope) {
- var view = this.view;
- var value = scope.get(this.exp);
- if (typeof value === "undefined") {
- value = this.initialValue;
- scope.setEval(this.exp, value);
- }
- value = value ? value : '';
- if (this.lastValue != value) {
- view.value = value;
- this.lastValue = value;
- }
- var isValidationError = false;
- view.removeAttribute('ng-error');
- if (this.required) {
- isValidationError = !(value && value.length > 0);
- }
- var errorText = isValidationError ? "Required Value" : null;
- if (!isValidationError && this.validator && value) {
- errorText = scope.validate(this.validator, value);
- isValidationError = !!errorText;
- }
- if (this.lastErrorText !== errorText) {
- this.lastErrorText = isValidationError;
- if (errorText !== null) {
- view.setAttribute('ng-error', errorText);
- scope.markInvalid(this);
+TextController.prototype = {
+ updateModel: function(scope) {
+ var value = this.view.value;
+ if (this.lastValue === value) {
+ return false;
+ } else {
+ scope.setEval(this.exp, value);
+ this.lastValue = value;
+ return true;
+ }
+ },
+
+ updateView: function(scope) {
+ var view = this.view;
+ var value = scope.get(this.exp);
+ if (typeof value === "undefined") {
+ value = this.initialValue;
+ scope.setEval(this.exp, value);
+ }
+ value = value ? value : '';
+ if (this.lastValue != value) {
+ view.value = value;
+ this.lastValue = value;
+ }
+ var isValidationError = false;
+ view.removeAttribute('ng-error');
+ if (this.required) {
+ isValidationError = !(value && value.length > 0);
+ }
+ var errorText = isValidationError ? "Required Value" : null;
+ if (!isValidationError && this.validator && value) {
+ errorText = scope.validate(this.validator, value);
+ isValidationError = !!errorText;
+ }
+ if (this.lastErrorText !== errorText) {
+ this.lastErrorText = isValidationError;
+ if (errorText !== null) {
+ view.setAttribute('ng-error', errorText);
+ scope.markInvalid(this);
+ }
+ jQuery(view).toggleClass('ng-validation-error', isValidationError);
}
- jQuery(view).toggleClass('ng-validation-error', isValidationError);
}
};
///////////////////////
// CheckboxController
///////////////////////
-CheckboxController = function(view, exp) {
+function CheckboxController(view, exp) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.initialValue = view.checked ? view.value : "";
};
-CheckboxController.prototype.updateModel = function(scope) {
- var input = this.view;
- var value = input.checked ? input.value : '';
- if (this.lastValue === value) {
- return false;
- } else {
- scope.setEval(this.exp, value);
- this.lastValue = value;
- return true;
- }
-};
-
-CheckboxController.prototype.updateView = function(scope) {
- var input = this.view;
- var value = scope.eval(this.exp);
- if (typeof value === "undefined") {
- value = this.initialValue;
- scope.setEval(this.exp, value);
+CheckboxController.prototype = {
+ updateModel: function(scope) {
+ var input = this.view;
+ var value = input.checked ? input.value : '';
+ if (this.lastValue === value) {
+ return false;
+ } else {
+ scope.setEval(this.exp, value);
+ this.lastValue = value;
+ return true;
+ }
+ },
+
+ updateView: function(scope) {
+ var input = this.view;
+ var value = scope.eval(this.exp);
+ if (typeof value === "undefined") {
+ value = this.initialValue;
+ scope.setEval(this.exp, value);
+ }
+ input.checked = input.value == (''+value);
}
- input.checked = input.value == (''+value);
};
///////////////////////
// SelectController
///////////////////////
-SelectController = function(view, exp) {
+function SelectController(view, exp) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.initialValue = view.value;
};
-SelectController.prototype.updateModel = function(scope) {
- var input = this.view;
- if (input.selectedIndex < 0) {
- scope.setEval(this.exp, null);
- } else {
- var value = this.view.value;
- if (this.lastValue === value) {
- return false;
+SelectController.prototype = {
+ updateModel: function(scope) {
+ var input = this.view;
+ if (input.selectedIndex < 0) {
+ scope.setEval(this.exp, null);
} else {
+ var value = this.view.value;
+ if (this.lastValue === value) {
+ return false;
+ } else {
+ scope.setEval(this.exp, value);
+ this.lastValue = value;
+ return true;
+ }
+ }
+ },
+
+ updateView: function(scope) {
+ var input = this.view;
+ var value = scope.get(this.exp);
+ if (typeof value === 'undefined') {
+ value = this.initialValue;
scope.setEval(this.exp, value);
+ }
+ if (value !== this.lastValue) {
+ input.value = value ? value : "";
this.lastValue = value;
- return true;
}
}
};
-SelectController.prototype.updateView = function(scope) {
- var input = this.view;
- var value = scope.get(this.exp);
- if (typeof value === 'undefined') {
- value = this.initialValue;
- scope.setEval(this.exp, value);
- }
- if (value !== this.lastValue) {
- input.value = value ? value : "";
- this.lastValue = value;
- }
-};
-
///////////////////////
// MultiSelectController
///////////////////////
-MultiSelectController = function(view, exp) {
+function MultiSelectController(view, exp) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.initialValue = this.selected();
};
-MultiSelectController.prototype.selected = function () {
- var value = [];
- var options = this.view.options;
- for ( var i = 0; i < options.length; i++) {
- var option = options[i];
- if (option.selected) {
- value.push(option.value);
- }
- }
- return value;
-};
-
-MultiSelectController.prototype.updateModel = function(scope) {
- var value = this.selected();
- // TODO: This is wrong! no caching going on here as we are always comparing arrays
- if (this.lastValue === value) {
- return false;
- } else {
- scope.setEval(this.exp, value);
- this.lastValue = value;
- return true;
- }
-};
-
-MultiSelectController.prototype.updateView = function(scope) {
- var input = this.view;
- var selected = scope.get(this.exp);
- if (typeof selected === "undefined") {
- selected = this.initialValue;
- scope.setEval(this.exp, selected);
- }
- if (selected !== this.lastValue) {
- var options = input.options;
+MultiSelectController.prototype = {
+ selected: function () {
+ var value = [];
+ var options = this.view.options;
for ( var i = 0; i < options.length; i++) {
var option = options[i];
- option.selected = _.include(selected, option.value);
+ if (option.selected) {
+ value.push(option.value);
+ }
+ }
+ return value;
+ },
+
+ updateModel: function(scope) {
+ var value = this.selected();
+ // TODO: This is wrong! no caching going on here as we are always comparing arrays
+ if (this.lastValue === value) {
+ return false;
+ } else {
+ scope.setEval(this.exp, value);
+ this.lastValue = value;
+ return true;
+ }
+ },
+
+ updateView: function(scope) {
+ var input = this.view;
+ var selected = scope.get(this.exp);
+ if (typeof selected === "undefined") {
+ selected = this.initialValue;
+ scope.setEval(this.exp, selected);
+ }
+ if (selected !== this.lastValue) {
+ var options = input.options;
+ for ( var i = 0; i < options.length; i++) {
+ var option = options[i];
+ option.selected = _.include(selected, option.value);
+ }
+ this.lastValue = selected;
}
- this.lastValue = selected;
}
};
///////////////////////
// RadioController
///////////////////////
-RadioController = function(view, exp) {
+function RadioController(view, exp) {
this.view = view;
this.exp = exp;
this.lastChecked = undefined;
@@ -3595,35 +3615,37 @@ RadioController = function(view, exp) {
this.initialValue = view.checked ? view.value : null;
};
-RadioController.prototype.updateModel = function(scope) {
- var input = this.view;
- if (this.lastChecked) {
- return false;
- } else {
- input.checked = true;
- this.lastValue = scope.setEval(this.exp, this.inputValue);
- this.lastChecked = true;
- return true;
- }
-};
-
-RadioController.prototype.updateView = function(scope) {
- var input = this.view;
- var value = scope.get(this.exp);
- if (this.initialValue && typeof value === "undefined") {
- value = this.initialValue;
- scope.setEval(this.exp, value);
- }
- if (this.lastValue != value) {
- this.lastChecked = input.checked = this.inputValue == (''+value);
- this.lastValue = value;
+RadioController.prototype = {
+ updateModel: function(scope) {
+ var input = this.view;
+ if (this.lastChecked) {
+ return false;
+ } else {
+ input.checked = true;
+ this.lastValue = scope.setEval(this.exp, this.inputValue);
+ this.lastChecked = true;
+ return true;
+ }
+ },
+
+ updateView: function(scope) {
+ var input = this.view;
+ var value = scope.get(this.exp);
+ if (this.initialValue && typeof value === "undefined") {
+ value = this.initialValue;
+ scope.setEval(this.exp, value);
+ }
+ if (this.lastValue != value) {
+ this.lastChecked = input.checked = this.inputValue == (''+value);
+ this.lastValue = value;
+ }
}
};
///////////////////////
//ElementController
///////////////////////
-BindUpdater = function(view, exp) {
+function BindUpdater(view, exp) {
this.view = view;
this.exp = Binder.parseBindings(exp);
this.hasError = false;
@@ -3673,152 +3695,170 @@ BindUpdater.toText = function(obj) {
}
};
-BindUpdater.prototype.updateModel = function(scope) {};
-BindUpdater.prototype.updateView = function(scope) {
- var html = [];
- var parts = this.exp;
- var length = parts.length;
- for(var i=0; i<length; i++) {
- var part = parts[i];
- var binding = Binder.binding(part);
- if (binding) {
- scope.evalWidget(this, binding, this.scopeSelf, function(value){
- html.push(BindUpdater.toText(value));
- }, function(e, text){
- setHtml(this.view, text);
- });
- if (this.hasError) {
- return;
+BindUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ var html = [];
+ var parts = this.exp;
+ var length = parts.length;
+ for(var i=0; i<length; i++) {
+ var part = parts[i];
+ var binding = Binder.binding(part);
+ if (binding) {
+ scope.evalWidget(this, binding, this.scopeSelf, function(value){
+ html.push(BindUpdater.toText(value));
+ }, function(e, text){
+ setHtml(this.view, text);
+ });
+ if (this.hasError) {
+ return;
+ }
+ } else {
+ html.push(escapeHtml(part));
}
- } else {
- html.push(escapeHtml(part));
}
+ setHtml(this.view, html.join(''));
}
- setHtml(this.view, html.join(''));
};
-BindAttrUpdater = function(view, attrs) {
+function BindAttrUpdater(view, attrs) {
this.view = view;
this.attrs = attrs;
};
-BindAttrUpdater.prototype.updateModel = function(scope) {};
-BindAttrUpdater.prototype.updateView = function(scope) {
- var jNode = jQuery(this.view);
- var attributeTemplates = this.attrs;
- if (this.hasError) {
- this.hasError = false;
- jNode.
- removeClass('ng-exception').
- removeAttr('ng-error');
- }
- var isImage = jNode.is('img');
- for (var attrName in attributeTemplates) {
- var attributeTemplate = Binder.parseBindings(attributeTemplates[attrName]);
- var attrValues = [];
- for ( var i = 0; i < attributeTemplate.length; i++) {
- var binding = Binder.binding(attributeTemplate[i]);
- if (binding) {
- try {
- var value = scope.eval(binding, {element:jNode[0], attrName:attrName});
- if (value && (value.constructor !== array || value.length !== 0))
- attrValues.push(value);
- } catch (e) {
- this.hasError = true;
- error('BindAttrUpdater', e);
- var jsonError = toJson(e, true);
- attrValues.push('[' + jsonError + ']');
- jNode.
- addClass('ng-exception').
- attr('ng-error', jsonError);
+BindAttrUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ var jNode = jQuery(this.view);
+ var attributeTemplates = this.attrs;
+ if (this.hasError) {
+ this.hasError = false;
+ jNode.
+ removeClass('ng-exception').
+ removeAttr('ng-error');
+ }
+ var isImage = jNode.is('img');
+ for (var attrName in attributeTemplates) {
+ var attributeTemplate = Binder.parseBindings(attributeTemplates[attrName]);
+ var attrValues = [];
+ for ( var i = 0; i < attributeTemplate.length; i++) {
+ var binding = Binder.binding(attributeTemplate[i]);
+ if (binding) {
+ try {
+ var value = scope.eval(binding, {element:jNode[0], attrName:attrName});
+ if (value && (value.constructor !== array || value.length !== 0))
+ attrValues.push(value);
+ } catch (e) {
+ this.hasError = true;
+ error('BindAttrUpdater', e);
+ var jsonError = toJson(e, true);
+ attrValues.push('[' + jsonError + ']');
+ jNode.
+ addClass('ng-exception').
+ attr('ng-error', jsonError);
+ }
+ } else {
+ attrValues.push(attributeTemplate[i]);
}
- } else {
- attrValues.push(attributeTemplate[i]);
}
- }
- var attrValue = attrValues.length ? attrValues.join('') : null;
- if(isImage && attrName == 'src' && !attrValue)
- attrValue = scope.get('config.server') + '/images/blank.gif';
- jNode.attr(attrName, attrValue);
+ var attrValue = attrValues.length ? attrValues.join('') : null;
+ if(isImage && attrName == 'src' && !attrValue)
+ attrValue = scope.get('config.server') + '/images/blank.gif';
+ jNode.attr(attrName, attrValue);
+ }
}
};
-EvalUpdater = function(view, exp) {
+function EvalUpdater(view, exp) {
this.view = view;
this.exp = exp;
this.hasError = false;
};
-EvalUpdater.prototype.updateModel = function(scope) {};
-EvalUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp);
+EvalUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp);
+ }
};
-HideUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-HideUpdater.prototype.updateModel = function(scope) {};
-HideUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(hideValue){
- var view = jQuery(this.view);
- if (toBoolean(hideValue)) {
- view.hide();
- } else {
- view.show();
- }
- });
+function HideUpdater(view, exp) { this.view = view; this.exp = exp; };
+HideUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(hideValue){
+ var view = jQuery(this.view);
+ if (toBoolean(hideValue)) {
+ view.hide();
+ } else {
+ view.show();
+ }
+ });
+ }
};
-ShowUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-ShowUpdater.prototype.updateModel = function(scope) {};
-ShowUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(hideValue){
- var view = jQuery(this.view);
- if (toBoolean(hideValue)) {
- view.show();
- } else {
- view.hide();
- }
- });
+function ShowUpdater(view, exp) { this.view = view; this.exp = exp; };
+ShowUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(hideValue){
+ var view = jQuery(this.view);
+ if (toBoolean(hideValue)) {
+ view.show();
+ } else {
+ view.hide();
+ }
+ });
+ }
};
-ClassUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-ClassUpdater.prototype.updateModel = function(scope) {};
-ClassUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(classValue){
- if (classValue !== null && classValue !== undefined) {
- this.view.className = classValue;
- }
- });
+function ClassUpdater(view, exp) { this.view = view; this.exp = exp; };
+ClassUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(classValue){
+ if (classValue !== null && classValue !== undefined) {
+ this.view.className = classValue;
+ }
+ });
+ }
};
-ClassEvenUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-ClassEvenUpdater.prototype.updateModel = function(scope) {};
-ClassEvenUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(classValue){
- var index = scope.get('$index');
- jQuery(this.view).toggleClass(classValue, index % 2 === 1);
- });
+function ClassEvenUpdater(view, exp) { this.view = view; this.exp = exp; };
+ClassEvenUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(classValue){
+ var index = scope.get('$index');
+ jQuery(this.view).toggleClass(classValue, index % 2 === 1);
+ });
+ }
};
-ClassOddUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-ClassOddUpdater.prototype.updateModel = function(scope) {};
-ClassOddUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(classValue){
- var index = scope.get('$index');
- jQuery(this.view).toggleClass(classValue, index % 2 === 0);
- });
+function ClassOddUpdater(view, exp) { this.view = view; this.exp = exp; };
+ClassOddUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(classValue){
+ var index = scope.get('$index');
+ jQuery(this.view).toggleClass(classValue, index % 2 === 0);
+ });
+ }
};
-StyleUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-StyleUpdater.prototype.updateModel = function(scope) {};
-StyleUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(styleValue){
- jQuery(this.view).attr('style', "").css(styleValue);
- });
+function StyleUpdater(view, exp) { this.view = view; this.exp = exp; };
+StyleUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(styleValue){
+ jQuery(this.view).attr('style', "").css(styleValue);
+ });
+ }
};
///////////////////////
// RepeaterUpdater
///////////////////////
-RepeaterUpdater = function(view, repeaterExpression, template, prefix) {
+function RepeaterUpdater(view, repeaterExpression, template, prefix) {
this.view = view;
this.template = template;
this.prefix = prefix;
@@ -3839,81 +3879,77 @@ RepeaterUpdater = function(view, repeaterExpression, template, prefix) {
this.keyExp = match[2];
};
-RepeaterUpdater.prototype.updateModel = function(scope) {};
-RepeaterUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.iteratorExp, {}, function(iterator){
- var self = this;
- if (!iterator) {
- iterator = [];
- if (scope.isProperty(this.iteratorExp)) {
- scope.set(this.iteratorExp, iterator);
- }
- }
- var iteratorLength = iterator.length;
- var childrenLength = this.children.length;
- var cursor = this.view;
- var time = 0;
- var child = null;
- var keyExp = this.keyExp;
- var valueExp = this.valueExp;
- var i = 0;
- foreach(iterator, function(value, key){
- if (i < childrenLength) {
- // reuse children
- child = self.children[i];
- child.scope.set(valueExp, value);
- } else {
- // grow children
- var name = self.prefix +
- valueExp + " in " + self.iteratorExp + "[" + i + "]";
- var childScope = new Scope(scope.state, name);
- childScope.set('$index', i);
- if (keyExp)
- childScope.set(keyExp, key);
- childScope.set(valueExp, value);
- child = { scope:childScope, element:self.template(childScope, self.prefix, i) };
- cursor.after(child.element);
- self.children.push(child);
- }
- cursor = child.element;
- var s = new Date().getTime();
- child.scope.updateView();
- time += new Date().getTime() - s;
- i++;
- });
- // shrink children
- for ( var r = childrenLength; r > iteratorLength; --r) {
- var unneeded = this.children.pop().element[0];
- unneeded.parentNode.removeChild(unneeded);
- }
- // Special case for option in select
- if (child && child.element[0].nodeName === "OPTION") {
- var select = jQuery(child.element[0].parentNode);
- var cntl = select.data('controller');
- if (cntl) {
- cntl.lastValue = undefined;
- cntl.updateView(scope);
+RepeaterUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.iteratorExp, {}, function(iterator){
+ var self = this;
+ if (!iterator) {
+ iterator = [];
+ if (scope.isProperty(this.iteratorExp)) {
+ scope.set(this.iteratorExp, iterator);
+ }
}
- }
- });
+ var iteratorLength = iterator.length;
+ var childrenLength = this.children.length;
+ var cursor = this.view;
+ var time = 0;
+ var child = null;
+ var keyExp = this.keyExp;
+ var valueExp = this.valueExp;
+ var i = 0;
+ foreach(iterator, function(value, key){
+ if (i < childrenLength) {
+ // reuse children
+ child = self.children[i];
+ child.scope.set(valueExp, value);
+ } else {
+ // grow children
+ var name = self.prefix +
+ valueExp + " in " + self.iteratorExp + "[" + i + "]";
+ var childScope = new Scope(scope.state, name);
+ childScope.set('$index', i);
+ if (keyExp)
+ childScope.set(keyExp, key);
+ childScope.set(valueExp, value);
+ child = { scope:childScope, element:self.template(childScope, self.prefix, i) };
+ cursor.after(child.element);
+ self.children.push(child);
+ }
+ cursor = child.element;
+ var s = new Date().getTime();
+ child.scope.updateView();
+ time += new Date().getTime() - s;
+ i++;
+ });
+ // shrink children
+ for ( var r = childrenLength; r > iteratorLength; --r) {
+ var unneeded = this.children.pop().element[0];
+ unneeded.parentNode.removeChild(unneeded);
+ }
+ // Special case for option in select
+ if (child && child.element[0].nodeName === "OPTION") {
+ var select = jQuery(child.element[0].parentNode);
+ var cntl = select.data('controller');
+ if (cntl) {
+ cntl.lastValue = undefined;
+ cntl.updateView(scope);
+ }
+ }
+ });
+ }
};
//////////////////////////////////
// PopUp
//////////////////////////////////
-PopUp = function(doc) {
+function PopUp(doc) {
this.doc = doc;
};
PopUp.OUT_EVENT = "mouseleave mouseout click dblclick keypress keyup";
-PopUp.prototype.bind = function () {
- var self = this;
- this.doc.find('.ng-validation-error,.ng-exception').
- live("mouseover", PopUp.onOver);
-};
-
PopUp.onOver = function(e) {
PopUp.onOut();
var jNode = jQuery(this);
@@ -3953,29 +3989,39 @@ PopUp.onOut = function() {
return true;
};
+PopUp.prototype = {
+ bind: function () {
+ var self = this;
+ this.doc.find('.ng-validation-error,.ng-exception').
+ live("mouseover", PopUp.onOver);
+ }
+};
+
//////////////////////////////////
// Status
//////////////////////////////////
-Status = function(body) {
+function Status(body) {
this.loader = body.append(Status.DOM).find("#ng-loading");
this.requestCount = 0;
};
Status.DOM ='<div id="ng-spacer"></div><div id="ng-loading">loading....</div>';
-Status.prototype.beginRequest = function () {
- if (this.requestCount === 0) {
- this.loader.show();
- }
- this.requestCount++;
-};
-
-Status.prototype.endRequest = function () {
- this.requestCount--;
- if (this.requestCount === 0) {
- this.loader.hide("fold");
+Status.prototype = {
+ beginRequest: function () {
+ if (this.requestCount === 0) {
+ this.loader.show();
+ }
+ this.requestCount++;
+ },
+
+ endRequest: function () {
+ this.requestCount--;
+ if (this.requestCount === 0) {
+ this.loader.hide("fold");
+ }
}
};
})(window, document); \ No newline at end of file
diff --git a/src/Binder.js b/src/Binder.js
index 4c5299ed..36cb6ec3 100644
--- a/src/Binder.js
+++ b/src/Binder.js
@@ -1,12 +1,11 @@
-// Copyright (C) 2009 BRAT Tech LLC
-Binder = function(doc, widgetFactory, urlWatcher, config) {
+function Binder(doc, widgetFactory, urlWatcher, config) {
this.doc = doc;
this.urlWatcher = urlWatcher;
this.anchor = {};
this.widgetFactory = widgetFactory;
this.config = config || {};
this.updateListeners = [];
-};
+}
Binder.parseBindings = function(string) {
var results = [];
@@ -39,312 +38,314 @@ Binder.binding = function(string) {
};
-Binder.prototype.parseQueryString = function(query) {
- var params = {};
- query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,
- function (match, left, right) {
- if (left) params[decodeURIComponent(left)] = decodeURIComponent(right);
- });
- return params;
-};
-
-Binder.prototype.parseAnchor = function(url) {
- var self = this;
- url = url || this.urlWatcher.getUrl();
-
- var anchorIndex = url.indexOf('#');
- if (anchorIndex < 0) return;
- var anchor = url.substring(anchorIndex + 1);
-
- var anchorQuery = this.parseQueryString(anchor);
- foreach(self.anchor, function(newValue, key) {
- delete self.anchor[key];
- });
- foreach(anchorQuery, function(newValue, key) {
- self.anchor[key] = newValue;
- });
-};
-
-Binder.prototype.onUrlChange = function (url) {
- log("URL change detected", url);
- this.parseAnchor(url);
- this.updateView();
-};
-
-Binder.prototype.updateAnchor = function() {
- var url = this.urlWatcher.getUrl();
- var anchorIndex = url.indexOf('#');
- if (anchorIndex > -1)
- url = url.substring(0, anchorIndex);
- url += "#";
- var sep = '';
- for (var key in this.anchor) {
- var value = this.anchor[key];
- if (typeof value === 'undefined' || value === null) {
- delete this.anchor[key];
- } else {
- url += sep + encodeURIComponent(key);
- if (value !== true)
- url += "=" + encodeURIComponent(value);
- sep = '&';
- }
- }
- this.urlWatcher.setUrl(url);
- return url;
-};
-
-Binder.prototype.updateView = function() {
- var start = new Date().getTime();
- var scope = jQuery(this.doc).scope();
- scope.set("$invalidWidgets", []);
- scope.updateView();
- var end = new Date().getTime();
- this.updateAnchor();
- _.each(this.updateListeners, function(fn) {fn();});
-};
-
-Binder.prototype.docFindWithSelf = function(exp){
- var doc = jQuery(this.doc);
- var selection = doc.find(exp);
- if (doc.is(exp)){
- selection = selection.andSelf();
- }
- return selection;
-};
-
-Binder.prototype.executeInit = function() {
- this.docFindWithSelf("[ng-init]").each(function() {
- var jThis = jQuery(this);
- var scope = jThis.scope();
- try {
- scope.eval(jThis.attr('ng-init'));
- } catch (e) {
- alert("EVAL ERROR:\n" + jThis.attr('ng-init') + '\n' + toJson(e, true));
+Binder.prototype = {
+ parseQueryString: function(query) {
+ var params = {};
+ query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,
+ function (match, left, right) {
+ if (left) params[decodeURIComponent(left)] = decodeURIComponent(right);
+ });
+ return params;
+ },
+
+ parseAnchor: function(url) {
+ var self = this;
+ url = url || this.urlWatcher.getUrl();
+
+ var anchorIndex = url.indexOf('#');
+ if (anchorIndex < 0) return;
+ var anchor = url.substring(anchorIndex + 1);
+
+ var anchorQuery = this.parseQueryString(anchor);
+ foreach(self.anchor, function(newValue, key) {
+ delete self.anchor[key];
+ });
+ foreach(anchorQuery, function(newValue, key) {
+ self.anchor[key] = newValue;
+ });
+ },
+
+ onUrlChange: function (url) {
+ log("URL change detected", url);
+ this.parseAnchor(url);
+ this.updateView();
+ },
+
+ updateAnchor: function() {
+ var url = this.urlWatcher.getUrl();
+ var anchorIndex = url.indexOf('#');
+ if (anchorIndex > -1)
+ url = url.substring(0, anchorIndex);
+ url += "#";
+ var sep = '';
+ for (var key in this.anchor) {
+ var value = this.anchor[key];
+ if (typeof value === 'undefined' || value === null) {
+ delete this.anchor[key];
+ } else {
+ url += sep + encodeURIComponent(key);
+ if (value !== true)
+ url += "=" + encodeURIComponent(value);
+ sep = '&';
+ }
}
- });
-};
-
-Binder.prototype.entity = function (scope) {
- this.docFindWithSelf("[ng-entity]").attr("ng-watch", function() {
- try {
- var jNode = jQuery(this);
- var decl = scope.entity(jNode.attr("ng-entity"));
- return decl + (jNode.attr('ng-watch') || "");
- } catch (e) {
- alert(e);
+ this.urlWatcher.setUrl(url);
+ return url;
+ },
+
+ updateView: function() {
+ var start = new Date().getTime();
+ var scope = jQuery(this.doc).scope();
+ scope.set("$invalidWidgets", []);
+ scope.updateView();
+ var end = new Date().getTime();
+ this.updateAnchor();
+ _.each(this.updateListeners, function(fn) {fn();});
+ },
+
+ docFindWithSelf: function(exp){
+ var doc = jQuery(this.doc);
+ var selection = doc.find(exp);
+ if (doc.is(exp)){
+ selection = selection.andSelf();
}
- });
-};
-
-Binder.prototype.compile = function() {
- var jNode = jQuery(this.doc);
- var self = this;
- if (this.config.autoSubmit) {
- var submits = this.docFindWithSelf(":submit").not("[ng-action]");
- submits.attr("ng-action", "$save()");
- submits.not(":disabled").not("ng-bind-attr").attr("ng-bind-attr", '{disabled:"{{$invalidWidgets}}"}');
- }
- this.precompile(this.doc)(this.doc, jNode.scope(), "");
- this.docFindWithSelf("a[ng-action]").live('click', function (event) {
- var jNode = jQuery(this);
- try {
- jNode.scope().eval(jNode.attr('ng-action'));
- jNode.removeAttr('ng-error');
- jNode.removeClass("ng-exception");
- } catch (e) {
- jNode.addClass("ng-exception");
- jNode.attr('ng-error', toJson(e, true));
+ return selection;
+ },
+
+ executeInit: function() {
+ this.docFindWithSelf("[ng-init]").each(function() {
+ var jThis = jQuery(this);
+ var scope = jThis.scope();
+ try {
+ scope.eval(jThis.attr('ng-init'));
+ } catch (e) {
+ alert("EVAL ERROR:\n" + jThis.attr('ng-init') + '\n' + toJson(e, true));
+ }
+ });
+ },
+
+ entity: function (scope) {
+ this.docFindWithSelf("[ng-entity]").attr("ng-watch", function() {
+ try {
+ var jNode = jQuery(this);
+ var decl = scope.entity(jNode.attr("ng-entity"));
+ return decl + (jNode.attr('ng-watch') || "");
+ } catch (e) {
+ alert(e);
+ }
+ });
+ },
+
+ compile: function() {
+ var jNode = jQuery(this.doc);
+ var self = this;
+ if (this.config.autoSubmit) {
+ var submits = this.docFindWithSelf(":submit").not("[ng-action]");
+ submits.attr("ng-action", "$save()");
+ submits.not(":disabled").not("ng-bind-attr").attr("ng-bind-attr", '{disabled:"{{$invalidWidgets}}"}');
}
- self.updateView();
- return false;
- });
-};
-
-Binder.prototype.translateBinding = function(node, parentPath, factories) {
- var path = parentPath.concat();
- var offset = path.pop();
- var parts = Binder.parseBindings(node.nodeValue);
- if (parts.length > 1 || Binder.binding(parts[0])) {
- var parent = node.parentNode;
- if (isLeafNode(parent)) {
- parent.setAttribute('ng-bind-template', node.nodeValue);
- factories.push({path:path, fn:function(node, scope, prefix) {
- return new BindUpdater(node, node.getAttribute('ng-bind-template'));
- }});
- } else {
- for (var i = 0; i < parts.length; i++) {
- var part = parts[i];
- var binding = Binder.binding(part);
- var newNode;
- if (binding) {
- newNode = document.createElement("span");
- var jNewNode = jQuery(newNode);
- jNewNode.attr("ng-bind", binding);
- if (i === 0) {
- factories.push({path:path.concat(offset + i), fn:Binder.prototype.ng_bind});
+ this.precompile(this.doc)(this.doc, jNode.scope(), "");
+ this.docFindWithSelf("a[ng-action]").live('click', function (event) {
+ var jNode = jQuery(this);
+ try {
+ jNode.scope().eval(jNode.attr('ng-action'));
+ jNode.removeAttr('ng-error');
+ jNode.removeClass("ng-exception");
+ } catch (e) {
+ jNode.addClass("ng-exception");
+ jNode.attr('ng-error', toJson(e, true));
+ }
+ self.updateView();
+ return false;
+ });
+ },
+
+ translateBinding: function(node, parentPath, factories) {
+ var path = parentPath.concat();
+ var offset = path.pop();
+ var parts = Binder.parseBindings(node.nodeValue);
+ if (parts.length > 1 || Binder.binding(parts[0])) {
+ var parent = node.parentNode;
+ if (isLeafNode(parent)) {
+ parent.setAttribute('ng-bind-template', node.nodeValue);
+ factories.push({path:path, fn:function(node, scope, prefix) {
+ return new BindUpdater(node, node.getAttribute('ng-bind-template'));
+ }});
+ } else {
+ for (var i = 0; i < parts.length; i++) {
+ var part = parts[i];
+ var binding = Binder.binding(part);
+ var newNode;
+ if (binding) {
+ newNode = document.createElement("span");
+ var jNewNode = jQuery(newNode);
+ jNewNode.attr("ng-bind", binding);
+ if (i === 0) {
+ factories.push({path:path.concat(offset + i), fn:this.ng_bind});
+ }
+ } else if (msie && part.charAt(0) == ' ') {
+ newNode = document.createElement("span");
+ newNode.innerHTML = '&nbsp;' + part.substring(1);
+ } else {
+ newNode = document.createTextNode(part);
}
- } else if (msie && part.charAt(0) == ' ') {
- newNode = document.createElement("span");
- newNode.innerHTML = '&nbsp;' + part.substring(1);
- } else {
- newNode = document.createTextNode(part);
+ parent.insertBefore(newNode, node);
}
- parent.insertBefore(newNode, node);
}
+ parent.removeChild(node);
}
- parent.removeChild(node);
- }
-};
-
-Binder.prototype.precompile = function(root) {
- var factories = [];
- this.precompileNode(root, [], factories);
- return function (template, scope, prefix) {
- var len = factories.length;
- for (var i = 0; i < len; i++) {
- var factory = factories[i];
- var node = template;
- var path = factory.path;
- for (var j = 0; j < path.length; j++) {
- node = node.childNodes[path[j]];
+ },
+
+ precompile: function(root) {
+ var factories = [];
+ this.precompileNode(root, [], factories);
+ return function (template, scope, prefix) {
+ var len = factories.length;
+ for (var i = 0; i < len; i++) {
+ var factory = factories[i];
+ var node = template;
+ var path = factory.path;
+ for (var j = 0; j < path.length; j++) {
+ node = node.childNodes[path[j]];
+ }
+ try {
+ scope.addWidget(factory.fn(node, scope, prefix));
+ } catch (e) {
+ alert(e);
+ }
}
- try {
- scope.addWidget(factory.fn(node, scope, prefix));
- } catch (e) {
- alert(e);
+ };
+ },
+
+ precompileNode: function(node, path, factories) {
+ var nodeType = node.nodeType;
+ if (nodeType == Node.TEXT_NODE) {
+ this.translateBinding(node, path, factories);
+ return;
+ } else if (nodeType != Node.ELEMENT_NODE && nodeType != Node.DOCUMENT_NODE) {
+ return;
+ }
+
+ if (!node.getAttribute) return;
+ var nonBindable = node.getAttribute('ng-non-bindable');
+ if (nonBindable || nonBindable === "") return;
+
+ var attributes = node.attributes;
+ if (attributes) {
+ var bindings = node.getAttribute('ng-bind-attr');
+ node.removeAttribute('ng-bind-attr');
+ bindings = bindings ? fromJson(bindings) : {};
+ var attrLen = attributes.length;
+ for (var i = 0; i < attrLen; i++) {
+ var attr = attributes[i];
+ var attrName = attr.name;
+ // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
+ var attrValue = msie && attrName == 'href' ?
+ decodeURI(node.getAttribute(attrName, 2)) : attr.value;
+ if (Binder.hasBinding(attrValue)) {
+ bindings[attrName] = attrValue;
+ }
+ }
+ var json = toJson(bindings);
+ if (json.length > 2) {
+ node.setAttribute("ng-bind-attr", json);
}
}
- };
-};
-
-Binder.prototype.precompileNode = function(node, path, factories) {
- var nodeType = node.nodeType;
- if (nodeType == Node.TEXT_NODE) {
- this.translateBinding(node, path, factories);
- return;
- } else if (nodeType != Node.ELEMENT_NODE && nodeType != Node.DOCUMENT_NODE) {
- return;
- }
-
- if (!node.getAttribute) return;
- var nonBindable = node.getAttribute('ng-non-bindable');
- if (nonBindable || nonBindable === "") return;
-
- var attributes = node.attributes;
- if (attributes) {
- var bindings = node.getAttribute('ng-bind-attr');
- node.removeAttribute('ng-bind-attr');
- bindings = bindings ? fromJson(bindings) : {};
- var attrLen = attributes.length;
- for (var i = 0; i < attrLen; i++) {
- var attr = attributes[i];
- var attrName = attr.name;
- // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
- var attrValue = msie && attrName == 'href' ?
- decodeURI(node.getAttribute(attrName, 2)) : attr.value;
- if (Binder.hasBinding(attrValue)) {
- bindings[attrName] = attrValue;
+
+ if (!node.getAttribute) log(node);
+ var repeaterExpression = node.getAttribute('ng-repeat');
+ if (repeaterExpression) {
+ node.removeAttribute('ng-repeat');
+ var precompiled = this.precompile(node);
+ var view = document.createComment("ng-repeat: " + repeaterExpression);
+ var parentNode = node.parentNode;
+ parentNode.insertBefore(view, node);
+ parentNode.removeChild(node);
+ function template(childScope, prefix, i) {
+ var clone = jQuery(node).clone();
+ clone.css('display', '');
+ clone.attr('ng-repeat-index', "" + i);
+ clone.data('scope', childScope);
+ precompiled(clone[0], childScope, prefix + i + ":");
+ return clone;
}
+ factories.push({path:path, fn:function(node, scope, prefix) {
+ return new RepeaterUpdater(jQuery(node), repeaterExpression, template, prefix);
+ }});
+ return;
}
- var json = toJson(bindings);
- if (json.length > 2) {
- node.setAttribute("ng-bind-attr", json);
+
+ if (node.getAttribute('ng-eval')) factories.push({path:path, fn:this.ng_eval});
+ if (node.getAttribute('ng-bind')) factories.push({path:path, fn:this.ng_bind});
+ if (node.getAttribute('ng-bind-attr')) factories.push({path:path, fn:this.ng_bind_attr});
+ if (node.getAttribute('ng-hide')) factories.push({path:path, fn:this.ng_hide});
+ if (node.getAttribute('ng-show')) factories.push({path:path, fn:this.ng_show});
+ if (node.getAttribute('ng-class')) factories.push({path:path, fn:this.ng_class});
+ if (node.getAttribute('ng-class-odd')) factories.push({path:path, fn:this.ng_class_odd});
+ if (node.getAttribute('ng-class-even')) factories.push({path:path, fn:this.ng_class_even});
+ if (node.getAttribute('ng-style')) factories.push({path:path, fn:this.ng_style});
+ if (node.getAttribute('ng-watch')) factories.push({path:path, fn:this.ng_watch});
+ var nodeName = node.nodeName;
+ if ((nodeName == 'INPUT' ) ||
+ nodeName == 'TEXTAREA' ||
+ nodeName == 'SELECT' ||
+ nodeName == 'BUTTON') {
+ var self = this;
+ factories.push({path:path, fn:function(node, scope, prefix) {
+ node.name = prefix + node.name.split(":").pop();
+ return self.widgetFactory.createController(jQuery(node), scope);
+ }});
}
- }
-
- if (!node.getAttribute) log(node);
- var repeaterExpression = node.getAttribute('ng-repeat');
- if (repeaterExpression) {
- node.removeAttribute('ng-repeat');
- var precompiled = this.precompile(node);
- var view = document.createComment("ng-repeat: " + repeaterExpression);
- var parentNode = node.parentNode;
- parentNode.insertBefore(view, node);
- parentNode.removeChild(node);
- var template = function(childScope, prefix, i) {
- var clone = jQuery(node).clone();
- clone.css('display', '');
- clone.attr('ng-repeat-index', "" + i);
- clone.data('scope', childScope);
- precompiled(clone[0], childScope, prefix + i + ":");
- return clone;
- };
- factories.push({path:path, fn:function(node, scope, prefix) {
- return new RepeaterUpdater(jQuery(node), repeaterExpression, template, prefix);
- }});
- return;
- }
-
- if (node.getAttribute('ng-eval')) factories.push({path:path, fn:this.ng_eval});
- if (node.getAttribute('ng-bind')) factories.push({path:path, fn:this.ng_bind});
- if (node.getAttribute('ng-bind-attr')) factories.push({path:path, fn:this.ng_bind_attr});
- if (node.getAttribute('ng-hide')) factories.push({path:path, fn:this.ng_hide});
- if (node.getAttribute('ng-show')) factories.push({path:path, fn:this.ng_show});
- if (node.getAttribute('ng-class')) factories.push({path:path, fn:this.ng_class});
- if (node.getAttribute('ng-class-odd')) factories.push({path:path, fn:this.ng_class_odd});
- if (node.getAttribute('ng-class-even')) factories.push({path:path, fn:this.ng_class_even});
- if (node.getAttribute('ng-style')) factories.push({path:path, fn:this.ng_style});
- if (node.getAttribute('ng-watch')) factories.push({path:path, fn:this.ng_watch});
- var nodeName = node.nodeName;
- if ((nodeName == 'INPUT' ) ||
- nodeName == 'TEXTAREA' ||
- nodeName == 'SELECT' ||
- nodeName == 'BUTTON') {
- var self = this;
- factories.push({path:path, fn:function(node, scope, prefix) {
- node.name = prefix + node.name.split(":").pop();
- return self.widgetFactory.createController(jQuery(node), scope);
- }});
- }
- if (nodeName == 'OPTION') {
- var html = jQuery('<select/>').append(jQuery(node).clone()).html();
- if (!html.match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi)) {
- node.value = node.text;
+ if (nodeName == 'OPTION') {
+ var html = jQuery('<select/>').append(jQuery(node).clone()).html();
+ if (!html.match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi)) {
+ node.value = node.text;
+ }
}
+
+ var children = node.childNodes;
+ for (var k = 0; k < children.length; k++) {
+ this.precompileNode(children[k], path.concat(k), factories);
+ }
+ },
+
+ ng_eval: function(node) {
+ return new EvalUpdater(node, node.getAttribute('ng-eval'));
+ },
+
+ ng_bind: function(node) {
+ return new BindUpdater(node, "{{" + node.getAttribute('ng-bind') + "}}");
+ },
+
+ ng_bind_attr: function(node) {
+ return new BindAttrUpdater(node, fromJson(node.getAttribute('ng-bind-attr')));
+ },
+
+ ng_hide: function(node) {
+ return new HideUpdater(node, node.getAttribute('ng-hide'));
+ },
+
+ ng_show: function(node) {
+ return new ShowUpdater(node, node.getAttribute('ng-show'));
+ },
+
+ ng_class: function(node) {
+ return new ClassUpdater(node, node.getAttribute('ng-class'));
+ },
+
+ ng_class_even: function(node) {
+ return new ClassEvenUpdater(node, node.getAttribute('ng-class-even'));
+ },
+
+ ng_class_odd: function(node) {
+ return new ClassOddUpdater(node, node.getAttribute('ng-class-odd'));
+ },
+
+ ng_style: function(node) {
+ return new StyleUpdater(node, node.getAttribute('ng-style'));
+ },
+
+ ng_watch: function(node, scope) {
+ scope.watch(node.getAttribute('ng-watch'));
}
-
- var children = node.childNodes;
- for (var k = 0; k < children.length; k++) {
- this.precompileNode(children[k], path.concat(k), factories);
- }
-};
-
-Binder.prototype.ng_eval = function(node) {
- return new EvalUpdater(node, node.getAttribute('ng-eval'));
-};
-
-Binder.prototype.ng_bind = function(node) {
- return new BindUpdater(node, "{{" + node.getAttribute('ng-bind') + "}}");
-};
-
-Binder.prototype.ng_bind_attr = function(node) {
- return new BindAttrUpdater(node, fromJson(node.getAttribute('ng-bind-attr')));
-};
-
-Binder.prototype.ng_hide = function(node) {
- return new HideUpdater(node, node.getAttribute('ng-hide'));
-};
-
-Binder.prototype.ng_show = function(node) {
- return new ShowUpdater(node, node.getAttribute('ng-show'));
-};
-
-Binder.prototype.ng_class = function(node) {
- return new ClassUpdater(node, node.getAttribute('ng-class'));
-};
-
-Binder.prototype.ng_class_even = function(node) {
- return new ClassEvenUpdater(node, node.getAttribute('ng-class-even'));
-};
-
-Binder.prototype.ng_class_odd = function(node) {
- return new ClassOddUpdater(node, node.getAttribute('ng-class-odd'));
-};
-
-Binder.prototype.ng_style = function(node) {
- return new StyleUpdater(node, node.getAttribute('ng-style'));
-};
-
-Binder.prototype.ng_watch = function(node, scope) {
- scope.watch(node.getAttribute('ng-watch'));
-};
+}; \ No newline at end of file
diff --git a/src/ControlBar.js b/src/ControlBar.js
index fb8147d5..53c87199 100644
--- a/src/ControlBar.js
+++ b/src/ControlBar.js
@@ -1,15 +1,10 @@
-// Copyright (C) 2008,2009 BRAT Tech LLC
-
-ControlBar = function (document, serverUrl) {
+function ControlBar(document, serverUrl) {
this.document = document;
this.serverUrl = serverUrl;
this.window = window;
this.callbacks = [];
};
-ControlBar.prototype.bind = function () {
-};
-
ControlBar.HTML =
'<div>' +
'<div class="ui-widget-overlay"></div>' +
@@ -18,54 +13,61 @@ ControlBar.HTML =
'</div>' +
'</div>';
-ControlBar.prototype.login = function (loginSubmitFn) {
- this.callbacks.push(loginSubmitFn);
- if (this.callbacks.length == 1) {
- this.doTemplate("/user_session/new.mini?return_url=" + encodeURIComponent(this.urlWithoutAnchor()));
- }
-};
-
-ControlBar.prototype.logout = function (loginSubmitFn) {
- this.callbacks.push(loginSubmitFn);
- if (this.callbacks.length == 1) {
- this.doTemplate("/user_session/do_destroy.mini");
- }
-};
-
-ControlBar.prototype.urlWithoutAnchor = function (path) {
- return this.window.location.href.split("#")[0];
-};
-
-ControlBar.prototype.doTemplate = function (path) {
- var self = this;
- var id = new Date().getTime();
- var url = this.urlWithoutAnchor();
- url += "#$iframe_notify=" + id;
- var iframeHeight = 330;
- var loginView = jQuery('<div style="overflow:hidden; padding:2px 0 0 0;"><iframe name="'+ url +'" src="'+this.serverUrl + path + '" width="500" height="'+ iframeHeight +'"/></div>');
- this.document.append(loginView);
- loginView.dialog({
- height:iframeHeight + 33, width:500,
- resizable: false, modal:true,
- title: 'Authentication: <a href="http://www.getangular.com"><tt>&lt;angular/&gt;</tt></a>'
- });
- callbacks["_iframe_notify_" + id] = function() {
- loginView.dialog("destroy");
- loginView.remove();
- foreach(self.callbacks, function(callback){
- callback();
- });
- self.callbacks = [];
- };
-};
-
ControlBar.FORBIDEN =
'<div ng-non-bindable="true" title="Permission Error:">' +
'Sorry, you do not have permission for this!'+
'</div>';
-ControlBar.prototype.notAuthorized = function () {
- if (this.forbidenView) return;
- this.forbidenView = jQuery(ControlBar.FORBIDEN);
- this.forbidenView.dialog({bgiframe:true, height:70, modal:true});
-};
+
+
+ControlBar.prototype = {
+ bind: function () {
+ },
+
+ login: function (loginSubmitFn) {
+ this.callbacks.push(loginSubmitFn);
+ if (this.callbacks.length == 1) {
+ this.doTemplate("/user_session/new.mini?return_url=" + encodeURIComponent(this.urlWithoutAnchor()));
+ }
+ },
+
+ logout: function (loginSubmitFn) {
+ this.callbacks.push(loginSubmitFn);
+ if (this.callbacks.length == 1) {
+ this.doTemplate("/user_session/do_destroy.mini");
+ }
+ },
+
+ urlWithoutAnchor: function (path) {
+ return this.window.location.href.split("#")[0];
+ },
+
+ doTemplate: function (path) {
+ var self = this;
+ var id = new Date().getTime();
+ var url = this.urlWithoutAnchor();
+ url += "#$iframe_notify=" + id;
+ var iframeHeight = 330;
+ var loginView = jQuery('<div style="overflow:hidden; padding:2px 0 0 0;"><iframe name="'+ url +'" src="'+this.serverUrl + path + '" width="500" height="'+ iframeHeight +'"/></div>');
+ this.document.append(loginView);
+ loginView.dialog({
+ height:iframeHeight + 33, width:500,
+ resizable: false, modal:true,
+ title: 'Authentication: <a href="http://www.getangular.com"><tt>&lt;angular/&gt;</tt></a>'
+ });
+ callbacks["_iframe_notify_" + id] = function() {
+ loginView.dialog("destroy");
+ loginView.remove();
+ foreach(self.callbacks, function(callback){
+ callback();
+ });
+ self.callbacks = [];
+ };
+ },
+
+ notAuthorized: function () {
+ if (this.forbidenView) return;
+ this.forbidenView = jQuery(ControlBar.FORBIDEN);
+ this.forbidenView.dialog({bgiframe:true, height:70, modal:true});
+ }
+}; \ No newline at end of file
diff --git a/src/DataStore.js b/src/DataStore.js
index f99e5824..7952096f 100644
--- a/src/DataStore.js
+++ b/src/DataStore.js
@@ -1,6 +1,4 @@
-// Copyright (C) 2009 BRAT Tech LLC
-
-DataStore = function(post, users, anchor) {
+function DataStore(post, users, anchor) {
this.post = post;
this.users = users;
this._cache = {$collections:[]};
@@ -8,325 +6,329 @@ DataStore = function(post, users, anchor) {
this.bulkRequest = [];
};
-DataStore.prototype.cache = function(document) {
- if (document.constructor != Model) {
- throw "Parameter must be an instance of Entity! " + toJson(document);
- }
- var key = document.$entity + '/' + document.$id;
- var cachedDocument = this._cache[key];
- if (cachedDocument) {
- Model.copyDirectFields(document, cachedDocument);
- } else {
- this._cache[key] = document;
- cachedDocument = document;
- }
- return cachedDocument;
-};
-
-DataStore.prototype.load = function(instance, id, callback, failure) {
- if (id && id !== '*') {
- var self = this;
- this._jsonRequest(["GET", instance.$entity + "/" + id], function(response) {
- instance.$loadFrom(response);
- instance.$migrate();
- var clone = instance.$$entity(instance);
- self.cache(clone);
- (callback||noop)(instance);
- }, failure);
- }
- return instance;
-};
-
-DataStore.prototype.loadMany = function(entity, ids, callback) {
- var self=this;
- var list = [];
- var callbackCount = 0;
- foreach(ids, function(id){
- list.push(self.load(entity(), id, function(){
- callbackCount++;
- if (callbackCount == ids.length) {
- (callback||noop)(list);
- }
- }));
- });
- return list;
-};
+DataStore.NullEntity = extend(function(){}, {
+ 'all': function(){return [];},
+ 'query': function(){return [];},
+ 'load': function(){return {};},
+ 'title': undefined
+});
-DataStore.prototype.loadOrCreate = function(instance, id, callback) {
- var self=this;
- return this.load(instance, id, callback, function(response){
- if (response.$status_code == 404) {
- instance.$id = id;
- (callback||noop)(instance);
+DataStore.prototype = {
+ cache: function(document) {
+ if (! document instanceof Model) {
+ throw "Parameter must be an instance of Entity! " + toJson(document);
+ }
+ var key = document.$entity + '/' + document.$id;
+ var cachedDocument = this._cache[key];
+ if (cachedDocument) {
+ Model.copyDirectFields(document, cachedDocument);
} else {
- throw response;
+ this._cache[key] = document;
+ cachedDocument = document;
}
- });
-};
-
-DataStore.prototype.loadAll = function(entity, callback) {
- var self = this;
- var list = [];
- list.$$accept = function(doc){
- return doc.$entity == entity.title;
- };
- this._cache.$collections.push(list);
- this._jsonRequest(["GET", entity.title], function(response) {
- var rows = response;
- for ( var i = 0; i < rows.length; i++) {
- var document = entity();
- document.$loadFrom(rows[i]);
- list.push(self.cache(document));
+ return cachedDocument;
+ },
+
+ load: function(instance, id, callback, failure) {
+ if (id && id !== '*') {
+ var self = this;
+ this._jsonRequest(["GET", instance.$entity + "/" + id], function(response) {
+ instance.$loadFrom(response);
+ instance.$migrate();
+ var clone = instance.$$entity(instance);
+ self.cache(clone);
+ (callback||noop)(instance);
+ }, failure);
}
- (callback||noop)(list);
- });
- return list;
-};
-
-DataStore.prototype.save = function(document, callback) {
- var self = this;
- var data = {};
- document.$saveTo(data);
- this._jsonRequest(["POST", "", data], function(response) {
- document.$loadFrom(response);
- var cachedDoc = self.cache(document);
- _.each(self._cache.$collections, function(collection){
- if (collection.$$accept(document)) {
- angular['Array']['includeIf'](collection, cachedDoc, true);
+ return instance;
+ },
+
+ loadMany: function(entity, ids, callback) {
+ var self=this;
+ var list = [];
+ var callbackCount = 0;
+ foreach(ids, function(id){
+ list.push(self.load(entity(), id, function(){
+ callbackCount++;
+ if (callbackCount == ids.length) {
+ (callback||noop)(list);
+ }
+ }));
+ });
+ return list;
+ },
+
+ loadOrCreate: function(instance, id, callback) {
+ var self=this;
+ return this.load(instance, id, callback, function(response){
+ if (response.$status_code == 404) {
+ instance.$id = id;
+ (callback||noop)(instance);
+ } else {
+ throw response;
}
});
- if (document.$$anchor) {
- self.anchor[document.$$anchor] = document.$id;
- }
- if (callback)
- callback(document);
- });
-};
-
-DataStore.prototype.remove = function(document, callback) {
- var self = this;
- var data = {};
- document.$saveTo(data);
- this._jsonRequest(["DELETE", "", data], function(response) {
- delete self._cache[document.$entity + '/' + document.$id];
- _.each(self._cache.$collections, function(collection){
- for ( var i = 0; i < collection.length; i++) {
- var item = collection[i];
- if (item.$id == document.$id) {
- collection.splice(i, 1);
+ },
+
+ loadAll: function(entity, callback) {
+ var self = this;
+ var list = [];
+ list.$$accept = function(doc){
+ return doc.$entity == entity.title;
+ };
+ this._cache.$collections.push(list);
+ this._jsonRequest(["GET", entity.title], function(response) {
+ var rows = response;
+ for ( var i = 0; i < rows.length; i++) {
+ var document = entity();
+ document.$loadFrom(rows[i]);
+ list.push(self.cache(document));
+ }
+ (callback||noop)(list);
+ });
+ return list;
+ },
+
+ save: function(document, callback) {
+ var self = this;
+ var data = {};
+ document.$saveTo(data);
+ this._jsonRequest(["POST", "", data], function(response) {
+ document.$loadFrom(response);
+ var cachedDoc = self.cache(document);
+ _.each(self._cache.$collections, function(collection){
+ if (collection.$$accept(document)) {
+ angular['Array']['includeIf'](collection, cachedDoc, true);
}
+ });
+ if (document.$$anchor) {
+ self.anchor[document.$$anchor] = document.$id;
}
+ if (callback)
+ callback(document);
});
- (callback||noop)(response);
- });
-};
-
-DataStore.prototype._jsonRequest = function(request, callback, failure) {
- request.$$callback = callback;
- request.$$failure = failure||function(response){
- throw response;
- };
- this.bulkRequest.push(request);
-};
-
-DataStore.prototype.flush = function() {
- if (this.bulkRequest.length === 0) return;
- var self = this;
- var bulkRequest = this.bulkRequest;
- this.bulkRequest = [];
- log('REQUEST:', bulkRequest);
- function callback(code, bulkResponse){
- log('RESPONSE[' + code + ']: ', bulkResponse);
- if(bulkResponse.$status_code == 401) {
- self.users.login(function(){
- self.post(bulkRequest, callback);
+ },
+
+ remove: function(document, callback) {
+ var self = this;
+ var data = {};
+ document.$saveTo(data);
+ this._jsonRequest(["DELETE", "", data], function(response) {
+ delete self._cache[document.$entity + '/' + document.$id];
+ _.each(self._cache.$collections, function(collection){
+ for ( var i = 0; i < collection.length; i++) {
+ var item = collection[i];
+ if (item.$id == document.$id) {
+ collection.splice(i, 1);
+ }
+ }
});
- } else if(bulkResponse.$status_code) {
- alert(toJson(bulkResponse));
- } else {
- for ( var i = 0; i < bulkResponse.length; i++) {
- var response = bulkResponse[i];
- var request = bulkRequest[i];
- var responseCode = response.$status_code;
- if(responseCode) {
- if(responseCode == 403) {
- self.users.notAuthorized();
+ (callback||noop)(response);
+ });
+ },
+
+ _jsonRequest: function(request, callback, failure) {
+ request.$$callback = callback;
+ request.$$failure = failure||function(response){
+ throw response;
+ };
+ this.bulkRequest.push(request);
+ },
+
+ flush: function() {
+ if (this.bulkRequest.length === 0) return;
+ var self = this;
+ var bulkRequest = this.bulkRequest;
+ this.bulkRequest = [];
+ log('REQUEST:', bulkRequest);
+ function callback(code, bulkResponse){
+ log('RESPONSE[' + code + ']: ', bulkResponse);
+ if(bulkResponse.$status_code == 401) {
+ self.users.login(function(){
+ self.post(bulkRequest, callback);
+ });
+ } else if(bulkResponse.$status_code) {
+ alert(toJson(bulkResponse));
+ } else {
+ for ( var i = 0; i < bulkResponse.length; i++) {
+ var response = bulkResponse[i];
+ var request = bulkRequest[i];
+ var responseCode = response.$status_code;
+ if(responseCode) {
+ if(responseCode == 403) {
+ self.users.notAuthorized();
+ } else {
+ request.$$failure(response);
+ }
} else {
- request.$$failure(response);
+ request.$$callback(response);
}
- } else {
- request.$$callback(response);
}
}
}
- }
- this.post(bulkRequest, callback);
-};
-
-DataStore.prototype.saveScope = function(scope, callback) {
- var saveCounter = 1;
- function onSaveDone() {
- saveCounter--;
- if (saveCounter === 0 && callback)
- callback();
- }
- for(var key in scope) {
- var item = scope[key];
- if (item && item.$save == Model.prototype.$save) {
- saveCounter++;
- item.$save(onSaveDone);
- }
- }
- onSaveDone();
-};
-
-DataStore.prototype.query = function(type, query, arg, callback){
- var self = this;
- var queryList = [];
- queryList.$$accept = function(doc){
- return false;
- };
- this._cache.$collections.push(queryList);
- var request = type.title + '/' + query + '=' + arg;
- this._jsonRequest(["GET", request], function(response){
- var list = response;
- for(var i = 0; i < list.length; i++) {
- var document = new type().$loadFrom(list[i]);
- queryList.push(self.cache(document));
+ this.post(bulkRequest, callback);
+ },
+
+ saveScope: function(scope, callback) {
+ var saveCounter = 1;
+ function onSaveDone() {
+ saveCounter--;
+ if (saveCounter === 0 && callback)
+ callback();
}
- if (callback)
- callback(queryList);
- });
- return queryList;
-};
-
-DataStore.prototype.entities = function(callback) {
- var entities = [];
- var self = this;
- this._jsonRequest(["GET", "$entities"], function(response) {
- for (var entityName in response) {
- entities.push(self.entity(entityName));
+ for(var key in scope) {
+ var item = scope[key];
+ if (item && item.$save == Model.prototype.$save) {
+ saveCounter++;
+ item.$save(onSaveDone);
+ }
}
- entities.sort(function(a,b){return a.title > b.title ? 1 : -1;});
- if (callback) callback(entities);
- });
- return entities;
-};
-
-DataStore.prototype.documentCountsByUser = function(){
- var counts = {};
- var self = this;
- self.post([["GET", "$users"]], function(code, response){
- foreach(response[0], function(value, key){
- counts[key] = value;
+ onSaveDone();
+ },
+
+ query: function(type, query, arg, callback){
+ var self = this;
+ var queryList = [];
+ queryList.$$accept = function(doc){
+ return false;
+ };
+ this._cache.$collections.push(queryList);
+ var request = type.title + '/' + query + '=' + arg;
+ this._jsonRequest(["GET", request], function(response){
+ var list = response;
+ for(var i = 0; i < list.length; i++) {
+ var document = new type().$loadFrom(list[i]);
+ queryList.push(self.cache(document));
+ }
+ if (callback)
+ callback(queryList);
});
- });
- return counts;
-};
-
-DataStore.prototype.userDocumentIdsByEntity = function(user){
- var ids = {};
- var self = this;
- self.post([["GET", "$users/" + user]], function(code, response){
- foreach(response[0], function(value, key){
- ids[key] = value;
+ return queryList;
+ },
+
+ entities: function(callback) {
+ var entities = [];
+ var self = this;
+ this._jsonRequest(["GET", "$entities"], function(response) {
+ for (var entityName in response) {
+ entities.push(self.entity(entityName));
+ }
+ entities.sort(function(a,b){return a.title > b.title ? 1 : -1;});
+ if (callback) callback(entities);
});
- });
- return ids;
-};
-
-DataStore.NullEntity = function(){};
-DataStore.NullEntity.all = function(){return [];};
-DataStore.NullEntity.query = function(){return [];};
-DataStore.NullEntity.load = function(){return {};};
-DataStore.NullEntity.title = undefined;
-
-DataStore.prototype.entity = function(name, defaults){
- if (!name) {
- return DataStore.NullEntity;
- }
- var self = this;
- var entity = function(initialState){
- return new Model(entity, initialState);
- };
- // entity.name does not work as name seems to be reserved for functions
- entity.title = name;
- entity.$$factory = true;
- entity.datastore = this;
- entity.defaults = defaults || {};
- entity.load = function(id, callback){
- return self.load(entity(), id, callback);
- };
- entity.loadMany = function(ids, callback){
- return self.loadMany(entity, ids, callback);
- };
- entity.loadOrCreate = function(id, callback){
- return self.loadOrCreate(entity(), id, callback);
- };
- entity.all = function(callback){
- return self.loadAll(entity, callback);
- };
- entity.query = function(query, queryArgs, callback){
- return self.query(entity, query, queryArgs, callback);
- };
- entity.properties = function(callback) {
- self._jsonRequest(["GET", name + "/$properties"], callback);
- };
- return entity;
-};
-
-DataStore.prototype.join = function(join){
- var fn = function(){
- throw "Joined entities can not be instantiated into a document.";
- };
- function base(name){return name ? name.substring(0, name.indexOf('.')) : undefined;}
- function next(name){return name.substring(name.indexOf('.') + 1);}
- var joinOrder = _(join).chain().
- map(function($, name){
- return name;}).
- sortBy(function(name){
- var path = [];
- do {
- if (_(path).include(name)) throw "Infinite loop in join: " + path.join(" -> ");
- path.push(name);
- if (!join[name]) throw _("Named entity '<%=name%>' is undefined.").template({name:name});
- name = base(join[name].on);
- } while(name);
- return path.length;
- }).
- value();
- if (_(joinOrder).select(function($){return join[$].on;}).length != joinOrder.length - 1)
- throw "Exactly one entity needs to be primary.";
- fn.query = function(exp, value) {
- var joinedResult = [];
- var baseName = base(exp);
- if (baseName != joinOrder[0]) throw _("Named entity '<%=name%>' is not a primary entity.").template({name:baseName});
- var Entity = join[baseName].join;
- var joinIndex = 1;
- Entity.query(next(exp), value, function(result){
- var nextJoinName = joinOrder[joinIndex++];
- var nextJoin = join[nextJoinName];
- var nextJoinOn = nextJoin.on;
- var joinIds = {};
- _(result).each(function(doc){
- var row = {};
- joinedResult.push(row);
- row[baseName] = doc;
- var id = Scope.getter(row, nextJoinOn);
- joinIds[id] = id;
+ return entities;
+ },
+
+ documentCountsByUser: function(){
+ var counts = {};
+ var self = this;
+ self.post([["GET", "$users"]], function(code, response){
+ foreach(response[0], function(value, key){
+ counts[key] = value;
});
- nextJoin.join.loadMany(_.toArray(joinIds), function(result){
- var byId = {};
+ });
+ return counts;
+ },
+
+ userDocumentIdsByEntity: function(user){
+ var ids = {};
+ var self = this;
+ self.post([["GET", "$users/" + user]], function(code, response){
+ foreach(response[0], function(value, key){
+ ids[key] = value;
+ });
+ });
+ return ids;
+ },
+
+ entity: function(name, defaults){
+ if (!name) {
+ return DataStore.NullEntity;
+ }
+ var self = this;
+ var entity = extend(function(initialState){
+ return new Model(entity, initialState);
+ }, {
+ // entity.name does not work as name seems to be reserved for functions
+ 'title': name,
+ '$$factory': true,
+ 'datastore': this,
+ 'defaults': defaults || {},
+ 'load': function(id, callback){
+ return self.load(entity(), id, callback);
+ },
+ 'loadMany': function(ids, callback){
+ return self.loadMany(entity, ids, callback);
+ },
+ 'loadOrCreate': function(id, callback){
+ return self.loadOrCreate(entity(), id, callback);
+ },
+ 'all': function(callback){
+ return self.loadAll(entity, callback);
+ },
+ 'query': function(query, queryArgs, callback){
+ return self.query(entity, query, queryArgs, callback);
+ },
+ 'properties': function(callback) {
+ self._jsonRequest(["GET", name + "/$properties"], callback);
+ }
+ });
+ return entity;
+ },
+
+ join: function(join){
+ function fn(){
+ throw "Joined entities can not be instantiated into a document.";
+ };
+ function base(name){return name ? name.substring(0, name.indexOf('.')) : undefined;}
+ function next(name){return name.substring(name.indexOf('.') + 1);}
+ var joinOrder = _(join).chain().
+ map(function($, name){
+ return name;}).
+ sortBy(function(name){
+ var path = [];
+ do {
+ if (_(path).include(name)) throw "Infinite loop in join: " + path.join(" -> ");
+ path.push(name);
+ if (!join[name]) throw _("Named entity '<%=name%>' is undefined.").template({name:name});
+ name = base(join[name].on);
+ } while(name);
+ return path.length;
+ }).
+ value();
+ if (_(joinOrder).select(function($){return join[$].on;}).length != joinOrder.length - 1)
+ throw "Exactly one entity needs to be primary.";
+ fn['query'] = function(exp, value) {
+ var joinedResult = [];
+ var baseName = base(exp);
+ if (baseName != joinOrder[0]) throw _("Named entity '<%=name%>' is not a primary entity.").template({name:baseName});
+ var Entity = join[baseName].join;
+ var joinIndex = 1;
+ Entity['query'](next(exp), value, function(result){
+ var nextJoinName = joinOrder[joinIndex++];
+ var nextJoin = join[nextJoinName];
+ var nextJoinOn = nextJoin.on;
+ var joinIds = {};
_(result).each(function(doc){
- byId[doc.$id] = doc;
- });
- _(joinedResult).each(function(row){
+ var row = {};
+ joinedResult.push(row);
+ row[baseName] = doc;
var id = Scope.getter(row, nextJoinOn);
- row[nextJoinName] = byId[id];
+ joinIds[id] = id;
+ });
+ nextJoin.join.loadMany(_.toArray(joinIds), function(result){
+ var byId = {};
+ _(result).each(function(doc){
+ byId[doc.$id] = doc;
+ });
+ _(joinedResult).each(function(row){
+ var id = Scope.getter(row, nextJoinOn);
+ row[nextJoinName] = byId[id];
+ });
});
});
- });
- return joinedResult;
- };
- return fn;
-};
+ return joinedResult;
+ };
+ return fn;
+ }
+}; \ No newline at end of file
diff --git a/src/Filters.js b/src/Filters.js
index 67fcffa1..666c9f30 100644
--- a/src/Filters.js
+++ b/src/Filters.js
@@ -1,5 +1,3 @@
-// Copyright (C) 2009 BRAT Tech LLC
-
angularFilter.Meta = function(obj){
if (obj) {
for ( var key in obj) {
diff --git a/src/JSON.js b/src/JSON.js
index 14fce1fb..0c842865 100644
--- a/src/JSON.js
+++ b/src/JSON.js
@@ -1,16 +1,16 @@
array = [].constructor;
-toJson = function(obj, pretty){
+function toJson(obj, pretty){
var buf = [];
toJsonArray(buf, obj, pretty ? "\n " : null);
return buf.join('');
};
-toPrettyJson = function(obj) {
+function toPrettyJson(obj) {
return toJson(obj, true);
};
-fromJson = function(json) {
+function fromJson(json) {
try {
var parser = new Parser(json, true);
var expression = parser.primary();
@@ -22,8 +22,10 @@ fromJson = function(json) {
}
};
+angular['toJson'] = toJson;
+angular['fromJson'] = fromJson;
-toJsonArray = function(buf, obj, pretty){
+function toJsonArray(buf, obj, pretty){
var type = typeof obj;
if (obj === null) {
buf.push("null");
diff --git a/src/Loader.js b/src/Loader.js
index 104dfec8..5207defb 100644
--- a/src/Loader.js
+++ b/src/Loader.js
@@ -1,7 +1,3 @@
-// Copyright (C) 2008,2009 BRAT Tech LLC
-
-// IE compatibility
-
if (typeof document.getAttribute == 'undefined')
document.getAttribute = function() {};
if (typeof Node == 'undefined') {
diff --git a/src/Model.js b/src/Model.js
index 35f6a1c1..4a3a1806 100644
--- a/src/Model.js
+++ b/src/Model.js
@@ -1,12 +1,10 @@
-// Copyright (C) 2009 BRAT Tech LLC
-
// Single $ is special and does not get searched
// Double $$ is special an is client only (does not get sent to server)
-Model = function(entity, initial) {
- this.$$entity = entity;
+function Model(entity, initial) {
+ this['$$entity'] = entity;
this.$loadFrom(initial||{});
- this.$entity = entity.title;
+ this.$entity = entity['title'];
this.$migrate();
};
@@ -27,39 +25,41 @@ Model.copyDirectFields = function(src, dst) {
}
};
-Model.prototype.$migrate = function() {
- merge(this.$$entity.defaults, this);
- return this;
-};
-
-Model.prototype.$merge = function(other) {
- merge(other, this);
- return this;
-};
-
-Model.prototype.$save = function(callback) {
- this.$$entity.datastore.save(this, callback === true ? undefined : callback);
- if (callback === true) this.$$entity.datastore.flush();
- return this;
-};
-
-Model.prototype.$delete = function(callback) {
- this.$$entity.datastore.remove(this, callback === true ? undefined : callback);
- if (callback === true) this.$$entity.datastore.flush();
- return this;
-};
-
-Model.prototype.$loadById = function(id, callback) {
- this.$$entity.datastore.load(this, id, callback);
- return this;
-};
-
-Model.prototype.$loadFrom = function(other) {
- Model.copyDirectFields(other, this);
- return this;
-};
-
-Model.prototype.$saveTo = function(other) {
- Model.copyDirectFields(this, other);
- return this;
-};
+Model.prototype = {
+ '$migrate': function() {
+ merge(this['$$entity'].defaults, this);
+ return this;
+ },
+
+ '$merge': function(other) {
+ merge(other, this);
+ return this;
+ },
+
+ '$save': function(callback) {
+ this['$$entity'].datastore.save(this, callback === true ? undefined : callback);
+ if (callback === true) this['$$entity'].datastore.flush();
+ return this;
+ },
+
+ '$delete': function(callback) {
+ this['$$entity'].datastore.remove(this, callback === true ? undefined : callback);
+ if (callback === true) this['$$entity'].datastore.flush();
+ return this;
+ },
+
+ '$loadById': function(id, callback) {
+ this['$$entity'].datastore.load(this, id, callback);
+ return this;
+ },
+
+ '$loadFrom': function(other) {
+ Model.copyDirectFields(other, this);
+ return this;
+ },
+
+ '$saveTo': function(other) {
+ Model.copyDirectFields(this, other);
+ return this;
+ }
+}; \ No newline at end of file
diff --git a/src/Parser.js b/src/Parser.js
index cdece11e..333b8413 100644
--- a/src/Parser.js
+++ b/src/Parser.js
@@ -1,4 +1,4 @@
-Lexer = function(text, parsStrings){
+function Lexer(text, parsStrings){
this.text = text;
// UTC dates have 20 characters, we send them through parser
this.dateParseLength = parsStrings ? 20 : -1;
@@ -30,210 +30,214 @@ Lexer.OPERATORS = {
'|':function(self, a,b){return b(self, a);},
'!':function(self, a){return !a;}
};
+Lexer.ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
-Lexer.prototype.peek = function() {
- if (this.index + 1 < this.text.length) {
- return this.text.charAt(this.index + 1);
- } else {
- return false;
- }
-};
-
-Lexer.prototype.parse = function() {
- var tokens = this.tokens;
- var OPERATORS = Lexer.OPERATORS;
- var canStartRegExp = true;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (ch == '"' || ch == "'") {
- this.readString(ch);
- canStartRegExp = true;
- } else if (ch == '(' || ch == '[') {
- tokens.push({index:this.index, text:ch});
- this.index++;
- } else if (ch == '{' ) {
- var peekCh = this.peek();
- if (peekCh == ':' || peekCh == '(') {
- tokens.push({index:this.index, text:ch + peekCh});
+Lexer.prototype = {
+ peek: function() {
+ if (this.index + 1 < this.text.length) {
+ return this.text.charAt(this.index + 1);
+ } else {
+ return false;
+ }
+ },
+
+ parse: function() {
+ var tokens = this.tokens;
+ var OPERATORS = Lexer.OPERATORS;
+ var canStartRegExp = true;
+ while (this.index < this.text.length) {
+ var ch = this.text.charAt(this.index);
+ if (ch == '"' || ch == "'") {
+ this.readString(ch);
+ canStartRegExp = true;
+ } else if (ch == '(' || ch == '[') {
+ tokens.push({index:this.index, text:ch});
this.index++;
- } else {
+ } else if (ch == '{' ) {
+ var peekCh = this.peek();
+ if (peekCh == ':' || peekCh == '(') {
+ tokens.push({index:this.index, text:ch + peekCh});
+ this.index++;
+ } else {
+ tokens.push({index:this.index, text:ch});
+ }
+ this.index++;
+ canStartRegExp = true;
+ } else if (ch == ')' || ch == ']' || ch == '}' ) {
tokens.push({index:this.index, text:ch});
+ this.index++;
+ canStartRegExp = false;
+ } else if ( ch == ':' || ch == '.' || ch == ',' || ch == ';') {
+ tokens.push({index:this.index, text:ch});
+ this.index++;
+ canStartRegExp = true;
+ } else if ( canStartRegExp && ch == '/' ) {
+ this.readRegexp();
+ canStartRegExp = false;
+ } else if ( this.isNumber(ch) ) {
+ this.readNumber();
+ canStartRegExp = false;
+ } else if (this.isIdent(ch)) {
+ this.readIdent();
+ canStartRegExp = false;
+ } else if (this.isWhitespace(ch)) {
+ this.index++;
+ } else {
+ var ch2 = ch + this.peek();
+ var fn = OPERATORS[ch];
+ var fn2 = OPERATORS[ch2];
+ if (fn2) {
+ tokens.push({index:this.index, text:ch2, fn:fn2});
+ this.index += 2;
+ } else if (fn) {
+ tokens.push({index:this.index, text:ch, fn:fn});
+ this.index += 1;
+ } else {
+ throw "Lexer Error: Unexpected next character [" +
+ this.text.substring(this.index) +
+ "] in expression '" + this.text +
+ "' at column '" + (this.index+1) + "'.";
+ }
+ canStartRegExp = true;
}
- this.index++;
- canStartRegExp = true;
- } else if (ch == ')' || ch == ']' || ch == '}' ) {
- tokens.push({index:this.index, text:ch});
- this.index++;
- canStartRegExp = false;
- } else if ( ch == ':' || ch == '.' || ch == ',' || ch == ';') {
- tokens.push({index:this.index, text:ch});
- this.index++;
- canStartRegExp = true;
- } else if ( canStartRegExp && ch == '/' ) {
- this.readRegexp();
- canStartRegExp = false;
- } else if ( this.isNumber(ch) ) {
- this.readNumber();
- canStartRegExp = false;
- } else if (this.isIdent(ch)) {
- this.readIdent();
- canStartRegExp = false;
- } else if (this.isWhitespace(ch)) {
- this.index++;
- } else {
- var ch2 = ch + this.peek();
- var fn = OPERATORS[ch];
- var fn2 = OPERATORS[ch2];
- if (fn2) {
- tokens.push({index:this.index, text:ch2, fn:fn2});
- this.index += 2;
- } else if (fn) {
- tokens.push({index:this.index, text:ch, fn:fn});
- this.index += 1;
+ }
+ return tokens;
+ },
+
+ isNumber: function(ch) {
+ return '0' <= ch && ch <= '9';
+ },
+
+ isWhitespace: function(ch) {
+ return ch == ' ' || ch == '\r' || ch == '\t' ||
+ ch == '\n' || ch == '\v';
+ },
+
+ isIdent: function(ch) {
+ return 'a' <= ch && ch <= 'z' ||
+ 'A' <= ch && ch <= 'Z' ||
+ '_' == ch || ch == '$';
+ },
+
+ readNumber: function() {
+ var number = "";
+ var start = this.index;
+ while (this.index < this.text.length) {
+ var ch = this.text.charAt(this.index);
+ if (ch == '.' || this.isNumber(ch)) {
+ number += ch;
} else {
- throw "Lexer Error: Unexpected next character [" +
- this.text.substring(this.index) +
- "] in expression '" + this.text +
- "' at column '" + (this.index+1) + "'.";
+ break;
}
- canStartRegExp = true;
+ this.index++;
}
- }
- return tokens;
-};
-
-Lexer.prototype.isNumber = function(ch) {
- return '0' <= ch && ch <= '9';
-};
-
-Lexer.prototype.isWhitespace = function(ch) {
- return ch == ' ' || ch == '\r' || ch == '\t' ||
- ch == '\n' || ch == '\v';
-};
-
-Lexer.prototype.isIdent = function(ch) {
- return 'a' <= ch && ch <= 'z' ||
- 'A' <= ch && ch <= 'Z' ||
- '_' == ch || ch == '$';
-};
-
-Lexer.prototype.readNumber = function() {
- var number = "";
- var start = this.index;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (ch == '.' || this.isNumber(ch)) {
- number += ch;
- } else {
- break;
+ number = 1 * number;
+ this.tokens.push({index:start, text:number,
+ fn:function(){return number;}});
+ },
+
+ readIdent: function() {
+ var ident = "";
+ var start = this.index;
+ while (this.index < this.text.length) {
+ var ch = this.text.charAt(this.index);
+ if (ch == '.' || this.isIdent(ch) || this.isNumber(ch)) {
+ ident += ch;
+ } else {
+ break;
+ }
+ this.index++;
}
- this.index++;
- }
- number = 1 * number;
- this.tokens.push({index:start, text:number,
- fn:function(){return number;}});
-};
-
-Lexer.prototype.readIdent = function() {
- var ident = "";
- var start = this.index;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (ch == '.' || this.isIdent(ch) || this.isNumber(ch)) {
- ident += ch;
- } else {
- break;
+ var fn = Lexer.OPERATORS[ident];
+ if (!fn) {
+ fn = function(self){
+ return self.scope.get(ident);
+ };
+ fn.isAssignable = ident;
}
+ this.tokens.push({index:start, text:ident, fn:fn});
+ },
+
+ readString: function(quote) {
+ var start = this.index;
+ var dateParseLength = this.dateParseLength;
this.index++;
- }
- var fn = Lexer.OPERATORS[ident];
- if (!fn) {
- fn = function(self){
- return self.scope.get(ident);
- };
- fn.isAssignable = ident;
- }
- this.tokens.push({index:start, text:ident, fn:fn});
-};
-Lexer.ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
-Lexer.prototype.readString = function(quote) {
- var start = this.index;
- var dateParseLength = this.dateParseLength;
- this.index++;
- var string = "";
- var escape = false;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (escape) {
- if (ch == 'u') {
- var hex = this.text.substring(this.index + 1, this.index + 5);
- this.index += 4;
- string += String.fromCharCode(parseInt(hex, 16));
- } else {
- var rep = Lexer.ESCAPE[ch];
- if (rep) {
- string += rep;
+ var string = "";
+ var escape = false;
+ while (this.index < this.text.length) {
+ var ch = this.text.charAt(this.index);
+ if (escape) {
+ if (ch == 'u') {
+ var hex = this.text.substring(this.index + 1, this.index + 5);
+ this.index += 4;
+ string += String.fromCharCode(parseInt(hex, 16));
} else {
- string += ch;
+ var rep = Lexer.ESCAPE[ch];
+ if (rep) {
+ string += rep;
+ } else {
+ string += ch;
+ }
}
+ escape = false;
+ } else if (ch == '\\') {
+ escape = true;
+ } else if (ch == quote) {
+ this.index++;
+ this.tokens.push({index:start, text:string,
+ fn:function(){
+ return (string.length == dateParseLength) ?
+ angular['String']['toDate'](string) : string;
+ }});
+ return;
+ } else {
+ string += ch;
}
- escape = false;
- } else if (ch == '\\') {
- escape = true;
- } else if (ch == quote) {
this.index++;
- this.tokens.push({index:start, text:string,
- fn:function(){
- return (string.length == dateParseLength) ?
- angular['String']['toDate'](string) : string;
- }});
- return;
- } else {
- string += ch;
}
+ throw "Lexer Error: Unterminated quote [" +
+ this.text.substring(start) + "] starting at column '" +
+ (start+1) + "' in expression '" + this.text + "'.";
+ },
+
+ readRegexp: function(quote) {
+ var start = this.index;
this.index++;
- }
- throw "Lexer Error: Unterminated quote [" +
- this.text.substring(start) + "] starting at column '" +
- (start+1) + "' in expression '" + this.text + "'.";
-};
-
-Lexer.prototype.readRegexp = function(quote) {
- var start = this.index;
- this.index++;
- var regexp = "";
- var escape = false;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (escape) {
- regexp += ch;
- escape = false;
- } else if (ch === '\\') {
- regexp += ch;
- escape = true;
- } else if (ch === '/') {
- this.index++;
- var flags = "";
- if (this.isIdent(this.text.charAt(this.index))) {
- this.readIdent();
- flags = this.tokens.pop().text;
+ var regexp = "";
+ var escape = false;
+ while (this.index < this.text.length) {
+ var ch = this.text.charAt(this.index);
+ if (escape) {
+ regexp += ch;
+ escape = false;
+ } else if (ch === '\\') {
+ regexp += ch;
+ escape = true;
+ } else if (ch === '/') {
+ this.index++;
+ var flags = "";
+ if (this.isIdent(this.text.charAt(this.index))) {
+ this.readIdent();
+ flags = this.tokens.pop().text;
+ }
+ var compiledRegexp = new RegExp(regexp, flags);
+ this.tokens.push({index:start, text:regexp, flags:flags,
+ fn:function(){return compiledRegexp;}});
+ return;
+ } else {
+ regexp += ch;
}
- var compiledRegexp = new RegExp(regexp, flags);
- this.tokens.push({index:start, text:regexp, flags:flags,
- fn:function(){return compiledRegexp;}});
- return;
- } else {
- regexp += ch;
+ this.index++;
}
- this.index++;
+ throw "Lexer Error: Unterminated RegExp [" +
+ this.text.substring(start) + "] starting at column '" +
+ (start+1) + "' in expression '" + this.text + "'.";
}
- throw "Lexer Error: Unterminated RegExp [" +
- this.text.substring(start) + "] starting at column '" +
- (start+1) + "' in expression '" + this.text + "'.";
};
+/////////////////////////////////////////
-Parser = function(text, parseStrings){
+function Parser(text, parseStrings){
this.text = text;
this.tokens = new Lexer(text, parseStrings).parse();
this.index = 0;
@@ -243,499 +247,501 @@ Parser.ZERO = function(){
return 0;
};
-Parser.prototype.error = function(msg, token) {
- throw "Token '" + token.text +
- "' is " + msg + " at column='" +
- (token.index + 1) + "' of expression '" +
- this.text + "' starting at '" + this.text.substring(token.index) + "'.";
-};
-
-Parser.prototype.peekToken = function() {
- if (this.tokens.length === 0)
- throw "Unexpected end of expression: " + this.text;
- return this.tokens[0];
-};
-
-Parser.prototype.peek = function(e1, e2, e3, e4) {
- var tokens = this.tokens;
- if (tokens.length > 0) {
- var token = tokens[0];
- var t = token.text;
- if (t==e1 || t==e2 || t==e3 || t==e4 ||
- (!e1 && !e2 && !e3 && !e4)) {
+Parser.prototype = {
+ error: function(msg, token) {
+ throw "Token '" + token.text +
+ "' is " + msg + " at column='" +
+ (token.index + 1) + "' of expression '" +
+ this.text + "' starting at '" + this.text.substring(token.index) + "'.";
+ },
+
+ peekToken: function() {
+ if (this.tokens.length === 0)
+ throw "Unexpected end of expression: " + this.text;
+ return this.tokens[0];
+ },
+
+ peek: function(e1, e2, e3, e4) {
+ var tokens = this.tokens;
+ if (tokens.length > 0) {
+ var token = tokens[0];
+ var t = token.text;
+ if (t==e1 || t==e2 || t==e3 || t==e4 ||
+ (!e1 && !e2 && !e3 && !e4)) {
+ return token;
+ }
+ }
+ return false;
+ },
+
+ expect: function(e1, e2, e3, e4){
+ var token = this.peek(e1, e2, e3, e4);
+ if (token) {
+ this.tokens.shift();
+ this.currentToken = token;
return token;
}
- }
- return false;
-};
-
-Parser.prototype.expect = function(e1, e2, e3, e4){
- var token = this.peek(e1, e2, e3, e4);
- if (token) {
- this.tokens.shift();
- this.currentToken = token;
- return token;
- }
- return false;
-};
-
-Parser.prototype.consume = function(e1){
- if (!this.expect(e1)) {
- var token = this.peek();
- throw "Expecting '" + e1 + "' at column '" +
- (token.index+1) + "' in '" +
- this.text + "' got '" +
- this.text.substring(token.index) + "'.";
- }
-};
-
-Parser.prototype._unary = function(fn, parse) {
- var right = parse.apply(this);
- return function(self) {
- return fn(self, right(self));
- };
-};
-
-Parser.prototype._binary = function(left, fn, parse) {
- var right = parse.apply(this);
- return function(self) {
- return fn(self, left(self), right(self));
- };
-};
-
-Parser.prototype.hasTokens = function () {
- return this.tokens.length > 0;
-};
-
-Parser.prototype.assertAllConsumed = function(){
- if (this.tokens.length !== 0) {
- throw "Did not understand '" + this.text.substring(this.tokens[0].index) +
- "' while evaluating '" + this.text + "'.";
- }
-};
-
-Parser.prototype.statements = function(){
- var statements = [];
- while(true) {
- if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
- statements.push(this.filterChain());
- if (!this.expect(';')) {
- return function (self){
- var value;
- for ( var i = 0; i < statements.length; i++) {
- var statement = statements[i];
- if (statement)
- value = statement(self);
- }
- return value;
- };
+ return false;
+ },
+
+ consume: function(e1){
+ if (!this.expect(e1)) {
+ var token = this.peek();
+ throw "Expecting '" + e1 + "' at column '" +
+ (token.index+1) + "' in '" +
+ this.text + "' got '" +
+ this.text.substring(token.index) + "'.";
}
- }
-};
-
-Parser.prototype.filterChain = function(){
- var left = this.expression();
- var token;
- while(true) {
- if ((token = this.expect('|'))) {
- left = this._binary(left, token.fn, this.filter);
- } else {
- return left;
+ },
+
+ _unary: function(fn, parse) {
+ var right = parse.apply(this);
+ return function(self) {
+ return fn(self, right(self));
+ };
+ },
+
+ _binary: function(left, fn, parse) {
+ var right = parse.apply(this);
+ return function(self) {
+ return fn(self, left(self), right(self));
+ };
+ },
+
+ hasTokens: function () {
+ return this.tokens.length > 0;
+ },
+
+ assertAllConsumed: function(){
+ if (this.tokens.length !== 0) {
+ throw "Did not understand '" + this.text.substring(this.tokens[0].index) +
+ "' while evaluating '" + this.text + "'.";
}
- }
-};
-
-Parser.prototype.filter = function(){
- return this._pipeFunction(angular['filter']);
-};
-
-Parser.prototype.validator = function(){
- return this._pipeFunction(angular['validator']);
-};
-
-Parser.prototype._pipeFunction = function(fnScope){
- var fn = this.functionIdent(fnScope);
- var argsFn = [];
- var token;
- while(true) {
- if ((token = this.expect(':'))) {
- argsFn.push(this.expression());
- } else {
- var fnInvoke = function(self, input){
- var args = [input];
- for ( var i = 0; i < argsFn.length; i++) {
- args.push(argsFn[i](self));
- }
- return fn.apply(self, args);
- };
- return function(){
- return fnInvoke;
- };
+ },
+
+ statements: function(){
+ var statements = [];
+ while(true) {
+ if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
+ statements.push(this.filterChain());
+ if (!this.expect(';')) {
+ return function (self){
+ var value;
+ for ( var i = 0; i < statements.length; i++) {
+ var statement = statements[i];
+ if (statement)
+ value = statement(self);
+ }
+ return value;
+ };
+ }
}
- }
-};
-
-Parser.prototype.expression = function(){
- return this.throwStmt();
-};
-
-Parser.prototype.throwStmt = function(){
- if (this.expect('throw')) {
- var throwExp = this.assignment();
- return function (self) {
- throw throwExp(self);
- };
- } else {
- return this.assignment();
- }
-};
-
-Parser.prototype.assignment = function(){
- var left = this.logicalOR();
- var token;
- if (token = this.expect('=')) {
- if (!left.isAssignable) {
- throw "Left hand side '" +
- this.text.substring(0, token.index) + "' of assignment '" +
- this.text.substring(token.index) + "' is not assignable.";
- }
- var ident = function(){return left.isAssignable;};
- return this._binary(ident, token.fn, this.logicalOR);
- } else {
- return left;
- }
-};
-
-Parser.prototype.logicalOR = function(){
- var left = this.logicalAND();
- var token;
- while(true) {
- if ((token = this.expect('||'))) {
- left = this._binary(left, token.fn, this.logicalAND);
+ },
+
+ filterChain: function(){
+ var left = this.expression();
+ var token;
+ while(true) {
+ if ((token = this.expect('|'))) {
+ left = this._binary(left, token.fn, this.filter);
+ } else {
+ return left;
+ }
+ }
+ },
+
+ filter: function(){
+ return this._pipeFunction(angular['filter']);
+ },
+
+ validator: function(){
+ return this._pipeFunction(angular['validator']);
+ },
+
+ _pipeFunction: function(fnScope){
+ var fn = this.functionIdent(fnScope);
+ var argsFn = [];
+ var token;
+ while(true) {
+ if ((token = this.expect(':'))) {
+ argsFn.push(this.expression());
+ } else {
+ var fnInvoke = function(self, input){
+ var args = [input];
+ for ( var i = 0; i < argsFn.length; i++) {
+ args.push(argsFn[i](self));
+ }
+ return fn.apply(self, args);
+ };
+ return function(){
+ return fnInvoke;
+ };
+ }
+ }
+ },
+
+ expression: function(){
+ return this.throwStmt();
+ },
+
+ throwStmt: function(){
+ if (this.expect('throw')) {
+ var throwExp = this.assignment();
+ return function (self) {
+ throw throwExp(self);
+ };
} else {
- return left;
+ return this.assignment();
}
- }
-};
-
-Parser.prototype.logicalAND = function(){
- var left = this.negated();
- var token;
- while(true) {
- if ((token = this.expect('&&'))) {
- left = this._binary(left, token.fn, this.negated);
+ },
+
+ assignment: function(){
+ var left = this.logicalOR();
+ var token;
+ if (token = this.expect('=')) {
+ if (!left.isAssignable) {
+ throw "Left hand side '" +
+ this.text.substring(0, token.index) + "' of assignment '" +
+ this.text.substring(token.index) + "' is not assignable.";
+ }
+ var ident = function(){return left.isAssignable;};
+ return this._binary(ident, token.fn, this.logicalOR);
} else {
- return left;
+ return left;
}
- }
-};
-
-Parser.prototype.negated = function(){
- var token;
- if (token = this.expect('!')) {
- return this._unary(token.fn, this.equality);
- } else {
- return this.equality();
- }
-};
-
-Parser.prototype.equality = function(){
- var left = this.relational();
- var token;
- while(true) {
- if ((token = this.expect('==','!='))) {
- left = this._binary(left, token.fn, this.relational);
+ },
+
+ logicalOR: function(){
+ var left = this.logicalAND();
+ var token;
+ while(true) {
+ if ((token = this.expect('||'))) {
+ left = this._binary(left, token.fn, this.logicalAND);
+ } else {
+ return left;
+ }
+ }
+ },
+
+ logicalAND: function(){
+ var left = this.negated();
+ var token;
+ while(true) {
+ if ((token = this.expect('&&'))) {
+ left = this._binary(left, token.fn, this.negated);
+ } else {
+ return left;
+ }
+ }
+ },
+
+ negated: function(){
+ var token;
+ if (token = this.expect('!')) {
+ return this._unary(token.fn, this.equality);
} else {
- return left;
+ return this.equality();
}
- }
-};
-
-Parser.prototype.relational = function(){
- var left = this.additive();
- var token;
- while(true) {
- if ((token = this.expect('<', '>', '<=', '>='))) {
- left = this._binary(left, token.fn, this.additive);
+ },
+
+ equality: function(){
+ var left = this.relational();
+ var token;
+ while(true) {
+ if ((token = this.expect('==','!='))) {
+ left = this._binary(left, token.fn, this.relational);
+ } else {
+ return left;
+ }
+ }
+ },
+
+ relational: function(){
+ var left = this.additive();
+ var token;
+ while(true) {
+ if ((token = this.expect('<', '>', '<=', '>='))) {
+ left = this._binary(left, token.fn, this.additive);
+ } else {
+ return left;
+ }
+ }
+ },
+
+ additive: function(){
+ var left = this.multiplicative();
+ var token;
+ while(token = this.expect('+','-')) {
+ left = this._binary(left, token.fn, this.multiplicative);
+ }
+ return left;
+ },
+
+ multiplicative: function(){
+ var left = this.unary();
+ var token;
+ while(token = this.expect('*','/','%')) {
+ left = this._binary(left, token.fn, this.unary);
+ }
+ return left;
+ },
+
+ unary: function(){
+ var token;
+ if (this.expect('+')) {
+ return this.primary();
+ } else if (token = this.expect('-')) {
+ return this._binary(Parser.ZERO, token.fn, this.multiplicative);
} else {
- return left;
+ return this.primary();
}
- }
-};
-
-Parser.prototype.additive = function(){
- var left = this.multiplicative();
- var token;
- while(token = this.expect('+','-')) {
- left = this._binary(left, token.fn, this.multiplicative);
- }
- return left;
-};
-
-Parser.prototype.multiplicative = function(){
- var left = this.unary();
- var token;
- while(token = this.expect('*','/','%')) {
- left = this._binary(left, token.fn, this.unary);
- }
- return left;
-};
-
-Parser.prototype.unary = function(){
- var token;
- if (this.expect('+')) {
- return this.primary();
- } else if (token = this.expect('-')) {
- return this._binary(Parser.ZERO, token.fn, this.multiplicative);
- } else {
- return this.primary();
- }
-};
-
-Parser.prototype.functionIdent = function(fnScope) {
- var token = this.expect();
- var element = token.text.split('.');
- var instance = fnScope;
- var key;
- for ( var i = 0; i < element.length; i++) {
- key = element[i];
- if (instance)
- instance = instance[key];
- }
- if (typeof instance != 'function') {
- throw "Function '" + token.text + "' at column '" +
- (token.index+1) + "' in '" + this.text + "' is not defined.";
- }
- return instance;
-};
-
-Parser.prototype.primary = function() {
- var primary;
- if (this.expect('(')) {
- var expression = this.filterChain();
- this.consume(')');
- primary = expression;
- } else if (this.expect('[')) {
- primary = this.arrayDeclaration();
- } else if (this.expect('{')) {
- primary = this.object();
- } else if (this.expect('{:')) {
- primary = this.closure(false);
- } else if (this.expect('{(')) {
- primary = this.closure(true);
- } else {
+ },
+
+ functionIdent: function(fnScope) {
var token = this.expect();
- primary = token.fn;
- if (!primary) {
- this.error("not a primary expression", token);
+ var element = token.text.split('.');
+ var instance = fnScope;
+ var key;
+ for ( var i = 0; i < element.length; i++) {
+ key = element[i];
+ if (instance)
+ instance = instance[key];
}
- }
- var next;
- while (next = this.expect('(', '[', '.')) {
- if (next.text === '(') {
- primary = this.functionCall(primary);
- } else if (next.text === '[') {
- primary = this.objectIndex(primary);
- } else if (next.text === '.') {
- primary = this.fieldAccess(primary);
+ if (typeof instance != 'function') {
+ throw "Function '" + token.text + "' at column '" +
+ (token.index+1) + "' in '" + this.text + "' is not defined.";
+ }
+ return instance;
+ },
+
+ primary: function() {
+ var primary;
+ if (this.expect('(')) {
+ var expression = this.filterChain();
+ this.consume(')');
+ primary = expression;
+ } else if (this.expect('[')) {
+ primary = this.arrayDeclaration();
+ } else if (this.expect('{')) {
+ primary = this.object();
+ } else if (this.expect('{:')) {
+ primary = this.closure(false);
+ } else if (this.expect('{(')) {
+ primary = this.closure(true);
} else {
- throw "IMPOSSIBLE";
+ var token = this.expect();
+ primary = token.fn;
+ if (!primary) {
+ this.error("not a primary expression", token);
+ }
}
- }
- return primary;
-};
-
-Parser.prototype.closure = function(hasArgs) {
- var args = [];
- if (hasArgs) {
- if (!this.expect(')')) {
- args.push(this.expect().text);
- while(this.expect(',')) {
+ var next;
+ while (next = this.expect('(', '[', '.')) {
+ if (next.text === '(') {
+ primary = this.functionCall(primary);
+ } else if (next.text === '[') {
+ primary = this.objectIndex(primary);
+ } else if (next.text === '.') {
+ primary = this.fieldAccess(primary);
+ } else {
+ throw "IMPOSSIBLE";
+ }
+ }
+ return primary;
+ },
+
+ closure: function(hasArgs) {
+ var args = [];
+ if (hasArgs) {
+ if (!this.expect(')')) {
args.push(this.expect().text);
+ while(this.expect(',')) {
+ args.push(this.expect().text);
+ }
+ this.consume(')');
}
- this.consume(')');
+ this.consume(":");
}
- this.consume(":");
- }
- var statements = this.statements();
- this.consume("}");
- return function(self){
- return function($){
- var scope = new Scope(self.scope.state);
- scope.set('$', $);
- for ( var i = 0; i < args.length; i++) {
- scope.set(args[i], arguments[i]);
+ var statements = this.statements();
+ this.consume("}");
+ return function(self){
+ return function($){
+ var scope = new Scope(self.scope.state);
+ scope.set('$', $);
+ for ( var i = 0; i < args.length; i++) {
+ scope.set(args[i], arguments[i]);
+ }
+ return statements({scope:scope});
+ };
+ };
+ },
+
+ fieldAccess: function(object) {
+ var field = this.expect().text;
+ var fn = function (self){
+ return Scope.getter(object(self), field);
+ };
+ fn.isAssignable = field;
+ return fn;
+ },
+
+ objectIndex: function(obj) {
+ var indexFn = this.expression();
+ this.consume(']');
+ if (this.expect('=')) {
+ var rhs = this.expression();
+ return function (self){
+ return obj(self)[indexFn(self)] = rhs(self);
+ };
+ } else {
+ return function (self){
+ var o = obj(self);
+ var i = indexFn(self);
+ return (o) ? o[i] : undefined;
+ };
+ }
+ },
+
+ functionCall: function(fn) {
+ var argsFn = [];
+ if (this.peekToken().text != ')') {
+ do {
+ argsFn.push(this.expression());
+ } while (this.expect(','));
+ }
+ this.consume(')');
+ return function (self){
+ var args = [];
+ for ( var i = 0; i < argsFn.length; i++) {
+ args.push(argsFn[i](self));
+ }
+ var fnPtr = fn(self);
+ if (typeof fnPtr === 'function') {
+ return fnPtr.apply(self, args);
+ } else {
+ throw "Expression '" + fn.isAssignable + "' is not a function.";
}
- return statements({scope:scope});
};
- };
-};
-
-Parser.prototype.fieldAccess = function(object) {
- var field = this.expect().text;
- var fn = function (self){
- return Scope.getter(object(self), field);
- };
- fn.isAssignable = field;
- return fn;
-};
-
-Parser.prototype.objectIndex = function(obj) {
- var indexFn = this.expression();
- this.consume(']');
- if (this.expect('=')) {
- var rhs = this.expression();
+ },
+
+ // This is used with json array declaration
+ arrayDeclaration: function () {
+ var elementFns = [];
+ if (this.peekToken().text != ']') {
+ do {
+ elementFns.push(this.expression());
+ } while (this.expect(','));
+ }
+ this.consume(']');
return function (self){
- return obj(self)[indexFn(self)] = rhs(self);
+ var array = [];
+ for ( var i = 0; i < elementFns.length; i++) {
+ array.push(elementFns[i](self));
+ }
+ return array;
};
- } else {
+ },
+
+ object: function () {
+ var keyValues = [];
+ if (this.peekToken().text != '}') {
+ do {
+ var key = this.expect().text;
+ this.consume(":");
+ var value = this.expression();
+ keyValues.push({key:key, value:value});
+ } while (this.expect(','));
+ }
+ this.consume('}');
return function (self){
- var o = obj(self);
- var i = indexFn(self);
- return (o) ? o[i] : undefined;
+ var object = {};
+ for ( var i = 0; i < keyValues.length; i++) {
+ var keyValue = keyValues[i];
+ var value = keyValue.value(self);
+ object[keyValue.key] = value;
+ }
+ return object;
};
- }
-};
-
-Parser.prototype.functionCall = function(fn) {
- var argsFn = [];
- if (this.peekToken().text != ')') {
- do {
- argsFn.push(this.expression());
- } while (this.expect(','));
- }
- this.consume(')');
- return function (self){
- var args = [];
- for ( var i = 0; i < argsFn.length; i++) {
- args.push(argsFn[i](self));
+ },
+
+ entityDeclaration: function () {
+ var decl = [];
+ while(this.hasTokens()) {
+ decl.push(this.entityDecl());
+ if (!this.expect(';')) {
+ this.assertAllConsumed();
+ }
}
- var fnPtr = fn(self);
- if (typeof fnPtr === 'function') {
- return fnPtr.apply(self, args);
- } else {
- throw "Expression '" + fn.isAssignable + "' is not a function.";
+ return function (self){
+ var code = "";
+ for ( var i = 0; i < decl.length; i++) {
+ code += decl[i](self);
+ }
+ return code;
+ };
+ },
+
+ entityDecl: function () {
+ var entity = this.expect().text;
+ var instance;
+ var defaults;
+ if (this.expect('=')) {
+ instance = entity;
+ entity = this.expect().text;
}
- };
-};
-
-// This is used with json array declaration
-Parser.prototype.arrayDeclaration = function () {
- var elementFns = [];
- if (this.peekToken().text != ']') {
- do {
- elementFns.push(this.expression());
- } while (this.expect(','));
- }
- this.consume(']');
- return function (self){
- var array = [];
- for ( var i = 0; i < elementFns.length; i++) {
- array.push(elementFns[i](self));
- }
- return array;
- };
-};
-
-Parser.prototype.object = function () {
- var keyValues = [];
- if (this.peekToken().text != '}') {
- do {
- var key = this.expect().text;
- this.consume(":");
- var value = this.expression();
- keyValues.push({key:key, value:value});
- } while (this.expect(','));
- }
- this.consume('}');
- return function (self){
- var object = {};
- for ( var i = 0; i < keyValues.length; i++) {
- var keyValue = keyValues[i];
- var value = keyValue.value(self);
- object[keyValue.key] = value;
- }
- return object;
- };
-};
-
-Parser.prototype.entityDeclaration = function () {
- var decl = [];
- while(this.hasTokens()) {
- decl.push(this.entityDecl());
- if (!this.expect(';')) {
- this.assertAllConsumed();
+ if (this.expect(':')) {
+ defaults = this.primary()(null);
}
- }
- return function (self){
- var code = "";
- for ( var i = 0; i < decl.length; i++) {
- code += decl[i](self);
+ return function(self) {
+ var datastore = self.scope.get('$datastore');
+ var Entity = datastore.entity(entity, defaults);
+ self.scope.set(entity, Entity);
+ if (instance) {
+ var document = Entity();
+ document.$$anchor = instance;
+ self.scope.set(instance, document);
+ return "$anchor." + instance + ":{" +
+ instance + "=" + entity + ".load($anchor." + instance + ");" +
+ instance + ".$$anchor=" + angular['String']['quote'](instance) + ";" +
+ "};";
+ } else {
+ return "";
+ }
+ };
+ },
+
+ watch: function () {
+ var decl = [];
+ while(this.hasTokens()) {
+ decl.push(this.watchDecl());
+ if (!this.expect(';')) {
+ this.assertAllConsumed();
+ }
}
- return code;
- };
-};
-
-Parser.prototype.entityDecl = function () {
- var entity = this.expect().text;
- var instance;
- var defaults;
- if (this.expect('=')) {
- instance = entity;
- entity = this.expect().text;
- }
- if (this.expect(':')) {
- defaults = this.primary()(null);
- }
- return function(self) {
- var datastore = self.scope.get('$datastore');
- var Entity = datastore.entity(entity, defaults);
- self.scope.set(entity, Entity);
- if (instance) {
- var document = Entity();
- document.$$anchor = instance;
- self.scope.set(instance, document);
- return "$anchor." + instance + ":{" +
- instance + "=" + entity + ".load($anchor." + instance + ");" +
- instance + ".$$anchor=" + angular['String']['quote'](instance) + ";" +
- "};";
+ this.assertAllConsumed();
+ return function (self){
+ for ( var i = 0; i < decl.length; i++) {
+ var d = decl[i](self);
+ self.addListener(d.name, d.fn);
+ }
+ };
+ },
+
+ watchDecl: function () {
+ var anchorName = this.expect().text;
+ this.consume(":");
+ var expression;
+ if (this.peekToken().text == '{') {
+ this.consume("{");
+ expression = this.statements();
+ this.consume("}");
} else {
- return "";
- }
- };
-};
-
-Parser.prototype.watch = function () {
- var decl = [];
- while(this.hasTokens()) {
- decl.push(this.watchDecl());
- if (!this.expect(';')) {
- this.assertAllConsumed();
- }
- }
- this.assertAllConsumed();
- return function (self){
- for ( var i = 0; i < decl.length; i++) {
- var d = decl[i](self);
- self.addListener(d.name, d.fn);
+ expression = this.expression();
}
- };
-};
-
-Parser.prototype.watchDecl = function () {
- var anchorName = this.expect().text;
- this.consume(":");
- var expression;
- if (this.peekToken().text == '{') {
- this.consume("{");
- expression = this.statements();
- this.consume("}");
- } else {
- expression = this.expression();
+ return function(self) {
+ return {name:anchorName, fn:expression};
+ };
}
- return function(self) {
- return {name:anchorName, fn:expression};
- };
};
diff --git a/src/Scope.js b/src/Scope.js
index f4b34c3c..dcc50007 100644
--- a/src/Scope.js
+++ b/src/Scope.js
@@ -1,6 +1,4 @@
-// Copyright (C) 2009 BRAT Tech LLC
-
-Scope = function(initialState, name) {
+function Scope(initialState, name) {
this.widgets = [];
this.watchListeners = {};
this.name = name;
@@ -15,31 +13,6 @@ Scope = function(initialState, name) {
};
Scope.expressionCache = {};
-
-Scope.prototype.updateView = function() {
- var self = this;
- this.fireWatchers();
- _.each(this.widgets, function(widget){
- self.evalWidget(widget, "", {}, function(){
- this.updateView(self);
- });
- });
-};
-
-Scope.prototype.addWidget = function(controller) {
- if (controller) this.widgets.push(controller);
-};
-
-Scope.prototype.isProperty = function(exp) {
- for ( var i = 0; i < exp.length; i++) {
- var ch = exp.charAt(i);
- if (ch!='.' && !Lexer.prototype.isIdent(ch)) {
- return false;
- }
- }
- return true;
-};
-
Scope.getter = function(instance, path) {
if (!path) return instance;
var element = path.split('.');
@@ -70,129 +43,155 @@ Scope.getter = function(instance, path) {
return instance;
};
-Scope.prototype.get = function(path) {
- return Scope.getter(this.state, path);
-};
-
-Scope.prototype.set = function(path, value) {
- var element = path.split('.');
- var instance = this.state;
- for ( var i = 0; element.length > 1; i++) {
- var key = element.shift();
- var newInstance = instance[key];
- if (!newInstance) {
- newInstance = {};
- instance[key] = newInstance;
+Scope.prototype = {
+ updateView: function() {
+ var self = this;
+ this.fireWatchers();
+ _.each(this.widgets, function(widget){
+ self.evalWidget(widget, "", {}, function(){
+ this.updateView(self);
+ });
+ });
+ },
+
+ addWidget: function(controller) {
+ if (controller) this.widgets.push(controller);
+ },
+
+ isProperty: function(exp) {
+ for ( var i = 0; i < exp.length; i++) {
+ var ch = exp.charAt(i);
+ if (ch!='.' && !Lexer.prototype.isIdent(ch)) {
+ return false;
+ }
}
- instance = newInstance;
- }
- instance[element.shift()] = value;
- return value;
-};
-
-Scope.prototype.setEval = function(expressionText, value) {
- this.eval(expressionText + "=" + toJson(value));
-};
-
-Scope.prototype.eval = function(expressionText, context) {
- var expression = Scope.expressionCache[expressionText];
- if (!expression) {
- var parser = new Parser(expressionText);
- expression = parser.statements();
- parser.assertAllConsumed();
- Scope.expressionCache[expressionText] = expression;
- }
- context = context || {};
- context.scope = this;
- return expression(context);
-};
-
-//TODO: Refactor. This function needs to be an execution closure for widgets
-// move to widgets
-// remove expression, just have inner closure.
-Scope.prototype.evalWidget = function(widget, expression, context, onSuccess, onFailure) {
- try {
- var value = this.eval(expression, context);
- if (widget.hasError) {
- widget.hasError = false;
- jQuery(widget.view).
- removeClass('ng-exception').
- removeAttr('ng-error');
+ return true;
+ },
+
+ get: function(path) {
+ return Scope.getter(this.state, path);
+ },
+
+ set: function(path, value) {
+ var element = path.split('.');
+ var instance = this.state;
+ for ( var i = 0; element.length > 1; i++) {
+ var key = element.shift();
+ var newInstance = instance[key];
+ if (!newInstance) {
+ newInstance = {};
+ instance[key] = newInstance;
+ }
+ instance = newInstance;
}
- if (onSuccess) {
- value = onSuccess.apply(widget, [value]);
+ instance[element.shift()] = value;
+ return value;
+ },
+
+ setEval: function(expressionText, value) {
+ this.eval(expressionText + "=" + toJson(value));
+ },
+
+ eval: function(expressionText, context) {
+ var expression = Scope.expressionCache[expressionText];
+ if (!expression) {
+ var parser = new Parser(expressionText);
+ expression = parser.statements();
+ parser.assertAllConsumed();
+ Scope.expressionCache[expressionText] = expression;
}
- return true;
- } catch (e){
- error('Eval Widget Error:', e);
- var jsonError = toJson(e, true);
- widget.hasError = true;
- jQuery(widget.view).
- addClass('ng-exception').
- attr('ng-error', jsonError);
- if (onFailure) {
- onFailure.apply(widget, [e, jsonError]);
+ context = context || {};
+ context.scope = this;
+ return expression(context);
+ },
+
+ //TODO: Refactor. This function needs to be an execution closure for widgets
+ // move to widgets
+ // remove expression, just have inner closure.
+ evalWidget: function(widget, expression, context, onSuccess, onFailure) {
+ try {
+ var value = this.eval(expression, context);
+ if (widget.hasError) {
+ widget.hasError = false;
+ jQuery(widget.view).
+ removeClass('ng-exception').
+ removeAttr('ng-error');
+ }
+ if (onSuccess) {
+ value = onSuccess.apply(widget, [value]);
+ }
+ return true;
+ } catch (e){
+ error('Eval Widget Error:', e);
+ var jsonError = toJson(e, true);
+ widget.hasError = true;
+ jQuery(widget.view).
+ addClass('ng-exception').
+ attr('ng-error', jsonError);
+ if (onFailure) {
+ onFailure.apply(widget, [e, jsonError]);
+ }
+ return false;
}
- return false;
- }
-};
-
-Scope.prototype.validate = function(expressionText, value) {
- var expression = Scope.expressionCache[expressionText];
- if (!expression) {
- expression = new Parser(expressionText).validator();
- Scope.expressionCache[expressionText] = expression;
- }
- var self = {scope:this};
- return expression(self)(self, value);
-};
-
-Scope.prototype.entity = function(entityDeclaration) {
- var expression = new Parser(entityDeclaration).entityDeclaration();
- return expression({scope:this});
-};
-
-Scope.prototype.markInvalid = function(widget) {
- this.state.$invalidWidgets.push(widget);
-};
-
-Scope.prototype.watch = function(declaration) {
- var self = this;
- new Parser(declaration).watch()({
- scope:this,
- addListener:function(watch, exp){
- self.addWatchListener(watch, function(n,o){
- try {
- return exp({scope:self}, n, o);
- } catch(e) {
- alert(e);
- }
- });
+ },
+
+ validate: function(expressionText, value) {
+ var expression = Scope.expressionCache[expressionText];
+ if (!expression) {
+ expression = new Parser(expressionText).validator();
+ Scope.expressionCache[expressionText] = expression;
}
- });
-};
-
-Scope.prototype.addWatchListener = function(watchExpression, listener) {
- var watcher = this.watchListeners[watchExpression];
- if (!watcher) {
- watcher = {listeners:[], expression:watchExpression};
- this.watchListeners[watchExpression] = watcher;
- }
- watcher.listeners.push(listener);
-};
-
-Scope.prototype.fireWatchers = function() {
- var self = this;
- var fired = false;
- foreach(this.watchListeners, function(watcher) {
- var value = self.eval(watcher.expression);
- if (value !== watcher.lastValue) {
- foreach(watcher.listeners, function(listener){
- listener(value, watcher.lastValue);
- fired = true;
- });
- watcher.lastValue = value;
+ var self = {scope:this};
+ return expression(self)(self, value);
+ },
+
+ entity: function(entityDeclaration) {
+ var expression = new Parser(entityDeclaration).entityDeclaration();
+ return expression({scope:this});
+ },
+
+ markInvalid: function(widget) {
+ this.state.$invalidWidgets.push(widget);
+ },
+
+ watch: function(declaration) {
+ var self = this;
+ new Parser(declaration).watch()({
+ scope:this,
+ addListener:function(watch, exp){
+ self.addWatchListener(watch, function(n,o){
+ try {
+ return exp({scope:self}, n, o);
+ } catch(e) {
+ alert(e);
+ }
+ });
+ }
+ });
+ },
+
+ addWatchListener: function(watchExpression, listener) {
+ var watcher = this.watchListeners[watchExpression];
+ if (!watcher) {
+ watcher = {listeners:[], expression:watchExpression};
+ this.watchListeners[watchExpression] = watcher;
}
- });
- return fired;
-};
+ watcher.listeners.push(listener);
+ },
+
+ fireWatchers: function() {
+ var self = this;
+ var fired = false;
+ foreach(this.watchListeners, function(watcher) {
+ var value = self.eval(watcher.expression);
+ if (value !== watcher.lastValue) {
+ foreach(watcher.listeners, function(listener){
+ listener(value, watcher.lastValue);
+ fired = true;
+ });
+ watcher.lastValue = value;
+ }
+ });
+ return fired;
+ }
+}; \ No newline at end of file
diff --git a/src/Server.js b/src/Server.js
index 8f682038..f351e84c 100644
--- a/src/Server.js
+++ b/src/Server.js
@@ -1,6 +1,4 @@
-// Copyright (C) 2008,2009 BRAT Tech LLC
-
-Server = function(url, getScript) {
+function Server(url, getScript) {
this.url = url;
this.nextId = 0;
this.getScript = getScript;
@@ -8,27 +6,29 @@ Server = function(url, getScript) {
this.maxSize = 1800;
};
-Server.prototype.base64url = function(txt) {
- return Base64.encode(txt);
-};
-
-Server.prototype.request = function(method, url, request, callback) {
- var requestId = this.uuid + (this.nextId++);
- angularCallbacks[requestId] = function(response) {
- delete angular[requestId];
- callback(200, response);
- };
- var payload = {u:url, m:method, p:request};
- payload = this.base64url(toJson(payload));
- var totalPockets = Math.ceil(payload.length / this.maxSize);
- var baseUrl = this.url + "/$/" + requestId + "/" + totalPockets + "/";
- for ( var pocketNo = 0; pocketNo < totalPockets; pocketNo++) {
- var pocket = payload.substr(pocketNo * this.maxSize, this.maxSize);
- this.getScript(baseUrl + (pocketNo+1) + "?h=" + pocket, noop);
+Server.prototype = {
+ base64url: function(txt) {
+ return Base64.encode(txt);
+ },
+
+ request: function(method, url, request, callback) {
+ var requestId = this.uuid + (this.nextId++);
+ angularCallbacks[requestId] = function(response) {
+ delete angular[requestId];
+ callback(200, response);
+ };
+ var payload = {u:url, m:method, p:request};
+ payload = this.base64url(toJson(payload));
+ var totalPockets = Math.ceil(payload.length / this.maxSize);
+ var baseUrl = this.url + "/$/" + requestId + "/" + totalPockets + "/";
+ for ( var pocketNo = 0; pocketNo < totalPockets; pocketNo++) {
+ var pocket = payload.substr(pocketNo * this.maxSize, this.maxSize);
+ this.getScript(baseUrl + (pocketNo+1) + "?h=" + pocket, noop);
+ }
}
};
-FrameServer = function(frame) {
+function FrameServer(frame) {
this.frame = frame;
};
FrameServer.PREFIX = "$DATASET:";
@@ -46,7 +46,7 @@ FrameServer.prototype = {
};
-VisualServer = function(delegate, status, update) {
+function VisualServer(delegate, status, update) {
this.delegate = delegate;
this.update = update;
this.status = status;
diff --git a/src/Users.js b/src/Users.js
index d10b96df..47da4f73 100644
--- a/src/Users.js
+++ b/src/Users.js
@@ -1,11 +1,10 @@
-// Copyright (C) 2008,2009 BRAT Tech LLC
-Users = function(server, controlBar) {
+function Users(server, controlBar) {
this.server = server;
this.controlBar = controlBar;
};
Users.prototype = {
- fetchCurrentUser:function(callback) {
+ 'fetchCurrentUser':function(callback) {
var self = this;
this.server.request("GET", "/account.json", {}, function(code, response){
self.current = response.user;
@@ -13,7 +12,7 @@ Users.prototype = {
});
},
- logout: function(callback) {
+ 'logout': function(callback) {
var self = this;
this.controlBar.logout(function(){
delete self.current;
@@ -21,7 +20,7 @@ Users.prototype = {
});
},
- login: function(callback) {
+ 'login': function(callback) {
var self = this;
this.controlBar.login(function(){
self.fetchCurrentUser(function(){
@@ -30,7 +29,7 @@ Users.prototype = {
});
},
- notAuthorized: function(){
+ 'notAuthorized': function(){
this.controlBar.notAuthorized();
}
};
diff --git a/src/Validators.js b/src/Validators.js
index eb8cff59..5549ee39 100644
--- a/src/Validators.js
+++ b/src/Validators.js
@@ -1,5 +1,3 @@
-// Copyright (C) 2009 BRAT Tech LLC
-
foreach({
'regexp': function(value, regexp, msg) {
if (!value.match(regexp)) {
diff --git a/src/Widgets.js b/src/Widgets.js
index 5dcb84c4..f93f2476 100644
--- a/src/Widgets.js
+++ b/src/Widgets.js
@@ -1,7 +1,4 @@
-// Copyright (C) 2009 BRAT Tech LLC
-
-
-WidgetFactory = function(serverUrl, database) {
+function WidgetFactory(serverUrl, database) {
this.nextUploadId = 0;
this.serverUrl = serverUrl;
this.database = database;
@@ -15,80 +12,81 @@ WidgetFactory = function(serverUrl, database) {
this.onChangeListener = function(){};
};
-WidgetFactory.prototype.createController = function(input, scope) {
- var controller;
- var type = input.attr('type').toLowerCase();
- var exp = input.attr('name');
- if (exp) exp = exp.split(':').pop();
- var event = "change";
- var bubbleEvent = true;
- if (type == 'button' || type == 'submit' || type == 'reset' || type == 'image') {
- controller = new ButtonController(input[0], exp);
- event = "click";
- bubbleEvent = false;
- } else if (type == 'text' || type == 'textarea' || type == 'hidden' || type == 'password') {
- controller = new TextController(input[0], exp);
- event = "keyup change";
- } else if (type == 'checkbox') {
- controller = new CheckboxController(input[0], exp);
- event = "click";
- } else if (type == 'radio') {
- controller = new RadioController(input[0], exp);
- event="click";
- } else if (type == 'select-one') {
- controller = new SelectController(input[0], exp);
- } else if (type == 'select-multiple') {
- controller = new MultiSelectController(input[0], exp);
- } else if (type == 'file') {
- controller = this.createFileController(input, exp);
- } else {
- throw 'Unknown type: ' + type;
- }
- input.data('controller', controller);
- var binder = scope.get('$binder');
- var action = function() {
- if (controller.updateModel(scope)) {
- var action = jQuery(controller.view).attr('ng-action') || "";
- if (scope.evalWidget(controller, action)) {
- binder.updateView(scope);
- }
+WidgetFactory.prototype = {
+ createController: function(input, scope) {
+ var controller;
+ var type = input.attr('type').toLowerCase();
+ var exp = input.attr('name');
+ if (exp) exp = exp.split(':').pop();
+ var event = "change";
+ var bubbleEvent = true;
+ if (type == 'button' || type == 'submit' || type == 'reset' || type == 'image') {
+ controller = new ButtonController(input[0], exp);
+ event = "click";
+ bubbleEvent = false;
+ } else if (type == 'text' || type == 'textarea' || type == 'hidden' || type == 'password') {
+ controller = new TextController(input[0], exp);
+ event = "keyup change";
+ } else if (type == 'checkbox') {
+ controller = new CheckboxController(input[0], exp);
+ event = "click";
+ } else if (type == 'radio') {
+ controller = new RadioController(input[0], exp);
+ event="click";
+ } else if (type == 'select-one') {
+ controller = new SelectController(input[0], exp);
+ } else if (type == 'select-multiple') {
+ controller = new MultiSelectController(input[0], exp);
+ } else if (type == 'file') {
+ controller = this.createFileController(input, exp);
+ } else {
+ throw 'Unknown type: ' + type;
}
- return bubbleEvent;
- };
- jQuery(controller.view, ":input").
- bind(event, action);
- return controller;
-};
-
-WidgetFactory.prototype.createFileController = function(fileInput) {
- var uploadId = '__uploadWidget_' + (this.nextUploadId++);
- var view = FileController.template(uploadId);
- fileInput.after(view);
- var att = {
- data:this.serverUrl + "/admin/ServerAPI.swf",
- width:"95", height:"20", align:"top",
- wmode:"transparent"};
- var par = {
- flashvars:"uploadWidgetId=" + uploadId,
- allowScriptAccess:"always"};
- var swfNode = this.createSWF(att, par, uploadId);
- fileInput.remove();
- var cntl = new FileController(view, fileInput[0].name, swfNode, this.serverUrl + "/data/" + this.database);
- jQuery(swfNode).data('controller', cntl);
- return cntl;
-};
-
-WidgetFactory.prototype.createTextWidget = function(textInput) {
- var controller = new TextController(textInput);
- controller.onChange(this.onChangeListener);
- return controller;
+ input.data('controller', controller);
+ var binder = scope.get('$binder');
+ var action = function() {
+ if (controller.updateModel(scope)) {
+ var action = jQuery(controller.view).attr('ng-action') || "";
+ if (scope.evalWidget(controller, action)) {
+ binder.updateView(scope);
+ }
+ }
+ return bubbleEvent;
+ };
+ jQuery(controller.view, ":input").
+ bind(event, action);
+ return controller;
+ },
+
+ createFileController: function(fileInput) {
+ var uploadId = '__uploadWidget_' + (this.nextUploadId++);
+ var view = FileController.template(uploadId);
+ fileInput.after(view);
+ var att = {
+ data:this.serverUrl + "/admin/ServerAPI.swf",
+ width:"95", height:"20", align:"top",
+ wmode:"transparent"};
+ var par = {
+ flashvars:"uploadWidgetId=" + uploadId,
+ allowScriptAccess:"always"};
+ var swfNode = this.createSWF(att, par, uploadId);
+ fileInput.remove();
+ var cntl = new FileController(view, fileInput[0].name, swfNode, this.serverUrl + "/data/" + this.database);
+ jQuery(swfNode).data('controller', cntl);
+ return cntl;
+ },
+
+ createTextWidget: function(textInput) {
+ var controller = new TextController(textInput);
+ controller.onChange(this.onChangeListener);
+ return controller;
+ }
};
-
/////////////////////
// FileController
///////////////////////
-FileController = function(view, scopeName, uploader, databaseUrl) {
+function FileController(view, scopeName, uploader, databaseUrl) {
this.view = view;
this.uploader = uploader;
this.scopeName = scopeName;
@@ -112,99 +110,89 @@ FileController.template = function(id) {
'</span>');
};
-FileController.prototype._on_cancel = function() {
-};
-
-FileController.prototype._on_complete = function() {
-};
-
-FileController.prototype._on_httpStatus = function(status) {
- alert("httpStatus:" + this.scopeName + " status:" + status);
-};
-
-FileController.prototype._on_ioError = function() {
- alert("ioError:" + this.scopeName);
-};
-
-FileController.prototype._on_open = function() {
- alert("open:" + this.scopeName);
-};
-
-FileController.prototype._on_progress = function(bytesLoaded, bytesTotal) {
-};
-
-FileController.prototype._on_securityError = function() {
- alert("securityError:" + this.scopeName);
-};
-
-FileController.prototype._on_uploadCompleteData = function(data) {
- var value = fromJson(data);
- value.url = this.attachmentsPath + '/' + value.id + '/' + value.text;
- this.view.find("input").attr('checked', true);
- var scope = this.view.scope();
- this.value = value;
- this.updateModel(scope);
- this.value = null;
- scope.get('$binder').updateView();
-};
-
-FileController.prototype._on_select = function(name, size, type) {
- this.name = name;
- this.view.find("a").text(name).attr('href', name);
- this.view.find("span").text(angular['filter']['bytes'](size));
- this.upload();
-};
-
-FileController.prototype.updateModel = function(scope) {
- var isChecked = this.view.find("input").attr('checked');
- var value = isChecked ? this.value : null;
- if (this.lastValue === value) {
- return false;
- } else {
- scope.set(this.scopeName, value);
- return true;
- }
-};
-
-FileController.prototype.updateView = function(scope) {
- var modelValue = scope.get(this.scopeName);
- if (modelValue && this.value !== modelValue) {
- this.value = modelValue;
- this.view.find("a").
- attr("href", this.value.url).
- text(this.value.text);
- this.view.find("span").text(angular['filter']['bytes'](this.value.size));
- }
- this.view.find("input").attr('checked', !!modelValue);
-};
-
-FileController.prototype.upload = function() {
- if (this.name) {
- this.uploader.uploadFile(this.attachmentsPath);
+FileController.prototype = {
+ '_on_cancel': noop,
+ '_on_complete': noop,
+ '_on_httpStatus': function(status) {
+ alert("httpStatus:" + this.scopeName + " status:" + status);
+ },
+ '_on_ioError': function() {
+ alert("ioError:" + this.scopeName);
+ },
+ '_on_open': function() {
+ alert("open:" + this.scopeName);
+ },
+ '_on_progress':noop,
+ '_on_securityError': function() {
+ alert("securityError:" + this.scopeName);
+ },
+ '_on_uploadCompleteData': function(data) {
+ var value = fromJson(data);
+ value.url = this.attachmentsPath + '/' + value.id + '/' + value.text;
+ this.view.find("input").attr('checked', true);
+ var scope = this.view.scope();
+ this.value = value;
+ this.updateModel(scope);
+ this.value = null;
+ scope.get('$binder').updateView();
+ },
+ '_on_select': function(name, size, type) {
+ this.name = name;
+ this.view.find("a").text(name).attr('href', name);
+ this.view.find("span").text(angular['filter']['bytes'](size));
+ this.upload();
+ },
+
+ updateModel: function(scope) {
+ var isChecked = this.view.find("input").attr('checked');
+ var value = isChecked ? this.value : null;
+ if (this.lastValue === value) {
+ return false;
+ } else {
+ scope.set(this.scopeName, value);
+ return true;
+ }
+ },
+
+ updateView: function(scope) {
+ var modelValue = scope.get(this.scopeName);
+ if (modelValue && this.value !== modelValue) {
+ this.value = modelValue;
+ this.view.find("a").
+ attr("href", this.value.url).
+ text(this.value.text);
+ this.view.find("span").text(angular['filter']['bytes'](this.value.size));
+ }
+ this.view.find("input").attr('checked', !!modelValue);
+ },
+
+ upload: function() {
+ if (this.name) {
+ this.uploader.uploadFile(this.attachmentsPath);
+ }
}
};
-
///////////////////////
// NullController
///////////////////////
-NullController = function(view) {this.view = view;};
-NullController.prototype.updateModel = function() { return true; };
-NullController.prototype.updateView = function() { };
+function NullController(view) {this.view = view;};
+NullController.prototype = {
+ updateModel: function() { return true; },
+ updateView: noop
+};
NullController.instance = new NullController();
///////////////////////
// ButtonController
///////////////////////
-ButtonController = function(view) {this.view = view;};
-ButtonController.prototype.updateModel = function(scope) { return true; };
-ButtonController.prototype.updateView = function(scope) {};
+var ButtonController = NullController;
///////////////////////
// TextController
///////////////////////
-TextController = function(view, exp) {
+function TextController(view, exp) {
this.view = view;
this.exp = exp;
this.validator = view.getAttribute('ng-validate');
@@ -218,175 +206,183 @@ TextController = function(view, exp) {
}
};
-TextController.prototype.updateModel = function(scope) {
- var value = this.view.value;
- if (this.lastValue === value) {
- return false;
- } else {
- scope.setEval(this.exp, value);
- this.lastValue = value;
- return true;
- }
-};
-
-TextController.prototype.updateView = function(scope) {
- var view = this.view;
- var value = scope.get(this.exp);
- if (typeof value === "undefined") {
- value = this.initialValue;
- scope.setEval(this.exp, value);
- }
- value = value ? value : '';
- if (this.lastValue != value) {
- view.value = value;
- this.lastValue = value;
- }
- var isValidationError = false;
- view.removeAttribute('ng-error');
- if (this.required) {
- isValidationError = !(value && value.length > 0);
- }
- var errorText = isValidationError ? "Required Value" : null;
- if (!isValidationError && this.validator && value) {
- errorText = scope.validate(this.validator, value);
- isValidationError = !!errorText;
- }
- if (this.lastErrorText !== errorText) {
- this.lastErrorText = isValidationError;
- if (errorText !== null) {
- view.setAttribute('ng-error', errorText);
- scope.markInvalid(this);
+TextController.prototype = {
+ updateModel: function(scope) {
+ var value = this.view.value;
+ if (this.lastValue === value) {
+ return false;
+ } else {
+ scope.setEval(this.exp, value);
+ this.lastValue = value;
+ return true;
+ }
+ },
+
+ updateView: function(scope) {
+ var view = this.view;
+ var value = scope.get(this.exp);
+ if (typeof value === "undefined") {
+ value = this.initialValue;
+ scope.setEval(this.exp, value);
+ }
+ value = value ? value : '';
+ if (this.lastValue != value) {
+ view.value = value;
+ this.lastValue = value;
+ }
+ var isValidationError = false;
+ view.removeAttribute('ng-error');
+ if (this.required) {
+ isValidationError = !(value && value.length > 0);
+ }
+ var errorText = isValidationError ? "Required Value" : null;
+ if (!isValidationError && this.validator && value) {
+ errorText = scope.validate(this.validator, value);
+ isValidationError = !!errorText;
+ }
+ if (this.lastErrorText !== errorText) {
+ this.lastErrorText = isValidationError;
+ if (errorText !== null) {
+ view.setAttribute('ng-error', errorText);
+ scope.markInvalid(this);
+ }
+ jQuery(view).toggleClass('ng-validation-error', isValidationError);
}
- jQuery(view).toggleClass('ng-validation-error', isValidationError);
}
};
///////////////////////
// CheckboxController
///////////////////////
-CheckboxController = function(view, exp) {
+function CheckboxController(view, exp) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.initialValue = view.checked ? view.value : "";
};
-CheckboxController.prototype.updateModel = function(scope) {
- var input = this.view;
- var value = input.checked ? input.value : '';
- if (this.lastValue === value) {
- return false;
- } else {
- scope.setEval(this.exp, value);
- this.lastValue = value;
- return true;
- }
-};
-
-CheckboxController.prototype.updateView = function(scope) {
- var input = this.view;
- var value = scope.eval(this.exp);
- if (typeof value === "undefined") {
- value = this.initialValue;
- scope.setEval(this.exp, value);
+CheckboxController.prototype = {
+ updateModel: function(scope) {
+ var input = this.view;
+ var value = input.checked ? input.value : '';
+ if (this.lastValue === value) {
+ return false;
+ } else {
+ scope.setEval(this.exp, value);
+ this.lastValue = value;
+ return true;
+ }
+ },
+
+ updateView: function(scope) {
+ var input = this.view;
+ var value = scope.eval(this.exp);
+ if (typeof value === "undefined") {
+ value = this.initialValue;
+ scope.setEval(this.exp, value);
+ }
+ input.checked = input.value == (''+value);
}
- input.checked = input.value == (''+value);
};
///////////////////////
// SelectController
///////////////////////
-SelectController = function(view, exp) {
+function SelectController(view, exp) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.initialValue = view.value;
};
-SelectController.prototype.updateModel = function(scope) {
- var input = this.view;
- if (input.selectedIndex < 0) {
- scope.setEval(this.exp, null);
- } else {
- var value = this.view.value;
- if (this.lastValue === value) {
- return false;
+SelectController.prototype = {
+ updateModel: function(scope) {
+ var input = this.view;
+ if (input.selectedIndex < 0) {
+ scope.setEval(this.exp, null);
} else {
+ var value = this.view.value;
+ if (this.lastValue === value) {
+ return false;
+ } else {
+ scope.setEval(this.exp, value);
+ this.lastValue = value;
+ return true;
+ }
+ }
+ },
+
+ updateView: function(scope) {
+ var input = this.view;
+ var value = scope.get(this.exp);
+ if (typeof value === 'undefined') {
+ value = this.initialValue;
scope.setEval(this.exp, value);
+ }
+ if (value !== this.lastValue) {
+ input.value = value ? value : "";
this.lastValue = value;
- return true;
}
}
};
-SelectController.prototype.updateView = function(scope) {
- var input = this.view;
- var value = scope.get(this.exp);
- if (typeof value === 'undefined') {
- value = this.initialValue;
- scope.setEval(this.exp, value);
- }
- if (value !== this.lastValue) {
- input.value = value ? value : "";
- this.lastValue = value;
- }
-};
-
///////////////////////
// MultiSelectController
///////////////////////
-MultiSelectController = function(view, exp) {
+function MultiSelectController(view, exp) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.initialValue = this.selected();
};
-MultiSelectController.prototype.selected = function () {
- var value = [];
- var options = this.view.options;
- for ( var i = 0; i < options.length; i++) {
- var option = options[i];
- if (option.selected) {
- value.push(option.value);
- }
- }
- return value;
-};
-
-MultiSelectController.prototype.updateModel = function(scope) {
- var value = this.selected();
- // TODO: This is wrong! no caching going on here as we are always comparing arrays
- if (this.lastValue === value) {
- return false;
- } else {
- scope.setEval(this.exp, value);
- this.lastValue = value;
- return true;
- }
-};
-
-MultiSelectController.prototype.updateView = function(scope) {
- var input = this.view;
- var selected = scope.get(this.exp);
- if (typeof selected === "undefined") {
- selected = this.initialValue;
- scope.setEval(this.exp, selected);
- }
- if (selected !== this.lastValue) {
- var options = input.options;
+MultiSelectController.prototype = {
+ selected: function () {
+ var value = [];
+ var options = this.view.options;
for ( var i = 0; i < options.length; i++) {
var option = options[i];
- option.selected = _.include(selected, option.value);
+ if (option.selected) {
+ value.push(option.value);
+ }
+ }
+ return value;
+ },
+
+ updateModel: function(scope) {
+ var value = this.selected();
+ // TODO: This is wrong! no caching going on here as we are always comparing arrays
+ if (this.lastValue === value) {
+ return false;
+ } else {
+ scope.setEval(this.exp, value);
+ this.lastValue = value;
+ return true;
+ }
+ },
+
+ updateView: function(scope) {
+ var input = this.view;
+ var selected = scope.get(this.exp);
+ if (typeof selected === "undefined") {
+ selected = this.initialValue;
+ scope.setEval(this.exp, selected);
+ }
+ if (selected !== this.lastValue) {
+ var options = input.options;
+ for ( var i = 0; i < options.length; i++) {
+ var option = options[i];
+ option.selected = _.include(selected, option.value);
+ }
+ this.lastValue = selected;
}
- this.lastValue = selected;
}
};
///////////////////////
// RadioController
///////////////////////
-RadioController = function(view, exp) {
+function RadioController(view, exp) {
this.view = view;
this.exp = exp;
this.lastChecked = undefined;
@@ -395,35 +391,37 @@ RadioController = function(view, exp) {
this.initialValue = view.checked ? view.value : null;
};
-RadioController.prototype.updateModel = function(scope) {
- var input = this.view;
- if (this.lastChecked) {
- return false;
- } else {
- input.checked = true;
- this.lastValue = scope.setEval(this.exp, this.inputValue);
- this.lastChecked = true;
- return true;
- }
-};
-
-RadioController.prototype.updateView = function(scope) {
- var input = this.view;
- var value = scope.get(this.exp);
- if (this.initialValue && typeof value === "undefined") {
- value = this.initialValue;
- scope.setEval(this.exp, value);
- }
- if (this.lastValue != value) {
- this.lastChecked = input.checked = this.inputValue == (''+value);
- this.lastValue = value;
+RadioController.prototype = {
+ updateModel: function(scope) {
+ var input = this.view;
+ if (this.lastChecked) {
+ return false;
+ } else {
+ input.checked = true;
+ this.lastValue = scope.setEval(this.exp, this.inputValue);
+ this.lastChecked = true;
+ return true;
+ }
+ },
+
+ updateView: function(scope) {
+ var input = this.view;
+ var value = scope.get(this.exp);
+ if (this.initialValue && typeof value === "undefined") {
+ value = this.initialValue;
+ scope.setEval(this.exp, value);
+ }
+ if (this.lastValue != value) {
+ this.lastChecked = input.checked = this.inputValue == (''+value);
+ this.lastValue = value;
+ }
}
};
///////////////////////
//ElementController
///////////////////////
-BindUpdater = function(view, exp) {
+function BindUpdater(view, exp) {
this.view = view;
this.exp = Binder.parseBindings(exp);
this.hasError = false;
@@ -473,152 +471,170 @@ BindUpdater.toText = function(obj) {
}
};
-BindUpdater.prototype.updateModel = function(scope) {};
-BindUpdater.prototype.updateView = function(scope) {
- var html = [];
- var parts = this.exp;
- var length = parts.length;
- for(var i=0; i<length; i++) {
- var part = parts[i];
- var binding = Binder.binding(part);
- if (binding) {
- scope.evalWidget(this, binding, this.scopeSelf, function(value){
- html.push(BindUpdater.toText(value));
- }, function(e, text){
- setHtml(this.view, text);
- });
- if (this.hasError) {
- return;
+BindUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ var html = [];
+ var parts = this.exp;
+ var length = parts.length;
+ for(var i=0; i<length; i++) {
+ var part = parts[i];
+ var binding = Binder.binding(part);
+ if (binding) {
+ scope.evalWidget(this, binding, this.scopeSelf, function(value){
+ html.push(BindUpdater.toText(value));
+ }, function(e, text){
+ setHtml(this.view, text);
+ });
+ if (this.hasError) {
+ return;
+ }
+ } else {
+ html.push(escapeHtml(part));
}
- } else {
- html.push(escapeHtml(part));
}
+ setHtml(this.view, html.join(''));
}
- setHtml(this.view, html.join(''));
};
-BindAttrUpdater = function(view, attrs) {
+function BindAttrUpdater(view, attrs) {
this.view = view;
this.attrs = attrs;
};
-BindAttrUpdater.prototype.updateModel = function(scope) {};
-BindAttrUpdater.prototype.updateView = function(scope) {
- var jNode = jQuery(this.view);
- var attributeTemplates = this.attrs;
- if (this.hasError) {
- this.hasError = false;
- jNode.
- removeClass('ng-exception').
- removeAttr('ng-error');
- }
- var isImage = jNode.is('img');
- for (var attrName in attributeTemplates) {
- var attributeTemplate = Binder.parseBindings(attributeTemplates[attrName]);
- var attrValues = [];
- for ( var i = 0; i < attributeTemplate.length; i++) {
- var binding = Binder.binding(attributeTemplate[i]);
- if (binding) {
- try {
- var value = scope.eval(binding, {element:jNode[0], attrName:attrName});
- if (value && (value.constructor !== array || value.length !== 0))
- attrValues.push(value);
- } catch (e) {
- this.hasError = true;
- error('BindAttrUpdater', e);
- var jsonError = toJson(e, true);
- attrValues.push('[' + jsonError + ']');
- jNode.
- addClass('ng-exception').
- attr('ng-error', jsonError);
+BindAttrUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ var jNode = jQuery(this.view);
+ var attributeTemplates = this.attrs;
+ if (this.hasError) {
+ this.hasError = false;
+ jNode.
+ removeClass('ng-exception').
+ removeAttr('ng-error');
+ }
+ var isImage = jNode.is('img');
+ for (var attrName in attributeTemplates) {
+ var attributeTemplate = Binder.parseBindings(attributeTemplates[attrName]);
+ var attrValues = [];
+ for ( var i = 0; i < attributeTemplate.length; i++) {
+ var binding = Binder.binding(attributeTemplate[i]);
+ if (binding) {
+ try {
+ var value = scope.eval(binding, {element:jNode[0], attrName:attrName});
+ if (value && (value.constructor !== array || value.length !== 0))
+ attrValues.push(value);
+ } catch (e) {
+ this.hasError = true;
+ error('BindAttrUpdater', e);
+ var jsonError = toJson(e, true);
+ attrValues.push('[' + jsonError + ']');
+ jNode.
+ addClass('ng-exception').
+ attr('ng-error', jsonError);
+ }
+ } else {
+ attrValues.push(attributeTemplate[i]);
}
- } else {
- attrValues.push(attributeTemplate[i]);
}
- }
- var attrValue = attrValues.length ? attrValues.join('') : null;
- if(isImage && attrName == 'src' && !attrValue)
- attrValue = scope.get('config.server') + '/images/blank.gif';
- jNode.attr(attrName, attrValue);
+ var attrValue = attrValues.length ? attrValues.join('') : null;
+ if(isImage && attrName == 'src' && !attrValue)
+ attrValue = scope.get('config.server') + '/images/blank.gif';
+ jNode.attr(attrName, attrValue);
+ }
}
};
-EvalUpdater = function(view, exp) {
+function EvalUpdater(view, exp) {
this.view = view;
this.exp = exp;
this.hasError = false;
};
-EvalUpdater.prototype.updateModel = function(scope) {};
-EvalUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp);
+EvalUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp);
+ }
};
-HideUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-HideUpdater.prototype.updateModel = function(scope) {};
-HideUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(hideValue){
- var view = jQuery(this.view);
- if (toBoolean(hideValue)) {
- view.hide();
- } else {
- view.show();
- }
- });
+function HideUpdater(view, exp) { this.view = view; this.exp = exp; };
+HideUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(hideValue){
+ var view = jQuery(this.view);
+ if (toBoolean(hideValue)) {
+ view.hide();
+ } else {
+ view.show();
+ }
+ });
+ }
};
-ShowUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-ShowUpdater.prototype.updateModel = function(scope) {};
-ShowUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(hideValue){
- var view = jQuery(this.view);
- if (toBoolean(hideValue)) {
- view.show();
- } else {
- view.hide();
- }
- });
+function ShowUpdater(view, exp) { this.view = view; this.exp = exp; };
+ShowUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(hideValue){
+ var view = jQuery(this.view);
+ if (toBoolean(hideValue)) {
+ view.show();
+ } else {
+ view.hide();
+ }
+ });
+ }
};
-ClassUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-ClassUpdater.prototype.updateModel = function(scope) {};
-ClassUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(classValue){
- if (classValue !== null && classValue !== undefined) {
- this.view.className = classValue;
- }
- });
+function ClassUpdater(view, exp) { this.view = view; this.exp = exp; };
+ClassUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(classValue){
+ if (classValue !== null && classValue !== undefined) {
+ this.view.className = classValue;
+ }
+ });
+ }
};
-ClassEvenUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-ClassEvenUpdater.prototype.updateModel = function(scope) {};
-ClassEvenUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(classValue){
- var index = scope.get('$index');
- jQuery(this.view).toggleClass(classValue, index % 2 === 1);
- });
+function ClassEvenUpdater(view, exp) { this.view = view; this.exp = exp; };
+ClassEvenUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(classValue){
+ var index = scope.get('$index');
+ jQuery(this.view).toggleClass(classValue, index % 2 === 1);
+ });
+ }
};
-ClassOddUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-ClassOddUpdater.prototype.updateModel = function(scope) {};
-ClassOddUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(classValue){
- var index = scope.get('$index');
- jQuery(this.view).toggleClass(classValue, index % 2 === 0);
- });
+function ClassOddUpdater(view, exp) { this.view = view; this.exp = exp; };
+ClassOddUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(classValue){
+ var index = scope.get('$index');
+ jQuery(this.view).toggleClass(classValue, index % 2 === 0);
+ });
+ }
};
-StyleUpdater = function(view, exp) { this.view = view; this.exp = exp; };
-StyleUpdater.prototype.updateModel = function(scope) {};
-StyleUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.exp, {}, function(styleValue){
- jQuery(this.view).attr('style', "").css(styleValue);
- });
+function StyleUpdater(view, exp) { this.view = view; this.exp = exp; };
+StyleUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.exp, {}, function(styleValue){
+ jQuery(this.view).attr('style', "").css(styleValue);
+ });
+ }
};
///////////////////////
// RepeaterUpdater
///////////////////////
-RepeaterUpdater = function(view, repeaterExpression, template, prefix) {
+function RepeaterUpdater(view, repeaterExpression, template, prefix) {
this.view = view;
this.template = template;
this.prefix = prefix;
@@ -639,81 +655,77 @@ RepeaterUpdater = function(view, repeaterExpression, template, prefix) {
this.keyExp = match[2];
};
-RepeaterUpdater.prototype.updateModel = function(scope) {};
-RepeaterUpdater.prototype.updateView = function(scope) {
- scope.evalWidget(this, this.iteratorExp, {}, function(iterator){
- var self = this;
- if (!iterator) {
- iterator = [];
- if (scope.isProperty(this.iteratorExp)) {
- scope.set(this.iteratorExp, iterator);
+RepeaterUpdater.prototype = {
+ updateModel: noop,
+ updateView: function(scope) {
+ scope.evalWidget(this, this.iteratorExp, {}, function(iterator){
+ var self = this;
+ if (!iterator) {
+ iterator = [];
+ if (scope.isProperty(this.iteratorExp)) {
+ scope.set(this.iteratorExp, iterator);
+ }
}
- }
- var iteratorLength = iterator.length;
- var childrenLength = this.children.length;
- var cursor = this.view;
- var time = 0;
- var child = null;
- var keyExp = this.keyExp;
- var valueExp = this.valueExp;
- var i = 0;
- foreach(iterator, function(value, key){
- if (i < childrenLength) {
- // reuse children
- child = self.children[i];
- child.scope.set(valueExp, value);
- } else {
- // grow children
- var name = self.prefix +
- valueExp + " in " + self.iteratorExp + "[" + i + "]";
- var childScope = new Scope(scope.state, name);
- childScope.set('$index', i);
- if (keyExp)
- childScope.set(keyExp, key);
- childScope.set(valueExp, value);
- child = { scope:childScope, element:self.template(childScope, self.prefix, i) };
- cursor.after(child.element);
- self.children.push(child);
+ var iteratorLength = iterator.length;
+ var childrenLength = this.children.length;
+ var cursor = this.view;
+ var time = 0;
+ var child = null;
+ var keyExp = this.keyExp;
+ var valueExp = this.valueExp;
+ var i = 0;
+ foreach(iterator, function(value, key){
+ if (i < childrenLength) {
+ // reuse children
+ child = self.children[i];
+ child.scope.set(valueExp, value);
+ } else {
+ // grow children
+ var name = self.prefix +
+ valueExp + " in " + self.iteratorExp + "[" + i + "]";
+ var childScope = new Scope(scope.state, name);
+ childScope.set('$index', i);
+ if (keyExp)
+ childScope.set(keyExp, key);
+ childScope.set(valueExp, value);
+ child = { scope:childScope, element:self.template(childScope, self.prefix, i) };
+ cursor.after(child.element);
+ self.children.push(child);
+ }
+ cursor = child.element;
+ var s = new Date().getTime();
+ child.scope.updateView();
+ time += new Date().getTime() - s;
+ i++;
+ });
+ // shrink children
+ for ( var r = childrenLength; r > iteratorLength; --r) {
+ var unneeded = this.children.pop().element[0];
+ unneeded.parentNode.removeChild(unneeded);
}
- cursor = child.element;
- var s = new Date().getTime();
- child.scope.updateView();
- time += new Date().getTime() - s;
- i++;
- });
- // shrink children
- for ( var r = childrenLength; r > iteratorLength; --r) {
- var unneeded = this.children.pop().element[0];
- unneeded.parentNode.removeChild(unneeded);
- }
- // Special case for option in select
- if (child && child.element[0].nodeName === "OPTION") {
- var select = jQuery(child.element[0].parentNode);
- var cntl = select.data('controller');
- if (cntl) {
- cntl.lastValue = undefined;
- cntl.updateView(scope);
+ // Special case for option in select
+ if (child && child.element[0].nodeName === "OPTION") {
+ var select = jQuery(child.element[0].parentNode);
+ var cntl = select.data('controller');
+ if (cntl) {
+ cntl.lastValue = undefined;
+ cntl.updateView(scope);
+ }
}
- }
- });
+ });
+ }
};
//////////////////////////////////
// PopUp
//////////////////////////////////
-PopUp = function(doc) {
+function PopUp(doc) {
this.doc = doc;
};
PopUp.OUT_EVENT = "mouseleave mouseout click dblclick keypress keyup";
-PopUp.prototype.bind = function () {
- var self = this;
- this.doc.find('.ng-validation-error,.ng-exception').
- live("mouseover", PopUp.onOver);
-};
-
PopUp.onOver = function(e) {
PopUp.onOut();
var jNode = jQuery(this);
@@ -753,28 +765,38 @@ PopUp.onOut = function() {
return true;
};
+PopUp.prototype = {
+ bind: function () {
+ var self = this;
+ this.doc.find('.ng-validation-error,.ng-exception').
+ live("mouseover", PopUp.onOver);
+ }
+};
+
//////////////////////////////////
// Status
//////////////////////////////////
-Status = function(body) {
+function Status(body) {
this.loader = body.append(Status.DOM).find("#ng-loading");
this.requestCount = 0;
};
Status.DOM ='<div id="ng-spacer"></div><div id="ng-loading">loading....</div>';
-Status.prototype.beginRequest = function () {
- if (this.requestCount === 0) {
- this.loader.show();
- }
- this.requestCount++;
-};
-
-Status.prototype.endRequest = function () {
- this.requestCount--;
- if (this.requestCount === 0) {
- this.loader.hide("fold");
+Status.prototype = {
+ beginRequest: function () {
+ if (this.requestCount === 0) {
+ this.loader.show();
+ }
+ this.requestCount++;
+ },
+
+ endRequest: function () {
+ this.requestCount--;
+ if (this.requestCount === 0) {
+ this.loader.hide("fold");
+ }
}
};
diff --git a/src/angular-bootstrap.js b/src/angular-bootstrap.js
index b13bbf34..50c78f81 100644
--- a/src/angular-bootstrap.js
+++ b/src/angular-bootstrap.js
@@ -1,5 +1,26 @@
-// Copyright (C) 2008,2009 BRAT Tech LLC
-
+/**
+ * The MIT License
+ *
+ * Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
(function(previousOnLoad){
var filename = /(.*)\/angular-(.*).js(#(.*))?/;
var scripts = document.getElementsByTagName("script");
diff --git a/src/angular.prefix b/src/angular.prefix
index dbd4959a..26a8429f 100644
--- a/src/angular.prefix
+++ b/src/angular.prefix
@@ -1 +1,24 @@
+/**
+ * The MIT License
+ *
+ * Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
(function(window, document){
diff --git a/test/DataStoreTest.js b/test/DataStoreTest.js
index 2dd4a582..87c5be2e 100644
--- a/test/DataStoreTest.js
+++ b/test/DataStoreTest.js
@@ -17,9 +17,8 @@ DataStoreTest.prototype.testSavePostsToServer = function(){
response.$version = "2";
callback(200, [response]);
};
- var model;
var datastore = new DataStore(post);
- model = datastore.entity('abc', {name: "value"})();
+ var model = datastore.entity('abc', {name: "value"})();
model.$id = "123";
model.$version = "1";