mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
angular.js
This commit is contained in:
commit
c9c176a53b
60 changed files with 14559 additions and 0 deletions
2
LICENSE
Normal file
2
LICENSE
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
TODO
|
||||
apache or MIT probably
|
||||
3
README.md
Normal file
3
README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Angular
|
||||
======
|
||||
TODO
|
||||
74
Rakefile
Normal file
74
Rakefile
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
include FileUtils
|
||||
|
||||
desc 'Compile JavaScript'
|
||||
task :compile do
|
||||
compiled = %x(java -jar lib/shrinksafe/shrinksafe.jar \
|
||||
lib/webtoolkit/webtoolkit.base64.js \
|
||||
lib/underscore/underscore.js \
|
||||
src/Loader.js \
|
||||
src/API.js \
|
||||
src/Binder.js \
|
||||
src/ControlBar.js \
|
||||
src/DataStore.js \
|
||||
src/Filters.js \
|
||||
src/JSON.js \
|
||||
src/Model.js \
|
||||
src/Parser.js \
|
||||
src/Scope.js \
|
||||
src/Server.js \
|
||||
src/Users.js \
|
||||
src/Validators.js \
|
||||
src/Widgets.js \
|
||||
src/angular-bootstrap.js \
|
||||
)
|
||||
f = File.new("angular.js", 'w')
|
||||
f.write(compiled)
|
||||
f.close
|
||||
end
|
||||
|
||||
desc 'Compile JavaScript with Google Closure Compiler'
|
||||
task :compileclosure do
|
||||
%x(java -jar lib/compiler-closure/compiler.jar \
|
||||
--compilation_level ADVANCED_OPTIMIZATIONS \
|
||||
--js lib/webtoolkit/webtoolkit.base64.js \
|
||||
--js lib/underscore/underscore.js \
|
||||
--js src/Loader.js \
|
||||
--js src/API.js \
|
||||
--js src/Binder.js \
|
||||
--js src/ControlBar.js \
|
||||
--js src/DataStore.js \
|
||||
--js src/Filters.js \
|
||||
--js src/JSON.js \
|
||||
--js src/Model.js \
|
||||
--js src/Parser.js \
|
||||
--js src/Scope.js \
|
||||
--js src/Server.js \
|
||||
--js src/Users.js \
|
||||
--js src/Validators.js \
|
||||
--js src/Widgets.js \
|
||||
--js src/angular-bootstrap.js \
|
||||
--js_output_file angular.js)
|
||||
end
|
||||
|
||||
namespace :server do
|
||||
desc 'Run JsTestDriver Server'
|
||||
task :start do
|
||||
sh %x(java -jar lib/jstestdriver/JsTestDriver.jar --browser open --port 9876)
|
||||
end
|
||||
|
||||
desc "Run JavaScript tests against the server"
|
||||
task :test do
|
||||
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all)
|
||||
end
|
||||
end
|
||||
|
||||
desc "Run JavaScript tests"
|
||||
task :test do
|
||||
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all --browser open --port 9876)
|
||||
end
|
||||
|
||||
desc 'Lint'
|
||||
task :lint do
|
||||
out = %x(lib/jsl/jsl -conf lib/jsl/jsl.default.conf)
|
||||
print out
|
||||
end
|
||||
128
angular.js
vendored
Normal file
128
angular.js
vendored
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
function r(){return function(a){return a}}function v(){return function(){}}function x(a){return function(b){this[a]=b}}function z(a){return function(){return a}}var A;
|
||||
function aa(a){var b="",c,e,d,f,i,j,n=0;a=a;a=a.replace(/\r\n/g,"\n");e="";for(d=0;d<a.length;d++){f=a.charCodeAt(d);if(f<128)e+=String.fromCharCode(f);else{if(f>127&&f<2048)e+=String.fromCharCode(f>>6|192);else{e+=String.fromCharCode(f>>12|224);e+=String.fromCharCode(f>>6&63|128)}e+=String.fromCharCode(f&63|128)}}for(a=e;n<a.length;){c=a.charCodeAt(n++);e=a.charCodeAt(n++);d=a.charCodeAt(n++);f=c>>2;c=(c&3)<<4|e>>4;i=(e&15)<<2|d>>6;j=d&63;if(isNaN(e))i=j=64;else if(isNaN(d))j=64;b=b+this.eb.charAt(f)+
|
||||
this.eb.charAt(c)+this.eb.charAt(i)+this.eb.charAt(j)}return b};(function(){var a=this,b=a.cb;function c(g){this.da=g}var e=typeof StopIteration!=="undefined"?StopIteration:"__break__",d=a.cb=function(g){return new c(g)};if(typeof exports!=="undefined")exports.cb=d;var f=Array.prototype.slice,i=Array.prototype.unshift,j=Object.prototype.toString,n=Object.prototype.hasOwnProperty,m=Object.prototype.propertyIsEnumerable;d.oe="0.5.1";d.a=function(g,h,k){try{if(g.forEach)g.forEach(h,k);else if(d.z(g)||d.dc(g))for(var l=0,p=g.length;l<p;l++)h.call(k,g[l],l,g);else{var s=
|
||||
d.la(g);p=s.length;for(l=0;l<p;l++)h.call(k,g[s[l]],s[l],g)}}catch(u){if(u!=e)throw u;}return g};d.map=function(g,h,k){if(g&&d.P(g.map))return g.map(h,k);var l=[];d.a(g,function(p,s,u){l.push(h.call(k,p,s,u))});return l};d.reduce=function(g,h,k,l){if(g&&d.P(g.reduce))return g.reduce(d.u(k,l),h);d.a(g,function(p,s,u){h=k.call(l,h,p,s,u)});return h};d.reduceRight=function(g,h,k,l){if(g&&d.P(g.reduceRight))return g.reduceRight(d.u(k,l),h);var p=d.fa(d.D(g)).reverse();d.a(p,function(s,u){h=k.call(l,h,
|
||||
s,u,g)});return h};d.Ub=function(g,h,k){var l;d.a(g,function(p,s,u){if(h.call(k,p,s,u)){l=p;d.va()}});return l};d.select=function(g,h,k){if(g&&d.P(g.filter))return g.filter(h,k);var l=[];d.a(g,function(p,s,u){h.call(k,p,s,u)&&l.push(p)});return l};d.vf=function(g,h,k){var l=[];d.a(g,function(p,s,u){!h.call(k,p,s,u)&&l.push(p)});return l};d.all=function(g,h,k){h=h||d.ka;if(g&&d.P(g.every))return g.every(h,k);var l=true;d.a(g,function(p,s,u){(l=l&&h.call(k,p,s,u))||d.va()});return l};d.Uc=function(g,
|
||||
h,k){h=h||d.ka;if(g&&d.P(g.some))return g.some(h,k);var l=false;d.a(g,function(p,s,u){if(l=h.call(k,p,s,u))d.va()});return l};d.Aa=function(g,h){if(d.z(g))return d.indexOf(g,h)!=-1;var k=false;d.a(g,function(l){if(k=l===h)d.va()});return k};d.Ze=function(g,h){var k=d.Q(arguments,2);return d.map(g,function(l){return(h?l[h]:l).apply(l,k)})};d.vb=function(g,h){return d.map(g,function(k){return k[h]})};d.max=function(g,h,k){if(!h&&d.z(g))return Math.max.apply(Math,g);var l={ga:-Infinity};d.a(g,function(p,
|
||||
s,u){s=h?h.call(k,p,s,u):p;s>=l.ga&&(l={value:p,ga:s})});return l.value};d.min=function(g,h,k){if(!h&&d.z(g))return Math.min.apply(Math,g);var l={ga:Infinity};d.a(g,function(p,s,u){s=h?h.call(k,p,s,u):p;s<l.ga&&(l={value:p,ga:s})});return l.value};d.Rd=function(g,h,k){return d.vb(d.map(g,function(l,p,s){return{value:l,Sb:h.call(k,l,p,s)}}).sort(function(l,p){l=l.Sb;p=p.Sb;return l<p?-1:l>p?1:0}),"value")};d.yf=function(g,h,k){k=k||d.ka;for(var l=0,p=g.length;l<p;){var s=l+p>>1;k(g[s])<k(h)?(l=s+1):
|
||||
(p=s)}return l};d.D=function(g){if(!g)return[];if(g.D)return g.D();if(d.z(g))return g;if(d.dc(g))return f.call(g);return d.map(g,r())};d.size=function(g){return d.D(g).length};d.jd=function(g,h,k){return h&&!k?f.call(g,0,h):g[0]};d.Q=function(g,h,k){return f.call(g,d.K(h)||k?1:h)};d.ud=function(g){return g[g.length-1]};d.compact=function(g){return d.select(g,function(h){return!!h})};d.kd=function(g){return d.reduce(g,[],function(h,k){if(d.z(k))return h.concat(d.kd(k));h.push(k);return h})};d.Mf=function(g){var h=
|
||||
d.Q(arguments);return d.select(g,function(k){return!d.Aa(h,k)})};d.Wd=function(g,h){return d.reduce(g,[],function(k,l,p){if(0==p||(h===true?d.ud(k)!=l:!d.Aa(k,l)))k.push(l);return k})};d.Ye=function(g){var h=d.Q(arguments);return d.select(d.Wd(g),function(k){return d.all(h,function(l){return d.indexOf(l,k)>=0})})};d.Pf=function(){for(var g=d.D(arguments),h=d.max(d.vb(g,"length")),k=new Array(h),l=0;l<h;l++)k[l]=d.vb(g,String(l));return k};d.indexOf=function(g,h){if(g.indexOf)return g.indexOf(h);for(var k=
|
||||
0,l=g.length;k<l;k++)if(g[k]===h)return k;return-1};d.lastIndexOf=function(g,h){if(g.lastIndexOf)return g.lastIndexOf(h);for(var k=g.length;k--;)if(g[k]===h)return k;return-1};d.Md=function(g,h,k){var l=d.D(arguments),p=l.length<=1;g=p?0:l[0];h=p?l[0]:l[1];k=l[2]||1;l=Math.ceil((h-g)/k);if(l<=0)return[];l=new Array(l);p=g;for(var s=0;;p+=k){if((k>0?p-h:h-p)>=0)return l;l[s++]=p}};d.u=function(g,h){var k=d.Q(arguments,2);return function(){return g.apply(h||a,k.concat(d.D(arguments)))}};d.we=function(g){var h=
|
||||
d.Q(arguments);if(h.length==0)h=d.nb(g);d.a(h,function(k){g[k]=d.u(g[k],g)});return g};d.lb=function(g,h){var k=d.Q(arguments,2);return setTimeout(function(){return g.apply(g,k)},h)};d.defer=function(g){return d.lb.apply(d,[g,1].concat(d.Q(arguments)))};d.Of=function(g,h){return function(){var k=[g].concat(d.D(arguments));return h.apply(h,k)}};d.Ie=function(){var g=d.D(arguments);return function(){for(var h=d.D(arguments),k=g.length-1;k>=0;k--)h=[g[k].apply(this,h)];return h[0]}};d.la=function(g){if(d.z(g))return d.Md(0,
|
||||
g.length);var h=[];for(var k in g)n.call(g,k)&&h.push(k);return h};d.Ab=function(g){return d.map(g,d.ka)};d.nb=function(g){return d.select(d.la(g),function(h){return d.P(g[h])}).sort()};d.extend=function(g,h){for(var k in h)g[k]=h[k];return g};d.fa=function(g){if(d.z(g))return g.slice(0);return d.extend({},g)};d.isEqual=function(g,h){if(g===h)return true;var k=typeof g;if(k!=typeof h)return false;if(g==h)return true;if(!g&&h||g&&!h)return false;if(g.isEqual)return g.isEqual(h);if(d.pd(g)&&d.pd(h))return g.getTime()===
|
||||
h.getTime();if(d.fc(g)&&d.fc(h))return true;if(d.qd(g)&&d.qd(h))return g.source===h.source&&g.global===h.global&&g.ignoreCase===h.ignoreCase&&g.multiline===h.multiline;if(k!=="object")return false;if(g.length&&g.length!==h.length)return false;k=d.la(g);var l=d.la(h);if(k.length!=l.length)return false;for(var p in g)if(!d.isEqual(g[p],h[p]))return false;return true};d.bf=function(g){return d.la(g).length==0};d.af=function(g){return!!(g&&g.nodeType==1)};d.dc=function(g){return g&&"0"<=g.length&&g.length<=
|
||||
"9"&&!d.z(g)&&!m.call(g,"length")};d.fc=function(g){return"0"<=g&&g<="9"&&isNaN(g)};d.cf=function(g){return g===null};d.K=function(g){return typeof g=="undefined"};for(var o=["Array","Date","Function","Number","RegExp","String"],q=0,w=o.length;q<w;q++)(function(){var g="[object "+o[q]+"]";d["is"+o[q]]=function(h){return j.call(h)==g}})();d.Id=function(){a.cb=b;return this};d.ka=r();d.va=function(){throw e;};var t=0;d.Hf=function(g){var h=t++;return g?g+h:h};d.Z=function(g,h){g=new Function("obj",
|
||||
"var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+g.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return h?g(h):g};d.forEach=d.a;d.Se=d.We=d.reduce;d.Te=d.reduceRight;d.filter=d.select;d.every=d.all;d.some=d.Uc;d.ac=d.jd;d.Cf=d.Q;d.hf=d.nb;function y(g,h){return h?d(g).Ob():g}d.a(d.nb(d),function(g){var h=
|
||||
d[g];c.prototype[g]=function(){i.call(arguments,this.da);return y(h.apply(d,arguments),this.db)}});d.a(["pop","push","reverse","shift","sort","splice","unshift"],function(g){var h=Array.prototype[g];c.prototype[g]=function(){h.apply(this.da,arguments);return y(this.da,this.db)}});d.a(["concat","join","slice"],function(g){var h=Array.prototype[g];c.prototype[g]=function(){return y(h.apply(this.da,arguments),this.db)}});c.prototype.Ob=function(){this.db=true;return this};c.prototype.value=function(){return this.da}})();if(typeof document.getAttribute=="undefined")document.getAttribute=v();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};if(_.K(window.jf))nglr={};if(_.K(window.Lb))angular={};if(_.K(angular.k))angular.k={};if(_.K(angular.filter))angular.filter={};
|
||||
if(_.K(window.console))window.console={log:v(),error:v()};if(_.K(nglr.alert))nglr.alert=function(){console.log(arguments);window.alert.apply(window,arguments)};nglr.Qb=function(a,b){var c=document.createElement("div");c.className=a;for(var e=a="",d=0;d<b.length;d++){var f=b[d];a+=e+(typeof f=="string"?f:nglr.m(f));e=" "}c.appendChild(document.createTextNode(a));nglr.hb.appendChild(c)};nglr.gc=function(a){return a&&a.tagName&&a.nodeName&&a.ownerDocument&&a.removeAttribute};
|
||||
nglr.ec=function(a){switch(a.nodeName){case "OPTION":case "PRE":case "TITLE":return true;default:return false}};nglr.L=v();nglr.yc=function(a,b){if(nglr.ec(a))if(nglr.Fa)a.innerText=b;else a.textContent=b;else a.innerHTML=b};nglr.mb=function(a){if(!a||!a.replace)return a;return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")};nglr.hd=function(a){if(!a||!a.replace)return a;return a.replace(/</g,"<").replace(/>/g,">").replace(/\"/g,""")};
|
||||
nglr.u=function(a,b){if(!a)throw"Missing this";if(!_.P(b))throw"Missing function";return function(){return b.apply(a,arguments)}};nglr.Qd=function(a,b){return function(){for(var c=[this],e=0;e<arguments.length;e++)c.push(arguments[e]);return b.apply(a,c)}};nglr.outerHTML=function(a){var b=document.createElement("div");b.appendChild(a);var c=b.innerHTML;b.removeChild(a);return c};nglr.Td=function(a){return a.replace(/^ */,"").replace(/ *$/,"")};
|
||||
nglr.xb=function(a){var b=(""+a).toLowerCase();if(b=="f"||b=="0"||b=="false"||b=="no")a=false;return!!a};nglr.Ea=function(a,b){for(var c in a){var e=b[c],d=typeof e;if(d=="undefined")b[c]=nglr.za(nglr.m(a[c]));else d=="object"&&e.constructor!=nglr.Mb&&c.substring(0,1)!="$"&&nglr.Ea(a[c],e)}};nglr.Va=function(a,b,c){this.document=jQuery(a);this.ac=jQuery(b);this.w=c;this.location=window.location};
|
||||
nglr.Va.prototype.load=function(){ba(this);B(this,"/stylesheets/jquery-ui/smoothness/jquery-ui-1.7.1.css");B(this,"/stylesheets/nglr.css");console.log("Server: "+this.w.C);jQuery.Id();nglr.Fa=jQuery.xe.Fa;ca(this);var a=this.w;if(!a.X){var b=a.C.match(/https?:\/\/([\w]*)/);a.X=b?b[1]:"$MEMORY"}da(this)};
|
||||
function ca(){console.log("Loader.configureJQueryPlugins()");jQuery.b.removeNode=function(){var a=this.i(0);a.parentNode.removeChild(a)};jQuery.b.scope=function(){for(var a=this;a&&a.i(0);){var b=a.data("scope");if(b)return b;a=a.parent()}return null};jQuery.b.Je=function(){return this.data("controller")||nglr.ba.od}}nglr.Va.prototype.Vd=function(){return""+(new Date).getTime()};
|
||||
function da(a){function b(){j.Yb(function(q){!q&&e.find("[ng-auth=eager]").length&&j.Da()})}console.log("Loader.bindHtml()");var c=new nglr.Hb(a.location),e=a.document,d=new nglr.Qc(a.w.C,a.w.X),f=new nglr.g(e[0],d,c,a.w);d.Jd=nglr.Qd(f,f.j);d=new nglr.M(e.find("body"),a.w.C);var i=a.w.X=="$MEMORY"?new nglr.ta(a.window):new nglr.Gb(a.w.C,jQuery.$b);i=new nglr.Jb(i,new nglr.$a(jQuery(e.body)),function(){f.c()});var j=new nglr.Ib(i,d),n="/data/"+a.w.X,m=new nglr.p(function(q,w){i.oa("POST",n,q,w)},
|
||||
j,f.anchor);f.Cc.push(function(){C(m)});var o=new nglr.h({ce:f.anchor,de:f,ee:a.w,fe:window.console,ge:m,sa:function(q){ea(m,o.I,q,f.anchor)},me:window,ke:a.Vd,le:j},"ROOT");jQuery.a(["get","set","eval","addWatchListener","updateView"],function(q,w){angular[w]=nglr.u(o,o[w])});e.data("scope",o);console.log("$binder.entity()");f.ha(o);console.log("$binder.compile()");f.compile();console.log("ControlBar.bind()");d.u();console.log("$users.fetchCurrentUser()");b();console.log("PopUp.bind()");(new nglr.A(e)).u();
|
||||
console.log("$binder.parseAnchor()");D(f);console.log("$binder.executeInit()");fa(f);console.log("$binder.updateView()");f.c();c.ic=nglr.u(f,f.Ld,c);c.kf=function(){nglr.alert("update")};c.watch();e.find("body").wb();console.log("ready()")}
|
||||
function ba(){var a=window.location.href+"#";a=a.split("#")[1];var b={dd:null};a=a.split("&");for(var c=0;c<a.length;c++){var e=(a[c]+"=").split("=");b[e[0]]=e[1]}if(b.dd=="console"){nglr.hb=document.createElement("div");nglr.hb.id="ng-console";document.getElementsByTagName("body")[0].appendChild(nglr.hb);console.log=function(){nglr.Qb("ng-console-info",arguments)};console.error=function(){nglr.Qb("ng-console-error",arguments)}}}
|
||||
function B(a,b){var c=document.createElement("link");c.rel="stylesheet";c.type="text/css";b.match(/^http:/)||(b=a.w.C+b);c.href=b;a.ac[0].appendChild(c)}nglr.Hb=function(a){this.location=a;this.lb=25;this.setTimeout=function(b,c){window.setTimeout(b,c)};this.ic=r();this.ia=a.href};
|
||||
nglr.Hb.prototype.watch=function(){var a=this;function b(){if(a.ia!==a.location.href){var c=a.location.hash.match(/^#\$iframe_notify=(.*)$/);if(c){a.ia.match(/#/)||(a.ia+="#");a.location.href=a.ia;c="_iframe_notify_"+c[1];var e=nglr[c];delete nglr[c];try{(e||nglr.L)()}catch(d){nglr.alert(d)}}else{a.ic(a.location.href);a.ia=a.location.href}}a.setTimeout(b,a.lb)}b()};angular.aa={Ud:function(a){var b=typeof a;switch(b){case "object":if(a===null)return"null";if(a instanceof Array)return"array";if(a instanceof Date)return"date";if(a.nodeType==1)return"element"}return b}};angular.Sa={};angular.Nc={};
|
||||
angular.La={md:function(a,b,c){var e=_.indexOf(a,b);if(c)e==-1&&a.push(b);else a.splice(e,1);return a},Bf:function(a,b){b=angular.$.compile(b);for(var c=0,e=0;e<a.length;e++){var d=1*b(a[e]);isNaN(d)||(c+=d)}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 e=angular.$.compile(b);_.Ub(a,function(d){if(e(d)){c=d;return true}});return c}},Pe:function(a,b){return angular.La.find(a,function(c){return c.R==b},null)},filter:function(a,b){var c=
|
||||
[];c.Zc=function(m){for(var o=0;o<c.length;o++)if(!c[o](m))return false;return true};var e=nglr.h.ja;function d(m,o){if(o.charAt(0)==="!")return!d(m,o.substr(1));switch(typeof m){case "boolean":case "number":case "string":return(""+m).toLowerCase().indexOf(o)>-1;case "object":for(var q in m)if(q.charAt(0)!=="$"&&d(m[q],o))return true;return false;case "array":for(q=0;q<m.length;q++)if(d(m[q],o))return true;return false;default:return false}}switch(typeof b){case "boolean":case "number":case "string":b=
|
||||
{be:b};case "object":for(var f in b)f=="$"?function(){var m=(""+b[f]).toLowerCase();m&&c.push(function(o){return d(o,m)})}():function(){var m=f,o=(""+b[f]).toLowerCase();o&&c.push(function(q){return d(e(q,m),o)})}();break;case "function":c.push(b);break;default:return a}for(var i=[],j=0;j<a.length;j++){var n=a[j];c.Zc(n)&&i.push(n)}return i},add:function(a,b){a.push(_.K(b)?{}:b);return a},Ke:function(a,b){if(!b)return a.length;var c=angular.$.compile(b);return _.reduce(a,0,function(e,d){return e+
|
||||
(c(d)?1:0)})},lf:function(a,b,c){function e(f,i){return nglr.xb(i)?function(j,n){return f(n,j)}:f}function d(f,i){var j=typeof f,n=typeof i;if(j==n){if(j=="string")f=f.toLowerCase();if(j=="string")i=i.toLowerCase();if(f===i)return 0;return f<i?-1:1}else return j<n?-1:1}b=_.z(b)?b:[b];b=_.map(b,function(f){var i=false;if(typeof f=="string"&&(f.charAt(0)=="+"||f.charAt(0)=="-")){i=f.charAt(0)=="-";f=f.substring(1)}var j=f?angular.$.compile(f):_.ka;return e(function(n,m){return d(j(n),j(m))},i)});return _.fa(a).sort(e(function(f,
|
||||
i){for(var j=0;j<b.length;j++){var n=b[j](f,i);if(n!=0)return n}return 0},c))},nf:function(a,b){var c=false,e=-1;_.Ub(a,function(d,f){if(d==b){c=true;e=f;return true}if((d.charAt(0)=="+"||d.charAt(0)=="-")&&d.substring(1)==b){c=d.charAt(0)=="+";e=f;return true}});e>=0&&a.splice(e,1);a.unshift((c?"-":"+")+b);return a},mf:function(a,b,c,e){c=c||"ng-ascend";e=e||"ng-descend";a=a[0]||"";var d=true;if(a.charAt(0)=="-"){a=a.substring(1);d=false}else if(a.charAt(0)=="+")a=a.substring(1);return a==b?d?c:
|
||||
e:""},Ea:function(a,b,c){var e=a[b];if(!e){e={};a[b]=e}nglr.Ea(c,e);return a}};
|
||||
angular.U={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")+'"'},tc:function(a){a=angular.U.quote(a);for(var b=[],c=0;c<a.length;c++){var e=a.charCodeAt(c);if(e<128)b.push(a.charAt(c));else{e="000"+e.toString(16);b.push("\\u"+e.substring(e.length-4))}}return b.join("")},Sd: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}};angular.Jc={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"}};angular.$={compile:function(a){if(_.P(a))return a;else if(a){var b=new nglr.h;return function(c){b.I=c;return b.eval(a)}}else return r()}};
|
||||
(function(){function a(b,c,e){_.extend(b,c);_.a(e||[],function(d){b[d]=_[d]})}a(angular.aa,{},["extend","clone","isEqual","isElement","isArray","isFunction","isUndefined"]);a(angular.Sa,angular.aa,["each","map","reduce","reduceRight","detect","select","reject","all","any","include","invoke","pluck","max","min","sortBy","sortedIndex","toArray","size"]);a(angular.La,angular.Sa,["first","last","compact","flatten","without","uniq","intersect","zip","indexOf","lastIndexOf"]);a(angular.Nc,angular.Sa,["keys",
|
||||
"values"]);a(angular.U,angular.aa);a(angular.$,angular.aa,["bind","bindAll","delay","defer","wrap","compose"])})();nglr.g=function(a,b,c,e){this.F=a;this.Lf=c;this.anchor={};this.$d=b;this.w=e||{};this.Cc=[]};nglr.g.Ha=function(a){for(var b=[],c=0,e;(e=a.indexOf("{{",c))>-1;){c<e&&b.push(a.substr(c,e-c));c=e;e=a.indexOf("}}",e);e=e<0?a.length:e+2;b.push(a.substr(c,e-c));c=e}c!=a.length&&b.push(a.substr(c,a.length-c));return b.length===0?[a]:b};nglr.g.ld=function(a){a=nglr.g.Ha(a);return a.length>1||nglr.g.ea(a[0])!==null};nglr.g.ea=function(a){return(a=a.replace(/\n/gm," ").match(/^\{\{(.*)\}\}$/))?a[1]:null};
|
||||
function ga(a,b){var c={};b.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,function(e,d,f){if(d)c[decodeURIComponent(d)]=decodeURIComponent(f)});return c}function D(a,b){b=b||window.location.href;var c=b.indexOf("#");if(!(c<0)){b=b.substring(c+1);b=ga(a,b);jQuery.a(a.anchor,function(e){delete a.anchor[e]});jQuery.a(b,function(e,d){a.anchor[e]=d})}}nglr.g.prototype.Ld=function(a){console.log("URL change detected",a);D(this,a);this.c()};
|
||||
function ha(a){var b=window.location.href,c=b.indexOf("#");if(c>-1)b=b.substring(0,c);b+="#";c="";for(var e in a.anchor){var d=a.anchor[e];if(typeof d==="undefined"||d===null)delete a.anchor[e];else{b+=c+encodeURIComponent(e);if(d!==true)b+="="+encodeURIComponent(d);c="&"}}a=b;e=window.location.href;e.match(/#/)||(e+="#");if(e!=a)window.location.href=a;self.Oe=a;return b}
|
||||
nglr.g.prototype.c=function(){(new Date).getTime();var a=jQuery(this.F).scope();E(a,"$invalidWidgets",[]);a.c();(new Date).getTime();ha(this);_.a(this.Cc,function(b){b()})};function fa(a){jQuery("[ng-init]",a.F).a(function(){var b=jQuery(this),c=b.scope();try{c.eval(b.e("ng-init"))}catch(e){nglr.alert("EVAL ERROR:\n"+b.e("ng-init")+"\n"+nglr.m(e,true))}})}
|
||||
nglr.g.prototype.ha=function(a){jQuery("[ng-entity]",this.F).e("ng-watch",function(){try{var b=jQuery(this);return a.ha(b.e("ng-entity"))+(b.e("ng-watch")||"")}catch(c){nglr.alert(c)}})};
|
||||
nglr.g.prototype.compile=function(){var a=jQuery(this.F),b=this;if(this.w.Xc){var c=jQuery(":submit",this.F).rc("[ng-action]");c.e("ng-action","$save()");c.rc(":disabled").rc("ng-bind-attr").e("ng-bind-attr",'{disabled:"{{$invalidWidgets}}"}')}F(this,this.F)(this.F,a.scope(),"");jQuery("a[ng-action]",this.F).vd("click",function(){var e=jQuery(this);try{e.scope().eval(e.e("ng-action"));e.vc("ng-error");e.wc("ng-exception")}catch(d){e.fb("ng-exception");e.e("ng-error",nglr.m(d,true))}b.c();return false})};
|
||||
function ia(a,b,c,e){a=c.concat();c=a.pop();var d=nglr.g.Ha(b.nodeValue);if(d.length>1||nglr.g.ea(d[0])){var f=b.parentNode;if(nglr.ec(f)){f.setAttribute("ng-bind-template",b.nodeValue);e.push({path:a,b:function(o){return new nglr.S(o,o.getAttribute("ng-bind-template"))}})}else for(var i=0;i<d.length;i++){var j=d[i],n=nglr.g.ea(j),m;if(n){m=document.createElement("span");jQuery(m).e("ng-bind",n);i===0&&e.push({path:a.concat(c+i),b:nglr.g.prototype.qc})}else if(nglr.Fa&&j.charAt(0)==" "){m=document.createElement("span");
|
||||
m.innerHTML=" "+j.substring(1)}else m=document.createTextNode(j);f.insertBefore(m,b)}f.removeChild(b)}}function F(a,b){var c=[];G(a,b,[],c);return function(e,d,f){for(var i=c.length,j=0;j<i;j++){for(var n=c[j],m=e,o=n.path,q=0;q<o.length;q++)m=m.childNodes[o[q]];try{var w=n.b(m,d,f);w&&d.Ec.push(w)}catch(t){nglr.alert(t)}}}}
|
||||
function G(a,b,c,e){var d=b.nodeType;if(d==Node.TEXT_NODE)ia(a,b,c,e);else if(!(d!=Node.ELEMENT_NODE&&d!=Node.DOCUMENT_NODE))if(b.getAttribute){d=b.getAttribute("ng-non-bindable");if(!(d||d==="")){if(d=b.attributes){var f=b.getAttribute("ng-bind-attr");b.removeAttribute("ng-bind-attr");f=f?nglr.za(f):{};for(var i=d.length,j=0;j<i;j++){var n=d[j],m=n.name;n=nglr.Fa&&m=="href"?decodeURI(b.getAttribute(m,2)):n.value;if(nglr.g.ld(n))f[m]=n}d=nglr.m(f);d.length>2&&b.setAttribute("ng-bind-attr",d)}b.getAttribute||
|
||||
console.log(b);var o=b.getAttribute("ng-repeat");if(o){b.removeAttribute("ng-repeat");var q=F(a,b);d=document.createComment("ng-repeat: "+o);f=b.parentNode;f.insertBefore(d,b);f.removeChild(b);var w=function(t,y,g){var h=jQuery(b).fa();h.kb("display","");h.e("ng-repeat-index",""+g);h.data("scope",t);q(h[0],t,y+g+":");return h};e.push({path:c,b:function(t,y,g){return new nglr.Xa(jQuery(t),o,w,g)}})}else{b.getAttribute("ng-eval")&&e.push({path:c,b:a.Dd});b.getAttribute("ng-bind")&&e.push({path:c,b:a.qc});
|
||||
b.getAttribute("ng-bind-attr")&&e.push({path:c,b:a.zd});b.getAttribute("ng-hide")&&e.push({path:c,b:a.Ed});b.getAttribute("ng-show")&&e.push({path:c,b:a.Fd});b.getAttribute("ng-class")&&e.push({path:c,b:a.Ad});b.getAttribute("ng-class-odd")&&e.push({path:c,b:a.Cd});b.getAttribute("ng-class-even")&&e.push({path:c,b:a.Bd});b.getAttribute("ng-style")&&e.push({path:c,b:a.Gd});b.getAttribute("ng-watch")&&e.push({path:c,b:a.Hd});d=b.nodeName;if(d=="INPUT"||d=="TEXTAREA"||d=="SELECT"||d=="BUTTON")e.push({path:c,
|
||||
b:function(t,y,g){t.name=g+t.name.split(":").pop();return ja(a.$d,jQuery(t),y)}});if(d=="OPTION")if(!jQuery("<select/>").append(jQuery(b).fa()).B().match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi))b.value=b.text;d=b.childNodes;for(f=0;f<d.length;f++)G(a,d[f],c.concat(f),e)}}}}A=nglr.g.prototype;A.Dd=function(a){return new nglr.Ta(a,a.getAttribute("ng-eval"))};A.qc=function(a){return new nglr.S(a,"{{"+a.getAttribute("ng-bind")+"}}")};A.zd=function(a){return new nglr.Ma(a,nglr.za(a.getAttribute("ng-bind-attr")))};
|
||||
A.Ed=function(a){return new nglr.Ua(a,a.getAttribute("ng-hide"))};A.Fd=function(a){return new nglr.Za(a,a.getAttribute("ng-show"))};A.Ad=function(a){return new nglr.Ra(a,a.getAttribute("ng-class"))};A.Bd=function(a){return new nglr.Pa(a,a.getAttribute("ng-class-even"))};A.Cd=function(a){return new nglr.Qa(a,a.getAttribute("ng-class-odd"))};A.Gd=function(a){return new nglr.ab(a,a.getAttribute("ng-style"))};A.Hd=function(a,b){b.watch(a.getAttribute("ng-watch"))};nglr.M=function(a,b){this.document=a;this.Ja=b;this.window=window;this.W=[]};nglr.M.prototype.u=v();nglr.M.ne='<div><div class="ui-widget-overlay"></div><div id="ng-login" ng-non-bindable="true"><div class="ng-login-container"></div></div></div>';nglr.M.prototype.Da=function(a){this.W.push(a);this.W.length==1&&H(this,"/user_session/new.mini?return_url="+encodeURIComponent(this.window.location.href.split("#")[0]))};nglr.M.prototype.oc=function(a){this.W.push(a);this.W.length==1&&H(this,"/user_session/do_destroy.mini")};
|
||||
function H(a,b){var c=(new Date).getTime(),e=a.window.location.href.split("#")[0];e+="#$iframe_notify="+c;var d=jQuery('<div style="overflow:hidden; padding:2px 0 0 0;"><iframe name="'+e+'" src="'+a.Ja+b+'" width="500" height="330"/></div>');a.document.append(d);d.Vb({height:363,width:500,wf:false,wd:true,title:'Authentication: <a href="http://www.getangular.com"><tt><angular/></tt></a>'});nglr["_iframe_notify_"+c]=function(){d.Vb("destroy");d.remove();jQuery.a(a.W,function(f,i){i()});a.W=[]}}
|
||||
nglr.M.Lc='<div ng-non-bindable="true" title="Permission Error:">Sorry, you do not have permission for this!</div>';nglr.M.prototype.sb=function(){if(!this.Zb){this.Zb=jQuery(nglr.M.Lc);this.Zb.Vb({ve:true,height:70,wd:true})}};nglr.p=function(a,b,c){this.sc=a;this.Dc=b;this.V={qa:[]};this.anchor=c;this.wa=[]};function I(a,b){if(b.constructor!=nglr.N)throw"Parameter must be an instance of Entity! "+nglr.m(b);var c=b.ra+"/"+b.R,e=a.V[c];if(e)nglr.N.jb(b,e);else e=a.V[c]=b;return e}nglr.p.prototype.load=function(a,b,c,e){if(b&&b!=="*"){var d=this;J(this,["GET",a.ra+"/"+b],function(f){K(a,f);L(a);f=a.pa(a);I(d,f);(c||nglr.L)(a)},e)}return a};
|
||||
nglr.p.prototype.pb=function(a,b,c){var e=this,d=[],f=0;jQuery.a(b,function(i,j){d.push(e.load(a(),j,function(){f++;if(f==b.length)(c||nglr.L)(d)}))});return d};nglr.p.prototype.kc=function(a,b,c){return this.load(a,b,c,function(e){if(e.Ka==404){a.R=b;(c||nglr.L)(a)}else throw e;})};function ka(a,b,c){var e=[];e.Cb=function(d){return d.ra==b.title};a.V.qa.push(e);J(a,["GET",b.title],function(d){for(var f=0;f<d.length;f++){var i=b();K(i,d[f]);e.push(I(a,i))}(c||nglr.L)(e)});return e}
|
||||
nglr.p.prototype.save=function(a,b){var c=this,e={};M(a,e);J(this,["POST","",e],function(d){K(a,d);var f=I(c,a);_.a(c.V.qa,function(i){i.Cb(a)&&angular.La.md(i,f,true)});if(a.Db)c.anchor[a.Db]=a.R;b&&b(a)})};nglr.p.prototype.remove=function(a,b){var c=this,e={};M(a,e);J(this,["DELETE","",e],function(d){delete c.V[a.ra+"/"+a.R];_.a(c.V.qa,function(f){for(var i=0;i<f.length;i++)f[i].R==a.R&&f.splice(i,1)});(b||nglr.L)(d)})};function J(a,b,c,e){b.Fc=c;b.Hc=e||function(d){throw d;};a.wa.push(b)}
|
||||
function C(a){function b(d,f){console.log("RESPONSE["+d+"]: ",f);if(f.Ka==401)c.Dc.Da(function(){c.sc(e,b)});else if(f.Ka)nglr.alert(nglr.m(f));else for(var i=0;i<f.length;i++){var j=f[i],n=e[i];if(d=j.Ka)d==403?c.Dc.sb():n.Hc(j);else n.Fc(j)}}if(a.wa.length!==0){var c=a,e=a.wa;a.wa=[];console.log("REQUEST:",e);a.sc(e,b)}}function ea(a,b,c){function e(){d--;d===0&&c&&c()}var d=1;for(var f in b)if((a=b[f])&&a.sa==nglr.N.prototype.sa){d++;a.sa(e)}e()}
|
||||
nglr.p.prototype.ma=function(a,b,c,e){var d=this,f=[];f.Cb=z(false);this.V.qa.push(f);J(this,["GET",a.title+"/"+b+"="+c],function(i){for(var j=0;j<i.length;j++){var n=K(new a,i[j]);f.push(I(d,n))}e&&e(f)});return f};nglr.p.ca=v();nglr.p.ca.all=function(){return[]};nglr.p.ca.ma=function(){return[]};nglr.p.ca.load=function(){return{}};nglr.p.ca.title=undefined;
|
||||
nglr.p.prototype.ha=function(a,b){if(!a)return nglr.p.ca;var c=this;function e(d){return new nglr.N(e,d)}e.title=a;e.Gc=true;e.Tb=this;e.ed=b||{};e.load=function(d,f){return c.load(e(),d,f)};e.pb=function(d,f){return c.pb(e,d,f)};e.kc=function(d,f){return c.kc(e(),d,f)};e.all=function(d){return ka(c,e,d)};e.ma=function(d,f,i){return c.ma(e,d,f,i)};e.tf=function(d){J(c,["GET",a+"/$properties"],d)};return e};
|
||||
nglr.p.prototype.join=function(a){function b(){throw"Joined entities can not be instantiated into a document.";}var c=_(a).Ob().map(function(e,d){return d}).Rd(function(e){var d=[];do{if(_(d).Aa(e))throw"Infinite loop in join: "+d.join(" -> ");d.push(e);if(!a[e])throw _("Named entity '<%=name%>' is undefined.").Z({name:e});e=a[e].Ga?a[e].Ga.substring(0,a[e].Ga.indexOf(".")):undefined}while(e);return d.length}).value();if(_(c).select(function(e){return a[e].Ga}).length!=c.length-1)throw"Exactly one entity needs to be primary.";
|
||||
b.ma=function(e,d){var f=[],i=e?e.substring(0,e.indexOf(".")):undefined;if(i!=c[0])throw _("Named entity '<%=name%>' is not a primary entity.").Z({name:i});var j=1;a[i].join.ma(e.substring(e.indexOf(".")+1),d,function(n){var m=c[j++],o=a[m],q=o.Ga,w={};_(n).a(function(t){var y={};f.push(y);y[i]=t;t=nglr.h.ja(y,q);w[t]=t});o.join.pb(_.D(w),function(t){var y={};_(t).a(function(g){y[g.R]=g});_(f).a(function(g){var h=nglr.h.ja(g,q);g[m]=y[h]})})});return f};return b};angular.filter.s=function(a){if(a)for(var b in a)this[b]=a[b]};angular.filter.s.i=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}};angular.filter.Le=function(a){jQuery(this.element).zb("ng-format-negative",a<0);return"$"+angular.filter.tb.apply(this,[a,2])};
|
||||
angular.filter.tb=function(a,b){if(isNaN(a)||!isFinite(a))return"";b=typeof b=="undefined"?2:b;var c=a<0;a=Math.abs(a);var e=Math.pow(10,b);a=""+Math.round(a*e);var d=a.substring(0,a.length-b);d=d||"0";e=a.substring(a.length-b);a=c?"-":"";for(c=0;c<d.length;c++){if((d.length-c)%3===0&&c!==0)a+=",";a+=d.charAt(c)}if(b>0){for(c=e.length;c<b;c++)e+="0";a+="."+e.substring(0,b)}return a};angular.filter.bd=v();angular.filter.rd=function(a){jQuery(this.element).fb("ng-monospace");return nglr.m(a,true)};
|
||||
angular.filter.Ac=function(a,b){a=nglr.Td(a);for(var c=a.replace(/ /g,""),e=angular.filter.Ac.Mc,d=0;d<e.length;d++)for(var f=e[d],i=0;i<f.na.length;i++)if(f.na[i].test(c)){b=f.name+": "+a;f=f.url+a;return new angular.filter.s({text:b,url:f,B:'<a href="'+nglr.hd(f)+'">'+b+"</a>",Ef:a})}return a?b||new angular.filter.s({text:a+" is not recognized"}):null};
|
||||
angular.filter.Ac.Mc=[{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]}];
|
||||
angular.filter.link=function(a,b){b=b||angular.filter.s.i(a);var c=angular.filter.s.i(a,"url")||angular.filter.s.i(a);if(c){if(angular.k.gd(c)===null)c="mailto:"+c;a='<a href="'+nglr.mb(c)+'">'+b+"</a>";return new angular.filter.s({text:b,url:c,B:a})}return a};angular.filter.gb=function(a){if(a===null)return"";for(var b=0;a>1E3;){a/=1024;b++}a=""+a;var c=a.indexOf(".");if(c>-1&&c+2<a.length)a=a.substring(0,c+2);return a+" "+angular.filter.gb.Pc[b]};
|
||||
angular.filter.gb.Pc=["bytes","KB","MB","GB","TB","PB"];angular.filter.Ve=function(a,b,c){if(a&&a.url){var e="";if(b)e=' style="max-width: '+b+"px; max-height: "+(c||b)+'px;"';return new angular.filter.s({url:a.url,text:a.url,B:'<img src="'+a.url+'"'+e+"/>"})}return null};angular.filter.ff=function(a){return(a=angular.filter.s.i(a))?(""+a).toLowerCase():a};angular.filter.Kf=function(a){return(a=angular.filter.s.i(a))?(""+a).toUpperCase():a};
|
||||
angular.filter.ef=function(a){a=angular.filter.s.i(a);if(a===""||!a)return 1;return a.split(/\n|\f/).length};angular.filter["if"]=function(a,b){return b?a:undefined};angular.filter.If=function(a,b){return b?undefined:a};angular.filter.l=function(a,b,c,e){b=b||{};var d=angular.filter.l;a={$c:a,ze:d.Pb(b,"color"),Fe:d.title(b),Be:d.Pb(b,"label"),Ae:d.Ab(b),Ce:"bg,s,FFFFFF00"};if(_.z(b.ae)){a.He="x";a.Ge="0:|"+b.ae.join("|")}return angular.filter.l.Wb(a,c,e)};
|
||||
angular.filter.l.Ab=function(a){var b=[];_.a(a.Pd||[],function(c){var e=[];_.a(c.Ab||[],function(d){e.push(d)});b.push(e.join(","))});a=b.join("|");return a===""?null:"t:"+a};angular.filter.l.title=function(a){var b=[];a=a.title||[];_.a(_.z(a)?a:[a],function(c){b.push(encodeURIComponent(c))});return b.join("|")};
|
||||
angular.filter.l.Pb=function(a,b){var c=[],e=0;_.a(a.Pd||[],function(d){var f=[];d=d[b]||[];_.a(_.z(d)?d:[d],function(i){f.push(encodeURIComponent(i));e++});c.push(f.join("|"))});return e?c.join(","):null};angular.filter.l.Wb=function(a,b,c){b=b||200;c=c||b;var e="http://chart.apis.google.com/chart?",d=[];a.Ee=b+"x"+c;for(var f in a){var i=a[f];i&&d.push(f+"="+i)}d.sort();e+=d.join("&");return new angular.filter.s({url:e,text:i,B:'<img width="'+b+'" height="'+c+'" src="'+e+'"/>'})};
|
||||
angular.filter.uf=function(a,b,c){return angular.filter.l.Wb({$c:"qr",De:encodeURIComponent(a)},b,c)};
|
||||
angular.filter.ye={qf:function(a,b,c){return angular.filter.l("p",a,b,c)},rf:function(a,b,c){return angular.filter.l("p3",a,b,c)},sf:function(a,b,c){return angular.filter.l("pc",a,b,c)},se:function(a,b,c){return angular.filter.l("bhs",a,b,c)},re:function(a,b,c){return angular.filter.l("bhg",a,b,c)},ue:function(a,b,c){return angular.filter.l("bvs",a,b,c)},te:function(a,b,c){return angular.filter.l("bvg",a,b,c)},df:function(a,b,c){return angular.filter.l("lc",a,b,c)},zf:function(a,b,c){return angular.filter.l("ls",
|
||||
a,b,c)},xf:function(a,b,c){return angular.filter.l("s",a,b,c)}};angular.filter.B=function(a){return new angular.filter.s({B:a})};nglr.Mb=[].constructor;nglr.m=function(a,b){var c=[];nglr.yb(c,a,b?"\n ":null);return c.join("")};nglr.Df=function(a){return nglr.m(a,true)};nglr.za=function(a){try{var b=new nglr.q(a,true),c=N(b);O(b);return c()}catch(e){console.error("fromJson error: ",a,e);throw e;}};
|
||||
nglr.yb=function(a,b,c){var e=typeof b;if(b===null)a.push("null");else if(e!=="function")if(e==="boolean")a.push(""+b);else if(e==="number")isNaN(b)?a.push("null"):a.push(""+b);else if(e==="string")return a.push(angular.U.tc(b));else if(e==="object")if(b instanceof Array){a.push("[");var d=b.length;e=false;for(var f=0;f<d;f++){var i=b[f];e&&a.push(",");typeof i=="function"||typeof i=="undefined"?a.push("null"):nglr.yb(a,i,c);e=true}a.push("]")}else if(b instanceof Date)a.push(angular.U.tc(angular.Jc.toString(b)));
|
||||
else{a.push("{");c&&a.push(c);e=false;f=c?c+" ":false;i=[];for(var j in b)j.indexOf("$$")!==0&&i.push(j);i.sort();for(j=0;j<i.length;j++){var n=i[j];try{d=b[n];if(typeof d!="function"){if(e){a.push(",");c&&a.push(c)}a.push(angular.U.quote(n));a.push(":");nglr.yb(a,d,f);e=true}}catch(m){}}a.push("}")}};nglr.N=function(a,b){this.pa=a;K(this,b||{});this.ra=a.title;L(this)};nglr.N.jb=function(a,b){if(!(a===b||!a||!b)){var c=function(d,f,i){return i.substring(0,2)!=="$$"&&typeof d[i]!=="function"&&typeof f[i]!=="function"};for(var e in b)c(a,b,e)&&delete b[e];for(e in a)if(c(a,b,e))b[e]=a[e]}};function L(a){nglr.Ea(a.pa.ed,a);return a}nglr.N.prototype.sa=function(a){this.pa.Tb.save(this,a===true?undefined:a);a===true&&C(this.pa.Tb);return this};function K(a,b){nglr.N.jb(b,a);return a}
|
||||
function M(a,b){nglr.N.jb(a,b);return a};nglr.J=function(a,b){this.text=a;this.cd=b?20:-1;this.o=[];this.index=0};
|
||||
nglr.J.Eb={"null":z(null),"true":z(true),"false":z(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 E(a.scope,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}};nglr.J.prototype.Y=function(){return this.index+1<this.text.length?this.text.charAt(this.index+1):false};
|
||||
nglr.J.prototype.parse=function(){for(var a=this.o,b=nglr.J.Eb,c=true;this.index<this.text.length;){var e=this.text.charAt(this.index);if(e=='"'||e=="'"){la(this,e);c=true}else if(e=="("||e=="["){a.push({index:this.index,text:e});this.index++}else if(e=="{"){c=this.Y();if(c==":"||c=="("){a.push({index:this.index,text:e+c});this.index++}else a.push({index:this.index,text:e});this.index++;c=true}else if(e==")"||e=="]"||e=="}"){a.push({index:this.index,text:e});this.index++;c=false}else if(e==":"||e==
|
||||
"."||e==","||e==";"){a.push({index:this.index,text:e});this.index++;c=true}else if(c&&e=="/"){ma(this);c=false}else if("0"<=e&&e<="9"){na(this);c=false}else if(P(this,e)){Q(this);c=false}else if(e==" "||e=="\r"||e=="\t"||e=="\n"||e=="\u000b")this.index++;else{c=e+this.Y();var d=b[e],f=b[c];if(f){a.push({index:this.index,text:c,b:f});this.index+=2}else if(d){a.push({index:this.index,text:e,b:d});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};function P(a,b){return"a"<=b&&b<="z"||"A"<=b&&b<="Z"||"_"==b||b=="$"}function na(a){for(var b="",c=a.index;a.index<a.text.length;){var e=a.text.charAt(a.index);if(e=="."||"0"<=e&&e<="9")b+=e;else break;a.index++}b=1*b;a.o.push({index:c,text:b,b:function(){return b}})}
|
||||
function Q(a){for(var b="",c=a.index;a.index<a.text.length;){var e=a.text.charAt(a.index);if(e=="."||P(a,e)||"0"<=e&&e<="9")b+=e;else break;a.index++}e=nglr.J.Eb[b];if(!e){e=function(d){return d.scope.i(b)};e.Ba=b}a.o.push({index:c,text:b,b:e})}nglr.J.Kc={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'};
|
||||
function la(a,b){var c=a.index,e=a.cd;a.index++;for(var d="",f=false;a.index<a.text.length;){var i=a.text.charAt(a.index);if(f){if(i=="u"){i=a.text.substring(a.index+1,a.index+5);a.index+=4;d+=String.fromCharCode(parseInt(i,16))}else{f=nglr.J.Kc[i];d+=f?f:i}f=false}else if(i=="\\")f=true;else if(i==b){a.index++;a.o.push({index:c,text:d,b:function(){return d.length==e?angular.U.Sd(d):d}});return}else d+=i;a.index++}throw"Lexer Error: Unterminated quote ["+a.text.substring(c)+"] starting at column '"+
|
||||
(c+1)+"' in expression '"+a.text+"'.";}
|
||||
function ma(a){var b=a.index;a.index++;for(var c="",e=false;a.index<a.text.length;){var d=a.text.charAt(a.index);if(e){c+=d;e=false}else if(d==="\\"){c+=d;e=true}else if(d==="/"){a.index++;e="";if(P(a,a.text.charAt(a.index))){Q(a);e=a.o.pop().text}var f=new RegExp(c,e);a.o.push({index:b,text:c,Qe:e,b:function(){return f}});return}else c+=d;a.index++}throw"Lexer Error: Unterminated RegExp ["+a.text.substring(b)+"] starting at column '"+(b+1)+"' in expression '"+a.text+"'.";}
|
||||
nglr.q=function(a,b){this.text=a;this.o=(new nglr.J(a,b)).parse();this.index=0};nglr.q.Rc=z(0);nglr.q.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)+"'.";};function R(a){if(a.o.length===0)throw"Unexpected end of expression: "+a.text;return a.o[0]}nglr.q.prototype.Y=function(a,b,c,e){var d=this.o;if(d.length>0){d=d[0];var f=d.text;if(f==a||f==b||f==c||f==e||!a&&!b&&!c&&!e)return d}return false};
|
||||
function S(a,b,c,e,d){if(b=a.Y(b,c,e,d)){a.o.shift();return a.Me=b}return false}function T(a,b){if(!S(a,b)){var c=a.Y();throw"Expecting '"+b+"' at column '"+(c.index+1)+"' in '"+a.text+"' got '"+a.text.substring(c.index)+"'.";}}function oa(a,b,c){var e=c.apply(a);return function(d){return b(d,e(d))}}function U(a,b,c,e){var d=e.apply(a);return function(f){return c(f,b(f),d(f))}}
|
||||
function O(a){if(a.o.length!==0)throw"Did not understand '"+a.text.substring(a.o[0].index)+"' while evaluating '"+a.text+"'.";}function V(a){for(var b=[];;){a.o.length>0&&!a.Y("}",")",";","]")&&b.push(W(a));if(!S(a,";"))return function(c){for(var e,d=0;d<b.length;d++){var f=b[d];if(f)e=f(c)}return e}}}function W(a){for(var b=a.G(),c;;)if(c=S(a,"|"))b=U(a,b,c.b,a.filter);else return b}nglr.q.prototype.filter=function(){return X(this,angular.filter)};nglr.q.prototype.k=function(){return X(this,angular.k)};
|
||||
function X(a,b){for(var c=pa(a,b),e=[];;)if(S(a,":"))e.push(a.G());else{var d=function(f,i){i=[i];for(var j=0;j<e.length;j++)i.push(e[j](f));return c.apply(f,i)};return function(){return d}}}nglr.q.prototype.G=function(){return qa(this)};function qa(a){if(S(a,"throw")){var b=Y(a);return function(c){throw b(c);}}else return Y(a)}
|
||||
function Y(a){var b=a.nc(),c;if(c=S(a,"=")){if(!b.Ba)throw"Left hand side '"+a.text.substring(0,c.index)+"' of assignment '"+a.text.substring(c.index)+"' is not assignable.";return U(a,function(){return b.Ba},c.b,a.nc)}else return b}A=nglr.q.prototype;A.nc=function(){for(var a=this.mc(),b;;)if(b=S(this,"||"))a=U(this,a,b.b,this.mc);else return a};A.mc=function(){for(var a=this.pc(),b;;)if(b=S(this,"&&"))a=U(this,a,b.b,this.pc);else return a};
|
||||
A.pc=function(){var a;return(a=S(this,"!"))?oa(this,a.b,this.Xb):this.Xb()};A.Xb=function(){for(var a=this.uc(),b;;)if(b=S(this,"==","!="))a=U(this,a,b.b,this.uc);else return a};A.uc=function(){for(var a=this.Kb(),b;;)if(b=S(this,"<",">","<=",">="))a=U(this,a,b.b,this.Kb);else return a};A.Kb=function(){for(var a=this.rb(),b;b=S(this,"+","-");)a=U(this,a,b.b,this.rb);return a};A.rb=function(){for(var a=this.Bc(),b;b=S(this,"*","/","%");)a=U(this,a,b.b,this.Bc);return a};
|
||||
A.Bc=function(){var a;return S(this,"+")?N(this):(a=S(this,"-"))?U(this,nglr.q.Rc,a.b,this.rb):N(this)};function pa(a,b){var c=S(a),e=c.text.split(".");b=b;for(var d,f=0;f<e.length;f++){d=e[f];if(b)b=b[d]}if(typeof b!="function")throw"Function '"+c.text+"' at column '"+(c.index+1)+"' in '"+a.text+"' is not defined.";return b}
|
||||
function N(a){var b;if(S(a,"(")){b=W(a);T(a,")");b=b}else if(S(a,"["))b=ra(a);else if(S(a,"{"))b=a.object();else if(S(a,"{:"))b=sa(a,false);else if(S(a,"{("))b=sa(a,true);else{var c=S(a);(b=c.b)||a.error("not a primary expression",c)}for(;c=S(a,"(","[",".");)if(c.text==="(")b=ta(a,b);else if(c.text==="[")b=ua(a,b);else if(c.text===".")b=va(a,b);else throw"IMPOSSIBLE";return b}
|
||||
function sa(a,b){var c=[];if(b){if(!S(a,")")){for(c.push(S(a).text);S(a,",");)c.push(S(a).text);T(a,")")}T(a,":")}var e=V(a);T(a,"}");return function(d){return function(f){var i=new nglr.h(d.scope.I);E(i,"$",f);for(var j=0;j<c.length;j++)E(i,c[j],arguments[j]);return e({scope:i})}}}function va(a,b){var c=S(a).text;function e(d){return nglr.h.ja(b(d),c)}e.Ba=c;return e}
|
||||
function ua(a,b){var c=a.G();T(a,"]");if(S(a,"=")){var e=a.G();return function(d){return b(d)[c(d)]=e(d)}}else return function(d){var f=b(d);d=c(d);return f?f[d]:undefined}}function ta(a,b){var c=[];if(R(a).text!=")"){do c.push(a.G());while(S(a,","))}T(a,")");return function(e){for(var d=[],f=0;f<c.length;f++)d.push(c[f](e));f=b(e);if(typeof f==="function")return f.apply(e,d);else throw"Expression '"+b.Ba+"' is not a function.";}}
|
||||
function ra(a){var b=[];if(R(a).text!="]"){do b.push(a.G());while(S(a,","))}T(a,"]");return function(c){for(var e=[],d=0;d<b.length;d++)e.push(b[d](c));return e}}nglr.q.prototype.object=function(){var a=[];if(R(this).text!="}"){do{var b=S(this).text;T(this,":");var c=this.G();a.push({sd:b,value:c})}while(S(this,","))}T(this,"}");return function(e){for(var d={},f=0;f<a.length;f++){var i=a[f],j=i.value(e);d[i.sd]=j}return d}};
|
||||
function wa(a){for(var b=[];a.o.length>0;){b.push(xa(a));S(a,";")||O(a)}return function(c){for(var e="",d=0;d<b.length;d++)e+=b[d](c);return e}}function xa(a){var b=S(a).text,c,e;if(S(a,"=")){c=b;b=S(a).text}if(S(a,":"))e=N(a)(null);return function(d){var f=d.scope.i("$datastore").ha(b,e);E(d.scope,b,f);if(c){f=f();f.Db=c;E(d.scope,c,f);return"$anchor."+c+":{"+c+"="+b+".load($anchor."+c+");"+c+".$$anchor="+angular.U.quote(c)+";};"}else return""}}
|
||||
nglr.q.prototype.watch=function(){for(var a=[];this.o.length>0;){a.push(ya(this));S(this,";")||O(this)}O(this);return function(b){for(var c=0;c<a.length;c++){var e=a[c](b);b.Sc(e.name,e.b)}}};function ya(a){var b=S(a).text;T(a,":");var c;if(R(a).text=="{"){T(a,"{");c=V(a);T(a,"}")}else c=a.G();return function(){return{name:b,b:c}}};nglr.h=function(a,b){this.Ec=[];this.Bb={};this.name=b;a=a||{};function c(){}c.prototype=a;this.I=new c;this.I.ie=a;if(b=="ROOT")this.I.je=this.I};nglr.h.ya={};nglr.h.prototype.c=function(){var a=this;za(this);_.a(this.Ec,function(b){Z(a,b,"",{},function(){this.c(a)})})};function Aa(a,b){for(a=0;a<b.length;a++){var c=b.charAt(a);if(c!="."&&!P(nglr.J.prototype,c))return false}return true}
|
||||
nglr.h.ja=function(a,b){if(!b)return a;for(var c=b.split("."),e,d=a,f=c.length,i=0;i<f;i++){e=c[i];if(!e.match(/^[\$\w][\$\w\d]*$/))throw"Expression '"+b+"' is not a valid expression for accesing variables.";if(a){d=a;a=a[e]}if(_.K(a)&&e.charAt(0)=="$"){var j=angular.aa.Ud(d);if(e=(j=angular[j.charAt(0).toUpperCase()+j.substring(1)])?j[[e.substring(1)]]:undefined)return a=_.u(e,d,d)}}if(typeof a==="function"&&!a.Gc)return nglr.u(d,a);return a};
|
||||
nglr.h.prototype.i=function(a){return nglr.h.ja(this.I,a)};function E(a,b,c){b=b.split(".");a=a.I;for(var e=0;b.length>1;e++){var d=b.shift(),f=a[d];if(!f){f={};a[d]=f}a=f}return a[b.shift()]=c}function $(a,b,c){a.eval(b+"="+nglr.m(c))}nglr.h.prototype.eval=function(a,b){var c=nglr.h.ya[a];if(!c){var e=new nglr.q(a);c=V(e);O(e);nglr.h.ya[a]=c}b=b||{};b.scope=this;return c(b)};
|
||||
function Z(a,b,c,e,d,f){try{var i=a.eval(c,e);if(b.O){b.O=false;jQuery(b.view).wc("ng-exception").vc("ng-error")}d&&d.apply(b,[i]);return true}catch(j){console.error("Eval Widget Error:",j);a=nglr.m(j,true);b.O=true;jQuery(b.view).fb("ng-exception").e("ng-error",a);f&&f.apply(b,[j,a]);return false}}nglr.h.prototype.ha=function(a){return wa(new nglr.q(a))({scope:this})};
|
||||
nglr.h.prototype.watch=function(a){var b=this;(new nglr.q(a)).watch()({scope:this,Sc:function(c,e){Ba(b,c,function(d,f){try{return e({scope:b},d,f)}catch(i){nglr.alert(i)}})}})};function Ba(a,b,c){var e=a.Bb[b];if(!e){e={jc:[],G:b};a.Bb[b]=e}e.jc.push(c)}function za(a){var b=false;jQuery.a(a.Bb,function(c,e){var d=a.eval(e.G);if(d!==e.d){jQuery.a(e.jc,function(f,i){i(d,e.d);b=true});e.d=d}});return b};nglr.Gb=function(a,b){this.url=a;this.xd=0;this.$b=b;this.Yd="_"+(""+Math.random()).substr(2)+"_";this.qb=1800};function Ca(a,b){return aa(b)}nglr.Gb.prototype.oa=function(a,b,c,e){var d=this.Yd+this.xd++;nglr[d]=function(j){delete nglr[d];e(200,j)};a={Ff:b,gf:a,of:c};a=Ca(this,nglr.m(a));b=Math.ceil(a.length/this.qb);c=this.url+"/$/"+d+"/"+b+"/";for(var f=0;f<b;f++){var i=a.substr(f*this.qb,this.qb);this.$b(c+(f+1)+"?h="+i,nglr.L)}};nglr.ta=x("frame");nglr.ta.Oc="$DATASET:";
|
||||
nglr.ta.prototype={write:function(){this.frame.name=nglr.ta.Oc+nglr.m(this.data)},oa:v()};nglr.Jb=function(a,b,c){this.fd=a;this.update=c;this.status=b};nglr.Jb.prototype={oa:function(a,b,c,e){var d=this;Da(this.status,c);this.fd.oa(a,b,c,function(){var f=d.status;f.Ia--;f.Ia===0&&f.lc.bc("fold");try{e.apply(this,arguments)}catch(i){nglr.alert(nglr.m(i))}d.update()})}};nglr.Ib=function(a,b){this.C=a;this.ib=b};nglr.Ib.prototype={Yb:function(a){var b=this;this.C.oa("GET","/account.json",{},function(c,e){b.ad=e.Xd;a(e.Xd)})},oc:function(a){var b=this;this.ib.oc(function(){delete b.ad;(a||nglr.L)()})},Da:function(a){var b=this;this.ib.Da(function(){b.Yb(function(){(a||nglr.L)()})})},sb:function(){this.ib.sb()}};angular.k.na=function(a,b,c){return a.match(b)?null:c||"Value does not match expected format "+b+"."};angular.k.tb=function(a,b,c){var e=1*a;if(e==a){if(typeof b!="undefined"&&e<b)return"Value can not be less than "+b+".";if(typeof b!="undefined"&&e>c)return"Value can not be greater than "+c+".";return null}else return"Value is not a number."};angular.k.Xe=function(a,b,c){b=angular.k.tb(a,b,c);if(b===null&&a!=Math.round(a))return"Value is not a whole number.";return b};
|
||||
angular.k.bd=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)."};angular.k.Af=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."};angular.k.gd=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."};
|
||||
angular.k.pf=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."};angular.k.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."};angular.k.rd=function(a){try{nglr.za(a);return null}catch(b){return b.toString()}};nglr.Qc=function(a,b){this.yd=0;this.Ja=a;this.X=b;this.Rb=swfobject.Rb;this.Jd=v()};
|
||||
function ja(a,b,c){var e,d=b.e("type").toLowerCase(),f=b.e("name");if(f)f=f.split(":").pop();var i="change",j=true;if(d=="button"||d=="submit"||d=="reset"||d=="image"){e=new nglr.Na(b[0],f);i="click";j=false}else if(d=="text"||d=="textarea"||d=="hidden"||d=="password"){e=new nglr.bb(b[0],f);i="keyup change"}else if(d=="checkbox"){e=new nglr.Oa(b[0],f);i="click"}else if(d=="radio"){e=new nglr.Wa(b[0],f);i="click"}else if(d=="select-one")e=new nglr.Ya(b[0],f);else if(d=="select-multiple")e=new nglr.ua(b[0],
|
||||
f);else if(d=="file")e=Ea(a,b,f);else throw"Unknown type: "+d;b.data("controller",e);var n=c.i("$binder");jQuery(e.view,":input").u(i,function(){if(e.j(c)){var m=jQuery(e.view).e("ng-action")||"";Z(c,e,m)&&n.c(c)}return j});return e}
|
||||
function Ea(a,b){var c="__uploadWidget_"+a.yd++,e=nglr.T.Z(c);b.Tc(e);c=a.Rb({data:a.Ja+"/admin/ServerAPI.swf",width:"95",height:"20",align:"top",Nf:"transparent"},{Re:"uploadWidgetId="+c,pe:"always"},c);b.remove();a=new nglr.T(e,b[0].name,c,a.Ja+"/data/"+a.X);jQuery(c).data("controller",a);return a}nglr.T=function(a,b,c,e){this.view=a;this.Jf=c;this.xc=b;this.qe=e+"/_attachments";this.value=null;this.d=undefined};
|
||||
nglr.T.dispatchEvent=function(a,b,c){a=document.getElementById(a);a=jQuery(a).data("controller");nglr.T.prototype["_on_"+b].apply(a,c)};nglr.T.Z=function(a){return jQuery('<span class="ng-upload-widget"><input type="checkbox" ng-non-bindable="true"/><object id="'+a+'" /><a></a><span/></span>')};nglr.T.prototype.j=function(a){var b=this.view.find("input").e("checked")?this.value:null;if(this.d===b)return false;else{E(a,this.xc,b);return true}};
|
||||
nglr.T.prototype.c=function(a){if((a=a.i(this.xc))&&this.value!==a){this.value=a;this.view.find("a").e("href",this.value.url).text(this.value.text);this.view.find("span").text(angular.filter.gb(this.value.size))}this.view.find("input").e("checked",!!a)};nglr.ba=x("view");nglr.ba.prototype.j=z(true);nglr.ba.prototype.c=v();nglr.ba.od=new nglr.ba;nglr.Na=x("view");nglr.Na.prototype.j=z(true);nglr.Na.prototype.c=v();
|
||||
nglr.bb=function(a,b){this.view=a;this.exp=b;this.k=a.getAttribute("ng-validate");this.Nd=typeof a.attributes["ng-required"]!="undefined";this.hc=null;this.d=undefined;this.H=a.value;a.getAttribute("ng-widget")==="datepicker"&&jQuery(a).Ne()};nglr.bb.prototype.j=function(a){var b=this.view.value;if(this.d===b)return false;else{$(a,this.exp,b);this.d=b;return true}};
|
||||
nglr.bb.prototype.c=function(a){var b=this.view,c=a.i(this.exp);if(typeof c==="undefined"){c=this.H;$(a,this.exp,c)}c=c?c:"";if(this.d!=c)this.d=b.value=c;var e=false;b.removeAttribute("ng-error");if(this.Nd)e=!(c&&c.length>0);var d=e?"Required Value":null;if(!e&&this.k&&c){e=this.k;c=c;d=nglr.h.ya[e];if(!d){d=(new nglr.q(e)).k();nglr.h.ya[e]=d}e={scope:a};d=d(e)(e,c);e=!!d}if(this.hc!==d){this.hc=e;if(d!==null){b.setAttribute("ng-error",d);a.I.he.push(this)}jQuery(b).zb("ng-validation-error",e)}};
|
||||
nglr.Oa=function(a,b){this.view=a;this.exp=b;this.d=undefined;this.H=a.checked?a.value:""};nglr.Oa.prototype.j=function(a){var b=this.view;b=b.checked?b.value:"";if(this.d===b)return false;else{$(a,this.exp,b);this.d=b;return true}};nglr.Oa.prototype.c=function(a){var b=this.view,c=a.eval(this.exp);if(typeof c==="undefined"){c=this.H;$(a,this.exp,c)}b.checked=b.value==""+c};nglr.Ya=function(a,b){this.view=a;this.exp=b;this.d=undefined;this.H=a.value};
|
||||
nglr.Ya.prototype.j=function(a){if(this.view.selectedIndex<0)$(a,this.exp,null);else{var b=this.view.value;if(this.d===b)return false;else{$(a,this.exp,b);this.d=b;return true}}};nglr.Ya.prototype.c=function(a){var b=this.view,c=a.i(this.exp);if(typeof c==="undefined"){c=this.H;$(a,this.exp,c)}if(c!==this.d){b.value=c?c:"";this.d=c}};nglr.ua=function(a,b){this.view=a;this.exp=b;this.d=undefined;this.H=this.selected()};
|
||||
nglr.ua.prototype.selected=function(){for(var a=[],b=this.view.options,c=0;c<b.length;c++){var e=b[c];e.selected&&a.push(e.value)}return a};nglr.ua.prototype.j=function(a){var b=this.selected();if(this.d===b)return false;else{$(a,this.exp,b);this.d=b;return true}};nglr.ua.prototype.c=function(a){var b=this.view,c=a.i(this.exp);if(typeof c==="undefined"){c=this.H;$(a,this.exp,c)}if(c!==this.d){a=b.options;for(b=0;b<a.length;b++){var e=a[b];e.selected=_.Aa(c,e.value)}this.d=c}};
|
||||
nglr.Wa=function(a,b){this.view=a;this.exp=b;this.d=this.ob=undefined;this.cc=a.value;this.H=a.checked?a.value:null};nglr.Wa.prototype.j=function(a){var b=this.view;if(this.ob)return false;else{b.checked=true;this.d=$(a,this.exp,this.cc);return this.ob=true}};nglr.Wa.prototype.c=function(a){var b=this.view,c=a.i(this.exp);if(this.H&&typeof c==="undefined"){c=this.H;$(a,this.exp,c)}if(this.d!=c){this.ob=b.checked=this.cc==""+c;this.d=c}};
|
||||
nglr.S=function(a,b){this.view=a;this.exp=nglr.g.Ha(b);this.O=false;this.Od={element:a}};
|
||||
nglr.S.zc=function(a){var b=nglr.mb;switch(typeof a){case "string":case "boolean":case "number":return b(a);case "function":return nglr.S.zc(a());case "object":if(nglr.gc(a))return nglr.outerHTML(a);else if(a instanceof angular.filter.s){switch(typeof a.B){case "string":case "number":return a.B;case "function":return a.B();case "object":if(nglr.gc(a.B))return nglr.outerHTML(a.B);default:break}switch(typeof a.text){case "string":case "number":return b(a.text);case "function":return b(a.text());default:break}}if(a===
|
||||
null)return"";return b(nglr.m(a,true));default:return""}};nglr.S.prototype.j=v();nglr.S.prototype.c=function(a){for(var b=[],c=this.exp,e=c.length,d=0;d<e;d++){var f=c[d],i=nglr.g.ea(f);if(i){Z(a,this,i,this.Od,function(j){b.push(nglr.S.zc(j))},function(j,n){nglr.yc(this.view,n)});if(this.O)return}else b.push(nglr.mb(f))}nglr.yc(this.view,b.join(""))};nglr.Ma=function(a,b){this.view=a;this.Vc=b};nglr.Ma.prototype.j=v();
|
||||
nglr.Ma.prototype.c=function(a){var b=jQuery(this.view),c=this.Vc;if(this.O){this.O=false;b.wc("ng-exception").vc("ng-error")}var e=b.$e("img");for(var d in c){for(var f=nglr.g.Ha(c[d]),i=[],j=0;j<f.length;j++){var n=nglr.g.ea(f[j]);if(n)try{var m=a.eval(n,{element:b[0],attrName:d});if(m&&(m.constructor!==nglr.Mb||m.length!==0))i.push(m)}catch(o){this.O=true;console.error("BindAttrUpdater",o);n=nglr.m(o,true);i.push("["+n+"]");b.fb("ng-exception").e("ng-error",n)}else i.push(f[j])}f=i.length?i.join(""):
|
||||
null;if(e&&d=="src"&&!f)f=a.i("config.server")+"/images/blank.gif";b.e(d,f)}};nglr.Ta=function(a,b){this.view=a;this.exp=b;this.O=false};nglr.Ta.prototype.j=v();nglr.Ta.prototype.c=function(a){Z(a,this,this.exp)};nglr.Ua=function(a,b){this.view=a;this.exp=b};nglr.Ua.prototype.j=v();nglr.Ua.prototype.c=function(a){Z(a,this,this.exp,{},function(b){var c=jQuery(this.view);nglr.xb(b)?c.bc():c.wb()})};nglr.Za=function(a,b){this.view=a;this.exp=b};nglr.Za.prototype.j=v();
|
||||
nglr.Za.prototype.c=function(a){Z(a,this,this.exp,{},function(b){var c=jQuery(this.view);nglr.xb(b)?c.wb():c.bc()})};nglr.Ra=function(a,b){this.view=a;this.exp=b};nglr.Ra.prototype.j=v();nglr.Ra.prototype.c=function(a){Z(a,this,this.exp,{},function(b){if(b!==null&&b!==undefined)this.view.className=b})};nglr.Pa=function(a,b){this.view=a;this.exp=b};nglr.Pa.prototype.j=v();nglr.Pa.prototype.c=function(a){Z(a,this,this.exp,{},function(b){var c=a.i("$index");jQuery(this.view).zb(b,c%2===1)})};
|
||||
nglr.Qa=function(a,b){this.view=a;this.exp=b};nglr.Qa.prototype.j=v();nglr.Qa.prototype.c=function(a){Z(a,this,this.exp,{},function(b){var c=a.i("$index");jQuery(this.view).zb(b,c%2===0)})};nglr.ab=function(a,b){this.view=a;this.exp=b};nglr.ab.prototype.j=v();nglr.ab.prototype.c=function(a){Z(a,this,this.exp,{},function(b){jQuery(this.view).e("style","").kb(b)})};
|
||||
nglr.Xa=function(a,b,c,e){this.view=a;this.Z=c;this.prefix=e;this.xa=[];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.Ca=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.Zd=a[3]||a[1];this.td=a[2]};nglr.Xa.prototype.j=v();
|
||||
nglr.Xa.prototype.c=function(a){Z(a,this,this.Ca,{},function(b){var c=this;if(!b){b=[];Aa(a,this.Ca)&&E(a,this.Ca,b)}var e=b.length,d=this.xa.length,f=this.view,i=0,j=null,n=this.td,m=this.Zd,o=0;jQuery.a(b,function(q,w){if(o<d){j=c.xa[o];E(j.scope,m,w)}else{var t=new nglr.h(a.I,c.prefix+m+" in "+c.Ca+"["+o+"]");E(t,"$index",o);n&&E(t,n,q);E(t,m,w);j={scope:t,element:c.Z(t,c.prefix,o)};f.Tc(j.element);c.xa.push(j)}f=j.element;q=(new Date).getTime();j.scope.c();i+=(new Date).getTime()-q;o++});for(b=
|
||||
d;b>e;--b)this.xa.pop().element.removeNode();if(j&&j.element[0].nodeName==="OPTION")if(e=jQuery(j.element[0].parentNode).data("controller")){e.d=undefined;e.c(a)}})};nglr.A=x("F");nglr.A.Fb="mouseleave mouseout click dblclick keypress keyup";nglr.A.prototype.u=function(){this.F.find(".ng-validation-error,.ng-exception").vd("mouseover",nglr.A.Kd)};
|
||||
nglr.A.Kd=function(){nglr.A.ub();var a=jQuery(this);a.u(nglr.A.Fb,nglr.A.ub);var b=a.position(),c=document.documentElement,e=(self.innerWidth||c&&c.clientWidth||document.body.clientWidth)-b.left;c=a.Ue("ng-exception")?"EXCEPTION:":"Validation error...";a=a.e("ng-error");e=e>375?"left":"right";c=jQuery("<div id='ng-callout' style='width:300px'><div class='ng-arrow-"+e+"'/><div class='ng-title'>"+c+"</div><div class='ng-content'>"+a+"</div></div>");jQuery("body").append(c);if(e==="left")a=b.left+this.offsetWidth+
|
||||
11;else{a=b.left-315;c.find(".ng-arrow-right").kb({left:301})}c.kb({left:a+"px",top:b.top-3+"px"});return true};nglr.A.ub=function(){jQuery("#ng-callout").Gf(nglr.A.Fb,nglr.A.ub).remove();return true};nglr.$a=function(a){this.lc=a.append(nglr.$a.Ic).find("#ng-loading");this.Ia=0};nglr.$a.Ic='<div id="ng-spacer"></div><div id="ng-loading">loading....</div>';function Da(a){a.Ia===0&&a.lc.wb();a.Ia++};(function(a){for(var b=/(.*)\/angular-(.*).js(#(.*))?/,c=document.getElementsByTagName("script"),e={Xc:true,Wc:true,Nb:false},d=0;d<c.length;d++){var f=c[d].src;if(f&&f.match(b)){f=f.match(b);if(f[2]=="bootstrap")e.Nb=true;e.C=f[1]||"";if(!e.C)e.C=window.location.toString().split(window.location.pathname)[0];if(f[4]){f=f[4].split("&");for(var i=0;i<f.length;i++){var j=f[i].split("="),n=j[0];j=j.length==1?true:j[1];if(j=="false")j=false;if(j=="true")j=true;e[n]=j}}}}function m(o,q){q=q||e.C;document.write('<script type="text/javascript" src="'+
|
||||
q+o+'"><\/script>')}if(e.Nb){m("/javascripts/webtoolkit.base64.js");m("/javascripts/swfobject.js");m("/javascripts/jQuery/jquery-1.3.2.js");m("/javascripts/jQuery/jquery-ui-1.7.1.custom.min.js");m("/javascripts/underscore/underscore.js");m("/javascripts/nglr/Loader.js");m("/javascripts/nglr/API.js");m("/javascripts/nglr/Binder.js");m("/javascripts/nglr/ControlBar.js");m("/javascripts/nglr/DataStore.js");m("/javascripts/nglr/Filters.js");m("/javascripts/nglr/JSON.js");m("/javascripts/nglr/Model.js");
|
||||
m("/javascripts/nglr/Parser.js");m("/javascripts/nglr/Scope.js");m("/javascripts/nglr/Server.js");m("/javascripts/nglr/Users.js");m("/javascripts/nglr/Validators.js");m("/javascripts/nglr/Widgets.js")}else{m("/ajax/libs/swfobject/2.2/swfobject.js","http://ajax.googleapis.com");m("/ajax/libs/jquery/1.3.2/jquery.min.js","http://ajax.googleapis.com");m("/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js","http://ajax.googleapis.com")}window.onload=function(){window.Lb.nd=function(h,k){var l=_.fa(e||{});_.extend(l,
|
||||
k);(new nglr.Va(h,jQuery("head"),l)).load()};var o=window.document;if(e.Yc){o=null;for(var q=e.Yc.split("|"),w=0;w<q.length&&!o;w++){var t=q[w].split("?"),y=t[0];if(t.length>1)if(!window.document.getElementById(t[1]))continue;o=window.document.getElementById(y)}}e.Wc&&o&&window.Lb.nd(o);if(typeof a==="function")try{a.apply(this,arguments)}catch(g){}}})(window.onload);
|
||||
16
jsTestDriver.conf
Normal file
16
jsTestDriver.conf
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
server: http://localhost:9876
|
||||
|
||||
load:
|
||||
- lib/swfobject/swfobject.js
|
||||
- lib/webtoolkit/webtoolkit.base64.js
|
||||
- lib/jquery/jquery-1.3.2.js
|
||||
- lib/jquery/jquery-ui-1.7.1.custom.min.js
|
||||
- lib/underscore/underscore.js
|
||||
- src/Loader.js
|
||||
- src/*.js
|
||||
- src/test/_namespace.js
|
||||
- src/test/*.js
|
||||
- test/testabilityPatch.js
|
||||
- test/test/*.js
|
||||
- test/*.js
|
||||
|
||||
202
lib/compiler-closure/COPYING
Normal file
202
lib/compiler-closure/COPYING
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
193
lib/compiler-closure/README
Normal file
193
lib/compiler-closure/README
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//
|
||||
// Contents
|
||||
//
|
||||
|
||||
The Closure Compiler performs checking, instrumentation, and
|
||||
optimizations on JavaScript code. The purpose of this README is to
|
||||
explain how to build and run the Closure Compiler.
|
||||
|
||||
The Closure Compiler requires Java 6 or higher.
|
||||
http://www.java.com/
|
||||
|
||||
|
||||
//
|
||||
// Building The Closure Compiler
|
||||
//
|
||||
|
||||
There are three ways to get a Closure Compiler executable.
|
||||
|
||||
1) Use one we built for you.
|
||||
|
||||
Pre-built Closure binaries can be found at
|
||||
http://code.google.com/p/closure-compiler/downloads/list
|
||||
|
||||
|
||||
2) Check out the source and build it with Apache Ant.
|
||||
|
||||
First, check out the full source tree of the Closure Compiler. There
|
||||
are instructions on how to do this at the project site.
|
||||
http://code.google.com/p/closure-compiler/source/checkout
|
||||
|
||||
Apache Ant is a cross-platform build tool.
|
||||
http://ant.apache.org/
|
||||
|
||||
At the root of the source tree, there is an Ant file named
|
||||
build.xml. To use it, navigate to the same directory and type the
|
||||
command
|
||||
|
||||
ant jar
|
||||
|
||||
This will produce a jar file called "build/compiler.jar".
|
||||
|
||||
|
||||
3) Check out the source and build it with Eclipse.
|
||||
|
||||
Eclipse is a cross-platform IDE.
|
||||
http://www.eclipse.org/
|
||||
|
||||
Under Eclipse's File menu, click "New > Project ..." and create a
|
||||
"Java Project." You will see an options screen. Give the project a
|
||||
name, select "Create project from existing source," and choose the
|
||||
root of the checked-out source tree as the existing directory. Verify
|
||||
that you are using JRE version 6 or higher.
|
||||
|
||||
Eclipse can use the build.xml file to discover rules. When you
|
||||
navigate to the build.xml file, you will see all the build rules in
|
||||
the "Outline" pane. Run the "jar" rule to build the compiler in
|
||||
build/compiler.jar.
|
||||
|
||||
|
||||
//
|
||||
// Running The Closure Compiler
|
||||
//
|
||||
|
||||
Once you have the jar binary, running the Closure Compiler is straightforward.
|
||||
|
||||
On the command line, type
|
||||
|
||||
java -jar compiler.jar
|
||||
|
||||
This starts the compiler in interactive mode. Type
|
||||
|
||||
var x = 17 + 25;
|
||||
|
||||
then hit "Enter", then hit "Ctrl-Z" (on Windows) or "Ctrl-D" (on Mac or Linux)
|
||||
and "Enter" again. The Compiler will respond:
|
||||
|
||||
var x=42;
|
||||
|
||||
The Closure Compiler has many options for reading input from a file,
|
||||
writing output to a file, checking your code, and running
|
||||
optimizations. To learn more, type
|
||||
|
||||
java -jar compiler.jar --help
|
||||
|
||||
You can read more detailed documentation about the many flags at
|
||||
http://code.google.com/closure/compiler/docs/gettingstarted_app.html
|
||||
|
||||
|
||||
//
|
||||
// Compiling Multiple Scripts
|
||||
//
|
||||
|
||||
If you have multiple scripts, you should compile them all together with
|
||||
one compile command.
|
||||
|
||||
java -jar compiler.jar --js=in1.js --js=in2.js ... --js_output_file=out.js
|
||||
|
||||
The Closure Compiler will concatenate the files in the order they're
|
||||
passed at the command line.
|
||||
|
||||
If you need to compile many, many scripts together, you may start to
|
||||
run into problems with managing dependencies between scripts. You
|
||||
should check out the Closure Library. It contains functions for
|
||||
enforcing dependencies between scripts, and a tool called calcdeps.py
|
||||
that knows how to give scripts to the Closure Compiler in the right
|
||||
order.
|
||||
|
||||
http://code.google.com/p/closure-library/
|
||||
|
||||
//
|
||||
// Licensing
|
||||
//
|
||||
|
||||
Unless otherwise stated, all source files are licensed under
|
||||
the Apache License, Version 2.0.
|
||||
|
||||
|
||||
-----
|
||||
Code under:
|
||||
src/com/google/javascript/rhino
|
||||
test/com/google/javascript/rhino
|
||||
|
||||
URL: http://www.mozilla.org/rhino
|
||||
Version: 1.5R3, with heavy modifications
|
||||
License: Netscape Public License and MPL / GPL dual license
|
||||
|
||||
Description: A partial copy of Mozilla Rhino. Mozilla Rhino is an
|
||||
implementation of JavaScript for the JVM. The JavaScript parser and
|
||||
the parse tree data structures were extracted and modified
|
||||
significantly for use by Google's JavaScript compiler.
|
||||
|
||||
Local Modifications: The packages have been renamespaced. All code not
|
||||
relavant to parsing has been removed. A JSDoc parser and static typing
|
||||
system have been added.
|
||||
|
||||
|
||||
-----
|
||||
Code in:
|
||||
lib/libtrunk_rhino_parser_jarjared.jar
|
||||
|
||||
URL: http://www.mozilla.org/rhino
|
||||
Version: Trunk
|
||||
License: Netscape Public License and MPL / GPL dual license
|
||||
|
||||
Description: Mozilla Rhino is an implementation of JavaScript for the JVM.
|
||||
|
||||
Local Modifications: None. We've used JarJar to renamespace the code
|
||||
post-compilation. See:
|
||||
http://code.google.com/p/jarjar/
|
||||
|
||||
|
||||
-----
|
||||
Code in:
|
||||
lib/google_common.jar
|
||||
|
||||
URL: http://code.google.com/p/guava-libraries/
|
||||
Version: Trunk
|
||||
License: Apache License 2.0
|
||||
|
||||
Description: Google's core Java libraries.
|
||||
|
||||
Local Modifications: None.
|
||||
|
||||
|
||||
----
|
||||
Code in:
|
||||
lib/junit.jar
|
||||
|
||||
URL: http://sourceforge.net/projects/junit/
|
||||
Version: 3.8.1
|
||||
License: Common Public License 1.0
|
||||
|
||||
Description: A framework for writing and running automated tests in Java.
|
||||
|
||||
Local Modifications: None.
|
||||
|
||||
|
||||
BIN
lib/compiler-closure/compiler.jar
Normal file
BIN
lib/compiler-closure/compiler.jar
Normal file
Binary file not shown.
4376
lib/jquery/jquery-1.3.2.js
vendored
Normal file
4376
lib/jquery/jquery-1.3.2.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
77
lib/jquery/jquery-ui-1.7.1.custom.min.js
vendored
Normal file
77
lib/jquery/jquery-ui-1.7.1.custom.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
lib/jsl/jsl
Executable file
BIN
lib/jsl/jsl
Executable file
Binary file not shown.
128
lib/jsl/jsl.default.conf
Executable file
128
lib/jsl/jsl.default.conf
Executable file
|
|
@ -0,0 +1,128 @@
|
|||
#
|
||||
# Configuration File for JavaScript Lint 0.3.0
|
||||
# Developed by Matthias Miller (http://www.JavaScriptLint.com)
|
||||
#
|
||||
# This configuration file can be used to lint a collection of scripts, or to enable
|
||||
# or disable warnings for scripts that are linted via the command line.
|
||||
#
|
||||
|
||||
### Warnings
|
||||
# Enable or disable warnings based on requirements.
|
||||
# Use "+WarningName" to display or "-WarningName" to suppress.
|
||||
#
|
||||
-no_return_value # function {0} does not always return a value
|
||||
+duplicate_formal # duplicate formal argument {0}
|
||||
-equal_as_assign # test for equality (==) mistyped as assignment (=)?{0}
|
||||
+var_hides_arg # variable {0} hides argument
|
||||
+redeclared_var # redeclaration of {0} {1}
|
||||
-anon_no_return_value # anonymous function does not always return a value
|
||||
+missing_semicolon # missing semicolon
|
||||
+meaningless_block # meaningless block; curly braces have no impact
|
||||
+comma_separated_stmts # multiple statements separated by commas (use semicolons?)
|
||||
+unreachable_code # unreachable code
|
||||
-missing_break # missing break statement
|
||||
+missing_break_for_last_case # missing break statement for last case in switch
|
||||
+comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
|
||||
+inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
|
||||
+useless_void # use of the void type may be unnecessary (void is always undefined)
|
||||
+multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
|
||||
+use_of_label # use of label
|
||||
-block_without_braces # block statement without curly braces
|
||||
+leading_decimal_point # leading decimal point may indicate a number or an object member
|
||||
+trailing_decimal_point # trailing decimal point may indicate a number or an object member
|
||||
+octal_number # leading zeros make an octal number
|
||||
+nested_comment # nested comment
|
||||
-misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
|
||||
+ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
|
||||
+empty_statement # empty statement or extra semicolon
|
||||
-missing_option_explicit # the "option explicit" control comment is missing
|
||||
+partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
|
||||
+dup_option_explicit # duplicate "option explicit" control comment
|
||||
+useless_assign # useless assignment
|
||||
+ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
|
||||
+ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent)
|
||||
+missing_default_case # missing default case in switch statement
|
||||
+duplicate_case_in_switch # duplicate case in switch statements
|
||||
+default_not_at_end # the default case is not at the end of the switch statement
|
||||
+legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
|
||||
+jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
|
||||
+useless_comparison # useless comparison; comparing identical expressions
|
||||
+with_statement # with statement hides undeclared variables; use temporary variable instead
|
||||
+trailing_comma_in_array # extra comma is not recommended in array initializers
|
||||
+assign_to_function_call # assignment to a function call
|
||||
+parseint_missing_radix # parseInt missing radix parameter
|
||||
|
||||
|
||||
### Output format
|
||||
# Customize the format of the error message.
|
||||
# __FILE__ indicates current file path
|
||||
# __FILENAME__ indicates current file name
|
||||
# __LINE__ indicates current line
|
||||
# __ERROR__ indicates error message
|
||||
#
|
||||
# Visual Studio syntax (default):
|
||||
+output-format __FILE__(__LINE__): __ERROR__
|
||||
# Alternative syntax:
|
||||
#+output-format __FILE__:__LINE__: __ERROR__
|
||||
|
||||
|
||||
### Context
|
||||
# Show the in-line position of the error.
|
||||
# Use "+context" to display or "-context" to suppress.
|
||||
#
|
||||
+context
|
||||
|
||||
|
||||
### Semicolons
|
||||
# By default, assignments of an anonymous function to a variable or
|
||||
# property (such as a function prototype) must be followed by a semicolon.
|
||||
#
|
||||
+lambda_assign_requires_semicolon
|
||||
|
||||
|
||||
### Control Comments
|
||||
# Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
|
||||
# the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
|
||||
# enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
|
||||
# although legacy control comments are enabled by default for backward compatibility.
|
||||
#
|
||||
+legacy_control_comments
|
||||
|
||||
|
||||
### JScript Function Extensions
|
||||
# JScript allows member functions to be defined like this:
|
||||
# function MyObj() { /*constructor*/ }
|
||||
# function MyObj.prototype.go() { /*member function*/ }
|
||||
#
|
||||
# It also allows events to be attached like this:
|
||||
# function window::onload() { /*init page*/ }
|
||||
#
|
||||
# This is a Microsoft-only JavaScript extension. Enable this setting to allow them.
|
||||
#
|
||||
-jscript_function_extensions
|
||||
|
||||
|
||||
### Defining identifiers
|
||||
# By default, "option explicit" is enabled on a per-file basis.
|
||||
# To enable this for all files, use "+always_use_option_explicit"
|
||||
-always_use_option_explicit
|
||||
|
||||
# Define certain identifiers of which the lint is not aware.
|
||||
# (Use this in conjunction with the "undeclared identifier" warning.)
|
||||
#
|
||||
# Common uses for webpages might be:
|
||||
#+define window
|
||||
#+define document
|
||||
|
||||
|
||||
### Files
|
||||
# Specify which files to lint
|
||||
# Use "+recurse" to enable recursion (disabled by default).
|
||||
# To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
|
||||
# or "+process Folder\Path\*.htm".
|
||||
#
|
||||
+process src/*.js
|
||||
+process src/test/*.js
|
||||
+process test/*.js
|
||||
+process test/test/*.js
|
||||
|
||||
BIN
lib/jstestdriver/JsTestDriver.jar
Normal file
BIN
lib/jstestdriver/JsTestDriver.jar
Normal file
Binary file not shown.
BIN
lib/shrinksafe/js.jar
Normal file
BIN
lib/shrinksafe/js.jar
Normal file
Binary file not shown.
BIN
lib/shrinksafe/shrinksafe.jar
Normal file
BIN
lib/shrinksafe/shrinksafe.jar
Normal file
Binary file not shown.
4
lib/swfobject/swfobject.js
Normal file
4
lib/swfobject/swfobject.js
Normal file
File diff suppressed because one or more lines are too long
609
lib/underscore/underscore.js
Normal file
609
lib/underscore/underscore.js
Normal file
|
|
@ -0,0 +1,609 @@
|
|||
// Underscore.js
|
||||
// (c) 2009 Jeremy Ashkenas, DocumentCloud Inc.
|
||||
// Underscore is freely distributable under the terms of the MIT license.
|
||||
// Portions of Underscore are inspired by or borrowed from Prototype.js,
|
||||
// Oliver Steele's Functional, and John Resig's Micro-Templating.
|
||||
// For all details and documentation:
|
||||
// http://documentcloud.github.com/underscore/
|
||||
|
||||
(function() {
|
||||
|
||||
/*------------------------- Baseline setup ---------------------------------*/
|
||||
|
||||
// Establish the root object, "window" in the browser, or "global" on the server.
|
||||
var root = this;
|
||||
|
||||
// Save the previous value of the "_" variable.
|
||||
var previousUnderscore = root._;
|
||||
|
||||
// If Underscore is called as a function, it returns a wrapped object that
|
||||
// can be used OO-style. This wrapper holds altered versions of all the
|
||||
// underscore functions. Wrapped objects may be chained.
|
||||
var wrapper = function(obj) { this._wrapped = obj; };
|
||||
|
||||
// Establish the object that gets thrown to break out of a loop iteration.
|
||||
var breaker = typeof StopIteration !== 'undefined' ? StopIteration : '__break__';
|
||||
|
||||
// Create a safe reference to the Underscore object for reference below.
|
||||
var _ = root._ = function(obj) { return new wrapper(obj); };
|
||||
|
||||
// Export the Underscore object for CommonJS.
|
||||
if (typeof exports !== 'undefined') exports._ = _;
|
||||
|
||||
// Create quick reference variables for speed access to core prototypes.
|
||||
var slice = Array.prototype.slice,
|
||||
unshift = Array.prototype.unshift,
|
||||
toString = Object.prototype.toString,
|
||||
hasOwnProperty = Object.prototype.hasOwnProperty,
|
||||
propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
|
||||
|
||||
// Current version.
|
||||
_.VERSION = '0.5.1';
|
||||
|
||||
/*------------------------ Collection Functions: ---------------------------*/
|
||||
|
||||
// The cornerstone, an each implementation.
|
||||
// Handles objects implementing forEach, arrays, and raw objects.
|
||||
_.each = function(obj, iterator, context) {
|
||||
var index = 0;
|
||||
try {
|
||||
if (obj.forEach) {
|
||||
obj.forEach(iterator, context);
|
||||
} else if (_.isArray(obj) || _.isArguments(obj)) {
|
||||
for (var i=0, l=obj.length; i<l; i++) iterator.call(context, obj[i], i, obj);
|
||||
} else {
|
||||
var keys = _.keys(obj), l = keys.length;
|
||||
for (var i=0; i<l; i++) iterator.call(context, obj[keys[i]], keys[i], obj);
|
||||
}
|
||||
} catch(e) {
|
||||
if (e != breaker) throw e;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
// Return the results of applying the iterator to each element. Use JavaScript
|
||||
// 1.6's version of map, if possible.
|
||||
_.map = function(obj, iterator, context) {
|
||||
if (obj && _.isFunction(obj.map)) return obj.map(iterator, context);
|
||||
var results = [];
|
||||
_.each(obj, function(value, index, list) {
|
||||
results.push(iterator.call(context, value, index, list));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
// Reduce builds up a single result from a list of values. Also known as
|
||||
// inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible.
|
||||
_.reduce = function(obj, memo, iterator, context) {
|
||||
if (obj && _.isFunction(obj.reduce)) return obj.reduce(_.bind(iterator, context), memo);
|
||||
_.each(obj, function(value, index, list) {
|
||||
memo = iterator.call(context, memo, value, index, list);
|
||||
});
|
||||
return memo;
|
||||
};
|
||||
|
||||
// The right-associative version of reduce, also known as foldr. Uses
|
||||
// JavaScript 1.8's version of reduceRight, if available.
|
||||
_.reduceRight = function(obj, memo, iterator, context) {
|
||||
if (obj && _.isFunction(obj.reduceRight)) return obj.reduceRight(_.bind(iterator, context), memo);
|
||||
var reversed = _.clone(_.toArray(obj)).reverse();
|
||||
_.each(reversed, function(value, index) {
|
||||
memo = iterator.call(context, memo, value, index, obj);
|
||||
});
|
||||
return memo;
|
||||
};
|
||||
|
||||
// Return the first value which passes a truth test.
|
||||
_.detect = function(obj, iterator, context) {
|
||||
var result;
|
||||
_.each(obj, function(value, index, list) {
|
||||
if (iterator.call(context, value, index, list)) {
|
||||
result = value;
|
||||
_.breakLoop();
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
// Return all the elements that pass a truth test. Use JavaScript 1.6's
|
||||
// filter(), if it exists.
|
||||
_.select = function(obj, iterator, context) {
|
||||
if (obj && _.isFunction(obj.filter)) return obj.filter(iterator, context);
|
||||
var results = [];
|
||||
_.each(obj, function(value, index, list) {
|
||||
iterator.call(context, value, index, list) && results.push(value);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
// Return all the elements for which a truth test fails.
|
||||
_.reject = function(obj, iterator, context) {
|
||||
var results = [];
|
||||
_.each(obj, function(value, index, list) {
|
||||
!iterator.call(context, value, index, list) && results.push(value);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
// Determine whether all of the elements match a truth test. Delegate to
|
||||
// JavaScript 1.6's every(), if it is present.
|
||||
_.all = function(obj, iterator, context) {
|
||||
iterator = iterator || _.identity;
|
||||
if (obj && _.isFunction(obj.every)) return obj.every(iterator, context);
|
||||
var result = true;
|
||||
_.each(obj, function(value, index, list) {
|
||||
if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop();
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
// Determine if at least one element in the object matches a truth test. Use
|
||||
// JavaScript 1.6's some(), if it exists.
|
||||
_.any = function(obj, iterator, context) {
|
||||
iterator = iterator || _.identity;
|
||||
if (obj && _.isFunction(obj.some)) return obj.some(iterator, context);
|
||||
var result = false;
|
||||
_.each(obj, function(value, index, list) {
|
||||
if (result = iterator.call(context, value, index, list)) _.breakLoop();
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
// Determine if a given value is included in the array or object,
|
||||
// based on '==='.
|
||||
_.include = function(obj, target) {
|
||||
if (_.isArray(obj)) return _.indexOf(obj, target) != -1;
|
||||
var found = false;
|
||||
_.each(obj, function(value) {
|
||||
if (found = value === target) _.breakLoop();
|
||||
});
|
||||
return found;
|
||||
};
|
||||
|
||||
// Invoke a method with arguments on every item in a collection.
|
||||
_.invoke = function(obj, method) {
|
||||
var args = _.rest(arguments, 2);
|
||||
return _.map(obj, function(value) {
|
||||
return (method ? value[method] : value).apply(value, args);
|
||||
});
|
||||
};
|
||||
|
||||
// Convenience version of a common use case of map: fetching a property.
|
||||
_.pluck = function(obj, key) {
|
||||
return _.map(obj, function(value){ return value[key]; });
|
||||
};
|
||||
|
||||
// Return the maximum item or (item-based computation).
|
||||
_.max = function(obj, iterator, context) {
|
||||
if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
|
||||
var result = {computed : -Infinity};
|
||||
_.each(obj, function(value, index, list) {
|
||||
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
||||
computed >= result.computed && (result = {value : value, computed : computed});
|
||||
});
|
||||
return result.value;
|
||||
};
|
||||
|
||||
// Return the minimum element (or element-based computation).
|
||||
_.min = function(obj, iterator, context) {
|
||||
if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
|
||||
var result = {computed : Infinity};
|
||||
_.each(obj, function(value, index, list) {
|
||||
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
||||
computed < result.computed && (result = {value : value, computed : computed});
|
||||
});
|
||||
return result.value;
|
||||
};
|
||||
|
||||
// Sort the object's values by a criteria produced by an iterator.
|
||||
_.sortBy = function(obj, iterator, context) {
|
||||
return _.pluck(_.map(obj, function(value, index, list) {
|
||||
return {
|
||||
value : value,
|
||||
criteria : iterator.call(context, value, index, list)
|
||||
};
|
||||
}).sort(function(left, right) {
|
||||
var a = left.criteria, b = right.criteria;
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
}), 'value');
|
||||
};
|
||||
|
||||
// Use a comparator function to figure out at what index an object should
|
||||
// be inserted so as to maintain order. Uses binary search.
|
||||
_.sortedIndex = function(array, obj, iterator) {
|
||||
iterator = iterator || _.identity;
|
||||
var low = 0, high = array.length;
|
||||
while (low < high) {
|
||||
var mid = (low + high) >> 1;
|
||||
iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
|
||||
}
|
||||
return low;
|
||||
};
|
||||
|
||||
// Convert anything iterable into a real, live array.
|
||||
_.toArray = function(iterable) {
|
||||
if (!iterable) return [];
|
||||
if (iterable.toArray) return iterable.toArray();
|
||||
if (_.isArray(iterable)) return iterable;
|
||||
if (_.isArguments(iterable)) return slice.call(iterable);
|
||||
return _.map(iterable, function(val){ return val; });
|
||||
};
|
||||
|
||||
// Return the number of elements in an object.
|
||||
_.size = function(obj) {
|
||||
return _.toArray(obj).length;
|
||||
};
|
||||
|
||||
/*-------------------------- Array Functions: ------------------------------*/
|
||||
|
||||
// Get the first element of an array. Passing "n" will return the first N
|
||||
// values in the array. Aliased as "head". The "guard" check allows it to work
|
||||
// with _.map.
|
||||
_.first = function(array, n, guard) {
|
||||
return n && !guard ? slice.call(array, 0, n) : array[0];
|
||||
};
|
||||
|
||||
// Returns everything but the first entry of the array. Aliased as "tail".
|
||||
// Especially useful on the arguments object. Passing an "index" will return
|
||||
// the rest of the values in the array from that index onward. The "guard"
|
||||
//check allows it to work with _.map.
|
||||
_.rest = function(array, index, guard) {
|
||||
return slice.call(array, _.isUndefined(index) || guard ? 1 : index);
|
||||
};
|
||||
|
||||
// Get the last element of an array.
|
||||
_.last = function(array) {
|
||||
return array[array.length - 1];
|
||||
};
|
||||
|
||||
// Trim out all falsy values from an array.
|
||||
_.compact = function(array) {
|
||||
return _.select(array, function(value){ return !!value; });
|
||||
};
|
||||
|
||||
// Return a completely flattened version of an array.
|
||||
_.flatten = function(array) {
|
||||
return _.reduce(array, [], function(memo, value) {
|
||||
if (_.isArray(value)) return memo.concat(_.flatten(value));
|
||||
memo.push(value);
|
||||
return memo;
|
||||
});
|
||||
};
|
||||
|
||||
// Return a version of the array that does not contain the specified value(s).
|
||||
_.without = function(array) {
|
||||
var values = _.rest(arguments);
|
||||
return _.select(array, function(value){ return !_.include(values, value); });
|
||||
};
|
||||
|
||||
// Produce a duplicate-free version of the array. If the array has already
|
||||
// been sorted, you have the option of using a faster algorithm.
|
||||
_.uniq = function(array, isSorted) {
|
||||
return _.reduce(array, [], function(memo, el, i) {
|
||||
if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo.push(el);
|
||||
return memo;
|
||||
});
|
||||
};
|
||||
|
||||
// Produce an array that contains every item shared between all the
|
||||
// passed-in arrays.
|
||||
_.intersect = function(array) {
|
||||
var rest = _.rest(arguments);
|
||||
return _.select(_.uniq(array), function(item) {
|
||||
return _.all(rest, function(other) {
|
||||
return _.indexOf(other, item) >= 0;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Zip together multiple lists into a single array -- elements that share
|
||||
// an index go together.
|
||||
_.zip = function() {
|
||||
var args = _.toArray(arguments);
|
||||
var length = _.max(_.pluck(args, 'length'));
|
||||
var results = new Array(length);
|
||||
for (var i=0; i<length; i++) results[i] = _.pluck(args, String(i));
|
||||
return results;
|
||||
};
|
||||
|
||||
// If the browser doesn't supply us with indexOf (I'm looking at you, MSIE),
|
||||
// we need this function. Return the position of the first occurence of an
|
||||
// item in an array, or -1 if the item is not included in the array.
|
||||
_.indexOf = function(array, item) {
|
||||
if (array.indexOf) return array.indexOf(item);
|
||||
for (var i=0, l=array.length; i<l; i++) if (array[i] === item) return i;
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Provide JavaScript 1.6's lastIndexOf, delegating to the native function,
|
||||
// if possible.
|
||||
_.lastIndexOf = function(array, item) {
|
||||
if (array.lastIndexOf) return array.lastIndexOf(item);
|
||||
var i = array.length;
|
||||
while (i--) if (array[i] === item) return i;
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Generate an integer Array containing an arithmetic progression. A port of
|
||||
// the native Python range() function. See:
|
||||
// http://docs.python.org/library/functions.html#range
|
||||
_.range = function(start, stop, step) {
|
||||
var a = _.toArray(arguments);
|
||||
var solo = a.length <= 1;
|
||||
var start = solo ? 0 : a[0], stop = solo ? a[0] : a[1], step = a[2] || 1;
|
||||
var len = Math.ceil((stop - start) / step);
|
||||
if (len <= 0) return [];
|
||||
var range = new Array(len);
|
||||
for (var i = start, idx = 0; true; i += step) {
|
||||
if ((step > 0 ? i - stop : stop - i) >= 0) return range;
|
||||
range[idx++] = i;
|
||||
}
|
||||
};
|
||||
|
||||
/* ----------------------- Function Functions: -----------------------------*/
|
||||
|
||||
// Create a function bound to a given object (assigning 'this', and arguments,
|
||||
// optionally). Binding with arguments is also known as 'curry'.
|
||||
_.bind = function(func, obj) {
|
||||
var args = _.rest(arguments, 2);
|
||||
return function() {
|
||||
return func.apply(obj || root, args.concat(_.toArray(arguments)));
|
||||
};
|
||||
};
|
||||
|
||||
// Bind all of an object's methods to that object. Useful for ensuring that
|
||||
// all callbacks defined on an object belong to it.
|
||||
_.bindAll = function(obj) {
|
||||
var funcs = _.rest(arguments);
|
||||
if (funcs.length == 0) funcs = _.functions(obj);
|
||||
_.each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
|
||||
return obj;
|
||||
};
|
||||
|
||||
// Delays a function for the given number of milliseconds, and then calls
|
||||
// it with the arguments supplied.
|
||||
_.delay = function(func, wait) {
|
||||
var args = _.rest(arguments, 2);
|
||||
return setTimeout(function(){ return func.apply(func, args); }, wait);
|
||||
};
|
||||
|
||||
// Defers a function, scheduling it to run after the current call stack has
|
||||
// cleared.
|
||||
_.defer = function(func) {
|
||||
return _.delay.apply(_, [func, 1].concat(_.rest(arguments)));
|
||||
};
|
||||
|
||||
// Returns the first function passed as an argument to the second,
|
||||
// allowing you to adjust arguments, run code before and after, and
|
||||
// conditionally execute the original function.
|
||||
_.wrap = function(func, wrapper) {
|
||||
return function() {
|
||||
var args = [func].concat(_.toArray(arguments));
|
||||
return wrapper.apply(wrapper, args);
|
||||
};
|
||||
};
|
||||
|
||||
// Returns a function that is the composition of a list of functions, each
|
||||
// consuming the return value of the function that follows.
|
||||
_.compose = function() {
|
||||
var funcs = _.toArray(arguments);
|
||||
return function() {
|
||||
var args = _.toArray(arguments);
|
||||
for (var i=funcs.length-1; i >= 0; i--) {
|
||||
args = [funcs[i].apply(this, args)];
|
||||
}
|
||||
return args[0];
|
||||
};
|
||||
};
|
||||
|
||||
/* ------------------------- Object Functions: ---------------------------- */
|
||||
|
||||
// Retrieve the names of an object's properties.
|
||||
_.keys = function(obj) {
|
||||
if(_.isArray(obj)) return _.range(0, obj.length);
|
||||
var keys = [];
|
||||
for (var key in obj) if (hasOwnProperty.call(obj, key)) keys.push(key);
|
||||
return keys;
|
||||
};
|
||||
|
||||
// Retrieve the values of an object's properties.
|
||||
_.values = function(obj) {
|
||||
return _.map(obj, _.identity);
|
||||
};
|
||||
|
||||
// Return a sorted list of the function names available in Underscore.
|
||||
_.functions = function(obj) {
|
||||
return _.select(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
|
||||
};
|
||||
|
||||
// Extend a given object with all of the properties in a source object.
|
||||
_.extend = function(destination, source) {
|
||||
for (var property in source) destination[property] = source[property];
|
||||
return destination;
|
||||
};
|
||||
|
||||
// Create a (shallow-cloned) duplicate of an object.
|
||||
_.clone = function(obj) {
|
||||
if (_.isArray(obj)) return obj.slice(0);
|
||||
return _.extend({}, obj);
|
||||
};
|
||||
|
||||
// Perform a deep comparison to check if two objects are equal.
|
||||
_.isEqual = function(a, b) {
|
||||
// Check object identity.
|
||||
if (a === b) return true;
|
||||
// Different types?
|
||||
var atype = typeof(a), btype = typeof(b);
|
||||
if (atype != btype) return false;
|
||||
// Basic equality test (watch out for coercions).
|
||||
if (a == b) return true;
|
||||
// One is falsy and the other truthy.
|
||||
if ((!a && b) || (a && !b)) return false;
|
||||
// One of them implements an isEqual()?
|
||||
if (a.isEqual) return a.isEqual(b);
|
||||
// Check dates' integer values.
|
||||
if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
|
||||
// Both are NaN?
|
||||
if (_.isNaN(a) && _.isNaN(b)) return true;
|
||||
// Compare regular expressions.
|
||||
if (_.isRegExp(a) && _.isRegExp(b))
|
||||
return a.source === b.source &&
|
||||
a.global === b.global &&
|
||||
a.ignoreCase === b.ignoreCase &&
|
||||
a.multiline === b.multiline;
|
||||
// If a is not an object by this point, we can't handle it.
|
||||
if (atype !== 'object') return false;
|
||||
// Check for different array lengths before comparing contents.
|
||||
if (a.length && (a.length !== b.length)) return false;
|
||||
// Nothing else worked, deep compare the contents.
|
||||
var aKeys = _.keys(a), bKeys = _.keys(b);
|
||||
// Different object sizes?
|
||||
if (aKeys.length != bKeys.length) return false;
|
||||
// Recursive comparison of contents.
|
||||
for (var key in a) if (!_.isEqual(a[key], b[key])) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Is a given array or object empty?
|
||||
_.isEmpty = function(obj) {
|
||||
return _.keys(obj).length == 0;
|
||||
};
|
||||
|
||||
// Is a given value a DOM element?
|
||||
_.isElement = function(obj) {
|
||||
return !!(obj && obj.nodeType == 1);
|
||||
};
|
||||
|
||||
// Is a given variable an arguments object?
|
||||
_.isArguments = function(obj) {
|
||||
return obj && _.isNumber(obj.length) && !_.isArray(obj) && !propertyIsEnumerable.call(obj, 'length');
|
||||
};
|
||||
|
||||
// Is the given value NaN -- this one is interesting. NaN != NaN, and
|
||||
// isNaN(undefined) == true, so we make sure it's a number first.
|
||||
_.isNaN = function(obj) {
|
||||
return _.isNumber(obj) && isNaN(obj);
|
||||
};
|
||||
|
||||
// Is a given value equal to null?
|
||||
_.isNull = function(obj) {
|
||||
return obj === null;
|
||||
};
|
||||
|
||||
// Is a given variable undefined?
|
||||
_.isUndefined = function(obj) {
|
||||
return typeof obj == 'undefined';
|
||||
};
|
||||
|
||||
// Define the isArray, isDate, isFunction, isNumber, isRegExp, and isString
|
||||
// functions based on their toString identifiers.
|
||||
var types = ['Array', 'Date', 'Function', 'Number', 'RegExp', 'String'];
|
||||
for (var i=0, l=types.length; i<l; i++) {
|
||||
(function() {
|
||||
var identifier = '[object ' + types[i] + ']';
|
||||
_['is' + types[i]] = function(obj) { return toString.call(obj) == identifier; };
|
||||
})();
|
||||
}
|
||||
|
||||
/* -------------------------- Utility Functions: -------------------------- */
|
||||
|
||||
// Run Underscore.js in noConflict mode, returning the '_' variable to its
|
||||
// previous owner. Returns a reference to the Underscore object.
|
||||
_.noConflict = function() {
|
||||
root._ = previousUnderscore;
|
||||
return this;
|
||||
};
|
||||
|
||||
// Keep the identity function around for default iterators.
|
||||
_.identity = function(value) {
|
||||
return value;
|
||||
};
|
||||
|
||||
// Break out of the middle of an iteration.
|
||||
_.breakLoop = function() {
|
||||
throw breaker;
|
||||
};
|
||||
|
||||
// Generate a unique integer id (unique within the entire client session).
|
||||
// Useful for temporary DOM ids.
|
||||
var idCounter = 0;
|
||||
_.uniqueId = function(prefix) {
|
||||
var id = idCounter++;
|
||||
return prefix ? prefix + id : id;
|
||||
};
|
||||
|
||||
// JavaScript templating a-la ERB, pilfered from John Resig's
|
||||
// "Secrets of the JavaScript Ninja", page 83.
|
||||
_.template = function(str, data) {
|
||||
var fn = new Function('obj',
|
||||
'var p=[],print=function(){p.push.apply(p,arguments);};' +
|
||||
'with(obj){p.push(\'' +
|
||||
str
|
||||
.replace(/[\r\t\n]/g, " ")
|
||||
.split("<%").join("\t")
|
||||
.replace(/((^|%>)[^\t]*)'/g, "$1\r")
|
||||
.replace(/\t=(.*?)%>/g, "',$1,'")
|
||||
.split("\t").join("');")
|
||||
.split("%>").join("p.push('")
|
||||
.split("\r").join("\\'")
|
||||
+ "');}return p.join('');");
|
||||
return data ? fn(data) : fn;
|
||||
};
|
||||
|
||||
/*------------------------------- Aliases ----------------------------------*/
|
||||
|
||||
_.forEach = _.each;
|
||||
_.foldl = _.inject = _.reduce;
|
||||
_.foldr = _.reduceRight;
|
||||
_.filter = _.select;
|
||||
_.every = _.all;
|
||||
_.some = _.any;
|
||||
_.head = _.first;
|
||||
_.tail = _.rest;
|
||||
_.methods = _.functions;
|
||||
|
||||
/*------------------------ Setup the OOP Wrapper: --------------------------*/
|
||||
|
||||
// Helper function to continue chaining intermediate results.
|
||||
var result = function(obj, chain) {
|
||||
return chain ? _(obj).chain() : obj;
|
||||
};
|
||||
|
||||
// Add all of the Underscore functions to the wrapper object.
|
||||
_.each(_.functions(_), function(name) {
|
||||
var method = _[name];
|
||||
wrapper.prototype[name] = function() {
|
||||
unshift.call(arguments, this._wrapped);
|
||||
return result(method.apply(_, arguments), this._chain);
|
||||
};
|
||||
});
|
||||
|
||||
// Add all mutator Array functions to the wrapper.
|
||||
_.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
||||
var method = Array.prototype[name];
|
||||
wrapper.prototype[name] = function() {
|
||||
method.apply(this._wrapped, arguments);
|
||||
return result(this._wrapped, this._chain);
|
||||
};
|
||||
});
|
||||
|
||||
// Add all accessor Array functions to the wrapper.
|
||||
_.each(['concat', 'join', 'slice'], function(name) {
|
||||
var method = Array.prototype[name];
|
||||
wrapper.prototype[name] = function() {
|
||||
return result(method.apply(this._wrapped, arguments), this._chain);
|
||||
};
|
||||
});
|
||||
|
||||
// Start chaining a wrapped Underscore object.
|
||||
wrapper.prototype.chain = function() {
|
||||
this._chain = true;
|
||||
return this;
|
||||
};
|
||||
|
||||
// Extracts the result from a wrapped and chained object.
|
||||
wrapper.prototype.value = function() {
|
||||
return this._wrapped;
|
||||
};
|
||||
|
||||
})();
|
||||
142
lib/webtoolkit/webtoolkit.base64.js
Normal file
142
lib/webtoolkit/webtoolkit.base64.js
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/**
|
||||
*
|
||||
* Base64 encode / decode
|
||||
* http://www.webtoolkit.info/
|
||||
*
|
||||
**/
|
||||
|
||||
var Base64 = {
|
||||
|
||||
// private property
|
||||
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",
|
||||
|
||||
// public method for encoding
|
||||
encode : function (input) {
|
||||
var output = "";
|
||||
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
|
||||
var i = 0;
|
||||
|
||||
input = Base64._utf8_encode(input);
|
||||
|
||||
while (i < input.length) {
|
||||
|
||||
chr1 = input.charCodeAt(i++);
|
||||
chr2 = input.charCodeAt(i++);
|
||||
chr3 = input.charCodeAt(i++);
|
||||
|
||||
enc1 = chr1 >> 2;
|
||||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||||
enc4 = chr3 & 63;
|
||||
|
||||
if (isNaN(chr2)) {
|
||||
enc3 = enc4 = 64;
|
||||
} else if (isNaN(chr3)) {
|
||||
enc4 = 64;
|
||||
}
|
||||
|
||||
output = output +
|
||||
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
|
||||
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
|
||||
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
// public method for decoding
|
||||
decode : function (input) {
|
||||
var output = "";
|
||||
var chr1, chr2, chr3;
|
||||
var enc1, enc2, enc3, enc4;
|
||||
var i = 0;
|
||||
|
||||
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
||||
|
||||
while (i < input.length) {
|
||||
|
||||
enc1 = this._keyStr.indexOf(input.charAt(i++));
|
||||
enc2 = this._keyStr.indexOf(input.charAt(i++));
|
||||
enc3 = this._keyStr.indexOf(input.charAt(i++));
|
||||
enc4 = this._keyStr.indexOf(input.charAt(i++));
|
||||
|
||||
chr1 = (enc1 << 2) | (enc2 >> 4);
|
||||
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
||||
chr3 = ((enc3 & 3) << 6) | enc4;
|
||||
|
||||
output = output + String.fromCharCode(chr1);
|
||||
|
||||
if (enc3 != 64) {
|
||||
output = output + String.fromCharCode(chr2);
|
||||
}
|
||||
if (enc4 != 64) {
|
||||
output = output + String.fromCharCode(chr3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
output = Base64._utf8_decode(output);
|
||||
|
||||
return output;
|
||||
|
||||
},
|
||||
|
||||
// private method for UTF-8 encoding
|
||||
_utf8_encode : function (string) {
|
||||
string = string.replace(/\r\n/g,"\n");
|
||||
var utftext = "";
|
||||
|
||||
for (var n = 0; n < string.length; n++) {
|
||||
|
||||
var c = string.charCodeAt(n);
|
||||
|
||||
if (c < 128) {
|
||||
utftext += String.fromCharCode(c);
|
||||
}
|
||||
else if((c > 127) && (c < 2048)) {
|
||||
utftext += String.fromCharCode((c >> 6) | 192);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
else {
|
||||
utftext += String.fromCharCode((c >> 12) | 224);
|
||||
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return utftext;
|
||||
},
|
||||
|
||||
// private method for UTF-8 decoding
|
||||
_utf8_decode : function (utftext) {
|
||||
var string = "";
|
||||
var i = 0;
|
||||
var c = c1 = c2 = 0;
|
||||
|
||||
while ( i < utftext.length ) {
|
||||
|
||||
c = utftext.charCodeAt(i);
|
||||
|
||||
if (c < 128) {
|
||||
string += String.fromCharCode(c);
|
||||
i++;
|
||||
}
|
||||
else if((c > 191) && (c < 224)) {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
|
||||
i += 2;
|
||||
}
|
||||
else {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
c3 = utftext.charCodeAt(i+2);
|
||||
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
|
||||
i += 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
};
|
||||
318
src/API.js
Normal file
318
src/API.js
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
angular.Global = {
|
||||
typeOf:function(obj){
|
||||
var type = typeof obj;
|
||||
switch(type) {
|
||||
case "object":
|
||||
if (obj === null) return "null";
|
||||
if (obj instanceof Array) return "array";
|
||||
if (obj instanceof Date) return "date";
|
||||
if (obj.nodeType == 1) return "element";
|
||||
}
|
||||
return type;
|
||||
}
|
||||
};
|
||||
|
||||
angular.Collection = {};
|
||||
angular.Object = {};
|
||||
angular.Array = {
|
||||
includeIf:function(array, value, condition) {
|
||||
var index = _.indexOf(array, value);
|
||||
if (condition) {
|
||||
if (index == -1)
|
||||
array.push(value);
|
||||
} else {
|
||||
array.splice(index, 1);
|
||||
}
|
||||
return array;
|
||||
},
|
||||
sum:function(array, expression) {
|
||||
var fn = angular.Function.compile(expression);
|
||||
var sum = 0;
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
var value = 1 * fn(array[i]);
|
||||
if (!isNaN(value)){
|
||||
sum += value;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
},
|
||||
remove:function(array, value) {
|
||||
var index = _.indexOf(array, value);
|
||||
if (index >=0)
|
||||
array.splice(index, 1);
|
||||
return value;
|
||||
},
|
||||
find:function(array, condition, defaultValue) {
|
||||
if (!condition) return undefined;
|
||||
var fn = angular.Function.compile(condition);
|
||||
_.detect(array, function($){
|
||||
if (fn($)){
|
||||
defaultValue = $;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return defaultValue;
|
||||
},
|
||||
findById:function(array, id) {
|
||||
return angular.Array.find(array, function($){return $.$id == id;}, null);
|
||||
},
|
||||
filter:function(array, expression) {
|
||||
var predicates = [];
|
||||
predicates.check = function(value) {
|
||||
for (var j = 0; j < predicates.length; j++) {
|
||||
if(!predicates[j](value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
var getter = nglr.Scope.getter;
|
||||
var search = function(obj, text){
|
||||
if (text.charAt(0) === '!') {
|
||||
return !search(obj, text.substr(1));
|
||||
}
|
||||
switch (typeof obj) {
|
||||
case "boolean":
|
||||
case "number":
|
||||
case "string":
|
||||
return ('' + obj).toLowerCase().indexOf(text) > -1;
|
||||
case "object":
|
||||
for ( var objKey in obj) {
|
||||
if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case "array":
|
||||
for ( var i = 0; i < obj.length; i++) {
|
||||
if (search(obj[i], text)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
switch (typeof expression) {
|
||||
case "boolean":
|
||||
case "number":
|
||||
case "string":
|
||||
expression = {$:expression};
|
||||
case "object":
|
||||
for (var key in expression) {
|
||||
if (key == '$') {
|
||||
(function(){
|
||||
var text = (''+expression[key]).toLowerCase();
|
||||
if (!text) return;
|
||||
predicates.push(function(value) {
|
||||
return search(value, text);
|
||||
});
|
||||
})();
|
||||
} else {
|
||||
(function(){
|
||||
var path = key;
|
||||
var text = (''+expression[key]).toLowerCase();
|
||||
if (!text) return;
|
||||
predicates.push(function(value) {
|
||||
return search(getter(value, path), text);
|
||||
});
|
||||
})();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "function":
|
||||
predicates.push(expression);
|
||||
break;
|
||||
default:
|
||||
return array;
|
||||
}
|
||||
var filtered = [];
|
||||
for ( var j = 0; j < array.length; j++) {
|
||||
var value = array[j];
|
||||
if (predicates.check(value)) {
|
||||
filtered.push(value);
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
},
|
||||
add:function(array, value) {
|
||||
array.push(_.isUndefined(value)? {} : value);
|
||||
return array;
|
||||
},
|
||||
count:function(array, condition) {
|
||||
if (!condition) return array.length;
|
||||
var fn = angular.Function.compile(condition);
|
||||
return _.reduce(array, 0, function(count, $){return count + (fn($)?1:0);});
|
||||
},
|
||||
orderBy:function(array, expression, descend) {
|
||||
function reverse(comp, descending) {
|
||||
return nglr.toBoolean(descending) ?
|
||||
function(a,b){return comp(b,a);} : comp;
|
||||
}
|
||||
function compare(v1, v2){
|
||||
var t1 = typeof v1;
|
||||
var t2 = typeof v2;
|
||||
if (t1 == t2) {
|
||||
if (t1 == "string") v1 = v1.toLowerCase();
|
||||
if (t1 == "string") v2 = v2.toLowerCase();
|
||||
if (v1 === v2) return 0;
|
||||
return v1 < v2 ? -1 : 1;
|
||||
} else {
|
||||
return t1 < t2 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
expression = _.isArray(expression) ? expression: [expression];
|
||||
expression = _.map(expression, function($){
|
||||
var descending = false;
|
||||
if (typeof $ == "string" && ($.charAt(0) == '+' || $.charAt(0) == '-')) {
|
||||
descending = $.charAt(0) == '-';
|
||||
$ = $.substring(1);
|
||||
}
|
||||
var get = $ ? angular.Function.compile($) : _.identity;
|
||||
return reverse(function(a,b){
|
||||
return compare(get(a),get(b));
|
||||
}, descending);
|
||||
});
|
||||
var comparator = function(o1, o2){
|
||||
for ( var i = 0; i < expression.length; i++) {
|
||||
var comp = expression[i](o1, o2);
|
||||
if (comp != 0) return comp;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
return _.clone(array).sort(reverse(comparator, descend));
|
||||
},
|
||||
orderByToggle:function(predicate, attribute) {
|
||||
var STRIP = /^([+|-])?(.*)/;
|
||||
var ascending = false;
|
||||
var index = -1;
|
||||
_.detect(predicate, function($, i){
|
||||
if ($ == attribute) {
|
||||
ascending = true;
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
if (($.charAt(0)=='+'||$.charAt(0)=='-') && $.substring(1) == attribute) {
|
||||
ascending = $.charAt(0) == '+';
|
||||
index = i;
|
||||
return true;
|
||||
};
|
||||
});
|
||||
if (index >= 0) {
|
||||
predicate.splice(index, 1);
|
||||
}
|
||||
predicate.unshift((ascending ? "-" : "+") + attribute);
|
||||
return predicate;
|
||||
},
|
||||
orderByDirection:function(predicate, attribute, ascend, descend) {
|
||||
ascend = ascend || 'ng-ascend';
|
||||
descend = descend || 'ng-descend';
|
||||
var att = predicate[0] || '';
|
||||
var direction = true;
|
||||
if (att.charAt(0) == '-') {
|
||||
att = att.substring(1);
|
||||
direction = false;
|
||||
} else if(att.charAt(0) == '+') {
|
||||
att = att.substring(1);
|
||||
}
|
||||
return att == attribute ? (direction ? ascend : descend) : "";
|
||||
},
|
||||
merge:function(array, index, mergeValue) {
|
||||
var value = array[index];
|
||||
if (!value) {
|
||||
value = {};
|
||||
array[index] = value;
|
||||
}
|
||||
nglr.merge(mergeValue, value);
|
||||
return array;
|
||||
}
|
||||
};
|
||||
angular.String = {
|
||||
quote:function(string) {
|
||||
return '"' + string.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(string) {
|
||||
var str = angular.String.quote(string);
|
||||
var chars = [];
|
||||
for ( var i = 0; i < str.length; i++) {
|
||||
var ch = str.charCodeAt(i);
|
||||
if (ch < 128) {
|
||||
chars.push(str.charAt(i));
|
||||
} else {
|
||||
var encode = "000" + ch.toString(16);
|
||||
chars.push("\\u" + encode.substring(encode.length - 4));
|
||||
}
|
||||
}
|
||||
return chars.join('');
|
||||
},
|
||||
toDate:function(string){
|
||||
var match;
|
||||
if (typeof string == 'string' &&
|
||||
(match = string.match(/^(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z$/))){
|
||||
var date = new Date(0);
|
||||
date.setUTCFullYear(match[1], match[2] - 1, match[3]);
|
||||
date.setUTCHours(match[4], match[5], match[6], 0);
|
||||
return date;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
};
|
||||
angular.Date = {
|
||||
toString:function(date){
|
||||
function pad(n) { return n < 10 ? "0" + n : n; }
|
||||
return (date.getUTCFullYear()) + '-' +
|
||||
pad(date.getUTCMonth() + 1) + '-' +
|
||||
pad(date.getUTCDate()) + 'T' +
|
||||
pad(date.getUTCHours()) + ':' +
|
||||
pad(date.getUTCMinutes()) + ':' +
|
||||
pad(date.getUTCSeconds()) + 'Z';
|
||||
}
|
||||
};
|
||||
angular.Function = {
|
||||
compile:function(expression) {
|
||||
if (_.isFunction(expression)){
|
||||
return expression;
|
||||
} else if (expression){
|
||||
var scope = new nglr.Scope();
|
||||
return function($) {
|
||||
scope.state = $;
|
||||
return scope.eval(expression);
|
||||
};
|
||||
} else {
|
||||
return function($){return $;};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(function(){
|
||||
function extend(dst, src, names){
|
||||
_.extend(dst, src);
|
||||
_.each((names||[]), function(name){
|
||||
dst[name] = _[name];
|
||||
});
|
||||
};
|
||||
extend(angular.Global, {},
|
||||
['extend', 'clone','isEqual',
|
||||
'isElement', 'isArray', 'isFunction', 'isUndefined']);
|
||||
extend(angular.Collection, angular.Global,
|
||||
['each', 'map', 'reduce', 'reduceRight', 'detect',
|
||||
'select', 'reject', 'all', 'any', 'include',
|
||||
'invoke', 'pluck', 'max', 'min', 'sortBy',
|
||||
'sortedIndex', 'toArray', 'size']);
|
||||
extend(angular.Array, angular.Collection,
|
||||
['first', 'last', 'compact', 'flatten', 'without',
|
||||
'uniq', 'intersect', 'zip', 'indexOf', 'lastIndexOf']);
|
||||
extend(angular.Object, angular.Collection,
|
||||
['keys', 'values']);
|
||||
extend(angular.String, angular.Global);
|
||||
extend(angular.Function, angular.Global,
|
||||
['bind', 'bindAll', 'delay', 'defer', 'wrap', 'compose']);
|
||||
})();
|
||||
341
src/Binder.js
Normal file
341
src/Binder.js
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
// Copyright (C) 2009 BRAT Tech LLC
|
||||
nglr.Binder = function(doc, widgetFactory, urlWatcher, config) {
|
||||
this.doc = doc;
|
||||
this.urlWatcher = urlWatcher;
|
||||
this.anchor = {};
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.config = config || {};
|
||||
this.updateListeners = [];
|
||||
};
|
||||
|
||||
nglr.Binder.parseBindings = function(string) {
|
||||
var results = [];
|
||||
var lastIndex = 0;
|
||||
var index;
|
||||
while((index = string.indexOf('{{', lastIndex)) > -1) {
|
||||
if (lastIndex < index)
|
||||
results.push(string.substr(lastIndex, index - lastIndex));
|
||||
lastIndex = index;
|
||||
|
||||
index = string.indexOf('}}', index);
|
||||
index = index < 0 ? string.length : index + 2;
|
||||
|
||||
results.push(string.substr(lastIndex, index - lastIndex));
|
||||
lastIndex = index;
|
||||
}
|
||||
if (lastIndex != string.length)
|
||||
results.push(string.substr(lastIndex, string.length - lastIndex));
|
||||
return results.length === 0 ? [ string ] : results;
|
||||
};
|
||||
|
||||
nglr.Binder.hasBinding = function(string) {
|
||||
var bindings = nglr.Binder.parseBindings(string);
|
||||
return bindings.length > 1 || nglr.Binder.binding(bindings[0]) !== null;
|
||||
};
|
||||
|
||||
nglr.Binder.binding = function(string) {
|
||||
var binding = string.replace(/\n/gm, ' ').match(/^\{\{(.*)\}\}$/);
|
||||
return binding ? binding[1] : null;
|
||||
};
|
||||
|
||||
|
||||
nglr.Binder.prototype.parseQueryString = function(query) {
|
||||
var params = {};
|
||||
query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,
|
||||
function (match, left, right) {
|
||||
if (left) params[decodeURIComponent(left)] = decodeURIComponent(right);
|
||||
});
|
||||
return params;
|
||||
};
|
||||
|
||||
nglr.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);
|
||||
jQuery.each(self.anchor, function(key, newValue) {
|
||||
delete self.anchor[key];
|
||||
});
|
||||
jQuery.each(anchorQuery, function(key, newValue) {
|
||||
self.anchor[key] = newValue;
|
||||
});
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.onUrlChange = function (url) {
|
||||
console.log("URL change detected", url);
|
||||
this.parseAnchor(url);
|
||||
this.updateView();
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
};
|
||||
|
||||
nglr.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();});
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.executeInit = function() {
|
||||
jQuery("[ng-init]", this.doc).each(function() {
|
||||
var jThis = jQuery(this);
|
||||
var scope = jThis.scope();
|
||||
try {
|
||||
scope.eval(jThis.attr('ng-init'));
|
||||
} catch (e) {
|
||||
nglr.alert("EVAL ERROR:\n" + jThis.attr('ng-init') + '\n' + nglr.toJson(e, true));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.entity = function (scope) {
|
||||
jQuery("[ng-entity]", this.doc).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) {
|
||||
nglr.alert(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.compile = function() {
|
||||
var jNode = jQuery(this.doc);
|
||||
var self = this;
|
||||
if (this.config.autoSubmit) {
|
||||
var submits = jQuery(":submit", this.doc).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(), "");
|
||||
jQuery("a[ng-action]", this.doc).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', nglr.toJson(e, true));
|
||||
}
|
||||
self.updateView();
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.translateBinding = function(node, parentPath, factories) {
|
||||
var path = parentPath.concat();
|
||||
var offset = path.pop();
|
||||
var parts = nglr.Binder.parseBindings(node.nodeValue);
|
||||
if (parts.length > 1 || nglr.Binder.binding(parts[0])) {
|
||||
var parent = node.parentNode;
|
||||
if (nglr.isLeafNode(parent)) {
|
||||
parent.setAttribute('ng-bind-template', node.nodeValue);
|
||||
factories.push({path:path, fn:function(node, scope, prefix) {
|
||||
return new nglr.BindUpdater(node, node.getAttribute('ng-bind-template'));
|
||||
}});
|
||||
} else {
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var part = parts[i];
|
||||
var binding = nglr.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:nglr.Binder.prototype.ng_bind});
|
||||
}
|
||||
} else if (nglr.msie && part.charAt(0) == ' ') {
|
||||
newNode = document.createElement("span");
|
||||
newNode.innerHTML = ' ' + part.substring(1);
|
||||
} else {
|
||||
newNode = document.createTextNode(part);
|
||||
}
|
||||
parent.insertBefore(newNode, node);
|
||||
}
|
||||
}
|
||||
parent.removeChild(node);
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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]];
|
||||
}
|
||||
try {
|
||||
scope.addWidget(factory.fn(node, scope, prefix));
|
||||
} catch (e) {
|
||||
nglr.alert(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
nglr.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 ? nglr.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 = nglr.msie && attrName == 'href' ?
|
||||
decodeURI(node.getAttribute(attrName, 2)) : attr.value;
|
||||
if (nglr.Binder.hasBinding(attrValue)) {
|
||||
bindings[attrName] = attrValue;
|
||||
}
|
||||
}
|
||||
var json = nglr.toJson(bindings);
|
||||
if (json.length > 2) {
|
||||
node.setAttribute("ng-bind-attr", json);
|
||||
}
|
||||
}
|
||||
|
||||
if (!node.getAttribute) console.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 nglr.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;
|
||||
}
|
||||
}
|
||||
|
||||
var children = node.childNodes;
|
||||
for (var k = 0; k < children.length; k++) {
|
||||
this.precompileNode(children[k], path.concat(k), factories);
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.ng_eval = function(node) {
|
||||
return new nglr.EvalUpdater(node, node.getAttribute('ng-eval'));
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.ng_bind = function(node) {
|
||||
return new nglr.BindUpdater(node, "{{" + node.getAttribute('ng-bind') + "}}");
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.ng_bind_attr = function(node) {
|
||||
return new nglr.BindAttrUpdater(node, nglr.fromJson(node.getAttribute('ng-bind-attr')));
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.ng_hide = function(node) {
|
||||
return new nglr.HideUpdater(node, node.getAttribute('ng-hide'));
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.ng_show = function(node) {
|
||||
return new nglr.ShowUpdater(node, node.getAttribute('ng-show'));
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.ng_class = function(node) {
|
||||
return new nglr.ClassUpdater(node, node.getAttribute('ng-class'));
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.ng_class_even = function(node) {
|
||||
return new nglr.ClassEvenUpdater(node, node.getAttribute('ng-class-even'));
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.ng_class_odd = function(node) {
|
||||
return new nglr.ClassOddUpdater(node, node.getAttribute('ng-class-odd'));
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.ng_style = function(node) {
|
||||
return new nglr.StyleUpdater(node, node.getAttribute('ng-style'));
|
||||
};
|
||||
|
||||
nglr.Binder.prototype.ng_watch = function(node, scope) {
|
||||
scope.watch(node.getAttribute('ng-watch'));
|
||||
};
|
||||
71
src/ControlBar.js
Normal file
71
src/ControlBar.js
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (C) 2008,2009 BRAT Tech LLC
|
||||
|
||||
nglr.ControlBar = function (document, serverUrl) {
|
||||
this.document = document;
|
||||
this.serverUrl = serverUrl;
|
||||
this.window = window;
|
||||
this.callbacks = [];
|
||||
};
|
||||
|
||||
nglr.ControlBar.prototype.bind = function () {
|
||||
};
|
||||
|
||||
nglr.ControlBar.HTML =
|
||||
'<div>' +
|
||||
'<div class="ui-widget-overlay"></div>' +
|
||||
'<div id="ng-login" ng-non-bindable="true">' +
|
||||
'<div class="ng-login-container"></div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
nglr.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()));
|
||||
}
|
||||
};
|
||||
|
||||
nglr.ControlBar.prototype.logout = function (loginSubmitFn) {
|
||||
this.callbacks.push(loginSubmitFn);
|
||||
if (this.callbacks.length == 1) {
|
||||
this.doTemplate("/user_session/do_destroy.mini");
|
||||
}
|
||||
};
|
||||
|
||||
nglr.ControlBar.prototype.urlWithoutAnchor = function (path) {
|
||||
return this.window.location.href.split("#")[0];
|
||||
};
|
||||
|
||||
nglr.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><angular/></tt></a>'
|
||||
});
|
||||
nglr["_iframe_notify_" + id] = function() {
|
||||
loginView.dialog("destroy");
|
||||
loginView.remove();
|
||||
jQuery.each(self.callbacks, function(i, callback){
|
||||
callback();
|
||||
});
|
||||
self.callbacks = [];
|
||||
};
|
||||
};
|
||||
|
||||
nglr.ControlBar.FORBIDEN =
|
||||
'<div ng-non-bindable="true" title="Permission Error:">' +
|
||||
'Sorry, you do not have permission for this!'+
|
||||
'</div>';
|
||||
|
||||
nglr.ControlBar.prototype.notAuthorized = function () {
|
||||
if (this.forbidenView) return;
|
||||
this.forbidenView = jQuery(nglr.ControlBar.FORBIDEN);
|
||||
this.forbidenView.dialog({bgiframe:true, height:70, modal:true});
|
||||
};
|
||||
332
src/DataStore.js
Normal file
332
src/DataStore.js
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
// Copyright (C) 2009 BRAT Tech LLC
|
||||
|
||||
nglr.DataStore = function(post, users, anchor) {
|
||||
this.post = post;
|
||||
this.users = users;
|
||||
this._cache = {$collections:[]};
|
||||
this.anchor = anchor;
|
||||
this.bulkRequest = [];
|
||||
};
|
||||
|
||||
nglr.DataStore.prototype.cache = function(document) {
|
||||
if (document.constructor != nglr.Model) {
|
||||
throw "Parameter must be an instance of Entity! " + nglr.toJson(document);
|
||||
}
|
||||
var key = document.$entity + '/' + document.$id;
|
||||
var cachedDocument = this._cache[key];
|
||||
if (cachedDocument) {
|
||||
nglr.Model.copyDirectFields(document, cachedDocument);
|
||||
} else {
|
||||
this._cache[key] = document;
|
||||
cachedDocument = document;
|
||||
}
|
||||
return cachedDocument;
|
||||
};
|
||||
|
||||
nglr.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||nglr.noop)(instance);
|
||||
}, failure);
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
|
||||
nglr.DataStore.prototype.loadMany = function(entity, ids, callback) {
|
||||
var self=this;
|
||||
var list = [];
|
||||
var callbackCount = 0;
|
||||
jQuery.each(ids, function(i, id){
|
||||
list.push(self.load(entity(), id, function(){
|
||||
callbackCount++;
|
||||
if (callbackCount == ids.length) {
|
||||
(callback||nglr.noop)(list);
|
||||
}
|
||||
}));
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
nglr.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||nglr.noop)(instance);
|
||||
} else {
|
||||
throw response;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
nglr.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||nglr.noop)(list);
|
||||
});
|
||||
return list;
|
||||
};
|
||||
|
||||
nglr.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);
|
||||
}
|
||||
});
|
||||
if (document.$$anchor) {
|
||||
self.anchor[document.$$anchor] = document.$id;
|
||||
}
|
||||
if (callback)
|
||||
callback(document);
|
||||
});
|
||||
};
|
||||
|
||||
nglr.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);
|
||||
}
|
||||
}
|
||||
});
|
||||
(callback||nglr.noop)(response);
|
||||
});
|
||||
};
|
||||
|
||||
nglr.DataStore.prototype._jsonRequest = function(request, callback, failure) {
|
||||
request.$$callback = callback;
|
||||
request.$$failure = failure||function(response){
|
||||
throw response;
|
||||
};
|
||||
this.bulkRequest.push(request);
|
||||
};
|
||||
|
||||
nglr.DataStore.prototype.flush = function() {
|
||||
if (this.bulkRequest.length === 0) return;
|
||||
var self = this;
|
||||
var bulkRequest = this.bulkRequest;
|
||||
this.bulkRequest = [];
|
||||
console.log('REQUEST:', bulkRequest);
|
||||
function callback(code, bulkResponse){
|
||||
console.log('RESPONSE[' + code + ']: ', bulkResponse);
|
||||
if(bulkResponse.$status_code == 401) {
|
||||
self.users.login(function(){
|
||||
self.post(bulkRequest, callback);
|
||||
});
|
||||
} else if(bulkResponse.$status_code) {
|
||||
nglr.alert(nglr.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();
|
||||
} else {
|
||||
request.$$failure(response);
|
||||
}
|
||||
} else {
|
||||
request.$$callback(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.post(bulkRequest, callback);
|
||||
};
|
||||
|
||||
nglr.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 == nglr.Model.prototype.$save) {
|
||||
saveCounter++;
|
||||
item.$save(onSaveDone);
|
||||
}
|
||||
}
|
||||
onSaveDone();
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
};
|
||||
|
||||
nglr.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));
|
||||
}
|
||||
entities.sort(function(a,b){return a.title > b.title ? 1 : -1;});
|
||||
if (callback) callback(entities);
|
||||
});
|
||||
return entities;
|
||||
};
|
||||
|
||||
nglr.DataStore.prototype.documentCountsByUser = function(){
|
||||
var counts = {};
|
||||
var self = this;
|
||||
self.post([["GET", "$users"]], function(code, response){
|
||||
jQuery.each(response[0], function(key, value){
|
||||
counts[key] = value;
|
||||
});
|
||||
});
|
||||
return counts;
|
||||
};
|
||||
|
||||
nglr.DataStore.prototype.userDocumentIdsByEntity = function(user){
|
||||
var ids = {};
|
||||
var self = this;
|
||||
self.post([["GET", "$users/" + user]], function(code, response){
|
||||
jQuery.each(response[0], function(key, value){
|
||||
ids[key] = value;
|
||||
});
|
||||
});
|
||||
return ids;
|
||||
};
|
||||
|
||||
nglr.DataStore.NullEntity = function(){};
|
||||
nglr.DataStore.NullEntity.all = function(){return [];};
|
||||
nglr.DataStore.NullEntity.query = function(){return [];};
|
||||
nglr.DataStore.NullEntity.load = function(){return {};};
|
||||
nglr.DataStore.NullEntity.title = undefined;
|
||||
|
||||
nglr.DataStore.prototype.entity = function(name, defaults){
|
||||
if (!name) {
|
||||
return nglr.DataStore.NullEntity;
|
||||
}
|
||||
var self = this;
|
||||
var entity = function(initialState){
|
||||
return new nglr.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;
|
||||
};
|
||||
|
||||
nglr.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 = nglr.Scope.getter(row, nextJoinOn);
|
||||
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 = nglr.Scope.getter(row, nextJoinOn);
|
||||
row[nextJoinName] = byId[id];
|
||||
});
|
||||
});
|
||||
});
|
||||
return joinedResult;
|
||||
};
|
||||
return fn;
|
||||
};
|
||||
290
src/Filters.js
Normal file
290
src/Filters.js
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
// Copyright (C) 2009 BRAT Tech LLC
|
||||
|
||||
angular.filter.Meta = function(obj){
|
||||
if (obj) {
|
||||
for ( var key in obj) {
|
||||
this[key] = obj[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
angular.filter.Meta.get = function(obj, attr){
|
||||
attr = attr || 'text';
|
||||
switch(typeof obj) {
|
||||
case "string":
|
||||
return attr == "text" ? obj : undefined;
|
||||
case "object":
|
||||
if (obj && typeof obj[attr] !== "undefined") {
|
||||
return obj[attr];
|
||||
}
|
||||
return undefined;
|
||||
default:
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
angular.filter.currency = function(amount){
|
||||
jQuery(this.element).toggleClass('ng-format-negative', amount < 0);
|
||||
return '$' + angular.filter.number.apply(this, [amount, 2]);
|
||||
};
|
||||
|
||||
angular.filter.number = function(amount, fractionSize){
|
||||
if (isNaN(amount) || !isFinite(amount)) {
|
||||
return '';
|
||||
}
|
||||
fractionSize = typeof fractionSize == 'undefined' ? 2 : fractionSize;
|
||||
var isNegative = amount < 0;
|
||||
amount = Math.abs(amount);
|
||||
var pow = Math.pow(10, fractionSize);
|
||||
var text = "" + Math.round(amount * pow);
|
||||
var whole = text.substring(0, text.length - fractionSize);
|
||||
whole = whole || '0';
|
||||
var frc = text.substring(text.length - fractionSize);
|
||||
text = isNegative ? '-' : '';
|
||||
for (var i = 0; i < whole.length; i++) {
|
||||
if ((whole.length - i)%3 === 0 && i !== 0) {
|
||||
text += ',';
|
||||
}
|
||||
text += whole.charAt(i);
|
||||
}
|
||||
if (fractionSize > 0) {
|
||||
for (var j = frc.length; j < fractionSize; j++) {
|
||||
frc += '0';
|
||||
}
|
||||
text += '.' + frc.substring(0, fractionSize);
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
angular.filter.date = function(amount) {
|
||||
};
|
||||
|
||||
angular.filter.json = function(object) {
|
||||
jQuery(this.element).addClass("ng-monospace");
|
||||
return nglr.toJson(object, true);
|
||||
};
|
||||
|
||||
angular.filter.trackPackage = function(trackingNo, noMatch) {
|
||||
trackingNo = nglr.trim(trackingNo);
|
||||
var tNo = trackingNo.replace(/ /g, '');
|
||||
var MATCHERS = angular.filter.trackPackage.MATCHERS;
|
||||
for ( var i = 0; i < MATCHERS.length; i++) {
|
||||
var carrier = MATCHERS[i];
|
||||
for ( var j = 0; j < carrier.regexp.length; j++) {
|
||||
var regexp = carrier.regexp[j];
|
||||
if (regexp.test(tNo)) {
|
||||
var text = carrier.name + ": " + trackingNo;
|
||||
var url = carrier.url + trackingNo;
|
||||
return new angular.filter.Meta({
|
||||
text:text,
|
||||
url:url,
|
||||
html: '<a href="' + nglr.escapeAttr(url) + '">' + text + '</a>',
|
||||
trackingNo:trackingNo});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trackingNo)
|
||||
return noMatch ||
|
||||
new angular.filter.Meta({text:trackingNo + " is not recognized"});
|
||||
else
|
||||
return null;
|
||||
};
|
||||
|
||||
angular.filter.trackPackage.MATCHERS = [
|
||||
{ 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=",
|
||||
regexp: [
|
||||
/^1Z[0-9A-Z]{16}$/i]},
|
||||
{ name: "FedEx",
|
||||
url: "http://www.fedex.com/Tracking?tracknumbers=",
|
||||
regexp: [
|
||||
/^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=",
|
||||
regexp: [
|
||||
/^(91\d{20})$/i,
|
||||
/^(91\d{18})$/i]}];
|
||||
|
||||
angular.filter.link = function(obj, title) {
|
||||
var text = title || angular.filter.Meta.get(obj);
|
||||
var url = angular.filter.Meta.get(obj, "url") || angular.filter.Meta.get(obj);
|
||||
if (url) {
|
||||
if (angular.validator.email(url) === null) {
|
||||
url = "mailto:" + url;
|
||||
}
|
||||
var html = '<a href="' + nglr.escapeHtml(url) + '">' + text + '</a>';
|
||||
return new angular.filter.Meta({text:text, url:url, html:html});
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
angular.filter.bytes = function(size) {
|
||||
if(size === null) return "";
|
||||
|
||||
var suffix = 0;
|
||||
while (size > 1000) {
|
||||
size = size / 1024;
|
||||
suffix++;
|
||||
}
|
||||
var txt = "" + size;
|
||||
var dot = txt.indexOf('.');
|
||||
if (dot > -1 && dot + 2 < txt.length) {
|
||||
txt = txt.substring(0, dot + 2);
|
||||
}
|
||||
return txt + " " + angular.filter.bytes.SUFFIX[suffix];
|
||||
};
|
||||
angular.filter.bytes.SUFFIX = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
||||
|
||||
angular.filter.image = function(obj, width, height) {
|
||||
if (obj && obj.url) {
|
||||
var style = "";
|
||||
if (width) {
|
||||
style = ' style="max-width: ' + width +
|
||||
'px; max-height: ' + (height || width) + 'px;"';
|
||||
}
|
||||
return new angular.filter.Meta({url:obj.url, text:obj.url,
|
||||
html:'<img src="'+obj.url+'"' + style + '/>'});
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
angular.filter.lowercase = function (obj) {
|
||||
var text = angular.filter.Meta.get(obj);
|
||||
return text ? ("" + text).toLowerCase() : text;
|
||||
};
|
||||
|
||||
angular.filter.uppercase = function (obj) {
|
||||
var text = angular.filter.Meta.get(obj);
|
||||
return text ? ("" + text).toUpperCase() : text;
|
||||
};
|
||||
|
||||
angular.filter.linecount = function (obj) {
|
||||
var text = angular.filter.Meta.get(obj);
|
||||
if (text==='' || !text) return 1;
|
||||
return text.split(/\n|\f/).length;
|
||||
};
|
||||
|
||||
angular.filter['if'] = function (result, expression) {
|
||||
return expression ? result : undefined;
|
||||
};
|
||||
|
||||
angular.filter.unless = function (result, expression) {
|
||||
return expression ? undefined : result;
|
||||
};
|
||||
|
||||
angular.filter.googleChartApi = function(type, data, width, height) {
|
||||
data = data || {};
|
||||
var api = angular.filter.googleChartApi;
|
||||
var chart = {
|
||||
cht:type,
|
||||
chco:api.collect(data, 'color'),
|
||||
chtt:api.title(data),
|
||||
chdl:api.collect(data, 'label'),
|
||||
chd:api.values(data),
|
||||
chf:'bg,s,FFFFFF00'
|
||||
};
|
||||
if (_.isArray(data.xLabels)) {
|
||||
chart.chxt='x';
|
||||
chart.chxl='0:|' + data.xLabels.join('|');
|
||||
}
|
||||
return angular.filter.googleChartApi.encode(chart, width, height);
|
||||
};
|
||||
|
||||
angular.filter.googleChartApi.values = function(data){
|
||||
var seriesValues = [];
|
||||
_.each(data.series||[], function(serie){
|
||||
var values = [];
|
||||
_.each(serie.values||[], function(value){
|
||||
values.push(value);
|
||||
});
|
||||
seriesValues.push(values.join(','));
|
||||
});
|
||||
var values = seriesValues.join('|');
|
||||
return values === "" ? null : "t:" + values;
|
||||
};
|
||||
|
||||
angular.filter.googleChartApi.title = function(data){
|
||||
var titles = [];
|
||||
var title = data.title || [];
|
||||
_.each(_.isArray(title)?title:[title], function(text){
|
||||
titles.push(encodeURIComponent(text));
|
||||
});
|
||||
return titles.join('|');
|
||||
};
|
||||
|
||||
angular.filter.googleChartApi.collect = function(data, key){
|
||||
var outterValues = [];
|
||||
var count = 0;
|
||||
_.each(data.series||[], function(serie){
|
||||
var innerValues = [];
|
||||
var value = serie[key] || [];
|
||||
_.each(_.isArray(value)?value:[value], function(color){
|
||||
innerValues.push(encodeURIComponent(color));
|
||||
count++;
|
||||
});
|
||||
outterValues.push(innerValues.join('|'));
|
||||
});
|
||||
return count?outterValues.join(','):null;
|
||||
};
|
||||
|
||||
angular.filter.googleChartApi.encode= function(params, width, height) {
|
||||
width = width || 200;
|
||||
height = height || width;
|
||||
var url = "http://chart.apis.google.com/chart?";
|
||||
var urlParam = [];
|
||||
params.chs = width + "x" + height;
|
||||
for ( var key in params) {
|
||||
var value = params[key];
|
||||
if (value) {
|
||||
urlParam.push(key + "=" + value);
|
||||
}
|
||||
}
|
||||
urlParam.sort();
|
||||
url += urlParam.join("&");
|
||||
return new angular.filter.Meta({url:url, text:value,
|
||||
html:'<img width="' + width + '" height="' + height + '" src="'+url+'"/>'});
|
||||
};
|
||||
|
||||
angular.filter.qrcode = function(value, width, height) {
|
||||
return angular.filter.googleChartApi.encode({cht:'qr', chl:encodeURIComponent(value)}, width, height);
|
||||
};
|
||||
angular.filter.chart = {
|
||||
pie:function(data, width, height) {
|
||||
return angular.filter.googleChartApi('p', data, width, height);
|
||||
},
|
||||
pie3d:function(data, width, height) {
|
||||
return angular.filter.googleChartApi('p3', data, width, height);
|
||||
},
|
||||
pieConcentric:function(data, width, height) {
|
||||
return angular.filter.googleChartApi('pc', data, width, height);
|
||||
},
|
||||
barHorizontalStacked:function(data, width, height) {
|
||||
return angular.filter.googleChartApi('bhs', data, width, height);
|
||||
},
|
||||
barHorizontalGrouped:function(data, width, height) {
|
||||
return angular.filter.googleChartApi('bhg', data, width, height);
|
||||
},
|
||||
barVerticalStacked:function(data, width, height) {
|
||||
return angular.filter.googleChartApi('bvs', data, width, height);
|
||||
},
|
||||
barVerticalGrouped:function(data, width, height) {
|
||||
return angular.filter.googleChartApi('bvg', data, width, height);
|
||||
},
|
||||
line:function(data, width, height) {
|
||||
return angular.filter.googleChartApi('lc', data, width, height);
|
||||
},
|
||||
sparkline:function(data, width, height) {
|
||||
return angular.filter.googleChartApi('ls', data, width, height);
|
||||
},
|
||||
scatter:function(data, width, height) {
|
||||
return angular.filter.googleChartApi('s', data, width, height);
|
||||
}
|
||||
};
|
||||
|
||||
angular.filter.html = function(html){
|
||||
return new angular.filter.Meta({html:html});
|
||||
};
|
||||
92
src/JSON.js
Normal file
92
src/JSON.js
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
nglr.array = [].constructor;
|
||||
|
||||
nglr.toJson = function(obj, pretty){
|
||||
var buf = [];
|
||||
nglr.toJsonArray(buf, obj, pretty ? "\n " : null);
|
||||
return buf.join('');
|
||||
};
|
||||
|
||||
nglr.toPrettyJson = function(obj) {
|
||||
return nglr.toJson(obj, true);
|
||||
};
|
||||
|
||||
nglr.fromJson = function(json) {
|
||||
try {
|
||||
var parser = new nglr.Parser(json, true);
|
||||
var expression = parser.primary();
|
||||
parser.assertAllConsumed();
|
||||
return expression();
|
||||
} catch (e) {
|
||||
console.error("fromJson error: ", json, e);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
nglr.toJsonArray = function(buf, obj, pretty){
|
||||
var type = typeof obj;
|
||||
if (obj === null) {
|
||||
buf.push("null");
|
||||
} else if (type === 'function') {
|
||||
return;
|
||||
} else if (type === 'boolean') {
|
||||
buf.push('' + obj);
|
||||
} else if (type === 'number') {
|
||||
if (isNaN(obj)) {
|
||||
buf.push('null');
|
||||
} else {
|
||||
buf.push('' + obj);
|
||||
}
|
||||
} else if (type === 'string') {
|
||||
return buf.push(angular.String.quoteUnicode(obj));
|
||||
} else if (type === 'object') {
|
||||
if (obj instanceof Array) {
|
||||
buf.push("[");
|
||||
var len = obj.length;
|
||||
var sep = false;
|
||||
for(var i=0; i<len; i++) {
|
||||
var item = obj[i];
|
||||
if (sep) buf.push(",");
|
||||
if (typeof item == 'function' || typeof item == 'undefined') {
|
||||
buf.push("null");
|
||||
} else {
|
||||
nglr.toJsonArray(buf, item, pretty);
|
||||
}
|
||||
sep = true;
|
||||
}
|
||||
buf.push("]");
|
||||
} else if (obj instanceof Date) {
|
||||
buf.push(angular.String.quoteUnicode(angular.Date.toString(obj)));
|
||||
} else {
|
||||
buf.push("{");
|
||||
if (pretty) buf.push(pretty);
|
||||
var comma = false;
|
||||
var childPretty = pretty ? pretty + " " : false;
|
||||
var keys = [];
|
||||
for(var k in obj) {
|
||||
if (k.indexOf('$$') === 0)
|
||||
continue;
|
||||
keys.push(k);
|
||||
}
|
||||
keys.sort();
|
||||
for ( var keyIndex = 0; keyIndex < keys.length; keyIndex++) {
|
||||
var key = keys[keyIndex];
|
||||
try {
|
||||
var value = obj[key];
|
||||
if (typeof value != 'function') {
|
||||
if (comma) {
|
||||
buf.push(",");
|
||||
if (pretty) buf.push(pretty);
|
||||
}
|
||||
buf.push(angular.String.quote(key));
|
||||
buf.push(":");
|
||||
nglr.toJsonArray(buf, value, childPretty);
|
||||
comma = true;
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
buf.push("}");
|
||||
}
|
||||
}
|
||||
};
|
||||
389
src/Loader.js
Normal file
389
src/Loader.js
Normal file
|
|
@ -0,0 +1,389 @@
|
|||
// Copyright (C) 2008,2009 BRAT Tech LLC
|
||||
|
||||
// IE compatibility
|
||||
|
||||
if (typeof document.getAttribute == 'undefined')
|
||||
document.getAttribute = function() {
|
||||
};
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
if (_.isUndefined(window.nglr)) nglr = {};
|
||||
if (_.isUndefined(window.angular)) angular = {};
|
||||
if (_.isUndefined(angular.validator)) angular.validator = {};
|
||||
if (_.isUndefined(angular.filter)) angular.filter = {};
|
||||
if (_.isUndefined(window.console))
|
||||
window.console = {
|
||||
log:function() {},
|
||||
error:function() {}
|
||||
};
|
||||
if (_.isUndefined(nglr.alert)) {
|
||||
nglr.alert = function(){console.log(arguments); window.alert.apply(window, arguments); };
|
||||
}
|
||||
|
||||
nglr.consoleLog = function(level, objs) {
|
||||
var log = document.createElement("div");
|
||||
log.className = level;
|
||||
var msg = "";
|
||||
var sep = "";
|
||||
for ( var i = 0; i < objs.length; i++) {
|
||||
var obj = objs[i];
|
||||
msg += sep + (typeof obj == 'string' ? obj : nglr.toJson(obj));
|
||||
sep = " ";
|
||||
}
|
||||
log.appendChild(document.createTextNode(msg));
|
||||
nglr.consoleNode.appendChild(log);
|
||||
};
|
||||
|
||||
nglr.isNode = function(inp) {
|
||||
return inp &&
|
||||
inp.tagName &&
|
||||
inp.nodeName &&
|
||||
inp.ownerDocument &&
|
||||
inp.removeAttribute;
|
||||
};
|
||||
|
||||
nglr.isLeafNode = function(node) {
|
||||
switch (node.nodeName) {
|
||||
case "OPTION":
|
||||
case "PRE":
|
||||
case "TITLE":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.noop = function() {
|
||||
};
|
||||
nglr.setHtml = function(node, html) {
|
||||
if (nglr.isLeafNode(node)) {
|
||||
if (nglr.msie) {
|
||||
node.innerText = html;
|
||||
} else {
|
||||
node.textContent = html;
|
||||
}
|
||||
} else {
|
||||
node.innerHTML = html;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.escapeHtml = function(html) {
|
||||
if (!html || !html.replace)
|
||||
return html;
|
||||
return html.
|
||||
replace(/&/g, '&').
|
||||
replace(/</g, '<').
|
||||
replace(/>/g, '>');
|
||||
};
|
||||
|
||||
nglr.escapeAttr = function(html) {
|
||||
if (!html || !html.replace)
|
||||
return html;
|
||||
return html.replace(/</g, '<').replace(/>/g, '>').replace(/\"/g,
|
||||
'"');
|
||||
};
|
||||
|
||||
nglr.bind = function(_this, _function) {
|
||||
if (!_this)
|
||||
throw "Missing this";
|
||||
if (!_.isFunction(_function))
|
||||
throw "Missing function";
|
||||
return function() {
|
||||
return _function.apply(_this, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
nglr.shiftBind = function(_this, _function) {
|
||||
return function() {
|
||||
var args = [ this ];
|
||||
for ( var i = 0; i < arguments.length; i++) {
|
||||
args.push(arguments[i]);
|
||||
}
|
||||
return _function.apply(_this, args);
|
||||
};
|
||||
};
|
||||
|
||||
nglr.outerHTML = function(node) {
|
||||
var temp = document.createElement('div');
|
||||
temp.appendChild(node);
|
||||
var outerHTML = temp.innerHTML;
|
||||
temp.removeChild(node);
|
||||
return outerHTML;
|
||||
};
|
||||
|
||||
nglr.trim = function(str) {
|
||||
return str.replace(/^ */, '').replace(/ *$/, '');
|
||||
};
|
||||
|
||||
nglr.toBoolean = function(value) {
|
||||
var v = ("" + value).toLowerCase();
|
||||
if (v == 'f' || v == '0' || v == 'false' || v == 'no')
|
||||
value = false;
|
||||
return !!value;
|
||||
};
|
||||
|
||||
nglr.merge = function(src, dst) {
|
||||
for ( var key in src) {
|
||||
var value = dst[key];
|
||||
var type = typeof value;
|
||||
if (type == 'undefined') {
|
||||
dst[key] = nglr.fromJson(nglr.toJson(src[key]));
|
||||
} else if (type == 'object' && value.constructor != nglr.array &&
|
||||
key.substring(0, 1) != "$") {
|
||||
nglr.merge(src[key], value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ////////////////////////////
|
||||
// Loader
|
||||
// ////////////////////////////
|
||||
|
||||
nglr.Loader = function(document, head, config) {
|
||||
this.document = jQuery(document);
|
||||
this.head = jQuery(head);
|
||||
this.config = config;
|
||||
this.location = window.location;
|
||||
};
|
||||
|
||||
nglr.Loader.prototype.load = function() {
|
||||
this.configureLogging();
|
||||
this.loadCss('/stylesheets/jquery-ui/smoothness/jquery-ui-1.7.1.css');
|
||||
this.loadCss('/stylesheets/nglr.css');
|
||||
console.log("Server: " + this.config.server);
|
||||
jQuery.noConflict();
|
||||
nglr.msie = jQuery.browser.msie;
|
||||
this.configureJQueryPlugins();
|
||||
this.computeConfiguration();
|
||||
this.bindHtml();
|
||||
};
|
||||
|
||||
nglr.Loader.prototype.configureJQueryPlugins = function() {
|
||||
console.log('Loader.configureJQueryPlugins()');
|
||||
jQuery.fn.removeNode = function() {
|
||||
var node = this.get(0);
|
||||
node.parentNode.removeChild(node);
|
||||
};
|
||||
jQuery.fn.scope = function() {
|
||||
var element = this;
|
||||
while (element && element.get(0)) {
|
||||
var scope = element.data("scope");
|
||||
if (scope)
|
||||
return scope;
|
||||
element = element.parent();
|
||||
}
|
||||
return null;
|
||||
};
|
||||
jQuery.fn.controller = function() {
|
||||
return this.data('controller') || nglr.NullController.instance;
|
||||
};
|
||||
};
|
||||
|
||||
nglr.Loader.prototype.uid = function() {
|
||||
return "" + new Date().getTime();
|
||||
};
|
||||
|
||||
nglr.Loader.prototype.computeConfiguration = function() {
|
||||
var config = this.config;
|
||||
if (!config.database) {
|
||||
var match = config.server.match(/https?:\/\/([\w]*)/)
|
||||
config.database = match ? match[1] : "$MEMORY";
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Loader.prototype.bindHtml = function() {
|
||||
console.log('Loader.bindHtml()');
|
||||
var watcher = new nglr.UrlWatcher(this.location);
|
||||
var document = this.document;
|
||||
var widgetFactory = new nglr.WidgetFactory(this.config.server, this.config.database);
|
||||
var binder = new nglr.Binder(document[0], widgetFactory, watcher, this.config);
|
||||
widgetFactory.onChangeListener = nglr.shiftBind(binder, binder.updateModel);
|
||||
var controlBar = new nglr.ControlBar(document.find('body'), this.config.server);
|
||||
var onUpdate = function(){binder.updateView();};
|
||||
var server = this.config.database=="$MEMORY" ?
|
||||
new nglr.FrameServer(this.window) :
|
||||
new nglr.Server(this.config.server, jQuery.getScript);
|
||||
server = new nglr.VisualServer(server, new nglr.Status(jQuery(document.body)), onUpdate);
|
||||
var users = new nglr.Users(server, controlBar);
|
||||
var databasePath = '/data/' + this.config.database;
|
||||
var post = function(request, callback){
|
||||
server.request("POST", databasePath, request, callback);
|
||||
};
|
||||
var datastore = new nglr.DataStore(post, users, binder.anchor);
|
||||
binder.updateListeners.push(function(){datastore.flush();});
|
||||
var scope = new nglr.Scope( {
|
||||
$anchor : binder.anchor,
|
||||
$binder : binder,
|
||||
$config : this.config,
|
||||
$console : window.console,
|
||||
$datastore : datastore,
|
||||
$save : function(callback) {
|
||||
datastore.saveScope(scope.state, callback, binder.anchor);
|
||||
},
|
||||
$window : window,
|
||||
$uid : this.uid,
|
||||
$users : users
|
||||
}, "ROOT");
|
||||
|
||||
jQuery.each(["get", "set", "eval", "addWatchListener", "updateView"],
|
||||
function(i, method){
|
||||
angular[method] = nglr.bind(scope, scope[method]);
|
||||
});
|
||||
|
||||
document.data('scope', scope);
|
||||
console.log('$binder.entity()');
|
||||
binder.entity(scope);
|
||||
|
||||
console.log('$binder.compile()');
|
||||
binder.compile();
|
||||
|
||||
console.log('ControlBar.bind()');
|
||||
controlBar.bind();
|
||||
|
||||
console.log('$users.fetchCurrentUser()');
|
||||
function fetchCurrentUser() {
|
||||
users.fetchCurrentUser(function(u) {
|
||||
if (!u && document.find("[ng-auth=eager]").length) {
|
||||
users.login();
|
||||
}
|
||||
});
|
||||
}
|
||||
fetchCurrentUser();
|
||||
|
||||
console.log('PopUp.bind()');
|
||||
new nglr.PopUp(document).bind();
|
||||
|
||||
console.log('$binder.parseAnchor()');
|
||||
binder.parseAnchor();
|
||||
|
||||
console.log('$binder.executeInit()');
|
||||
binder.executeInit();
|
||||
|
||||
console.log('$binder.updateView()');
|
||||
binder.updateView();
|
||||
|
||||
watcher.listener = nglr.bind(binder, binder.onUrlChange, watcher);
|
||||
watcher.onUpdate = function(){nglr.alert("update");};
|
||||
watcher.watch();
|
||||
document.find("body").show();
|
||||
console.log('ready()');
|
||||
|
||||
};
|
||||
|
||||
nglr.Loader.prototype.visualPost = function(delegate) {
|
||||
var status = new nglr.Status(jQuery(document.body));
|
||||
return function(request, delegateCallback) {
|
||||
status.beginRequest(request);
|
||||
var callback = function() {
|
||||
status.endRequest();
|
||||
try {
|
||||
delegateCallback.apply(this, arguments);
|
||||
} catch (e) {
|
||||
nglr.alert(nglr.toJson(e));
|
||||
}
|
||||
};
|
||||
delegate(request, callback);
|
||||
};
|
||||
};
|
||||
|
||||
nglr.Loader.prototype.configureLogging = function() {
|
||||
var url = window.location.href + '#';
|
||||
url = url.split('#')[1];
|
||||
var config = {
|
||||
debug : null
|
||||
};
|
||||
var configs = url.split('&');
|
||||
for ( var i = 0; i < configs.length; i++) {
|
||||
var part = (configs[i] + '=').split('=');
|
||||
config[part[0]] = part[1];
|
||||
}
|
||||
if (config.debug == 'console') {
|
||||
nglr.consoleNode = document.createElement("div");
|
||||
nglr.consoleNode.id = 'ng-console';
|
||||
document.getElementsByTagName('body')[0].appendChild(nglr.consoleNode);
|
||||
console.log = function() {
|
||||
nglr.consoleLog('ng-console-info', arguments);
|
||||
};
|
||||
console.error = function() {
|
||||
nglr.consoleLog('ng-console-error', arguments);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Loader.prototype.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);
|
||||
};
|
||||
|
||||
nglr.UrlWatcher = function(location) {
|
||||
this.location = location;
|
||||
this.delay = 25;
|
||||
this.setTimeout = function(fn, delay) {
|
||||
window.setTimeout(fn, delay);
|
||||
};
|
||||
this.listener = function(url) {
|
||||
return url;
|
||||
};
|
||||
this.expectedUrl = location.href;
|
||||
};
|
||||
|
||||
nglr.UrlWatcher.prototype.watch = function() {
|
||||
var self = this;
|
||||
var pull = function() {
|
||||
if (self.expectedUrl !== self.location.href) {
|
||||
var notify = self.location.hash.match(/^#\$iframe_notify=(.*)$/);
|
||||
if (notify) {
|
||||
if (!self.expectedUrl.match(/#/)) {
|
||||
self.expectedUrl += "#";
|
||||
}
|
||||
self.location.href = self.expectedUrl;
|
||||
var id = '_iframe_notify_' + notify[1];
|
||||
var notifyFn = nglr[id];
|
||||
delete nglr[id];
|
||||
try {
|
||||
(notifyFn||nglr.noop)();
|
||||
} catch (e) {
|
||||
nglr.alert(e);
|
||||
}
|
||||
} else {
|
||||
self.listener(self.location.href);
|
||||
self.expectedUrl = self.location.href;
|
||||
}
|
||||
}
|
||||
self.setTimeout(pull, self.delay);
|
||||
};
|
||||
pull();
|
||||
};
|
||||
|
||||
nglr.UrlWatcher.prototype.setUrl = function(url) {
|
||||
var existingURL = window.location.href;
|
||||
if (!existingURL.match(/#/))
|
||||
existingURL += '#';
|
||||
if (existingURL != url)
|
||||
window.location.href = url;
|
||||
self.existingURL = url;
|
||||
};
|
||||
|
||||
nglr.UrlWatcher.prototype.getUrl = function() {
|
||||
return window.location.href;
|
||||
};
|
||||
65
src/Model.js
Normal file
65
src/Model.js
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// 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)
|
||||
|
||||
nglr.Model = function(entity, initial) {
|
||||
this.$$entity = entity;
|
||||
this.$loadFrom(initial||{});
|
||||
this.$entity = entity.title;
|
||||
this.$migrate();
|
||||
};
|
||||
|
||||
nglr.Model.copyDirectFields = function(src, dst) {
|
||||
if (src === dst || !src || !dst) return;
|
||||
var isDataField = function(src, dst, field) {
|
||||
return (field.substring(0,2) !== '$$') &&
|
||||
(typeof src[field] !== 'function') &&
|
||||
(typeof dst[field] !== 'function');
|
||||
};
|
||||
for (var field in dst) {
|
||||
if (isDataField(src, dst, field))
|
||||
delete dst[field];
|
||||
}
|
||||
for (field in src) {
|
||||
if (isDataField(src, dst, field))
|
||||
dst[field] = src[field];
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Model.prototype.$migrate = function() {
|
||||
nglr.merge(this.$$entity.defaults, this);
|
||||
return this;
|
||||
};
|
||||
|
||||
nglr.Model.prototype.$merge = function(other) {
|
||||
nglr.merge(other, this);
|
||||
return this;
|
||||
};
|
||||
|
||||
nglr.Model.prototype.$save = function(callback) {
|
||||
this.$$entity.datastore.save(this, callback === true ? undefined : callback);
|
||||
if (callback === true) this.$$entity.datastore.flush();
|
||||
return this;
|
||||
};
|
||||
|
||||
nglr.Model.prototype.$delete = function(callback) {
|
||||
this.$$entity.datastore.remove(this, callback === true ? undefined : callback);
|
||||
if (callback === true) this.$$entity.datastore.flush();
|
||||
return this;
|
||||
};
|
||||
|
||||
nglr.Model.prototype.$loadById = function(id, callback) {
|
||||
this.$$entity.datastore.load(this, id, callback);
|
||||
return this;
|
||||
};
|
||||
|
||||
nglr.Model.prototype.$loadFrom = function(other) {
|
||||
nglr.Model.copyDirectFields(other, this);
|
||||
return this;
|
||||
};
|
||||
|
||||
nglr.Model.prototype.$saveTo = function(other) {
|
||||
nglr.Model.copyDirectFields(this, other);
|
||||
return this;
|
||||
};
|
||||
741
src/Parser.js
Normal file
741
src/Parser.js
Normal file
|
|
@ -0,0 +1,741 @@
|
|||
nglr.Lexer = function(text, parsStrings){
|
||||
this.text = text;
|
||||
// UTC dates have 20 characters, we send them through parser
|
||||
this.dateParseLength = parsStrings ? 20 : -1;
|
||||
this.tokens = [];
|
||||
this.index = 0;
|
||||
};
|
||||
|
||||
nglr.Lexer.OPERATORS = {
|
||||
'null':function(self){return null;},
|
||||
'true':function(self){return true;},
|
||||
'false':function(self){return false;},
|
||||
'+':function(self, a,b){return (a||0)+(b||0);},
|
||||
'-':function(self, a,b){return (a||0)-(b||0);},
|
||||
'*':function(self, a,b){return a*b;},
|
||||
'/':function(self, a,b){return a/b;},
|
||||
'%':function(self, a,b){return a%b;},
|
||||
'^':function(self, a,b){return a^b;},
|
||||
'=':function(self, a,b){return self.scope.set(a, b);},
|
||||
'==':function(self, a,b){return a==b;},
|
||||
'!=':function(self, a,b){return a!=b;},
|
||||
'<':function(self, a,b){return a<b;},
|
||||
'>':function(self, a,b){return a>b;},
|
||||
'<=':function(self, a,b){return a<=b;},
|
||||
'>=':function(self, a,b){return a>=b;},
|
||||
'&&':function(self, a,b){return a&&b;},
|
||||
'||':function(self, a,b){return a||b;},
|
||||
'&':function(self, a,b){return a&b;},
|
||||
// '|':function(self, a,b){return a|b;},
|
||||
'|':function(self, a,b){return b(self, a);},
|
||||
'!':function(self, a){return !a;}
|
||||
};
|
||||
|
||||
nglr.Lexer.prototype.peek = function() {
|
||||
if (this.index + 1 < this.text.length) {
|
||||
return this.text.charAt(this.index + 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Lexer.prototype.parse = function() {
|
||||
var tokens = this.tokens;
|
||||
var OPERATORS = nglr.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});
|
||||
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;
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
};
|
||||
|
||||
nglr.Lexer.prototype.isNumber = function(ch) {
|
||||
return '0' <= ch && ch <= '9';
|
||||
};
|
||||
|
||||
nglr.Lexer.prototype.isWhitespace = function(ch) {
|
||||
return ch == ' ' || ch == '\r' || ch == '\t' ||
|
||||
ch == '\n' || ch == '\v';
|
||||
};
|
||||
|
||||
nglr.Lexer.prototype.isIdent = function(ch) {
|
||||
return 'a' <= ch && ch <= 'z' ||
|
||||
'A' <= ch && ch <= 'Z' ||
|
||||
'_' == ch || ch == '$';
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
this.index++;
|
||||
}
|
||||
number = 1 * number;
|
||||
this.tokens.push({index:start, text:number,
|
||||
fn:function(){return number;}});
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
this.index++;
|
||||
}
|
||||
var fn = nglr.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});
|
||||
};
|
||||
nglr.Lexer.ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
|
||||
nglr.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 = nglr.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;
|
||||
}
|
||||
this.index++;
|
||||
}
|
||||
throw "Lexer Error: Unterminated quote [" +
|
||||
this.text.substring(start) + "] starting at column '" +
|
||||
(start+1) + "' in expression '" + this.text + "'.";
|
||||
};
|
||||
|
||||
nglr.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 compiledRegexp = new RegExp(regexp, flags);
|
||||
this.tokens.push({index:start, text:regexp, flags:flags,
|
||||
fn:function(){return compiledRegexp;}});
|
||||
return;
|
||||
} else {
|
||||
regexp += ch;
|
||||
}
|
||||
this.index++;
|
||||
}
|
||||
throw "Lexer Error: Unterminated RegExp [" +
|
||||
this.text.substring(start) + "] starting at column '" +
|
||||
(start+1) + "' in expression '" + this.text + "'.";
|
||||
};
|
||||
|
||||
|
||||
nglr.Parser = function(text, parseStrings){
|
||||
this.text = text;
|
||||
this.tokens = new nglr.Lexer(text, parseStrings).parse();
|
||||
this.index = 0;
|
||||
};
|
||||
|
||||
nglr.Parser.ZERO = function(){
|
||||
return 0;
|
||||
};
|
||||
|
||||
nglr.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) + "'.";
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.peekToken = function() {
|
||||
if (this.tokens.length === 0)
|
||||
throw "Unexpected end of expression: " + this.text;
|
||||
return this.tokens[0];
|
||||
};
|
||||
|
||||
nglr.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)) {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
};
|
||||
|
||||
nglr.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) + "'.";
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Parser.prototype._unary = function(fn, parse) {
|
||||
var right = parse.apply(this);
|
||||
return function(self) {
|
||||
return fn(self, right(self));
|
||||
};
|
||||
};
|
||||
|
||||
nglr.Parser.prototype._binary = function(left, fn, parse) {
|
||||
var right = parse.apply(this);
|
||||
return function(self) {
|
||||
return fn(self, left(self), right(self));
|
||||
};
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.hasTokens = function () {
|
||||
return this.tokens.length > 0;
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.assertAllConsumed = function(){
|
||||
if (this.tokens.length !== 0) {
|
||||
throw "Did not understand '" + this.text.substring(this.tokens[0].index) +
|
||||
"' while evaluating '" + this.text + "'.";
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.filter = function(){
|
||||
return this._pipeFunction(angular.filter);
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.validator = function(){
|
||||
return this._pipeFunction(angular.validator);
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.expression = function(){
|
||||
return this.throwStmt();
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.throwStmt = function(){
|
||||
if (this.expect('throw')) {
|
||||
var throwExp = this.assignment();
|
||||
return function (self) {
|
||||
throw throwExp(self);
|
||||
};
|
||||
} else {
|
||||
return this.assignment();
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.negated = function(){
|
||||
var token;
|
||||
if (token = this.expect('!')) {
|
||||
return this._unary(token.fn, this.equality);
|
||||
} else {
|
||||
return this.equality();
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.additive = function(){
|
||||
var left = this.multiplicative();
|
||||
var token;
|
||||
while(token = this.expect('+','-')) {
|
||||
left = this._binary(left, token.fn, this.multiplicative);
|
||||
}
|
||||
return left;
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.multiplicative = function(){
|
||||
var left = this.unary();
|
||||
var token;
|
||||
while(token = this.expect('*','/','%')) {
|
||||
left = this._binary(left, token.fn, this.unary);
|
||||
}
|
||||
return left;
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.unary = function(){
|
||||
var token;
|
||||
if (this.expect('+')) {
|
||||
return this.primary();
|
||||
} else if (token = this.expect('-')) {
|
||||
return this._binary(nglr.Parser.ZERO, token.fn, this.multiplicative);
|
||||
} else {
|
||||
return this.primary();
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
};
|
||||
|
||||
nglr.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 {
|
||||
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);
|
||||
} else {
|
||||
throw "IMPOSSIBLE";
|
||||
}
|
||||
}
|
||||
return primary;
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.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(":");
|
||||
}
|
||||
var statements = this.statements();
|
||||
this.consume("}");
|
||||
return function(self){
|
||||
return function($){
|
||||
var scope = new nglr.Scope(self.scope.state);
|
||||
scope.set('$', $);
|
||||
for ( var i = 0; i < args.length; i++) {
|
||||
scope.set(args[i], arguments[i]);
|
||||
}
|
||||
return statements({scope:scope});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.fieldAccess = function(object) {
|
||||
var field = this.expect().text;
|
||||
var fn = function (self){
|
||||
return nglr.Scope.getter(object(self), field);
|
||||
};
|
||||
fn.isAssignable = field;
|
||||
return fn;
|
||||
};
|
||||
|
||||
nglr.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);
|
||||
};
|
||||
} else {
|
||||
return function (self){
|
||||
var o = obj(self);
|
||||
var i = indexFn(self);
|
||||
return (o) ? o[i] : undefined;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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);
|
||||
} else {
|
||||
throw "Expression '" + fn.isAssignable + "' is not a function.";
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// This is used with json array declaration
|
||||
nglr.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;
|
||||
};
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
};
|
||||
};
|
||||
|
||||
nglr.Parser.prototype.entityDeclaration = function () {
|
||||
var decl = [];
|
||||
while(this.hasTokens()) {
|
||||
decl.push(this.entityDecl());
|
||||
if (!this.expect(';')) {
|
||||
this.assertAllConsumed();
|
||||
}
|
||||
}
|
||||
return function (self){
|
||||
var code = "";
|
||||
for ( var i = 0; i < decl.length; i++) {
|
||||
code += decl[i](self);
|
||||
}
|
||||
return code;
|
||||
};
|
||||
};
|
||||
|
||||
nglr.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 "";
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
nglr.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);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
nglr.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};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
198
src/Scope.js
Normal file
198
src/Scope.js
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
// Copyright (C) 2009 BRAT Tech LLC
|
||||
|
||||
nglr.Scope = function(initialState, name) {
|
||||
this.widgets = [];
|
||||
this.watchListeners = {};
|
||||
this.name = name;
|
||||
initialState = initialState || {};
|
||||
var State = function(){};
|
||||
State.prototype = initialState;
|
||||
this.state = new State();
|
||||
this.state.$parent = initialState;
|
||||
if (name == "ROOT") {
|
||||
this.state.$root = this.state;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Scope.expressionCache = {};
|
||||
|
||||
nglr.Scope.prototype.updateView = function() {
|
||||
var self = this;
|
||||
this.fireWatchers();
|
||||
_.each(this.widgets, function(widget){
|
||||
self.evalWidget(widget, "", {}, function(){
|
||||
this.updateView(self);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
nglr.Scope.prototype.addWidget = function(controller) {
|
||||
if (controller) this.widgets.push(controller);
|
||||
};
|
||||
|
||||
nglr.Scope.prototype.isProperty = function(exp) {
|
||||
for ( var i = 0; i < exp.length; i++) {
|
||||
var ch = exp.charAt(i);
|
||||
if (ch!='.' && !nglr.Lexer.prototype.isIdent(ch)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
nglr.Scope.getter = function(instance, path) {
|
||||
if (!path) return instance;
|
||||
var element = path.split('.');
|
||||
var key;
|
||||
var lastInstance = instance;
|
||||
var len = element.length;
|
||||
for ( var i = 0; i < len; i++) {
|
||||
key = element[i];
|
||||
if (!key.match(/^[\$\w][\$\w\d]*$/))
|
||||
throw "Expression '" + path + "' is not a valid expression for accesing variables.";
|
||||
if (instance) {
|
||||
lastInstance = instance;
|
||||
instance = instance[key];
|
||||
}
|
||||
if (_.isUndefined(instance) && key.charAt(0) == '$') {
|
||||
var type = angular.Global.typeOf(lastInstance);
|
||||
type = angular[type.charAt(0).toUpperCase()+type.substring(1)];
|
||||
var fn = type ? type[[key.substring(1)]] : undefined;
|
||||
if (fn) {
|
||||
instance = _.bind(fn, lastInstance, lastInstance);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof instance === 'function' && !instance.$$factory) {
|
||||
return nglr.bind(lastInstance, instance);
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
|
||||
nglr.Scope.prototype.get = function(path) {
|
||||
return nglr.Scope.getter(this.state, path);
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
};
|
||||
|
||||
nglr.Scope.prototype.setEval = function(expressionText, value) {
|
||||
this.eval(expressionText + "=" + nglr.toJson(value));
|
||||
};
|
||||
|
||||
nglr.Scope.prototype.eval = function(expressionText, context) {
|
||||
var expression = nglr.Scope.expressionCache[expressionText];
|
||||
if (!expression) {
|
||||
var parser = new nglr.Parser(expressionText);
|
||||
expression = parser.statements();
|
||||
parser.assertAllConsumed();
|
||||
nglr.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.
|
||||
nglr.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]);
|
||||
}
|
||||
return true;
|
||||
} catch (e){
|
||||
console.error('Eval Widget Error:', e);
|
||||
var jsonError = nglr.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;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.Scope.prototype.validate = function(expressionText, value) {
|
||||
var expression = nglr.Scope.expressionCache[expressionText];
|
||||
if (!expression) {
|
||||
expression = new nglr.Parser(expressionText).validator();
|
||||
nglr.Scope.expressionCache[expressionText] = expression;
|
||||
}
|
||||
var self = {scope:this};
|
||||
return expression(self)(self, value);
|
||||
};
|
||||
|
||||
nglr.Scope.prototype.entity = function(entityDeclaration) {
|
||||
var expression = new nglr.Parser(entityDeclaration).entityDeclaration();
|
||||
return expression({scope:this});
|
||||
};
|
||||
|
||||
nglr.Scope.prototype.markInvalid = function(widget) {
|
||||
this.state.$invalidWidgets.push(widget);
|
||||
};
|
||||
|
||||
nglr.Scope.prototype.watch = function(declaration) {
|
||||
var self = this;
|
||||
new nglr.Parser(declaration).watch()({
|
||||
scope:this,
|
||||
addListener:function(watch, exp){
|
||||
self.addWatchListener(watch, function(n,o){
|
||||
try {
|
||||
return exp({scope:self}, n, o);
|
||||
} catch(e) {
|
||||
nglr.alert(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
nglr.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);
|
||||
};
|
||||
|
||||
nglr.Scope.prototype.fireWatchers = function() {
|
||||
var self = this;
|
||||
var fired = false;
|
||||
jQuery.each(this.watchListeners, function(name, watcher) {
|
||||
var value = self.eval(watcher.expression);
|
||||
if (value !== watcher.lastValue) {
|
||||
jQuery.each(watcher.listeners, function(i, listener){
|
||||
listener(value, watcher.lastValue);
|
||||
fired = true;
|
||||
});
|
||||
watcher.lastValue = value;
|
||||
}
|
||||
});
|
||||
return fired;
|
||||
};
|
||||
69
src/Server.js
Normal file
69
src/Server.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (C) 2008,2009 BRAT Tech LLC
|
||||
|
||||
nglr.Server = function(url, getScript) {
|
||||
this.url = url;
|
||||
this.nextId = 0;
|
||||
this.getScript = getScript;
|
||||
this.uuid = "_" + ("" + Math.random()).substr(2) + "_";
|
||||
this.maxSize = 1800;
|
||||
};
|
||||
|
||||
nglr.Server.prototype.base64url = function(txt) {
|
||||
return Base64.encode(txt);
|
||||
};
|
||||
|
||||
nglr.Server.prototype.request = function(method, url, request, callback) {
|
||||
var requestId = this.uuid + (this.nextId++);
|
||||
nglr[requestId] = function(response) {
|
||||
delete nglr[requestId];
|
||||
callback(200, response);
|
||||
};
|
||||
var payload = {u:url, m:method, p:request};
|
||||
payload = this.base64url(nglr.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, nglr.noop);
|
||||
}
|
||||
};
|
||||
|
||||
nglr.FrameServer = function(frame) {
|
||||
this.frame = frame;
|
||||
};
|
||||
nglr.FrameServer.PREFIX = "$DATASET:";
|
||||
|
||||
nglr.FrameServer.prototype = {
|
||||
read:function(){
|
||||
this.data = nglr.fromJson(this.frame.name.substr(nglr.FrameServer.PREFIX.length));
|
||||
},
|
||||
write:function(){
|
||||
this.frame.name = nglr.FrameServer.PREFIX + nglr.toJson(this.data);
|
||||
},
|
||||
request: function(method, url, request, callback) {
|
||||
//alert(method + " " + url + " " + nglr.toJson(request) + " " + nglr.toJson(callback));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
nglr.VisualServer = function(delegate, status, update) {
|
||||
this.delegate = delegate;
|
||||
this.update = update;
|
||||
this.status = status;
|
||||
};
|
||||
|
||||
nglr.VisualServer.prototype = {
|
||||
request:function(method, url, request, callback) {
|
||||
var self = this;
|
||||
this.status.beginRequest(request);
|
||||
this.delegate.request(method, url, request, function() {
|
||||
self.status.endRequest();
|
||||
try {
|
||||
callback.apply(this, arguments);
|
||||
} catch (e) {
|
||||
nglr.alert(nglr.toJson(e));
|
||||
}
|
||||
self.update();
|
||||
});
|
||||
}
|
||||
};
|
||||
36
src/Users.js
Normal file
36
src/Users.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (C) 2008,2009 BRAT Tech LLC
|
||||
nglr.Users = function(server, controlBar) {
|
||||
this.server = server;
|
||||
this.controlBar = controlBar;
|
||||
};
|
||||
|
||||
nglr.Users.prototype = {
|
||||
fetchCurrentUser:function(callback) {
|
||||
var self = this;
|
||||
this.server.request("GET", "/account.json", {}, function(code, response){
|
||||
self.current = response.user;
|
||||
callback(response.user);
|
||||
});
|
||||
},
|
||||
|
||||
logout: function(callback) {
|
||||
var self = this;
|
||||
this.controlBar.logout(function(){
|
||||
delete self.current;
|
||||
(callback||nglr.noop)();
|
||||
});
|
||||
},
|
||||
|
||||
login: function(callback) {
|
||||
var self = this;
|
||||
this.controlBar.login(function(){
|
||||
self.fetchCurrentUser(function(){
|
||||
(callback||nglr.noop)();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
notAuthorized: function(){
|
||||
this.controlBar.notAuthorized();
|
||||
}
|
||||
};
|
||||
80
src/Validators.js
Normal file
80
src/Validators.js
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (C) 2009 BRAT Tech LLC
|
||||
|
||||
angular.validator.regexp = function(value, regexp, msg) {
|
||||
if (!value.match(regexp)) {
|
||||
return msg ||
|
||||
"Value does not match expected format " + regexp + ".";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
angular.validator.number = function(value, min, max) {
|
||||
var num = 1 * value;
|
||||
if (num == value) {
|
||||
if (typeof min != 'undefined' && num < min) {
|
||||
return "Value can not be less than " + min + ".";
|
||||
}
|
||||
if (typeof min != 'undefined' && num > max) {
|
||||
return "Value can not be greater than " + max + ".";
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return "Value is not a number.";
|
||||
}
|
||||
};
|
||||
|
||||
angular.validator.integer = function(value, min, max) {
|
||||
var number = angular.validator.number(value, min, max);
|
||||
if (number === null && value != Math.round(value)) {
|
||||
return "Value is not a whole number.";
|
||||
}
|
||||
return number;
|
||||
};
|
||||
|
||||
angular.validator.date = function(value, min, max) {
|
||||
if (value.match(/^\d\d?\/\d\d?\/\d\d\d\d$/)) {
|
||||
return null;
|
||||
}
|
||||
return "Value is not a date. (Expecting format: 12/31/2009).";
|
||||
};
|
||||
|
||||
angular.validator.ssn = function(value) {
|
||||
if (value.match(/^\d\d\d-\d\d-\d\d\d\d$/)) {
|
||||
return null;
|
||||
}
|
||||
return "SSN needs to be in 999-99-9999 format.";
|
||||
};
|
||||
|
||||
angular.validator.email = function(value) {
|
||||
if (value.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.";
|
||||
};
|
||||
|
||||
angular.validator.phone = function(value) {
|
||||
if (value.match(/^1\(\d\d\d\)\d\d\d-\d\d\d\d$/)) {
|
||||
return null;
|
||||
}
|
||||
if (value.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.";
|
||||
};
|
||||
|
||||
angular.validator.url = function(value) {
|
||||
if (value.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.";
|
||||
};
|
||||
|
||||
angular.validator.json = function(value) {
|
||||
try {
|
||||
nglr.fromJson(value);
|
||||
return null;
|
||||
} catch (e) {
|
||||
return e.toString();
|
||||
}
|
||||
};
|
||||
774
src/Widgets.js
Normal file
774
src/Widgets.js
Normal file
|
|
@ -0,0 +1,774 @@
|
|||
// Copyright (C) 2009 BRAT Tech LLC
|
||||
|
||||
|
||||
nglr.WidgetFactory = function(serverUrl, database) {
|
||||
this.nextUploadId = 0;
|
||||
this.serverUrl = serverUrl;
|
||||
this.database = database;
|
||||
this.createSWF = swfobject.createSWF;
|
||||
this.onChangeListener = function(){};
|
||||
};
|
||||
|
||||
nglr.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 nglr.ButtonController(input[0], exp);
|
||||
event = "click";
|
||||
bubbleEvent = false;
|
||||
} else if (type == 'text' || type == 'textarea' || type == 'hidden' || type == 'password') {
|
||||
controller = new nglr.TextController(input[0], exp);
|
||||
event = "keyup change";
|
||||
} else if (type == 'checkbox') {
|
||||
controller = new nglr.CheckboxController(input[0], exp);
|
||||
event = "click";
|
||||
} else if (type == 'radio') {
|
||||
controller = new nglr.RadioController(input[0], exp);
|
||||
event="click";
|
||||
} else if (type == 'select-one') {
|
||||
controller = new nglr.SelectController(input[0], exp);
|
||||
} else if (type == 'select-multiple') {
|
||||
controller = new nglr.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;
|
||||
};
|
||||
|
||||
nglr.WidgetFactory.prototype.createFileController = function(fileInput) {
|
||||
var uploadId = '__uploadWidget_' + (this.nextUploadId++);
|
||||
var view = nglr.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 nglr.FileController(view, fileInput[0].name, swfNode, this.serverUrl + "/data/" + this.database);
|
||||
jQuery(swfNode).data('controller', cntl);
|
||||
return cntl;
|
||||
};
|
||||
|
||||
nglr.WidgetFactory.prototype.createTextWidget = function(textInput) {
|
||||
var controller = new nglr.TextController(textInput);
|
||||
controller.onChange(this.onChangeListener);
|
||||
return controller;
|
||||
};
|
||||
|
||||
/////////////////////
|
||||
// FileController
|
||||
///////////////////////
|
||||
|
||||
nglr.FileController = function(view, scopeName, uploader, databaseUrl) {
|
||||
this.view = view;
|
||||
this.uploader = uploader;
|
||||
this.scopeName = scopeName;
|
||||
this.attachmentsPath = databaseUrl + '/_attachments';
|
||||
this.value = null;
|
||||
this.lastValue = undefined;
|
||||
};
|
||||
|
||||
nglr.FileController.dispatchEvent = function(id, event, args) {
|
||||
var object = document.getElementById(id);
|
||||
var controller = jQuery(object).data("controller");
|
||||
nglr.FileController.prototype['_on_' + event].apply(controller, args);
|
||||
};
|
||||
|
||||
nglr.FileController.template = function(id) {
|
||||
return jQuery('<span class="ng-upload-widget">' +
|
||||
'<input type="checkbox" ng-non-bindable="true"/>' +
|
||||
'<object id="' + id + '" />' +
|
||||
'<a></a>' +
|
||||
'<span/>' +
|
||||
'</span>');
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_cancel = function() {
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_complete = function() {
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_httpStatus = function(status) {
|
||||
nglr.alert("httpStatus:" + this.scopeName + " status:" + status);
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_ioError = function() {
|
||||
nglr.alert("ioError:" + this.scopeName);
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_open = function() {
|
||||
nglr.alert("open:" + this.scopeName);
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_progress = function(bytesLoaded, bytesTotal) {
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_securityError = function() {
|
||||
nglr.alert("securityError:" + this.scopeName);
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_uploadCompleteData = function(data) {
|
||||
var value = nglr.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();
|
||||
};
|
||||
|
||||
nglr.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();
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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);
|
||||
};
|
||||
|
||||
nglr.FileController.prototype.upload = function() {
|
||||
if (this.name) {
|
||||
this.uploader.uploadFile(this.attachmentsPath);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///////////////////////
|
||||
// NullController
|
||||
///////////////////////
|
||||
nglr.NullController = function(view) {this.view = view;};
|
||||
nglr.NullController.prototype.updateModel = function() { return true; };
|
||||
nglr.NullController.prototype.updateView = function() { };
|
||||
nglr.NullController.instance = new nglr.NullController();
|
||||
|
||||
|
||||
///////////////////////
|
||||
// ButtonController
|
||||
///////////////////////
|
||||
nglr.ButtonController = function(view) {this.view = view;};
|
||||
nglr.ButtonController.prototype.updateModel = function(scope) { return true; };
|
||||
nglr.ButtonController.prototype.updateView = function(scope) {};
|
||||
|
||||
///////////////////////
|
||||
// TextController
|
||||
///////////////////////
|
||||
nglr.TextController = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.validator = view.getAttribute('ng-validate');
|
||||
this.required = typeof view.attributes['ng-required'] != "undefined";
|
||||
this.lastErrorText = null;
|
||||
this.lastValue = undefined;
|
||||
this.initialValue = view.value;
|
||||
var widget = view.getAttribute('ng-widget');
|
||||
if (widget === 'datepicker') {
|
||||
jQuery(view).datepicker();
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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);
|
||||
}
|
||||
jQuery(view).toggleClass('ng-validation-error', isValidationError);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// CheckboxController
|
||||
///////////////////////
|
||||
nglr.CheckboxController = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.lastValue = undefined;
|
||||
this.initialValue = view.checked ? view.value : "";
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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);
|
||||
}
|
||||
input.checked = input.value == (''+value);
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// SelectController
|
||||
///////////////////////
|
||||
nglr.SelectController = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.lastValue = undefined;
|
||||
this.initialValue = view.value;
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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
|
||||
///////////////////////
|
||||
nglr.MultiSelectController = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.lastValue = undefined;
|
||||
this.initialValue = this.selected();
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
for ( var i = 0; i < options.length; i++) {
|
||||
var option = options[i];
|
||||
option.selected = _.include(selected, option.value);
|
||||
}
|
||||
this.lastValue = selected;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// RadioController
|
||||
///////////////////////
|
||||
nglr.RadioController = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.lastChecked = undefined;
|
||||
this.lastValue = undefined;
|
||||
this.inputValue = view.value;
|
||||
this.initialValue = view.checked ? view.value : null;
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
//ElementController
|
||||
///////////////////////
|
||||
nglr.BindUpdater = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = nglr.Binder.parseBindings(exp);
|
||||
this.hasError = false;
|
||||
this.scopeSelf = {element:view};
|
||||
};
|
||||
|
||||
nglr.BindUpdater.toText = function(obj) {
|
||||
var e = nglr.escapeHtml;
|
||||
switch(typeof obj) {
|
||||
case "string":
|
||||
case "boolean":
|
||||
case "number":
|
||||
return e(obj);
|
||||
case "function":
|
||||
return nglr.BindUpdater.toText(obj());
|
||||
case "object":
|
||||
if (nglr.isNode(obj)) {
|
||||
return nglr.outerHTML(obj);
|
||||
} else if (obj instanceof angular.filter.Meta) {
|
||||
switch(typeof obj.html) {
|
||||
case "string":
|
||||
case "number":
|
||||
return obj.html;
|
||||
case "function":
|
||||
return obj.html();
|
||||
case "object":
|
||||
if (nglr.isNode(obj.html))
|
||||
return nglr.outerHTML(obj.html);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch(typeof obj.text) {
|
||||
case "string":
|
||||
case "number":
|
||||
return e(obj.text);
|
||||
case "function":
|
||||
return e(obj.text());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (obj === null)
|
||||
return "";
|
||||
return e(nglr.toJson(obj, true));
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
nglr.BindUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.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 = nglr.Binder.binding(part);
|
||||
if (binding) {
|
||||
scope.evalWidget(this, binding, this.scopeSelf, function(value){
|
||||
html.push(nglr.BindUpdater.toText(value));
|
||||
}, function(e, text){
|
||||
nglr.setHtml(this.view, text);
|
||||
});
|
||||
if (this.hasError) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
html.push(nglr.escapeHtml(part));
|
||||
}
|
||||
}
|
||||
nglr.setHtml(this.view, html.join(''));
|
||||
};
|
||||
|
||||
nglr.BindAttrUpdater = function(view, attrs) {
|
||||
this.view = view;
|
||||
this.attrs = attrs;
|
||||
};
|
||||
|
||||
nglr.BindAttrUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.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 = nglr.Binder.parseBindings(attributeTemplates[attrName]);
|
||||
var attrValues = [];
|
||||
for ( var i = 0; i < attributeTemplate.length; i++) {
|
||||
var binding = nglr.Binder.binding(attributeTemplate[i]);
|
||||
if (binding) {
|
||||
try {
|
||||
var value = scope.eval(binding, {element:jNode[0], attrName:attrName});
|
||||
if (value && (value.constructor !== nglr.array || value.length !== 0))
|
||||
attrValues.push(value);
|
||||
} catch (e) {
|
||||
this.hasError = true;
|
||||
console.error('BindAttrUpdater', e);
|
||||
var jsonError = nglr.toJson(e, true);
|
||||
attrValues.push('[' + jsonError + ']');
|
||||
jNode.
|
||||
addClass('ng-exception').
|
||||
attr('ng-error', jsonError);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
};
|
||||
|
||||
nglr.EvalUpdater = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.hasError = false;
|
||||
};
|
||||
nglr.EvalUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.EvalUpdater.prototype.updateView = function(scope) {
|
||||
scope.evalWidget(this, this.exp);
|
||||
};
|
||||
|
||||
nglr.HideUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.HideUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.HideUpdater.prototype.updateView = function(scope) {
|
||||
scope.evalWidget(this, this.exp, {}, function(hideValue){
|
||||
var view = jQuery(this.view);
|
||||
if (nglr.toBoolean(hideValue)) {
|
||||
view.hide();
|
||||
} else {
|
||||
view.show();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
nglr.ShowUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.ShowUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.ShowUpdater.prototype.updateView = function(scope) {
|
||||
scope.evalWidget(this, this.exp, {}, function(hideValue){
|
||||
var view = jQuery(this.view);
|
||||
if (nglr.toBoolean(hideValue)) {
|
||||
view.show();
|
||||
} else {
|
||||
view.hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
nglr.ClassUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.ClassUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.ClassUpdater.prototype.updateView = function(scope) {
|
||||
scope.evalWidget(this, this.exp, {}, function(classValue){
|
||||
if (classValue !== null && classValue !== undefined) {
|
||||
this.view.className = classValue;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
nglr.ClassEvenUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.ClassEvenUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.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);
|
||||
});
|
||||
};
|
||||
|
||||
nglr.ClassOddUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.ClassOddUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.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);
|
||||
});
|
||||
};
|
||||
|
||||
nglr.StyleUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.StyleUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.StyleUpdater.prototype.updateView = function(scope) {
|
||||
scope.evalWidget(this, this.exp, {}, function(styleValue){
|
||||
jQuery(this.view).attr('style', "").css(styleValue);
|
||||
});
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// RepeaterUpdater
|
||||
///////////////////////
|
||||
nglr.RepeaterUpdater = function(view, repeaterExpression, template, prefix) {
|
||||
this.view = view;
|
||||
this.template = template;
|
||||
this.prefix = prefix;
|
||||
this.children = [];
|
||||
var match = repeaterExpression.match(/^\s*(.+)\s+in\s+(.*)\s*$/);
|
||||
if (! match) {
|
||||
throw "Expected ng-repeat in form of 'item in collection' but got '" +
|
||||
repeaterExpression + "'.";
|
||||
}
|
||||
var keyValue = match[1];
|
||||
this.iteratorExp = match[2];
|
||||
match = keyValue.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
|
||||
if (!match) {
|
||||
throw "'item' in 'item in collection' should be identifier or (key, value) but get '" +
|
||||
keyValue + "'.";
|
||||
}
|
||||
this.valueExp = match[3] || match[1];
|
||||
this.keyExp = match[2];
|
||||
};
|
||||
|
||||
nglr.RepeaterUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.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;
|
||||
jQuery.each(iterator, function(key, value){
|
||||
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 nglr.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();
|
||||
unneeded.element.removeNode();
|
||||
}
|
||||
// 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
|
||||
//////////////////////////////////
|
||||
|
||||
nglr.PopUp = function(doc) {
|
||||
this.doc = doc;
|
||||
};
|
||||
|
||||
nglr.PopUp.OUT_EVENT = "mouseleave mouseout click dblclick keypress keyup";
|
||||
|
||||
nglr.PopUp.prototype.bind = function () {
|
||||
var self = this;
|
||||
this.doc.find('.ng-validation-error,.ng-exception').
|
||||
live("mouseover", nglr.PopUp.onOver);
|
||||
};
|
||||
|
||||
nglr.PopUp.onOver = function(e) {
|
||||
nglr.PopUp.onOut();
|
||||
var jNode = jQuery(this);
|
||||
jNode.bind(nglr.PopUp.OUT_EVENT, nglr.PopUp.onOut);
|
||||
var position = jNode.position();
|
||||
var de = document.documentElement;
|
||||
var w = self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
|
||||
var hasArea = w - position.left;
|
||||
var width = 300;
|
||||
var title = jNode.hasClass("ng-exception") ? "EXCEPTION:" : "Validation error...";
|
||||
var msg = jNode.attr("ng-error");
|
||||
|
||||
var x;
|
||||
var arrowPos = hasArea>(width+75) ? "left" : "right";
|
||||
var tip = jQuery(
|
||||
"<div id='ng-callout' style='width:"+width+"px'>" +
|
||||
"<div class='ng-arrow-"+arrowPos+"'/>" +
|
||||
"<div class='ng-title'>"+title+"</div>" +
|
||||
"<div class='ng-content'>"+msg+"</div>" +
|
||||
"</div>");
|
||||
jQuery("body").append(tip);
|
||||
if(arrowPos === 'left'){
|
||||
x = position.left + this.offsetWidth + 11;
|
||||
}else{
|
||||
x = position.left - (width + 15);
|
||||
tip.find('.ng-arrow-right').css({left:width+1});
|
||||
}
|
||||
|
||||
tip.css({left: x+"px", top: (position.top - 3)+"px"});
|
||||
return true;
|
||||
};
|
||||
|
||||
nglr.PopUp.onOut = function() {
|
||||
jQuery('#ng-callout').
|
||||
unbind(nglr.PopUp.OUT_EVENT, nglr.PopUp.onOut).
|
||||
remove();
|
||||
return true;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
// Status
|
||||
//////////////////////////////////
|
||||
|
||||
|
||||
nglr.Status = function(body) {
|
||||
this.loader = body.append(nglr.Status.DOM).find("#ng-loading");
|
||||
this.requestCount = 0;
|
||||
};
|
||||
|
||||
nglr.Status.DOM ='<div id="ng-spacer"></div><div id="ng-loading">loading....</div>';
|
||||
|
||||
nglr.Status.prototype.beginRequest = function () {
|
||||
if (this.requestCount === 0) {
|
||||
this.loader.show();
|
||||
}
|
||||
this.requestCount++;
|
||||
};
|
||||
|
||||
nglr.Status.prototype.endRequest = function () {
|
||||
this.requestCount--;
|
||||
if (this.requestCount === 0) {
|
||||
this.loader.hide("fold");
|
||||
}
|
||||
};
|
||||
764
src/Widgets.js.orig
Normal file
764
src/Widgets.js.orig
Normal file
|
|
@ -0,0 +1,764 @@
|
|||
// Copyright (C) 2009 BRAT Tech LLC
|
||||
|
||||
|
||||
nglr.WidgetFactory = function(serverUrl) {
|
||||
this.nextUploadId = 0;
|
||||
this.serverUrl = serverUrl;
|
||||
this.createSWF = swfobject.createSWF;
|
||||
this.onChangeListener = function(){};
|
||||
};
|
||||
|
||||
nglr.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') {
|
||||
controller = new nglr.ButtonController(input[0], exp);
|
||||
event = "click";
|
||||
bubbleEvent = false;
|
||||
} else if (type == 'text' || type == 'textarea') {
|
||||
controller = new nglr.TextController(input[0], exp);
|
||||
event = "keyup change";
|
||||
} else if (type == 'checkbox') {
|
||||
controller = new nglr.CheckboxController(input[0], exp);
|
||||
event = "click";
|
||||
} else if (type == 'radio') {
|
||||
controller = new nglr.RadioController(input[0], exp);
|
||||
event="click";
|
||||
} else if (type == 'select-one') {
|
||||
controller = new nglr.SelectController(input[0], exp);
|
||||
} else if (type == 'select-multiple') {
|
||||
controller = new nglr.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;
|
||||
};
|
||||
|
||||
nglr.WidgetFactory.prototype.createFileController = function(fileInput) {
|
||||
var uploadId = '__uploadWidget_' + (this.nextUploadId++);
|
||||
var view = nglr.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 nglr.FileController(view, fileInput[0].name, swfNode, this.serverUrl);
|
||||
jQuery(swfNode).data('controller', cntl);
|
||||
return cntl;
|
||||
};
|
||||
|
||||
nglr.WidgetFactory.prototype.createTextWidget = function(textInput) {
|
||||
var controller = new nglr.TextController(textInput);
|
||||
controller.onChange(this.onChangeListener);
|
||||
return controller;
|
||||
};
|
||||
|
||||
/////////////////////
|
||||
// FileController
|
||||
///////////////////////
|
||||
|
||||
nglr.FileController = function(view, scopeName, uploader, serverUrl) {
|
||||
this.view = view;
|
||||
this.uploader = uploader;
|
||||
this.scopeName = scopeName;
|
||||
this.uploadUrl = serverUrl + '/upload';
|
||||
this.attachmentBase = serverUrl + '/attachments';
|
||||
this.value = null;
|
||||
this.lastValue = undefined;
|
||||
};
|
||||
|
||||
nglr.FileController.dispatchEvent = function(id, event, args) {
|
||||
var object = document.getElementById(id);
|
||||
var controller = jQuery(object).data("controller");
|
||||
nglr.FileController.prototype['_on_' + event].apply(controller, args);
|
||||
};
|
||||
|
||||
nglr.FileController.template = function(id) {
|
||||
return jQuery('<span class="ng-upload-widget">' +
|
||||
'<input type="checkbox" ng-non-bindable="true"/>' +
|
||||
'<object id="' + id + '" />' +
|
||||
'<a></a>' +
|
||||
'<span/>' +
|
||||
'</span>');
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_cancel = function() {
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_complete = function() {
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_httpStatus = function(status) {
|
||||
nglr.alert("httpStatus:" + this.scopeName + " status:" + status);
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_ioError = function() {
|
||||
nglr.alert("ioError:" + this.scopeName);
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_open = function() {
|
||||
nglr.alert("open:" + this.scopeName);
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_progress = function(bytesLoaded, bytesTotal) {
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_securityError = function() {
|
||||
nglr.alert("securityError:" + this.scopeName);
|
||||
};
|
||||
|
||||
nglr.FileController.prototype._on_uploadCompleteData = function(data) {
|
||||
this.value = nglr.fromJson(data);
|
||||
this.value.url = this.attachmentBase + '/' + this.value.id + '/' + this.value.text;
|
||||
this.view.find("input").attr('checked', true);
|
||||
var scope = this.view.scope();
|
||||
this.updateModel(scope);
|
||||
scope.get('$binder').updateView();
|
||||
};
|
||||
|
||||
nglr.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(filters.bytes(size));
|
||||
this.upload();
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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.name);
|
||||
this.view.find("span").text(filters.bytes(this.value.size));
|
||||
}
|
||||
this.view.find("input").attr('checked', !!modelValue);
|
||||
};
|
||||
|
||||
nglr.FileController.prototype.upload = function() {
|
||||
if (this.name) {
|
||||
this.uploader.uploadFile(this.uploadUrl);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///////////////////////
|
||||
// NullController
|
||||
///////////////////////
|
||||
nglr.NullController = function(view) {this.view = view;};
|
||||
nglr.NullController.prototype.updateModel = function() { return true; };
|
||||
nglr.NullController.prototype.updateView = function() { };
|
||||
nglr.NullController.instance = new nglr.NullController();
|
||||
|
||||
|
||||
///////////////////////
|
||||
// ButtonController
|
||||
///////////////////////
|
||||
nglr.ButtonController = function(view) {this.view = view;};
|
||||
nglr.ButtonController.prototype.updateModel = function(scope) { return true; };
|
||||
nglr.ButtonController.prototype.updateView = function(scope) {};
|
||||
|
||||
///////////////////////
|
||||
// TextController
|
||||
///////////////////////
|
||||
nglr.TextController = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.validator = view.getAttribute('ng-validate');
|
||||
this.required = typeof view.attributes['ng-required'] != "undefined";
|
||||
this.lastErrorText = null;
|
||||
this.lastValue = undefined;
|
||||
this.initialValue = view.value;
|
||||
var widget = view.getAttribute('ng-widget');
|
||||
if (widget === 'datepicker') {
|
||||
jQuery(view).datepicker();
|
||||
}
|
||||
};
|
||||
|
||||
nglr.TextController.prototype.updateModel = function(scope) {
|
||||
var value = this.view.value;
|
||||
if (this.lastValue === value) {
|
||||
return false;
|
||||
} else {
|
||||
scope.set(this.exp, value);
|
||||
this.lastValue = value;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.TextController.prototype.updateView = function(scope) {
|
||||
var view = this.view;
|
||||
var value = scope.get(this.exp);
|
||||
if (typeof value === "undefined") {
|
||||
value = this.initialValue;
|
||||
scope.set(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);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// CheckboxController
|
||||
///////////////////////
|
||||
nglr.CheckboxController = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.lastValue = undefined;
|
||||
this.initialValue = view.checked ? view.value : "";
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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);
|
||||
}
|
||||
input.checked = input.value == (''+value);
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// SelectController
|
||||
///////////////////////
|
||||
nglr.SelectController = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.lastValue = undefined;
|
||||
this.initialValue = view.value;
|
||||
};
|
||||
|
||||
nglr.SelectController.prototype.updateModel = function(scope) {
|
||||
var input = this.view;
|
||||
if (input.selectedIndex < 0) {
|
||||
scope.set(this.exp, null);
|
||||
} else {
|
||||
var value = this.view.value;
|
||||
if (this.lastValue === value) {
|
||||
return false;
|
||||
} else {
|
||||
scope.set(this.exp, value);
|
||||
this.lastValue = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nglr.SelectController.prototype.updateView = function(scope) {
|
||||
var input = this.view;
|
||||
var value = scope.get(this.exp);
|
||||
if (typeof value === 'undefined') {
|
||||
value = this.initialValue;
|
||||
scope.set(this.exp, value);
|
||||
}
|
||||
if (value !== this.lastValue) {
|
||||
input.value = value ? value : "";
|
||||
this.lastValue = value;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// MultiSelectController
|
||||
///////////////////////
|
||||
nglr.MultiSelectController = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.lastValue = undefined;
|
||||
this.initialValue = this.selected();
|
||||
};
|
||||
|
||||
nglr.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;
|
||||
};
|
||||
|
||||
nglr.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.set(this.exp, value);
|
||||
this.lastValue = value;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.MultiSelectController.prototype.updateView = function(scope) {
|
||||
var input = this.view;
|
||||
var selected = scope.get(this.exp);
|
||||
if (typeof selected === "undefined") {
|
||||
selected = this.initialValue;
|
||||
scope.set(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 = selected.contains(option.value);
|
||||
}
|
||||
this.lastValue = selected;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// RadioController
|
||||
///////////////////////
|
||||
nglr.RadioController = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.lastChecked = undefined;
|
||||
this.lastValue = undefined;
|
||||
this.inputValue = view.value;
|
||||
this.initialValue = view.checked ? view.value : null;
|
||||
};
|
||||
|
||||
nglr.RadioController.prototype.updateModel = function(scope) {
|
||||
var input = this.view;
|
||||
if (this.lastChecked) {
|
||||
return false;
|
||||
} else {
|
||||
input.checked = true;
|
||||
this.lastValue = scope.set(this.exp, this.inputValue);
|
||||
this.lastChecked = true;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.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.set(this.exp, value);
|
||||
}
|
||||
if (this.lastValue != value) {
|
||||
this.lastChecked = input.checked = this.inputValue == (''+value);
|
||||
this.lastValue = value;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
//ElementController
|
||||
///////////////////////
|
||||
nglr.BindUpdater = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp.parseBindings();
|
||||
this.hasError = false;
|
||||
this.scopeSelf = {element:view};
|
||||
};
|
||||
|
||||
nglr.BindUpdater.toText = function(obj) {
|
||||
var e = nglr.escapeHtml;
|
||||
switch(typeof obj) {
|
||||
case "string":
|
||||
case "boolean":
|
||||
case "number":
|
||||
return e(obj);
|
||||
case "function":
|
||||
return nglr.BindUpdater.toText(obj());
|
||||
case "object":
|
||||
if (nglr.isNode(obj)) {
|
||||
return nglr.outerHTML(obj);
|
||||
} else if (obj && obj.TAG === filters.Meta.TAG) {
|
||||
switch(typeof obj.html) {
|
||||
case "string":
|
||||
case "number":
|
||||
return obj.html;
|
||||
case "function":
|
||||
return obj.html();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch(typeof obj.text) {
|
||||
case "string":
|
||||
case "number":
|
||||
return e(obj.text);
|
||||
case "function":
|
||||
return e(obj.text());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (obj === null)
|
||||
return "";
|
||||
return e(nglr.toJson(obj, true));
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
nglr.BindUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.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 = part.binding();
|
||||
if (binding) {
|
||||
scope.evalWidget(this, binding, this.scopeSelf, function(value){
|
||||
html.push(nglr.BindUpdater.toText(value));
|
||||
}, function(e, text){
|
||||
nglr.setHtml(this.view, text);
|
||||
});
|
||||
if (this.hasError) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
html.push(nglr.escapeHtml(part));
|
||||
}
|
||||
}
|
||||
nglr.setHtml(this.view, html.join(''));
|
||||
};
|
||||
|
||||
nglr.BindAttrUpdater = function(view, attrs) {
|
||||
this.view = view;
|
||||
this.attrs = attrs;
|
||||
};
|
||||
|
||||
nglr.BindAttrUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.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 = attributeTemplates[attrName].parseBindings();
|
||||
var attrValues = [];
|
||||
for ( var i = 0; i < attributeTemplate.length; i++) {
|
||||
var binding = attributeTemplate[i].binding();
|
||||
if (binding) {
|
||||
try {
|
||||
var value = scope.eval(binding, {element:jNode[0], attrName:attrName});
|
||||
if (value && (value.constructor !== nglr.array || value.length !== 0))
|
||||
attrValues.push(value);
|
||||
} catch (e) {
|
||||
this.hasError = true;
|
||||
console.error('BindAttrUpdater', e);
|
||||
var jsonError = nglr.toJson(e, true);
|
||||
attrValues.push('[' + jsonError + ']');
|
||||
jNode.
|
||||
addClass('ng-exception').
|
||||
attr('ng-error', jsonError);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
};
|
||||
|
||||
nglr.EvalUpdater = function(view, exp) {
|
||||
this.view = view;
|
||||
this.exp = exp;
|
||||
this.hasError = false;
|
||||
};
|
||||
nglr.EvalUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.EvalUpdater.prototype.updateView = function(scope) {
|
||||
scope.evalWidget(this, this.exp);
|
||||
};
|
||||
|
||||
nglr.HideUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.HideUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.HideUpdater.prototype.updateView = function(scope) {
|
||||
scope.evalWidget(this, this.exp, {}, function(hideValue){
|
||||
var view = jQuery(this.view);
|
||||
if (nglr.toBoolean(hideValue)) {
|
||||
view.hide();
|
||||
} else {
|
||||
view.show();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
nglr.ShowUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.ShowUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.ShowUpdater.prototype.updateView = function(scope) {
|
||||
scope.evalWidget(this, this.exp, {}, function(hideValue){
|
||||
var view = jQuery(this.view);
|
||||
if (nglr.toBoolean(hideValue)) {
|
||||
view.show();
|
||||
} else {
|
||||
view.hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
nglr.ClassUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.ClassUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.ClassUpdater.prototype.updateView = function(scope) {
|
||||
scope.evalWidget(this, this.exp, {}, function(classValue){
|
||||
if (classValue !== null && classValue !== undefined) {
|
||||
this.view.className = classValue;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
nglr.ClassEvenUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.ClassEvenUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.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);
|
||||
});
|
||||
};
|
||||
|
||||
nglr.ClassOddUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.ClassOddUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.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);
|
||||
});
|
||||
};
|
||||
|
||||
nglr.StyleUpdater = function(view, exp) { this.view = view; this.exp = exp; };
|
||||
nglr.StyleUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.StyleUpdater.prototype.updateView = function(scope) {
|
||||
scope.evalWidget(this, this.exp, {}, function(styleValue){
|
||||
jQuery(this.view).attr('style', "").css(styleValue);
|
||||
});
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// RepeaterUpdater
|
||||
///////////////////////
|
||||
nglr.RepeaterUpdater = function(view, repeaterExpression, template, prefix) {
|
||||
this.view = view;
|
||||
this.template = template;
|
||||
this.prefix = prefix;
|
||||
this.children = [];
|
||||
var match = repeaterExpression.match(/^\s*(.+)\s+in\s+(.*)\s*$/);
|
||||
if (! match) {
|
||||
throw "Expected ng-repeat in form of 'item in collection' but got '" + repeaterExpression + "'.";
|
||||
}
|
||||
this.itemExp = match[1];
|
||||
this.iteratorExp = match[2];
|
||||
};
|
||||
|
||||
nglr.RepeaterUpdater.prototype.updateModel = function(scope) {};
|
||||
nglr.RepeaterUpdater.prototype.updateView = function(scope) {
|
||||
scope.evalWidget(this, this.iteratorExp, {}, function(iterator){
|
||||
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 itemExp = this.itemExp;
|
||||
for ( var i = 0; i < iteratorLength; i++) {
|
||||
if (i < iteratorLength) {
|
||||
if (i < childrenLength) { // reuse children
|
||||
child = this.children[i];
|
||||
child.scope.set(itemExp, iterator[i]);
|
||||
} else { // grow children
|
||||
var name = this.prefix +
|
||||
itemExp + " in " + this.iteratorExp + "[" + i + "]";
|
||||
var childScope = new nglr.Scope(scope.state, name);
|
||||
childScope.set('$index', i);
|
||||
childScope.set(itemExp, iterator[i]);
|
||||
child = { scope:childScope, element:this.template(childScope, this.prefix, i) };
|
||||
cursor.after(child.element);
|
||||
this.children.push(child);
|
||||
}
|
||||
cursor = child.element;
|
||||
var s = new Date().getTime();
|
||||
child.scope.updateView();
|
||||
time += new Date().getTime() - s;
|
||||
}
|
||||
}
|
||||
// shrink children
|
||||
for ( var r = childrenLength; r > iteratorLength; --r) {
|
||||
var unneeded = this.children.pop();
|
||||
unneeded.element.removeNode();
|
||||
}
|
||||
// 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
|
||||
//////////////////////////////////
|
||||
|
||||
nglr.PopUp = function(doc) {
|
||||
this.doc = doc;
|
||||
};
|
||||
|
||||
nglr.PopUp.OUT_EVENT = "mouseleave mouseout click dblclick keypress keyup";
|
||||
|
||||
nglr.PopUp.prototype.bind = function () {
|
||||
var self = this;
|
||||
this.doc.find('.ng-validation-error,.ng-exception').
|
||||
live("mouseover", nglr.PopUp.onOver);
|
||||
};
|
||||
|
||||
nglr.PopUp.onOver = function(e) {
|
||||
nglr.PopUp.onOut();
|
||||
var jNode = jQuery(this);
|
||||
jNode.bind(nglr.PopUp.OUT_EVENT, nglr.PopUp.onOut);
|
||||
var position = jNode.position();
|
||||
var de = document.documentElement;
|
||||
var w = self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
|
||||
var hasArea = w - position.left;
|
||||
var width = 300;
|
||||
var title = jNode.hasClass("ng-exception") ? "EXCEPTION:" : "Validation error...";
|
||||
var msg = jNode.attr("ng-error");
|
||||
|
||||
var x;
|
||||
var arrowPos = hasArea>(width+75) ? "left" : "right";
|
||||
var tip = jQuery(
|
||||
"<div id='ng-callout' style='width:"+width+"px'>" +
|
||||
"<div class='ng-arrow-"+arrowPos+"'/>" +
|
||||
"<div class='ng-title'>"+title+"</div>" +
|
||||
"<div class='ng-content'>"+msg+"</div>" +
|
||||
"</div>");
|
||||
jQuery("body").append(tip);
|
||||
if(arrowPos === 'left'){
|
||||
x = position.left + this.offsetWidth + 11;
|
||||
}else{
|
||||
x = position.left - (width + 15);
|
||||
tip.find('.ng-arrow-right').css({left:width+1});
|
||||
}
|
||||
|
||||
tip.css({left: x+"px", top: (position.top - 3)+"px"});
|
||||
return true;
|
||||
};
|
||||
|
||||
nglr.PopUp.onOut = function() {
|
||||
jQuery('#ng-callout').
|
||||
unbind(nglr.PopUp.OUT_EVENT, nglr.PopUp.onOut).
|
||||
remove();
|
||||
return true;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
// Status
|
||||
//////////////////////////////////
|
||||
|
||||
nglr.Status = function (body) {
|
||||
this.body = body;
|
||||
this.requestCount = 0;
|
||||
};
|
||||
nglr.Status.ANGULAR = "<a class='ng-angular-logo' href='http://www.getangular.com'>&lt;angular/&gt;</a>™";
|
||||
|
||||
nglr.Status.prototype.beginRequest = function () {
|
||||
if (this.requestCount === 0) {
|
||||
<<<<<<< HEAD:public/javascripts/nglr/Widgets.js
|
||||
this.dialogView = jQuery('<div class="ng-dialog" title="'+nglr.ControlBar.ANGULAR+' Server Communication:">Please Wait...<div/><div class="loader"></div></div>');
|
||||
=======
|
||||
this.dialogView = jQuery('<div title="'+nglr.Status.ANGULAR+' Server Communication:">Please Wait...<div/></div>');
|
||||
this.progressWidget = this.dialogView.find("div");
|
||||
this.progressWidget.progressbar({value:0});
|
||||
>>>>>>> master:public/javascripts/nglr/Widgets.js
|
||||
this.dialogView.dialog({bgiframe:true, minHeight:50, modal:true});
|
||||
this.maxRequestCount = 0;
|
||||
}
|
||||
this.requestCount++;
|
||||
this.maxRequestCount++;
|
||||
};
|
||||
|
||||
nglr.Status.prototype.endRequest = function () {
|
||||
this.requestCount--;
|
||||
if (this.requestCount === 0) {
|
||||
this.dialogView.dialog("destroy");
|
||||
this.dialogView.remove();
|
||||
this.dialogView = null;
|
||||
}
|
||||
};
|
||||
100
src/XSitePost.js
Normal file
100
src/XSitePost.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright (C) 2008,2009 BRAT Tech LLC
|
||||
|
||||
if (typeof nglr == 'undefined') nglr = {};
|
||||
|
||||
if (typeof console == 'undefined') console = {};
|
||||
if (typeof console.log == 'undefined')
|
||||
console.log = function() {};
|
||||
if (typeof console.error == 'undefined')
|
||||
console.error = function() {};
|
||||
|
||||
nglr.XSitePost = function(baseUrl, window, prefix) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.post = jQuery.post;
|
||||
this.window = window;
|
||||
this.inQueue = {};
|
||||
this.outQueue = [];
|
||||
this.maxMsgSize = 100000;
|
||||
this.delay = 20;
|
||||
this.prefix = prefix;
|
||||
this.setTimeout=function(fn, delay){window.setTimeout(fn, delay);};
|
||||
};
|
||||
|
||||
nglr.XSitePost.prototype.init = function() {
|
||||
this.window.name = '';
|
||||
this.response('ready', 'null');
|
||||
};
|
||||
|
||||
nglr.XSitePost.prototype.incomingFragment = function(fragment) {
|
||||
var parts = fragment.split(";");
|
||||
this.incomingMsg(parts.shift(), 1*parts.shift(), 1*parts.shift(), parts.shift());
|
||||
};
|
||||
|
||||
nglr.XSitePost.prototype.incomingMsg = function(id, partNo, totalParts, msgPart) {
|
||||
var msg = this.inQueue[id];
|
||||
if (!msg) {
|
||||
msg = {id:id, parts:[], count:0};
|
||||
this.inQueue[id] = msg;
|
||||
}
|
||||
msg.parts[partNo] = msgPart;
|
||||
msg.count++;
|
||||
if (totalParts === msg.count) {
|
||||
delete this.inQueue[id];
|
||||
var request = this.decodePost(msg.parts.join(''));
|
||||
var self = this;
|
||||
this.post(this.baseUrl + request.url, request.params, function(response, status){
|
||||
self.response(id, response, status);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
nglr.XSitePost.prototype.response = function(id, response, status) {
|
||||
var start = 0;
|
||||
var end;
|
||||
var msg = Base64.encode(response);
|
||||
var msgLen = msg.length;
|
||||
var total = Math.ceil(msgLen / this.maxMsgSize);
|
||||
var part = 0;
|
||||
while (start < msgLen) {
|
||||
end = Math.min(msgLen, start + this.maxMsgSize);
|
||||
this.outQueue.push(id + ':'+part+':'+total+':' + msg.substring(start, end));
|
||||
start = end;
|
||||
part++;
|
||||
}
|
||||
};
|
||||
|
||||
nglr.XSitePost.prototype.decodePost = function(post) {
|
||||
var parts = post.split(':');
|
||||
var url = Base64.decode(parts.shift());
|
||||
var params = {};
|
||||
while(parts.length !== 0) {
|
||||
var key = parts.shift();
|
||||
var value = Base64.decode(parts.shift());
|
||||
params[key] = value;
|
||||
}
|
||||
return {url:url, params:params};
|
||||
};
|
||||
|
||||
nglr.XSitePost.prototype.listen = function() {
|
||||
console.log("listen()");
|
||||
var self = this;
|
||||
var window = this.window;
|
||||
var outQueue = this.outQueue;
|
||||
var setTimeout = this.setTimeout;
|
||||
var prefix = this.prefix;
|
||||
var prefixLen = prefix.length;
|
||||
var prefixRec = prefix + '>';
|
||||
var prefixRecLen = prefixRec.length;
|
||||
window.name = prefix;
|
||||
var pull = function(){
|
||||
var value = window.name;
|
||||
if (value == prefix && outQueue.length > 0) {
|
||||
window.name = prefix + '<' + outQueue.shift();
|
||||
} else if (value.substr(0, prefixRecLen) == prefixRec) {
|
||||
self.incomingFragment(value.substr(prefixRecLen));
|
||||
window.name = prefix;
|
||||
}
|
||||
setTimeout(pull, self.delay);
|
||||
};
|
||||
pull();
|
||||
};
|
||||
100
src/angular-bootstrap.js
vendored
Normal file
100
src/angular-bootstrap.js
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright (C) 2008,2009 BRAT Tech LLC
|
||||
|
||||
(function(previousOnLoad){
|
||||
var filename = /(.*)\/angular-(.*).js(#(.*))?/;
|
||||
var scripts = document.getElementsByTagName("script");
|
||||
var scriptConfig = {
|
||||
autoSubmit:true,
|
||||
autoBind:true,
|
||||
autoLoadDependencies:false
|
||||
};
|
||||
for(var j = 0; j < scripts.length; j++) {
|
||||
var src = scripts[j].src;
|
||||
if (src && src.match(filename)) {
|
||||
var parts = src.match(filename);
|
||||
if (parts[2] == 'bootstrap') {
|
||||
scriptConfig.autoLoadDependencies = true;
|
||||
}
|
||||
scriptConfig.server = parts[1] || '';
|
||||
if (!scriptConfig.server) {
|
||||
scriptConfig.server = window.location.toString().split(window.location.pathname)[0];
|
||||
}
|
||||
if (parts[4]) {
|
||||
var directive = parts[4].split('&');
|
||||
for ( var i = 0; i < directive.length; i++) {
|
||||
var keyValue = directive[i].split('=');
|
||||
var key = keyValue[0];
|
||||
var value = keyValue.length == 1 ? true : keyValue[1];
|
||||
if (value == 'false') value = false;
|
||||
if (value == 'true') value = true;
|
||||
scriptConfig[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var addScript = function(path, server){
|
||||
server = server || scriptConfig.server;
|
||||
document.write('<script type="text/javascript" src="' + server + path +'"></script>');
|
||||
};
|
||||
|
||||
if (scriptConfig.autoLoadDependencies) {
|
||||
addScript("/javascripts/webtoolkit.base64.js");
|
||||
addScript("/javascripts/swfobject.js");
|
||||
addScript("/javascripts/jQuery/jquery-1.3.2.js");
|
||||
addScript("/javascripts/jQuery/jquery-ui-1.7.1.custom.min.js");
|
||||
addScript("/javascripts/underscore/underscore.js");
|
||||
addScript("/javascripts/nglr/Loader.js");
|
||||
addScript("/javascripts/nglr/API.js");
|
||||
addScript("/javascripts/nglr/Binder.js");
|
||||
addScript("/javascripts/nglr/ControlBar.js");
|
||||
addScript("/javascripts/nglr/DataStore.js");
|
||||
addScript("/javascripts/nglr/Filters.js");
|
||||
addScript("/javascripts/nglr/JSON.js");
|
||||
addScript("/javascripts/nglr/Model.js");
|
||||
addScript("/javascripts/nglr/Parser.js");
|
||||
addScript("/javascripts/nglr/Scope.js");
|
||||
addScript("/javascripts/nglr/Server.js");
|
||||
addScript("/javascripts/nglr/Users.js");
|
||||
addScript("/javascripts/nglr/Validators.js");
|
||||
addScript("/javascripts/nglr/Widgets.js");
|
||||
} else {
|
||||
addScript("/ajax/libs/swfobject/2.2/swfobject.js", "http://ajax.googleapis.com");
|
||||
addScript("/ajax/libs/jquery/1.3.2/jquery.min.js", "http://ajax.googleapis.com");
|
||||
addScript("/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js", "http://ajax.googleapis.com");
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
window.angular.init = function(root, config){
|
||||
var cnfgMerged = _.clone(scriptConfig||{});
|
||||
_.extend(cnfgMerged, config);
|
||||
new nglr.Loader(root, jQuery("head"), cnfgMerged).load();
|
||||
};
|
||||
|
||||
var doc = window.document;
|
||||
if (scriptConfig.bindRootId) {
|
||||
doc = null;
|
||||
var ids = scriptConfig.bindRootId.split('|');
|
||||
for ( var i = 0; i < ids.length && !doc; i++) {
|
||||
var idCond = ids[i].split('?');
|
||||
var id = idCond[0];
|
||||
if (idCond.length > 1) {
|
||||
if (!window.document.getElementById(idCond[1])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
doc = window.document.getElementById(id);
|
||||
}
|
||||
}
|
||||
if (scriptConfig.autoBind && doc) {
|
||||
window.angular.init(doc);
|
||||
}
|
||||
if (typeof previousOnLoad === 'function') {
|
||||
try {
|
||||
previousOnLoad.apply(this, arguments);
|
||||
} catch (e) {}
|
||||
}
|
||||
};
|
||||
})(window.onload);
|
||||
|
||||
|
||||
160
src/test/Runner.js
Normal file
160
src/test/Runner.js
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
nglr.test.ScenarioRunner = function(scenarios, body) {
|
||||
this.scenarios = scenarios;
|
||||
this.body = body;
|
||||
};
|
||||
|
||||
nglr.test.ScenarioRunner.prototype = {
|
||||
run:function(){
|
||||
this.setUpUI();
|
||||
this.runScenarios();
|
||||
},
|
||||
setUpUI:function(){
|
||||
this.body.html(
|
||||
'<div id="runner">' +
|
||||
'<div class="console"></div>' +
|
||||
'</div>' +
|
||||
'<div id="testView">' +
|
||||
'<iframe></iframe>' +
|
||||
'</div>');
|
||||
this.console = this.body.find(".console");
|
||||
this.testFrame = this.body.find("iframe");
|
||||
this.console.find(".run").live("click", function(){
|
||||
jQuery(this).parent().find('.log').toggle();
|
||||
});
|
||||
},
|
||||
runScenarios:function(){
|
||||
var runner = new nglr.test.Runner(this.console, this.testFrame);
|
||||
_.stepper(this.scenarios, function(next, scenario, name){
|
||||
new nglr.test.Scenario(name, scenario).run(runner, next);
|
||||
}, function(){
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
nglr.test.Runner = function(console, frame){
|
||||
this.console = console;
|
||||
this.current = null;
|
||||
this.tests = [];
|
||||
this.frame = frame;
|
||||
};
|
||||
nglr.test.Runner.prototype = {
|
||||
start:function(name){
|
||||
var current = this.current = {
|
||||
name:name,
|
||||
start:new Date().getTime(),
|
||||
scenario:jQuery('<div class="scenario"></div>')
|
||||
};
|
||||
current.run = current.scenario.append(
|
||||
'<div class="run">' +
|
||||
'<span class="name">.</span>' +
|
||||
'<span class="time">.</span>' +
|
||||
'<span class="state">.</span>' +
|
||||
'</run>').find(".run");
|
||||
current.log = current.scenario.append('<div class="log"></div>').find(".log");
|
||||
current.run.find(".name").text(name);
|
||||
this.tests.push(current);
|
||||
this.console.append(current.scenario);
|
||||
},
|
||||
end:function(name){
|
||||
var current = this.current;
|
||||
var run = current.run;
|
||||
this.current = null;
|
||||
current.end = new Date().getTime();
|
||||
current.time = current.end - current.start;
|
||||
run.find(".time").text(current.time);
|
||||
run.find(".state").text(current.error ? "FAIL" : "PASS");
|
||||
run.addClass(current.error ? "fail" : "pass");
|
||||
if (current.error)
|
||||
run.find(".run").append('<span div="error"></span>').text(current.error);
|
||||
current.scenario.find(".log").hide();
|
||||
},
|
||||
log:function(level) {
|
||||
var buf = [];
|
||||
for ( var i = 1; i < arguments.length; i++) {
|
||||
var arg = arguments[i];
|
||||
buf.push(typeof arg == "string" ?arg:nglr.toJson(arg));
|
||||
}
|
||||
var log = jQuery('<div class="' + level + '"></div>');
|
||||
log.text(buf.join(" "));
|
||||
this.current.log.append(log);
|
||||
this.console.scrollTop(this.console[0].scrollHeight);
|
||||
if (level == "error")
|
||||
this.current.error = buf.join(" ");
|
||||
}
|
||||
};
|
||||
|
||||
nglr.test.Scenario = function(name, scenario){
|
||||
this.name = name;
|
||||
this.scenario = scenario;
|
||||
};
|
||||
nglr.test.Scenario.prototype = {
|
||||
run:function(runner, callback) {
|
||||
var self = this;
|
||||
_.stepper(this.scenario, function(next, steps, name){
|
||||
if (name.charAt(0) == '$') {
|
||||
next();
|
||||
} else {
|
||||
runner.start(self.name + "::" + name);
|
||||
var allSteps = (self.scenario.$before||[]).concat(steps);
|
||||
_.stepper(allSteps, function(next, step){
|
||||
self.executeStep(runner, step, next);
|
||||
}, function(){
|
||||
runner.end();
|
||||
next();
|
||||
});
|
||||
}
|
||||
}, callback);
|
||||
},
|
||||
verb:function(step){
|
||||
var fn = null;
|
||||
if (!step) fn = function (){ throw "Step is null!"; }
|
||||
else if (step.Given) fn = angular.test.GIVEN[step.Given];
|
||||
else if (step.When) fn = angular.test.WHEN[step.When];
|
||||
else if (step.Then) fn = angular.test.THEN[step.Then];
|
||||
return fn || function (){
|
||||
throw "ERROR: Need Given/When/Then got: " + nglr.toJson(step);
|
||||
};
|
||||
},
|
||||
context: function(runner) {
|
||||
var frame = runner.frame;
|
||||
var window = frame[0].contentWindow;
|
||||
var document;
|
||||
if (window.jQuery)
|
||||
document = window.jQuery(window.document);
|
||||
var context = {
|
||||
frame:frame,
|
||||
window:window,
|
||||
log:_.bind(runner.log, runner, "info"),
|
||||
document:document,
|
||||
assert:function(element, path){
|
||||
if (element.size() != 1) {
|
||||
throw "Expected to find '1' found '"+
|
||||
element.size()+"' for '"+path+"'.";
|
||||
}
|
||||
return element;
|
||||
},
|
||||
element:function(path){
|
||||
var exp = path.replace("{{","[ng-bind=").replace("}}", "]");
|
||||
var element = document.find(exp);
|
||||
return context.assert(element, path);
|
||||
}
|
||||
};
|
||||
return context;
|
||||
},
|
||||
executeStep:function(runner, step, callback) {
|
||||
if (!step) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
runner.log("info", nglr.toJson(step));
|
||||
var fn = this.verb(step);
|
||||
var context = this.context(runner);
|
||||
_.extend(context, step);
|
||||
try {
|
||||
(fn.call(context)||function(c){c();})(callback);
|
||||
} catch (e) {
|
||||
runner.log("error", "ERROR: " + nglr.toJson(e));
|
||||
}
|
||||
}
|
||||
};
|
||||
57
src/test/Steps.js
Normal file
57
src/test/Steps.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
angular.test.GIVEN = {
|
||||
browser:function(){
|
||||
var self = this;
|
||||
if (jQuery.browser.safari && this.frame.attr('src') == this.at) {
|
||||
this.window.location.reload();
|
||||
} else {
|
||||
this.frame.attr('src', this.at);
|
||||
}
|
||||
return function(done){
|
||||
self.frame.load(function(){
|
||||
self.frame.unbind();
|
||||
done();
|
||||
});
|
||||
};
|
||||
},
|
||||
dataset:function(){
|
||||
this.frame.name="$DATASET:" + nglr.toJson({dataset:this.dataset});
|
||||
}
|
||||
};
|
||||
angular.test.WHEN = {
|
||||
enter:function(){
|
||||
var element = this.element(this.at);
|
||||
element.attr('value', this.text);
|
||||
element.change();
|
||||
},
|
||||
click:function(){
|
||||
var element = this.element(this.at);
|
||||
var input = element[0];
|
||||
// emulate the browser behavior which causes it
|
||||
// to be overridden at the end.
|
||||
var checked = input.checked = !input.checked;
|
||||
element.click();
|
||||
input.checked = checked;
|
||||
},
|
||||
select:function(){
|
||||
var element = this.element(this.at);
|
||||
var path = "option[value=" + this.option + "]";
|
||||
var option = this.assert(element.find(path));
|
||||
option[0].selected = !option[0].selected;
|
||||
element.change();
|
||||
}
|
||||
};
|
||||
angular.test.THEN = {
|
||||
text:function(){
|
||||
var element = this.element(this.at);
|
||||
if (typeof this.should_be != undefined ) {
|
||||
var should_be = this.should_be;
|
||||
if (_.isArray(this.should_be))
|
||||
should_be = JSON.stringify(should_be);
|
||||
if (element.text() != should_be)
|
||||
throw "Expected " + should_be +
|
||||
" but was " + element.text() + ".";
|
||||
}
|
||||
},
|
||||
drainRequestQueue:function(){
|
||||
}
|
||||
};
|
||||
5
src/test/_namespace.js
Normal file
5
src/test/_namespace.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
if (!angular) angular = {};
|
||||
if (!angular.test) angular.test = {};
|
||||
if (!angular.test.GIVEN) angular.test.GIVEN = {};
|
||||
if (!angular.test.WHEN) angular.test.WHEN = {};
|
||||
if (!angular.test.THEN) angular.test.THEN = {};
|
||||
252
test/ApiTest.js
Normal file
252
test/ApiTest.js
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
ApiTest = TestCase("ApiTest");
|
||||
|
||||
ApiTest.prototype.testItShouldReturnTypeOf = function (){
|
||||
assertEquals("undefined", angular.Object.typeOf(undefined));
|
||||
assertEquals("null", angular.Object.typeOf(null));
|
||||
assertEquals("object", angular.Collection.typeOf({}));
|
||||
assertEquals("array", angular.Array.typeOf([]));
|
||||
assertEquals("string", angular.Object.typeOf(""));
|
||||
assertEquals("date", angular.Object.typeOf(new Date()));
|
||||
assertEquals("element", angular.Object.typeOf(document.body));
|
||||
assertEquals("function", angular.Object.typeOf(function(){}));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testItShouldReturnSize = function(){
|
||||
assertEquals(0, angular.Collection.size({}));
|
||||
assertEquals(1, angular.Collection.size({a:"b"}));
|
||||
assertEquals(0, angular.Object.size({}));
|
||||
assertEquals(1, angular.Array.size([0]));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testIncludeIf = function() {
|
||||
var array = [];
|
||||
var obj = {};
|
||||
|
||||
angular.Array.includeIf(array, obj, true);
|
||||
angular.Array.includeIf(array, obj, true);
|
||||
assertTrue(_.include(array, obj));
|
||||
assertEquals(1, array.length);
|
||||
|
||||
angular.Array.includeIf(array, obj, false);
|
||||
assertFalse(_.include(array, obj));
|
||||
assertEquals(0, array.length);
|
||||
|
||||
angular.Array.includeIf(array, obj, 'x');
|
||||
assertTrue(_.include(array, obj));
|
||||
assertEquals(1, array.length);
|
||||
angular.Array.includeIf(array, obj, '');
|
||||
assertFalse(_.include(array, obj));
|
||||
assertEquals(0, array.length);
|
||||
};
|
||||
|
||||
ApiTest.prototype.testSum = function(){
|
||||
assertEquals(3, angular.Array.sum([{a:"1"}, {a:"2"}], 'a'));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testSumContainingNaN = function(){
|
||||
assertEquals(1, angular.Array.sum([{a:1}, {a:Number.NaN}], 'a'));
|
||||
assertEquals(1, angular.Array.sum([{a:1}, {a:Number.NaN}], function($){return $.a;}));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testInclude = function(){
|
||||
assertTrue(angular.Array.include(['a'], 'a'));
|
||||
assertTrue(angular.Array.include(['a', 'b'], 'a'));
|
||||
assertTrue(!angular.Array.include(['c'], 'a'));
|
||||
assertTrue(!angular.Array.include(['c', 'b'], 'a'));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testIndex = function(){
|
||||
assertEquals(angular.Array.indexOf(['a'], 'a'), 0);
|
||||
assertEquals(angular.Array.indexOf(['a', 'b'], 'a'), 0);
|
||||
assertEquals(angular.Array.indexOf(['b', 'a'], 'a'), 1);
|
||||
assertEquals(angular.Array.indexOf(['b', 'b'],'x'), -1);
|
||||
};
|
||||
|
||||
ApiTest.prototype.testRemove = function(){
|
||||
var items = ['a', 'b', 'c'];
|
||||
assertEquals(angular.Array.remove(items, 'q'), 'q');
|
||||
assertEquals(items.length, 3);
|
||||
|
||||
assertEquals(angular.Array.remove(items, 'b'), 'b');
|
||||
assertEquals(items.length, 2);
|
||||
|
||||
assertEquals(angular.Array.remove(items, 'a'), 'a');
|
||||
assertEquals(items.length, 1);
|
||||
|
||||
assertEquals(angular.Array.remove(items, 'c'), 'c');
|
||||
assertEquals(items.length, 0);
|
||||
|
||||
assertEquals(angular.Array.remove(items, 'q'), 'q');
|
||||
assertEquals(items.length, 0);
|
||||
};
|
||||
|
||||
ApiTest.prototype.testFindById = function() {
|
||||
var items = [{$id:1}, {$id:2}, {$id:3}];
|
||||
assertNull(angular.Array.findById(items, 0));
|
||||
assertEquals(items[0], angular.Array.findById(items, 1));
|
||||
assertEquals(items[1], angular.Array.findById(items, 2));
|
||||
assertEquals(items[2], angular.Array.findById(items, 3));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testFilter = function() {
|
||||
var items = ["MIsKO", {name:"shyam"}, ["adam"], 1234];
|
||||
assertEquals(4, angular.Array.filter(items, "").length);
|
||||
assertEquals(4, angular.Array.filter(items, undefined).length);
|
||||
|
||||
assertEquals(1, angular.Array.filter(items, 'iSk').length);
|
||||
assertEquals("MIsKO", angular.Array.filter(items, 'isk')[0]);
|
||||
|
||||
assertEquals(1, angular.Array.filter(items, 'yam').length);
|
||||
assertEquals(items[1], angular.Array.filter(items, 'yam')[0]);
|
||||
|
||||
assertEquals(1, angular.Array.filter(items, 'da').length);
|
||||
assertEquals(items[2], angular.Array.filter(items, 'da')[0]);
|
||||
|
||||
assertEquals(1, angular.Array.filter(items, '34').length);
|
||||
assertEquals(1234, angular.Array.filter(items, '34')[0]);
|
||||
|
||||
assertEquals(0, angular.Array.filter(items, "I don't exist").length);
|
||||
};
|
||||
|
||||
ApiTest.prototype.testShouldNotFilterOnSystemData = function() {
|
||||
assertEquals("", "".charAt(0)); // assumption
|
||||
var items = [{$name:"misko"}];
|
||||
assertEquals(0, angular.Array.filter(items, "misko").length);
|
||||
};
|
||||
|
||||
ApiTest.prototype.testFilterOnSpecificProperty = function() {
|
||||
var items = [{ignore:"a", name:"a"}, {ignore:"a", name:"abc"}];
|
||||
assertEquals(2, angular.Array.filter(items, {}).length);
|
||||
|
||||
assertEquals(2, angular.Array.filter(items, {name:'a'}).length);
|
||||
|
||||
assertEquals(1, angular.Array.filter(items, {name:'b'}).length);
|
||||
assertEquals("abc", angular.Array.filter(items, {name:'b'})[0].name);
|
||||
};
|
||||
|
||||
ApiTest.prototype.testFilterOnFunction = function() {
|
||||
var items = [{name:"a"}, {name:"abc", done:true}];
|
||||
assertEquals(1, angular.Array.filter(items, function(i){return i.done;}).length);
|
||||
};
|
||||
|
||||
ApiTest.prototype.testFilterIsAndFunction = function() {
|
||||
var items = [{first:"misko", last:"hevery"},
|
||||
{first:"adam", last:"abrons"}];
|
||||
|
||||
assertEquals(2, angular.Array.filter(items, {first:'', last:''}).length);
|
||||
assertEquals(1, angular.Array.filter(items, {first:'', last:'hevery'}).length);
|
||||
assertEquals(0, angular.Array.filter(items, {first:'adam', last:'hevery'}).length);
|
||||
assertEquals(1, angular.Array.filter(items, {first:'misko', last:'hevery'}).length);
|
||||
assertEquals(items[0], angular.Array.filter(items, {first:'misko', last:'hevery'})[0]);
|
||||
};
|
||||
|
||||
ApiTest.prototype.testFilterNot = function() {
|
||||
var items = ["misko", "adam"];
|
||||
|
||||
assertEquals(1, angular.Array.filter(items, '!isk').length);
|
||||
assertEquals(items[1], angular.Array.filter(items, '!isk')[0]);
|
||||
};
|
||||
|
||||
ApiTest.prototype.testAdd = function() {
|
||||
var add = angular.Array.add;
|
||||
assertJsonEquals([{}, "a"], add(add([]),"a"));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testCount = function() {
|
||||
var array = [{name:'a'},{name:'b'},{name:''}];
|
||||
var obj = {};
|
||||
|
||||
assertEquals(3, angular.Array.count(array));
|
||||
assertEquals(2, angular.Array.count(array, 'name'));
|
||||
assertEquals(1, angular.Array.count(array, 'name=="a"'));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testFind = function() {
|
||||
var array = [{name:'a'},{name:'b'},{name:''}];
|
||||
var obj = {};
|
||||
|
||||
assertEquals(undefined, angular.Array.find(array, 'false'));
|
||||
assertEquals('default', angular.Array.find(array, 'false', 'default'));
|
||||
assertEquals('a', angular.Array.find(array, 'name == "a"').name);
|
||||
assertEquals('', angular.Array.find(array, 'name == ""').name);
|
||||
};
|
||||
|
||||
ApiTest.prototype.testItShouldSortArray = function() {
|
||||
assertEquals([2,15], angular.Array.orderBy([15,2]));
|
||||
assertEquals(["a","B", "c"], angular.Array.orderBy(["c","B", "a"]));
|
||||
assertEquals([15,"2"], angular.Array.orderBy([15,"2"]));
|
||||
assertEquals(["15","2"], angular.Array.orderBy(["15","2"]));
|
||||
assertJsonEquals([{a:2},{a:15}], angular.Array.orderBy([{a:15},{a:2}], 'a'));
|
||||
assertJsonEquals([{a:2},{a:15}], angular.Array.orderBy([{a:15},{a:2}], 'a', "F"));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testItShouldSortArrayInReverse = function() {
|
||||
assertJsonEquals([{a:15},{a:2}], angular.Array.orderBy([{a:15},{a:2}], 'a', true));
|
||||
assertJsonEquals([{a:15},{a:2}], angular.Array.orderBy([{a:15},{a:2}], 'a', "T"));
|
||||
assertJsonEquals([{a:15},{a:2}], angular.Array.orderBy([{a:15},{a:2}], 'a', "reverse"));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testItShouldSortArrayByPredicate = function() {
|
||||
assertJsonEquals([{a:2, b:1},{a:15, b:1}],
|
||||
angular.Array.orderBy([{a:15, b:1},{a:2, b:1}], ['a', 'b']));
|
||||
assertJsonEquals([{a:2, b:1},{a:15, b:1}],
|
||||
angular.Array.orderBy([{a:15, b:1},{a:2, b:1}], ['b', 'a']));
|
||||
assertJsonEquals([{a:15, b:1},{a:2, b:1}],
|
||||
angular.Array.orderBy([{a:15, b:1},{a:2, b:1}], ['+b', '-a']));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testQuoteString = function(){
|
||||
assertEquals(angular.String.quote('a'), '"a"');
|
||||
assertEquals(angular.String.quote('\\'), '"\\\\"');
|
||||
assertEquals(angular.String.quote("'a'"), '"\'a\'"');
|
||||
assertEquals(angular.String.quote('"a"'), '"\\"a\\""');
|
||||
assertEquals(angular.String.quote('\n\f\r\t'), '"\\n\\f\\r\\t"');
|
||||
};
|
||||
|
||||
ApiTest.prototype.testQuoteStringBug = function(){
|
||||
assertEquals(angular.String.quote('"7\\\\\\\"7"', "7\\\"7"));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testQuoteUnicode = function(){
|
||||
assertEquals('"abc\\u00a0def"', angular.String.quoteUnicode('abc\u00A0def'));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testMerge = function() {
|
||||
var array = [{name:"misko"}];
|
||||
angular.Array.merge(array, 0, {name:"", email:"email1"});
|
||||
angular.Array.merge(array, 1, {name:"adam", email:"email2"});
|
||||
assertJsonEquals([{"email":"email1","name":"misko"},{"email":"email2","name":"adam"}], array);
|
||||
};
|
||||
|
||||
ApiTest.prototype.testOrderByToggle = function() {
|
||||
var orderByToggle = angular.Array.orderByToggle;
|
||||
var predicate = [];
|
||||
assertEquals(['+a'], orderByToggle(predicate, 'a'));
|
||||
assertEquals(['-a'], orderByToggle(predicate, 'a'));
|
||||
|
||||
assertEquals(['-a', '-b'], orderByToggle(['-b', 'a'], 'a'));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testOrderByToggle = function() {
|
||||
var orderByDirection = angular.Array.orderByDirection;
|
||||
assertEquals("", orderByDirection(['+a','b'], 'x'));
|
||||
assertEquals("", orderByDirection(['+a','b'], 'b'));
|
||||
assertEquals('ng-ascend', orderByDirection(['a','b'], 'a'));
|
||||
assertEquals('ng-ascend', orderByDirection(['+a','b'], 'a'));
|
||||
assertEquals('ng-descend', orderByDirection(['-a','b'], 'a'));
|
||||
assertEquals('up', orderByDirection(['+a','b'], 'a', 'up', 'down'));
|
||||
assertEquals('down', orderByDirection(['-a','b'], 'a', 'up', 'down'));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testDateToUTC = function(){
|
||||
var date = new Date("Sep 10 2003 13:02:03 GMT");
|
||||
assertEquals("date", angular.Object.typeOf(date));
|
||||
assertEquals("2003-09-10T13:02:03Z", angular.Date.toString(date));
|
||||
};
|
||||
|
||||
ApiTest.prototype.testStringFromUTC = function(){
|
||||
var date = angular.String.toDate("2003-09-10T13:02:03Z");
|
||||
assertEquals("date", angular.Object.typeOf(date));
|
||||
assertEquals("2003-09-10T13:02:03Z", angular.Date.toString(date));
|
||||
assertEquals("str", angular.String.toDate("str"));
|
||||
};
|
||||
5
test/Base64Test.js
Normal file
5
test/Base64Test.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Base64Test = TestCase('Base64Test');
|
||||
|
||||
Base64Test.prototype.testEncodeDecode = function(){
|
||||
assertEquals(Base64.decode(Base64.encode('hello')), 'hello');
|
||||
};
|
||||
1001
test/BinderTest.js
Normal file
1001
test/BinderTest.js
Normal file
File diff suppressed because it is too large
Load diff
13
test/ConsoleTest.js
Normal file
13
test/ConsoleTest.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
ConsoleTest = TestCase('ConsoleTest');
|
||||
|
||||
ConsoleTest.prototype.testConsoleWrite = function(){
|
||||
var consoleNode = $("<div></div>")[0];
|
||||
nglr.consoleNode = consoleNode;
|
||||
nglr.consoleLog("error", ["Hello", "world"]);
|
||||
assertEquals($(consoleNode)[0].nodeName, 'DIV');
|
||||
assertEquals($(consoleNode).text(), 'Hello world');
|
||||
assertEquals($('div', consoleNode)[0].className, 'error');
|
||||
nglr.consoleLog("error",["Bye"]);
|
||||
assertEquals($(consoleNode).text(), 'Hello worldBye');
|
||||
nglr.consoleNode = null;
|
||||
};
|
||||
2
test/ControlBarTest.js
Normal file
2
test/ControlBarTest.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ControlBarTest = TestCase("ControlBarTest");
|
||||
|
||||
617
test/DataStoreTest.js
Normal file
617
test/DataStoreTest.js
Normal file
|
|
@ -0,0 +1,617 @@
|
|||
DataStoreTest = TestCase('DataStoreTest');
|
||||
|
||||
DataStoreTest.prototype.testSavePostsToServer = function(){
|
||||
expectAsserts(10);
|
||||
var response;
|
||||
var post = function(data, callback){
|
||||
var method = data[0][0];
|
||||
var posted = data[0][2];
|
||||
assertEquals("POST", method);
|
||||
assertEquals("abc", posted.$entity);
|
||||
assertEquals("123", posted.$id);
|
||||
assertEquals("1", posted.$version);
|
||||
assertFalse('function' == typeof posted.save);
|
||||
response = nglr.fromJson(nglr.toJson(posted));
|
||||
response.$entity = "abc";
|
||||
response.$id = "123";
|
||||
response.$version = "2";
|
||||
callback(200, [response]);
|
||||
};
|
||||
var model;
|
||||
var datastore = new nglr.DataStore(post);
|
||||
model = datastore.entity('abc', {name: "value"})();
|
||||
model.$id = "123";
|
||||
model.$version = "1";
|
||||
|
||||
datastore.save(model, function(obj){
|
||||
assertTrue(obj === model);
|
||||
assertEquals(obj.$entity, "abc");
|
||||
assertEquals(obj.$id, "123");
|
||||
assertEquals(obj.$version, "2");
|
||||
assertEquals(obj.name, "value");
|
||||
obj.after = true;
|
||||
});
|
||||
datastore.flush();
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testLoadGetsFromServer = function(){
|
||||
expectAsserts(12);
|
||||
var post = function(data, callback){
|
||||
var method = data[0][0];
|
||||
var path = data[0][1];
|
||||
assertEquals("GET", method);
|
||||
assertEquals("abc/1", path);
|
||||
response = [{$entity:'abc', $id:'1', $version:'2', key:"value"}];
|
||||
callback(200, response);
|
||||
};
|
||||
var datastore = new nglr.DataStore(post);
|
||||
|
||||
var model = datastore.entity("abc", {merge:true})();
|
||||
assertEquals(datastore.load(model, '1', function(obj){
|
||||
assertEquals(obj.$entity, "abc");
|
||||
assertEquals(obj.$id, "1");
|
||||
assertEquals(obj.$version, "2");
|
||||
assertEquals(obj.key, "value");
|
||||
}), model);
|
||||
datastore.flush();
|
||||
assertEquals(model.$entity, "abc");
|
||||
assertEquals(model.$id, "1");
|
||||
assertEquals(model.$version, "2");
|
||||
assertEquals(model.key, "value");
|
||||
assertEquals(model.merge, true);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testRemove = function(){
|
||||
expectAsserts(8);
|
||||
var response;
|
||||
var post = function(data, callback){
|
||||
var method = data[0][0];
|
||||
var posted = data[0][2];
|
||||
assertEquals("DELETE", method);
|
||||
assertEquals("abc", posted.$entity);
|
||||
assertEquals("123", posted.$id);
|
||||
assertEquals("1", posted.$version);
|
||||
assertFalse('function' == typeof posted.save);
|
||||
response = nglr.fromJson(nglr.toJson(posted));
|
||||
response.$entity = "abc";
|
||||
response.$id = "123";
|
||||
response.$version = "2";
|
||||
callback(200, [response]);
|
||||
};
|
||||
var model;
|
||||
var datastore = new nglr.DataStore(post);
|
||||
model = datastore.entity('abc', {name: "value"})();
|
||||
model.$id = "123";
|
||||
model.$version = "1";
|
||||
|
||||
datastore.remove(model, function(obj){
|
||||
assertEquals(obj.$id, "123");
|
||||
assertEquals(obj.$version, "2");
|
||||
assertEquals(obj.name, "value");
|
||||
obj.after = true;
|
||||
});
|
||||
datastore.flush();
|
||||
|
||||
};
|
||||
|
||||
|
||||
DataStoreTest.prototype.test401ResponseDoesNotCallCallback = function(){
|
||||
expectAsserts(1);
|
||||
var post = function(data, callback) {
|
||||
callback(200, {$status_code: 401});
|
||||
};
|
||||
|
||||
var datastore = new nglr.DataStore(post, {login:function(){
|
||||
assertTrue(true);
|
||||
}});
|
||||
|
||||
var onLoadAll = function(){
|
||||
assertTrue(false, "onLoadAll should not be called when response is status 401");
|
||||
};
|
||||
datastore.bulkRequest.push({});
|
||||
datastore.flush();
|
||||
datastore.loadAll({type: "A"}, onLoadAll);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.test403ResponseDoesNotCallCallback = function(){
|
||||
expectAsserts(1);
|
||||
var post = function(data, callback) {
|
||||
callback(200, [{$status_code: 403}]);
|
||||
};
|
||||
|
||||
var datastore = new nglr.DataStore(post, {notAuthorized:function(){
|
||||
assertTrue(true);
|
||||
}});
|
||||
|
||||
var onLoadAll = function(){
|
||||
assertTrue(false, "onLoadAll should not be called when response is status 403");
|
||||
};
|
||||
datastore.bulkRequest.push({});
|
||||
datastore.flush();
|
||||
datastore.loadAll({type: "A"}, onLoadAll);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testLoadCalledWithoutIdShouldBeNoop = function(){
|
||||
expectAsserts(2);
|
||||
var post = function(url, callback){
|
||||
assertTrue(false);
|
||||
};
|
||||
var datastore = new nglr.DataStore(post);
|
||||
var model = datastore.entity("abc")();
|
||||
assertEquals(datastore.load(model, undefined), model);
|
||||
assertEquals(model.$entity, "abc");
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testEntityFactory = function(){
|
||||
var ds = new nglr.DataStore();
|
||||
var Recipe = ds.entity("Recipe", {a:1, b:2});
|
||||
assertEquals(Recipe.title, "Recipe");
|
||||
assertEquals(Recipe.defaults.a, 1);
|
||||
assertEquals(Recipe.defaults.b, 2);
|
||||
|
||||
var recipe = Recipe();
|
||||
assertEquals(recipe.$entity, "Recipe");
|
||||
assertEquals(recipe.a, 1);
|
||||
assertEquals(recipe.b, 2);
|
||||
|
||||
recipe = new Recipe();
|
||||
assertEquals(recipe.$entity, "Recipe");
|
||||
assertEquals(recipe.a, 1);
|
||||
assertEquals(recipe.b, 2);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testEntityFactoryNoDefaults = function(){
|
||||
var ds = new nglr.DataStore();
|
||||
var Recipe = ds.entity("Recipe");
|
||||
assertEquals(Recipe.title, "Recipe");
|
||||
|
||||
recipe = new Recipe();
|
||||
assertEquals(recipe.$entity, "Recipe");
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testEntityFactoryWithInitialValues = function(){
|
||||
var ds = new nglr.DataStore();
|
||||
var Recipe = ds.entity("Recipe");
|
||||
|
||||
var recipe = Recipe({name: "name"});
|
||||
assertEquals("name", recipe.name);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testEntityLoad = function(){
|
||||
var ds = new nglr.DataStore();
|
||||
var Recipe = ds.entity("Recipe", {a:1, b:2});
|
||||
ds.load = function(instance, id, callback){
|
||||
callback.apply(instance);
|
||||
return instance;
|
||||
};
|
||||
var instance = null;
|
||||
var recipe2 = Recipe.load("ID", function(){
|
||||
instance = this;
|
||||
});
|
||||
assertTrue(recipe2 === instance);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testSaveScope = function(){
|
||||
var ds = new nglr.DataStore();
|
||||
var log = "";
|
||||
var Person = ds.entity("Person");
|
||||
var person1 = Person({name:"A", $entity:"Person", $id:"1", $version:"1"}, ds);
|
||||
person1.$$anchor = "A";
|
||||
var person2 = Person({name:"B", $entity:"Person", $id:"2", $version:"2"}, ds);
|
||||
person2.$$anchor = "B";
|
||||
var anchor = {};
|
||||
ds.anchor = anchor;
|
||||
ds._jsonRequest = function(request, callback){
|
||||
log += "save(" + request[2].$id + ");";
|
||||
callback({$id:request[2].$id});
|
||||
};
|
||||
ds.saveScope({person1:person1, person2:person2,
|
||||
ignoreMe:{name: "ignore", save:function(callback){callback();}}}, function(){
|
||||
log += "done();";
|
||||
});
|
||||
assertEquals("save(1);save(2);done();", log);
|
||||
assertEquals(1, anchor.A);
|
||||
assertEquals(2, anchor.B);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testEntityLoadAllRows = function(){
|
||||
var ds = new nglr.DataStore();
|
||||
var Recipe = ds.entity("Recipe");
|
||||
var list = [];
|
||||
ds.loadAll = function(entity, callback){
|
||||
assertTrue(Recipe === entity);
|
||||
callback.apply(list);
|
||||
return list;
|
||||
};
|
||||
var items = Recipe.all(function(){
|
||||
assertTrue(list === this);
|
||||
});
|
||||
assertTrue(items === list);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testLoadAll = function(){
|
||||
expectAsserts(8);
|
||||
var post = function(data, callback){
|
||||
assertEquals("GET", data[0][0]);
|
||||
assertEquals("A", data[0][1]);
|
||||
callback(200, [[{$entity:'A', $id:'1'},{$entity:'A', $id:'2'}]]);
|
||||
};
|
||||
var datastore = new nglr.DataStore(post);
|
||||
var list = datastore.entity("A").all(function(){
|
||||
assertTrue(true);
|
||||
});
|
||||
datastore.flush();
|
||||
assertEquals(list.length, 2);
|
||||
assertEquals(list[0].$entity, "A");
|
||||
assertEquals(list[0].$id, "1");
|
||||
assertEquals(list[1].$entity, "A");
|
||||
assertEquals(list[1].$id, "2");
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testQuery = function(){
|
||||
expectAsserts(5);
|
||||
var post = function(data, callback) {
|
||||
assertEquals("GET", data[0][0]);
|
||||
assertEquals("Employee/managerId=123abc", data[0][1]);
|
||||
callback(200, [[{$entity:"Employee", $id: "456", managerId: "123ABC"}]]);
|
||||
|
||||
};
|
||||
var datastore = new nglr.DataStore(post);
|
||||
var Employee = datastore.entity("Employee");
|
||||
var list = Employee.query('managerId', "123abc", function(){
|
||||
assertTrue(true);
|
||||
});
|
||||
datastore.flush();
|
||||
assertJsonEquals([[{$entity:"Employee", $id: "456", managerId: "123ABC"}]], datastore._cache.$collections);
|
||||
assertEquals(list[0].$id, "456");
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testLoadingDocumentRefreshesExistingArrays = function() {
|
||||
expectAsserts(12);
|
||||
var post;
|
||||
var datastore = new nglr.DataStore(function(r, c){post(r,c);});
|
||||
var Book = datastore.entity('Book');
|
||||
post = function(req, callback) {
|
||||
callback(200, [[{$id:1, $entity:"Book", name:"Moby"},
|
||||
{$id:2, $entity:"Book", name:"Dick"}]]);
|
||||
};
|
||||
var allBooks = Book.all();
|
||||
datastore.flush();
|
||||
var queryBooks = Book.query("a", "b");
|
||||
datastore.flush();
|
||||
assertEquals("Moby", allBooks[0].name);
|
||||
assertEquals("Dick", allBooks[1].name);
|
||||
assertEquals("Moby", queryBooks[0].name);
|
||||
assertEquals("Dick", queryBooks[1].name);
|
||||
|
||||
post = function(req, callback) {
|
||||
assertEquals('[["GET","Book/1"]]', nglr.toJson(req));
|
||||
callback(200, [{$id:1, $entity:"Book", name:"Moby Dick"}]);
|
||||
};
|
||||
var book = Book.load(1);
|
||||
datastore.flush();
|
||||
assertEquals("Moby Dick", book.name);
|
||||
assertEquals("Moby Dick", allBooks[0].name);
|
||||
assertEquals("Moby Dick", queryBooks[0].name);
|
||||
|
||||
post = function(req, callback) {
|
||||
assertEquals('POST', req[0][0]);
|
||||
callback(200, [{$id:1, $entity:"Book", name:"The Big Fish"}]);
|
||||
};
|
||||
book.$save();
|
||||
datastore.flush();
|
||||
assertEquals("The Big Fish", book.name);
|
||||
assertEquals("The Big Fish", allBooks[0].name);
|
||||
assertEquals("The Big Fish", queryBooks[0].name);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testEntityProperties = function() {
|
||||
expectAsserts(2);
|
||||
var datastore = new nglr.DataStore();
|
||||
var callback = {};
|
||||
|
||||
datastore._jsonRequest = function(request, callbackFn) {
|
||||
assertJsonEquals(["GET", "Cheese/$properties"], request);
|
||||
assertEquals(callback, callbackFn);
|
||||
};
|
||||
|
||||
var Cheese = datastore.entity("Cheese");
|
||||
Cheese.properties(callback);
|
||||
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testLoadInstanceIsNotFromCache = function() {
|
||||
var post;
|
||||
var datastore = new nglr.DataStore(function(r, c){post(r,c);});
|
||||
var Book = datastore.entity('Book');
|
||||
|
||||
post = function(req, callback) {
|
||||
assertEquals('[["GET","Book/1"]]', nglr.toJson(req));
|
||||
callback(200, [{$id:1, $entity:"Book", name:"Moby Dick"}]);
|
||||
};
|
||||
var book = Book.load(1);
|
||||
datastore.flush();
|
||||
assertEquals("Moby Dick", book.name);
|
||||
assertFalse(book === datastore._cache['Book/1']);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testLoadStarsIsNewDocument = function() {
|
||||
var datastore = new nglr.DataStore();
|
||||
var Book = datastore.entity('Book');
|
||||
var book = Book.load('*');
|
||||
assertEquals('Book', book.$entity);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testUndefinedEntityReturnsNullValueObject = function() {
|
||||
var datastore = new nglr.DataStore();
|
||||
var Entity = datastore.entity(undefined);
|
||||
var all = Entity.all();
|
||||
assertEquals(0, all.length);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testFetchEntities = function(){
|
||||
expectAsserts(6);
|
||||
var post = function(data, callback){
|
||||
assertJsonEquals(["GET", "$entities"], data[0]);
|
||||
callback(200, [{A:0, B:0}]);
|
||||
};
|
||||
var datastore = new nglr.DataStore(post);
|
||||
var entities = datastore.entities(function(){
|
||||
assertTrue(true);
|
||||
});
|
||||
datastore.flush();
|
||||
assertJsonEquals([], datastore.bulkRequest);
|
||||
assertEquals(2, entities.length);
|
||||
assertEquals("A", entities[0].title);
|
||||
assertEquals("B", entities[1].title);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldMigrateSchema = function() {
|
||||
var datastore = new nglr.DataStore();
|
||||
var Entity = datastore.entity("Entity", {a:[], user:{name:"Misko", email:""}});
|
||||
var doc = Entity().$loadFrom({b:'abc', user:{email:"misko@hevery.com"}});
|
||||
assertFalse(
|
||||
nglr.toJson({a:[], b:'abc', user:{name:"Misko", email:"misko@hevery.com"}}) ==
|
||||
nglr.toJson(doc));
|
||||
doc.$migrate();
|
||||
assertEquals(
|
||||
nglr.toJson({a:[], b:'abc', user:{name:"Misko", email:"misko@hevery.com"}}),
|
||||
nglr.toJson(doc));
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldCollectRequestsForBulk = function() {
|
||||
var ds = new nglr.DataStore();
|
||||
var Book = ds.entity("Book");
|
||||
var Library = ds.entity("Library");
|
||||
Book.all();
|
||||
Library.load("123");
|
||||
assertEquals(2, ds.bulkRequest.length);
|
||||
assertJsonEquals(["GET", "Book"], ds.bulkRequest[0]);
|
||||
assertJsonEquals(["GET", "Library/123"], ds.bulkRequest[1]);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testEmptyFlushShouldDoNothing = function () {
|
||||
var ds = new nglr.DataStore(function(){
|
||||
fail("expecting noop");
|
||||
});
|
||||
ds.flush();
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testFlushShouldCallAllCallbacks = function() {
|
||||
var log = "";
|
||||
function post(request, callback){
|
||||
log += 'BulkRequest:' + nglr.toJson(request) + ';';
|
||||
callback(200, [[{$id:'ABC'}], {$id:'XYZ'}]);
|
||||
}
|
||||
var ds = new nglr.DataStore(post);
|
||||
var Book = ds.entity("Book");
|
||||
var Library = ds.entity("Library");
|
||||
Book.all(function(instance){
|
||||
log += nglr.toJson(instance) + ';';
|
||||
});
|
||||
Library.load("123", function(instance){
|
||||
log += nglr.toJson(instance) + ';';
|
||||
});
|
||||
assertEquals("", log);
|
||||
ds.flush();
|
||||
assertJsonEquals([], ds.bulkRequest);
|
||||
assertEquals('BulkRequest:[["GET","Book"],["GET","Library/123"]];[{"$id":"ABC"}];{"$id":"XYZ"};', log);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testSaveOnNotLoggedInRetriesAfterLoggin = function(){
|
||||
var log = "";
|
||||
var book;
|
||||
var ds = new nglr.DataStore(null, {login:function(c){c();}});
|
||||
ds.post = function (request, callback){
|
||||
assertJsonEquals([["POST", "", book]], request);
|
||||
ds.post = function(request, callback){
|
||||
assertJsonEquals([["POST", "", book]], request);
|
||||
ds.post = function(){fail("too much recursion");};
|
||||
callback(200, [{saved:"ok"}]);
|
||||
};
|
||||
callback(200, {$status_code:401});
|
||||
};
|
||||
book = ds.entity("Book")({name:"misko"});
|
||||
book.$save();
|
||||
ds.flush();
|
||||
assertJsonEquals({saved:"ok"}, book);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldRemoveItemFromCollectionWhenDeleted = function() {
|
||||
expectAsserts(6);
|
||||
var ds = new nglr.DataStore();
|
||||
ds.post = function(request, callback){
|
||||
assertJsonEquals([["GET", "Book"]], request);
|
||||
callback(200, [[{name:"Moby Dick", $id:123, $entity:'Book'}]]);
|
||||
};
|
||||
var Book = ds.entity("Book");
|
||||
var books = Book.all();
|
||||
ds.flush();
|
||||
assertJsonEquals([[{name:"Moby Dick", $id:123, $entity:'Book'}]], ds._cache.$collections);
|
||||
assertDefined(ds._cache['Book/123']);
|
||||
var book = Book({$id:123});
|
||||
ds.post = function(request, callback){
|
||||
assertJsonEquals([["DELETE", "", book]], request);
|
||||
callback(200, [book]);
|
||||
};
|
||||
ds.remove(book);
|
||||
ds.flush();
|
||||
assertUndefined(ds._cache['Book/123']);
|
||||
assertJsonEquals([[]],ds._cache.$collections);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldAddToAll = function() {
|
||||
expectAsserts(8);
|
||||
var ds = new nglr.DataStore();
|
||||
ds.post = function(request, callback){
|
||||
assertJsonEquals([["GET", "Book"]], request);
|
||||
callback(200, [[]]);
|
||||
};
|
||||
var Book = ds.entity("Book");
|
||||
var books = Book.all();
|
||||
assertEquals(0, books.length);
|
||||
ds.flush();
|
||||
var moby = Book({name:'moby'});
|
||||
moby.$save();
|
||||
ds.post = function(request, callback){
|
||||
assertJsonEquals([["POST", "", moby]], request);
|
||||
moby.$id = '123';
|
||||
callback(200, [moby]);
|
||||
};
|
||||
ds.flush();
|
||||
assertEquals(1, books.length);
|
||||
assertEquals(moby, books[0]);
|
||||
|
||||
moby.$save();
|
||||
ds.flush();
|
||||
assertEquals(1, books.length);
|
||||
assertEquals(moby, books[0]);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldReturnCreatedDocumentCountByUser = function(){
|
||||
expectAsserts(2);
|
||||
var datastore = new nglr.DataStore(
|
||||
function(request, callback){
|
||||
assertJsonEquals([["GET", "$users"]], request);
|
||||
callback(200, [{misko:1, adam:1}]);
|
||||
});
|
||||
var users = datastore.documentCountsByUser();
|
||||
assertJsonEquals({misko:1, adam:1}, users);
|
||||
};
|
||||
|
||||
|
||||
DataStoreTest.prototype.testItShouldReturnDocumentIdsForUeserByEntity = function(){
|
||||
expectAsserts(2);
|
||||
var datastore = new nglr.DataStore(
|
||||
function(request, callback){
|
||||
assertJsonEquals([["GET", "$users/misko@hevery.com"]], request);
|
||||
callback(200, [{Book:["1"], Library:["2"]}]);
|
||||
});
|
||||
var users = datastore.userDocumentIdsByEntity("misko@hevery.com");
|
||||
assertJsonEquals({Book:["1"], Library:["2"]}, users);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldReturnNewInstanceOn404 = function(){
|
||||
expectAsserts(7);
|
||||
var log = "";
|
||||
var datastore = new nglr.DataStore(
|
||||
function(request, callback){
|
||||
assertJsonEquals([["GET", "User/misko"]], request);
|
||||
callback(200, [{$status_code:404}]);
|
||||
});
|
||||
var User = datastore.entity("User", {admin:false});
|
||||
var user = User.loadOrCreate('misko', function(i){log+="cb "+i.$id+";";});
|
||||
datastore.flush();
|
||||
assertEquals("misko", user.$id);
|
||||
assertEquals("User", user.$entity);
|
||||
assertEquals(false, user.admin);
|
||||
assertEquals("undefined", typeof user.$secret);
|
||||
assertEquals("undefined", typeof user.$version);
|
||||
assertEquals("cb misko;", log);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldReturnNewInstanceOn404 = function(){
|
||||
var log = "";
|
||||
var datastore = new nglr.DataStore(
|
||||
function(request, callback){
|
||||
assertJsonEquals([["GET", "User/misko"],["GET", "User/adam"]], request);
|
||||
callback(200, [{$id:'misko'},{$id:'adam'}]);
|
||||
});
|
||||
var User = datastore.entity("User");
|
||||
var users = User.loadMany(['misko', 'adam'], function(i){log+="cb "+nglr.toJson(i)+";";});
|
||||
datastore.flush();
|
||||
assertEquals("misko", users[0].$id);
|
||||
assertEquals("adam", users[1].$id);
|
||||
assertEquals('cb [{"$id":"misko"},{"$id":"adam"}];', log);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldCreateJoinAndQuery = function() {
|
||||
var datastore = new nglr.DataStore();
|
||||
var Invoice = datastore.entity("Invoice");
|
||||
var Customer = datastore.entity("Customer");
|
||||
var InvoiceWithCustomer = datastore.join({
|
||||
invoice:{join:Invoice},
|
||||
customer:{join:Customer, on:"invoice.customer"}
|
||||
});
|
||||
var invoiceWithCustomer = InvoiceWithCustomer.query("invoice.month", 1);
|
||||
assertEquals([], invoiceWithCustomer);
|
||||
assertJsonEquals([["GET", "Invoice/month=1"]], datastore.bulkRequest);
|
||||
var request = datastore.bulkRequest.shift();
|
||||
request.$$callback([{$id:1, customer:1},{$id:2, customer:1},{$id:3, customer:3}]);
|
||||
assertJsonEquals([["GET","Customer/1"],["GET","Customer/3"]], datastore.bulkRequest);
|
||||
datastore.bulkRequest.shift().$$callback({$id:1});
|
||||
datastore.bulkRequest.shift().$$callback({$id:3});
|
||||
assertJsonEquals([
|
||||
{invoice:{$id:1,customer:1},customer:{$id:1}},
|
||||
{invoice:{$id:2,customer:1},customer:{$id:1}},
|
||||
{invoice:{$id:3,customer:3},customer:{$id:3}}], invoiceWithCustomer);
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldThrowIfMoreThanOneEntityIsPrimary = function() {
|
||||
var datastore = new nglr.DataStore();
|
||||
var Invoice = datastore.entity("Invoice");
|
||||
var Customer = datastore.entity("Customer");
|
||||
assertThrows("Exactly one entity needs to be primary.", function(){
|
||||
datastore.join({
|
||||
invoice:{join:Invoice},
|
||||
customer:{join:Customer}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldThrowIfLoopInReferences = function() {
|
||||
var datastore = new nglr.DataStore();
|
||||
var Invoice = datastore.entity("Invoice");
|
||||
var Customer = datastore.entity("Customer");
|
||||
assertThrows("Infinite loop in join: invoice -> customer", function(){
|
||||
datastore.join({
|
||||
invoice:{join:Invoice, on:"customer.invoice"},
|
||||
customer:{join:Customer, on:"invoice.customer"}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldThrowIfReferenceToNonExistantJoin = function() {
|
||||
var datastore = new nglr.DataStore();
|
||||
var Invoice = datastore.entity("Invoice");
|
||||
var Customer = datastore.entity("Customer");
|
||||
assertThrows("Named entity 'x' is undefined.", function(){
|
||||
datastore.join({
|
||||
invoice:{join:Invoice, on:"x.invoice"},
|
||||
customer:{join:Customer, on:"invoice.customer"}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
DataStoreTest.prototype.testItShouldThrowIfQueryOnNonPrimary = function() {
|
||||
var datastore = new nglr.DataStore();
|
||||
var Invoice = datastore.entity("Invoice");
|
||||
var Customer = datastore.entity("Customer");
|
||||
var InvoiceWithCustomer = datastore.join({
|
||||
invoice:{join:Invoice},
|
||||
customer:{join:Customer, on:"invoice.customer"}
|
||||
});
|
||||
assertThrows("Named entity 'customer' is not a primary entity.", function(){
|
||||
InvoiceWithCustomer.query("customer.month", 1);
|
||||
});
|
||||
};
|
||||
46
test/EntityDeclarationTest.js
Normal file
46
test/EntityDeclarationTest.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
EntityDeclarationTest = TestCase('EntityDeclarationTest');
|
||||
|
||||
EntityDeclarationTest.prototype.testEntityTypeOnly = function(){
|
||||
expectAsserts(2);
|
||||
var scope = new nglr.Scope({$datastore:{entity:function(name){
|
||||
assertEquals("Person", name);
|
||||
}}});
|
||||
var init = scope.entity("Person");
|
||||
assertEquals("", init);
|
||||
};
|
||||
|
||||
EntityDeclarationTest.prototype.testWithDefaults = function(){
|
||||
expectAsserts(4);
|
||||
var scope = new nglr.Scope({$datastore:{entity:function(name, init){
|
||||
assertEquals("Person", name);
|
||||
assertEquals("=a:", init.a);
|
||||
assertEquals(0, init.b.length);
|
||||
}}});
|
||||
var init = scope.entity('Person:{a:"=a:", b:[]}');
|
||||
assertEquals("", init);
|
||||
};
|
||||
|
||||
EntityDeclarationTest.prototype.testWithName = function(){
|
||||
expectAsserts(2);
|
||||
var scope = new nglr.Scope({$datastore:{entity:function(name, init){
|
||||
assertEquals("Person", name);
|
||||
return function (){ return {}; };
|
||||
}}});
|
||||
var init = scope.entity('friend=Person');
|
||||
assertEquals("$anchor.friend:{friend=Person.load($anchor.friend);friend.$$anchor=\"friend\";};", init);
|
||||
};
|
||||
|
||||
EntityDeclarationTest.prototype.testMultipleEntities = function(){
|
||||
expectAsserts(3);
|
||||
var expect = ['Person', 'Book'];
|
||||
var i=0;
|
||||
var scope = new nglr.Scope({$datastore:{entity:function(name, init){
|
||||
assertEquals(expect[i], name);
|
||||
i++;
|
||||
return function (){ return {}; };
|
||||
}}});
|
||||
var init = scope.entity('friend=Person;book=Book;');
|
||||
assertEquals("$anchor.friend:{friend=Person.load($anchor.friend);friend.$$anchor=\"friend\";};" +
|
||||
"$anchor.book:{book=Book.load($anchor.book);book.$$anchor=\"book\";};",
|
||||
init);
|
||||
};
|
||||
98
test/FileControllerTest.js
Normal file
98
test/FileControllerTest.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
FileControllerTest = TestCase('FileControllerTest');
|
||||
|
||||
FileControllerTest.prototype.testOnSelectUpdateView = function(){
|
||||
var view = jQuery('<span><a/><span/></span>');
|
||||
var swf = {};
|
||||
var controller = new nglr.FileController(view, null, swf);
|
||||
swf.uploadFile = function(path){};
|
||||
controller._on_select('A', 9, '9 bytes');
|
||||
assertEquals(view.find('a').text(), "A");
|
||||
assertEquals(view.find('span').text(), "9 bytes");
|
||||
};
|
||||
|
||||
FileControllerTest.prototype.testUpdateModelView = function(){
|
||||
var view = nglr.FileController.template('');
|
||||
var input = $('<input name="value.input">');
|
||||
var controller;
|
||||
var scope = new nglr.Scope({value:{}, $binder:{updateView:function(){
|
||||
controller.updateView(scope);
|
||||
}}});
|
||||
view.data('scope', scope);
|
||||
controller = new nglr.FileController(view, 'value.input', null, "http://server_base");
|
||||
var value = '{"text":"A", "size":123, "id":"890"}';
|
||||
controller._on_uploadCompleteData(value);
|
||||
controller.updateView(scope);
|
||||
assertEquals(scope.get('value.input.text'), 'A');
|
||||
assertEquals(scope.get('value.input.size'), 123);
|
||||
assertEquals(scope.get('value.input.id'), '890');
|
||||
assertEquals(scope.get('value.input.url'), 'http://server_base/_attachments/890/A');
|
||||
assertEquals(view.find('a').text(), "A");
|
||||
assertEquals(view.find('a').attr('href'), "http://server_base/_attachments/890/A");
|
||||
assertEquals(view.find('span').text(), "123 bytes");
|
||||
};
|
||||
|
||||
FileControllerTest.prototype.testFileUpload = function(){
|
||||
expectAsserts(1);
|
||||
var swf = {};
|
||||
var controller = new nglr.FileController(null, null, swf, "http://server_base");
|
||||
swf.uploadFile = function(path){
|
||||
assertEquals("http://server_base/_attachments", path);
|
||||
};
|
||||
controller.name = "Name";
|
||||
controller.upload();
|
||||
};
|
||||
|
||||
FileControllerTest.prototype.testFileUploadNoFileIsNoop = function(){
|
||||
expectAsserts(0);
|
||||
var swf = {uploadFile:function(path){
|
||||
fail();
|
||||
}};
|
||||
var controller = new nglr.FileController(null, swf);
|
||||
controller.upload("basePath", null);
|
||||
};
|
||||
|
||||
FileControllerTest.prototype.testRemoveAttachment = function(){
|
||||
var doc = nglr.FileController.template();
|
||||
var input = $('<input name="file">');
|
||||
var scope = new nglr.Scope();
|
||||
input.data('scope', scope);
|
||||
var controller = new nglr.FileController(doc, 'file', null, null);
|
||||
controller.updateView(scope);
|
||||
assertEquals(false, doc.find('input').attr('checked'));
|
||||
|
||||
scope.set('file', {url:'url', size:123});
|
||||
controller.updateView(scope);
|
||||
assertEquals(true, doc.find('input').attr('checked'));
|
||||
|
||||
doc.find('input').attr('checked', false);
|
||||
controller.updateModel(scope);
|
||||
assertNull(scope.get('file'));
|
||||
|
||||
doc.find('input').attr('checked', true);
|
||||
controller.updateModel(scope);
|
||||
assertEquals('url', scope.get('file.url'));
|
||||
assertEquals(123, scope.get('file.size'));
|
||||
};
|
||||
|
||||
FileControllerTest.prototype.testShouldEmptyOutOnUndefined = function () {
|
||||
var view = nglr.FileController.template('hello');
|
||||
var controller = new nglr.FileController(view, 'abc', null, null);
|
||||
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('abc', {text: 'myname', url: 'myurl', size: 1234});
|
||||
|
||||
controller.updateView(scope);
|
||||
assertEquals("myurl", view.find('a').attr('href'));
|
||||
assertEquals("myname", view.find('a').text());
|
||||
assertEquals(true, view.find('input').is(':checked'));
|
||||
assertEquals("1.2 KB", view.find('span').text());
|
||||
|
||||
scope.set('abc', undefined);
|
||||
controller.updateView(scope);
|
||||
assertEquals("myurl", view.find('a').attr('href'));
|
||||
assertEquals("myname", view.find('a').text());
|
||||
assertEquals(false, view.find('input').is(':checked'));
|
||||
assertEquals("1.2 KB", view.find('span').text());
|
||||
};
|
||||
|
||||
|
||||
153
test/FiltersTest.js
Normal file
153
test/FiltersTest.js
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
FiltersTest = TestCase('FiltersTest');
|
||||
|
||||
FiltersTest.prototype.testCurrency = function(){
|
||||
var html = $('<span/>');
|
||||
var context = {element:html[0]};
|
||||
var currency = nglr.bind(context, angular.filter.currency);
|
||||
|
||||
assertEquals(currency(0), '$0.00');
|
||||
assertEquals(html.hasClass('ng-format-negative'), false);
|
||||
assertEquals(currency(-999), '$-999.00');
|
||||
assertEquals(html.hasClass('ng-format-negative'), true);
|
||||
assertEquals(currency(1234.5678), '$1,234.57');
|
||||
assertEquals(html.hasClass('ng-format-negative'), false);
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testFilterThisIsContext = function(){
|
||||
expectAsserts(2);
|
||||
var scope = new nglr.Scope();
|
||||
nglr.Scope.expressionCache = {};
|
||||
var context = {element:123};
|
||||
angular.filter.testFn = function () {
|
||||
assertEquals('Context not equal', this, context);
|
||||
assertEquals('scope not equal', this.scope, scope);
|
||||
};
|
||||
scope.eval("0|testFn", context);
|
||||
delete angular.filter['testFn'];
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testNumberFormat = function(){
|
||||
var context = {jqElement:$('<span/>')};
|
||||
var number = nglr.bind(context, angular.filter.number);
|
||||
|
||||
assertEquals('0', number(0, 0));
|
||||
assertEquals('0.00', number(0));
|
||||
assertEquals('-999.00', number(-999));
|
||||
assertEquals('1,234.57', number(1234.5678));
|
||||
assertEquals('', number(Number.NaN));
|
||||
assertEquals('1,234.57', number("1234.5678"));
|
||||
assertEquals("", number(1/0));
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testJson = function () {
|
||||
assertEquals(nglr.toJson({a:"b"}, true), angular.filter.json({a:"b"}));
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testPackageTracking = function () {
|
||||
var assert = function(title, trackingNo) {
|
||||
var val = angular.filter.trackPackage(trackingNo, title);
|
||||
assertNotNull("Did Not Match: " + trackingNo, val);
|
||||
assertEquals(angular.filter.Meta.TAG, val.TAG);
|
||||
assertEquals(title + ": " + nglr.trim(trackingNo), val.text);
|
||||
assertNotNull(val.url);
|
||||
assertEquals(nglr.trim(trackingNo), val.trackingNo);
|
||||
assertEquals('<a href="' + val.url + '">' + val.text + '</a>', val.html);
|
||||
};
|
||||
assert('UPS', ' 1Z 999 999 99 9999 999 9 ');
|
||||
assert('UPS', '1ZW5w5220379084747');
|
||||
|
||||
assert('FedEx', '418822131061812');
|
||||
assert('FedEx', '9612019 5935 3267 2473 738');
|
||||
assert('FedEx', '9612019593532672473738');
|
||||
assert('FedEx', '235354667129449');
|
||||
assert('FedEx', '915368880571');
|
||||
assert('FedEx', '901712142390');
|
||||
assert('FedEx', '297391510063413');
|
||||
|
||||
assert('USPS', '9101 8052 1390 7402 4335 49');
|
||||
assert('USPS', '9101010521297963339560');
|
||||
assert('USPS', '9102901001301038667029');
|
||||
assert('USPS', '910 27974 4490 3000 8916 56');
|
||||
assert('USPS', '9102801438635051633253');
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testLink = function() {
|
||||
var assert = function(text, url, obj){
|
||||
var val = angular.filter.link(obj);
|
||||
assertEquals(angular.filter.Meta.TAG, val.TAG);
|
||||
assertEquals('<a href="' + url + '">' + text + '</a>', val.html);
|
||||
};
|
||||
assert("url", "url", "url");
|
||||
assert("hello", "url", {text:"hello", url:"url"});
|
||||
assert("a@b.com", "mailto:a@b.com", "a@b.com");
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testBytes = function(){
|
||||
var controller = new nglr.FileController();
|
||||
assertEquals(angular.filter.bytes(123), '123 bytes');
|
||||
assertEquals(angular.filter.bytes(1234), '1.2 KB');
|
||||
assertEquals(angular.filter.bytes(1234567), '1.1 MB');
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testImage = function(){
|
||||
assertEquals(null, angular.filter.image());
|
||||
assertEquals(null, angular.filter.image({}));
|
||||
assertEquals(null, angular.filter.image(""));
|
||||
assertEquals('<img src="abc"/>', angular.filter.image({url:"abc"}).html);
|
||||
assertEquals(
|
||||
'<img src="abc" style="max-width: 10px; max-height: 10px;"/>',
|
||||
angular.filter.image({url:"abc"}, 10).html);
|
||||
assertEquals(
|
||||
'<img src="abc" style="max-width: 10px; max-height: 20px;"/>',
|
||||
angular.filter.image({url:"abc"}, 10, 20).html);
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testQRcode = function() {
|
||||
assertEquals(
|
||||
'<img width="200" height="200" src="http://chart.apis.google.com/chart?chl=Hello%20world&chs=200x200&cht=qr"/>',
|
||||
angular.filter.qrcode('Hello world').html);
|
||||
assertEquals(
|
||||
'<img width="100" height="100" src="http://chart.apis.google.com/chart?chl=http%3A%2F%2Fserver%3Fa%26b%3Dc&chs=100x100&cht=qr"/>',
|
||||
angular.filter.qrcode('http://server?a&b=c', 100).html);
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testLowercase = function() {
|
||||
assertEquals('abc', angular.filter.lowercase('AbC'));
|
||||
assertEquals(null, angular.filter.lowercase(null));
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testUppercase = function() {
|
||||
assertEquals('ABC', angular.filter.uppercase('AbC'));
|
||||
assertEquals(null, angular.filter.uppercase(null));
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testLineCount = function() {
|
||||
assertEquals(1, angular.filter.linecount(null));
|
||||
assertEquals(1, angular.filter.linecount(''));
|
||||
assertEquals(1, angular.filter.linecount('a'));
|
||||
assertEquals(2, angular.filter.linecount('a\nb'));
|
||||
assertEquals(3, angular.filter.linecount('a\nb\nc'));
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testIf = function() {
|
||||
assertEquals('A', angular.filter['if']('A', true));
|
||||
assertEquals(undefined, angular.filter['if']('A', false));
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testUnless = function() {
|
||||
assertEquals('A', angular.filter.unless('A', false));
|
||||
assertEquals(undefined, angular.filter.unless('A', true));
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testGoogleChartApiEncode = function() {
|
||||
assertEquals(
|
||||
'<img width="200" height="200" src="http://chart.apis.google.com/chart?chl=Hello world&chs=200x200&cht=qr"/>',
|
||||
angular.filter.googleChartApi.encode({cht:"qr", chl:"Hello world"}).html);
|
||||
};
|
||||
|
||||
FiltersTest.prototype.testHtml = function() {
|
||||
assertEquals(
|
||||
"a<b>c</b>d",
|
||||
angular.filter.html("a<b>c</b>d").html);
|
||||
assertTrue(angular.filter.html("a<b>c</b>d") instanceof angular.filter.Meta);
|
||||
};
|
||||
69
test/JsonTest.js
Normal file
69
test/JsonTest.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
JsonTest = TestCase("JsonTest");
|
||||
|
||||
JsonTest.prototype.testPrimitives = function () {
|
||||
assertEquals("null", nglr.toJson(0/0));
|
||||
assertEquals("null", nglr.toJson(null));
|
||||
assertEquals("true", nglr.toJson(true));
|
||||
assertEquals("false", nglr.toJson(false));
|
||||
assertEquals("123.45", nglr.toJson(123.45));
|
||||
assertEquals('"abc"', nglr.toJson("abc"));
|
||||
assertEquals('"a \\t \\n \\r b \\\\"', nglr.toJson("a \t \n \r b \\"));
|
||||
};
|
||||
|
||||
JsonTest.prototype.testEscaping = function () {
|
||||
assertEquals("\"7\\\\\\\"7\"", nglr.toJson("7\\\"7"));
|
||||
};
|
||||
|
||||
JsonTest.prototype.testObjects = function () {
|
||||
assertEquals('{"a":1,"b":2}', nglr.toJson({a:1,b:2}));
|
||||
assertEquals('{"a":{"b":2}}', nglr.toJson({a:{b:2}}));
|
||||
assertEquals('{"a":{"b":{"c":0}}}', nglr.toJson({a:{b:{c:0}}}));
|
||||
assertEquals('{"a":{"b":null}}', nglr.toJson({a:{b:0/0}}));
|
||||
};
|
||||
|
||||
JsonTest.prototype.testObjectPretty = function () {
|
||||
assertEquals('{\n "a":1,\n "b":2}', nglr.toJson({a:1,b:2}, true));
|
||||
assertEquals('{\n "a":{\n "b":2}}', nglr.toJson({a:{b:2}}, true));
|
||||
};
|
||||
|
||||
JsonTest.prototype.testArray = function () {
|
||||
assertEquals('[]', nglr.toJson([]));
|
||||
assertEquals('[1,"b"]', nglr.toJson([1,"b"]));
|
||||
};
|
||||
|
||||
JsonTest.prototype.testIgnoreFunctions = function () {
|
||||
assertEquals('[null,1]', nglr.toJson([function(){},1]));
|
||||
assertEquals('{}', nglr.toJson({a:function(){}}));
|
||||
};
|
||||
|
||||
JsonTest.prototype.testParseNull = function () {
|
||||
assertNull(nglr.fromJson("null"));
|
||||
};
|
||||
|
||||
JsonTest.prototype.testParseBoolean = function () {
|
||||
assertTrue(nglr.fromJson("true"));
|
||||
assertFalse(nglr.fromJson("false"));
|
||||
};
|
||||
|
||||
JsonTest.prototype.test$$isIgnored = function () {
|
||||
assertEquals("{}", nglr.toJson({$$:0}));
|
||||
};
|
||||
|
||||
JsonTest.prototype.testArrayWithEmptyItems = function () {
|
||||
var a = [];
|
||||
a[1] = "X";
|
||||
assertEquals('[null,"X"]', nglr.toJson(a));
|
||||
};
|
||||
|
||||
JsonTest.prototype.testItShouldEscapeUnicode = function () {
|
||||
assertEquals(1, "\u00a0".length);
|
||||
assertEquals(8, nglr.toJson("\u00a0").length);
|
||||
assertEquals(1, nglr.fromJson(nglr.toJson("\u00a0")).length);
|
||||
};
|
||||
|
||||
JsonTest.prototype.testItShouldUTCDates = function() {
|
||||
var date = angular.String.toDate("2009-10-09T01:02:03Z");
|
||||
assertEquals('"2009-10-09T01:02:03Z"', nglr.toJson(date));
|
||||
assertEquals(date.getTime(),
|
||||
nglr.fromJson('"2009-10-09T01:02:03Z"').getTime());
|
||||
};
|
||||
70
test/LoaderTest.js
Normal file
70
test/LoaderTest.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
LoaderTest = TestCase('LoaderTest');
|
||||
|
||||
LoaderTest.prototype.testLoadCss = function(){
|
||||
if ($.browser.safari) return;
|
||||
var head = jQuery('<head/>')[0];
|
||||
var loader = new nglr.Loader(document, head, {});
|
||||
var log = '';
|
||||
loader.config.server = 'http://';
|
||||
loader.loadCss('x');
|
||||
assertEquals($(head).find('link').attr('href'), 'http://x');
|
||||
};
|
||||
|
||||
LoaderTest.prototype.testDefaultDatabasePathFromSubdomain = function() {
|
||||
var loader = new nglr.Loader(null, null, {server:"http://account.getangular.com", database:"database"});
|
||||
loader.computeConfiguration();
|
||||
assertEquals("database", loader.config.database);
|
||||
|
||||
loader = new nglr.Loader(null, null, {server:"http://account.getangular.com"});
|
||||
loader.computeConfiguration();
|
||||
assertEquals("account", loader.config.database);
|
||||
|
||||
loader = new nglr.Loader(null, null, {server:"https://account.getangular.com"});
|
||||
loader.computeConfiguration();
|
||||
assertEquals("account", loader.config.database);
|
||||
};
|
||||
|
||||
|
||||
|
||||
UrlWatcherTest = TestCase('UrlWatcherTest');
|
||||
|
||||
UrlWatcherTest.prototype.testUrlWatcher = function () {
|
||||
expectAsserts(2);
|
||||
var location = {href:"http://server", hash:""};
|
||||
var watcher = new nglr.UrlWatcher(location);
|
||||
watcher.delay = 1;
|
||||
watcher.listener = function(url){
|
||||
assertEquals('http://getangular.test', url);
|
||||
};
|
||||
watcher.setTimeout = function(fn, delay){
|
||||
assertEquals(1, delay);
|
||||
location.href = "http://getangular.test";
|
||||
watcher.setTimeout = function(fn, delay) {
|
||||
};
|
||||
fn();
|
||||
};
|
||||
watcher.watch();
|
||||
};
|
||||
|
||||
UrlWatcherTest.prototype.testItShouldFireOnUpdateEventWhenSpecialURLSet = function(){
|
||||
expectAsserts(2);
|
||||
var location = {href:"http://server", hash:"#$iframe_notify=1234"};
|
||||
var watcher = new nglr.UrlWatcher(location);
|
||||
nglr._iframe_notify_1234 = function () {
|
||||
assertEquals("undefined", typeof nglr._iframe_notify_1234);
|
||||
assertEquals("http://server2#", location.href);
|
||||
};
|
||||
watcher.delay = 1;
|
||||
watcher.expectedUrl = "http://server2";
|
||||
watcher.setTimeout = function(fn, delay){
|
||||
watcher.setTimeout = function(fn, delay) {};
|
||||
fn();
|
||||
};
|
||||
watcher.watch();
|
||||
};
|
||||
|
||||
FunctionTest = TestCase("FunctionTest");
|
||||
|
||||
FunctionTest.prototype.testEscapeHtml = function () {
|
||||
assertEquals("<div>&amp;</div>", nglr.escapeHtml('<div>&</div>'));
|
||||
};
|
||||
84
test/ModelTest.js
Normal file
84
test/ModelTest.js
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
ModelTest = TestCase('ModelTest');
|
||||
|
||||
ModelTest.prototype.testLoadSaveOperations = function(){
|
||||
var m1 = new nglr.DataStore().entity('A')();
|
||||
m1.a = 1;
|
||||
|
||||
var m2 = {b:1};
|
||||
|
||||
m1.$loadFrom(m2);
|
||||
|
||||
assertTrue(!m1.a);
|
||||
assertEquals(m1.b, 1);
|
||||
};
|
||||
|
||||
ModelTest.prototype.testLoadfromDoesNotClobberFunctions = function(){
|
||||
var m1 = new nglr.DataStore().entity('A')();
|
||||
m1.id = function(){return 'OK';};
|
||||
m1.$loadFrom({id:null});
|
||||
assertEquals(m1.id(), 'OK');
|
||||
|
||||
m1.b = 'OK';
|
||||
m1.$loadFrom({b:function(){}});
|
||||
assertEquals(m1.b, 'OK');
|
||||
};
|
||||
|
||||
ModelTest.prototype.testDataStoreDoesNotGetClobbered = function(){
|
||||
var ds = new nglr.DataStore();
|
||||
var m = ds.entity('A')();
|
||||
assertTrue(m.$$entity.datastore === ds);
|
||||
m.$loadFrom({});
|
||||
assertTrue(m.$$entity.datastore === ds);
|
||||
};
|
||||
|
||||
ModelTest.prototype.testManagedModelDelegatesMethodsToDataStore = function(){
|
||||
expectAsserts(7);
|
||||
var datastore = new nglr.DataStore();
|
||||
var model = datastore.entity("A", {a:1})();
|
||||
var fn = {};
|
||||
datastore.save = function(instance, callback) {
|
||||
assertTrue(model === instance);
|
||||
assertTrue(callback === fn);
|
||||
};
|
||||
datastore.remove = function(instance, callback) {
|
||||
assertTrue(model === instance);
|
||||
assertTrue(callback === fn);
|
||||
};
|
||||
datastore.load = function(instance, id, callback) {
|
||||
assertTrue(model === instance);
|
||||
assertTrue(id === "123");
|
||||
assertTrue(callback === fn);
|
||||
};
|
||||
model.$save(fn);
|
||||
model.$delete(fn);
|
||||
model.$loadById("123", fn);
|
||||
};
|
||||
|
||||
ModelTest.prototype.testManagedModelCanBeForcedToFlush = function(){
|
||||
expectAsserts(6);
|
||||
var datastore = new nglr.DataStore();
|
||||
var model = datastore.entity("A", {a:1})();
|
||||
|
||||
datastore.save = function(instance, callback) {
|
||||
assertTrue(model === instance);
|
||||
assertTrue(callback === undefined);
|
||||
};
|
||||
datastore.remove = function(instance, callback) {
|
||||
assertTrue(model === instance);
|
||||
assertTrue(callback === undefined);
|
||||
};
|
||||
datastore.flush = function(){
|
||||
assertTrue(true);
|
||||
};
|
||||
model.$save(true);
|
||||
model.$delete(true);
|
||||
};
|
||||
|
||||
|
||||
ModelTest.prototype.testItShouldMakeDeepCopyOfInitialValues = function (){
|
||||
var initial = {a:[]};
|
||||
var entity = new nglr.DataStore().entity("A", initial);
|
||||
var model = entity();
|
||||
model.a.push(1);
|
||||
assertEquals(0, entity().a.length);
|
||||
};
|
||||
462
test/ParserTest.js
Normal file
462
test/ParserTest.js
Normal file
|
|
@ -0,0 +1,462 @@
|
|||
LexerTest = TestCase('LexerTest');
|
||||
|
||||
LexerTest.prototype.testTokenizeAString = function(){
|
||||
var lexer = new nglr.Lexer("a.bc[22]+1.3|f:'a\\\'c':\"d\\\"e\"");
|
||||
var tokens = lexer.parse();
|
||||
var i = 0;
|
||||
assertEquals(tokens[i].index, 0);
|
||||
assertEquals(tokens[i].text, 'a.bc');
|
||||
|
||||
i++;
|
||||
assertEquals(tokens[i].index, 4);
|
||||
assertEquals(tokens[i].text, '[');
|
||||
|
||||
i++;
|
||||
assertEquals(tokens[i].index, 5);
|
||||
assertEquals(tokens[i].text, 22);
|
||||
|
||||
i++;
|
||||
assertEquals(tokens[i].index, 7);
|
||||
assertEquals(tokens[i].text, ']');
|
||||
|
||||
i++;
|
||||
assertEquals(tokens[i].index, 8);
|
||||
assertEquals(tokens[i].text, '+');
|
||||
|
||||
i++;
|
||||
assertEquals(tokens[i].index, 9);
|
||||
assertEquals(tokens[i].text, 1.3);
|
||||
|
||||
i++;
|
||||
assertEquals(tokens[i].index, 12);
|
||||
assertEquals(tokens[i].text, '|');
|
||||
|
||||
i++;
|
||||
assertEquals(tokens[i].index, 13);
|
||||
assertEquals(tokens[i].text, 'f');
|
||||
|
||||
i++;
|
||||
assertEquals(tokens[i].index, 14);
|
||||
assertEquals(tokens[i].text, ':');
|
||||
|
||||
i++;
|
||||
assertEquals(tokens[i].index, 15);
|
||||
assertEquals(tokens[i].text, "a'c");
|
||||
|
||||
i++;
|
||||
assertEquals(tokens[i].index, 21);
|
||||
assertEquals(tokens[i].text, ':');
|
||||
|
||||
i++;
|
||||
assertEquals(tokens[i].index, 22);
|
||||
assertEquals(tokens[i].text, 'd"e');
|
||||
};
|
||||
|
||||
|
||||
LexerTest.prototype.testTokenizeRegExp = function(){
|
||||
var lexer = new nglr.Lexer("/r 1/");
|
||||
var tokens = lexer.parse();
|
||||
var i = 0;
|
||||
assertEquals(tokens[i].index, 0);
|
||||
assertEquals(tokens[i].text, 'r 1');
|
||||
assertEquals("r 1".match(tokens[i].fn())[0], 'r 1');
|
||||
};
|
||||
|
||||
LexerTest.prototype.testQuotedString = function(){
|
||||
var str = "['\\'', \"\\\"\"]";
|
||||
var lexer = new nglr.Lexer(str);
|
||||
var tokens = lexer.parse();
|
||||
|
||||
assertEquals(1, tokens[1].index);
|
||||
assertEquals("'", tokens[1].text);
|
||||
|
||||
assertEquals(7, tokens[3].index);
|
||||
assertEquals('"', tokens[3].text);
|
||||
|
||||
};
|
||||
|
||||
LexerTest.prototype.testQuotedStringEscape = function(){
|
||||
var str = '"\\"\\n\\f\\r\\t\\v\\u00A0"';
|
||||
var lexer = new nglr.Lexer(str);
|
||||
var tokens = lexer.parse();
|
||||
|
||||
assertEquals('"\n\f\r\t\v\u00A0', tokens[0].text);
|
||||
};
|
||||
|
||||
LexerTest.prototype.testTokenizeUnicode = function(){
|
||||
var lexer = new nglr.Lexer('"\\u00A0"');
|
||||
var tokens = lexer.parse();
|
||||
assertEquals(1, tokens.length);
|
||||
assertEquals('\u00a0', tokens[0].text);
|
||||
};
|
||||
|
||||
LexerTest.prototype.testTokenizeRegExpWithOptions = function(){
|
||||
var lexer = new nglr.Lexer("/r/g");
|
||||
var tokens = lexer.parse();
|
||||
var i = 0;
|
||||
assertEquals(tokens[i].index, 0);
|
||||
assertEquals(tokens[i].text, 'r');
|
||||
assertEquals(tokens[i].flags, 'g');
|
||||
assertEquals("rr".match(tokens[i].fn()).length, 2);
|
||||
};
|
||||
|
||||
LexerTest.prototype.testTokenizeRegExpWithEscape = function(){
|
||||
var lexer = new nglr.Lexer("/\\/\\d/");
|
||||
var tokens = lexer.parse();
|
||||
var i = 0;
|
||||
assertEquals(tokens[i].index, 0);
|
||||
assertEquals(tokens[i].text, '\\/\\d');
|
||||
assertEquals("/1".match(tokens[i].fn())[0], '/1');
|
||||
};
|
||||
|
||||
LexerTest.prototype.testIgnoreWhitespace = function(){
|
||||
var lexer = new nglr.Lexer("a \t \n \r b");
|
||||
var tokens = lexer.parse();
|
||||
assertEquals(tokens[0].text, 'a');
|
||||
assertEquals(tokens[1].text, 'b');
|
||||
};
|
||||
|
||||
LexerTest.prototype.testRelation = function(){
|
||||
var lexer = new nglr.Lexer("! == != < > <= >=");
|
||||
var tokens = lexer.parse();
|
||||
assertEquals(tokens[0].text, '!');
|
||||
assertEquals(tokens[1].text, '==');
|
||||
assertEquals(tokens[2].text, '!=');
|
||||
assertEquals(tokens[3].text, '<');
|
||||
assertEquals(tokens[4].text, '>');
|
||||
assertEquals(tokens[5].text, '<=');
|
||||
assertEquals(tokens[6].text, '>=');
|
||||
};
|
||||
|
||||
LexerTest.prototype.testStatements = function(){
|
||||
var lexer = new nglr.Lexer("a;b;");
|
||||
var tokens = lexer.parse();
|
||||
assertEquals(tokens[0].text, 'a');
|
||||
assertEquals(tokens[1].text, ';');
|
||||
assertEquals(tokens[2].text, 'b');
|
||||
assertEquals(tokens[3].text, ';');
|
||||
};
|
||||
|
||||
ParserTest = TestCase('ParserTest');
|
||||
|
||||
ParserTest.prototype.testExpressions = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(scope.eval("-1"), -1);
|
||||
assertEquals(scope.eval("1 + 2.5"), 3.5);
|
||||
assertEquals(scope.eval("1 + -2.5"), -1.5);
|
||||
assertEquals(scope.eval("1+2*3/4"), 1+2*3/4);
|
||||
assertEquals(scope.eval("0--1+1.5"), 0- -1 + 1.5);
|
||||
assertEquals(scope.eval("-0--1++2*-3/-4"), -0- -1+ +2*-3/-4);
|
||||
assertEquals(scope.eval("1/2*3"), 1/2*3);
|
||||
};
|
||||
|
||||
ParserTest.prototype.testComparison = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(scope.eval("false"), false);
|
||||
assertEquals(scope.eval("!true"), false);
|
||||
assertEquals(scope.eval("1==1"), true);
|
||||
assertEquals(scope.eval("1!=2"), true);
|
||||
assertEquals(scope.eval("1<2"), true);
|
||||
assertEquals(scope.eval("1<=1"), true);
|
||||
assertEquals(scope.eval("1>2"), 1>2);
|
||||
assertEquals(scope.eval("2>=1"), 2>=1);
|
||||
};
|
||||
|
||||
ParserTest.prototype.testLogical = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(scope.eval("0&&2"), 0&&2);
|
||||
assertEquals(scope.eval("0||2"), 0||2);
|
||||
assertEquals(scope.eval("0||1&&2"), 0||1&&2);
|
||||
};
|
||||
|
||||
ParserTest.prototype.testString = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(scope.eval("'a' + 'b c'"), "ab c");
|
||||
};
|
||||
|
||||
ParserTest.prototype.testFilters = function(){
|
||||
angular.filter.substring = function(input, start, end) {
|
||||
return input.substring(start, end);
|
||||
};
|
||||
|
||||
angular.filter.upper = {_case:function(input) {
|
||||
return input.toUpperCase();
|
||||
}};
|
||||
var scope = new nglr.Scope();
|
||||
try {
|
||||
scope.eval("1|nonExistant");
|
||||
fail();
|
||||
} catch (e) {
|
||||
assertEquals(e, "Function 'nonExistant' at column '3' in '1|nonExistant' is not defined.");
|
||||
}
|
||||
scope.set('offset', 3);
|
||||
assertEquals(scope.eval("'abcd'|upper._case"), "ABCD");
|
||||
assertEquals(scope.eval("'abcd'|substring:1:offset"), "bc");
|
||||
assertEquals(scope.eval("'abcd'|substring:1:3|upper._case"), "BC");
|
||||
};
|
||||
|
||||
ParserTest.prototype.testScopeAccess = function(){
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('a', 123);
|
||||
scope.set('b.c', 456);
|
||||
assertEquals(scope.eval("a", scope), 123);
|
||||
assertEquals(scope.eval("b.c", scope), 456);
|
||||
assertEquals(scope.eval("x.y.z", scope), undefined);
|
||||
};
|
||||
|
||||
ParserTest.prototype.testGrouping = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(scope.eval("(1+2)*3"), (1+2)*3);
|
||||
};
|
||||
|
||||
ParserTest.prototype.testAssignments = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(scope.eval("a=12"), 12);
|
||||
assertEquals(scope.get("a"), 12);
|
||||
|
||||
scope = new nglr.Scope();
|
||||
assertEquals(scope.eval("x.y.z=123;"), 123);
|
||||
assertEquals(scope.get("x.y.z"), 123);
|
||||
|
||||
assertEquals(234, scope.eval("a=123; b=234"));
|
||||
assertEquals(123, scope.get("a"));
|
||||
assertEquals(234, scope.get("b"));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testFunctionCallsNoArgs = function(){
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('const', function(a,b){return 123;});
|
||||
assertEquals(scope.eval("const()"), 123);
|
||||
};
|
||||
|
||||
ParserTest.prototype.testFunctionCalls = function(){
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('add', function(a,b){
|
||||
return a+b;
|
||||
});
|
||||
assertEquals(3, scope.eval("add(1,2)"));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testCalculationBug = function(){
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('taxRate', 8);
|
||||
scope.set('subTotal', 100);
|
||||
assertEquals(scope.eval("taxRate / 100 * subTotal"), 8);
|
||||
assertEquals(scope.eval("subTotal * taxRate / 100"), 8);
|
||||
};
|
||||
|
||||
ParserTest.prototype.testArray = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(scope.eval("[]").length, 0);
|
||||
assertEquals(scope.eval("[1, 2]").length, 2);
|
||||
assertEquals(scope.eval("[1, 2]")[0], 1);
|
||||
assertEquals(scope.eval("[1, 2]")[1], 2);
|
||||
};
|
||||
|
||||
ParserTest.prototype.testArrayAccess = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(scope.eval("[1][0]"), 1);
|
||||
assertEquals(scope.eval("[[1]][0][0]"), 1);
|
||||
assertEquals(scope.eval("[].length"), 0);
|
||||
assertEquals(scope.eval("[1, 2].length"), 2);
|
||||
};
|
||||
|
||||
ParserTest.prototype.testObject = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(nglr.toJson(scope.eval("{}")), "{}");
|
||||
assertEquals(nglr.toJson(scope.eval("{a:'b'}")), '{"a":"b"}');
|
||||
assertEquals(nglr.toJson(scope.eval("{'a':'b'}")), '{"a":"b"}');
|
||||
assertEquals(nglr.toJson(scope.eval("{\"a\":'b'}")), '{"a":"b"}');
|
||||
};
|
||||
|
||||
ParserTest.prototype.testObjectAccess = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals("WC", scope.eval("{false:'WC', true:'CC'}[false]"));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testJSON = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(nglr.toJson(scope.eval("[{}]")), "[{}]");
|
||||
assertEquals(nglr.toJson(scope.eval("[{a:[]}, {b:1}]")), '[{"a":[]},{"b":1}]');
|
||||
};
|
||||
|
||||
ParserTest.prototype.testMultippleStatements = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(scope.eval("a=1;b=3;a+b"), 4);
|
||||
assertEquals(scope.eval(";;1;;"), 1);
|
||||
};
|
||||
|
||||
ParserTest.prototype.testParseThrow = function(){
|
||||
expectAsserts(1);
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('e', 'abc');
|
||||
try {
|
||||
scope.eval("throw e");
|
||||
} catch(e) {
|
||||
assertEquals(e, 'abc');
|
||||
}
|
||||
};
|
||||
|
||||
ParserTest.prototype.testMethodsGetDispatchedWithCorrectThis = function(){
|
||||
var scope = new nglr.Scope();
|
||||
var C = function (){
|
||||
this.a=123;
|
||||
};
|
||||
C.prototype.getA = function(){
|
||||
return this.a;
|
||||
};
|
||||
|
||||
scope.set("obj", new C());
|
||||
assertEquals(123, scope.eval("obj.getA()"));
|
||||
};
|
||||
ParserTest.prototype.testMethodsArgumentsGetCorrectThis = function(){
|
||||
var scope = new nglr.Scope();
|
||||
var C = function (){
|
||||
this.a=123;
|
||||
};
|
||||
C.prototype.sum = function(value){
|
||||
return this.a + value;
|
||||
};
|
||||
C.prototype.getA = function(){
|
||||
return this.a;
|
||||
};
|
||||
|
||||
scope.set("obj", new C());
|
||||
assertEquals(246, scope.eval("obj.sum(obj.getA())"));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testObjectPointsToScopeValue = function(){
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('a', "abc");
|
||||
assertEquals("abc", scope.eval("{a:a}").a);
|
||||
};
|
||||
|
||||
ParserTest.prototype.testFieldAccess = function(){
|
||||
var scope = new nglr.Scope();
|
||||
var fn = function(){
|
||||
return {name:'misko'};
|
||||
};
|
||||
scope.set('a', fn);
|
||||
assertEquals("misko", scope.eval("a().name"));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testArrayIndexBug = function () {
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('items', [{}, {name:'misko'}]);
|
||||
|
||||
assertEquals("misko", scope.eval('items[1].name'));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testArrayAssignment = function () {
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('items', []);
|
||||
|
||||
assertEquals("abc", scope.eval('items[1] = "abc"'));
|
||||
assertEquals("abc", scope.eval('items[1]'));
|
||||
// Dont know how to make this work....
|
||||
// assertEquals("moby", scope.eval('books[1] = "moby"'));
|
||||
// assertEquals("moby", scope.eval('books[1]'));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testFiltersCanBeGrouped = function () {
|
||||
var scope = new nglr.Scope({name:'MISKO'});
|
||||
assertEquals('misko', scope.eval('n = (name|lowercase)'));
|
||||
assertEquals('misko', scope.eval('n'));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testFiltersCanBeGrouped = function () {
|
||||
var scope = new nglr.Scope({name:'MISKO'});
|
||||
assertEquals('misko', scope.eval('n = (name|lowercase)'));
|
||||
assertEquals('misko', scope.eval('n'));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testRemainder = function () {
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(1, scope.eval('1%2'));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testSumOfUndefinedIsNotUndefined = function () {
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(1, scope.eval('1+undefined'));
|
||||
assertEquals(1, scope.eval('undefined+1'));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testMissingThrowsError = function() {
|
||||
var scope = new nglr.Scope();
|
||||
try {
|
||||
scope.eval('[].count(');
|
||||
fail();
|
||||
} catch (e) {
|
||||
assertEquals('Unexpected end of expression: [].count(', e);
|
||||
}
|
||||
};
|
||||
|
||||
ParserTest.prototype.testItShouldParseOnChangeIntoHashSet = function () {
|
||||
var scope = new nglr.Scope({count:0});
|
||||
scope.watch("$anchor.a:count=count+1;$anchor.a:count=count+20;b:count=count+300");
|
||||
|
||||
scope.watchListeners["$anchor.a"].listeners[0]();
|
||||
assertEquals(1, scope.get("count"));
|
||||
scope.watchListeners["$anchor.a"].listeners[1]();
|
||||
assertEquals(21, scope.get("count"));
|
||||
scope.watchListeners["b"].listeners[0]({scope:scope});
|
||||
assertEquals(321, scope.get("count"));
|
||||
};
|
||||
ParserTest.prototype.testItShouldParseOnChangeBlockIntoHashSet = function () {
|
||||
var scope = new nglr.Scope({count:0});
|
||||
var listeners = {a:[], b:[]};
|
||||
scope.watch("a:{count=count+1;count=count+20;};b:count=count+300",
|
||||
function(n, fn){listeners[n].push(fn);});
|
||||
|
||||
assertEquals(1, scope.watchListeners.a.listeners.length);
|
||||
assertEquals(1, scope.watchListeners.b.listeners.length);
|
||||
scope.watchListeners["a"].listeners[0]();
|
||||
assertEquals(21, scope.get("count"));
|
||||
scope.watchListeners["b"].listeners[0]();
|
||||
assertEquals(321, scope.get("count"));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testItShouldParseEmptyOnChangeAsNoop = function () {
|
||||
var scope = new nglr.Scope();
|
||||
scope.watch("", function(){fail();});
|
||||
};
|
||||
|
||||
ParserTest.prototype.testItShouldCreateClosureFunctionWithNoArguments = function () {
|
||||
var scope = new nglr.Scope();
|
||||
var fn = scope.eval("{:value}");
|
||||
scope.set("value", 1);
|
||||
assertEquals(1, fn());
|
||||
scope.set("value", 2);
|
||||
assertEquals(2, fn());
|
||||
fn = scope.eval("{():value}");
|
||||
assertEquals(2, fn());
|
||||
};
|
||||
|
||||
ParserTest.prototype.testItShouldCreateClosureFunctionWithArguments = function () {
|
||||
var scope = new nglr.Scope();
|
||||
var fn = scope.eval("{(a):value+a}");
|
||||
scope.set("value", 1);
|
||||
assertEquals(11, fn(10));
|
||||
scope.set("value", 2);
|
||||
assertEquals(12, fn(10));
|
||||
fn = scope.eval("{(a,b):value+a+b}");
|
||||
assertEquals(112, fn(10, 100));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testItShouldHaveDefaultArugument = function(){
|
||||
var scope = new nglr.Scope();
|
||||
var fn = scope.eval("{:$*2}");
|
||||
assertEquals(4, fn(2));
|
||||
};
|
||||
|
||||
ParserTest.prototype.testReturnFunctionsAreNotBound = function(){
|
||||
var scope = new nglr.Scope();
|
||||
scope.set("$datastore", new nglr.DataStore());
|
||||
scope.entity("Group");
|
||||
var Group = scope.get("Group");
|
||||
assertEquals("eval Group", "function", typeof scope.eval("Group"));
|
||||
assertEquals("direct Group", "function", typeof Group);
|
||||
assertEquals("eval Group.all", "function", typeof scope.eval("Group.query"));
|
||||
assertEquals("direct Group.all", "function", typeof Group.query);
|
||||
};
|
||||
|
||||
144
test/ScopeTest.js
Normal file
144
test/ScopeTest.js
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
ScopeTest = TestCase('ScopeTest');
|
||||
|
||||
ScopeTest.prototype.testGetScopeRetrieval = function(){
|
||||
var scope = {};
|
||||
var form = jQuery("<a><b><c></c></b></a>");
|
||||
form.data('scope', scope);
|
||||
var c = form.find('c');
|
||||
assertTrue(scope === c.scope());
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testGetScopeRetrievalIntermediateNode = function(){
|
||||
var scope = {};
|
||||
var form = jQuery("<a><b><c></c></b></a>");
|
||||
form.find("b").data('scope', scope);
|
||||
var b = form.find('b');
|
||||
assertTrue(scope === b.scope());
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testNoScopeDoesNotCauseInfiniteRecursion = function(){
|
||||
var form = jQuery("<a><b><c></c></b></a>");
|
||||
var c = form.find('c');
|
||||
assertTrue(!c.scope());
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testScopeEval = function(){
|
||||
var scope = new nglr.Scope({b:345});
|
||||
assertEquals(scope.eval('b = 123'), 123);
|
||||
assertEquals(scope.get('b'), 123);
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testScopeFromPrototype = function(){
|
||||
var scope = new nglr.Scope({b:123});
|
||||
scope.eval('a = b');
|
||||
scope.eval('b = 456');
|
||||
assertEquals(scope.get('a'), 123);
|
||||
assertEquals(scope.get('b'), 456);
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testSetScopeGet = function(){
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('a', 987);
|
||||
assertEquals(scope.get('a'), 987);
|
||||
assertEquals(scope.eval('a'), 987);
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testGetChain = function(){
|
||||
var scope = new nglr.Scope({a:{b:987}});
|
||||
assertEquals(scope.get('a.b'), 987);
|
||||
assertEquals(scope.eval('a.b'), 987);
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testGetUndefinedChain = function(){
|
||||
var scope = new nglr.Scope();
|
||||
assertEquals(typeof scope.get('a.b'), 'undefined');
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testSetChain = function(){
|
||||
var scope = new nglr.Scope({a:{}});
|
||||
scope.set('a.b', 987);
|
||||
assertEquals(scope.get('a.b'), 987);
|
||||
assertEquals(scope.eval('a.b'), 987);
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testSetGetOnChain = function(){
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('a.b', 987);
|
||||
assertEquals(scope.get('a.b'), 987);
|
||||
assertEquals(scope.eval('a.b'), 987);
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testGlobalFunctionAccess =function(){
|
||||
window['scopeAddTest'] = function (a, b) {return a+b;};
|
||||
var scope = new nglr.Scope({window:window});
|
||||
assertEquals(scope.eval('window.scopeAddTest(1,2)'), 3);
|
||||
|
||||
scope.set('add', function (a, b) {return a+b;});
|
||||
assertEquals(scope.eval('add(1,2)'), 3);
|
||||
|
||||
scope.set('math.add', function (a, b) {return a+b;});
|
||||
assertEquals(scope.eval('math.add(1,2)'), 3);
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testValidationEval = function(){
|
||||
expectAsserts(4);
|
||||
var scope = new nglr.Scope();
|
||||
angular.validator.testValidator = function(value, expect){
|
||||
assertEquals(scope, this.scope);
|
||||
return value == expect ? null : "Error text";
|
||||
};
|
||||
|
||||
assertEquals("Error text", scope.validate("testValidator:'abc'", 'x'));
|
||||
assertEquals(null, scope.validate("testValidator:'abc'", 'abc'));
|
||||
|
||||
delete angular.validator['testValidator'];
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testCallingNonExistantMethodShouldProduceFriendlyException = function() {
|
||||
expectAsserts(1);
|
||||
var scope = new nglr.Scope({obj:{}});
|
||||
try {
|
||||
scope.eval("obj.iDontExist()");
|
||||
fail();
|
||||
} catch (e) {
|
||||
assertEquals("Expression 'obj.iDontExist' is not a function.", e);
|
||||
}
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testAccessingWithInvalidPathShouldThrowError = function() {
|
||||
var scope = new nglr.Scope();
|
||||
try {
|
||||
scope.get('a.{{b}}');
|
||||
fail();
|
||||
} catch (e) {
|
||||
assertEquals("Expression 'a.{{b}}' is not a valid expression for accesing variables.", e);
|
||||
}
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testItShouldHave$parent = function() {
|
||||
var parent = new nglr.Scope({}, "ROOT");
|
||||
var child = new nglr.Scope(parent.state);
|
||||
assertSame("parent", child.state.$parent, parent.state);
|
||||
assertSame("root", child.state.$root, parent.state);
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testItShouldHave$root = function() {
|
||||
var scope = new nglr.Scope({}, "ROOT");
|
||||
assertSame(scope.state.$root, scope.state);
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testItShouldBuildPathOnUndefined = function(){
|
||||
var scope = new nglr.Scope({}, "ROOT");
|
||||
scope.setEval("a.$b.c", 1);
|
||||
assertJsonEquals({$b:{c:1}}, scope.get("a"));
|
||||
};
|
||||
|
||||
ScopeTest.prototype.testItShouldMapUnderscoreFunctions = function(){
|
||||
var scope = new nglr.Scope({}, "ROOT");
|
||||
scope.set("a", [1,2,3]);
|
||||
assertEquals('function', typeof scope.get("a.$size"));
|
||||
scope.eval("a.$includeIf(4,true)");
|
||||
assertEquals(4, scope.get("a.$size")());
|
||||
assertEquals(4, scope.eval("a.$size()"));
|
||||
assertEquals('undefined', typeof scope.get("a.dontExist"));
|
||||
};
|
||||
42
test/ServerTest.js
Normal file
42
test/ServerTest.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
ServerTest = TestCase("ServerTest");
|
||||
ServerTest.prototype.testBreakLargeRequestIntoPackets = function() {
|
||||
var log = "";
|
||||
var server = new nglr.Server("http://server", function(url){
|
||||
log += "|" + url;
|
||||
});
|
||||
server.maxSize = 30;
|
||||
server.uuid = "uuid";
|
||||
server.request("POST", "/data/database", {}, function(code, r){
|
||||
assertEquals(200, code);
|
||||
assertEquals("response", r);
|
||||
});
|
||||
nglr.uuid0("response");
|
||||
assertEquals(
|
||||
"|http://server/$/uuid0/2/1?h=eyJtIjoiUE9TVCIsInAiOnt9LCJ1Ij" +
|
||||
"|http://server/$/uuid0/2/2?h=oiL2RhdGEvZGF0YWJhc2UifQ==",
|
||||
log);
|
||||
};
|
||||
|
||||
ServerTest.prototype.testItShouldEncodeUsingUrlRules = function() {
|
||||
var server = new nglr.Server("http://server");
|
||||
assertEquals("fn5-fn5-", server.base64url("~~~~~~"));
|
||||
assertEquals("fn5_fn5_", server.base64url("~~\u007f~~\u007f"));
|
||||
};
|
||||
|
||||
FrameServerTest = TestCase("FrameServerTest");
|
||||
|
||||
FrameServerTest.prototype = {
|
||||
testRead:function(){
|
||||
var window = {name:'$DATASET:"MyData"'};
|
||||
var server = new nglr.FrameServer(window);
|
||||
server.read();
|
||||
assertEquals("MyData", server.data);
|
||||
},
|
||||
testWrite:function(){
|
||||
var window = {};
|
||||
var server = new nglr.FrameServer(window);
|
||||
server.data = "TestData"
|
||||
server.write();
|
||||
assertEquals('$DATASET:"TestData"', window.name);
|
||||
}
|
||||
};
|
||||
26
test/UsersTest.js
Normal file
26
test/UsersTest.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (C) 2008,2009 BRAT Tech LLC
|
||||
|
||||
UsersTest = TestCase("UsersTest");
|
||||
|
||||
UsersTest.prototype = {
|
||||
setUp:function(){},
|
||||
|
||||
tearDown:function(){},
|
||||
|
||||
testItShouldFetchCurrentUser:function(){
|
||||
expectAsserts(5);
|
||||
var user;
|
||||
var users = new nglr.Users({request:function(method, url, request, callback){
|
||||
assertEquals("GET", method);
|
||||
assertEquals("/account.json", url);
|
||||
assertEquals("{}", nglr.toJson(request));
|
||||
callback(200, {$status_code:200, user:{name:'misko'}});
|
||||
}});
|
||||
users.fetchCurrentUser(function(u){
|
||||
user = u;
|
||||
assertEquals("misko", u.name);
|
||||
assertEquals("misko", users.current.name);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
65
test/ValidatorsTest.js
Normal file
65
test/ValidatorsTest.js
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
ValidatorTest = TestCase('ValidatorTest');
|
||||
|
||||
ValidatorTest.prototype.testRegexp = function() {
|
||||
assertEquals(angular.validator.regexp("abc", /x/, "E1"), "E1");
|
||||
assertEquals(angular.validator.regexp("abc", '/x/'),
|
||||
"Value does not match expected format /x/.");
|
||||
assertEquals(angular.validator.regexp("ab", '^ab$'), null);
|
||||
assertEquals(angular.validator.regexp("ab", '^axb$', "E3"), "E3");
|
||||
};
|
||||
|
||||
ValidatorTest.prototype.testNumber = function() {
|
||||
assertEquals(angular.validator.number("ab"), "Value is not a number.");
|
||||
assertEquals(angular.validator.number("-0.1",0), "Value can not be less than 0.");
|
||||
assertEquals(angular.validator.number("10.1",0,10), "Value can not be greater than 10.");
|
||||
assertEquals(angular.validator.number("1.2"), null);
|
||||
assertEquals(angular.validator.number(" 1 ", 1, 1), null);
|
||||
};
|
||||
|
||||
ValidatorTest.prototype.testInteger = function() {
|
||||
assertEquals(angular.validator.integer("ab"), "Value is not a number.");
|
||||
assertEquals(angular.validator.integer("1.1"), "Value is not a whole number.");
|
||||
assertEquals(angular.validator.integer("-1",0), "Value can not be less than 0.");
|
||||
assertEquals(angular.validator.integer("11",0,10), "Value can not be greater than 10.");
|
||||
assertEquals(angular.validator.integer("1"), null);
|
||||
assertEquals(angular.validator.integer(" 1 ", 1, 1), null);
|
||||
};
|
||||
|
||||
ValidatorTest.prototype.testDate = function() {
|
||||
var error = "Value is not a date. (Expecting format: 12/31/2009).";
|
||||
assertEquals(angular.validator.date("ab"), error);
|
||||
assertEquals(angular.validator.date("12/31/2009"), null);
|
||||
};
|
||||
|
||||
ValidatorTest.prototype.testPhone = function() {
|
||||
var error = "Phone number needs to be in 1(987)654-3210 format in North America or +999 (123) 45678 906 internationaly.";
|
||||
assertEquals(angular.validator.phone("ab"), error);
|
||||
assertEquals(null, angular.validator.phone("1(408)757-3023"));
|
||||
assertEquals(null, angular.validator.phone("+421 (0905) 933 297"));
|
||||
assertEquals(null, angular.validator.phone("+421 0905 933 297"));
|
||||
};
|
||||
|
||||
ValidatorTest.prototype.testSSN = function() {
|
||||
var error = "SSN needs to be in 999-99-9999 format.";
|
||||
assertEquals(angular.validator.ssn("ab"), error);
|
||||
assertEquals(angular.validator.ssn("123-45-6789"), null);
|
||||
};
|
||||
|
||||
ValidatorTest.prototype.testURL = function() {
|
||||
var error = "URL needs to be in http://server[:port]/path format.";
|
||||
assertEquals(angular.validator.url("ab"), error);
|
||||
assertEquals(angular.validator.url("http://server:123/path"), null);
|
||||
};
|
||||
|
||||
ValidatorTest.prototype.testEmail = function() {
|
||||
var error = "Email needs to be in username@host.com format.";
|
||||
assertEquals(error, angular.validator.email("ab"));
|
||||
assertEquals(null, angular.validator.email("misko@hevery.com"));
|
||||
};
|
||||
|
||||
ValidatorTest.prototype.testJson = function() {
|
||||
assertNotNull(angular.validator.json("'"));
|
||||
assertNotNull(angular.validator.json("''X"));
|
||||
assertNull(angular.validator.json("{}"));
|
||||
};
|
||||
|
||||
269
test/WidgetsTest.js
Normal file
269
test/WidgetsTest.js
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
WidgetTest = TestCase('WidgetTest');
|
||||
|
||||
WidgetTest.prototype.testRequired = function () {
|
||||
var view = $('<input name="a" ng-required>');
|
||||
var scope = new nglr.Scope({$invalidWidgets:[]});
|
||||
var cntl = new nglr.TextController(view[0], 'a');
|
||||
cntl.updateView(scope);
|
||||
assertTrue(view.hasClass('ng-validation-error'));
|
||||
assertEquals("Required Value", view.attr('ng-error'));
|
||||
scope.set('a', 'A');
|
||||
cntl.updateView(scope);
|
||||
assertFalse(view.hasClass('ng-validation-error'));
|
||||
assertEquals("undefined", typeof view.attr('ng-error'));
|
||||
};
|
||||
|
||||
WidgetTest.prototype.testValidator = function () {
|
||||
var view = $('<input name="a" ng-validate="testValidator:\'ABC\'">');
|
||||
var scope = new nglr.Scope({$invalidWidgets:[]});
|
||||
var cntl = new nglr.TextController(view[0], 'a');
|
||||
angular.validator.testValidator = function(value, expect){
|
||||
return value == expect ? null : "Error text";
|
||||
};
|
||||
|
||||
scope.set('a', '');
|
||||
cntl.updateView(scope);
|
||||
assertEquals(view.hasClass('ng-validation-error'), false);
|
||||
assertEquals(null, view.attr('ng-error'));
|
||||
|
||||
scope.set('a', 'X');
|
||||
cntl.updateView(scope);
|
||||
assertEquals(view.hasClass('ng-validation-error'), true);
|
||||
assertEquals(view.attr('ng-error'), "Error text");
|
||||
assertEquals("Error text", view.attr('ng-error'));
|
||||
|
||||
scope.set('a', 'ABC');
|
||||
cntl.updateView(scope);
|
||||
assertEquals(view.hasClass('ng-validation-error'), false);
|
||||
assertEquals(view.attr('ng-error'), null);
|
||||
assertEquals(null, view.attr('ng-error'));
|
||||
|
||||
delete angular.validator['testValidator'];
|
||||
};
|
||||
|
||||
WidgetTest.prototype.testRequiredValidator = function () {
|
||||
var view = $('<input name="a" ng-required ng-validate="testValidator:\'ABC\'">');
|
||||
var scope = new nglr.Scope({$invalidWidgets:[]});
|
||||
var cntl = new nglr.TextController(view[0], 'a');
|
||||
angular.validator.testValidator = function(value, expect){
|
||||
return value == expect ? null : "Error text";
|
||||
};
|
||||
|
||||
scope.set('a', '');
|
||||
cntl.updateView(scope);
|
||||
assertEquals(view.hasClass('ng-validation-error'), true);
|
||||
assertEquals("Required Value", view.attr('ng-error'));
|
||||
|
||||
scope.set('a', 'X');
|
||||
cntl.updateView(scope);
|
||||
assertEquals(view.hasClass('ng-validation-error'), true);
|
||||
assertEquals("Error text", view.attr('ng-error'));
|
||||
|
||||
scope.set('a', 'ABC');
|
||||
cntl.updateView(scope);
|
||||
assertEquals(view.hasClass('ng-validation-error'), false);
|
||||
assertEquals(null, view.attr('ng-error'));
|
||||
|
||||
delete angular.validator['testValidator'];
|
||||
};
|
||||
|
||||
TextController = TestCase("TextController");
|
||||
|
||||
TextController.prototype.testDatePicker = function() {
|
||||
var input = $('<input type="text" ng-widget="datepicker">');
|
||||
input.data('scope', new nglr.Scope());
|
||||
var body = $(document.body);
|
||||
body.append(input);
|
||||
var binder = new nglr.Binder(input[0], new nglr.WidgetFactory());
|
||||
assertTrue('before', input.data('datepicker') === undefined);
|
||||
binder.compile();
|
||||
assertTrue('after', input.data('datepicker') !== null);
|
||||
assertTrue(body.html(), input.hasClass('hasDatepicker'));
|
||||
};
|
||||
|
||||
RepeaterUpdater = TestCase("RepeaterUpdater");
|
||||
|
||||
RepeaterUpdater.prototype.testRemoveThenAdd = function() {
|
||||
var view = $("<div><span/></div>");
|
||||
var template = function () {
|
||||
return $("<li/>");
|
||||
};
|
||||
var repeater = new nglr.RepeaterUpdater(view.find("span"), "a in b", template, "");
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('b', [1,2]);
|
||||
|
||||
repeater.updateView(scope);
|
||||
|
||||
scope.set('b', []);
|
||||
repeater.updateView(scope);
|
||||
|
||||
scope.set('b', [1]);
|
||||
repeater.updateView(scope);
|
||||
assertEquals(1, view.find("li").size());
|
||||
};
|
||||
|
||||
RepeaterUpdater.prototype.testShouldBindWidgetOnRepeaterClone = function(){
|
||||
//fail();
|
||||
};
|
||||
|
||||
RepeaterUpdater.prototype.testShouldThrowInformativeSyntaxError= function(){
|
||||
expectAsserts(1);
|
||||
try {
|
||||
var repeater = new nglr.RepeaterUpdater(null, "a=b");
|
||||
} catch (e) {
|
||||
assertEquals("Expected ng-repeat in form of 'item in collection' but got 'a=b'.", e);
|
||||
}
|
||||
};
|
||||
|
||||
SelectControllerTest = TestCase("SelectControllerTest");
|
||||
|
||||
SelectControllerTest.prototype.testShouldUpdateModelNullOnNothingSelected = function(){
|
||||
var scope = new nglr.Scope();
|
||||
var view = {selectedIndex:-1, options:[]};
|
||||
var cntl = new nglr.SelectController(view, 'abc');
|
||||
cntl.updateModel(scope);
|
||||
assertNull(scope.get('abc'));
|
||||
};
|
||||
|
||||
SelectControllerTest.prototype.testShouldUpdateModelWhenNothingSelected = function(){
|
||||
var scope = new nglr.Scope();
|
||||
var view = {value:'123'};
|
||||
var cntl = new nglr.SelectController(view, 'abc');
|
||||
cntl.updateView(scope);
|
||||
assertEquals("123", scope.get('abc'));
|
||||
};
|
||||
|
||||
BindUpdaterTest = TestCase("BindUpdaterTest");
|
||||
|
||||
BindUpdaterTest.prototype.testShouldDisplayNothingForUndefined = function () {
|
||||
var view = $('<span />');
|
||||
var controller = new nglr.BindUpdater(view[0], "{{a}}");
|
||||
var scope = new nglr.Scope();
|
||||
|
||||
scope.set('a', undefined);
|
||||
controller.updateView(scope);
|
||||
assertEquals("", view.text());
|
||||
|
||||
scope.set('a', null);
|
||||
controller.updateView(scope);
|
||||
assertEquals("", view.text());
|
||||
};
|
||||
|
||||
BindUpdaterTest.prototype.testShouldDisplayJsonForNonStrings = function () {
|
||||
var view = $('<span />');
|
||||
var controller = new nglr.BindUpdater(view[0], "{{obj}}");
|
||||
|
||||
controller.updateView(new nglr.Scope({obj:[]}));
|
||||
assertEquals("[]", view.text());
|
||||
|
||||
controller.updateView(new nglr.Scope({obj:{text:'abc'}}));
|
||||
assertEquals('abc', nglr.fromJson(view.text()).text);
|
||||
};
|
||||
|
||||
|
||||
BindUpdaterTest.prototype.testShouldInsertHtmlNode = function () {
|
||||
var view = $('<span />');
|
||||
var controller = new nglr.BindUpdater(view[0], "<fake>&{{obj}}</fake>");
|
||||
var scope = new nglr.Scope();
|
||||
|
||||
scope.set("obj", $('<div>myDiv</div>')[0]);
|
||||
controller.updateView(scope);
|
||||
assertEquals("<fake>&myDiv</fake>", view.text());
|
||||
};
|
||||
|
||||
|
||||
BindUpdaterTest.prototype.testShouldDisplayTextMethod = function () {
|
||||
var view = $('<div />');
|
||||
var controller = new nglr.BindUpdater(view[0], "{{obj}}");
|
||||
var scope = new nglr.Scope();
|
||||
|
||||
scope.set("obj", new angular.filter.Meta({text:function(){return "abc";}}));
|
||||
controller.updateView(scope);
|
||||
assertEquals("abc", view.text());
|
||||
|
||||
scope.set("obj", new angular.filter.Meta({text:"123"}));
|
||||
controller.updateView(scope);
|
||||
assertEquals("123", view.text());
|
||||
|
||||
scope.set("obj", {text:"123"});
|
||||
controller.updateView(scope);
|
||||
assertEquals("123", nglr.fromJson(view.text()).text);
|
||||
};
|
||||
|
||||
BindUpdaterTest.prototype.testShouldDisplayHtmlMethod = function () {
|
||||
var view = $('<div />');
|
||||
var controller = new nglr.BindUpdater(view[0], "{{obj}}");
|
||||
var scope = new nglr.Scope();
|
||||
|
||||
scope.set("obj", new angular.filter.Meta({html:function(){return "a<div>b</div>c";}}));
|
||||
controller.updateView(scope);
|
||||
assertEquals("abc", view.text());
|
||||
|
||||
scope.set("obj", new angular.filter.Meta({html:"1<div>2</div>3"}));
|
||||
controller.updateView(scope);
|
||||
assertEquals("123", view.text());
|
||||
|
||||
scope.set("obj", {html:"123"});
|
||||
controller.updateView(scope);
|
||||
assertEquals("123", nglr.fromJson(view.text()).html);
|
||||
};
|
||||
|
||||
BindUpdaterTest.prototype.testUdateBoolean = function() {
|
||||
var view = $('<div />');
|
||||
var controller = new nglr.BindUpdater(view[0], "{{true}}, {{false}}");
|
||||
controller.updateView(new nglr.Scope());
|
||||
assertEquals('true, false', view.text());
|
||||
};
|
||||
|
||||
BindAttrUpdaterTest = TestCase("BindAttrUpdaterTest");
|
||||
|
||||
BindAttrUpdaterTest.prototype.testShouldLoadBlankImageWhenBindingIsUndefined = function () {
|
||||
var view = $('<img />');
|
||||
var controller = new nglr.BindAttrUpdater(view[0], {src: '{{imageUrl}}'});
|
||||
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('imageUrl', undefined);
|
||||
scope.set('config.server', 'http://server');
|
||||
|
||||
controller.updateView(scope);
|
||||
assertEquals("http://server/images/blank.gif", view.attr('src'));
|
||||
};
|
||||
|
||||
RepeaterUpdaterTest = TestCase("RepeaterUpdaterTest");
|
||||
RepeaterUpdaterTest.prototype.testShouldNotDieWhenRepeatExpressionIsNull = function() {
|
||||
var rep = new nglr.RepeaterUpdater(null, "$item in items", null, null);
|
||||
var scope = new nglr.Scope();
|
||||
scope.set('items', undefined);
|
||||
rep.updateView(scope);
|
||||
};
|
||||
|
||||
RepeaterUpdaterTest.prototype.testShouldIterateOverKeys = function() {
|
||||
var rep = new nglr.RepeaterUpdater(null, "($k,_v) in items", null, null);
|
||||
assertEquals("items", rep.iteratorExp);
|
||||
assertEquals("_v", rep.valueExp);
|
||||
assertEquals("$k", rep.keyExp);
|
||||
};
|
||||
|
||||
EvalUpdaterTest = TestCase("EvalUpdaterTest");
|
||||
EvalUpdaterTest.prototype.testEvalThrowsException = function(){
|
||||
var view = $('<div/>');
|
||||
var eval = new nglr.EvalUpdater(view[0], 'undefined()');
|
||||
|
||||
eval.updateView(new nglr.Scope());
|
||||
assertTrue(!!view.attr('ng-error'));
|
||||
assertTrue(view.hasClass('ng-exception'));
|
||||
|
||||
eval.exp = "1";
|
||||
eval.updateView(new nglr.Scope());
|
||||
assertFalse(!!view.attr('ng-error'));
|
||||
assertFalse(view.hasClass('ng-exception'));
|
||||
};
|
||||
|
||||
RadioControllerTest = TestCase("RadioController");
|
||||
RadioControllerTest.prototype.testItShouldTreatTrueStringAsBoolean = function () {
|
||||
var view = $('<input type="radio" name="select" value="true"/>');
|
||||
var radio = new nglr.RadioController(view[0], 'select');
|
||||
var scope = new nglr.Scope({select:true});
|
||||
radio.updateView(scope);
|
||||
assertTrue(view[0].checked);
|
||||
};
|
||||
47
test/XSitePostTest.js
Normal file
47
test/XSitePostTest.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
XSitePost = TestCase("XSitePost");
|
||||
|
||||
var e = function(text){ return Base64.encode(text); };
|
||||
|
||||
XSitePost.prototype.testMessageReceived = function () {
|
||||
expectAsserts(4);
|
||||
var xPost = new nglr.XSitePost();
|
||||
xPost.baseUrl = "http://getangular.test";
|
||||
xPost.post = function(url, request, callback){
|
||||
assertEquals('http://getangular.test/url', url);
|
||||
assertEquals('abc', request.a);
|
||||
assertEquals('xyz', request.x);
|
||||
};
|
||||
xPost.incomingFragment('#id;0;1;'+e('/url')+':a:'+e('abc')+':x:'+e('xyz'));
|
||||
assertEquals('{}', nglr.toJson(xPost.inQueue));
|
||||
};
|
||||
|
||||
XSitePost.prototype.testMessageReceivedInParts = function () {
|
||||
expectAsserts(5);
|
||||
var xPost = new nglr.XSitePost();
|
||||
xPost.baseUrl = "http://getangular.test";
|
||||
xPost.post = function(url, request, callback){
|
||||
assertEquals('http://getangular.test/url', url);
|
||||
assertEquals('abc', request.a);
|
||||
assertEquals('xyz', request.x);
|
||||
};
|
||||
xPost.incomingFragment('#id;1;2;:x:'+e('xyz'));
|
||||
assertNotSame('{}', nglr.toJson(xPost.inQueue));
|
||||
xPost.incomingFragment('#id;0;2;'+e('/url')+':a:'+e('abc'));
|
||||
assertEquals('{}', nglr.toJson(xPost.inQueue));
|
||||
};
|
||||
|
||||
XSitePost.prototype.testPostResponsIsEnqueued = function () {
|
||||
var xPost = new nglr.XSitePost();
|
||||
xPost.maxMsgSize = 11;
|
||||
xPost.response("id", "response", "status");
|
||||
|
||||
assertEquals('["id:0:2:cmVzcG9uc2U","id:1:2:="]',
|
||||
nglr.toJson(xPost.outQueue));
|
||||
};
|
||||
|
||||
XSitePost.prototype.testPush = function () {
|
||||
var window = {};
|
||||
var xPost = new nglr.XSitePost(window);
|
||||
xPost.response("id", "response", "status");
|
||||
assertEquals('id:0:1:cmVzcG9uc2U=', xPost.outQueue[0]);
|
||||
};
|
||||
22
test/formsTest.js
Normal file
22
test/formsTest.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
nglrTest = TestCase('nglrTest');
|
||||
|
||||
nglrTest.prototype.testShiftBind = function(){
|
||||
expectAsserts(3);
|
||||
nglr.shiftBind('this', function(target, arg) {
|
||||
assertEquals(this, 'this');
|
||||
assertEquals(target, 'target');
|
||||
assertEquals(arg, 'arg');
|
||||
}).apply('target', ['arg']);
|
||||
};
|
||||
|
||||
nglrTest.prototype.testBind = function(){
|
||||
expectAsserts(2);
|
||||
nglr.bind('this', function(arg) {
|
||||
assertEquals(this, 'this');
|
||||
assertEquals(arg, 'arg');
|
||||
}).apply('XXX', ['arg']);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
7
test/test/StepsTest.js
Normal file
7
test/test/StepsTest.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
StepsTest = TestCase("StepsTest");
|
||||
|
||||
StepsTest.prototype.testGivenDataset=function(){
|
||||
var self = {frame:{}, dataset:[]};
|
||||
angular.test.GIVEN.dataset.call(self);
|
||||
assertEquals('$DATASET:{"dataset":[]}', self.frame.name);
|
||||
};
|
||||
129
test/testabilityPatch.js
Normal file
129
test/testabilityPatch.js
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
TestCase = function(name) { return jstestdriver.testCaseManager.TestCase(name); };
|
||||
|
||||
HIDDEN = jQuery.browser.msie ?
|
||||
'' :
|
||||
jQuery.browser.safari ?
|
||||
' style="display: none; "' :
|
||||
' style="display: none;"';
|
||||
|
||||
nglr.msie = jQuery.browser.msie;
|
||||
nglr.alert = function(msg) {jstestdriver.console.log("ALERT: " + msg);};
|
||||
|
||||
function noop(){}
|
||||
|
||||
jstd = jstestdriver;
|
||||
|
||||
function html(content) {
|
||||
return jQuery("<div></div>").html(content);
|
||||
}
|
||||
|
||||
function report(reportTest){
|
||||
$("#tests").children().each(function(i){
|
||||
var success = this.className == "pass";
|
||||
var strong = this.firstChild;
|
||||
var msg = strong.firstChild.nodeValue;
|
||||
var parts = msg.split(" module: ");
|
||||
var module = parts[0];
|
||||
var name = parts[1].replace(/ *$/, "");
|
||||
reportTest(success, module, name, this.nodeValue);
|
||||
});
|
||||
}
|
||||
|
||||
MockUrlWatcher = function() {
|
||||
this.url = "http://server";
|
||||
};
|
||||
MockUrlWatcher.prototype.getUrl = function(){
|
||||
return this.url;
|
||||
};
|
||||
MockUrlWatcher.prototype.setUrl = function(url){
|
||||
this.url = url;
|
||||
};
|
||||
|
||||
jQuery.fn.sortedHtml = function() {
|
||||
var html = "";
|
||||
var toString = function(index, node) {
|
||||
node = node || this;
|
||||
if (node.nodeName == "#text") {
|
||||
html += nglr.escapeHtml(node.nodeValue);
|
||||
} else {
|
||||
html += '<' + node.nodeName.toLowerCase();
|
||||
var attributes = node.attributes || [];
|
||||
var attrs = [];
|
||||
for(var i=0; i<attributes.length; i++) {
|
||||
var attr = attributes[i];
|
||||
if(attr.name.match(/^ng-/) ||
|
||||
attr.value &&
|
||||
attr.value !='null' &&
|
||||
attr.value !='auto' &&
|
||||
attr.value !='false' &&
|
||||
attr.value !='inherit' &&
|
||||
attr.value !='0' &&
|
||||
attr.name !='loop' &&
|
||||
attr.name !='maxLength' &&
|
||||
attr.name !='size' &&
|
||||
attr.name !='start' &&
|
||||
attr.name !='tabIndex' &&
|
||||
attr.name.substr(0, 6) != 'jQuery') {
|
||||
// in IE we need to check for all of these.
|
||||
attrs.push(' ' + attr.name + '="' + attr.value + '"');
|
||||
}
|
||||
}
|
||||
attrs.sort();
|
||||
html += attrs.join('');
|
||||
html += '>';
|
||||
var children = node.childNodes;
|
||||
for(var j=0; j<children.length; j++) {
|
||||
toString(j, children[j]);
|
||||
}
|
||||
html += '</' + node.nodeName.toLowerCase() + '>';
|
||||
}
|
||||
};
|
||||
this.children().each(toString);
|
||||
return html;
|
||||
};
|
||||
|
||||
function encode64(obj){
|
||||
return Base64.encode(nglr.toJson(obj));
|
||||
}
|
||||
|
||||
function decode64(base64){
|
||||
return nglr.fromJson(Base64.decode(base64));
|
||||
}
|
||||
|
||||
nglr.Loader.prototype.configureJQueryPlugins();
|
||||
|
||||
function assertHidden(node) {
|
||||
var display = node.css('display');
|
||||
assertEquals("Node should be hidden but vas visible: " + node.sortedHtml(), 'none', display);
|
||||
}
|
||||
|
||||
function assertVisible(node) {
|
||||
var display = node.css('display');
|
||||
if (display == 'block') display = "";
|
||||
assertEquals("Node should be visible but vas hidden: " + node.sortedHtml(), '', display);
|
||||
}
|
||||
|
||||
function assertJsonEquals(expected, actual) {
|
||||
assertEquals(nglr.toJson(expected), nglr.toJson(actual));
|
||||
}
|
||||
|
||||
function assertUndefined(value) {
|
||||
assertEquals('undefined', typeof value);
|
||||
}
|
||||
|
||||
function assertDefined(value) {
|
||||
assertTrue(nglr.toJson(value), !!value);
|
||||
}
|
||||
|
||||
function assertThrows(error, fn){
|
||||
var exception = null;
|
||||
try {
|
||||
fn();
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
if (!exception) {
|
||||
fail("Expecting exception, none thrown");
|
||||
}
|
||||
assertEquals(error, exception);
|
||||
}
|
||||
Loading…
Reference in a new issue