From 0e566fe6cb41de388df6793b350fb81aaa4a8476 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 18 Jan 2010 17:56:08 -0800 Subject: tweeter demo client --- .externalToolBuilders/JSTD_Tests.launch | 7 +- angular-minified.js | 193 ++++++++++++++++--------------- angular.js | 71 +++++++----- example/business_card.html | 50 -------- example/tweeter/style.css | 87 ++++++++++++++ example/tweeter/tweeter_addressbook.html | 64 ++++++++++ example/tweeter/tweeterclient.js | 35 ++++++ src/Angular.js | 30 ++--- src/Binder.js | 1 - src/Filters.js | 17 +++ test.sh | 3 +- test/FiltersTest.js | 9 ++ 12 files changed, 369 insertions(+), 198 deletions(-) delete mode 100644 example/business_card.html create mode 100644 example/tweeter/style.css create mode 100644 example/tweeter/tweeter_addressbook.html create mode 100644 example/tweeter/tweeterclient.js diff --git a/.externalToolBuilders/JSTD_Tests.launch b/.externalToolBuilders/JSTD_Tests.launch index 17fb5035..503cbaff 100644 --- a/.externalToolBuilders/JSTD_Tests.launch +++ b/.externalToolBuilders/JSTD_Tests.launch @@ -1,10 +1,9 @@ - + - - + + - diff --git a/angular-minified.js b/angular-minified.js index e49e0324..f590b704 100644 --- a/angular-minified.js +++ b/angular-minified.js @@ -1,98 +1,99 @@ -function J(){return function(){}}function K(p){return function(){return p}} -(function(p,y){function n(){}function v(a,b,c){var d=p.console;switch(arguments.length){case 1:d.log(a);break;case 2:d.log(a,b);break;default:d.log(a,b,c);break}}function W(a,b,c){var d=p.console;switch(arguments.length){case 1:d.error(a);break;case 2:d.error(a,b);break;default:d.error(a,b,c);break}}function da(a,b){var c=y.createElement("div");c.className=a;for(var d=a="",e=0;e/g,">")}function Ca(a){if(!a||!a.replace)return a;return a.replace(//g,">").replace(/\"/g,""")}function Da(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/g,">")}function Da(a){if(!a||!a.replace)return a;return a.replace(//g,">").replace(/\"/g,""")}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>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},qd:function(a){var b="",c,d,e,f,g,h=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");h>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.nb(b)},ob:function(a){a=a.replace(/\r\n/g,"\n"); -for(var b="",c=0;c127&&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},nb:function(a){for(var b="",c=0,d=c1=c2=0;c191&&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 y.getAttribute=="undefined")y.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};p.console||(p.console={log:n,error:n});var R,q=_.each,S=_.extend,k=p.jQuery,X=k.browser.msie,m=p.angular||(p.angular= -{}),Ba=m.validator||(m.validator={}),r=m.filter||(m.filter={}),ca=m.callbacks||(m.callbacks={});m.alert||(m.alert=function(){v(arguments);p.alert.apply(p,arguments)});ha.prototype={load:function(){this.Cb();v("Server: "+this.j.H);this.Bb();this.Ab();this.wb()},Bb:function(){v("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.Ub}},Ec:function(){return""+ -(new Date).getTime()},Ab:function(){var a=this.j;if(!a.F){var b=a.H.match(/https?:\/\/([\w]*)/);a.F=b?b[1]:"$MEMORY"}},wb:function(){function a(){g.Ob(function(l){!l&&c.find("[ng-auth=eager]").length&&g.ja()})}v("Loader.bindHtml()");var b=new ia(this.location),c=this.document,d=new ma(this.j.H,this.j.F),e=new x(c[0],d,b,this.j);d.qc=Ea(e,e.e);b=new P(c.find("body"),this.j.H);var f=this.j.F=="$MEMORY"?new aa(this.window):new ja(this.j.H,k.getScript);f=new ka(f,new U(k(c.body)),function(){e.c()});var g= -new la(f,b),h="/data/"+this.j.F,i=new T(function(l,o){f.N("POST",h,l,o)},g,e.anchor);e.Za.push(function(){i.Ea()});var j=new w({$anchor:e.anchor,$binder:e,$config:this.j,$console:p.console,$datastore:i,$save:function(l){i.zc(j.q,l,e.anchor)},$window:p,$uid:this.Ec,$users:g},"ROOT");c.data("scope",j);v("$binder.entity()");e.K(j);v("$binder.compile()");e.compile();v("ControlBar.bind()");b.bind();v("$users.fetchCurrentUser()");a();v("PopUp.bind()");(new B(c)).bind();v("$binder.parseAnchor()");e.sc(); -v("$binder.updateView()");e.c();c.find("body").show();v("ready()")},Cb:function(){var a=p.location.href+"#";a=a.split("#")[1];var b={Ib:null};a=a.split("&");for(var c=0;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.Tc.find(a,function(c){return c.z==b},null)},filter:function(a,b){var c=[];c.xb=function(j){for(var l=0;l-1;case "object":for(var o in j)if(o.charAt(0)!=="$"&&e(j[o],l))return true;return false;case "array":for(o=0;o=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}Z(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-1;){c1||x.J(a[0])!==null};x.J=function(a){return(a=a.replace(/\n/gm," ").match(/^\{\{(.*)\}\}$/))?a[1]:null};x.prototype={tc:function(a){var b={};a.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,function(c,d,e){if(d)b[decodeURIComponent(d)]=decodeURIComponent(e)});return b},sc:function(a){var b= -this;a=a||this.$a.Ga();var c=a.indexOf("#");if(!(c<0)){a=this.tc(a.substring(c+1));q(b.anchor,function(d,e){delete b.anchor[e]});q(a,function(d,e){b.anchor[e]=d})}},Fc:function(){var a=this.$a.Ga(),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="&"}}return a},c:function(){(new Date).getTime();var a=k(this.B).scope(); -a.i("$invalidWidgets",[]);a.c();(new Date).getTime();this.Fc();_.each(this.Za,function(b){b()})},ga:function(a){var b=k(this.B),c=b.find(a);if(b.is(a))c=c.andSelf();return c},K:function(a){this.ga("[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.B),b=this;if(this.j.Yc){var c=this.ga(":submit").not("[ng-action]");c.attr("ng-action","$save()");c.not(":disabled").not("ng-bind-attr").attr("ng-bind-attr", -'{disabled:"{{$invalidWidgets}}"}')}this.Sa(this.B)(this.B,a.scope(),"");this.ga("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",z(e,true))}b.c();return false})},Dc:function(a,b,c){b=b.concat();var d=b.pop(),e=x.Z(a.nodeValue);if(e.length>1||x.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;g2&&a.setAttribute("ng-bind-attr", -d)}a.getAttribute||v(a);var j=a.getAttribute("ng-repeat");if(j){a.removeAttribute("ng-repeat");var l=this.Sa(a);d=y.createComment("ng-repeat: "+j);e=a.parentNode;e.insertBefore(d,a);e.removeChild(a);function o(s,t,A){var I=k(a).clone();I.css("display","");I.attr("ng-repeat-index",""+A);I.data("scope",s);l(I[0],s,t+A+":");return I}c.push({path:b,b:function(s,t,A){return new Aa(k(s),j,o,A)}})}else{a.getAttribute("ng-eval")&&c.push({path:b,b:this.kc});a.getAttribute("ng-bind")&&c.push({path:b,b:this.Qa}); -a.getAttribute("ng-bind-attr")&&c.push({path:b,b:this.gc});a.getAttribute("ng-hide")&&c.push({path:b,b:this.lc});a.getAttribute("ng-show")&&c.push({path:b,b:this.mc});a.getAttribute("ng-class")&&c.push({path:b,b:this.hc});a.getAttribute("ng-class-odd")&&c.push({path:b,b:this.jc});a.getAttribute("ng-class-even")&&c.push({path:b,b:this.ic});a.getAttribute("ng-style")&&c.push({path:b,b:this.nc});a.getAttribute("ng-watch")&&c.push({path:b,b:this.oc});d=a.nodeName;if(d=="INPUT"||d=="TEXTAREA"||d=="SELECT"|| -d=="BUTTON"){var C=this;c.push({path:b,b:function(s,t,A){s.name=A+s.name.split(":").pop();return C.Lc.Db(k(s),t)}})}if(d=="OPTION")if(!k("").append(k(a).clone()).html().match(/.*<\/\s*option\s*>/gi))a.value=a.text;d=a.childNodes;for(e=0;e'; -P.jb='Sorry, you do not have permission for this!';P.prototype={bind:J(),ja:function(a){this.D.push(a);this.D.length==1&&this.Ba("/user_session/new.mini?return_url="+encodeURIComponent(this.ab()))},bc:function(a){this.D.push(a);this.D.length==1&&this.Ba("/user_session/do_destroy.mini")},ab:function(){return this.window.location.href.split("#")[0]},Ba:function(a){var b=this,c=(new Date).getTime(),d=this.ab();d+="#$iframe_notify="+c;var e= -k('');this.document.append(e);e.Aa({height:363,width:500,Bd:false,dc:true,title:'Authentication: <angular/>'});callbacks["_iframe_notify_"+c]=function(){e.Aa("destroy");e.remove();q(b.D,function(f){f()});b.D=[]}},Ra:function(){if(!this.Fa){this.Fa=k(P.jb);this.Fa.Aa({cd:true,height:70,dc:true})}}};T.kb=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! "+z(a);var b=a.Q+"/"+a.z,c=this.A[b];if(c)E.fa(a,c);else c=this.A[b]=a;return c},load:function(a,b,c,d){if(b&&b!=="*"){var e=this;this.C(["GET",a.Q+"/"+b],function(f){a.R(f);a.fb();f=a.Oc(a);e.T(f);(c||n)(a)},d)}return a},La: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},ac:function(a,b,c){return this.load(a,b,c,function(d){if(d.da==404){a.z=b;(c||n)(a)}else throw d;})},$b:function(a,b){var c=this,d=[];d.qa=function(e){return e.Q==a.title};this.A.P.push(d);this.C(["GET",a.title],function(e){for(var f=0;f ");e.push(d);if(!a[d])throw _("Named entity '<%=name%>' is undefined.").template({name:d});d=a[d].Y?a[d].Y.substring(0,a[d].Y.indexOf(".")):undefined}while(d);return e.length}).value();if(_(c).select(function(d){return a[d].Y}).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],o=l.Y,C={};_(i).each(function(s){var t={};f.push(t);t[g]=s;s=w.M(t,o);C[s]=s});l.join.La(_.toArray(C),function(s){var t={};_(s).each(function(A){t[A.z]=A});_(f).each(function(A){var I=w.M(A,o);A[j]=t[I]})})});return f};return b}};r.h=function(a){if(a)for(var b in a)this[b]=a[b]};r.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 u; -q({currency:function(a){k(this.element).toggleClass("ng-format-negative",a<0);return"$"+r.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;c0){for(c=d.length;c'+g+"",Fd:b});_.breakLoop()}});e&&_.breakLoop()});return e?e:b?c||new r.h({text:b+" is not recognized"}):null}}(),link:function(a,b){b=b||r.h.get(a);var c=r.h.get(a,"url")||r.h.get(a);if(c){if(m.O.sd(c)===null)c="mailto:"+c;a=''+b+"";return new r.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"})}return null},lowercase:function(a){return(a=r.h.get(a))?(""+a).toLowerCase(): -a},uppercase:function(a){return(a=r.h.get(a))?(""+a).toUpperCase():a},linecount:function(a){a=r.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={yb:a,ed:u.zb(b,"color"),ld:u.title(b),gd:u.zb(b,"label"),fd:u.values(b),hd:"bg,s,FFFFFF00"};if(_.isArray(b.Mc)){a.nd="x";a.md="0:|"+b.Mc.join("|")}return u.encode(a,c,d)},{values:function(a){var b=[];q(a.Bc||[], -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.Bc||[],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.kd=b+"x"+c;q(a,function(f,g){f&&e.push(g+"="+f)});e.sort();d+=e.join("&");return new r.h({url:d,html:''})}}),qrcode:function(a,b,c){return u.encode({yb:"qr",jd:encodeURIComponent(a)},b,c)},chart:{yd:function(a,b,c){return u("p",a,b,c)},zd:function(a,b,c){return u("p3",a,b,c)},Ad:function(a,b,c){return u("pc",a,b,c)},$c:function(a,b,c){return u("bhs",a,b,c)},Zc:function(a,b,c){return u("bhg",a,b,c)},bd:function(a,b,c){return u("bvs",a,b,c)},ad:function(a, -b,c){return u("bvg",a,b,c)},vd:function(a,b,c){return u("lc",a,b,c)},Dd:function(a,b,c){return u("ls",a,b,c)},Cd:function(a,b,c){return u("s",a,b,c)}},html:function(a){return new r.h({html:a})}},function(a,b){r[b]=a});u=r.googleChartApi;array=[].constructor;m.toJson=z;m.fromJson=O;E.fa=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(){Z(this.$$entity.rd,this);return this},$save:function(a){this.$$entity.Gb.save(this,a===true?undefined:a);a===true&&this.$$entity.Gb.Ea();return this},$loadFrom:function(a){E.fa(a,this);return this},$saveTo:function(a){E.fa(this,a);return this}};F.ta={"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.i(b,c)},"==":function(a,b,c){return b==c},"!=":function(a,b,c){return b!=c},"<":function(a,b,c){return b":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.ib={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'};F.prototype= -{G:function(){return this.index+10){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.G(a,b,c,d)){this.g.shift();return this.od=a}return false},k:function(a){if(!this.a(a)){var b=this.G();throw"Expecting '"+a+"' at column '"+(b.index+1)+"' in '"+this.text+"' got '"+this.text.substring(b.index)+"'.";}},mb: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))}},Ha: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.G("}",")",";","]")&&a.push(this.Da());if(!this.a(";"))return function(b){for(var c,d=0;d","<=",">="))a=this.s(a,b.b,this.wa);else return a},wa: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.Ya(),b;b=this.a("*","/","%");)a=this.s(a,b.b,this.Ya);return a},Ya:function(){var a;return this.a("+")?this.aa():(a=this.a("-"))?this.s(D.lb,a.b,this.la):this.aa()}, -Sb:function(a){var b=this.a(),c=b.text.split(".");a=a;for(var d,e=0;e1;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+"="+z(b))},eval:function(a,b){var c=w.U[a];if(!c){var d=new D(a);c=d.oa();d.I();w.U[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){W("Eval Widget Error:",g);b=z(g,true);a.w=true;k(a.view).addClass("ng-exception").attr("ng-error",b);e&&e.apply(a,[g,b]);return false}}, -Ic:function(a,b){var c=w.U[a];if(!c){c=(new D(a)).O();w.U[a]=c}a={scope:this};return c(a)(a,b)},K:function(a){return(new D(a)).Nb()({scope:this})},cc:function(a){this.q.Qc.push(a)},watch:function(a){var b=this;(new D(a)).watch()({scope:this,pb:function(c,d){b.qb(c,function(e,f){try{return d({scope:b},e,f)}catch(g){alert(g)}})}})},qb:function(a,b){var c=this.pa[a];if(!c){c={Ka:[],o:a};this.pa[a]=c}c.Ka.push(b)},Qb:function(){var a=this,b=false;q(this.pa,function(c){var d=a.eval(c.o);if(d!==c.d){q(c.Ka, -function(e){e(d,c.d);b=true});c.d=d}});return b}};ja.prototype={ub:function(a){return ba.Kb(a)},N:function(a,b,c,d){var e=this.Hc+this.ec++;ca[e]=function(h){delete m[e];d(200,h)};a={Gd:b,wd:a,xd:c};a=this.ub(z(a));b=Math.ceil(a.length/this.ka);c=this.url+"/$/"+e+"/"+b+"/";for(var f=0;fc)return"Value can not be greater than "+c+".";return null}else return"Value is not a number."},integer:function(a,b,c){b=Ba.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){Ba[b]=a});ma.prototype={Db: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 na(a[0],e);f="keyup change"}else if(d=="checkbox"){c=new oa(a[0], -e);f="click"}else if(d=="radio"){c=new ra(a[0],e);f="click"}else if(d=="select-one")c=new pa(a[0],e);else if(d=="select-multiple")c=new qa(a[0],e);else if(d=="file")c=this.Eb(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},Eb:function(a){var b="__uploadWidget_"+this.fc++,c=M.template(b);a.after(c);b=this.za({data:this.ca+"/admin/ServerAPI.swf", -width:"95",height:"20",align:"top",Id:"transparent"},{ud:"uploadWidgetId="+b,Wc:"always"},b);a.remove();a=new M(c,a[0].name,b,this.ca+"/data/"+this.F);k(b).data("controller",a);return a}};M.dispatchEvent=function(a,b,c){a=y.getElementById(a);a=k(a).data("controller");M.prototype["_on_"+b].apply(a,c)};M.template=function(a){return k('')};M.prototype={e:function(a){var b=this.view.find("input").attr("checked")? -this.value:null;if(this.d===b)return false;else{a.i(this.Wa,b);return true}},c:function(a){if((a=a.get(this.Wa))&&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.Ub=new Q;var Ja=Q;na.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.yc)d=!(c&&c.length>0);var e=d?"Required Value":null;if(!d&&this.O&&c){e=a.Ic(this.O,c);d=!!e}if(this.Ja!==e){this.Ja=d;if(e!==null){b.setAttribute("ng-error",e);a.cc(this)}k(b).toggleClass("ng-validation-error",d)}}};oa.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}};pa.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}}};qa.prototype={selected:function(){for(var a= -[],b=this.view.options,c=0;cd;--b){var o=this.children.pop().element[0];o.parentNode.removeChild(o)}if(h&&h.element[0].nodeName==="OPTION")if(d=k(h.element[0].parentNode).data("controller")){d.d= -undefined;d.c(a)}})}};B.ua="mouseleave mouseout click dblclick keypress keyup";B.rc=function(){B.ma();var a=k(this);a.bind(B.ua,B.ma);var b=a.position(),c=y.documentElement,d=(self.innerWidth||c&&c.clientWidth||y.body.clientWidth)-b.left;c=a.hasClass("ng-exception")?"EXCEPTION:":"Validation error...";a=a.attr("ng-error");d=d>375?"left":"right";c=k(""+c+""+a+"");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.ua,B.ma).remove();return true};B.prototype={bind:function(){this.B.find(".ng-validation-error,.ng-exception").live("mouseover",B.rc)}};U.hb='loading....';U.prototype={vb:function(){this.ba===0&&this.Ma.show();this.ba++},Lb:function(){this.ba--;this.ba=== -0&&this.Ma.hide("fold")}}})(window,document); +a;this.R(b||{});this.Q=a.title;this.hb()}function F(a,b){this.text=a;this.Jb=b?20:-1;this.h=[];this.index=0}function D(a,b){this.text=a;this.h=(new F(a,b)).parse();this.index=0}function v(a,b){this.eb=[];this.qa={};this.name=b;a=a||{};function c(){}c.prototype=a;this.q=new c;this.q.Uc=a;if(b=="ROOT")this.q.Vc=this.q}function ka(a,b){this.url=a;this.fc=0;this.getScript=b;this.Jc="_"+(""+Math.random()).substr(2)+"_";this.ka=1800}function aa(a){this.frame=a}function la(a,b,c){this.Lb=a;this.update=c; +this.status=b}function ma(a,b){this.H=a;this.ea=b}function na(a,b){this.gc=0;this.ca=a;this.F=b;this.Aa=o.Jd?swfobject.Aa:function(){alert("ERROR: swfobject not loaded!")};this.rc=J()}function M(a,b,c,d){this.view=a;this.Md=c;this.Za=b;this.$c=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.zc=typeof a.attributes["ng-required"]!="undefined";this.Ka=null;this.d=undefined;this.p=a.value;a.getAttribute("ng-widget")=== +"datepicker"&&k(a).sd()}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=x.Z(b);this.w=false;this.Bc={element:a}}function ta(a,b){this.view=a;this.vb=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.X=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.Lc=a[3]||a[1];this.$b=a[2]}function B(a){this.B=a}function U(a){this.Oa=a.append(U.jb).find("#ng-loading");this.ba=0}var ba={u:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",Mb:function(a){var b="",c,d,e,f,g,h,i=0;for(a=ba.qb(a);i>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},td:function(a){var b="",c,d,e,f,g,h=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");h>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.pb(b)},qb:function(a){a=a.replace(/\r\n/g,"\n"); +for(var b="",c=0;c127&&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},pb:function(a){for(var b="",c=0,d=c1=c2=0;c191&&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 y.getAttribute=="undefined")y.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,p=_.each,S=_.extend,k=o.jQuery,X=k.browser.msie,m=o.angular||(o.angular= +{}),Ca=m.validator||(m.validator={}),r=m.filter||(m.filter={}),ca=m.callbacks||(m.callbacks={});m.alert||(m.alert=function(){w(arguments);o.alert.apply(o,arguments)});ia.prototype={load:function(){this.Eb();w("Server: "+this.j.H);this.Db();this.Cb();this.yb()},Db:function(){w("Angular.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.Wb}},Gc:function(){return""+ +(new Date).getTime()},Cb:function(){var a=this.j;if(!a.F){var b=a.H.match(/https?:\/\/([\w]*)/);a.F=b?b[1]:"$MEMORY"}},yb:function(){function a(){g.Qb(function(l){!l&&c.find("[ng-auth=eager]").length&&g.ja()})}w("Angular.bindHtml()");var b=this.Nc=new ja(this.location),c=this.document,d=new na(this.j.H,this.j.F),e=new x(c[0],d,b,this.j);d.rc=Ea(e,e.e);b=new P(c.find("body"),this.j.H);var f=this.j.F=="$MEMORY"?new aa(this.window):new ka(this.j.H,k.getScript);f=new la(f,new U(k(c.body)),function(){e.c()}); +var g=new ma(f,b),h="/data/"+this.j.F,i=new T(function(l,q){f.N("POST",h,l,q)},g,e.anchor);e.bb.push(function(){i.Fa()});var j=new v({$anchor:e.anchor,$binder:e,$config:this.j,$console:o.console,$datastore:i,$save:function(l){i.Ac(j.q,l,e.anchor)},$window:o,$uid:this.Gc,$users:g},"ROOT");c.data("scope",j);w("$binder.entity()");e.K(j);w("$binder.compile()");e.compile();w("ControlBar.bind()");b.bind();w("$users.fetchCurrentUser()");a();w("PopUp.bind()");(new B(c)).bind();w("$binder.parseAnchor()"); +e.Ua();c.find("body").show();w("ready()")},Eb:function(){var a=o.location.href+"#";a=a.split("#")[1];var b={Kb:null};a=a.split("&");for(var c=0;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.Wc.find(a,function(c){return c.z==b},null)},filter:function(a, +b){var c=[];c.zb=function(j){for(var l=0;l-1;case "object":for(var q in j)if(q.charAt(0)!=="$"&&e(j[q],l))return true;return false;case "array":for(q=0;q=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}Z(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-1;){c1||x.J(a[0])!==null};x.J=function(a){return(a=a.replace(/\n/gm," ").match(/^\{\{(.*)\}\}$/))? +a[1]:null};x.prototype={uc:function(a){var b={};a.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,function(c,d,e){if(d)b[decodeURIComponent(d)]=decodeURIComponent(e)});return b},Ua:function(a){var b=this;a=a||this.pa.Ha();var c=a.indexOf("#");if(!(c<0)){a=this.uc(a.substring(c+1));p(b.anchor,function(d,e){delete b.anchor[e]});p(a,function(d,e){b.anchor[e]=d})}},tc:function(a){this.Ua(a);this.c()},Hc: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.Dc(a);return a},c:function(){(new Date).getTime();var a=k(this.B).scope();a.i("$invalidWidgets",[]);a.c();(new Date).getTime();this.Hc();_.each(this.bb,function(b){b()})},ga:function(a){var b=k(this.B),c=b.find(a);if(b.is(a))c=c.andSelf();return c},K:function(a){this.ga("[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.B),b=this;if(this.j.ad){var c=this.ga(":submit").not("[ng-action]");c.attr("ng-action","$save()");c.not(":disabled").not("ng-bind-attr").attr("ng-bind-attr",'{disabled:"{{$invalidWidgets}}"}')}this.Va(this.B)(this.B,a.scope(),"");this.ga("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",z(e,true))}b.c();return false})},Fc:function(a,b,c){b=b.concat();var d=b.pop(),e=x.Z(a.nodeValue);if(e.length>1||x.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;g2&&a.setAttribute("ng-bind-attr",d)}a.getAttribute||w(a);var j=a.getAttribute("ng-repeat");if(j){a.removeAttribute("ng-repeat");var l=this.Va(a);d=y.createComment("ng-repeat: "+j);e=a.parentNode;e.insertBefore(d,a);e.removeChild(a);function q(s,t,A){var I= +k(a).clone();I.css("display","");I.attr("ng-repeat-index",""+A);I.data("scope",s);l(I[0],s,t+A+":");return I}c.push({path:b,b:function(s,t,A){return new Ba(k(s),j,q,A)}})}else{a.getAttribute("ng-eval")&&c.push({path:b,b:this.lc});a.getAttribute("ng-bind")&&c.push({path:b,b:this.Sa});a.getAttribute("ng-bind-attr")&&c.push({path:b,b:this.hc});a.getAttribute("ng-hide")&&c.push({path:b,b:this.mc});a.getAttribute("ng-show")&&c.push({path:b,b:this.nc});a.getAttribute("ng-class")&&c.push({path:b,b:this.ic}); +a.getAttribute("ng-class-odd")&&c.push({path:b,b:this.kc});a.getAttribute("ng-class-even")&&c.push({path:b,b:this.jc});a.getAttribute("ng-style")&&c.push({path:b,b:this.oc});a.getAttribute("ng-watch")&&c.push({path:b,b:this.pc});d=a.nodeName;if(d=="INPUT"||d=="TEXTAREA"||d=="SELECT"||d=="BUTTON"){var C=this;c.push({path:b,b:function(s,t,A){s.name=A+s.name.split(":").pop();return C.Oc.Fb(k(s),t)}})}if(d=="OPTION")if(!k("").append(k(a).clone()).html().match(/.*<\/\s*option\s*>/gi))a.value= +a.text;d=a.childNodes;for(e=0;e';P.lb='Sorry, you do not have permission for this!';P.prototype={bind:J(),ja:function(a){this.D.push(a);this.D.length==1&& +this.Ca("/user_session/new.mini?return_url="+encodeURIComponent(this.cb()))},cc:function(a){this.D.push(a);this.D.length==1&&this.Ca("/user_session/do_destroy.mini")},cb:function(){return this.window.location.href.split("#")[0]},Ca:function(a){var b=this,c=(new Date).getTime(),d=this.cb();d+="#$iframe_notify="+c;var e=k('');this.document.append(e);e.Ba({height:363,width:500,Gd:false, +ec:true,title:'Authentication: <angular/>'});callbacks["_iframe_notify_"+c]=function(){e.Ba("destroy");e.remove();p(b.D,function(f){f()});b.D=[]}},Ta:function(){if(!this.Ga){this.Ga=k(P.lb);this.Ga.Ba({fd:true,height:70,ec:true})}}};T.mb=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! "+z(a);var b= +a.Q+"/"+a.z,c=this.A[b];if(c)E.fa(a,c);else c=this.A[b]=a;return c},load:function(a,b,c,d){if(b&&b!=="*"){var e=this;this.C(["GET",a.Q+"/"+b],function(f){a.R(f);a.hb();f=a.Rc(a);e.T(f);(c||n)(a)},d)}return a},Na:function(a,b,c){var d=this,e=[],f=0;p(b,function(g){e.push(d.load(a(),g,function(){f++;if(f==b.length)(c||n)(e)}))});return e},bc:function(a,b,c){return this.load(a,b,c,function(d){if(d.da==404){a.z=b;(c||n)(a)}else throw d;})},ac:function(a,b){var c=this,d=[];d.ra=function(e){return e.Q== +a.title};this.A.P.push(d);this.C(["GET",a.title],function(e){for(var f=0;f ");e.push(d);if(!a[d])throw _("Named entity '<%=name%>' is undefined.").template({name:d});d=a[d].Y?a[d].Y.substring(0, +a[d].Y.indexOf(".")):undefined}while(d);return e.length}).value();if(_(c).select(function(d){return a[d].Y}).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],q=l.Y,C={};_(i).each(function(s){var t={};f.push(t);t[g]=s;s=v.M(t,q);C[s]= +s});l.join.Na(_.toArray(C),function(s){var t={};_(s).each(function(A){t[A.z]=A});_(f).each(function(A){var I=v.M(A,q);A[j]=t[I]})})});return f};return b}};r.g=function(a){if(a)for(var b in a)this[b]=a[b]};r.g.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 u;p({currency:function(a){k(this.element).toggleClass("ng-format-negative",a<0);return"$"+r.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;c0){for(c=d.length;c'+g+"",Kd:b});_.breakLoop()}});e&&_.breakLoop()});return e?e:b?c||new r.g({text:b+" is not recognized"}):null}}(),link:function(a,b){b=b||r.g.get(a);var c=r.g.get(a,"url")||r.g.get(a);if(c){if(m.O.vd(c)===null)c="mailto:"+c;a=''+b+"";return new r.g({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"})}return null},lowercase:function(a){return(a=r.g.get(a))?(""+a).toLowerCase():a},uppercase:function(a){return(a=r.g.get(a))? +(""+a).toUpperCase():a},linecount:function(a){a=r.g.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={Ab:a,hd:u.Bb(b,"color"),od:u.title(b),kd:u.Bb(b,"label"),jd:u.values(b),ld:"bg,s,FFFFFF00"};if(_.isArray(b.Pc)){a.qd="x";a.pd="0:|"+b.Pc.join("|")}return u.encode(a,c,d)},{values:function(a){var b=[];p(a.Cc||[],function(c){var d=[];p(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||[];p(_.isArray(a)?a:[a],function(c){b.push(encodeURIComponent(c))});return b.join("|")},collect:function(a,b){var c=[],d=0;p(a.Cc||[],function(e){var f=[];e=e[b]||[];p(_.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.nd=b+"x"+c;p(a,function(f, +g){f&&e.push(g+"="+f)});e.sort();d+=e.join("&");return new r.g({url:d,html:''})}}),qrcode:function(a,b,c){return u.encode({Ab:"qr",md:encodeURIComponent(a)},b,c)},chart:{Dd:function(a,b,c){return u("p",a,b,c)},Ed:function(a,b,c){return u("p3",a,b,c)},Fd:function(a,b,c){return u("pc",a,b,c)},cd:function(a,b,c){return u("bhs",a,b,c)},bd:function(a,b,c){return u("bhg",a,b,c)},ed:function(a,b,c){return u("bvs",a,b,c)},dd:function(a,b,c){return u("bvg",a, +b,c)},zd:function(a,b,c){return u("lc",a,b,c)},Id:function(a,b,c){return u("ls",a,b,c)},Hd:function(a,b,c){return u("s",a,b,c)}},html:function(a){return new r.g({html:a})},linky:function(a){var b=a,c={};p(a.match(/(ftp|http|https):\/\/([^\(\)|\s]+)/gm)||[],function(d){d=d.replace(/\.$/,"");if(!c[d]){b=b.replace(new RegExp(d.replace(/([\/\.\*\+\?\|\(\)\[\]\{\}\\])/g,"\\$1"),"gm"),''+d+"");c[d]=true}});return new r.g({text:a,html:b})}},function(a,b){r[b]=a});u=r.googleChartApi;array= +[].constructor;m.toJson=z;m.fromJson=O;E.fa=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(){Z(this.$$entity.ud,this);return this},$save:function(a){this.$$entity.Ib.save(this,a===true?undefined:a);a===true&&this.$$entity.Ib.Fa();return this},$loadFrom:function(a){E.fa(a,this);return this},$saveTo:function(a){E.fa(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.i(b,c)},"==":function(a,b,c){return b==c},"!=":function(a,b,c){return b!=c},"<":function(a,b,c){return b":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.kb={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'};F.prototype={G:function(){return this.index+10){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.G(a,b,c,d)){this.h.shift();return this.rd=a}return false},k:function(a){if(!this.a(a)){var b=this.G();throw"Expecting '"+a+"' at column '"+(b.index+1)+"' in '"+this.text+"' got '"+this.text.substring(b.index)+"'.";}},ob: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.h.length>0},I:function(){if(this.h.length!==0)throw"Did not understand '"+ +this.text.substring(this.h[0].index)+"' while evaluating '"+this.text+"'.";},oa:function(){for(var a=[];;){this.h.length>0&&!this.G("}",")",";","]")&&a.push(this.Ea());if(!this.a(";"))return function(b){for(var c,d=0;d","<=",">="))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.ab(),b;b=this.a("*","/","%");)a=this.s(a,b.b,this.ab);return a},ab:function(){var a;return this.a("+")?this.aa():(a=this.a("-"))?this.s(D.nb,a.b,this.la):this.aa()},Ub:function(a){var b=this.a(),c=b.text.split(".");a=a;for(var d,e=0;e1;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+"="+z(b))},eval:function(a,b){var c=v.U[a];if(!c){var d=new D(a);c=d.oa();d.I();v.U[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){W("Eval Widget Error:",g);b=z(g,true);a.w=true;k(a.view).addClass("ng-exception").attr("ng-error",b);e&&e.apply(a,[g,b]);return false}},Kc:function(a,b){var c=v.U[a];if(!c){c=(new D(a)).O();v.U[a]=c}a={scope:this};return c(a)(a,b)},K:function(a){return(new D(a)).Pb()({scope:this})},dc:function(a){this.q.Tc.push(a)},watch:function(a){var b=this;(new D(a)).watch()({scope:this, +rb:function(c,d){b.sb(c,function(e,f){try{return d({scope:b},e,f)}catch(g){alert(g)}})}})},sb:function(a,b){var c=this.qa[a];if(!c){c={Ma:[],o:a};this.qa[a]=c}c.Ma.push(b)},Sb:function(){var a=this,b=false;p(this.qa,function(c){var d=a.eval(c.o);if(d!==c.d){p(c.Ma,function(e){e(d,c.d);b=true});c.d=d}});return b}};ka.prototype={wb:function(a){return ba.Mb(a)},N:function(a,b,c,d){var e=this.Jc+this.fc++;ca[e]=function(h){delete m[e];d(200,h)};a={Ld:b,Ad:a,Cd:c};a=this.wb(z(a));b=Math.ceil(a.length/ +this.ka);c=this.url+"/$/"+e+"/"+b+"/";for(var f=0;fc)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={Fb: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.Gb(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},Gb:function(a){var b="__uploadWidget_"+this.gc++,c=M.template(b);a.after(c);b=this.Aa({data:this.ca+"/admin/ServerAPI.swf",width:"95",height:"20",align:"top",Nd:"transparent"},{yd:"uploadWidgetId="+b,Zc:"always"},b);a.remove();a=new M(c,a[0].name,b,this.ca+"/data/"+this.F);k(b).data("controller",a);return a}};M.dispatchEvent=function(a,b,c){a=y.getElementById(a); +a=k(a).data("controller");M.prototype["_on_"+b].apply(a,c)};M.template=function(a){return k('')};M.prototype={e:function(a){var b=this.view.find("input").attr("checked")?this.value:null;if(this.d===b)return false;else{a.i(this.Za,b);return true}},c:function(a){if((a=a.get(this.Za))&&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.Wb=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.zc)d=!(c&&c.length>0);var e=d?"Required Value": +null;if(!d&&this.O&&c){e=a.Kc(this.O,c);d=!!e}if(this.Ka!==e){this.Ka=d;if(e!==null){b.setAttribute("ng-error",e);a.dc(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;cd;--b){var q=this.children.pop().element[0];q.parentNode.removeChild(q)}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.sc=function(){B.ma();var a=k(this);a.bind(B.va,B.ma);var b=a.position(),c=y.documentElement,d=(self.innerWidth||c&&c.clientWidth|| +y.body.clientWidth)-b.left;c=a.hasClass("ng-exception")?"EXCEPTION:":"Validation error...";a=a.attr("ng-error");d=d>375?"left":"right";c=k(""+c+""+a+"");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.B.find(".ng-validation-error,.ng-exception").live("mouseover",B.sc)}};U.jb='loading....';U.prototype={xb:function(){this.ba===0&&this.Oa.show();this.ba++},Nb:function(){this.ba--;this.ba===0&&this.Oa.hide("fold")}}})(window,document); diff --git a/angular.js b/angular.js index e3f24ecb..dee0b57e 100644 --- a/angular.js +++ b/angular.js @@ -342,17 +342,17 @@ function merge(src, dst) { } // //////////////////////////// -// Loader +// Angular // //////////////////////////// -function Loader(document, head, config) { +function Angular(document, head, config) { this.document = jQuery(document); this.head = jQuery(head); this.config = config; this.location = window.location; } -Loader.prototype = { +Angular.prototype = { load: function() { this.configureLogging(); log("Server: " + this.config.server); @@ -362,7 +362,7 @@ Loader.prototype = { }, configureJQueryPlugins: function() { - log('Loader.configureJQueryPlugins()'); + log('Angular.configureJQueryPlugins()'); jQuery['fn']['scope'] = function() { var element = this; while (element && element.get(0)) { @@ -391,8 +391,8 @@ Loader.prototype = { }, bindHtml: function() { - log('Loader.bindHtml()'); - var watcher = new UrlWatcher(this.location); + log('Angular.bindHtml()'); + var watcher = this.watcher = new UrlWatcher(this.location); var document = this.document; var widgetFactory = new WidgetFactory(this.config.server, this.config.database); var binder = new Binder(document[0], widgetFactory, watcher, this.config); @@ -450,12 +450,6 @@ Loader.prototype = { log('$binder.parseAnchor()'); binder.parseAnchor(); - log('$binder.updateView()'); - binder.updateView(); - - //watcher.listener = bind(binder, binder.onUrlChange, watcher); - //watcher.onUpdate = function(){alert("update");}; - //watcher.watch(); document.find("body").show(); log('ready()'); }, @@ -498,16 +492,6 @@ Loader.prototype = { consoleLog('ng-console-error', arguments); }; } - }, - - loadCss: function(css) { - var cssTag = document.createElement('link'); - cssTag.rel = "stylesheet"; - cssTag.type = "text/css"; - if (!css.match(/^http:/)) - css = this.config.server + css; - cssTag.href = css; - this.head[0].appendChild(cssTag); } }; @@ -553,12 +537,12 @@ UrlWatcher.prototype = { }, setUrl: function(url) { -// var existingURL = window.location.href; -// if (!existingURL.match(/#/)) -// existingURL += '#'; -// if (existingURL != url) -// window.location.href = url; -// this.existingURL = url; + var existingURL = window.location.href; + if (!existingURL.match(/#/)) + existingURL += '#'; + if (existingURL != url) + window.location.href = url; + this.existingURL = url; }, getUrl: function() { @@ -573,18 +557,25 @@ angular['compile'] = function(root, config) { 'addUrlChangeListener': noop }; //todo: don't start watcher - var loader = new Loader(root, jQuery("head"), _(defaults).extend(config)); + var angular = new Angular(root, jQuery("head"), _(defaults).extend(config)); //todo: don't load stylesheet by default // loader.loadCss('/stylesheets/jquery-ui/smoothness/jquery-ui-1.7.1.css'); // loader.loadCss('/stylesheets/css'); - loader.load(); + angular.load(); var scope = jQuery(root).scope(); //TODO: cleanup return { 'updateView':function(){return scope.updateView();}, 'set':function(){return scope.set.apply(scope, arguments);}, 'get':function(){return scope.get.apply(scope, arguments);}, - 'init':function(){scope.get('$binder.executeInit')(); scope.updateView();} + 'init':function(){scope.get('$binder.executeInit')(); scope.updateView();}, + 'watchUrl':function(){ + var binder = scope.get('$binder'); + var watcher = angular.watcher; + watcher.listener = bind(binder, binder.onUrlChange, watcher); + watcher.onUpdate = function(){alert("update");}; + watcher.watch(); + } }; };var angularGlobal = { 'typeOf':function(obj){ @@ -977,7 +968,6 @@ Binder.prototype = { }, onUrlChange: function (url) { - log("URL change detected", url); this.parseAnchor(url); this.updateView(); }, @@ -1959,6 +1949,23 @@ foreach({ 'html': function(html){ return new angularFilter.Meta({html:html}); + }, + + 'linky': function(text){ + function regExpEscape(text) { + return text.replace(/([\/\.\*\+\?\|\(\)\[\]\{\}\\])/g, '\\$1'); + } + var URL = /(ftp|http|https):\/\/([^\(\)|\s]+)/gm; + var html = text; + var dups = {}; + foreach(text.match(URL)||[], function(url){ + url = url.replace(/\.$/, ''); + if (!dups[url]) { + html = html.replace(new RegExp(regExpEscape(url), 'gm'), ''+url+''); + dups[url] = true; + } + }); + return new angularFilter.Meta({text:text, html:html}); } }, function(v,k){angularFilter[k] = v;}); diff --git a/example/business_card.html b/example/business_card.html deleted file mode 100644 index cc45529f..00000000 --- a/example/business_card.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - Fetch tweets for: - - - - Loading... - - [{{tweet.user.screen_name}}]: {{tweet.text}} - - - diff --git a/example/tweeter/style.css b/example/tweeter/style.css new file mode 100644 index 00000000..769a6f45 --- /dev/null +++ b/example/tweeter/style.css @@ -0,0 +1,87 @@ +.loading {display: none;} +.fetching .loading {display: block;} + +a { + color: blue; +} + +h1 { + background-color: black; + margin: 0; + padding: .25em; + color: white; + border-bottom: 5px solid gray; +} + +.box { + border: 2px solid gray; +} + +.tweeter { + margin-right: 360px; +} + +ul { + list-style: none; + margin: 0; + padding: 0; +} + +li { + margin: .25em; + padding: 2px; +} + +li img { + float: left; + margin: 2px; + margin-right: .5em; + max-height: 48px; + min-height: 48px; +} + +li.even { + background-color: lightgray; +} + + +.addressbook { + float: right; + width: 350px; +} + +.clrleft { + clear: left; +} + +.notes { + font-size: .8em; + color: gray; +} + +.username, .nickname { + font-weight: bold; +} + +.editor { + padding: 4px; +} + +label { + color: gray; + display: inline-block; + width: 75px; + text-align: right; + padding: 2px; + margin-top: 10px; +} + +.editor input[type=text], +.editor textarea { + width: 230px; + vertical-align: text-top; +} + +.editor TEXTAREA { + height: 50px; +} \ No newline at end of file diff --git a/example/tweeter/tweeter_addressbook.html b/example/tweeter/tweeter_addressbook.html new file mode 100644 index 00000000..d8b8b893 --- /dev/null +++ b/example/tweeter/tweeter_addressbook.html @@ -0,0 +1,64 @@ + + + + + + + + + + + + + Address Book + [ Filter: ] + + + + {{user.screen_name}} + as {{user.name}} + [ edit + | X + ] + {{user.notes}} + + + + + + + Username: + + Name: + + Image: + + Notes: + + + + + + + + Tweets: {{$anchor.user}} + [ Filter: + | << All + ] + Loading... + + + + [ {{user.nickname || user.name || user.screen_name }} + | + + ]: + {{tweet.text | linky}} + {{tweet.created_at}} + {{user.notes}} + + + + + + diff --git a/example/tweeter/tweeterclient.js b/example/tweeter/tweeterclient.js new file mode 100644 index 00000000..27ec3348 --- /dev/null +++ b/example/tweeter/tweeterclient.js @@ -0,0 +1,35 @@ +function noop(){} +$(document).ready(function(){ + var scope = window.scope = angular.compile(document); + scope.getJSON = function(url, callback) { + var list = []; + var self = this; + self.set('status', 'fetching'); + $.getJSON(url, function(response){ + _(response).forEach(function(v,k){ + list[k] = v; + }); + (callback||noop)(response); + self.set('status', ''); + self.updateView(); + }); + return list; + }; + + function fetchTweets(username){ + return scope.getJSON( + username ? + "http://twitter.com/statuses/user_timeline/"+username+".json" : + "http://twitter.com/statuses/home_timeline.json"); + } + + scope.set('fetchTweets', fetchTweets); + scope.set('users', [ + {screen_name:'mhevery', name:'Mi\u0161ko Hevery', notes:'Author of .', + profile_image_url:'http://a3.twimg.com/profile_images/54360179/Me_-_Small_Banner_normal.jpg'}, + {screen_name:'abrons', name:'Adam Abrons', notes:'Author of & Ruby guru.', + profile_image_url:'http://a1.twimg.com/profile_images/533646480/PIC00024_normal.jpg'} + ]); + scope.watchUrl(); + scope.init(); +}); diff --git a/src/Angular.js b/src/Angular.js index 69cab0a2..3dc72ff7 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -227,7 +227,7 @@ Angular.prototype = { bindHtml: function() { log('Angular.bindHtml()'); - var watcher = new UrlWatcher(this.location); + var watcher = this.watcher = new UrlWatcher(this.location); var document = this.document; var widgetFactory = new WidgetFactory(this.config.server, this.config.database); var binder = new Binder(document[0], widgetFactory, watcher, this.config); @@ -285,12 +285,6 @@ Angular.prototype = { log('$binder.parseAnchor()'); binder.parseAnchor(); - log('$binder.updateView()'); - binder.updateView(); - - //watcher.listener = bind(binder, binder.onUrlChange, watcher); - //watcher.onUpdate = function(){alert("update");}; - //watcher.watch(); document.find("body").show(); log('ready()'); }, @@ -378,12 +372,13 @@ UrlWatcher.prototype = { }, setUrl: function(url) { -// var existingURL = window.location.href; -// if (!existingURL.match(/#/)) -// existingURL += '#'; -// if (existingURL != url) -// window.location.href = url; -// this.existingURL = url; + //TODO: conditionaly? + var existingURL = window.location.href; + if (!existingURL.match(/#/)) + existingURL += '#'; + if (existingURL != url) + window.location.href = url; + this.existingURL = url; }, getUrl: function() { @@ -409,6 +404,13 @@ angular['compile'] = function(root, config) { 'updateView':function(){return scope.updateView();}, 'set':function(){return scope.set.apply(scope, arguments);}, 'get':function(){return scope.get.apply(scope, arguments);}, - 'init':function(){scope.get('$binder.executeInit')(); scope.updateView();} + 'init':function(){scope.get('$binder.executeInit')(); scope.updateView();}, + 'watchUrl':function(){ + var binder = scope.get('$binder'); + var watcher = angular.watcher; + watcher.listener = bind(binder, binder.onUrlChange, watcher); + watcher.onUpdate = function(){alert("update");}; + watcher.watch(); + } }; }; \ No newline at end of file diff --git a/src/Binder.js b/src/Binder.js index 36cb6ec3..b29a07c6 100644 --- a/src/Binder.js +++ b/src/Binder.js @@ -66,7 +66,6 @@ Binder.prototype = { }, onUrlChange: function (url) { - log("URL change detected", url); this.parseAnchor(url); this.updateView(); }, diff --git a/src/Filters.js b/src/Filters.js index 666c9f30..833d5630 100644 --- a/src/Filters.js +++ b/src/Filters.js @@ -293,6 +293,23 @@ foreach({ 'html': function(html){ return new angularFilter.Meta({html:html}); + }, + + 'linky': function(text){ + function regExpEscape(text) { + return text.replace(/([\/\.\*\+\?\|\(\)\[\]\{\}\\])/g, '\\$1'); + } + var URL = /(ftp|http|https):\/\/([^\(\)|\s]+)/gm; + var html = text; + var dups = {}; + foreach(text.match(URL)||[], function(url){ + url = url.replace(/\.$/, ''); + if (!dups[url]) { + html = html.replace(new RegExp(regExpEscape(url), 'gm'), ''+url+''); + dups[url] = true; + } + }); + return new angularFilter.Meta({text:text, html:html}); } }, function(v,k){angularFilter[k] = v;}); diff --git a/test.sh b/test.sh index 8993c3ff..32e8b4b7 100755 --- a/test.sh +++ b/test.sh @@ -1 +1,2 @@ -java -jar lib/jstestdriver/JsTestDriver.jar --tests all +java -jar lib/jstestdriver/JsTestDriver.jar --tests all 2>/dev/null | grep -v lib/jasmine + diff --git a/test/FiltersTest.js b/test/FiltersTest.js index c219f24f..fee59bac 100644 --- a/test/FiltersTest.js +++ b/test/FiltersTest.js @@ -151,3 +151,12 @@ FiltersTest.prototype.testHtml = function() { angular.filter.html("acd").html); assertTrue(angular.filter.html("acd") instanceof angular.filter.Meta); }; + +FiltersTest.prototype.testLinky = function() { + assertEquals( + 'a (http://a) http://a \n http://1.2/v:~-123. c', + angular.filter.linky("a (http://a) http://a \n http://1.2/v:~-123. c").html); + assertTrue(angular.filter.linky("a") instanceof angular.filter.Meta); +}; + + -- cgit v1.2.3