// Source: public/lib/angular/angular.min.js /* AngularJS v1.2.32 (c) 2010-2014 Google, Inc. http://angularjs.org License: MIT */ (function(V,W,v){'use strict';function z(b){return function(){var a=arguments[0],c,a="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.2.32/"+(b?b+"/":"")+a;for(c=1;c").append(b).html();try{return 3===b[0].nodeType?A(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+A(b)})}catch(d){return A(c)}}function ac(b){try{return decodeURIComponent(b)}catch(a){}}function bc(b){var a={},c,d;r((b||"").split("&"),function(b){b&&(c=b.replace(/\+/g,"%20").split("="),d=ac(c[0]),G(d)&&(b=G(c[1])?ac(c[1]):!0,kb.call(a,d)?M(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function Bb(b){var a= [];r(b,function(b,d){M(b)?r(b,function(b){a.push(Ca(d,!0)+(!0===b?"":"="+Ca(b,!0)))}):a.push(Ca(d,!0)+(!0===b?"":"="+Ca(b,!0)))});return a.length?a.join("&"):""}function lb(b){return Ca(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function Ca(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function Xc(b,a){function c(a){a&&d.push(a)}var d=[b],e,f,g=["ng:app","ng-app","x-ng-app", "data-ng-app"],h=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;r(g,function(a){g[a]=!0;c(W.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(r(b.querySelectorAll("."+a),c),r(b.querySelectorAll("."+a+"\\:"),c),r(b.querySelectorAll("["+a+"]"),c))});r(d,function(a){if(!e){var b=h.exec(" "+a.className+" ");b?(e=a,f=(b[2]||"").replace(/\s+/g,",")):r(a.attributes,function(b){!e&&g[b.name]&&(e=a,f=b.value)})}});e&&a(e,f?[f]:[])}function cc(b,a){var c=function(){b=D(b);if(b.injector()){var c=b[0]===W? "document":ia(b);throw Ua("btstrpd",c.replace(//,">"));}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");c=dc(a);c.invoke(["$rootScope","$rootElement","$compile","$injector","$animate",function(a,b,c,d,e){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},d=/^NG_DEFER_BOOTSTRAP!/;if(V&&!d.test(V.name))return c();V.name=V.name.replace(d,"");Wa.resumeBootstrap=function(b){r(b,function(b){a.push(b)});c()}}function mb(b,a){a= a||"_";return b.replace(Yc,function(b,d){return(d?a:"")+b.toLowerCase()})}function Cb(b,a,c){if(!b)throw Ua("areq",a||"?",c||"required");return b}function Xa(b,a,c){c&&M(b)&&(b=b[b.length-1]);Cb(O(b),a,"not a function, got "+(b&&"object"===typeof b?b.constructor.name||"Object":typeof b));return b}function Da(b,a){if("hasOwnProperty"===b)throw Ua("badname",a);}function ec(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,f=a.length,g=0;g "+e[1]+a.replace(me,"<$1>")+e[2];d.removeChild(d.firstChild);for(a=e[0];a--;)d=d.lastChild;a=0;for(e=d.childNodes.length;a=u?(c.preventDefault=null,c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function La(b,a){var c=typeof b,d;"function"==c||"object"==c&&null!==b?"function"==typeof(d= b.$$hashKey)?d=b.$$hashKey():d===v&&(d=b.$$hashKey=(a||hb)()):d=b;return c+":"+d}function cb(b,a){if(a){var c=0;this.nextUid=function(){return++c}}r(b,this.put,this)}function pc(b){var a,c;"function"===typeof b?(a=b.$inject)||(a=[],b.length&&(c=b.toString().replace(pe,""),c=c.match(qe),r(c[1].split(re),function(b){b.replace(se,function(b,c,d){a.push(d)})})),b.$inject=a):M(b)?(c=b.length-1,Xa(b[c],"fn"),a=b.slice(0,c)):Xa(b,"fn",!0);return a}function dc(b){function a(a){return function(b,c){if(T(b))r(b, Xb(a));else return a(b,c)}}function c(a,b){Da(a,"service");if(O(b)||M(b))b=n.instantiate(b);if(!b.$get)throw db("pget",a);return m[a+h]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[],c,d,f,h;r(a,function(a){if(!l.get(a)){l.put(a,!0);try{if(E(a))for(c=Za(a),b=b.concat(e(c.requires)).concat(c._runBlocks),d=c._invokeQueue,f=0,h=d.length;f 4096 bytes)!"));else{if(k.cookie!==ba)for(ba=k.cookie,d=ba.split("; "),N={},f=0;fl&&this.remove(q.key), b},get:function(a){if(l").parent()[0])});var f=P(a,b,a,c,d,e);aa(a,"ng-scope");return function(b,c,d,e){Cb(b,"scope");var g=c?Ma.clone.call(a):a;r(d,function(a,b){g.data("$"+b+"Controller",a)});d=0;for(var k=g.length;darguments.length&&(b=a,a=v);Ga&&(c=ba);return n(a,b,c)}var x,R,y,N,C,Q,ba={},ra;x=c===f?d:ha(d,new Nb(D(f),d.$attr));R=x.$$element;if(L){var ve=/^\s*([@=&])(\??)\s*(\w*)\s*$/; Q=e.$new(!0);!J||J!==L&&J!==L.$$originalDirective?R.data("$isolateScopeNoTemplate",Q):R.data("$isolateScope",Q);aa(R,"ng-isolate-scope");r(L.scope,function(a,c){var d=a.match(ve)||[],f=d[3]||c,g="?"==d[2],d=d[1],k,m,n,q;Q.$$isolateBindings[c]=d+f;switch(d){case "@":x.$observe(f,function(a){Q[c]=a});x.$$observers[f].$$scope=e;x[f]&&(Q[c]=b(x[f])(e));break;case "=":if(g&&!x[f])break;m=p(x[f]);q=m.literal?Ba:function(a,b){return a===b||a!==a&&b!==b};n=m.assign||function(){k=Q[c]=m(e);throw ja("nonassign", x[f],L.name);};k=Q[c]=m(e);Q.$watch(function(){var a=m(e);q(a,Q[c])||(q(a,k)?n(e,a=Q[c]):Q[c]=a);return k=a},null,m.literal);break;case "&":m=p(x[f]);Q[c]=function(a){return m(e,a)};break;default:throw ja("iscp",L.name,c,a);}})}ra=n&&w;P&&r(P,function(a){var b={$scope:a===L||a.$$isolateScope?Q:e,$element:R,$attrs:x,$transclude:ra},c;C=a.controller;"@"==C&&(C=x[a.name]);c=s(C,b);ba[a.name]=c;Ga||R.data("$"+a.name+"Controller",c);a.controllerAs&&(b.$scope[a.controllerAs]=c)});g=0;for(y=k.length;gI.priority)break;if(u=I.scope)N=N||I,I.templateUrl||(eb("new/isolated scope",L,I,A),T(u)&&(L=I));z=I.name;!I.templateUrl&&I.controller&&(u=I.controller,P=P||{},eb("'"+z+"' controller",P[z],I,A),P[z]=I);if(u=I.transclude)H=!0,I.$$tlb||(eb("transclusion",da,I,A),da=I),"element"==u?(Ga=!0,x=I.priority,u=A,A=d.$$element=D(W.createComment(" "+z+": "+d[z]+" ")),c=A[0],ra(f,va.call(u,0),c),S=y(u,e,x,g&& g.name,{nonTlbTranscludeDirective:da})):(u=D(Jb(c)).contents(),A.empty(),S=y(u,e));if(I.template)if(F=!0,eb("template",J,I,A),J=I,u=O(I.template)?I.template(A,d):I.template,u=V(u),I.replace){g=I;u=Hb.test(u)?D($(u)):[];c=u[0];if(1!=u.length||1!==c.nodeType)throw ja("tplrt",z,"");ra(f,A,c);U={$attr:{}};u=ba(c,[],U);var we=a.splice(ka+1,a.length-(ka+1));L&&G(u);a=a.concat(u).concat(we);B(d,U);U=a.length}else A.html(u);if(I.templateUrl)F=!0,eb("template",J,I,A),J=I,I.replace&&(g=I),K=ue(a.splice(ka, a.length-ka),A,d,f,H&&S,k,q,{controllerDirectives:P,newIsolateScopeDirective:L,templateDirective:J,nonTlbTranscludeDirective:da}),U=a.length;else if(I.compile)try{Oa=I.compile(A,d,S),O(Oa)?w(null,Oa,X,Y):Oa&&w(Oa.pre,Oa.post,X,Y)}catch(Z){m(Z,ia(A))}I.terminal&&(K.terminal=!0,x=Math.max(x,I.priority))}K.scope=N&&!0===N.scope;K.transcludeOnThisElement=H;K.templateOnThisElement=F;K.transclude=S;n.hasElementTranscludeDirective=Ga;return K}function G(a){for(var b=0,c=a.length;bq.priority)&&-1!=q.restrict.indexOf(f)&&(l&&(q=Zb(q,{$$start:l,$$end:n})),b.push(q),p=q)}catch(x){m(x)}}return p}function B(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;r(a,function(d,e){"$"!=e.charAt(0)&&(b[e]&&b[e]!==d&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});r(b,function(b,f){"class"==f?(aa(e,b),a["class"]=(a["class"]?a["class"]+" ": "")+b):"style"==f?(e.attr("style",e.attr("style")+";"+b),a.style=(a.style?a.style+";":"")+b):"$"==f.charAt(0)||a.hasOwnProperty(f)||(a[f]=b,d[f]=c[f])})}function ue(a,b,c,d,e,f,g,k){var p=[],l,m,w=b[0],s=a.shift(),x=F({},s,{templateUrl:null,transclude:null,replace:null,$$originalDirective:s}),K=O(s.templateUrl)?s.templateUrl(b,c):s.templateUrl;b.empty();n.get(t.getTrustedResourceUrl(K),{cache:q}).success(function(q){var n,t;q=V(q);if(s.replace){q=Hb.test(q)?D($(q)):[];n=q[0];if(1!=q.length||1!==n.nodeType)throw ja("tplrt", s.name,K);q={$attr:{}};ra(d,b,n);var y=ba(n,[],q);T(s.scope)&&G(y);a=y.concat(a);B(c,q)}else n=w,b.html(q);a.unshift(x);l=J(a,n,c,e,b,s,f,g,k);r(d,function(a,c){a==n&&(d[c]=b[0])});for(m=P(b[0].childNodes,e);p.length;){q=p.shift();t=p.shift();var L=p.shift(),C=p.shift(),y=b[0];if(t!==w){var Q=t.className;k.hasElementTranscludeDirective&&s.replace||(y=Jb(n));ra(L,D(t),y);aa(D(y),Q)}t=l.transcludeOnThisElement?N(q,l.transclude,C):C;l(m,q,y,d,t)}p=null}).error(function(a,b,c,d){throw ja("tpload",d.url); });return function(a,b,c,d,e){a=e;p?(p.push(b),p.push(c),p.push(d),p.push(a)):(l.transcludeOnThisElement&&(a=N(b,l.transclude,e)),l(m,b,c,d,a))}}function H(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.namea.status?d:n.reject(d)}var c={method:"get",transformRequest:e.transformRequest,transformResponse:e.transformResponse},d=function(a){var b=e.headers,c=F({},a.headers),d,f,b=F({},b.common,b[A(a.method)]);a:for(d in b){a=A(d);for(f in c)if(A(f)===a)continue a;c[d]=b[d]}(function(a){var b;r(a,function(c,d){O(c)&&(b=c(),null!=b?a[d]=b:delete a[d])})})(c); return c}(a);F(c,a);c.headers=d;c.method=Ja(c.method);var f=[function(a){d=a.headers;var c=uc(a.data,tc(d),a.transformRequest);H(c)&&r(d,function(a,b){"content-type"===A(b)&&delete d[b]});H(a.withCredentials)&&!H(e.withCredentials)&&(a.withCredentials=e.withCredentials);return s(a,c,d).then(b,b)},v],g=n.when(c);for(r(t,function(a){(a.request||a.requestError)&&f.unshift(a.request,a.requestError);(a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;){a=f.shift();var h=f.shift(), g=g.then(a,h)}g.success=function(a){g.then(function(b){a(b.data,b.status,b.headers,c)});return g};g.error=function(a){g.then(null,function(b){a(b.data,b.status,b.headers,c)});return g};return g}function s(c,f,g){function l(a,b,c,e){C&&(200<=a&&300>a?C.put(u,[a,b,sc(c),e]):C.remove(u));q(b,a,c,e);d.$$phase||d.$apply()}function q(a,b,d,e){b=Math.max(b,0);(200<=b&&300>b?t.resolve:t.reject)({data:a,status:b,headers:tc(d),config:c,statusText:e})}function s(){var a=Sa(p.pendingRequests,c);-1!==a&&p.pendingRequests.splice(a, 1)}var t=n.defer(),r=t.promise,C,J,u=K(c.url,c.params);p.pendingRequests.push(c);r.then(s,s);!c.cache&&!e.cache||(!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method)||(C=T(c.cache)?c.cache:T(e.cache)?e.cache:w);if(C)if(J=C.get(u),G(J)){if(J&&O(J.then))return J.then(s,s),J;M(J)?q(J[1],J[0],ha(J[2]),J[3]):q(J,200,{},"OK")}else C.put(u,r);H(J)&&((J=Ob(c.url)?b.cookies()[c.xsrfCookieName||e.xsrfCookieName]:v)&&(g[c.xsrfHeaderName||e.xsrfHeaderName]=J),a(c.method,u,f,l,g,c.timeout,c.withCredentials,c.responseType)); return r}function K(a,b){if(!b)return a;var c=[];Tc(b,function(a,b){null===a||H(a)||(M(a)||(a=[a]),r(a,function(a){T(a)&&(a=ua(a)?a.toISOString():oa(a));c.push(Ca(b)+"="+Ca(a))}))});0=u&&(!b.match(/^(get|post|head|put|delete|options)$/i)||!V.XMLHttpRequest))return new V.ActiveXObject("Microsoft.XMLHTTP");if(V.XMLHttpRequest)return new V.XMLHttpRequest;throw z("$httpBackend")("noxhr"); }function Vd(){this.$get=["$browser","$window","$document",function(b,a,c){return ze(b,ye,b.defer,a.angular.callbacks,c[0])}]}function ze(b,a,c,d,e){function f(a,b,c){var f=e.createElement("script"),g=null;f.type="text/javascript";f.src=a;f.async=!0;g=function(a){ab(f,"load",g);ab(f,"error",g);e.body.removeChild(f);f=null;var h=-1,s="unknown";a&&("load"!==a.type||d[b].called||(a={type:"error"}),s=a.type,h="error"===a.type?404:200);c&&c(h,s)};rb(f,"load",g);rb(f,"error",g);8>=u&&(f.onreadystatechange= function(){E(f.readyState)&&/loaded|complete/.test(f.readyState)&&(f.onreadystatechange=null,g({type:"load"}))});e.body.appendChild(f);return g}var g=-1;return function(e,k,l,m,n,q,p,s){function K(){t=g;L&&L();y&&y.abort()}function w(a,d,e,f,g){P&&c.cancel(P);L=y=null;0===d&&(d=e?200:"file"==wa(k).protocol?404:0);a(1223===d?204:d,e,f,g||"");b.$$completeOutstandingRequest(B)}var t;b.$$incOutstandingRequestCount();k=k||b.url();if("jsonp"==A(e)){var x="_"+(d.counter++).toString(36);d[x]=function(a){d[x].data= a;d[x].called=!0};var L=f(k.replace("JSON_CALLBACK","angular.callbacks."+x),x,function(a,b){w(m,a,d[x].data,"",b);d[x]=B})}else{var y=a(e);y.open(e,k,!0);r(n,function(a,b){G(a)&&y.setRequestHeader(b,a)});y.onreadystatechange=function(){if(y&&4==y.readyState){var a=null,b=null,c="";t!==g&&(a=y.getAllResponseHeaders(),b="response"in y?y.response:y.responseText);t===g&&10>u||(c=y.statusText);w(m,t||y.status,b,a,c)}};p&&(y.withCredentials=!0);if(s)try{y.responseType=s}catch(aa){if("json"!==s)throw aa; }y.send(l||null)}if(0=h&&(n.resolve(p),m(q.$$intervalId),delete e[q.$$intervalId]);s||b.$apply()},g);e[q.$$intervalId]=n;return q}var e={};d.cancel=function(b){return b&&b.$$intervalId in e?(e[b.$$intervalId].reject("canceled"),a.clearInterval(b.$$intervalId),delete e[b.$$intervalId], !0):!1};return d}]}function bd(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "), DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return 1===b?"one":"other"}}}}function Pb(b){b=b.split("/");for(var a=b.length;a--;)b[a]=lb(b[a]);return b.join("/")}function wc(b,a,c){b=wa(b,c);a.$$protocol= b.protocol;a.$$host=b.hostname;a.$$port=U(b.port)||Ae[b.protocol]||null}function xc(b,a,c){var d="/"!==b.charAt(0);d&&(b="/"+b);b=wa(b,c);a.$$path=decodeURIComponent(d&&"/"===b.pathname.charAt(0)?b.pathname.substring(1):b.pathname);a.$$search=bc(b.search);a.$$hash=decodeURIComponent(b.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function sa(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function Fa(b){var a=b.indexOf("#");return-1==a?b:b.substr(0,a)}function yc(b){return b.replace(/(#.+)|#$/, "$1")}function Qb(b){return b.substr(0,Fa(b).lastIndexOf("/")+1)}function zc(b,a){this.$$html5=!0;a=a||"";var c=Qb(b);wc(b,this,b);this.$$parse=function(a){var e=sa(c,a);if(!E(e))throw Rb("ipthprfx",a,c);xc(e,this,b);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=Bb(this.$$search),b=this.$$hash?"#"+lb(this.$$hash):"";this.$$url=Pb(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$parseLinkUrl=function(d,e){var f,g;(f=sa(b,d))!==v?(g=f,g=(f= sa(a,f))!==v?c+(sa("/",f)||f):b+g):(f=sa(c,d))!==v?g=c+f:c==d+"/"&&(g=c);g&&this.$$parse(g);return!!g}}function Sb(b,a){var c=Qb(b);wc(b,this,b);this.$$parse=function(d){var e=sa(b,d)||sa(c,d),e="#"==e.charAt(0)?sa(a,e):this.$$html5?e:"";if(!E(e))throw Rb("ihshprfx",d,a);xc(e,this,b);d=this.$$path;var f=/^\/[A-Z]:(\/.*)/;0===e.indexOf(b)&&(e=e.replace(b,""));f.exec(e)||(d=(e=f.exec(d))?e[1]:d);this.$$path=d;this.$$compose()};this.$$compose=function(){var c=Bb(this.$$search),e=this.$$hash?"#"+lb(this.$$hash): "";this.$$url=Pb(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+(this.$$url?a+this.$$url:"")};this.$$parseLinkUrl=function(a,c){return Fa(b)==Fa(a)?(this.$$parse(a),!0):!1}}function Ac(b,a){this.$$html5=!0;Sb.apply(this,arguments);var c=Qb(b);this.$$parseLinkUrl=function(d,e){var f,g;b==Fa(d)?f=d:(g=sa(c,d))?f=b+a+g:c===d+"/"&&(f=c);f&&this.$$parse(f);return!!f};this.$$compose=function(){var c=Bb(this.$$search),e=this.$$hash?"#"+lb(this.$$hash):"";this.$$url=Pb(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl= b+a+this.$$url}}function sb(b){return function(){return this[b]}}function Bc(b,a){return function(c){if(H(c))return this[b];this[b]=a(c);this.$$compose();return this}}function Wd(){var b="",a=!1;this.hashPrefix=function(a){return G(a)?(b=a,this):b};this.html5Mode=function(b){return G(b)?(a=b,this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,f){function g(a){c.$broadcast("$locationChangeSuccess",h.absUrl(),a)}var h,k=d.baseHref(),l=d.url();a?(k=l.substring(0,l.indexOf("/", l.indexOf("//")+2))+(k||"/"),e=e.history?zc:Ac):(k=Fa(l),e=Sb);h=new e(k,"#"+b);h.$$parseLinkUrl(l,l);var m=/^\s*(javascript|mailto):/i;f.on("click",function(a){if(!a.ctrlKey&&!a.metaKey&&2!=a.which){for(var b=D(a.target);"a"!==A(b[0].nodeName);)if(b[0]===f[0]||!(b=b.parent())[0])return;var e=b.prop("href"),g=b.attr("href")||b.attr("xlink:href");T(e)&&"[object SVGAnimatedString]"===e.toString()&&(e=wa(e.animVal).href);m.test(e)||(!e||(b.attr("target")||a.isDefaultPrevented())||!h.$$parseLinkUrl(e, g))||(a.preventDefault(),h.absUrl()!=d.url()&&(c.$apply(),V.angular["ff-684208-preventDefault"]=!0))}});h.absUrl()!=l&&d.url(h.absUrl(),!0);d.onUrlChange(function(a){h.absUrl()!=a&&(c.$evalAsync(function(){var b=h.absUrl();h.$$parse(a);c.$broadcast("$locationChangeStart",a,b).defaultPrevented?(h.$$parse(b),d.url(b)):g(b)}),c.$$phase||c.$digest())});var n=0;c.$watch(function(){var a=yc(d.url()),b=yc(h.absUrl()),e=h.$$replace;n&&a==b||(n++,c.$evalAsync(function(){c.$broadcast("$locationChangeStart", h.absUrl(),a).defaultPrevented?h.$$parse(a):(d.url(h.absUrl(),e),g(a))}));h.$$replace=!1;return n});return h}]}function Xd(){var b=!0,a=this;this.debugEnabled=function(a){return G(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=c.console||{},e=b[a]||b.log||B;a=!1;try{a=!!e.apply}catch(k){}return a? function(){var a=[];r(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function la(b,a){if("__defineGetter__"===b||"__defineSetter__"===b||"__lookupGetter__"===b||"__lookupSetter__"===b||"__proto__"===b)throw ea("isecfld",a);return b}function Cc(b,a){b+="";if(!E(b))throw ea("iseccst",a);return b}function ma(b, a){if(b){if(b.constructor===b)throw ea("isecfn",a);if(b.document&&b.location&&b.alert&&b.setInterval)throw ea("isecwindow",a);if(b.children&&(b.nodeName||b.prop&&b.attr&&b.find))throw ea("isecdom",a);if(b===Object)throw ea("isecobj",a);}return b}function tb(b,a,c,d,e){ma(b,d);e=e||{};a=a.split(".");for(var f,g=0;1g?Dc(f[0],f[1],f[2],f[3],f[4],c,a):function(b,d){var e=0,h;do h= Dc(f[e++],f[e++],f[e++],f[e++],f[e++],c,a)(b,d),d=v,b=h;while(ea||37<=a&&40>=a)||p()});if(e.hasEvent("paste"))a.on("paste cut",p)}a.on("change",n);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)?"":d.$viewValue)};var s=c.ngPattern;s&&((e=s.match(/^\/(.*)\/([gim]*)$/))?(s=RegExp(e[1],e[2]),e=function(a){return ta(d,"pattern",d.$isEmpty(a)||s.test(a),a)}):e=function(c){var e=b.$eval(s);if(!e||!e.test)throw z("ngPattern")("noregexp",s, e,ia(a));return ta(d,"pattern",d.$isEmpty(c)||e.test(c),c)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var r=U(c.ngMinlength);e=function(a){return ta(d,"minlength",d.$isEmpty(a)||a.length>=r,a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){var w=U(c.ngMaxlength);e=function(a){return ta(d,"maxlength",d.$isEmpty(a)||a.length<=w,a)};d.$parsers.push(e);d.$formatters.push(e)}}function Vb(b,a){b="ngClass"+b;return["$animate",function(c){function d(a,b){var c=[],d=0;a:for(;d< a.length;d++){for(var e=a[d],m=0;mu?function(b){b=b.nodeName?b:b[0];return b.scopeName&&"HTML"!=b.scopeName?Ja(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?b.nodeName:b[0].nodeName};var Ya=function(){if(G(Ya.isActive_))return Ya.isActive_;var b=!(!W.querySelector("[ng-csp]")&&!W.querySelector("[data-ng-csp]"));if(!b)try{new Function("")}catch(a){b=!0}return Ya.isActive_=b},Yc=/[A-Z]/g,ad={full:"1.2.32",major:1,minor:2, dot:32,codeName:"alternation-intention"};S.expando="ng339";var bb=S.cache={},ne=1,rb=V.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},ab=V.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)};S._data=function(b){return this.cache[b[this.expando]]||{}};var ie=/([\:\-\_]+(.))/g,je=/^moz([A-Z])/,Gb=z("jqLite"),ke=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Hb=/<|&#?\w+;/,le=/<([\w:]+)/,me= /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ca={option:[1,'"],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ca.optgroup=ca.option;ca.tbody=ca.tfoot=ca.colgroup=ca.caption=ca.thead;ca.th=ca.td;var Ma=S.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===W.readyState? setTimeout(a):(this.on("DOMContentLoaded",a),S(V).on("load",a))},toString:function(){var b=[];r(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return 0<=b?D(this[b]):D(this[this.length+b])},length:0,push:Qe,sort:[].sort,splice:[].splice},qb={};r("multiple selected checked disabled readOnly required open".split(" "),function(b){qb[A(b)]=b});var oc={};r("input select option textarea button form details".split(" "),function(b){oc[Ja(b)]=!0});r({data:Lb,removeData:Kb},function(b, a){S[a]=b});r({data:Lb,inheritedData:pb,scope:function(b){return D.data(b,"$scope")||pb(b.parentNode||b,["$isolateScope","$scope"])},isolateScope:function(b){return D.data(b,"$isolateScope")||D.data(b,"$isolateScopeNoTemplate")},controller:lc,injector:function(b){return pb(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Mb,css:function(b,a,c){a=$a(a);if(G(c))b.style[a]=c;else{var d;8>=u&&(d=b.currentStyle&&b.currentStyle[a],""===d&&(d="auto"));d=d||b.style[a];8>=u&&(d=""=== d?v:d);return d}},attr:function(b,a,c){var d=A(a);if(qb[d])if(G(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||B).specified?d:v;else if(G(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),null===b?v:b},prop:function(b,a,c){if(G(c))b[a]=c;else return b[a]},text:function(){function b(b,d){var e=a[b.nodeType];if(H(d))return e?b[e]:"";b[e]=d}var a=[];9>u?(a[1]="innerText",a[3]="nodeValue"):a[1]=a[3]="textContent"; b.$dv="";return b}(),val:function(b,a){if(H(a)){if("SELECT"===Na(b)&&b.multiple){var c=[];r(b.options,function(a){a.selected&&c.push(a.value||a.text)});return 0===c.length?null:c}return b.value}b.value=a},html:function(b,a){if(H(a))return b.innerHTML;for(var c=0,d=b.childNodes;c":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Ve={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'}, Tb=function(a){this.options=a};Tb.prototype={constructor:Tb,lex:function(a){this.text=a;this.index=0;this.ch=v;this.lastCh=":";for(this.tokens=[];this.index=a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,c,d){d=d||this.index;c=G(c)?"s "+c+"-"+this.index+" ["+this.text.substring(c,d)+"]":" "+d;throw ea("lexerr", a,c,this.text);},readNumber:function(){for(var a="",c=this.index;this.index","<=",">="))a=this.binaryFn(a,c.fn,this.relational());return a},additive:function(){for(var a=this.multiplicative(),c;c=this.expect("+","-");)a=this.binaryFn(a,c.fn,this.multiplicative());return a},multiplicative:function(){for(var a=this.unary(),c;c=this.expect("*","/","%");)a=this.binaryFn(a,c.fn,this.unary());return a},unary:function(){var a;return this.expect("+")?this.primary():(a=this.expect("-"))?this.binaryFn(fb.ZERO,a.fn,this.unary()):(a=this.expect("!"))?this.unaryFn(a.fn,this.unary()): this.primary()},fieldAccess:function(a){var c=this,d=this.expect().text,e=Ec(d,this.options,this.text);return F(function(c,d,h){return e(h||a(c,d))},{assign:function(e,g,h){(h=a(e,h))||a.assign(e,h={});return tb(h,d,g,c.text,c.options)}})},objectIndex:function(a){var c=this,d=this.expression();this.consume("]");return F(function(e,f){var g=a(e,f),h=Cc(d(e,f),c.text),k;la(h,c.text);if(!g)return v;(g=ma(g[h],c.text))&&(g.then&&c.options.unwrapPromises)&&(k=g,"$$v"in g||(k.$$v=v,k.then(function(a){k.$$v= a})),g=g.$$v);return g},{assign:function(e,f,g){var h=la(Cc(d(e,g),c.text),c.text);(g=ma(a(e,g),c.text))||a.assign(e,g={});return g[h]=f}})},functionCall:function(a,c){var d=[];if(")"!==this.peekToken().text){do d.push(this.expression());while(this.expect(","))}this.consume(")");var e=this;return function(f,g){for(var h=[],k=c?c(f,g):f,l=0;la.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=-1*a.getTimezoneOffset();return a=(0<=a?"+":"")+(Ub(Math[0=u&&(c.href||c.name||c.$set("href",""),a.append(W.createComment("IE fix")));if(!c.href&&!c.xlinkHref&&!c.name)return function(a,c){var f="[object SVGAnimatedString]"===Aa.call(c.prop("href"))?"xlink:href":"href";c.on("click",function(a){c.attr(f)|| a.preventDefault()})}}}),Eb={};r(qb,function(a,c){if("multiple"!=a){var d=qa("ng-"+c);Eb[d]=function(){return{priority:100,link:function(a,f,g){a.$watch(g[d],function(a){g.$set(c,!!a)})}}}}});r(["src","srcset","href"],function(a){var c=qa("ng-"+a);Eb[c]=function(){return{priority:99,link:function(d,e,f){var g=a,h=a;"href"===a&&"[object SVGAnimatedString]"===Aa.call(e.prop("href"))&&(h="xlinkHref",f.$attr[h]="xlink:href",g=null);f.$observe(c,function(c){c?(f.$set(h,c),u&&g&&e.prop(g,f[h])):"href"=== a&&f.$set(h,null)})}}}});var xb={$addControl:B,$removeControl:B,$setValidity:B,$setDirty:B,$setPristine:B};Oc.$inject=["$element","$attrs","$scope","$animate"];var Rc=function(a){return["$timeout",function(c){return{name:"form",restrict:a?"EAC":"E",controller:Oc,compile:function(){return{pre:function(a,e,f,g){if(!f.action){var h=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1};rb(e[0],"submit",h);e.on("$destroy",function(){c(function(){ab(e[0],"submit",h)},0,!1)})}var k=e.parent().controller("form"), l=f.name||f.ngForm;l&&tb(a,l,g,l);if(k)e.on("$destroy",function(){k.$removeControl(g);l&&tb(a,l,v,l);F(g,xb)})}}}}}]},ed=Rc(),rd=Rc(!0),We=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,Xe=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,Ye=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,Sc={text:zb,number:function(a,c,d,e,f,g){zb(a,c,d,e,f,g);e.$parsers.push(function(a){var c=e.$isEmpty(a);if(c||Ye.test(a))return e.$setValidity("number", !0),""===a?null:c?a:parseFloat(a);e.$setValidity("number",!1);return v});Oe(e,"number",Ze,null,e.$$validityState);e.$formatters.push(function(a){return e.$isEmpty(a)?"":""+a});d.min&&(a=function(a){var c=parseFloat(d.min);return ta(e,"min",e.$isEmpty(a)||a>=c,a)},e.$parsers.push(a),e.$formatters.push(a));d.max&&(a=function(a){var c=parseFloat(d.max);return ta(e,"max",e.$isEmpty(a)||a<=c,a)},e.$parsers.push(a),e.$formatters.push(a));e.$formatters.push(function(a){return ta(e,"number",e.$isEmpty(a)|| ib(a),a)})},url:function(a,c,d,e,f,g){zb(a,c,d,e,f,g);a=function(a){return ta(e,"url",e.$isEmpty(a)||We.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,f,g){zb(a,c,d,e,f,g);a=function(a){return ta(e,"email",e.$isEmpty(a)||Xe.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){H(d.name)&&c.attr("name",hb());c.on("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue}; d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var f=d.ngTrueValue,g=d.ngFalseValue;E(f)||(f=!0);E(g)||(g=!1);c.on("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});e.$render=function(){c[0].checked=e.$viewValue};e.$isEmpty=function(a){return a!==f};e.$formatters.push(function(a){return a===f});e.$parsers.push(function(a){return a?f:g})},hidden:B,button:B,submit:B,reset:B,file:B},Ze=["badInput"],gc=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel", link:function(d,e,f,g){g&&(Sc[A(f.type)]||Sc.text)(d,e,f,g,c,a)}}}],vb="ng-valid",wb="ng-invalid",Qa="ng-pristine",yb="ng-dirty",$e=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate",function(a,c,d,e,f,g){function h(a,c){c=c?"-"+mb(c,"-"):"";g.removeClass(e,(a?wb:vb)+c);g.addClass(e,(a?vb:wb)+c)}this.$modelValue=this.$viewValue=Number.NaN;this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name= d.name;var k=f(d.ngModel),l=k.assign;if(!l)throw z("ngModel")("nonassign",d.ngModel,ia(e));this.$render=B;this.$isEmpty=function(a){return H(a)||""===a||null===a||a!==a};var m=e.inheritedData("$formController")||xb,n=0,q=this.$error={};e.addClass(Qa);h(!0);this.$setValidity=function(a,c){q[a]!==!c&&(c?(q[a]&&n--,n||(h(!0),this.$valid=!0,this.$invalid=!1)):(h(!1),this.$invalid=!0,this.$valid=!1,n++),q[a]=!c,h(c,a),m.$setValidity(a,c,this))};this.$setPristine=function(){this.$dirty=!1;this.$pristine= !0;g.removeClass(e,yb);g.addClass(e,Qa)};this.$setViewValue=function(d){this.$viewValue=d;this.$pristine&&(this.$dirty=!0,this.$pristine=!1,g.removeClass(e,Qa),g.addClass(e,yb),m.$setDirty());r(this.$parsers,function(a){d=a(d)});this.$modelValue!==d&&(this.$modelValue=d,l(a,d),r(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}}))};var p=this;a.$watch(function(){var c=k(a);if(p.$modelValue!==c){var d=p.$formatters,e=d.length;for(p.$modelValue=c;e--;)c=d[e](c);p.$viewValue!==c&&(p.$viewValue= c,p.$render())}return c})}],Gd=function(){return{require:["ngModel","^?form"],controller:$e,link:function(a,c,d,e){var f=e[0],g=e[1]||xb;g.$addControl(f);a.$on("$destroy",function(){g.$removeControl(f)})}}},Id=Z({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),hc=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var f=function(a){if(d.required&&e.$isEmpty(a))e.$setValidity("required",!1);else return e.$setValidity("required", !0),a};e.$formatters.push(f);e.$parsers.unshift(f);d.$observe("required",function(){f(e.$viewValue)})}}}},Hd=function(){return{require:"ngModel",link:function(a,c,d,e){var f=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){if(!H(a)){var c=[];a&&r(a.split(f),function(a){a&&c.push($(a))});return c}});e.$formatters.push(function(a){return M(a)?a.join(", "):v});e.$isEmpty=function(a){return!a||!a.length}}}},af=/^(true|false|\d+)$/,Jd=function(){return{priority:100, compile:function(a,c){return af.test(c.ngValue)?function(a,c,f){f.$set("value",a.$eval(f.ngValue))}:function(a,c,f){a.$watch(f.ngValue,function(a){f.$set("value",a)})}}}},jd=za({compile:function(a){a.addClass("ng-binding");return function(a,d,e){d.data("$binding",e.ngBind);a.$watch(e.ngBind,function(a){d.text(a==v?"":a)})}}}),ld=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}], kd=["$sce","$parse",function(a,c){return{compile:function(d){d.addClass("ng-binding");return function(d,f,g){f.data("$binding",g.ngBindHtml);var h=c(g.ngBindHtml);d.$watch(function(){return(h(d)||"").toString()},function(c){f.html(a.getTrustedHtml(h(d))||"")})}}}}],md=Vb("",!0),od=Vb("Odd",0),nd=Vb("Even",1),pd=za({compile:function(a,c){c.$set("ngCloak",v);a.removeClass("ng-cloak")}}),qd=[function(){return{scope:!0,controller:"@",priority:500}}],ic={},bf={blur:!0,focus:!0};r("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "), function(a){var c=qa("ng-"+a);ic[c]=["$parse","$rootScope",function(d,e){return{compile:function(f,g){var h=d(g[c],!0);return function(c,d){d.on(a,function(d){var f=function(){h(c,{$event:d})};bf[a]&&e.$$phase?c.$evalAsync(f):c.$apply(f)})}}}}]});var td=["$animate",function(a){return{transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(c,d,e,f,g){var h,k,l;c.$watch(e.ngIf,function(f){Va(f)?k||(k=c.$new(),g(k,function(c){c[c.length++]=W.createComment(" end ngIf: "+e.ngIf+ " ");h={clone:c};a.enter(c,d.parent(),d)})):(l&&(l.remove(),l=null),k&&(k.$destroy(),k=null),h&&(l=Db(h.clone),a.leave(l,function(){l=null}),h=null))})}}}],ud=["$http","$templateCache","$anchorScroll","$animate","$sce",function(a,c,d,e,f){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:Wa.noop,compile:function(g,h){var k=h.ngInclude||h.src,l=h.onload||"",m=h.autoscroll;return function(g,h,p,r,K){var w=0,t,x,u,y=function(){x&&(x.remove(),x=null);t&&(t.$destroy(),t=null); u&&(e.leave(u,function(){x=null}),x=u,u=null)};g.$watch(f.parseAsResourceUrl(k),function(f){var k=function(){!G(m)||m&&!g.$eval(m)||d()},p=++w;f?(a.get(f,{cache:c}).success(function(a){if(p===w){var c=g.$new();r.template=a;a=K(c,function(a){y();e.enter(a,null,h,k)});t=c;u=a;t.$emit("$includeContentLoaded");g.$eval(l)}}).error(function(){p===w&&y()}),g.$emit("$includeContentRequested")):(y(),r.template=null)})}}}}],Kd=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude", link:function(c,d,e,f){d.html(f.template);a(d.contents())(c)}}}],vd=za({priority:450,compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),wd=za({terminal:!0,priority:1E3}),xd=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,f,g){var h=g.count,k=g.$attr.when&&f.attr(g.$attr.when),l=g.offset||0,m=e.$eval(k)||{},n={},q=c.startSymbol(),p=c.endSymbol(),s=/^when(Minus)?(.+)$/;r(g,function(a,c){s.test(c)&&(m[A(c.replace("when","").replace("Minus","-"))]= f.attr(g.$attr[c]))});r(m,function(a,e){n[e]=c(a.replace(d,q+h+"-"+l+p))});e.$watch(function(){var c=parseFloat(e.$eval(h));if(isNaN(c))return"";c in m||(c=a.pluralCat(c-l));return n[c](e,f,!0)},function(a){f.text(a)})}}}],yd=["$parse","$animate",function(a,c){var d=z("ngRepeat");return{transclude:"element",priority:1E3,terminal:!0,$$tlb:!0,link:function(e,f,g,h,k){var l=g.ngRepeat,m=l.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),n,q,p,s,u,v,t={$id:La};if(!m)throw d("iexp", l);g=m[1];h=m[2];(m=m[3])?(n=a(m),q=function(a,c,d){v&&(t[v]=a);t[u]=c;t.$index=d;return n(e,t)}):(p=function(a,c){return La(c)},s=function(a){return a});m=g.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!m)throw d("iidexp",g);u=m[3]||m[1];v=m[2];var x={};e.$watchCollection(h,function(a){var g,h,m=f[0],n,t={},G,C,J,A,E,B,z,H=[];if(Ra(a))B=a,E=q||p;else{E=q||s;B=[];for(J in a)a.hasOwnProperty(J)&&"$"!=J.charAt(0)&&B.push(J);B.sort()}G=B.length;h=H.length=B.length;for(g=0;gC;)d=v.pop(),q.removeOption(d.label),d.element.remove()}for(;D.length>R;)D.pop()[0].element.remove()}var k;if(!(k=s.match(d)))throw cf("iexp",s,ia(f));var l=c(k[2]||k[1]), m=k[4]||k[6],n=k[5],r=c(k[3]||""),A=c(k[2]?k[1]:m),B=c(k[7]),y=k[8]?c(k[8]):null,D=[[{element:f,label:""}]];z&&(a(z)(e),z.removeClass("ng-scope"),z.remove());f.empty();f.on("change",function(){e.$apply(function(){var a,c=B(e)||[],d={},k,l,q,r,s,t,u;if(p)for(l=[],r=0,t=D.length;r@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}.ng-hide-add-active,.ng-hide-remove{display:block!important;}'); //# sourceMappingURL=angular.min.js.map // Source: public/lib/angular-resource/angular-resource.min.js /* AngularJS v1.2.32 (c) 2010-2014 Google, Inc. http://angularjs.org License: MIT */ (function(H,a,A){'use strict';function D(p,g){g=g||{};a.forEach(g,function(a,c){delete g[c]});for(var c in p)!p.hasOwnProperty(c)||"$"===c.charAt(0)&&"$"===c.charAt(1)||(g[c]=p[c]);return g}var v=a.$$minErr("$resource"),C=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;a.module("ngResource",["ng"]).factory("$resource",["$http","$q",function(p,g){function c(a,c){this.template=a;this.defaults=c||{};this.urlParams={}}function t(n,w,l){function r(h,d){var e={};d=x({},w,d);s(d,function(b,d){u(b)&&(b=b());var k;if(b&& b.charAt&&"@"==b.charAt(0)){k=h;var a=b.substr(1);if(null==a||""===a||"hasOwnProperty"===a||!C.test("."+a))throw v("badmember",a);for(var a=a.split("."),f=0,c=a.length;f', link: function(scope, element, attrs) { var domElement = element[0], canvas = element.find('canvas')[0], context = canvas2D ? canvas.getContext('2d') : null, trim = /^\s+|\s+$/g, error, version, errorCorrectionLevel, data, size, modules, tile, qr, setVersion = function(value) { version = Math.max(1, Math.min(parseInt(value, 10), 10)) || 4; }, setErrorCorrectionLevel = function(value) { errorCorrectionLevel = value in levels ? value : 'M'; }, setData = function(value) { if (!value) { return; } data = value.replace(trim, ''); qr = qrcode(version, errorCorrectionLevel); qr.addData(data); try { qr.make(); } catch(e) { error = e.message; return; } error = false; modules = qr.getModuleCount(); }, setSize = function(value) { size = parseInt(value, 10) || modules * 2; tile = size / modules; canvas.width = canvas.height = size; }, render = function() { if (!qr) { return; } if (error) { if (!canvas2D) { domElement.innerHTML = ''; } scope.$emit('qrcode:error', error); return; } if (canvas2D) { draw(context, qr, modules, tile); } else { domElement.innerHTML = qr.createImgTag(tile, 0); } }; setVersion(attrs.version); setErrorCorrectionLevel(attrs.errorCorrectionLevel); setSize(attrs.size); attrs.$observe('version', function(value) { if (!value) { return; } setVersion(value); setData(data); setSize(size); render(); }); attrs.$observe('errorCorrectionLevel', function(value) { if (!value) { return; } setErrorCorrectionLevel(value); setData(data); setSize(size); render(); }); attrs.$observe('data', function(value) { if (!value) { return; } setData(value); setSize(size); render(); }); attrs.$observe('size', function(value) { if (!value) { return; } setSize(value); render(); }); } }; }]); // Source: public/lib/angular-animate/angular-animate.min.js /* AngularJS v1.2.32 (c) 2010-2014 Google, Inc. http://angularjs.org License: MIT */ (function(G,d,P){'use strict';d.module("ngAnimate",["ng"]).directive("ngAnimateChildren",function(){return function(H,k,e){e=e.ngAnimateChildren;d.isString(e)&&0===e.length?k.data("$$ngAnimateChildren",!0):H.$watch(e,function(d){k.data("$$ngAnimateChildren",!!d)})}}).factory("$$animateReflow",["$$rAF","$document",function(d,k){var e=k[0].body;return function(k){return d(function(){k(e.offsetWidth)})}}]).config(["$provide","$animateProvider",function(H,k){function e(d){for(var e=0;e=y&&b>=r&&d()}var k=e(b);a=b.data(v);if(-1!=k.getAttribute("class").indexOf(c)&&a){var l="";x(c.split(" "),function(a,b){l+=(0 // Heading containing HTML - // .directive('accordionHeading', function() { return { restrict: 'EA', transclude: true, // Grab the contents to be used as the heading template: '', // In effect remove this element! replace: true, require: '^accordionGroup', compile: function(element, attr, transclude) { return function link(scope, element, attr, accordionGroupCtrl) { // Pass the heading to the accordion-group controller // so that it can be transcluded into the right place in the template // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat] accordionGroupCtrl.setHeading(transclude(scope, function() {})); }; } }; }) // Use in the accordion-group template to indicate where you want the heading to be transcluded // You must provide the property on the accordion-group controller that will hold the transcluded element //
// // ... //
.directive('accordionTransclude', function() { return { require: '^accordionGroup', link: function(scope, element, attr, controller) { scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) { if ( heading ) { element.html(''); element.append(heading); } }); } }; }); angular.module("ui.bootstrap.alert", []) .controller('AlertController', ['$scope', '$attrs', function ($scope, $attrs) { $scope.closeable = 'close' in $attrs; }]) .directive('alert', function () { return { restrict:'EA', controller:'AlertController', templateUrl:'template/alert/alert.html', transclude:true, replace:true, scope: { type: '=', close: '&' } }; }); angular.module('ui.bootstrap.bindHtml', []) .directive('bindHtmlUnsafe', function () { return function (scope, element, attr) { element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe); scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) { element.html(value || ''); }); }; }); angular.module('ui.bootstrap.buttons', []) .constant('buttonConfig', { activeClass: 'active', toggleEvent: 'click' }) .controller('ButtonsController', ['buttonConfig', function(buttonConfig) { this.activeClass = buttonConfig.activeClass || 'active'; this.toggleEvent = buttonConfig.toggleEvent || 'click'; }]) .directive('btnRadio', function () { return { require: ['btnRadio', 'ngModel'], controller: 'ButtonsController', link: function (scope, element, attrs, ctrls) { var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; //model -> UI ngModelCtrl.$render = function () { element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.btnRadio))); }; //ui->model element.bind(buttonsCtrl.toggleEvent, function () { if (!element.hasClass(buttonsCtrl.activeClass)) { scope.$apply(function () { ngModelCtrl.$setViewValue(scope.$eval(attrs.btnRadio)); ngModelCtrl.$render(); }); } }); } }; }) .directive('btnCheckbox', function () { return { require: ['btnCheckbox', 'ngModel'], controller: 'ButtonsController', link: function (scope, element, attrs, ctrls) { var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; function getTrueValue() { return getCheckboxValue(attrs.btnCheckboxTrue, true); } function getFalseValue() { return getCheckboxValue(attrs.btnCheckboxFalse, false); } function getCheckboxValue(attributeValue, defaultValue) { var val = scope.$eval(attributeValue); return angular.isDefined(val) ? val : defaultValue; } //model -> UI ngModelCtrl.$render = function () { element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue())); }; //ui->model element.bind(buttonsCtrl.toggleEvent, function () { scope.$apply(function () { ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue()); ngModelCtrl.$render(); }); }); } }; }); /** * @ngdoc overview * @name ui.bootstrap.carousel * * @description * AngularJS version of an image carousel. * */ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition']) .controller('CarouselController', ['$scope', '$timeout', '$transition', '$q', function ($scope, $timeout, $transition, $q) { var self = this, slides = self.slides = [], currentIndex = -1, currentTimeout, isPlaying; self.currentSlide = null; var destroyed = false; /* direction: "prev" or "next" */ self.select = function(nextSlide, direction) { var nextIndex = slides.indexOf(nextSlide); //Decide direction if it's not given if (direction === undefined) { direction = nextIndex > currentIndex ? "next" : "prev"; } if (nextSlide && nextSlide !== self.currentSlide) { if ($scope.$currentTransition) { $scope.$currentTransition.cancel(); //Timeout so ng-class in template has time to fix classes for finished slide $timeout(goNext); } else { goNext(); } } function goNext() { // Scope has been destroyed, stop here. if (destroyed) { return; } //If we have a slide to transition from and we have a transition type and we're allowed, go if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) { //We shouldn't do class manip in here, but it's the same weird thing bootstrap does. need to fix sometime nextSlide.$element.addClass(direction); var reflow = nextSlide.$element[0].offsetWidth; //force reflow //Set all other slides to stop doing their stuff for the new transition angular.forEach(slides, function(slide) { angular.extend(slide, {direction: '', entering: false, leaving: false, active: false}); }); angular.extend(nextSlide, {direction: direction, active: true, entering: true}); angular.extend(self.currentSlide||{}, {direction: direction, leaving: true}); $scope.$currentTransition = $transition(nextSlide.$element, {}); //We have to create new pointers inside a closure since next & current will change (function(next,current) { $scope.$currentTransition.then( function(){ transitionDone(next, current); }, function(){ transitionDone(next, current); } ); }(nextSlide, self.currentSlide)); } else { transitionDone(nextSlide, self.currentSlide); } self.currentSlide = nextSlide; currentIndex = nextIndex; //every time you change slides, reset the timer restartTimer(); } function transitionDone(next, current) { angular.extend(next, {direction: '', active: true, leaving: false, entering: false}); angular.extend(current||{}, {direction: '', active: false, leaving: false, entering: false}); $scope.$currentTransition = null; } }; $scope.$on('$destroy', function () { destroyed = true; }); /* Allow outside people to call indexOf on slides array */ self.indexOfSlide = function(slide) { return slides.indexOf(slide); }; $scope.next = function() { var newIndex = (currentIndex + 1) % slides.length; //Prevent this user-triggered transition from occurring if there is already one in progress if (!$scope.$currentTransition) { return self.select(slides[newIndex], 'next'); } }; $scope.prev = function() { var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1; //Prevent this user-triggered transition from occurring if there is already one in progress if (!$scope.$currentTransition) { return self.select(slides[newIndex], 'prev'); } }; $scope.select = function(slide) { self.select(slide); }; $scope.isActive = function(slide) { return self.currentSlide === slide; }; $scope.slides = function() { return slides; }; $scope.$watch('interval', restartTimer); $scope.$on('$destroy', resetTimer); function restartTimer() { resetTimer(); var interval = +$scope.interval; if (!isNaN(interval) && interval>=0) { currentTimeout = $timeout(timerFn, interval); } } function resetTimer() { if (currentTimeout) { $timeout.cancel(currentTimeout); currentTimeout = null; } } function timerFn() { if (isPlaying) { $scope.next(); restartTimer(); } else { $scope.pause(); } } $scope.play = function() { if (!isPlaying) { isPlaying = true; restartTimer(); } }; $scope.pause = function() { if (!$scope.noPause) { isPlaying = false; resetTimer(); } }; self.addSlide = function(slide, element) { slide.$element = element; slides.push(slide); //if this is the first slide or the slide is set to active, select it if(slides.length === 1 || slide.active) { self.select(slides[slides.length-1]); if (slides.length == 1) { $scope.play(); } } else { slide.active = false; } }; self.removeSlide = function(slide) { //get the index of the slide inside the carousel var index = slides.indexOf(slide); slides.splice(index, 1); if (slides.length > 0 && slide.active) { if (index >= slides.length) { self.select(slides[index-1]); } else { self.select(slides[index]); } } else if (currentIndex > index) { currentIndex--; } }; }]) /** * @ngdoc directive * @name ui.bootstrap.carousel.directive:carousel * @restrict EA * * @description * Carousel is the outer container for a set of image 'slides' to showcase. * * @param {number=} interval The time, in milliseconds, that it will take the carousel to go to the next slide. * @param {boolean=} noTransition Whether to disable transitions on the carousel. * @param {boolean=} noPause Whether to disable pausing on the carousel (by default, the carousel interval pauses on hover). * * @example .carousel-indicators { top: auto; bottom: 15px; } */ .directive('carousel', [function() { return { restrict: 'EA', transclude: true, replace: true, controller: 'CarouselController', require: 'carousel', templateUrl: 'template/carousel/carousel.html', scope: { interval: '=', noTransition: '=', noPause: '=' } }; }]) /** * @ngdoc directive * @name ui.bootstrap.carousel.directive:slide * @restrict EA * * @description * Creates a slide inside a {@link ui.bootstrap.carousel.directive:carousel carousel}. Must be placed as a child of a carousel element. * * @param {boolean=} active Model binding, whether or not this slide is currently active. * * @example
  • {{$index}}: {{slide.text}}
Add Slide
Interval, in milliseconds:
Enter a negative number to stop the interval.
function CarouselDemoCtrl($scope) { $scope.myInterval = 5000; var slides = $scope.slides = []; $scope.addSlide = function() { var newWidth = 200 + ((slides.length + (25 * slides.length)) % 150); slides.push({ image: 'http://placekitten.com/' + newWidth + '/200', text: ['More','Extra','Lots of','Surplus'][slides.length % 4] + ' ' ['Cats', 'Kittys', 'Felines', 'Cutes'][slides.length % 4] }); }; for (var i=0; i<4; i++) $scope.addSlide(); } .carousel-indicators { top: auto; bottom: 15px; }
*/ .directive('slide', ['$parse', function($parse) { return { require: '^carousel', restrict: 'EA', transclude: true, replace: true, templateUrl: 'template/carousel/slide.html', scope: { }, link: function (scope, element, attrs, carouselCtrl) { //Set up optional 'active' = binding if (attrs.active) { var getActive = $parse(attrs.active); var setActive = getActive.assign; var lastValue = scope.active = getActive(scope.$parent); scope.$watch(function parentActiveWatch() { var parentActive = getActive(scope.$parent); if (parentActive !== scope.active) { // we are out of sync and need to copy if (parentActive !== lastValue) { // parent changed and it has precedence lastValue = scope.active = parentActive; } else { // if the parent can be assigned then do so setActive(scope.$parent, parentActive = lastValue = scope.active); } } return parentActive; }); } carouselCtrl.addSlide(scope, element); //when the scope is destroyed then remove the slide from the current slides array scope.$on('$destroy', function() { carouselCtrl.removeSlide(scope); }); scope.$watch('active', function(active) { if (active) { carouselCtrl.select(scope); } }); } }; }]); angular.module('ui.bootstrap.position', []) /** * A set of utility methods that can be use to retrieve position of DOM elements. * It is meant to be used where we need to absolute-position DOM elements in * relation to other, existing elements (this is the case for tooltips, popovers, * typeahead suggestions etc.). */ .factory('$position', ['$document', '$window', function ($document, $window) { function getStyle(el, cssprop) { if (el.currentStyle) { //IE return el.currentStyle[cssprop]; } else if ($window.getComputedStyle) { return $window.getComputedStyle(el)[cssprop]; } // finally try and get inline style return el.style[cssprop]; } /** * Checks if a given element is statically positioned * @param element - raw DOM element */ function isStaticPositioned(element) { return (getStyle(element, "position") || 'static' ) === 'static'; } /** * returns the closest, non-statically positioned parentOffset of a given element * @param element */ var parentOffsetEl = function (element) { var docDomEl = $document[0]; var offsetParent = element.offsetParent || docDomEl; while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) { offsetParent = offsetParent.offsetParent; } return offsetParent || docDomEl; }; return { /** * Provides read-only equivalent of jQuery's position function: * http://api.jquery.com/position/ */ position: function (element) { var elBCR = this.offset(element); var offsetParentBCR = { top: 0, left: 0 }; var offsetParentEl = parentOffsetEl(element[0]); if (offsetParentEl != $document[0]) { offsetParentBCR = this.offset(angular.element(offsetParentEl)); offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop; offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft; } var boundingClientRect = element[0].getBoundingClientRect(); return { width: boundingClientRect.width || element.prop('offsetWidth'), height: boundingClientRect.height || element.prop('offsetHeight'), top: elBCR.top - offsetParentBCR.top, left: elBCR.left - offsetParentBCR.left }; }, /** * Provides read-only equivalent of jQuery's offset function: * http://api.jquery.com/offset/ */ offset: function (element) { var boundingClientRect = element[0].getBoundingClientRect(); return { width: boundingClientRect.width || element.prop('offsetWidth'), height: boundingClientRect.height || element.prop('offsetHeight'), top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop), left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft) }; } }; }]); angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position']) .constant('datepickerConfig', { dayFormat: 'dd', monthFormat: 'MMMM', yearFormat: 'yyyy', dayHeaderFormat: 'EEE', dayTitleFormat: 'MMMM yyyy', monthTitleFormat: 'yyyy', showWeeks: true, startingDay: 0, yearRange: 20, minDate: null, maxDate: null }) .controller('DatepickerController', ['$scope', '$attrs', 'dateFilter', 'datepickerConfig', function($scope, $attrs, dateFilter, dtConfig) { var format = { day: getValue($attrs.dayFormat, dtConfig.dayFormat), month: getValue($attrs.monthFormat, dtConfig.monthFormat), year: getValue($attrs.yearFormat, dtConfig.yearFormat), dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat), dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat), monthTitle: getValue($attrs.monthTitleFormat, dtConfig.monthTitleFormat) }, startingDay = getValue($attrs.startingDay, dtConfig.startingDay), yearRange = getValue($attrs.yearRange, dtConfig.yearRange); this.minDate = dtConfig.minDate ? new Date(dtConfig.minDate) : null; this.maxDate = dtConfig.maxDate ? new Date(dtConfig.maxDate) : null; function getValue(value, defaultValue) { return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue; } function getDaysInMonth( year, month ) { return new Date(year, month, 0).getDate(); } function getDates(startDate, n) { var dates = new Array(n); var current = startDate, i = 0; while (i < n) { dates[i++] = new Date(current); current.setDate( current.getDate() + 1 ); } return dates; } function makeDate(date, format, isSelected, isSecondary) { return { date: date, label: dateFilter(date, format), selected: !!isSelected, secondary: !!isSecondary }; } this.modes = [ { name: 'day', getVisibleDates: function(date, selected) { var year = date.getFullYear(), month = date.getMonth(), firstDayOfMonth = new Date(year, month, 1); var difference = startingDay - firstDayOfMonth.getDay(), numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference, firstDate = new Date(firstDayOfMonth), numDates = 0; if ( numDisplayedFromPreviousMonth > 0 ) { firstDate.setDate( - numDisplayedFromPreviousMonth + 1 ); numDates += numDisplayedFromPreviousMonth; // Previous } numDates += getDaysInMonth(year, month + 1); // Current numDates += (7 - numDates % 7) % 7; // Next var days = getDates(firstDate, numDates), labels = new Array(7); for (var i = 0; i < numDates; i ++) { var dt = new Date(days[i]); days[i] = makeDate(dt, format.day, (selected && selected.getDate() === dt.getDate() && selected.getMonth() === dt.getMonth() && selected.getFullYear() === dt.getFullYear()), dt.getMonth() !== month); } for (var j = 0; j < 7; j++) { labels[j] = dateFilter(days[j].date, format.dayHeader); } return { objects: days, title: dateFilter(date, format.dayTitle), labels: labels }; }, compare: function(date1, date2) { return (new Date( date1.getFullYear(), date1.getMonth(), date1.getDate() ) - new Date( date2.getFullYear(), date2.getMonth(), date2.getDate() ) ); }, split: 7, step: { months: 1 } }, { name: 'month', getVisibleDates: function(date, selected) { var months = new Array(12), year = date.getFullYear(); for ( var i = 0; i < 12; i++ ) { var dt = new Date(year, i, 1); months[i] = makeDate(dt, format.month, (selected && selected.getMonth() === i && selected.getFullYear() === year)); } return { objects: months, title: dateFilter(date, format.monthTitle) }; }, compare: function(date1, date2) { return new Date( date1.getFullYear(), date1.getMonth() ) - new Date( date2.getFullYear(), date2.getMonth() ); }, split: 3, step: { years: 1 } }, { name: 'year', getVisibleDates: function(date, selected) { var years = new Array(yearRange), year = date.getFullYear(), startYear = parseInt((year - 1) / yearRange, 10) * yearRange + 1; for ( var i = 0; i < yearRange; i++ ) { var dt = new Date(startYear + i, 0, 1); years[i] = makeDate(dt, format.year, (selected && selected.getFullYear() === dt.getFullYear())); } return { objects: years, title: [years[0].label, years[yearRange - 1].label].join(' - ') }; }, compare: function(date1, date2) { return date1.getFullYear() - date2.getFullYear(); }, split: 5, step: { years: yearRange } } ]; this.isDisabled = function(date, mode) { var currentMode = this.modes[mode || 0]; return ((this.minDate && currentMode.compare(date, this.minDate) < 0) || (this.maxDate && currentMode.compare(date, this.maxDate) > 0) || ($scope.dateDisabled && $scope.dateDisabled({date: date, mode: currentMode.name}))); }; }]) .directive( 'datepicker', ['dateFilter', '$parse', 'datepickerConfig', '$log', function (dateFilter, $parse, datepickerConfig, $log) { return { restrict: 'EA', replace: true, templateUrl: 'template/datepicker/datepicker.html', scope: { dateDisabled: '&' }, require: ['datepicker', '?^ngModel'], controller: 'DatepickerController', link: function(scope, element, attrs, ctrls) { var datepickerCtrl = ctrls[0], ngModel = ctrls[1]; if (!ngModel) { return; // do nothing if no ng-model } // Configuration parameters var mode = 0, selected = new Date(), showWeeks = datepickerConfig.showWeeks; if (attrs.showWeeks) { scope.$parent.$watch($parse(attrs.showWeeks), function(value) { showWeeks = !! value; updateShowWeekNumbers(); }); } else { updateShowWeekNumbers(); } if (attrs.min) { scope.$parent.$watch($parse(attrs.min), function(value) { datepickerCtrl.minDate = value ? new Date(value) : null; refill(); }); } if (attrs.max) { scope.$parent.$watch($parse(attrs.max), function(value) { datepickerCtrl.maxDate = value ? new Date(value) : null; refill(); }); } function updateShowWeekNumbers() { scope.showWeekNumbers = mode === 0 && showWeeks; } // Split array into smaller arrays function split(arr, size) { var arrays = []; while (arr.length > 0) { arrays.push(arr.splice(0, size)); } return arrays; } function refill( updateSelected ) { var date = null, valid = true; if ( ngModel.$modelValue ) { date = new Date( ngModel.$modelValue ); if ( isNaN(date) ) { valid = false; $log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'); } else if ( updateSelected ) { selected = date; } } ngModel.$setValidity('date', valid); var currentMode = datepickerCtrl.modes[mode], data = currentMode.getVisibleDates(selected, date); angular.forEach(data.objects, function(obj) { obj.disabled = datepickerCtrl.isDisabled(obj.date, mode); }); ngModel.$setValidity('date-disabled', (!date || !datepickerCtrl.isDisabled(date))); scope.rows = split(data.objects, currentMode.split); scope.labels = data.labels || []; scope.title = data.title; } function setMode(value) { mode = value; updateShowWeekNumbers(); refill(); } ngModel.$render = function() { refill( true ); }; scope.select = function( date ) { if ( mode === 0 ) { var dt = ngModel.$modelValue ? new Date( ngModel.$modelValue ) : new Date(0, 0, 0, 0, 0, 0, 0); dt.setFullYear( date.getFullYear(), date.getMonth(), date.getDate() ); ngModel.$setViewValue( dt ); refill( true ); } else { selected = date; setMode( mode - 1 ); } }; scope.move = function(direction) { var step = datepickerCtrl.modes[mode].step; selected.setMonth( selected.getMonth() + direction * (step.months || 0) ); selected.setFullYear( selected.getFullYear() + direction * (step.years || 0) ); refill(); }; scope.toggleMode = function() { setMode( (mode + 1) % datepickerCtrl.modes.length ); }; scope.getWeekNumber = function(row) { return ( mode === 0 && scope.showWeekNumbers && row.length === 7 ) ? getISO8601WeekNumber(row[0].date) : null; }; function getISO8601WeekNumber(date) { var checkDate = new Date(date); checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday var time = checkDate.getTime(); checkDate.setMonth(0); // Compare with Jan 1 checkDate.setDate(1); return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; } } }; }]) .constant('datepickerPopupConfig', { dateFormat: 'yyyy-MM-dd', currentText: 'Today', toggleWeeksText: 'Weeks', clearText: 'Clear', closeText: 'Done', closeOnDateSelection: true, appendToBody: false, showButtonBar: true }) .directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', 'datepickerPopupConfig', 'datepickerConfig', function ($compile, $parse, $document, $position, dateFilter, datepickerPopupConfig, datepickerConfig) { return { restrict: 'EA', require: 'ngModel', link: function(originalScope, element, attrs, ngModel) { var scope = originalScope.$new(), // create a child scope so we are not polluting original one dateFormat, closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? originalScope.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection, appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? originalScope.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody; attrs.$observe('datepickerPopup', function(value) { dateFormat = value || datepickerPopupConfig.dateFormat; ngModel.$render(); }); scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? originalScope.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar; originalScope.$on('$destroy', function() { $popup.remove(); scope.$destroy(); }); attrs.$observe('currentText', function(text) { scope.currentText = angular.isDefined(text) ? text : datepickerPopupConfig.currentText; }); attrs.$observe('toggleWeeksText', function(text) { scope.toggleWeeksText = angular.isDefined(text) ? text : datepickerPopupConfig.toggleWeeksText; }); attrs.$observe('clearText', function(text) { scope.clearText = angular.isDefined(text) ? text : datepickerPopupConfig.clearText; }); attrs.$observe('closeText', function(text) { scope.closeText = angular.isDefined(text) ? text : datepickerPopupConfig.closeText; }); var getIsOpen, setIsOpen; if ( attrs.isOpen ) { getIsOpen = $parse(attrs.isOpen); setIsOpen = getIsOpen.assign; originalScope.$watch(getIsOpen, function updateOpen(value) { scope.isOpen = !! value; }); } scope.isOpen = getIsOpen ? getIsOpen(originalScope) : false; // Initial state function setOpen( value ) { if (setIsOpen) { setIsOpen(originalScope, !!value); } else { scope.isOpen = !!value; } } var documentClickBind = function(event) { if (scope.isOpen && event.target !== element[0]) { scope.$apply(function() { setOpen(false); }); } }; var elementFocusBind = function() { scope.$apply(function() { setOpen( true ); }); }; // popup element used to display calendar var popupEl = angular.element('
'); popupEl.attr({ 'ng-model': 'date', 'ng-change': 'dateSelection()' }); var datepickerEl = angular.element(popupEl.children()[0]), datepickerOptions = {}; if (attrs.datepickerOptions) { datepickerOptions = originalScope.$eval(attrs.datepickerOptions); datepickerEl.attr(angular.extend({}, datepickerOptions)); } // TODO: reverse from dateFilter string to Date object function parseDate(viewValue) { if (!viewValue) { ngModel.$setValidity('date', true); return null; } else if (angular.isDate(viewValue)) { ngModel.$setValidity('date', true); return viewValue; } else if (angular.isString(viewValue)) { var date = new Date(viewValue); if (isNaN(date)) { ngModel.$setValidity('date', false); return undefined; } else { ngModel.$setValidity('date', true); return date; } } else { ngModel.$setValidity('date', false); return undefined; } } ngModel.$parsers.unshift(parseDate); // Inner change scope.dateSelection = function(dt) { if (angular.isDefined(dt)) { scope.date = dt; } ngModel.$setViewValue(scope.date); ngModel.$render(); if (closeOnDateSelection) { setOpen( false ); } }; element.bind('input change keyup', function() { scope.$apply(function() { scope.date = ngModel.$modelValue; }); }); // Outter change ngModel.$render = function() { var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : ''; element.val(date); scope.date = ngModel.$modelValue; }; function addWatchableAttribute(attribute, scopeProperty, datepickerAttribute) { if (attribute) { originalScope.$watch($parse(attribute), function(value){ scope[scopeProperty] = value; }); datepickerEl.attr(datepickerAttribute || scopeProperty, scopeProperty); } } addWatchableAttribute(attrs.min, 'min'); addWatchableAttribute(attrs.max, 'max'); if (attrs.showWeeks) { addWatchableAttribute(attrs.showWeeks, 'showWeeks', 'show-weeks'); } else { scope.showWeeks = 'show-weeks' in datepickerOptions ? datepickerOptions['show-weeks'] : datepickerConfig.showWeeks; datepickerEl.attr('show-weeks', 'showWeeks'); } if (attrs.dateDisabled) { datepickerEl.attr('date-disabled', attrs.dateDisabled); } function updatePosition() { scope.position = appendToBody ? $position.offset(element) : $position.position(element); scope.position.top = scope.position.top + element.prop('offsetHeight'); } var documentBindingInitialized = false, elementFocusInitialized = false; scope.$watch('isOpen', function(value) { if (value) { updatePosition(); $document.bind('click', documentClickBind); if(elementFocusInitialized) { element.unbind('focus', elementFocusBind); } element[0].focus(); documentBindingInitialized = true; } else { if(documentBindingInitialized) { $document.unbind('click', documentClickBind); } element.bind('focus', elementFocusBind); elementFocusInitialized = true; } if ( setIsOpen ) { setIsOpen(originalScope, value); } }); scope.today = function() { scope.dateSelection(new Date()); }; scope.clear = function() { scope.dateSelection(null); }; var $popup = $compile(popupEl)(scope); if ( appendToBody ) { $document.find('body').append($popup); } else { element.after($popup); } } }; }]) .directive('datepickerPopupWrap', function() { return { restrict:'EA', replace: true, transclude: true, templateUrl: 'template/datepicker/popup.html', link:function (scope, element, attrs) { element.bind('click', function(event) { event.preventDefault(); event.stopPropagation(); }); } }; }); /* * dropdownToggle - Provides dropdown menu functionality in place of bootstrap js * @restrict class or attribute * @example: */ angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle', ['$document', '$location', function ($document, $location) { var openElement = null, closeMenu = angular.noop; return { restrict: 'CA', link: function(scope, element, attrs) { scope.$watch('$location.path', function() { closeMenu(); }); element.parent().bind('click', function() { closeMenu(); }); element.bind('click', function (event) { var elementWasOpen = (element === openElement); event.preventDefault(); event.stopPropagation(); if (!!openElement) { closeMenu(); } if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) { element.parent().addClass('open'); openElement = element; closeMenu = function (event) { if (event) { event.preventDefault(); event.stopPropagation(); } $document.unbind('click', closeMenu); element.parent().removeClass('open'); closeMenu = angular.noop; openElement = null; }; $document.bind('click', closeMenu); } }); } }; }]); angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition']) /** * A helper, internal data structure that acts as a map but also allows getting / removing * elements in the LIFO order */ .factory('$$stackedMap', function () { return { createNew: function () { var stack = []; return { add: function (key, value) { stack.push({ key: key, value: value }); }, get: function (key) { for (var i = 0; i < stack.length; i++) { if (key == stack[i].key) { return stack[i]; } } }, keys: function() { var keys = []; for (var i = 0; i < stack.length; i++) { keys.push(stack[i].key); } return keys; }, top: function () { return stack[stack.length - 1]; }, remove: function (key) { var idx = -1; for (var i = 0; i < stack.length; i++) { if (key == stack[i].key) { idx = i; break; } } return stack.splice(idx, 1)[0]; }, removeTop: function () { return stack.splice(stack.length - 1, 1)[0]; }, length: function () { return stack.length; } }; } }; }) /** * A helper directive for the $modal service. It creates a backdrop element. */ .directive('modalBackdrop', ['$timeout', function ($timeout) { return { restrict: 'EA', replace: true, templateUrl: 'template/modal/backdrop.html', link: function (scope) { scope.animate = false; //trigger CSS transitions $timeout(function () { scope.animate = true; }); } }; }]) .directive('modalWindow', ['$modalStack', '$timeout', function ($modalStack, $timeout) { return { restrict: 'EA', scope: { index: '@', animate: '=' }, replace: true, transclude: true, templateUrl: 'template/modal/window.html', link: function (scope, element, attrs) { scope.windowClass = attrs.windowClass || ''; $timeout(function () { // trigger CSS transitions scope.animate = true; // focus a freshly-opened modal element[0].focus(); }); scope.close = function (evt) { var modal = $modalStack.getTop(); if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) { evt.preventDefault(); evt.stopPropagation(); $modalStack.dismiss(modal.key, 'backdrop click'); } }; } }; }]) .factory('$modalStack', ['$transition', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap', function ($transition, $timeout, $document, $compile, $rootScope, $$stackedMap) { var OPENED_MODAL_CLASS = 'modal-open'; var backdropDomEl, backdropScope; var openedWindows = $$stackedMap.createNew(); var $modalStack = {}; function backdropIndex() { var topBackdropIndex = -1; var opened = openedWindows.keys(); for (var i = 0; i < opened.length; i++) { if (openedWindows.get(opened[i]).value.backdrop) { topBackdropIndex = i; } } return topBackdropIndex; } $rootScope.$watch(backdropIndex, function(newBackdropIndex){ if (backdropScope) { backdropScope.index = newBackdropIndex; } }); function removeModalWindow(modalInstance) { var body = $document.find('body').eq(0); var modalWindow = openedWindows.get(modalInstance).value; //clean up the stack openedWindows.remove(modalInstance); //remove window DOM element removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300, checkRemoveBackdrop); body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0); } function checkRemoveBackdrop() { //remove backdrop if no longer needed if (backdropDomEl && backdropIndex() == -1) { var backdropScopeRef = backdropScope; removeAfterAnimate(backdropDomEl, backdropScope, 150, function () { backdropScopeRef.$destroy(); backdropScopeRef = null; }); backdropDomEl = undefined; backdropScope = undefined; } } function removeAfterAnimate(domEl, scope, emulateTime, done) { // Closing animation scope.animate = false; var transitionEndEventName = $transition.transitionEndEventName; if (transitionEndEventName) { // transition out var timeout = $timeout(afterAnimating, emulateTime); domEl.bind(transitionEndEventName, function () { $timeout.cancel(timeout); afterAnimating(); scope.$apply(); }); } else { // Ensure this call is async $timeout(afterAnimating, 0); } function afterAnimating() { if (afterAnimating.done) { return; } afterAnimating.done = true; domEl.remove(); if (done) { done(); } } } $document.bind('keydown', function (evt) { var modal; if (evt.which === 27) { modal = openedWindows.top(); if (modal && modal.value.keyboard) { $rootScope.$apply(function () { $modalStack.dismiss(modal.key); }); } } }); $modalStack.open = function (modalInstance, modal) { openedWindows.add(modalInstance, { deferred: modal.deferred, modalScope: modal.scope, backdrop: modal.backdrop, keyboard: modal.keyboard }); var body = $document.find('body').eq(0), currBackdropIndex = backdropIndex(); if (currBackdropIndex >= 0 && !backdropDomEl) { backdropScope = $rootScope.$new(true); backdropScope.index = currBackdropIndex; backdropDomEl = $compile('
')(backdropScope); body.append(backdropDomEl); } var angularDomEl = angular.element('
'); angularDomEl.attr('window-class', modal.windowClass); angularDomEl.attr('index', openedWindows.length() - 1); angularDomEl.attr('animate', 'animate'); angularDomEl.html(modal.content); var modalDomEl = $compile(angularDomEl)(modal.scope); openedWindows.top().value.modalDomEl = modalDomEl; body.append(modalDomEl); body.addClass(OPENED_MODAL_CLASS); }; $modalStack.close = function (modalInstance, result) { var modalWindow = openedWindows.get(modalInstance).value; if (modalWindow) { modalWindow.deferred.resolve(result); removeModalWindow(modalInstance); } }; $modalStack.dismiss = function (modalInstance, reason) { var modalWindow = openedWindows.get(modalInstance).value; if (modalWindow) { modalWindow.deferred.reject(reason); removeModalWindow(modalInstance); } }; $modalStack.dismissAll = function (reason) { var topModal = this.getTop(); while (topModal) { this.dismiss(topModal.key, reason); topModal = this.getTop(); } }; $modalStack.getTop = function () { return openedWindows.top(); }; return $modalStack; }]) .provider('$modal', function () { var $modalProvider = { options: { backdrop: true, //can be also false or 'static' keyboard: true }, $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) { var $modal = {}; function getTemplatePromise(options) { return options.template ? $q.when(options.template) : $http.get(options.templateUrl, {cache: $templateCache}).then(function (result) { return result.data; }); } function getResolvePromises(resolves) { var promisesArr = []; angular.forEach(resolves, function (value, key) { if (angular.isFunction(value) || angular.isArray(value)) { promisesArr.push($q.when($injector.invoke(value))); } }); return promisesArr; } $modal.open = function (modalOptions) { var modalResultDeferred = $q.defer(); var modalOpenedDeferred = $q.defer(); //prepare an instance of a modal to be injected into controllers and returned to a caller var modalInstance = { result: modalResultDeferred.promise, opened: modalOpenedDeferred.promise, close: function (result) { $modalStack.close(modalInstance, result); }, dismiss: function (reason) { $modalStack.dismiss(modalInstance, reason); } }; //merge and clean up options modalOptions = angular.extend({}, $modalProvider.options, modalOptions); modalOptions.resolve = modalOptions.resolve || {}; //verify options if (!modalOptions.template && !modalOptions.templateUrl) { throw new Error('One of template or templateUrl options is required.'); } var templateAndResolvePromise = $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve))); templateAndResolvePromise.then(function resolveSuccess(tplAndVars) { var modalScope = (modalOptions.scope || $rootScope).$new(); modalScope.$close = modalInstance.close; modalScope.$dismiss = modalInstance.dismiss; var ctrlInstance, ctrlLocals = {}; var resolveIter = 1; //controllers if (modalOptions.controller) { ctrlLocals.$scope = modalScope; ctrlLocals.$modalInstance = modalInstance; angular.forEach(modalOptions.resolve, function (value, key) { ctrlLocals[key] = tplAndVars[resolveIter++]; }); ctrlInstance = $controller(modalOptions.controller, ctrlLocals); } $modalStack.open(modalInstance, { scope: modalScope, deferred: modalResultDeferred, content: tplAndVars[0], backdrop: modalOptions.backdrop, keyboard: modalOptions.keyboard, windowClass: modalOptions.windowClass }); }, function resolveError(reason) { modalResultDeferred.reject(reason); }); templateAndResolvePromise.then(function () { modalOpenedDeferred.resolve(true); }, function () { modalOpenedDeferred.reject(false); }); return modalInstance; }; return $modal; }] }; return $modalProvider; }); angular.module('ui.bootstrap.pagination', []) .controller('PaginationController', ['$scope', '$attrs', '$parse', '$interpolate', function ($scope, $attrs, $parse, $interpolate) { var self = this, setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop; this.init = function(defaultItemsPerPage) { if ($attrs.itemsPerPage) { $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) { self.itemsPerPage = parseInt(value, 10); $scope.totalPages = self.calculateTotalPages(); }); } else { this.itemsPerPage = defaultItemsPerPage; } }; this.noPrevious = function() { return this.page === 1; }; this.noNext = function() { return this.page === $scope.totalPages; }; this.isActive = function(page) { return this.page === page; }; this.calculateTotalPages = function() { var totalPages = this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage); return Math.max(totalPages || 0, 1); }; this.getAttributeValue = function(attribute, defaultValue, interpolate) { return angular.isDefined(attribute) ? (interpolate ? $interpolate(attribute)($scope.$parent) : $scope.$parent.$eval(attribute)) : defaultValue; }; this.render = function() { this.page = parseInt($scope.page, 10) || 1; if (this.page > 0 && this.page <= $scope.totalPages) { $scope.pages = this.getPages(this.page, $scope.totalPages); } }; $scope.selectPage = function(page) { if ( ! self.isActive(page) && page > 0 && page <= $scope.totalPages) { $scope.page = page; $scope.onSelectPage({ page: page }); } }; $scope.$watch('page', function() { self.render(); }); $scope.$watch('totalItems', function() { $scope.totalPages = self.calculateTotalPages(); }); $scope.$watch('totalPages', function(value) { setNumPages($scope.$parent, value); // Readonly variable if ( self.page > value ) { $scope.selectPage(value); } else { self.render(); } }); }]) .constant('paginationConfig', { itemsPerPage: 10, boundaryLinks: false, directionLinks: true, firstText: 'First', previousText: 'Previous', nextText: 'Next', lastText: 'Last', rotate: true }) .directive('pagination', ['$parse', 'paginationConfig', function($parse, config) { return { restrict: 'EA', scope: { page: '=', totalItems: '=', onSelectPage:' &' }, controller: 'PaginationController', templateUrl: 'template/pagination/pagination.html', replace: true, link: function(scope, element, attrs, paginationCtrl) { // Setup configuration parameters var maxSize, boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks, config.boundaryLinks ), directionLinks = paginationCtrl.getAttributeValue(attrs.directionLinks, config.directionLinks ), firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true), previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true), nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true), lastText = paginationCtrl.getAttributeValue(attrs.lastText, config.lastText, true), rotate = paginationCtrl.getAttributeValue(attrs.rotate, config.rotate); paginationCtrl.init(config.itemsPerPage); if (attrs.maxSize) { scope.$parent.$watch($parse(attrs.maxSize), function(value) { maxSize = parseInt(value, 10); paginationCtrl.render(); }); } // Create page object used in template function makePage(number, text, isActive, isDisabled) { return { number: number, text: text, active: isActive, disabled: isDisabled }; } paginationCtrl.getPages = function(currentPage, totalPages) { var pages = []; // Default page limits var startPage = 1, endPage = totalPages; var isMaxSized = ( angular.isDefined(maxSize) && maxSize < totalPages ); // recompute if maxSize if ( isMaxSized ) { if ( rotate ) { // Current page is displayed in the middle of the visible ones startPage = Math.max(currentPage - Math.floor(maxSize/2), 1); endPage = startPage + maxSize - 1; // Adjust if limit is exceeded if (endPage > totalPages) { endPage = totalPages; startPage = endPage - maxSize + 1; } } else { // Visible pages are paginated with maxSize startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1; // Adjust last page if limit is exceeded endPage = Math.min(startPage + maxSize - 1, totalPages); } } // Add page number links for (var number = startPage; number <= endPage; number++) { var page = makePage(number, number, paginationCtrl.isActive(number), false); pages.push(page); } // Add links to move between page sets if ( isMaxSized && ! rotate ) { if ( startPage > 1 ) { var previousPageSet = makePage(startPage - 1, '...', false, false); pages.unshift(previousPageSet); } if ( endPage < totalPages ) { var nextPageSet = makePage(endPage + 1, '...', false, false); pages.push(nextPageSet); } } // Add previous & next links if (directionLinks) { var previousPage = makePage(currentPage - 1, previousText, false, paginationCtrl.noPrevious()); pages.unshift(previousPage); var nextPage = makePage(currentPage + 1, nextText, false, paginationCtrl.noNext()); pages.push(nextPage); } // Add first & last links if (boundaryLinks) { var firstPage = makePage(1, firstText, false, paginationCtrl.noPrevious()); pages.unshift(firstPage); var lastPage = makePage(totalPages, lastText, false, paginationCtrl.noNext()); pages.push(lastPage); } return pages; }; } }; }]) .constant('pagerConfig', { itemsPerPage: 10, previousText: '« Previous', nextText: 'Next »', align: true }) .directive('pager', ['pagerConfig', function(config) { return { restrict: 'EA', scope: { page: '=', totalItems: '=', onSelectPage:' &' }, controller: 'PaginationController', templateUrl: 'template/pagination/pager.html', replace: true, link: function(scope, element, attrs, paginationCtrl) { // Setup configuration parameters var previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true), nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true), align = paginationCtrl.getAttributeValue(attrs.align, config.align); paginationCtrl.init(config.itemsPerPage); // Create page object used in template function makePage(number, text, isDisabled, isPrevious, isNext) { return { number: number, text: text, disabled: isDisabled, previous: ( align && isPrevious ), next: ( align && isNext ) }; } paginationCtrl.getPages = function(currentPage) { return [ makePage(currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false), makePage(currentPage + 1, nextText, paginationCtrl.noNext(), false, true) ]; }; } }; }]); /** * The following features are still outstanding: animation as a * function, placement as a function, inside, support for more triggers than * just mouse enter/leave, html tooltips, and selector delegation. */ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap.bindHtml' ] ) /** * The $tooltip service creates tooltip- and popover-like directives as well as * houses global options for them. */ .provider( '$tooltip', function () { // The default options tooltip and popover. var defaultOptions = { placement: 'top', animation: true, popupDelay: 0 }; // Default hide triggers for each show trigger var triggerMap = { 'mouseenter': 'mouseleave', 'click': 'click', 'focus': 'blur' }; // The options specified to the provider globally. var globalOptions = {}; /** * `options({})` allows global configuration of all tooltips in the * application. * * var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) { * // place tooltips left instead of top by default * $tooltipProvider.options( { placement: 'left' } ); * }); */ this.options = function( value ) { angular.extend( globalOptions, value ); }; /** * This allows you to extend the set of trigger mappings available. E.g.: * * $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' ); */ this.setTriggers = function setTriggers ( triggers ) { angular.extend( triggerMap, triggers ); }; /** * This is a helper function for translating camel-case to snake-case. */ function snake_case(name){ var regexp = /[A-Z]/g; var separator = '-'; return name.replace(regexp, function(letter, pos) { return (pos ? separator : '') + letter.toLowerCase(); }); } /** * Returns the actual instance of the $tooltip service. * TODO support multiple triggers */ this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function ( $window, $compile, $timeout, $parse, $document, $position, $interpolate ) { return function $tooltip ( type, prefix, defaultTriggerShow ) { var options = angular.extend( {}, defaultOptions, globalOptions ); /** * Returns an object of show and hide triggers. * * If a trigger is supplied, * it is used to show the tooltip; otherwise, it will use the `trigger` * option passed to the `$tooltipProvider.options` method; else it will * default to the trigger supplied to this directive factory. * * The hide trigger is based on the show trigger. If the `trigger` option * was passed to the `$tooltipProvider.options` method, it will use the * mapped trigger from `triggerMap` or the passed trigger if the map is * undefined; otherwise, it uses the `triggerMap` value of the show * trigger; else it will just use the show trigger. */ function getTriggers ( trigger ) { var show = trigger || options.trigger || defaultTriggerShow; var hide = triggerMap[show] || show; return { show: show, hide: hide }; } var directiveName = snake_case( type ); var startSym = $interpolate.startSymbol(); var endSym = $interpolate.endSymbol(); var template = '
'+ '
'; return { restrict: 'EA', scope: true, compile: function (tElem, tAttrs) { var tooltipLinker = $compile( template ); return function link ( scope, element, attrs ) { var tooltip; var transitionTimeout; var popupTimeout; var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false; var triggers = getTriggers( undefined ); var hasRegisteredTriggers = false; var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']); var positionTooltip = function (){ var position, ttWidth, ttHeight, ttPosition; // Get the position of the directive element. position = appendToBody ? $position.offset( element ) : $position.position( element ); // Get the height and width of the tooltip so we can center it. ttWidth = tooltip.prop( 'offsetWidth' ); ttHeight = tooltip.prop( 'offsetHeight' ); // Calculate the tooltip's top and left coordinates to center it with // this directive. switch ( scope.tt_placement ) { case 'right': ttPosition = { top: position.top + position.height / 2 - ttHeight / 2, left: position.left + position.width }; break; case 'bottom': ttPosition = { top: position.top + position.height, left: position.left + position.width / 2 - ttWidth / 2 }; break; case 'left': ttPosition = { top: position.top + position.height / 2 - ttHeight / 2, left: position.left - ttWidth }; break; default: ttPosition = { top: position.top - ttHeight, left: position.left + position.width / 2 - ttWidth / 2 }; break; } ttPosition.top += 'px'; ttPosition.left += 'px'; // Now set the calculated positioning. tooltip.css( ttPosition ); }; // By default, the tooltip is not open. // TODO add ability to start tooltip opened scope.tt_isOpen = false; function toggleTooltipBind () { if ( ! scope.tt_isOpen ) { showTooltipBind(); } else { hideTooltipBind(); } } // Show the tooltip with delay if specified, otherwise show it immediately function showTooltipBind() { if(hasEnableExp && !scope.$eval(attrs[prefix+'Enable'])) { return; } if ( scope.tt_popupDelay ) { popupTimeout = $timeout( show, scope.tt_popupDelay, false ); popupTimeout.then(function(reposition){reposition();}); } else { show()(); } } function hideTooltipBind () { scope.$apply(function () { hide(); }); } // Show the tooltip popup element. function show() { // Don't show empty tooltips. if ( ! scope.tt_content ) { return angular.noop; } createTooltip(); // If there is a pending remove transition, we must cancel it, lest the // tooltip be mysteriously removed. if ( transitionTimeout ) { $timeout.cancel( transitionTimeout ); } // Set the initial positioning. tooltip.css({ top: 0, left: 0, display: 'block' }); // Now we add it to the DOM because need some info about it. But it's not // visible yet anyway. if ( appendToBody ) { $document.find( 'body' ).append( tooltip ); } else { element.after( tooltip ); } positionTooltip(); // And show the tooltip. scope.tt_isOpen = true; scope.$digest(); // digest required as $apply is not called // Return positioning function as promise callback for correct // positioning after draw. return positionTooltip; } // Hide the tooltip popup element. function hide() { // First things first: we don't show it anymore. scope.tt_isOpen = false; //if tooltip is going to be shown after delay, we must cancel this $timeout.cancel( popupTimeout ); // And now we remove it from the DOM. However, if we have animation, we // need to wait for it to expire beforehand. // FIXME: this is a placeholder for a port of the transitions library. if ( scope.tt_animation ) { transitionTimeout = $timeout(removeTooltip, 500); } else { removeTooltip(); } } function createTooltip() { // There can only be one tooltip element per directive shown at once. if (tooltip) { removeTooltip(); } tooltip = tooltipLinker(scope, function () {}); // Get contents rendered into the tooltip scope.$digest(); } function removeTooltip() { if (tooltip) { tooltip.remove(); tooltip = null; } } /** * Observe the relevant attributes. */ attrs.$observe( type, function ( val ) { scope.tt_content = val; if (!val && scope.tt_isOpen ) { hide(); } }); attrs.$observe( prefix+'Title', function ( val ) { scope.tt_title = val; }); attrs.$observe( prefix+'Placement', function ( val ) { scope.tt_placement = angular.isDefined( val ) ? val : options.placement; }); attrs.$observe( prefix+'PopupDelay', function ( val ) { var delay = parseInt( val, 10 ); scope.tt_popupDelay = ! isNaN(delay) ? delay : options.popupDelay; }); var unregisterTriggers = function() { if (hasRegisteredTriggers) { element.unbind( triggers.show, showTooltipBind ); element.unbind( triggers.hide, hideTooltipBind ); } }; attrs.$observe( prefix+'Trigger', function ( val ) { unregisterTriggers(); triggers = getTriggers( val ); if ( triggers.show === triggers.hide ) { element.bind( triggers.show, toggleTooltipBind ); } else { element.bind( triggers.show, showTooltipBind ); element.bind( triggers.hide, hideTooltipBind ); } hasRegisteredTriggers = true; }); var animation = scope.$eval(attrs[prefix + 'Animation']); scope.tt_animation = angular.isDefined(animation) ? !!animation : options.animation; attrs.$observe( prefix+'AppendToBody', function ( val ) { appendToBody = angular.isDefined( val ) ? $parse( val )( scope ) : appendToBody; }); // if a tooltip is attached to we need to remove it on // location change as its parent scope will probably not be destroyed // by the change. if ( appendToBody ) { scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess () { if ( scope.tt_isOpen ) { hide(); } }); } // Make sure tooltip is destroyed and removed. scope.$on('$destroy', function onDestroyTooltip() { $timeout.cancel( transitionTimeout ); $timeout.cancel( popupTimeout ); unregisterTriggers(); removeTooltip(); }); }; } }; }; }]; }) .directive( 'tooltipPopup', function () { return { restrict: 'EA', replace: true, scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, templateUrl: 'template/tooltip/tooltip-popup.html' }; }) .directive( 'tooltip', [ '$tooltip', function ( $tooltip ) { return $tooltip( 'tooltip', 'tooltip', 'mouseenter' ); }]) .directive( 'tooltipHtmlUnsafePopup', function () { return { restrict: 'EA', replace: true, scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html' }; }) .directive( 'tooltipHtmlUnsafe', [ '$tooltip', function ( $tooltip ) { return $tooltip( 'tooltipHtmlUnsafe', 'tooltip', 'mouseenter' ); }]); /** * The following features are still outstanding: popup delay, animation as a * function, placement as a function, inside, support for more triggers than * just mouse enter/leave, html popovers, and selector delegatation. */ angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] ) .directive( 'popoverPopup', function () { return { restrict: 'EA', replace: true, scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' }, templateUrl: 'template/popover/popover.html' }; }) .directive( 'popover', [ '$tooltip', function ( $tooltip ) { return $tooltip( 'popover', 'popover', 'click' ); }]); angular.module('ui.bootstrap.progressbar', ['ui.bootstrap.transition']) .constant('progressConfig', { animate: true, max: 100 }) .controller('ProgressController', ['$scope', '$attrs', 'progressConfig', '$transition', function($scope, $attrs, progressConfig, $transition) { var self = this, bars = [], max = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : progressConfig.max, animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate; this.addBar = function(bar, element) { var oldValue = 0, index = bar.$parent.$index; if ( angular.isDefined(index) && bars[index] ) { oldValue = bars[index].value; } bars.push(bar); this.update(element, bar.value, oldValue); bar.$watch('value', function(value, oldValue) { if (value !== oldValue) { self.update(element, value, oldValue); } }); bar.$on('$destroy', function() { self.removeBar(bar); }); }; // Update bar element width this.update = function(element, newValue, oldValue) { var percent = this.getPercentage(newValue); if (animate) { element.css('width', this.getPercentage(oldValue) + '%'); $transition(element, {width: percent + '%'}); } else { element.css({'transition': 'none', 'width': percent + '%'}); } }; this.removeBar = function(bar) { bars.splice(bars.indexOf(bar), 1); }; this.getPercentage = function(value) { return Math.round(100 * value / max); }; }]) .directive('progress', function() { return { restrict: 'EA', replace: true, transclude: true, controller: 'ProgressController', require: 'progress', scope: {}, template: '
' //templateUrl: 'template/progressbar/progress.html' // Works in AngularJS 1.2 }; }) .directive('bar', function() { return { restrict: 'EA', replace: true, transclude: true, require: '^progress', scope: { value: '=', type: '@' }, templateUrl: 'template/progressbar/bar.html', link: function(scope, element, attrs, progressCtrl) { progressCtrl.addBar(scope, element); } }; }) .directive('progressbar', function() { return { restrict: 'EA', replace: true, transclude: true, controller: 'ProgressController', scope: { value: '=', type: '@' }, templateUrl: 'template/progressbar/progressbar.html', link: function(scope, element, attrs, progressCtrl) { progressCtrl.addBar(scope, angular.element(element.children()[0])); } }; }); angular.module('ui.bootstrap.rating', []) .constant('ratingConfig', { max: 5, stateOn: null, stateOff: null }) .controller('RatingController', ['$scope', '$attrs', '$parse', 'ratingConfig', function($scope, $attrs, $parse, ratingConfig) { this.maxRange = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max; this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn; this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff; this.createRateObjects = function(states) { var defaultOptions = { stateOn: this.stateOn, stateOff: this.stateOff }; for (var i = 0, n = states.length; i < n; i++) { states[i] = angular.extend({ index: i }, defaultOptions, states[i]); } return states; }; // Get objects used in template $scope.range = angular.isDefined($attrs.ratingStates) ? this.createRateObjects(angular.copy($scope.$parent.$eval($attrs.ratingStates))): this.createRateObjects(new Array(this.maxRange)); $scope.rate = function(value) { if ( $scope.value !== value && !$scope.readonly ) { $scope.value = value; } }; $scope.enter = function(value) { if ( ! $scope.readonly ) { $scope.val = value; } $scope.onHover({value: value}); }; $scope.reset = function() { $scope.val = angular.copy($scope.value); $scope.onLeave(); }; $scope.$watch('value', function(value) { $scope.val = value; }); $scope.readonly = false; if ($attrs.readonly) { $scope.$parent.$watch($parse($attrs.readonly), function(value) { $scope.readonly = !!value; }); } }]) .directive('rating', function() { return { restrict: 'EA', scope: { value: '=', onHover: '&', onLeave: '&' }, controller: 'RatingController', templateUrl: 'template/rating/rating.html', replace: true }; }); /** * @ngdoc overview * @name ui.bootstrap.tabs * * @description * AngularJS version of the tabs directive. */ angular.module('ui.bootstrap.tabs', []) .controller('TabsetController', ['$scope', function TabsetCtrl($scope) { var ctrl = this, tabs = ctrl.tabs = $scope.tabs = []; ctrl.select = function(tab) { angular.forEach(tabs, function(tab) { tab.active = false; }); tab.active = true; }; ctrl.addTab = function addTab(tab) { tabs.push(tab); if (tabs.length === 1 || tab.active) { ctrl.select(tab); } }; ctrl.removeTab = function removeTab(tab) { var index = tabs.indexOf(tab); //Select a new tab if the tab to be removed is selected if (tab.active && tabs.length > 1) { //If this is the last tab, select the previous tab. else, the next tab. var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1; ctrl.select(tabs[newActiveIndex]); } tabs.splice(index, 1); }; }]) /** * @ngdoc directive * @name ui.bootstrap.tabs.directive:tabset * @restrict EA * * @description * Tabset is the outer container for the tabs directive * * @param {boolean=} vertical Whether or not to use vertical styling for the tabs. * @param {boolean=} justified Whether or not to use justified styling for the tabs. * * @example First Content! Second Content!
First Vertical Content! Second Vertical Content! First Justified Content! Second Justified Content!
*/ .directive('tabset', function() { return { restrict: 'EA', transclude: true, replace: true, scope: {}, controller: 'TabsetController', templateUrl: 'template/tabs/tabset.html', link: function(scope, element, attrs) { scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false; scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false; scope.type = angular.isDefined(attrs.type) ? scope.$parent.$eval(attrs.type) : 'tabs'; } }; }) /** * @ngdoc directive * @name ui.bootstrap.tabs.directive:tab * @restrict EA * * @param {string=} heading The visible heading, or title, of the tab. Set HTML headings with {@link ui.bootstrap.tabs.directive:tabHeading tabHeading}. * @param {string=} select An expression to evaluate when the tab is selected. * @param {boolean=} active A binding, telling whether or not this tab is selected. * @param {boolean=} disabled A binding, telling whether or not this tab is disabled. * * @description * Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}. * * @example

First Tab Alert me! Second Tab, with alert callback and html heading! {{item.content}}
function TabsDemoCtrl($scope) { $scope.items = [ { title:"Dynamic Title 1", content:"Dynamic Item 0" }, { title:"Dynamic Title 2", content:"Dynamic Item 1", disabled: true } ]; $scope.alertMe = function() { setTimeout(function() { alert("You've selected the alert tab!"); }); }; };
*/ /** * @ngdoc directive * @name ui.bootstrap.tabs.directive:tabHeading * @restrict EA * * @description * Creates an HTML heading for a {@link ui.bootstrap.tabs.directive:tab tab}. Must be placed as a child of a tab element. * * @example HTML in my titles?! And some content, too! Icon heading?!? That's right. */ .directive('tab', ['$parse', function($parse) { return { require: '^tabset', restrict: 'EA', replace: true, templateUrl: 'template/tabs/tab.html', transclude: true, scope: { heading: '@', onSelect: '&select', //This callback is called in contentHeadingTransclude //once it inserts the tab's content into the dom onDeselect: '&deselect' }, controller: function() { //Empty controller so other directives can require being 'under' a tab }, compile: function(elm, attrs, transclude) { return function postLink(scope, elm, attrs, tabsetCtrl) { var getActive, setActive; if (attrs.active) { getActive = $parse(attrs.active); setActive = getActive.assign; scope.$parent.$watch(getActive, function updateActive(value, oldVal) { // Avoid re-initializing scope.active as it is already initialized // below. (watcher is called async during init with value === // oldVal) if (value !== oldVal) { scope.active = !!value; } }); scope.active = getActive(scope.$parent); } else { setActive = getActive = angular.noop; } scope.$watch('active', function(active) { // Note this watcher also initializes and assigns scope.active to the // attrs.active expression. setActive(scope.$parent, active); if (active) { tabsetCtrl.select(scope); scope.onSelect(); } else { scope.onDeselect(); } }); scope.disabled = false; if ( attrs.disabled ) { scope.$parent.$watch($parse(attrs.disabled), function(value) { scope.disabled = !! value; }); } scope.select = function() { if ( ! scope.disabled ) { scope.active = true; } }; tabsetCtrl.addTab(scope); scope.$on('$destroy', function() { tabsetCtrl.removeTab(scope); }); //We need to transclude later, once the content container is ready. //when this link happens, we're inside a tab heading. scope.$transcludeFn = transclude; }; } }; }]) .directive('tabHeadingTransclude', [function() { return { restrict: 'A', require: '^tab', link: function(scope, elm, attrs, tabCtrl) { scope.$watch('headingElement', function updateHeadingElement(heading) { if (heading) { elm.html(''); elm.append(heading); } }); } }; }]) .directive('tabContentTransclude', function() { return { restrict: 'A', require: '^tabset', link: function(scope, elm, attrs) { var tab = scope.$eval(attrs.tabContentTransclude); //Now our tab is ready to be transcluded: both the tab heading area //and the tab content area are loaded. Transclude 'em both. tab.$transcludeFn(tab.$parent, function(contents) { angular.forEach(contents, function(node) { if (isTabHeading(node)) { //Let tabHeadingTransclude know. tab.headingElement = node; } else { elm.append(node); } }); }); } }; function isTabHeading(node) { return node.tagName && ( node.hasAttribute('tab-heading') || node.hasAttribute('data-tab-heading') || node.tagName.toLowerCase() === 'tab-heading' || node.tagName.toLowerCase() === 'data-tab-heading' ); } }) ; angular.module('ui.bootstrap.timepicker', []) .constant('timepickerConfig', { hourStep: 1, minuteStep: 1, showMeridian: true, meridians: null, readonlyInput: false, mousewheel: true }) .directive('timepicker', ['$parse', '$log', 'timepickerConfig', '$locale', function ($parse, $log, timepickerConfig, $locale) { return { restrict: 'EA', require:'?^ngModel', replace: true, scope: {}, templateUrl: 'template/timepicker/timepicker.html', link: function(scope, element, attrs, ngModel) { if ( !ngModel ) { return; // do nothing if no ng-model } var selected = new Date(), meridians = angular.isDefined(attrs.meridians) ? scope.$parent.$eval(attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS; var hourStep = timepickerConfig.hourStep; if (attrs.hourStep) { scope.$parent.$watch($parse(attrs.hourStep), function(value) { hourStep = parseInt(value, 10); }); } var minuteStep = timepickerConfig.minuteStep; if (attrs.minuteStep) { scope.$parent.$watch($parse(attrs.minuteStep), function(value) { minuteStep = parseInt(value, 10); }); } // 12H / 24H mode scope.showMeridian = timepickerConfig.showMeridian; if (attrs.showMeridian) { scope.$parent.$watch($parse(attrs.showMeridian), function(value) { scope.showMeridian = !!value; if ( ngModel.$error.time ) { // Evaluate from template var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate(); if (angular.isDefined( hours ) && angular.isDefined( minutes )) { selected.setHours( hours ); refresh(); } } else { updateTemplate(); } }); } // Get scope.hours in 24H mode if valid function getHoursFromTemplate ( ) { var hours = parseInt( scope.hours, 10 ); var valid = ( scope.showMeridian ) ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24); if ( !valid ) { return undefined; } if ( scope.showMeridian ) { if ( hours === 12 ) { hours = 0; } if ( scope.meridian === meridians[1] ) { hours = hours + 12; } } return hours; } function getMinutesFromTemplate() { var minutes = parseInt(scope.minutes, 10); return ( minutes >= 0 && minutes < 60 ) ? minutes : undefined; } function pad( value ) { return ( angular.isDefined(value) && value.toString().length < 2 ) ? '0' + value : value; } // Input elements var inputs = element.find('input'), hoursInputEl = inputs.eq(0), minutesInputEl = inputs.eq(1); // Respond on mousewheel spin var mousewheel = (angular.isDefined(attrs.mousewheel)) ? scope.$eval(attrs.mousewheel) : timepickerConfig.mousewheel; if ( mousewheel ) { var isScrollingUp = function(e) { if (e.originalEvent) { e = e.originalEvent; } //pick correct delta variable depending on event var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY; return (e.detail || delta > 0); }; hoursInputEl.bind('mousewheel wheel', function(e) { scope.$apply( (isScrollingUp(e)) ? scope.incrementHours() : scope.decrementHours() ); e.preventDefault(); }); minutesInputEl.bind('mousewheel wheel', function(e) { scope.$apply( (isScrollingUp(e)) ? scope.incrementMinutes() : scope.decrementMinutes() ); e.preventDefault(); }); } scope.readonlyInput = (angular.isDefined(attrs.readonlyInput)) ? scope.$eval(attrs.readonlyInput) : timepickerConfig.readonlyInput; if ( ! scope.readonlyInput ) { var invalidate = function(invalidHours, invalidMinutes) { ngModel.$setViewValue( null ); ngModel.$setValidity('time', false); if (angular.isDefined(invalidHours)) { scope.invalidHours = invalidHours; } if (angular.isDefined(invalidMinutes)) { scope.invalidMinutes = invalidMinutes; } }; scope.updateHours = function() { var hours = getHoursFromTemplate(); if ( angular.isDefined(hours) ) { selected.setHours( hours ); refresh( 'h' ); } else { invalidate(true); } }; hoursInputEl.bind('blur', function(e) { if ( !scope.validHours && scope.hours < 10) { scope.$apply( function() { scope.hours = pad( scope.hours ); }); } }); scope.updateMinutes = function() { var minutes = getMinutesFromTemplate(); if ( angular.isDefined(minutes) ) { selected.setMinutes( minutes ); refresh( 'm' ); } else { invalidate(undefined, true); } }; minutesInputEl.bind('blur', function(e) { if ( !scope.invalidMinutes && scope.minutes < 10 ) { scope.$apply( function() { scope.minutes = pad( scope.minutes ); }); } }); } else { scope.updateHours = angular.noop; scope.updateMinutes = angular.noop; } ngModel.$render = function() { var date = ngModel.$modelValue ? new Date( ngModel.$modelValue ) : null; if ( isNaN(date) ) { ngModel.$setValidity('time', false); $log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'); } else { if ( date ) { selected = date; } makeValid(); updateTemplate(); } }; // Call internally when we know that model is valid. function refresh( keyboardChange ) { makeValid(); ngModel.$setViewValue( new Date(selected) ); updateTemplate( keyboardChange ); } function makeValid() { ngModel.$setValidity('time', true); scope.invalidHours = false; scope.invalidMinutes = false; } function updateTemplate( keyboardChange ) { var hours = selected.getHours(), minutes = selected.getMinutes(); if ( scope.showMeridian ) { hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12; // Convert 24 to 12 hour system } scope.hours = keyboardChange === 'h' ? hours : pad(hours); scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes); scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1]; } function addMinutes( minutes ) { var dt = new Date( selected.getTime() + minutes * 60000 ); selected.setHours( dt.getHours(), dt.getMinutes() ); refresh(); } scope.incrementHours = function() { addMinutes( hourStep * 60 ); }; scope.decrementHours = function() { addMinutes( - hourStep * 60 ); }; scope.incrementMinutes = function() { addMinutes( minuteStep ); }; scope.decrementMinutes = function() { addMinutes( - minuteStep ); }; scope.toggleMeridian = function() { addMinutes( 12 * 60 * (( selected.getHours() < 12 ) ? 1 : -1) ); }; } }; }]); angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap.bindHtml']) /** * A helper service that can parse typeahead's syntax (string provided by users) * Extracted to a separate service for ease of unit testing */ .factory('typeaheadParser', ['$parse', function ($parse) { // 00000111000000000000022200000000000000003333333333333330000000000044000 var TYPEAHEAD_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+(.*)$/; return { parse:function (input) { var match = input.match(TYPEAHEAD_REGEXP), modelMapper, viewMapper, source; if (!match) { throw new Error( "Expected typeahead specification in form of '_modelValue_ (as _label_)? for _item_ in _collection_'" + " but got '" + input + "'."); } return { itemName:match[3], source:$parse(match[4]), viewMapper:$parse(match[2] || match[1]), modelMapper:$parse(match[1]) }; } }; }]) .directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser', function ($compile, $parse, $q, $timeout, $document, $position, typeaheadParser) { var HOT_KEYS = [9, 13, 27, 38, 40]; return { require:'ngModel', link:function (originalScope, element, attrs, modelCtrl) { //SUPPORTED ATTRIBUTES (OPTIONS) //minimal no of characters that needs to be entered before typeahead kicks-in var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1; //minimal wait time after last character typed before typehead kicks-in var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0; //should it restrict model values to the ones selected from the popup only? var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false; //binding to a variable that indicates if matches are being retrieved asynchronously var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop; //a callback executed when a match is selected var onSelectCallback = $parse(attrs.typeaheadOnSelect); var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined; var appendToBody = attrs.typeaheadAppendToBody ? $parse(attrs.typeaheadAppendToBody) : false; //INTERNAL VARIABLES //model setter executed upon match selection var $setModelValue = $parse(attrs.ngModel).assign; //expressions used by typeahead var parserResult = typeaheadParser.parse(attrs.typeahead); var hasFocus; //pop-up element used to display matches var popUpEl = angular.element('
'); popUpEl.attr({ matches: 'matches', active: 'activeIdx', select: 'select(activeIdx)', query: 'query', position: 'position' }); //custom item template if (angular.isDefined(attrs.typeaheadTemplateUrl)) { popUpEl.attr('template-url', attrs.typeaheadTemplateUrl); } //create a child scope for the typeahead directive so we are not polluting original scope //with typeahead-specific data (matches, query etc.) var scope = originalScope.$new(); originalScope.$on('$destroy', function(){ scope.$destroy(); }); var resetMatches = function() { scope.matches = []; scope.activeIdx = -1; }; var getMatchesAsync = function(inputValue) { var locals = {$viewValue: inputValue}; isLoadingSetter(originalScope, true); $q.when(parserResult.source(originalScope, locals)).then(function(matches) { //it might happen that several async queries were in progress if a user were typing fast //but we are interested only in responses that correspond to the current view value if (inputValue === modelCtrl.$viewValue && hasFocus) { if (matches.length > 0) { scope.activeIdx = 0; scope.matches.length = 0; //transform labels for(var i=0; i= minSearch) { if (waitTime > 0) { if (timeoutPromise) { $timeout.cancel(timeoutPromise);//cancel previous timeout } timeoutPromise = $timeout(function () { getMatchesAsync(inputValue); }, waitTime); } else { getMatchesAsync(inputValue); } } else { isLoadingSetter(originalScope, false); resetMatches(); } if (isEditable) { return inputValue; } else { if (!inputValue) { // Reset in case user had typed something previously. modelCtrl.$setValidity('editable', true); return inputValue; } else { modelCtrl.$setValidity('editable', false); return undefined; } } }); modelCtrl.$formatters.push(function (modelValue) { var candidateViewValue, emptyViewValue; var locals = {}; if (inputFormatter) { locals['$model'] = modelValue; return inputFormatter(originalScope, locals); } else { //it might happen that we don't have enough info to properly render input value //we need to check for this situation and simply return model value if we can't apply custom formatting locals[parserResult.itemName] = modelValue; candidateViewValue = parserResult.viewMapper(originalScope, locals); locals[parserResult.itemName] = undefined; emptyViewValue = parserResult.viewMapper(originalScope, locals); return candidateViewValue!== emptyViewValue ? candidateViewValue : modelValue; } }); scope.select = function (activeIdx) { //called from within the $digest() cycle var locals = {}; var model, item; locals[parserResult.itemName] = item = scope.matches[activeIdx].model; model = parserResult.modelMapper(originalScope, locals); $setModelValue(originalScope, model); modelCtrl.$setValidity('editable', true); onSelectCallback(originalScope, { $item: item, $model: model, $label: parserResult.viewMapper(originalScope, locals) }); resetMatches(); //return focus to the input element if a mach was selected via a mouse click event element[0].focus(); }; //bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27) element.bind('keydown', function (evt) { //typeahead is open and an "interesting" key was pressed if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) { return; } evt.preventDefault(); if (evt.which === 40) { scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length; scope.$digest(); } else if (evt.which === 38) { scope.activeIdx = (scope.activeIdx ? scope.activeIdx : scope.matches.length) - 1; scope.$digest(); } else if (evt.which === 13 || evt.which === 9) { scope.$apply(function () { scope.select(scope.activeIdx); }); } else if (evt.which === 27) { evt.stopPropagation(); resetMatches(); scope.$digest(); } }); element.bind('blur', function (evt) { hasFocus = false; }); // Keep reference to click handler to unbind it. var dismissClickHandler = function (evt) { if (element[0] !== evt.target) { resetMatches(); scope.$digest(); } }; $document.bind('click', dismissClickHandler); originalScope.$on('$destroy', function(){ $document.unbind('click', dismissClickHandler); }); var $popup = $compile(popUpEl)(scope); if ( appendToBody ) { $document.find('body').append($popup); } else { element.after($popup); } } }; }]) .directive('typeaheadPopup', function () { return { restrict:'EA', scope:{ matches:'=', query:'=', active:'=', position:'=', select:'&' }, replace:true, templateUrl:'template/typeahead/typeahead-popup.html', link:function (scope, element, attrs) { scope.templateUrl = attrs.templateUrl; scope.isOpen = function () { return scope.matches.length > 0; }; scope.isActive = function (matchIdx) { return scope.active == matchIdx; }; scope.selectActive = function (matchIdx) { scope.active = matchIdx; }; scope.selectMatch = function (activeIdx) { scope.select({activeIdx:activeIdx}); }; } }; }) .directive('typeaheadMatch', ['$http', '$templateCache', '$compile', '$parse', function ($http, $templateCache, $compile, $parse) { return { restrict:'EA', scope:{ index:'=', match:'=', query:'=' }, link:function (scope, element, attrs) { var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'template/typeahead/typeahead-match.html'; $http.get(tplUrl, {cache: $templateCache}).success(function(tplContent){ element.replaceWith($compile(tplContent.trim())(scope)); }); } }; }]) .filter('typeaheadHighlight', function() { function escapeRegexp(queryToEscape) { return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); } return function(matchItem, query) { return query ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '$&') : matchItem; }; }); // Source: public/lib/angular-bootstrap/ui-bootstrap-tpls.js /* * angular-ui-bootstrap * http://angular-ui.github.io/bootstrap/ * Version: 0.10.0 - 2014-01-13 * License: MIT */ angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.bindHtml","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.dropdownToggle","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]); angular.module("ui.bootstrap.tpls", ["template/accordion/accordion-group.html","template/accordion/accordion.html","template/alert/alert.html","template/carousel/carousel.html","template/carousel/slide.html","template/datepicker/datepicker.html","template/datepicker/popup.html","template/modal/backdrop.html","template/modal/window.html","template/pagination/pager.html","template/pagination/pagination.html","template/tooltip/tooltip-html-unsafe-popup.html","template/tooltip/tooltip-popup.html","template/popover/popover.html","template/progressbar/bar.html","template/progressbar/progress.html","template/progressbar/progressbar.html","template/rating/rating.html","template/tabs/tab.html","template/tabs/tabset.html","template/timepicker/timepicker.html","template/typeahead/typeahead-match.html","template/typeahead/typeahead-popup.html"]); angular.module('ui.bootstrap.transition', []) /** * $transition service provides a consistent interface to trigger CSS 3 transitions and to be informed when they complete. * @param {DOMElement} element The DOMElement that will be animated. * @param {string|object|function} trigger The thing that will cause the transition to start: * - As a string, it represents the css class to be added to the element. * - As an object, it represents a hash of style attributes to be applied to the element. * - As a function, it represents a function to be called that will cause the transition to occur. * @return {Promise} A promise that is resolved when the transition finishes. */ .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) { var $transition = function(element, trigger, options) { options = options || {}; var deferred = $q.defer(); var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"]; var transitionEndHandler = function(event) { $rootScope.$apply(function() { element.unbind(endEventName, transitionEndHandler); deferred.resolve(element); }); }; if (endEventName) { element.bind(endEventName, transitionEndHandler); } // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur $timeout(function() { if ( angular.isString(trigger) ) { element.addClass(trigger); } else if ( angular.isFunction(trigger) ) { trigger(element); } else if ( angular.isObject(trigger) ) { element.css(trigger); } //If browser does not support transitions, instantly resolve if ( !endEventName ) { deferred.resolve(element); } }); // Add our custom cancel function to the promise that is returned // We can call this if we are about to run a new transition, which we know will prevent this transition from ending, // i.e. it will therefore never raise a transitionEnd event for that transition deferred.promise.cancel = function() { if ( endEventName ) { element.unbind(endEventName, transitionEndHandler); } deferred.reject('Transition cancelled'); }; return deferred.promise; }; // Work out the name of the transitionEnd event var transElement = document.createElement('trans'); var transitionEndEventNames = { 'WebkitTransition': 'webkitTransitionEnd', 'MozTransition': 'transitionend', 'OTransition': 'oTransitionEnd', 'transition': 'transitionend' }; var animationEndEventNames = { 'WebkitTransition': 'webkitAnimationEnd', 'MozTransition': 'animationend', 'OTransition': 'oAnimationEnd', 'transition': 'animationend' }; function findEndEventName(endEventNames) { for (var name in endEventNames){ if (transElement.style[name] !== undefined) { return endEventNames[name]; } } } $transition.transitionEndEventName = findEndEventName(transitionEndEventNames); $transition.animationEndEventName = findEndEventName(animationEndEventNames); return $transition; }]); angular.module('ui.bootstrap.collapse', ['ui.bootstrap.transition']) .directive('collapse', ['$transition', function ($transition, $timeout) { return { link: function (scope, element, attrs) { var initialAnimSkip = true; var currentTransition; function doTransition(change) { var newTransition = $transition(element, change); if (currentTransition) { currentTransition.cancel(); } currentTransition = newTransition; newTransition.then(newTransitionDone, newTransitionDone); return newTransition; function newTransitionDone() { // Make sure it's this transition, otherwise, leave it alone. if (currentTransition === newTransition) { currentTransition = undefined; } } } function expand() { if (initialAnimSkip) { initialAnimSkip = false; expandDone(); } else { element.removeClass('collapse').addClass('collapsing'); doTransition({ height: element[0].scrollHeight + 'px' }).then(expandDone); } } function expandDone() { element.removeClass('collapsing'); element.addClass('collapse in'); element.css({height: 'auto'}); } function collapse() { if (initialAnimSkip) { initialAnimSkip = false; collapseDone(); element.css({height: 0}); } else { // CSS transitions don't work with height: auto, so we have to manually change the height to a specific value element.css({ height: element[0].scrollHeight + 'px' }); //trigger reflow so a browser realizes that height was updated from auto to a specific value var x = element[0].offsetWidth; element.removeClass('collapse in').addClass('collapsing'); doTransition({ height: 0 }).then(collapseDone); } } function collapseDone() { element.removeClass('collapsing'); element.addClass('collapse'); } scope.$watch(attrs.collapse, function (shouldCollapse) { if (shouldCollapse) { collapse(); } else { expand(); } }); } }; }]); angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse']) .constant('accordionConfig', { closeOthers: true }) .controller('AccordionController', ['$scope', '$attrs', 'accordionConfig', function ($scope, $attrs, accordionConfig) { // This array keeps track of the accordion groups this.groups = []; // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to this.closeOthers = function(openGroup) { var closeOthers = angular.isDefined($attrs.closeOthers) ? $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers; if ( closeOthers ) { angular.forEach(this.groups, function (group) { if ( group !== openGroup ) { group.isOpen = false; } }); } }; // This is called from the accordion-group directive to add itself to the accordion this.addGroup = function(groupScope) { var that = this; this.groups.push(groupScope); groupScope.$on('$destroy', function (event) { that.removeGroup(groupScope); }); }; // This is called from the accordion-group directive when to remove itself this.removeGroup = function(group) { var index = this.groups.indexOf(group); if ( index !== -1 ) { this.groups.splice(this.groups.indexOf(group), 1); } }; }]) // The accordion directive simply sets up the directive controller // and adds an accordion CSS class to itself element. .directive('accordion', function () { return { restrict:'EA', controller:'AccordionController', transclude: true, replace: false, templateUrl: 'template/accordion/accordion.html' }; }) // The accordion-group directive indicates a block of html that will expand and collapse in an accordion .directive('accordionGroup', ['$parse', function($parse) { return { require:'^accordion', // We need this directive to be inside an accordion restrict:'EA', transclude:true, // It transcludes the contents of the directive into the template replace: true, // The element containing the directive will be replaced with the template templateUrl:'template/accordion/accordion-group.html', scope:{ heading:'@' }, // Create an isolated scope and interpolate the heading attribute onto this scope controller: function() { this.setHeading = function(element) { this.heading = element; }; }, link: function(scope, element, attrs, accordionCtrl) { var getIsOpen, setIsOpen; accordionCtrl.addGroup(scope); scope.isOpen = false; if ( attrs.isOpen ) { getIsOpen = $parse(attrs.isOpen); setIsOpen = getIsOpen.assign; scope.$parent.$watch(getIsOpen, function(value) { scope.isOpen = !!value; }); } scope.$watch('isOpen', function(value) { if ( value ) { accordionCtrl.closeOthers(scope); } if ( setIsOpen ) { setIsOpen(scope.$parent, value); } }); } }; }]) // Use accordion-heading below an accordion-group to provide a heading containing HTML // // Heading containing HTML - // .directive('accordionHeading', function() { return { restrict: 'EA', transclude: true, // Grab the contents to be used as the heading template: '', // In effect remove this element! replace: true, require: '^accordionGroup', compile: function(element, attr, transclude) { return function link(scope, element, attr, accordionGroupCtrl) { // Pass the heading to the accordion-group controller // so that it can be transcluded into the right place in the template // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat] accordionGroupCtrl.setHeading(transclude(scope, function() {})); }; } }; }) // Use in the accordion-group template to indicate where you want the heading to be transcluded // You must provide the property on the accordion-group controller that will hold the transcluded element //
// // ... //
.directive('accordionTransclude', function() { return { require: '^accordionGroup', link: function(scope, element, attr, controller) { scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) { if ( heading ) { element.html(''); element.append(heading); } }); } }; }); angular.module("ui.bootstrap.alert", []) .controller('AlertController', ['$scope', '$attrs', function ($scope, $attrs) { $scope.closeable = 'close' in $attrs; }]) .directive('alert', function () { return { restrict:'EA', controller:'AlertController', templateUrl:'template/alert/alert.html', transclude:true, replace:true, scope: { type: '=', close: '&' } }; }); angular.module('ui.bootstrap.bindHtml', []) .directive('bindHtmlUnsafe', function () { return function (scope, element, attr) { element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe); scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) { element.html(value || ''); }); }; }); angular.module('ui.bootstrap.buttons', []) .constant('buttonConfig', { activeClass: 'active', toggleEvent: 'click' }) .controller('ButtonsController', ['buttonConfig', function(buttonConfig) { this.activeClass = buttonConfig.activeClass || 'active'; this.toggleEvent = buttonConfig.toggleEvent || 'click'; }]) .directive('btnRadio', function () { return { require: ['btnRadio', 'ngModel'], controller: 'ButtonsController', link: function (scope, element, attrs, ctrls) { var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; //model -> UI ngModelCtrl.$render = function () { element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.btnRadio))); }; //ui->model element.bind(buttonsCtrl.toggleEvent, function () { if (!element.hasClass(buttonsCtrl.activeClass)) { scope.$apply(function () { ngModelCtrl.$setViewValue(scope.$eval(attrs.btnRadio)); ngModelCtrl.$render(); }); } }); } }; }) .directive('btnCheckbox', function () { return { require: ['btnCheckbox', 'ngModel'], controller: 'ButtonsController', link: function (scope, element, attrs, ctrls) { var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; function getTrueValue() { return getCheckboxValue(attrs.btnCheckboxTrue, true); } function getFalseValue() { return getCheckboxValue(attrs.btnCheckboxFalse, false); } function getCheckboxValue(attributeValue, defaultValue) { var val = scope.$eval(attributeValue); return angular.isDefined(val) ? val : defaultValue; } //model -> UI ngModelCtrl.$render = function () { element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue())); }; //ui->model element.bind(buttonsCtrl.toggleEvent, function () { scope.$apply(function () { ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue()); ngModelCtrl.$render(); }); }); } }; }); /** * @ngdoc overview * @name ui.bootstrap.carousel * * @description * AngularJS version of an image carousel. * */ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition']) .controller('CarouselController', ['$scope', '$timeout', '$transition', '$q', function ($scope, $timeout, $transition, $q) { var self = this, slides = self.slides = [], currentIndex = -1, currentTimeout, isPlaying; self.currentSlide = null; var destroyed = false; /* direction: "prev" or "next" */ self.select = function(nextSlide, direction) { var nextIndex = slides.indexOf(nextSlide); //Decide direction if it's not given if (direction === undefined) { direction = nextIndex > currentIndex ? "next" : "prev"; } if (nextSlide && nextSlide !== self.currentSlide) { if ($scope.$currentTransition) { $scope.$currentTransition.cancel(); //Timeout so ng-class in template has time to fix classes for finished slide $timeout(goNext); } else { goNext(); } } function goNext() { // Scope has been destroyed, stop here. if (destroyed) { return; } //If we have a slide to transition from and we have a transition type and we're allowed, go if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) { //We shouldn't do class manip in here, but it's the same weird thing bootstrap does. need to fix sometime nextSlide.$element.addClass(direction); var reflow = nextSlide.$element[0].offsetWidth; //force reflow //Set all other slides to stop doing their stuff for the new transition angular.forEach(slides, function(slide) { angular.extend(slide, {direction: '', entering: false, leaving: false, active: false}); }); angular.extend(nextSlide, {direction: direction, active: true, entering: true}); angular.extend(self.currentSlide||{}, {direction: direction, leaving: true}); $scope.$currentTransition = $transition(nextSlide.$element, {}); //We have to create new pointers inside a closure since next & current will change (function(next,current) { $scope.$currentTransition.then( function(){ transitionDone(next, current); }, function(){ transitionDone(next, current); } ); }(nextSlide, self.currentSlide)); } else { transitionDone(nextSlide, self.currentSlide); } self.currentSlide = nextSlide; currentIndex = nextIndex; //every time you change slides, reset the timer restartTimer(); } function transitionDone(next, current) { angular.extend(next, {direction: '', active: true, leaving: false, entering: false}); angular.extend(current||{}, {direction: '', active: false, leaving: false, entering: false}); $scope.$currentTransition = null; } }; $scope.$on('$destroy', function () { destroyed = true; }); /* Allow outside people to call indexOf on slides array */ self.indexOfSlide = function(slide) { return slides.indexOf(slide); }; $scope.next = function() { var newIndex = (currentIndex + 1) % slides.length; //Prevent this user-triggered transition from occurring if there is already one in progress if (!$scope.$currentTransition) { return self.select(slides[newIndex], 'next'); } }; $scope.prev = function() { var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1; //Prevent this user-triggered transition from occurring if there is already one in progress if (!$scope.$currentTransition) { return self.select(slides[newIndex], 'prev'); } }; $scope.select = function(slide) { self.select(slide); }; $scope.isActive = function(slide) { return self.currentSlide === slide; }; $scope.slides = function() { return slides; }; $scope.$watch('interval', restartTimer); $scope.$on('$destroy', resetTimer); function restartTimer() { resetTimer(); var interval = +$scope.interval; if (!isNaN(interval) && interval>=0) { currentTimeout = $timeout(timerFn, interval); } } function resetTimer() { if (currentTimeout) { $timeout.cancel(currentTimeout); currentTimeout = null; } } function timerFn() { if (isPlaying) { $scope.next(); restartTimer(); } else { $scope.pause(); } } $scope.play = function() { if (!isPlaying) { isPlaying = true; restartTimer(); } }; $scope.pause = function() { if (!$scope.noPause) { isPlaying = false; resetTimer(); } }; self.addSlide = function(slide, element) { slide.$element = element; slides.push(slide); //if this is the first slide or the slide is set to active, select it if(slides.length === 1 || slide.active) { self.select(slides[slides.length-1]); if (slides.length == 1) { $scope.play(); } } else { slide.active = false; } }; self.removeSlide = function(slide) { //get the index of the slide inside the carousel var index = slides.indexOf(slide); slides.splice(index, 1); if (slides.length > 0 && slide.active) { if (index >= slides.length) { self.select(slides[index-1]); } else { self.select(slides[index]); } } else if (currentIndex > index) { currentIndex--; } }; }]) /** * @ngdoc directive * @name ui.bootstrap.carousel.directive:carousel * @restrict EA * * @description * Carousel is the outer container for a set of image 'slides' to showcase. * * @param {number=} interval The time, in milliseconds, that it will take the carousel to go to the next slide. * @param {boolean=} noTransition Whether to disable transitions on the carousel. * @param {boolean=} noPause Whether to disable pausing on the carousel (by default, the carousel interval pauses on hover). * * @example .carousel-indicators { top: auto; bottom: 15px; } */ .directive('carousel', [function() { return { restrict: 'EA', transclude: true, replace: true, controller: 'CarouselController', require: 'carousel', templateUrl: 'template/carousel/carousel.html', scope: { interval: '=', noTransition: '=', noPause: '=' } }; }]) /** * @ngdoc directive * @name ui.bootstrap.carousel.directive:slide * @restrict EA * * @description * Creates a slide inside a {@link ui.bootstrap.carousel.directive:carousel carousel}. Must be placed as a child of a carousel element. * * @param {boolean=} active Model binding, whether or not this slide is currently active. * * @example
  • {{$index}}: {{slide.text}}
Add Slide
Interval, in milliseconds:
Enter a negative number to stop the interval.
function CarouselDemoCtrl($scope) { $scope.myInterval = 5000; var slides = $scope.slides = []; $scope.addSlide = function() { var newWidth = 200 + ((slides.length + (25 * slides.length)) % 150); slides.push({ image: 'http://placekitten.com/' + newWidth + '/200', text: ['More','Extra','Lots of','Surplus'][slides.length % 4] + ' ' ['Cats', 'Kittys', 'Felines', 'Cutes'][slides.length % 4] }); }; for (var i=0; i<4; i++) $scope.addSlide(); } .carousel-indicators { top: auto; bottom: 15px; }
*/ .directive('slide', ['$parse', function($parse) { return { require: '^carousel', restrict: 'EA', transclude: true, replace: true, templateUrl: 'template/carousel/slide.html', scope: { }, link: function (scope, element, attrs, carouselCtrl) { //Set up optional 'active' = binding if (attrs.active) { var getActive = $parse(attrs.active); var setActive = getActive.assign; var lastValue = scope.active = getActive(scope.$parent); scope.$watch(function parentActiveWatch() { var parentActive = getActive(scope.$parent); if (parentActive !== scope.active) { // we are out of sync and need to copy if (parentActive !== lastValue) { // parent changed and it has precedence lastValue = scope.active = parentActive; } else { // if the parent can be assigned then do so setActive(scope.$parent, parentActive = lastValue = scope.active); } } return parentActive; }); } carouselCtrl.addSlide(scope, element); //when the scope is destroyed then remove the slide from the current slides array scope.$on('$destroy', function() { carouselCtrl.removeSlide(scope); }); scope.$watch('active', function(active) { if (active) { carouselCtrl.select(scope); } }); } }; }]); angular.module('ui.bootstrap.position', []) /** * A set of utility methods that can be use to retrieve position of DOM elements. * It is meant to be used where we need to absolute-position DOM elements in * relation to other, existing elements (this is the case for tooltips, popovers, * typeahead suggestions etc.). */ .factory('$position', ['$document', '$window', function ($document, $window) { function getStyle(el, cssprop) { if (el.currentStyle) { //IE return el.currentStyle[cssprop]; } else if ($window.getComputedStyle) { return $window.getComputedStyle(el)[cssprop]; } // finally try and get inline style return el.style[cssprop]; } /** * Checks if a given element is statically positioned * @param element - raw DOM element */ function isStaticPositioned(element) { return (getStyle(element, "position") || 'static' ) === 'static'; } /** * returns the closest, non-statically positioned parentOffset of a given element * @param element */ var parentOffsetEl = function (element) { var docDomEl = $document[0]; var offsetParent = element.offsetParent || docDomEl; while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) { offsetParent = offsetParent.offsetParent; } return offsetParent || docDomEl; }; return { /** * Provides read-only equivalent of jQuery's position function: * http://api.jquery.com/position/ */ position: function (element) { var elBCR = this.offset(element); var offsetParentBCR = { top: 0, left: 0 }; var offsetParentEl = parentOffsetEl(element[0]); if (offsetParentEl != $document[0]) { offsetParentBCR = this.offset(angular.element(offsetParentEl)); offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop; offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft; } var boundingClientRect = element[0].getBoundingClientRect(); return { width: boundingClientRect.width || element.prop('offsetWidth'), height: boundingClientRect.height || element.prop('offsetHeight'), top: elBCR.top - offsetParentBCR.top, left: elBCR.left - offsetParentBCR.left }; }, /** * Provides read-only equivalent of jQuery's offset function: * http://api.jquery.com/offset/ */ offset: function (element) { var boundingClientRect = element[0].getBoundingClientRect(); return { width: boundingClientRect.width || element.prop('offsetWidth'), height: boundingClientRect.height || element.prop('offsetHeight'), top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop), left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft) }; } }; }]); angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.position']) .constant('datepickerConfig', { dayFormat: 'dd', monthFormat: 'MMMM', yearFormat: 'yyyy', dayHeaderFormat: 'EEE', dayTitleFormat: 'MMMM yyyy', monthTitleFormat: 'yyyy', showWeeks: true, startingDay: 0, yearRange: 20, minDate: null, maxDate: null }) .controller('DatepickerController', ['$scope', '$attrs', 'dateFilter', 'datepickerConfig', function($scope, $attrs, dateFilter, dtConfig) { var format = { day: getValue($attrs.dayFormat, dtConfig.dayFormat), month: getValue($attrs.monthFormat, dtConfig.monthFormat), year: getValue($attrs.yearFormat, dtConfig.yearFormat), dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat), dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat), monthTitle: getValue($attrs.monthTitleFormat, dtConfig.monthTitleFormat) }, startingDay = getValue($attrs.startingDay, dtConfig.startingDay), yearRange = getValue($attrs.yearRange, dtConfig.yearRange); this.minDate = dtConfig.minDate ? new Date(dtConfig.minDate) : null; this.maxDate = dtConfig.maxDate ? new Date(dtConfig.maxDate) : null; function getValue(value, defaultValue) { return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue; } function getDaysInMonth( year, month ) { return new Date(year, month, 0).getDate(); } function getDates(startDate, n) { var dates = new Array(n); var current = startDate, i = 0; while (i < n) { dates[i++] = new Date(current); current.setDate( current.getDate() + 1 ); } return dates; } function makeDate(date, format, isSelected, isSecondary) { return { date: date, label: dateFilter(date, format), selected: !!isSelected, secondary: !!isSecondary }; } this.modes = [ { name: 'day', getVisibleDates: function(date, selected) { var year = date.getFullYear(), month = date.getMonth(), firstDayOfMonth = new Date(year, month, 1); var difference = startingDay - firstDayOfMonth.getDay(), numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference, firstDate = new Date(firstDayOfMonth), numDates = 0; if ( numDisplayedFromPreviousMonth > 0 ) { firstDate.setDate( - numDisplayedFromPreviousMonth + 1 ); numDates += numDisplayedFromPreviousMonth; // Previous } numDates += getDaysInMonth(year, month + 1); // Current numDates += (7 - numDates % 7) % 7; // Next var days = getDates(firstDate, numDates), labels = new Array(7); for (var i = 0; i < numDates; i ++) { var dt = new Date(days[i]); days[i] = makeDate(dt, format.day, (selected && selected.getDate() === dt.getDate() && selected.getMonth() === dt.getMonth() && selected.getFullYear() === dt.getFullYear()), dt.getMonth() !== month); } for (var j = 0; j < 7; j++) { labels[j] = dateFilter(days[j].date, format.dayHeader); } return { objects: days, title: dateFilter(date, format.dayTitle), labels: labels }; }, compare: function(date1, date2) { return (new Date( date1.getFullYear(), date1.getMonth(), date1.getDate() ) - new Date( date2.getFullYear(), date2.getMonth(), date2.getDate() ) ); }, split: 7, step: { months: 1 } }, { name: 'month', getVisibleDates: function(date, selected) { var months = new Array(12), year = date.getFullYear(); for ( var i = 0; i < 12; i++ ) { var dt = new Date(year, i, 1); months[i] = makeDate(dt, format.month, (selected && selected.getMonth() === i && selected.getFullYear() === year)); } return { objects: months, title: dateFilter(date, format.monthTitle) }; }, compare: function(date1, date2) { return new Date( date1.getFullYear(), date1.getMonth() ) - new Date( date2.getFullYear(), date2.getMonth() ); }, split: 3, step: { years: 1 } }, { name: 'year', getVisibleDates: function(date, selected) { var years = new Array(yearRange), year = date.getFullYear(), startYear = parseInt((year - 1) / yearRange, 10) * yearRange + 1; for ( var i = 0; i < yearRange; i++ ) { var dt = new Date(startYear + i, 0, 1); years[i] = makeDate(dt, format.year, (selected && selected.getFullYear() === dt.getFullYear())); } return { objects: years, title: [years[0].label, years[yearRange - 1].label].join(' - ') }; }, compare: function(date1, date2) { return date1.getFullYear() - date2.getFullYear(); }, split: 5, step: { years: yearRange } } ]; this.isDisabled = function(date, mode) { var currentMode = this.modes[mode || 0]; return ((this.minDate && currentMode.compare(date, this.minDate) < 0) || (this.maxDate && currentMode.compare(date, this.maxDate) > 0) || ($scope.dateDisabled && $scope.dateDisabled({date: date, mode: currentMode.name}))); }; }]) .directive( 'datepicker', ['dateFilter', '$parse', 'datepickerConfig', '$log', function (dateFilter, $parse, datepickerConfig, $log) { return { restrict: 'EA', replace: true, templateUrl: 'template/datepicker/datepicker.html', scope: { dateDisabled: '&' }, require: ['datepicker', '?^ngModel'], controller: 'DatepickerController', link: function(scope, element, attrs, ctrls) { var datepickerCtrl = ctrls[0], ngModel = ctrls[1]; if (!ngModel) { return; // do nothing if no ng-model } // Configuration parameters var mode = 0, selected = new Date(), showWeeks = datepickerConfig.showWeeks; if (attrs.showWeeks) { scope.$parent.$watch($parse(attrs.showWeeks), function(value) { showWeeks = !! value; updateShowWeekNumbers(); }); } else { updateShowWeekNumbers(); } if (attrs.min) { scope.$parent.$watch($parse(attrs.min), function(value) { datepickerCtrl.minDate = value ? new Date(value) : null; refill(); }); } if (attrs.max) { scope.$parent.$watch($parse(attrs.max), function(value) { datepickerCtrl.maxDate = value ? new Date(value) : null; refill(); }); } function updateShowWeekNumbers() { scope.showWeekNumbers = mode === 0 && showWeeks; } // Split array into smaller arrays function split(arr, size) { var arrays = []; while (arr.length > 0) { arrays.push(arr.splice(0, size)); } return arrays; } function refill( updateSelected ) { var date = null, valid = true; if ( ngModel.$modelValue ) { date = new Date( ngModel.$modelValue ); if ( isNaN(date) ) { valid = false; $log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'); } else if ( updateSelected ) { selected = date; } } ngModel.$setValidity('date', valid); var currentMode = datepickerCtrl.modes[mode], data = currentMode.getVisibleDates(selected, date); angular.forEach(data.objects, function(obj) { obj.disabled = datepickerCtrl.isDisabled(obj.date, mode); }); ngModel.$setValidity('date-disabled', (!date || !datepickerCtrl.isDisabled(date))); scope.rows = split(data.objects, currentMode.split); scope.labels = data.labels || []; scope.title = data.title; } function setMode(value) { mode = value; updateShowWeekNumbers(); refill(); } ngModel.$render = function() { refill( true ); }; scope.select = function( date ) { if ( mode === 0 ) { var dt = ngModel.$modelValue ? new Date( ngModel.$modelValue ) : new Date(0, 0, 0, 0, 0, 0, 0); dt.setFullYear( date.getFullYear(), date.getMonth(), date.getDate() ); ngModel.$setViewValue( dt ); refill( true ); } else { selected = date; setMode( mode - 1 ); } }; scope.move = function(direction) { var step = datepickerCtrl.modes[mode].step; selected.setMonth( selected.getMonth() + direction * (step.months || 0) ); selected.setFullYear( selected.getFullYear() + direction * (step.years || 0) ); refill(); }; scope.toggleMode = function() { setMode( (mode + 1) % datepickerCtrl.modes.length ); }; scope.getWeekNumber = function(row) { return ( mode === 0 && scope.showWeekNumbers && row.length === 7 ) ? getISO8601WeekNumber(row[0].date) : null; }; function getISO8601WeekNumber(date) { var checkDate = new Date(date); checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday var time = checkDate.getTime(); checkDate.setMonth(0); // Compare with Jan 1 checkDate.setDate(1); return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; } } }; }]) .constant('datepickerPopupConfig', { dateFormat: 'yyyy-MM-dd', currentText: 'Today', toggleWeeksText: 'Weeks', clearText: 'Clear', closeText: 'Done', closeOnDateSelection: true, appendToBody: false, showButtonBar: true }) .directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', 'datepickerPopupConfig', 'datepickerConfig', function ($compile, $parse, $document, $position, dateFilter, datepickerPopupConfig, datepickerConfig) { return { restrict: 'EA', require: 'ngModel', link: function(originalScope, element, attrs, ngModel) { var scope = originalScope.$new(), // create a child scope so we are not polluting original one dateFormat, closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? originalScope.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection, appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? originalScope.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody; attrs.$observe('datepickerPopup', function(value) { dateFormat = value || datepickerPopupConfig.dateFormat; ngModel.$render(); }); scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? originalScope.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar; originalScope.$on('$destroy', function() { $popup.remove(); scope.$destroy(); }); attrs.$observe('currentText', function(text) { scope.currentText = angular.isDefined(text) ? text : datepickerPopupConfig.currentText; }); attrs.$observe('toggleWeeksText', function(text) { scope.toggleWeeksText = angular.isDefined(text) ? text : datepickerPopupConfig.toggleWeeksText; }); attrs.$observe('clearText', function(text) { scope.clearText = angular.isDefined(text) ? text : datepickerPopupConfig.clearText; }); attrs.$observe('closeText', function(text) { scope.closeText = angular.isDefined(text) ? text : datepickerPopupConfig.closeText; }); var getIsOpen, setIsOpen; if ( attrs.isOpen ) { getIsOpen = $parse(attrs.isOpen); setIsOpen = getIsOpen.assign; originalScope.$watch(getIsOpen, function updateOpen(value) { scope.isOpen = !! value; }); } scope.isOpen = getIsOpen ? getIsOpen(originalScope) : false; // Initial state function setOpen( value ) { if (setIsOpen) { setIsOpen(originalScope, !!value); } else { scope.isOpen = !!value; } } var documentClickBind = function(event) { if (scope.isOpen && event.target !== element[0]) { scope.$apply(function() { setOpen(false); }); } }; var elementFocusBind = function() { scope.$apply(function() { setOpen( true ); }); }; // popup element used to display calendar var popupEl = angular.element('
'); popupEl.attr({ 'ng-model': 'date', 'ng-change': 'dateSelection()' }); var datepickerEl = angular.element(popupEl.children()[0]), datepickerOptions = {}; if (attrs.datepickerOptions) { datepickerOptions = originalScope.$eval(attrs.datepickerOptions); datepickerEl.attr(angular.extend({}, datepickerOptions)); } // TODO: reverse from dateFilter string to Date object function parseDate(viewValue) { if (!viewValue) { ngModel.$setValidity('date', true); return null; } else if (angular.isDate(viewValue)) { ngModel.$setValidity('date', true); return viewValue; } else if (angular.isString(viewValue)) { var date = new Date(viewValue); if (isNaN(date)) { ngModel.$setValidity('date', false); return undefined; } else { ngModel.$setValidity('date', true); return date; } } else { ngModel.$setValidity('date', false); return undefined; } } ngModel.$parsers.unshift(parseDate); // Inner change scope.dateSelection = function(dt) { if (angular.isDefined(dt)) { scope.date = dt; } ngModel.$setViewValue(scope.date); ngModel.$render(); if (closeOnDateSelection) { setOpen( false ); } }; element.bind('input change keyup', function() { scope.$apply(function() { scope.date = ngModel.$modelValue; }); }); // Outter change ngModel.$render = function() { var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : ''; element.val(date); scope.date = ngModel.$modelValue; }; function addWatchableAttribute(attribute, scopeProperty, datepickerAttribute) { if (attribute) { originalScope.$watch($parse(attribute), function(value){ scope[scopeProperty] = value; }); datepickerEl.attr(datepickerAttribute || scopeProperty, scopeProperty); } } addWatchableAttribute(attrs.min, 'min'); addWatchableAttribute(attrs.max, 'max'); if (attrs.showWeeks) { addWatchableAttribute(attrs.showWeeks, 'showWeeks', 'show-weeks'); } else { scope.showWeeks = 'show-weeks' in datepickerOptions ? datepickerOptions['show-weeks'] : datepickerConfig.showWeeks; datepickerEl.attr('show-weeks', 'showWeeks'); } if (attrs.dateDisabled) { datepickerEl.attr('date-disabled', attrs.dateDisabled); } function updatePosition() { scope.position = appendToBody ? $position.offset(element) : $position.position(element); scope.position.top = scope.position.top + element.prop('offsetHeight'); } var documentBindingInitialized = false, elementFocusInitialized = false; scope.$watch('isOpen', function(value) { if (value) { updatePosition(); $document.bind('click', documentClickBind); if(elementFocusInitialized) { element.unbind('focus', elementFocusBind); } element[0].focus(); documentBindingInitialized = true; } else { if(documentBindingInitialized) { $document.unbind('click', documentClickBind); } element.bind('focus', elementFocusBind); elementFocusInitialized = true; } if ( setIsOpen ) { setIsOpen(originalScope, value); } }); scope.today = function() { scope.dateSelection(new Date()); }; scope.clear = function() { scope.dateSelection(null); }; var $popup = $compile(popupEl)(scope); if ( appendToBody ) { $document.find('body').append($popup); } else { element.after($popup); } } }; }]) .directive('datepickerPopupWrap', function() { return { restrict:'EA', replace: true, transclude: true, templateUrl: 'template/datepicker/popup.html', link:function (scope, element, attrs) { element.bind('click', function(event) { event.preventDefault(); event.stopPropagation(); }); } }; }); /* * dropdownToggle - Provides dropdown menu functionality in place of bootstrap js * @restrict class or attribute * @example: */ angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle', ['$document', '$location', function ($document, $location) { var openElement = null, closeMenu = angular.noop; return { restrict: 'CA', link: function(scope, element, attrs) { scope.$watch('$location.path', function() { closeMenu(); }); element.parent().bind('click', function() { closeMenu(); }); element.bind('click', function (event) { var elementWasOpen = (element === openElement); event.preventDefault(); event.stopPropagation(); if (!!openElement) { closeMenu(); } if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) { element.parent().addClass('open'); openElement = element; closeMenu = function (event) { if (event) { event.preventDefault(); event.stopPropagation(); } $document.unbind('click', closeMenu); element.parent().removeClass('open'); closeMenu = angular.noop; openElement = null; }; $document.bind('click', closeMenu); } }); } }; }]); angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition']) /** * A helper, internal data structure that acts as a map but also allows getting / removing * elements in the LIFO order */ .factory('$$stackedMap', function () { return { createNew: function () { var stack = []; return { add: function (key, value) { stack.push({ key: key, value: value }); }, get: function (key) { for (var i = 0; i < stack.length; i++) { if (key == stack[i].key) { return stack[i]; } } }, keys: function() { var keys = []; for (var i = 0; i < stack.length; i++) { keys.push(stack[i].key); } return keys; }, top: function () { return stack[stack.length - 1]; }, remove: function (key) { var idx = -1; for (var i = 0; i < stack.length; i++) { if (key == stack[i].key) { idx = i; break; } } return stack.splice(idx, 1)[0]; }, removeTop: function () { return stack.splice(stack.length - 1, 1)[0]; }, length: function () { return stack.length; } }; } }; }) /** * A helper directive for the $modal service. It creates a backdrop element. */ .directive('modalBackdrop', ['$timeout', function ($timeout) { return { restrict: 'EA', replace: true, templateUrl: 'template/modal/backdrop.html', link: function (scope) { scope.animate = false; //trigger CSS transitions $timeout(function () { scope.animate = true; }); } }; }]) .directive('modalWindow', ['$modalStack', '$timeout', function ($modalStack, $timeout) { return { restrict: 'EA', scope: { index: '@', animate: '=' }, replace: true, transclude: true, templateUrl: 'template/modal/window.html', link: function (scope, element, attrs) { scope.windowClass = attrs.windowClass || ''; $timeout(function () { // trigger CSS transitions scope.animate = true; // focus a freshly-opened modal element[0].focus(); }); scope.close = function (evt) { var modal = $modalStack.getTop(); if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) { evt.preventDefault(); evt.stopPropagation(); $modalStack.dismiss(modal.key, 'backdrop click'); } }; } }; }]) .factory('$modalStack', ['$transition', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap', function ($transition, $timeout, $document, $compile, $rootScope, $$stackedMap) { var OPENED_MODAL_CLASS = 'modal-open'; var backdropDomEl, backdropScope; var openedWindows = $$stackedMap.createNew(); var $modalStack = {}; function backdropIndex() { var topBackdropIndex = -1; var opened = openedWindows.keys(); for (var i = 0; i < opened.length; i++) { if (openedWindows.get(opened[i]).value.backdrop) { topBackdropIndex = i; } } return topBackdropIndex; } $rootScope.$watch(backdropIndex, function(newBackdropIndex){ if (backdropScope) { backdropScope.index = newBackdropIndex; } }); function removeModalWindow(modalInstance) { var body = $document.find('body').eq(0); var modalWindow = openedWindows.get(modalInstance).value; //clean up the stack openedWindows.remove(modalInstance); //remove window DOM element removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300, checkRemoveBackdrop); body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0); } function checkRemoveBackdrop() { //remove backdrop if no longer needed if (backdropDomEl && backdropIndex() == -1) { var backdropScopeRef = backdropScope; removeAfterAnimate(backdropDomEl, backdropScope, 150, function () { backdropScopeRef.$destroy(); backdropScopeRef = null; }); backdropDomEl = undefined; backdropScope = undefined; } } function removeAfterAnimate(domEl, scope, emulateTime, done) { // Closing animation scope.animate = false; var transitionEndEventName = $transition.transitionEndEventName; if (transitionEndEventName) { // transition out var timeout = $timeout(afterAnimating, emulateTime); domEl.bind(transitionEndEventName, function () { $timeout.cancel(timeout); afterAnimating(); scope.$apply(); }); } else { // Ensure this call is async $timeout(afterAnimating, 0); } function afterAnimating() { if (afterAnimating.done) { return; } afterAnimating.done = true; domEl.remove(); if (done) { done(); } } } $document.bind('keydown', function (evt) { var modal; if (evt.which === 27) { modal = openedWindows.top(); if (modal && modal.value.keyboard) { $rootScope.$apply(function () { $modalStack.dismiss(modal.key); }); } } }); $modalStack.open = function (modalInstance, modal) { openedWindows.add(modalInstance, { deferred: modal.deferred, modalScope: modal.scope, backdrop: modal.backdrop, keyboard: modal.keyboard }); var body = $document.find('body').eq(0), currBackdropIndex = backdropIndex(); if (currBackdropIndex >= 0 && !backdropDomEl) { backdropScope = $rootScope.$new(true); backdropScope.index = currBackdropIndex; backdropDomEl = $compile('
')(backdropScope); body.append(backdropDomEl); } var angularDomEl = angular.element('
'); angularDomEl.attr('window-class', modal.windowClass); angularDomEl.attr('index', openedWindows.length() - 1); angularDomEl.attr('animate', 'animate'); angularDomEl.html(modal.content); var modalDomEl = $compile(angularDomEl)(modal.scope); openedWindows.top().value.modalDomEl = modalDomEl; body.append(modalDomEl); body.addClass(OPENED_MODAL_CLASS); }; $modalStack.close = function (modalInstance, result) { var modalWindow = openedWindows.get(modalInstance).value; if (modalWindow) { modalWindow.deferred.resolve(result); removeModalWindow(modalInstance); } }; $modalStack.dismiss = function (modalInstance, reason) { var modalWindow = openedWindows.get(modalInstance).value; if (modalWindow) { modalWindow.deferred.reject(reason); removeModalWindow(modalInstance); } }; $modalStack.dismissAll = function (reason) { var topModal = this.getTop(); while (topModal) { this.dismiss(topModal.key, reason); topModal = this.getTop(); } }; $modalStack.getTop = function () { return openedWindows.top(); }; return $modalStack; }]) .provider('$modal', function () { var $modalProvider = { options: { backdrop: true, //can be also false or 'static' keyboard: true }, $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) { var $modal = {}; function getTemplatePromise(options) { return options.template ? $q.when(options.template) : $http.get(options.templateUrl, {cache: $templateCache}).then(function (result) { return result.data; }); } function getResolvePromises(resolves) { var promisesArr = []; angular.forEach(resolves, function (value, key) { if (angular.isFunction(value) || angular.isArray(value)) { promisesArr.push($q.when($injector.invoke(value))); } }); return promisesArr; } $modal.open = function (modalOptions) { var modalResultDeferred = $q.defer(); var modalOpenedDeferred = $q.defer(); //prepare an instance of a modal to be injected into controllers and returned to a caller var modalInstance = { result: modalResultDeferred.promise, opened: modalOpenedDeferred.promise, close: function (result) { $modalStack.close(modalInstance, result); }, dismiss: function (reason) { $modalStack.dismiss(modalInstance, reason); } }; //merge and clean up options modalOptions = angular.extend({}, $modalProvider.options, modalOptions); modalOptions.resolve = modalOptions.resolve || {}; //verify options if (!modalOptions.template && !modalOptions.templateUrl) { throw new Error('One of template or templateUrl options is required.'); } var templateAndResolvePromise = $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve))); templateAndResolvePromise.then(function resolveSuccess(tplAndVars) { var modalScope = (modalOptions.scope || $rootScope).$new(); modalScope.$close = modalInstance.close; modalScope.$dismiss = modalInstance.dismiss; var ctrlInstance, ctrlLocals = {}; var resolveIter = 1; //controllers if (modalOptions.controller) { ctrlLocals.$scope = modalScope; ctrlLocals.$modalInstance = modalInstance; angular.forEach(modalOptions.resolve, function (value, key) { ctrlLocals[key] = tplAndVars[resolveIter++]; }); ctrlInstance = $controller(modalOptions.controller, ctrlLocals); } $modalStack.open(modalInstance, { scope: modalScope, deferred: modalResultDeferred, content: tplAndVars[0], backdrop: modalOptions.backdrop, keyboard: modalOptions.keyboard, windowClass: modalOptions.windowClass }); }, function resolveError(reason) { modalResultDeferred.reject(reason); }); templateAndResolvePromise.then(function () { modalOpenedDeferred.resolve(true); }, function () { modalOpenedDeferred.reject(false); }); return modalInstance; }; return $modal; }] }; return $modalProvider; }); angular.module('ui.bootstrap.pagination', []) .controller('PaginationController', ['$scope', '$attrs', '$parse', '$interpolate', function ($scope, $attrs, $parse, $interpolate) { var self = this, setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop; this.init = function(defaultItemsPerPage) { if ($attrs.itemsPerPage) { $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) { self.itemsPerPage = parseInt(value, 10); $scope.totalPages = self.calculateTotalPages(); }); } else { this.itemsPerPage = defaultItemsPerPage; } }; this.noPrevious = function() { return this.page === 1; }; this.noNext = function() { return this.page === $scope.totalPages; }; this.isActive = function(page) { return this.page === page; }; this.calculateTotalPages = function() { var totalPages = this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage); return Math.max(totalPages || 0, 1); }; this.getAttributeValue = function(attribute, defaultValue, interpolate) { return angular.isDefined(attribute) ? (interpolate ? $interpolate(attribute)($scope.$parent) : $scope.$parent.$eval(attribute)) : defaultValue; }; this.render = function() { this.page = parseInt($scope.page, 10) || 1; if (this.page > 0 && this.page <= $scope.totalPages) { $scope.pages = this.getPages(this.page, $scope.totalPages); } }; $scope.selectPage = function(page) { if ( ! self.isActive(page) && page > 0 && page <= $scope.totalPages) { $scope.page = page; $scope.onSelectPage({ page: page }); } }; $scope.$watch('page', function() { self.render(); }); $scope.$watch('totalItems', function() { $scope.totalPages = self.calculateTotalPages(); }); $scope.$watch('totalPages', function(value) { setNumPages($scope.$parent, value); // Readonly variable if ( self.page > value ) { $scope.selectPage(value); } else { self.render(); } }); }]) .constant('paginationConfig', { itemsPerPage: 10, boundaryLinks: false, directionLinks: true, firstText: 'First', previousText: 'Previous', nextText: 'Next', lastText: 'Last', rotate: true }) .directive('pagination', ['$parse', 'paginationConfig', function($parse, config) { return { restrict: 'EA', scope: { page: '=', totalItems: '=', onSelectPage:' &' }, controller: 'PaginationController', templateUrl: 'template/pagination/pagination.html', replace: true, link: function(scope, element, attrs, paginationCtrl) { // Setup configuration parameters var maxSize, boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks, config.boundaryLinks ), directionLinks = paginationCtrl.getAttributeValue(attrs.directionLinks, config.directionLinks ), firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true), previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true), nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true), lastText = paginationCtrl.getAttributeValue(attrs.lastText, config.lastText, true), rotate = paginationCtrl.getAttributeValue(attrs.rotate, config.rotate); paginationCtrl.init(config.itemsPerPage); if (attrs.maxSize) { scope.$parent.$watch($parse(attrs.maxSize), function(value) { maxSize = parseInt(value, 10); paginationCtrl.render(); }); } // Create page object used in template function makePage(number, text, isActive, isDisabled) { return { number: number, text: text, active: isActive, disabled: isDisabled }; } paginationCtrl.getPages = function(currentPage, totalPages) { var pages = []; // Default page limits var startPage = 1, endPage = totalPages; var isMaxSized = ( angular.isDefined(maxSize) && maxSize < totalPages ); // recompute if maxSize if ( isMaxSized ) { if ( rotate ) { // Current page is displayed in the middle of the visible ones startPage = Math.max(currentPage - Math.floor(maxSize/2), 1); endPage = startPage + maxSize - 1; // Adjust if limit is exceeded if (endPage > totalPages) { endPage = totalPages; startPage = endPage - maxSize + 1; } } else { // Visible pages are paginated with maxSize startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1; // Adjust last page if limit is exceeded endPage = Math.min(startPage + maxSize - 1, totalPages); } } // Add page number links for (var number = startPage; number <= endPage; number++) { var page = makePage(number, number, paginationCtrl.isActive(number), false); pages.push(page); } // Add links to move between page sets if ( isMaxSized && ! rotate ) { if ( startPage > 1 ) { var previousPageSet = makePage(startPage - 1, '...', false, false); pages.unshift(previousPageSet); } if ( endPage < totalPages ) { var nextPageSet = makePage(endPage + 1, '...', false, false); pages.push(nextPageSet); } } // Add previous & next links if (directionLinks) { var previousPage = makePage(currentPage - 1, previousText, false, paginationCtrl.noPrevious()); pages.unshift(previousPage); var nextPage = makePage(currentPage + 1, nextText, false, paginationCtrl.noNext()); pages.push(nextPage); } // Add first & last links if (boundaryLinks) { var firstPage = makePage(1, firstText, false, paginationCtrl.noPrevious()); pages.unshift(firstPage); var lastPage = makePage(totalPages, lastText, false, paginationCtrl.noNext()); pages.push(lastPage); } return pages; }; } }; }]) .constant('pagerConfig', { itemsPerPage: 10, previousText: '« Previous', nextText: 'Next »', align: true }) .directive('pager', ['pagerConfig', function(config) { return { restrict: 'EA', scope: { page: '=', totalItems: '=', onSelectPage:' &' }, controller: 'PaginationController', templateUrl: 'template/pagination/pager.html', replace: true, link: function(scope, element, attrs, paginationCtrl) { // Setup configuration parameters var previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true), nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true), align = paginationCtrl.getAttributeValue(attrs.align, config.align); paginationCtrl.init(config.itemsPerPage); // Create page object used in template function makePage(number, text, isDisabled, isPrevious, isNext) { return { number: number, text: text, disabled: isDisabled, previous: ( align && isPrevious ), next: ( align && isNext ) }; } paginationCtrl.getPages = function(currentPage) { return [ makePage(currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false), makePage(currentPage + 1, nextText, paginationCtrl.noNext(), false, true) ]; }; } }; }]); /** * The following features are still outstanding: animation as a * function, placement as a function, inside, support for more triggers than * just mouse enter/leave, html tooltips, and selector delegation. */ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap.bindHtml' ] ) /** * The $tooltip service creates tooltip- and popover-like directives as well as * houses global options for them. */ .provider( '$tooltip', function () { // The default options tooltip and popover. var defaultOptions = { placement: 'top', animation: true, popupDelay: 0 }; // Default hide triggers for each show trigger var triggerMap = { 'mouseenter': 'mouseleave', 'click': 'click', 'focus': 'blur' }; // The options specified to the provider globally. var globalOptions = {}; /** * `options({})` allows global configuration of all tooltips in the * application. * * var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) { * // place tooltips left instead of top by default * $tooltipProvider.options( { placement: 'left' } ); * }); */ this.options = function( value ) { angular.extend( globalOptions, value ); }; /** * This allows you to extend the set of trigger mappings available. E.g.: * * $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' ); */ this.setTriggers = function setTriggers ( triggers ) { angular.extend( triggerMap, triggers ); }; /** * This is a helper function for translating camel-case to snake-case. */ function snake_case(name){ var regexp = /[A-Z]/g; var separator = '-'; return name.replace(regexp, function(letter, pos) { return (pos ? separator : '') + letter.toLowerCase(); }); } /** * Returns the actual instance of the $tooltip service. * TODO support multiple triggers */ this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function ( $window, $compile, $timeout, $parse, $document, $position, $interpolate ) { return function $tooltip ( type, prefix, defaultTriggerShow ) { var options = angular.extend( {}, defaultOptions, globalOptions ); /** * Returns an object of show and hide triggers. * * If a trigger is supplied, * it is used to show the tooltip; otherwise, it will use the `trigger` * option passed to the `$tooltipProvider.options` method; else it will * default to the trigger supplied to this directive factory. * * The hide trigger is based on the show trigger. If the `trigger` option * was passed to the `$tooltipProvider.options` method, it will use the * mapped trigger from `triggerMap` or the passed trigger if the map is * undefined; otherwise, it uses the `triggerMap` value of the show * trigger; else it will just use the show trigger. */ function getTriggers ( trigger ) { var show = trigger || options.trigger || defaultTriggerShow; var hide = triggerMap[show] || show; return { show: show, hide: hide }; } var directiveName = snake_case( type ); var startSym = $interpolate.startSymbol(); var endSym = $interpolate.endSymbol(); var template = '
'+ '
'; return { restrict: 'EA', scope: true, compile: function (tElem, tAttrs) { var tooltipLinker = $compile( template ); return function link ( scope, element, attrs ) { var tooltip; var transitionTimeout; var popupTimeout; var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false; var triggers = getTriggers( undefined ); var hasRegisteredTriggers = false; var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']); var positionTooltip = function (){ var position, ttWidth, ttHeight, ttPosition; // Get the position of the directive element. position = appendToBody ? $position.offset( element ) : $position.position( element ); // Get the height and width of the tooltip so we can center it. ttWidth = tooltip.prop( 'offsetWidth' ); ttHeight = tooltip.prop( 'offsetHeight' ); // Calculate the tooltip's top and left coordinates to center it with // this directive. switch ( scope.tt_placement ) { case 'right': ttPosition = { top: position.top + position.height / 2 - ttHeight / 2, left: position.left + position.width }; break; case 'bottom': ttPosition = { top: position.top + position.height, left: position.left + position.width / 2 - ttWidth / 2 }; break; case 'left': ttPosition = { top: position.top + position.height / 2 - ttHeight / 2, left: position.left - ttWidth }; break; default: ttPosition = { top: position.top - ttHeight, left: position.left + position.width / 2 - ttWidth / 2 }; break; } ttPosition.top += 'px'; ttPosition.left += 'px'; // Now set the calculated positioning. tooltip.css( ttPosition ); }; // By default, the tooltip is not open. // TODO add ability to start tooltip opened scope.tt_isOpen = false; function toggleTooltipBind () { if ( ! scope.tt_isOpen ) { showTooltipBind(); } else { hideTooltipBind(); } } // Show the tooltip with delay if specified, otherwise show it immediately function showTooltipBind() { if(hasEnableExp && !scope.$eval(attrs[prefix+'Enable'])) { return; } if ( scope.tt_popupDelay ) { popupTimeout = $timeout( show, scope.tt_popupDelay, false ); popupTimeout.then(function(reposition){reposition();}); } else { show()(); } } function hideTooltipBind () { scope.$apply(function () { hide(); }); } // Show the tooltip popup element. function show() { // Don't show empty tooltips. if ( ! scope.tt_content ) { return angular.noop; } createTooltip(); // If there is a pending remove transition, we must cancel it, lest the // tooltip be mysteriously removed. if ( transitionTimeout ) { $timeout.cancel( transitionTimeout ); } // Set the initial positioning. tooltip.css({ top: 0, left: 0, display: 'block' }); // Now we add it to the DOM because need some info about it. But it's not // visible yet anyway. if ( appendToBody ) { $document.find( 'body' ).append( tooltip ); } else { element.after( tooltip ); } positionTooltip(); // And show the tooltip. scope.tt_isOpen = true; scope.$digest(); // digest required as $apply is not called // Return positioning function as promise callback for correct // positioning after draw. return positionTooltip; } // Hide the tooltip popup element. function hide() { // First things first: we don't show it anymore. scope.tt_isOpen = false; //if tooltip is going to be shown after delay, we must cancel this $timeout.cancel( popupTimeout ); // And now we remove it from the DOM. However, if we have animation, we // need to wait for it to expire beforehand. // FIXME: this is a placeholder for a port of the transitions library. if ( scope.tt_animation ) { transitionTimeout = $timeout(removeTooltip, 500); } else { removeTooltip(); } } function createTooltip() { // There can only be one tooltip element per directive shown at once. if (tooltip) { removeTooltip(); } tooltip = tooltipLinker(scope, function () {}); // Get contents rendered into the tooltip scope.$digest(); } function removeTooltip() { if (tooltip) { tooltip.remove(); tooltip = null; } } /** * Observe the relevant attributes. */ attrs.$observe( type, function ( val ) { scope.tt_content = val; if (!val && scope.tt_isOpen ) { hide(); } }); attrs.$observe( prefix+'Title', function ( val ) { scope.tt_title = val; }); attrs.$observe( prefix+'Placement', function ( val ) { scope.tt_placement = angular.isDefined( val ) ? val : options.placement; }); attrs.$observe( prefix+'PopupDelay', function ( val ) { var delay = parseInt( val, 10 ); scope.tt_popupDelay = ! isNaN(delay) ? delay : options.popupDelay; }); var unregisterTriggers = function() { if (hasRegisteredTriggers) { element.unbind( triggers.show, showTooltipBind ); element.unbind( triggers.hide, hideTooltipBind ); } }; attrs.$observe( prefix+'Trigger', function ( val ) { unregisterTriggers(); triggers = getTriggers( val ); if ( triggers.show === triggers.hide ) { element.bind( triggers.show, toggleTooltipBind ); } else { element.bind( triggers.show, showTooltipBind ); element.bind( triggers.hide, hideTooltipBind ); } hasRegisteredTriggers = true; }); var animation = scope.$eval(attrs[prefix + 'Animation']); scope.tt_animation = angular.isDefined(animation) ? !!animation : options.animation; attrs.$observe( prefix+'AppendToBody', function ( val ) { appendToBody = angular.isDefined( val ) ? $parse( val )( scope ) : appendToBody; }); // if a tooltip is attached to we need to remove it on // location change as its parent scope will probably not be destroyed // by the change. if ( appendToBody ) { scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess () { if ( scope.tt_isOpen ) { hide(); } }); } // Make sure tooltip is destroyed and removed. scope.$on('$destroy', function onDestroyTooltip() { $timeout.cancel( transitionTimeout ); $timeout.cancel( popupTimeout ); unregisterTriggers(); removeTooltip(); }); }; } }; }; }]; }) .directive( 'tooltipPopup', function () { return { restrict: 'EA', replace: true, scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, templateUrl: 'template/tooltip/tooltip-popup.html' }; }) .directive( 'tooltip', [ '$tooltip', function ( $tooltip ) { return $tooltip( 'tooltip', 'tooltip', 'mouseenter' ); }]) .directive( 'tooltipHtmlUnsafePopup', function () { return { restrict: 'EA', replace: true, scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html' }; }) .directive( 'tooltipHtmlUnsafe', [ '$tooltip', function ( $tooltip ) { return $tooltip( 'tooltipHtmlUnsafe', 'tooltip', 'mouseenter' ); }]); /** * The following features are still outstanding: popup delay, animation as a * function, placement as a function, inside, support for more triggers than * just mouse enter/leave, html popovers, and selector delegatation. */ angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] ) .directive( 'popoverPopup', function () { return { restrict: 'EA', replace: true, scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' }, templateUrl: 'template/popover/popover.html' }; }) .directive( 'popover', [ '$tooltip', function ( $tooltip ) { return $tooltip( 'popover', 'popover', 'click' ); }]); angular.module('ui.bootstrap.progressbar', ['ui.bootstrap.transition']) .constant('progressConfig', { animate: true, max: 100 }) .controller('ProgressController', ['$scope', '$attrs', 'progressConfig', '$transition', function($scope, $attrs, progressConfig, $transition) { var self = this, bars = [], max = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : progressConfig.max, animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate; this.addBar = function(bar, element) { var oldValue = 0, index = bar.$parent.$index; if ( angular.isDefined(index) && bars[index] ) { oldValue = bars[index].value; } bars.push(bar); this.update(element, bar.value, oldValue); bar.$watch('value', function(value, oldValue) { if (value !== oldValue) { self.update(element, value, oldValue); } }); bar.$on('$destroy', function() { self.removeBar(bar); }); }; // Update bar element width this.update = function(element, newValue, oldValue) { var percent = this.getPercentage(newValue); if (animate) { element.css('width', this.getPercentage(oldValue) + '%'); $transition(element, {width: percent + '%'}); } else { element.css({'transition': 'none', 'width': percent + '%'}); } }; this.removeBar = function(bar) { bars.splice(bars.indexOf(bar), 1); }; this.getPercentage = function(value) { return Math.round(100 * value / max); }; }]) .directive('progress', function() { return { restrict: 'EA', replace: true, transclude: true, controller: 'ProgressController', require: 'progress', scope: {}, template: '
' //templateUrl: 'template/progressbar/progress.html' // Works in AngularJS 1.2 }; }) .directive('bar', function() { return { restrict: 'EA', replace: true, transclude: true, require: '^progress', scope: { value: '=', type: '@' }, templateUrl: 'template/progressbar/bar.html', link: function(scope, element, attrs, progressCtrl) { progressCtrl.addBar(scope, element); } }; }) .directive('progressbar', function() { return { restrict: 'EA', replace: true, transclude: true, controller: 'ProgressController', scope: { value: '=', type: '@' }, templateUrl: 'template/progressbar/progressbar.html', link: function(scope, element, attrs, progressCtrl) { progressCtrl.addBar(scope, angular.element(element.children()[0])); } }; }); angular.module('ui.bootstrap.rating', []) .constant('ratingConfig', { max: 5, stateOn: null, stateOff: null }) .controller('RatingController', ['$scope', '$attrs', '$parse', 'ratingConfig', function($scope, $attrs, $parse, ratingConfig) { this.maxRange = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max; this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn; this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff; this.createRateObjects = function(states) { var defaultOptions = { stateOn: this.stateOn, stateOff: this.stateOff }; for (var i = 0, n = states.length; i < n; i++) { states[i] = angular.extend({ index: i }, defaultOptions, states[i]); } return states; }; // Get objects used in template $scope.range = angular.isDefined($attrs.ratingStates) ? this.createRateObjects(angular.copy($scope.$parent.$eval($attrs.ratingStates))): this.createRateObjects(new Array(this.maxRange)); $scope.rate = function(value) { if ( $scope.value !== value && !$scope.readonly ) { $scope.value = value; } }; $scope.enter = function(value) { if ( ! $scope.readonly ) { $scope.val = value; } $scope.onHover({value: value}); }; $scope.reset = function() { $scope.val = angular.copy($scope.value); $scope.onLeave(); }; $scope.$watch('value', function(value) { $scope.val = value; }); $scope.readonly = false; if ($attrs.readonly) { $scope.$parent.$watch($parse($attrs.readonly), function(value) { $scope.readonly = !!value; }); } }]) .directive('rating', function() { return { restrict: 'EA', scope: { value: '=', onHover: '&', onLeave: '&' }, controller: 'RatingController', templateUrl: 'template/rating/rating.html', replace: true }; }); /** * @ngdoc overview * @name ui.bootstrap.tabs * * @description * AngularJS version of the tabs directive. */ angular.module('ui.bootstrap.tabs', []) .controller('TabsetController', ['$scope', function TabsetCtrl($scope) { var ctrl = this, tabs = ctrl.tabs = $scope.tabs = []; ctrl.select = function(tab) { angular.forEach(tabs, function(tab) { tab.active = false; }); tab.active = true; }; ctrl.addTab = function addTab(tab) { tabs.push(tab); if (tabs.length === 1 || tab.active) { ctrl.select(tab); } }; ctrl.removeTab = function removeTab(tab) { var index = tabs.indexOf(tab); //Select a new tab if the tab to be removed is selected if (tab.active && tabs.length > 1) { //If this is the last tab, select the previous tab. else, the next tab. var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1; ctrl.select(tabs[newActiveIndex]); } tabs.splice(index, 1); }; }]) /** * @ngdoc directive * @name ui.bootstrap.tabs.directive:tabset * @restrict EA * * @description * Tabset is the outer container for the tabs directive * * @param {boolean=} vertical Whether or not to use vertical styling for the tabs. * @param {boolean=} justified Whether or not to use justified styling for the tabs. * * @example First Content! Second Content!
First Vertical Content! Second Vertical Content! First Justified Content! Second Justified Content!
*/ .directive('tabset', function() { return { restrict: 'EA', transclude: true, replace: true, scope: {}, controller: 'TabsetController', templateUrl: 'template/tabs/tabset.html', link: function(scope, element, attrs) { scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false; scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false; scope.type = angular.isDefined(attrs.type) ? scope.$parent.$eval(attrs.type) : 'tabs'; } }; }) /** * @ngdoc directive * @name ui.bootstrap.tabs.directive:tab * @restrict EA * * @param {string=} heading The visible heading, or title, of the tab. Set HTML headings with {@link ui.bootstrap.tabs.directive:tabHeading tabHeading}. * @param {string=} select An expression to evaluate when the tab is selected. * @param {boolean=} active A binding, telling whether or not this tab is selected. * @param {boolean=} disabled A binding, telling whether or not this tab is disabled. * * @description * Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}. * * @example

First Tab Alert me! Second Tab, with alert callback and html heading! {{item.content}}
function TabsDemoCtrl($scope) { $scope.items = [ { title:"Dynamic Title 1", content:"Dynamic Item 0" }, { title:"Dynamic Title 2", content:"Dynamic Item 1", disabled: true } ]; $scope.alertMe = function() { setTimeout(function() { alert("You've selected the alert tab!"); }); }; };
*/ /** * @ngdoc directive * @name ui.bootstrap.tabs.directive:tabHeading * @restrict EA * * @description * Creates an HTML heading for a {@link ui.bootstrap.tabs.directive:tab tab}. Must be placed as a child of a tab element. * * @example HTML in my titles?! And some content, too! Icon heading?!? That's right. */ .directive('tab', ['$parse', function($parse) { return { require: '^tabset', restrict: 'EA', replace: true, templateUrl: 'template/tabs/tab.html', transclude: true, scope: { heading: '@', onSelect: '&select', //This callback is called in contentHeadingTransclude //once it inserts the tab's content into the dom onDeselect: '&deselect' }, controller: function() { //Empty controller so other directives can require being 'under' a tab }, compile: function(elm, attrs, transclude) { return function postLink(scope, elm, attrs, tabsetCtrl) { var getActive, setActive; if (attrs.active) { getActive = $parse(attrs.active); setActive = getActive.assign; scope.$parent.$watch(getActive, function updateActive(value, oldVal) { // Avoid re-initializing scope.active as it is already initialized // below. (watcher is called async during init with value === // oldVal) if (value !== oldVal) { scope.active = !!value; } }); scope.active = getActive(scope.$parent); } else { setActive = getActive = angular.noop; } scope.$watch('active', function(active) { // Note this watcher also initializes and assigns scope.active to the // attrs.active expression. setActive(scope.$parent, active); if (active) { tabsetCtrl.select(scope); scope.onSelect(); } else { scope.onDeselect(); } }); scope.disabled = false; if ( attrs.disabled ) { scope.$parent.$watch($parse(attrs.disabled), function(value) { scope.disabled = !! value; }); } scope.select = function() { if ( ! scope.disabled ) { scope.active = true; } }; tabsetCtrl.addTab(scope); scope.$on('$destroy', function() { tabsetCtrl.removeTab(scope); }); //We need to transclude later, once the content container is ready. //when this link happens, we're inside a tab heading. scope.$transcludeFn = transclude; }; } }; }]) .directive('tabHeadingTransclude', [function() { return { restrict: 'A', require: '^tab', link: function(scope, elm, attrs, tabCtrl) { scope.$watch('headingElement', function updateHeadingElement(heading) { if (heading) { elm.html(''); elm.append(heading); } }); } }; }]) .directive('tabContentTransclude', function() { return { restrict: 'A', require: '^tabset', link: function(scope, elm, attrs) { var tab = scope.$eval(attrs.tabContentTransclude); //Now our tab is ready to be transcluded: both the tab heading area //and the tab content area are loaded. Transclude 'em both. tab.$transcludeFn(tab.$parent, function(contents) { angular.forEach(contents, function(node) { if (isTabHeading(node)) { //Let tabHeadingTransclude know. tab.headingElement = node; } else { elm.append(node); } }); }); } }; function isTabHeading(node) { return node.tagName && ( node.hasAttribute('tab-heading') || node.hasAttribute('data-tab-heading') || node.tagName.toLowerCase() === 'tab-heading' || node.tagName.toLowerCase() === 'data-tab-heading' ); } }) ; angular.module('ui.bootstrap.timepicker', []) .constant('timepickerConfig', { hourStep: 1, minuteStep: 1, showMeridian: true, meridians: null, readonlyInput: false, mousewheel: true }) .directive('timepicker', ['$parse', '$log', 'timepickerConfig', '$locale', function ($parse, $log, timepickerConfig, $locale) { return { restrict: 'EA', require:'?^ngModel', replace: true, scope: {}, templateUrl: 'template/timepicker/timepicker.html', link: function(scope, element, attrs, ngModel) { if ( !ngModel ) { return; // do nothing if no ng-model } var selected = new Date(), meridians = angular.isDefined(attrs.meridians) ? scope.$parent.$eval(attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS; var hourStep = timepickerConfig.hourStep; if (attrs.hourStep) { scope.$parent.$watch($parse(attrs.hourStep), function(value) { hourStep = parseInt(value, 10); }); } var minuteStep = timepickerConfig.minuteStep; if (attrs.minuteStep) { scope.$parent.$watch($parse(attrs.minuteStep), function(value) { minuteStep = parseInt(value, 10); }); } // 12H / 24H mode scope.showMeridian = timepickerConfig.showMeridian; if (attrs.showMeridian) { scope.$parent.$watch($parse(attrs.showMeridian), function(value) { scope.showMeridian = !!value; if ( ngModel.$error.time ) { // Evaluate from template var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate(); if (angular.isDefined( hours ) && angular.isDefined( minutes )) { selected.setHours( hours ); refresh(); } } else { updateTemplate(); } }); } // Get scope.hours in 24H mode if valid function getHoursFromTemplate ( ) { var hours = parseInt( scope.hours, 10 ); var valid = ( scope.showMeridian ) ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24); if ( !valid ) { return undefined; } if ( scope.showMeridian ) { if ( hours === 12 ) { hours = 0; } if ( scope.meridian === meridians[1] ) { hours = hours + 12; } } return hours; } function getMinutesFromTemplate() { var minutes = parseInt(scope.minutes, 10); return ( minutes >= 0 && minutes < 60 ) ? minutes : undefined; } function pad( value ) { return ( angular.isDefined(value) && value.toString().length < 2 ) ? '0' + value : value; } // Input elements var inputs = element.find('input'), hoursInputEl = inputs.eq(0), minutesInputEl = inputs.eq(1); // Respond on mousewheel spin var mousewheel = (angular.isDefined(attrs.mousewheel)) ? scope.$eval(attrs.mousewheel) : timepickerConfig.mousewheel; if ( mousewheel ) { var isScrollingUp = function(e) { if (e.originalEvent) { e = e.originalEvent; } //pick correct delta variable depending on event var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY; return (e.detail || delta > 0); }; hoursInputEl.bind('mousewheel wheel', function(e) { scope.$apply( (isScrollingUp(e)) ? scope.incrementHours() : scope.decrementHours() ); e.preventDefault(); }); minutesInputEl.bind('mousewheel wheel', function(e) { scope.$apply( (isScrollingUp(e)) ? scope.incrementMinutes() : scope.decrementMinutes() ); e.preventDefault(); }); } scope.readonlyInput = (angular.isDefined(attrs.readonlyInput)) ? scope.$eval(attrs.readonlyInput) : timepickerConfig.readonlyInput; if ( ! scope.readonlyInput ) { var invalidate = function(invalidHours, invalidMinutes) { ngModel.$setViewValue( null ); ngModel.$setValidity('time', false); if (angular.isDefined(invalidHours)) { scope.invalidHours = invalidHours; } if (angular.isDefined(invalidMinutes)) { scope.invalidMinutes = invalidMinutes; } }; scope.updateHours = function() { var hours = getHoursFromTemplate(); if ( angular.isDefined(hours) ) { selected.setHours( hours ); refresh( 'h' ); } else { invalidate(true); } }; hoursInputEl.bind('blur', function(e) { if ( !scope.validHours && scope.hours < 10) { scope.$apply( function() { scope.hours = pad( scope.hours ); }); } }); scope.updateMinutes = function() { var minutes = getMinutesFromTemplate(); if ( angular.isDefined(minutes) ) { selected.setMinutes( minutes ); refresh( 'm' ); } else { invalidate(undefined, true); } }; minutesInputEl.bind('blur', function(e) { if ( !scope.invalidMinutes && scope.minutes < 10 ) { scope.$apply( function() { scope.minutes = pad( scope.minutes ); }); } }); } else { scope.updateHours = angular.noop; scope.updateMinutes = angular.noop; } ngModel.$render = function() { var date = ngModel.$modelValue ? new Date( ngModel.$modelValue ) : null; if ( isNaN(date) ) { ngModel.$setValidity('time', false); $log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'); } else { if ( date ) { selected = date; } makeValid(); updateTemplate(); } }; // Call internally when we know that model is valid. function refresh( keyboardChange ) { makeValid(); ngModel.$setViewValue( new Date(selected) ); updateTemplate( keyboardChange ); } function makeValid() { ngModel.$setValidity('time', true); scope.invalidHours = false; scope.invalidMinutes = false; } function updateTemplate( keyboardChange ) { var hours = selected.getHours(), minutes = selected.getMinutes(); if ( scope.showMeridian ) { hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12; // Convert 24 to 12 hour system } scope.hours = keyboardChange === 'h' ? hours : pad(hours); scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes); scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1]; } function addMinutes( minutes ) { var dt = new Date( selected.getTime() + minutes * 60000 ); selected.setHours( dt.getHours(), dt.getMinutes() ); refresh(); } scope.incrementHours = function() { addMinutes( hourStep * 60 ); }; scope.decrementHours = function() { addMinutes( - hourStep * 60 ); }; scope.incrementMinutes = function() { addMinutes( minuteStep ); }; scope.decrementMinutes = function() { addMinutes( - minuteStep ); }; scope.toggleMeridian = function() { addMinutes( 12 * 60 * (( selected.getHours() < 12 ) ? 1 : -1) ); }; } }; }]); angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap.bindHtml']) /** * A helper service that can parse typeahead's syntax (string provided by users) * Extracted to a separate service for ease of unit testing */ .factory('typeaheadParser', ['$parse', function ($parse) { // 00000111000000000000022200000000000000003333333333333330000000000044000 var TYPEAHEAD_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+(.*)$/; return { parse:function (input) { var match = input.match(TYPEAHEAD_REGEXP), modelMapper, viewMapper, source; if (!match) { throw new Error( "Expected typeahead specification in form of '_modelValue_ (as _label_)? for _item_ in _collection_'" + " but got '" + input + "'."); } return { itemName:match[3], source:$parse(match[4]), viewMapper:$parse(match[2] || match[1]), modelMapper:$parse(match[1]) }; } }; }]) .directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser', function ($compile, $parse, $q, $timeout, $document, $position, typeaheadParser) { var HOT_KEYS = [9, 13, 27, 38, 40]; return { require:'ngModel', link:function (originalScope, element, attrs, modelCtrl) { //SUPPORTED ATTRIBUTES (OPTIONS) //minimal no of characters that needs to be entered before typeahead kicks-in var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1; //minimal wait time after last character typed before typehead kicks-in var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0; //should it restrict model values to the ones selected from the popup only? var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false; //binding to a variable that indicates if matches are being retrieved asynchronously var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop; //a callback executed when a match is selected var onSelectCallback = $parse(attrs.typeaheadOnSelect); var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined; var appendToBody = attrs.typeaheadAppendToBody ? $parse(attrs.typeaheadAppendToBody) : false; //INTERNAL VARIABLES //model setter executed upon match selection var $setModelValue = $parse(attrs.ngModel).assign; //expressions used by typeahead var parserResult = typeaheadParser.parse(attrs.typeahead); var hasFocus; //pop-up element used to display matches var popUpEl = angular.element('
'); popUpEl.attr({ matches: 'matches', active: 'activeIdx', select: 'select(activeIdx)', query: 'query', position: 'position' }); //custom item template if (angular.isDefined(attrs.typeaheadTemplateUrl)) { popUpEl.attr('template-url', attrs.typeaheadTemplateUrl); } //create a child scope for the typeahead directive so we are not polluting original scope //with typeahead-specific data (matches, query etc.) var scope = originalScope.$new(); originalScope.$on('$destroy', function(){ scope.$destroy(); }); var resetMatches = function() { scope.matches = []; scope.activeIdx = -1; }; var getMatchesAsync = function(inputValue) { var locals = {$viewValue: inputValue}; isLoadingSetter(originalScope, true); $q.when(parserResult.source(originalScope, locals)).then(function(matches) { //it might happen that several async queries were in progress if a user were typing fast //but we are interested only in responses that correspond to the current view value if (inputValue === modelCtrl.$viewValue && hasFocus) { if (matches.length > 0) { scope.activeIdx = 0; scope.matches.length = 0; //transform labels for(var i=0; i= minSearch) { if (waitTime > 0) { if (timeoutPromise) { $timeout.cancel(timeoutPromise);//cancel previous timeout } timeoutPromise = $timeout(function () { getMatchesAsync(inputValue); }, waitTime); } else { getMatchesAsync(inputValue); } } else { isLoadingSetter(originalScope, false); resetMatches(); } if (isEditable) { return inputValue; } else { if (!inputValue) { // Reset in case user had typed something previously. modelCtrl.$setValidity('editable', true); return inputValue; } else { modelCtrl.$setValidity('editable', false); return undefined; } } }); modelCtrl.$formatters.push(function (modelValue) { var candidateViewValue, emptyViewValue; var locals = {}; if (inputFormatter) { locals['$model'] = modelValue; return inputFormatter(originalScope, locals); } else { //it might happen that we don't have enough info to properly render input value //we need to check for this situation and simply return model value if we can't apply custom formatting locals[parserResult.itemName] = modelValue; candidateViewValue = parserResult.viewMapper(originalScope, locals); locals[parserResult.itemName] = undefined; emptyViewValue = parserResult.viewMapper(originalScope, locals); return candidateViewValue!== emptyViewValue ? candidateViewValue : modelValue; } }); scope.select = function (activeIdx) { //called from within the $digest() cycle var locals = {}; var model, item; locals[parserResult.itemName] = item = scope.matches[activeIdx].model; model = parserResult.modelMapper(originalScope, locals); $setModelValue(originalScope, model); modelCtrl.$setValidity('editable', true); onSelectCallback(originalScope, { $item: item, $model: model, $label: parserResult.viewMapper(originalScope, locals) }); resetMatches(); //return focus to the input element if a mach was selected via a mouse click event element[0].focus(); }; //bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27) element.bind('keydown', function (evt) { //typeahead is open and an "interesting" key was pressed if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) { return; } evt.preventDefault(); if (evt.which === 40) { scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length; scope.$digest(); } else if (evt.which === 38) { scope.activeIdx = (scope.activeIdx ? scope.activeIdx : scope.matches.length) - 1; scope.$digest(); } else if (evt.which === 13 || evt.which === 9) { scope.$apply(function () { scope.select(scope.activeIdx); }); } else if (evt.which === 27) { evt.stopPropagation(); resetMatches(); scope.$digest(); } }); element.bind('blur', function (evt) { hasFocus = false; }); // Keep reference to click handler to unbind it. var dismissClickHandler = function (evt) { if (element[0] !== evt.target) { resetMatches(); scope.$digest(); } }; $document.bind('click', dismissClickHandler); originalScope.$on('$destroy', function(){ $document.unbind('click', dismissClickHandler); }); var $popup = $compile(popUpEl)(scope); if ( appendToBody ) { $document.find('body').append($popup); } else { element.after($popup); } } }; }]) .directive('typeaheadPopup', function () { return { restrict:'EA', scope:{ matches:'=', query:'=', active:'=', position:'=', select:'&' }, replace:true, templateUrl:'template/typeahead/typeahead-popup.html', link:function (scope, element, attrs) { scope.templateUrl = attrs.templateUrl; scope.isOpen = function () { return scope.matches.length > 0; }; scope.isActive = function (matchIdx) { return scope.active == matchIdx; }; scope.selectActive = function (matchIdx) { scope.active = matchIdx; }; scope.selectMatch = function (activeIdx) { scope.select({activeIdx:activeIdx}); }; } }; }) .directive('typeaheadMatch', ['$http', '$templateCache', '$compile', '$parse', function ($http, $templateCache, $compile, $parse) { return { restrict:'EA', scope:{ index:'=', match:'=', query:'=' }, link:function (scope, element, attrs) { var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'template/typeahead/typeahead-match.html'; $http.get(tplUrl, {cache: $templateCache}).success(function(tplContent){ element.replaceWith($compile(tplContent.trim())(scope)); }); } }; }]) .filter('typeaheadHighlight', function() { function escapeRegexp(queryToEscape) { return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); } return function(matchItem, query) { return query ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '$&') : matchItem; }; }); angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/accordion/accordion-group.html", "
\n" + "
\n" + "

\n" + " {{heading}}\n" + "

\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
"); }]); angular.module("template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/accordion/accordion.html", "
"); }]); angular.module("template/alert/alert.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/alert/alert.html", "
\n" + " \n" + "
\n" + "
\n" + ""); }]); angular.module("template/carousel/carousel.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/carousel/carousel.html", "
\n" + "
    1\">\n" + "
  1. \n" + "
\n" + "
\n" + " 1\">\n" + " 1\">\n" + "
\n" + ""); }]); angular.module("template/carousel/slide.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/carousel/slide.html", "
\n" + ""); }]); angular.module("template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/datepicker/datepicker.html", "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 0\" class=\"h6\">\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
#{{label}}
{{ getWeekNumber(row) }}\n" + " \n" + "
\n" + ""); }]); angular.module("template/datepicker/popup.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/datepicker/popup.html", "
    \n" + "
  • \n" + "
  • \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
  • \n" + "
\n" + ""); }]); angular.module("template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/modal/backdrop.html", "
"); }]); angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/modal/window.html", "
\n" + "
\n" + "
"); }]); angular.module("template/pagination/pager.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/pagination/pager.html", ""); }]); angular.module("template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/pagination/pagination.html", ""); }]); angular.module("template/tooltip/tooltip-html-unsafe-popup.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/tooltip/tooltip-html-unsafe-popup.html", "
\n" + "
\n" + "
\n" + "
\n" + ""); }]); angular.module("template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/tooltip/tooltip-popup.html", "
\n" + "
\n" + "
\n" + "
\n" + ""); }]); angular.module("template/popover/popover.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/popover/popover.html", "
\n" + "
\n" + "\n" + "
\n" + "

\n" + "
\n" + "
\n" + "
\n" + ""); }]); angular.module("template/progressbar/bar.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/progressbar/bar.html", "
"); }]); angular.module("template/progressbar/progress.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/progressbar/progress.html", "
"); }]); angular.module("template/progressbar/progressbar.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/progressbar/progressbar.html", "
"); }]); angular.module("template/rating/rating.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/rating/rating.html", "\n" + " \n" + ""); }]); angular.module("template/tabs/tab.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/tabs/tab.html", "
  • \n" + " {{heading}}\n" + "
  • \n" + ""); }]); angular.module("template/tabs/tabset-titles.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/tabs/tabset-titles.html", "
      \n" + "
    \n" + ""); }]); angular.module("template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/tabs/tabset.html", "\n" + "
    \n" + "
      \n" + "
      \n" + "
      \n" + "
      \n" + "
      \n" + "
      \n" + ""); }]); angular.module("template/timepicker/timepicker.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/timepicker/timepicker.html", "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
       
      \n" + " \n" + " :\n" + " \n" + "
       
      \n" + ""); }]); angular.module("template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/typeahead/typeahead-match.html", ""); }]); angular.module("template/typeahead/typeahead-popup.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/typeahead/typeahead-popup.html", "
        \n" + "
      • \n" + "
        \n" + "
      • \n" + "
      "); }]); // Source: public/lib/angular-ui-utils/ui-utils.min.js /** * angular-ui-utils - Swiss-Army-Knife of AngularJS tools (with no external dependencies!) * @version v0.1.1 - 2014-02-05 * @link http://angular-ui.github.com * @license MIT License, http://www.opensource.org/licenses/MIT */ angular.module("ui.alias",[]).config(["$compileProvider","uiAliasConfig",function(a,b){b=b||{},angular.forEach(b,function(b,c){angular.isString(b)&&(b={replace:!0,template:b}),a.directive(c,function(){return b})})}]),angular.module("ui.event",[]).directive("uiEvent",["$parse",function(a){return function(b,c,d){var e=b.$eval(d.uiEvent);angular.forEach(e,function(d,e){var f=a(d);c.bind(e,function(a){var c=Array.prototype.slice.call(arguments);c=c.splice(1),f(b,{$event:a,$params:c}),b.$$phase||b.$apply()})})}}]),angular.module("ui.format",[]).filter("format",function(){return function(a,b){var c=a;if(angular.isString(c)&&void 0!==b)if(angular.isArray(b)||angular.isObject(b)||(b=[b]),angular.isArray(b)){var d=b.length,e=function(a,c){return c=parseInt(c,10),c>=0&&d>c?b[c]:a};c=c.replace(/\$([0-9]+)/g,e)}else angular.forEach(b,function(a,b){c=c.split(":"+b).join(a)});return c}}),angular.module("ui.highlight",[]).filter("highlight",function(){return function(a,b,c){return b||angular.isNumber(b)?(a=a.toString(),b=b.toString(),c?a.split(b).join(''+b+""):a.replace(new RegExp(b,"gi"),'$&')):a}}),angular.module("ui.include",[]).directive("uiInclude",["$http","$templateCache","$anchorScroll","$compile",function(a,b,c,d){return{restrict:"ECA",terminal:!0,compile:function(e,f){var g=f.uiInclude||f.src,h=f.fragment||"",i=f.onload||"",j=f.autoscroll;return function(e,f){function k(){var k=++m,o=e.$eval(g),p=e.$eval(h);o?a.get(o,{cache:b}).success(function(a){if(k===m){l&&l.$destroy(),l=e.$new();var b;b=p?angular.element("
      ").html(a).find(p):angular.element("
      ").html(a).contents(),f.html(b),d(b)(l),!angular.isDefined(j)||j&&!e.$eval(j)||c(),l.$emit("$includeContentLoaded"),e.$eval(i)}}).error(function(){k===m&&n()}):n()}var l,m=0,n=function(){l&&(l.$destroy(),l=null),f.html("")};e.$watch(h,k),e.$watch(g,k)}}}}]),angular.module("ui.indeterminate",[]).directive("uiIndeterminate",[function(){return{compile:function(a,b){return b.type&&"checkbox"===b.type.toLowerCase()?function(a,b,c){a.$watch(c.uiIndeterminate,function(a){b[0].indeterminate=!!a})}:angular.noop}}}]),angular.module("ui.inflector",[]).filter("inflector",function(){function a(a){return a.replace(/^([a-z])|\s+([a-z])/g,function(a){return a.toUpperCase()})}function b(a,b){return a.replace(/[A-Z]/g,function(a){return b+a})}var c={humanize:function(c){return a(b(c," ").split("_").join(" "))},underscore:function(a){return a.substr(0,1).toLowerCase()+b(a.substr(1),"_").toLowerCase().split(" ").join("_")},variable:function(b){return b=b.substr(0,1).toLowerCase()+a(b.split("_").join(" ")).substr(1).split(" ").join("")}};return function(a,b){return b!==!1&&angular.isString(a)?(b=b||"humanize",c[b](a)):a}}),angular.module("ui.jq",[]).value("uiJqConfig",{}).directive("uiJq",["uiJqConfig","$timeout",function(a,b){return{restrict:"A",compile:function(c,d){if(!angular.isFunction(c[d.uiJq]))throw new Error('ui-jq: The "'+d.uiJq+'" function does not exist');var e=a&&a[d.uiJq];return function(a,c,d){function f(){b(function(){c[d.uiJq].apply(c,g)},0,!1)}var g=[];d.uiOptions?(g=a.$eval("["+d.uiOptions+"]"),angular.isObject(e)&&angular.isObject(g[0])&&(g[0]=angular.extend({},e,g[0]))):e&&(g=[e]),d.ngModel&&c.is("select,input,textarea")&&c.bind("change",function(){c.trigger("input")}),d.uiRefresh&&a.$watch(d.uiRefresh,function(){f()}),f()}}}}]),angular.module("ui.keypress",[]).factory("keypressHelper",["$parse",function(a){var b={8:"backspace",9:"tab",13:"enter",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"delete"},c=function(a){return a.charAt(0).toUpperCase()+a.slice(1)};return function(d,e,f,g){var h,i=[];h=e.$eval(g["ui"+c(d)]),angular.forEach(h,function(b,c){var d,e;e=a(b),angular.forEach(c.split(" "),function(a){d={expression:e,keys:{}},angular.forEach(a.split("-"),function(a){d.keys[a]=!0}),i.push(d)})}),f.bind(d,function(a){var c=!(!a.metaKey||a.ctrlKey),f=!!a.altKey,g=!!a.ctrlKey,h=!!a.shiftKey,j=a.keyCode;"keypress"===d&&!h&&j>=97&&122>=j&&(j-=32),angular.forEach(i,function(d){var i=d.keys[b[j]]||d.keys[j.toString()],k=!!d.keys.meta,l=!!d.keys.alt,m=!!d.keys.ctrl,n=!!d.keys.shift;i&&k===c&&l===f&&m===g&&n===h&&e.$apply(function(){d.expression(e,{$event:a})})})})}}]),angular.module("ui.keypress").directive("uiKeydown",["keypressHelper",function(a){return{link:function(b,c,d){a("keydown",b,c,d)}}}]),angular.module("ui.keypress").directive("uiKeypress",["keypressHelper",function(a){return{link:function(b,c,d){a("keypress",b,c,d)}}}]),angular.module("ui.keypress").directive("uiKeyup",["keypressHelper",function(a){return{link:function(b,c,d){a("keyup",b,c,d)}}}]),angular.module("ui.mask",[]).value("uiMaskConfig",{maskDefinitions:{9:/\d/,A:/[a-zA-Z]/,"*":/[a-zA-Z0-9]/}}).directive("uiMask",["uiMaskConfig",function(a){return{priority:100,require:"ngModel",restrict:"A",compile:function(){var b=a;return function(a,c,d,e){function f(a){return angular.isDefined(a)?(s(a),N?(k(),l(),!0):j()):j()}function g(a){angular.isDefined(a)&&(D=a,N&&w())}function h(a){return N?(G=o(a||""),I=n(G),e.$setValidity("mask",I),I&&G.length?p(G):void 0):a}function i(a){return N?(G=o(a||""),I=n(G),e.$viewValue=G.length?p(G):"",e.$setValidity("mask",I),""===G&&void 0!==e.$error.required&&e.$setValidity("required",!1),I?G:void 0):a}function j(){return N=!1,m(),angular.isDefined(P)?c.attr("placeholder",P):c.removeAttr("placeholder"),angular.isDefined(Q)?c.attr("maxlength",Q):c.removeAttr("maxlength"),c.val(e.$modelValue),e.$viewValue=e.$modelValue,!1}function k(){G=K=o(e.$modelValue||""),H=J=p(G),I=n(G);var a=I&&G.length?H:"";d.maxlength&&c.attr("maxlength",2*B[B.length-1]),c.attr("placeholder",D),c.val(a),e.$viewValue=a}function l(){O||(c.bind("blur",t),c.bind("mousedown mouseup",u),c.bind("input keyup click focus",w),O=!0)}function m(){O&&(c.unbind("blur",t),c.unbind("mousedown",u),c.unbind("mouseup",u),c.unbind("input",w),c.unbind("keyup",w),c.unbind("click",w),c.unbind("focus",w),O=!1)}function n(a){return a.length?a.length>=F:!0}function o(a){var b="",c=C.slice();return a=a.toString(),angular.forEach(E,function(b){a=a.replace(b,"")}),angular.forEach(a.split(""),function(a){c.length&&c[0].test(a)&&(b+=a,c.shift())}),b}function p(a){var b="",c=B.slice();return angular.forEach(D.split(""),function(d,e){a.length&&e===c[0]?(b+=a.charAt(0)||"_",a=a.substr(1),c.shift()):b+=d}),b}function q(a){var b=d.placeholder;return"undefined"!=typeof b&&b[a]?b[a]:"_"}function r(){return D.replace(/[_]+/g,"_").replace(/([^_]+)([a-zA-Z0-9])([^_])/g,"$1$2_$3").split("_")}function s(a){var b=0;if(B=[],C=[],D="","string"==typeof a){F=0;var c=!1,d=a.split("");angular.forEach(d,function(a,d){R.maskDefinitions[a]?(B.push(b),D+=q(d),C.push(R.maskDefinitions[a]),b++,c||F++):"?"===a?c=!0:(D+=a,b++)})}B.push(B.slice().pop()+1),E=r(),N=B.length>1?!0:!1}function t(){L=0,M=0,I&&0!==G.length||(H="",c.val(""),a.$apply(function(){e.$setViewValue("")}))}function u(a){"mousedown"===a.type?c.bind("mouseout",v):c.unbind("mouseout",v)}function v(){M=A(this),c.unbind("mouseout",v)}function w(b){b=b||{};var d=b.which,f=b.type;if(16!==d&&91!==d){var g,h=c.val(),i=J,j=o(h),k=K,l=!1,m=y(this)||0,n=L||0,q=m-n,r=B[0],s=B[j.length]||B.slice().shift(),t=M||0,u=A(this)>0,v=t>0,w=h.length>i.length||t&&h.length>i.length-t,C=h.length=37&&40>=d&&b.shiftKey,E=37===d,F=8===d||"keyup"!==f&&C&&-1===q,G=46===d||"keyup"!==f&&C&&0===q&&!v,H=(E||F||"click"===f)&&m>r;if(M=A(this),!D&&(!u||"click"!==f&&"keyup"!==f)){if("input"===f&&C&&!v&&j===k){for(;F&&m>r&&!x(m);)m--;for(;G&&s>m&&-1===B.indexOf(m);)m++;var I=B.indexOf(m);j=j.substring(0,I)+j.substring(I+1),l=!0}for(g=p(j),J=g,K=j,c.val(g),l&&a.$apply(function(){e.$setViewValue(j)}),w&&r>=m&&(m=r+1),H&&m--,m=m>s?s:r>m?r:m;!x(m)&&m>r&&s>m;)m+=H?-1:1;(H&&s>m||w&&!x(n))&&m++,L=m,z(this,m)}}}function x(a){return B.indexOf(a)>-1}function y(a){if(!a)return 0;if(void 0!==a.selectionStart)return a.selectionStart;if(document.selection){a.focus();var b=document.selection.createRange();return b.moveStart("character",-a.value.length),b.text.length}return 0}function z(a,b){if(!a)return 0;if(0!==a.offsetWidth&&0!==a.offsetHeight)if(a.setSelectionRange)a.focus(),a.setSelectionRange(b,b);else if(a.createTextRange){var c=a.createTextRange();c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",b),c.select()}}function A(a){return a?void 0!==a.selectionStart?a.selectionEnd-a.selectionStart:document.selection?document.selection.createRange().text.length:0:0}var B,C,D,E,F,G,H,I,J,K,L,M,N=!1,O=!1,P=d.placeholder,Q=d.maxlength,R={};d.uiOptions?(R=a.$eval("["+d.uiOptions+"]"),angular.isObject(R[0])&&(R=function(a,b){for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(b[c]?angular.extend(b[c],a[c]):b[c]=angular.copy(a[c]));return b}(b,R[0]))):R=b,d.$observe("uiMask",f),d.$observe("placeholder",g),e.$formatters.push(h),e.$parsers.push(i),c.bind("mousedown mouseup",u),Array.prototype.indexOf||(Array.prototype.indexOf=function(a){if(null===this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=0;if(arguments.length>1&&(d=Number(arguments[1]),d!==d?d=0:0!==d&&1/0!==d&&d!==-1/0&&(d=(d>0||-1)*Math.floor(Math.abs(d)))),d>=c)return-1;for(var e=d>=0?d:Math.max(c-Math.abs(d),0);c>e;e++)if(e in b&&b[e]===a)return e;return-1})}}}}]),angular.module("ui.reset",[]).value("uiResetConfig",null).directive("uiReset",["uiResetConfig",function(a){var b=null;return void 0!==a&&(b=a),{require:"ngModel",link:function(a,c,d,e){var f;f=angular.element(''),c.wrap('').after(f),f.bind("click",function(c){c.preventDefault(),a.$apply(function(){e.$setViewValue(d.uiReset?a.$eval(d.uiReset):b),e.$render()})})}}}]),angular.module("ui.route",[]).directive("uiRoute",["$location","$parse",function(a,b){return{restrict:"AC",scope:!0,compile:function(c,d){var e;if(d.uiRoute)e="uiRoute";else if(d.ngHref)e="ngHref";else{if(!d.href)throw new Error("uiRoute missing a route or href property on "+c[0]);e="href"}return function(c,d,f){function g(b){var d=b.indexOf("#");d>-1&&(b=b.substr(d+1)),(j=function(){i(c,a.path().indexOf(b)>-1)})()}function h(b){var d=b.indexOf("#");d>-1&&(b=b.substr(d+1)),(j=function(){var d=new RegExp("^"+b+"$",["i"]);i(c,d.test(a.path()))})()}var i=b(f.ngModel||f.routeModel||"$uiRoute").assign,j=angular.noop;switch(e){case"uiRoute":f.uiRoute?h(f.uiRoute):f.$observe("uiRoute",h);break;case"ngHref":f.ngHref?g(f.ngHref):f.$observe("ngHref",g);break;case"href":g(f.href)}c.$on("$routeChangeSuccess",function(){j()}),c.$on("$stateChangeSuccess",function(){j()})}}}}]),angular.module("ui.scroll.jqlite",["ui.scroll"]).service("jqLiteExtras",["$log","$window",function(a,b){return{registerFor:function(a){var c,d,e,f,g,h,i;return d=angular.element.prototype.css,a.prototype.css=function(a,b){var c,e;return e=this,c=e[0],c&&3!==c.nodeType&&8!==c.nodeType&&c.style?d.call(e,a,b):void 0},h=function(a){return a&&a.document&&a.location&&a.alert&&a.setInterval},i=function(a,b,c){var d,e,f,g,i;return d=a[0],i={top:["scrollTop","pageYOffset","scrollLeft"],left:["scrollLeft","pageXOffset","scrollTop"]}[b],e=i[0],g=i[1],f=i[2],h(d)?angular.isDefined(c)?d.scrollTo(a[f].call(a),c):g in d?d[g]:d.document.documentElement[e]:angular.isDefined(c)?d[e]=c:d[e]},b.getComputedStyle?(f=function(a){return b.getComputedStyle(a,null)},c=function(a,b){return parseFloat(b)}):(f=function(a){return a.currentStyle},c=function(a,b){var c,d,e,f,g,h,i;return c=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,f=new RegExp("^("+c+")(?!px)[a-z%]+$","i"),f.test(b)?(i=a.style,d=i.left,g=a.runtimeStyle,h=g&&g.left,g&&(g.left=i.left),i.left=b,e=i.pixelLeft,i.left=d,h&&(g.left=h),e):parseFloat(b)}),e=function(a,b){var d,e,g,i,j,k,l,m,n,o,p,q,r;return h(a)?(d=document.documentElement[{height:"clientHeight",width:"clientWidth"}[b]],{base:d,padding:0,border:0,margin:0}):(r={width:[a.offsetWidth,"Left","Right"],height:[a.offsetHeight,"Top","Bottom"]}[b],d=r[0],l=r[1],m=r[2],k=f(a),p=c(a,k["padding"+l])||0,q=c(a,k["padding"+m])||0,e=c(a,k["border"+l+"Width"])||0,g=c(a,k["border"+m+"Width"])||0,i=k["margin"+l],j=k["margin"+m],n=c(a,i)||0,o=c(a,j)||0,{base:d,padding:p+q,border:e+g,margin:n+o})},g=function(a,b,c){var d,g,h;return g=e(a,b),g.base>0?{base:g.base-g.padding-g.border,outer:g.base,outerfull:g.base+g.margin}[c]:(d=f(a),h=d[b],(0>h||null===h)&&(h=a.style[b]||0),h=parseFloat(h)||0,{base:h-g.padding-g.border,outer:h,outerfull:h+g.padding+g.border+g.margin}[c])},angular.forEach({before:function(a){var b,c,d,e,f,g,h;if(f=this,c=f[0],e=f.parent(),b=e.contents(),b[0]===c)return e.prepend(a);for(d=g=1,h=b.length-1;h>=1?h>=g:g>=h;d=h>=1?++g:--g)if(b[d]===c)return void angular.element(b[d-1]).after(a);throw new Error("invalid DOM structure "+c.outerHTML)},height:function(a){var b;return b=this,angular.isDefined(a)?(angular.isNumber(a)&&(a+="px"),d.call(b,"height",a)):g(this[0],"height","base")},outerHeight:function(a){return g(this[0],"height",a?"outerfull":"outer")},offset:function(a){var b,c,d,e,f,g;return f=this,arguments.length?void 0===a?f:a:(b={top:0,left:0},e=f[0],(c=e&&e.ownerDocument)?(d=c.documentElement,e.getBoundingClientRect&&(b=e.getBoundingClientRect()),g=c.defaultView||c.parentWindow,{top:b.top+(g.pageYOffset||d.scrollTop)-(d.clientTop||0),left:b.left+(g.pageXOffset||d.scrollLeft)-(d.clientLeft||0)}):void 0)},scrollTop:function(a){return i(this,"top",a)},scrollLeft:function(a){return i(this,"left",a)}},function(b,c){return a.prototype[c]?void 0:a.prototype[c]=b})}}}]).run(["$log","$window","jqLiteExtras",function(a,b,c){return b.jQuery?void 0:c.registerFor(angular.element)}]),angular.module("ui.scroll",[]).directive("ngScrollViewport",["$log",function(){return{controller:["$scope","$element",function(a,b){return b}]}}]).directive("ngScroll",["$log","$injector","$rootScope","$timeout",function(a,b,c,d){return{require:["?^ngScrollViewport"],transclude:"element",priority:1e3,terminal:!0,compile:function(e,f,g){return function(f,h,i,j){var k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T;if(H=i.ngScroll.match(/^\s*(\w+)\s+in\s+(\w+)\s*$/),!H)throw new Error('Expected ngScroll in form of "item_ in _datasource_" but got "'+i.ngScroll+'"');if(F=H[1],v=H[2],D=function(a){return angular.isObject(a)&&a.get&&angular.isFunction(a.get)},u=f[v],!D(u)&&(u=b.get(v),!D(u)))throw new Error(v+" is not a valid datasource");return r=Math.max(3,+i.bufferSize||10),q=function(){return T.height()*Math.max(.1,+i.padding||.1)},O=function(a){return a[0].scrollHeight||a[0].document.documentElement.scrollHeight},k=null,g(R=f.$new(),function(a){var b,c,d,f,g,h;if(f=a[0].localName,"dl"===f)throw new Error("ng-scroll directive does not support <"+a[0].localName+"> as a repeating tag: "+a[0].outerHTML);return"li"!==f&&"tr"!==f&&(f="div"),h=j[0]||angular.element(window),h.css({"overflow-y":"auto",display:"block"}),d=function(a){var b,c,d;switch(a){case"tr":return d=angular.element("
      "),b=d.find("div"),c=d.find("tr"),c.paddingHeight=function(){return b.height.apply(b,arguments)},c;default:return c=angular.element("<"+a+">"),c.paddingHeight=c.height,c}},c=function(a,b,c){return b[{top:"before",bottom:"after"}[c]](a),{paddingHeight:function(){return a.paddingHeight.apply(a,arguments)},insert:function(b){return a[{top:"after",bottom:"before"}[c]](b)}}},g=c(d(f),e,"top"),b=c(d(f),e,"bottom"),R.$destroy(),k={viewport:h,topPadding:g.paddingHeight,bottomPadding:b.paddingHeight,append:b.insert,prepend:g.insert,bottomDataPos:function(){return O(h)-b.paddingHeight()},topDataPos:function(){return g.paddingHeight()}}}),T=k.viewport,B=1,I=1,p=[],J=[],x=!1,n=!1,G=u.loading||function(){},E=!1,L=function(a,b){var c,d;for(c=d=a;b>=a?b>d:d>b;c=b>=a?++d:--d)p[c].scope.$destroy(),p[c].element.remove();return p.splice(a,b-a)},K=function(){return B=1,I=1,L(0,p.length),k.topPadding(0),k.bottomPadding(0),J=[],x=!1,n=!1,l(!1)},o=function(){return T.scrollTop()+T.height()},S=function(){return T.scrollTop()},P=function(){return!x&&k.bottomDataPos()=g?0>=f:f>=0)&&(d=p[c].element.outerHeight(!0),k.bottomDataPos()-b-d>o()+q());c=0>=g?++f:--f)b+=d,e++,x=!1;return e>0?(k.bottomPadding(k.bottomPadding()+b),L(p.length-e,p.length),I-=e,a.log("clipped off bottom "+e+" bottom padding "+k.bottomPadding())):void 0},Q=function(){return!n&&k.topDataPos()>S()-q()},t=function(){var b,c,d,e,f,g;for(e=0,d=0,f=0,g=p.length;g>f&&(b=p[f],c=b.element.outerHeight(!0),k.topDataPos()+e+c0?(k.topPadding(k.topPadding()+e),L(0,d),B+=d,a.log("clipped off top "+d+" top padding "+k.topPadding())):void 0},w=function(a,b){return E||(E=!0,G(!0)),1===J.push(a)?z(b):void 0},C=function(a,b){var c,d,e;return c=f.$new(),c[F]=b,d=a>B,c.$index=a,d&&c.$index--,e={scope:c},g(c,function(b){return e.element=b,d?a===I?(k.append(b),p.push(e)):(p[a-B].element.after(b),p.splice(a-B+1,0,e)):(k.prepend(b),p.unshift(e))}),{appended:d,wrapper:e}},m=function(a,b){var c;return a?k.bottomPadding(Math.max(0,k.bottomPadding()-b.element.outerHeight(!0))):(c=k.topPadding()-b.element.outerHeight(!0),c>=0?k.topPadding(c):T.scrollTop(T.scrollTop()+b.element.outerHeight(!0)))},l=function(b,c,e){var f;return f=function(){return a.log("top {actual="+k.topDataPos()+" visible from="+S()+" bottom {visible through="+o()+" actual="+k.bottomDataPos()+"}"),P()?w(!0,b):Q()&&w(!1,b),e?e():void 0},c?d(function(){var a,b,d;for(b=0,d=c.length;d>b;b++)a=c[b],m(a.appended,a.wrapper);return f()}):f()},A=function(a,b){return l(a,b,function(){return J.shift(),0===J.length?(E=!1,G(!1)):z(a)})},z=function(b){var c;return c=J[0],c?p.length&&!P()?A(b):u.get(I,r,function(c){var d,e,f,g;if(e=[],0===c.length)x=!0,k.bottomPadding(0),a.log("appended: requested "+r+" records starting from "+I+" recieved: eof");else{for(t(),f=0,g=c.length;g>f;f++)d=c[f],e.push(C(++I,d));a.log("appended: requested "+r+" received "+c.length+" buffer size "+p.length+" first "+B+" next "+I)}return A(b,e)}):p.length&&!Q()?A(b):u.get(B-r,r,function(c){var d,e,f,g;if(e=[],0===c.length)n=!0,k.topPadding(0),a.log("prepended: requested "+r+" records starting from "+(B-r)+" recieved: bof");else{for(s(),d=f=g=c.length-1;0>=g?0>=f:f>=0;d=0>=g?++f:--f)e.unshift(C(--B,c[d]));a.log("prepended: requested "+r+" received "+c.length+" buffer size "+p.length+" first "+B+" next "+I)}return A(b,e)})},M=function(){return c.$$phase||E?void 0:(l(!1),f.$apply())},T.bind("resize",M),N=function(){return c.$$phase||E?void 0:(l(!0),f.$apply())},T.bind("scroll",N),f.$watch(u.revision,function(){return K()}),y=u.scope?u.scope.$new():f.$new(),f.$on("$destroy",function(){return y.$destroy(),T.unbind("resize",M),T.unbind("scroll",N)}),y.$on("update.items",function(a,b,c){var d,e,f,g,h;if(angular.isFunction(b))for(e=function(a){return b(a.scope)},f=0,g=p.length;g>f;f++)d=p[f],e(d);else 0<=(h=b-B-1)&&hh;h++)d=p[h],e.unshift(d);for(g=function(a){return b(a.scope)?(L(e.length-1-c,e.length-c),I--):void 0},c=i=0,m=e.length;m>i;c=++i)f=e[c],g(f)}else 0<=(o=b-B-1)&&oj;c=++j)d=p[c],d.scope.$index=B+c;return l(!1)}),y.$on("insert.item",function(a,b,c){var d,e,f,g,h,i,j,k,m,n,o,q;if(e=[],angular.isFunction(b)){for(f=[],i=0,m=p.length;m>i;i++)c=p[i],f.unshift(c);for(h=function(a){var f,g,h,i,j;if(g=b(a.scope)){if(C=function(a,b){return C(a,b),I++},angular.isArray(g)){for(j=[],f=h=0,i=g.length;i>h;f=++h)c=g[f],j.push(e.push(C(d+f,c)));return j}return e.push(C(d,g))}},d=j=0,n=f.length;n>j;d=++j)g=f[d],h(g)}else 0<=(q=b-B-1)&&qk;d=++k)c=p[d],c.scope.$index=B+d;return l(!1,e)})}}}}]),angular.module("ui.scrollfix",[]).directive("uiScrollfix",["$window",function(a){return{require:"^?uiScrollfixTarget",link:function(b,c,d,e){function f(){var b;if(angular.isDefined(a.pageYOffset))b=a.pageYOffset;else{var e=document.compatMode&&"BackCompat"!==document.compatMode?document.documentElement:document.body;b=e.scrollTop}!c.hasClass("ui-scrollfix")&&b>d.uiScrollfix?c.addClass("ui-scrollfix"):c.hasClass("ui-scrollfix")&&b")(i);j.appendChild(k[0]),i.count=f,void 0!==g&&k.eq(0).children().css("height",g),void 0!==h&&(k.eq(0).children().css("background-color",h),k.eq(0).children().css("color",h));var l,m=0;return{start:function(){this.show();var a=this;clearInterval(m),m=setInterval(function(){if(isNaN(f))clearInterval(m),f=0,a.hide();else{var b=100-f;f+=.15*Math.pow(1-Math.sqrt(b),2),a.updateCount(f)}},200)},updateCount:function(a){i.count=a,i.$$phase||i.$apply()},height:function(a){return void 0!==a&&(g=a,i.height=g,i.$$phase||i.$apply()),g},color:function(a){return void 0!==a&&(h=a,i.color=h,i.$$phase||i.$apply()),h},hide:function(){k.children().css("opacity","0");var a=this;a.animate(function(){k.children().css("width","0%"),a.animate(function(){a.show()},500)},500)},show:function(){var a=this;a.animate(function(){k.children().css("opacity","1")},100)},animate:function(a,b){l&&e.cancel(l),l=e(a,b)},status:function(){return f},stop:function(){clearInterval(m)},set:function(a){return this.show(),this.updateCount(a),f=a,clearInterval(m),f},css:function(a){return k.children().css(a)},reset:function(){return clearInterval(m),f=0,this.updateCount(f),0},complete:function(){f=100,this.updateCount(f);var a=this;return clearInterval(m),e(function(){a.hide(),e(function(){f=0,a.updateCount(f)},500)},1e3),f},setParent:function(a){if(null===a||void 0===a)throw new Error("Provide a valid parent of type HTMLElement");null!==j&&void 0!==j&&j.removeChild(k[0]),j=a,j.appendChild(k[0])},getDomElement:function(){return k}}}],this.setColor=function(a){return void 0!==a&&(this.color=a),this.color},this.setHeight=function(a){return void 0!==a&&(this.height=a),this.height}}),angular.module("ngProgress.directive",[]).directive("ngProgress",["$window","$rootScope",function(a,b){var c={replace:!0,restrict:"E",link:function(a,c){b.$watch("count",function(b){(void 0!==b||null!==b)&&(a.counter=b,c.eq(0).children().css("width",b+"%"))}),b.$watch("color",function(b){(void 0!==b||null!==b)&&(a.color=b,c.eq(0).children().css("background-color",b),c.eq(0).children().css("color",b))}),b.$watch("height",function(b){(void 0!==b||null!==b)&&(a.height=b,c.eq(0).children().css("height",b))})},template:'
      '};return c}]),angular.module("ngProgress",["ngProgress.directive","ngProgress.provider"]); // Source: public/lib/angular-gettext/dist/angular-gettext.min.js angular.module("gettext",[]),angular.module("gettext").constant("gettext",function(a){return a}),angular.module("gettext").factory("gettextCatalog",["gettextPlurals","$http","$cacheFactory","$interpolate","$rootScope",function(a,b,c,d,e){function f(){e.$broadcast("gettextLanguageChanged")}var g,h=function(a){return g.debug&&g.currentLanguage!==g.baseLanguage?g.debugPrefix+a:a},i=function(a){return g.showTranslatedMarkers?g.translatedMarkerPrefix+a+g.translatedMarkerSuffix:a};return g={debug:!1,debugPrefix:"[MISSING]: ",showTranslatedMarkers:!1,translatedMarkerPrefix:"[",translatedMarkerSuffix:"]",strings:{},baseLanguage:"en",currentLanguage:"en",cache:c("strings"),setCurrentLanguage:function(a){this.currentLanguage=a,f()},setStrings:function(a,b){this.strings[a]||(this.strings[a]={});for(var c in b){var d=b[c];this.strings[a][c]="string"==typeof d?[d]:d}f()},getStringForm:function(a,b){var c=this.strings[this.currentLanguage]||{},d=c[a]||[];return d[b]},getString:function(a,b){return a=this.getStringForm(a,0)||h(a),a=b?d(a)(b):a,i(a)},getPlural:function(b,c,e,f){var g=a(this.currentLanguage,b);return c=this.getStringForm(c,g)||h(1===b?c:e),c=f?d(c)(f):c,i(c)},loadRemote:function(a){return b({method:"GET",url:a,cache:g.cache}).success(function(a){for(var b in a)g.setStrings(b,a[b])})}}}]),angular.module("gettext").directive("translate",["gettextCatalog","$parse","$animate","$compile",function(a,b,c,d){function e(a,b,c){if(!a)throw new Error("You should add a "+b+" attribute whenever you add a "+c+" attribute.")}var f=function(){return String.prototype.trim?function(a){return"string"==typeof a?a.trim():a}:function(a){return"string"==typeof a?a.replace(/^\s*/,"").replace(/\s*$/,""):a}}();return{restrict:"A",terminal:!0,compile:function(g,h){e(!h.translatePlural||h.translateN,"translate-n","translate-plural"),e(!h.translateN||h.translatePlural,"translate-plural","translate-n");var i=f(g.html()),j=h.translatePlural;return{post:function(e,f,g){function h(){var b;j?(e=l||(l=e.$new()),e.$count=k(e),b=a.getPlural(e.$count,i,j)):b=a.getString(i);var g=angular.element(""+b+"");d(g.contents())(e);var h=f.contents(),m=g.contents();c.enter(m,f),c.leave(h)}var k=b(g.translateN),l=null;g.translateN&&e.$watch(g.translateN,h),e.$on("gettextLanguageChanged",h),h()}}}}}]),angular.module("gettext").filter("translate",["gettextCatalog",function(a){function b(b){return a.getString(b)}return b.$stateful=!0,b}]),angular.module("gettext").factory("gettextPlurals",function(){return function(a,b){switch(a){case"ay":case"bo":case"cgg":case"dz":case"fa":case"id":case"ja":case"jbo":case"ka":case"kk":case"km":case"ko":case"ky":case"lo":case"ms":case"my":case"sah":case"su":case"th":case"tt":case"ug":case"vi":case"wo":case"zh":return 0;case"is":return b%10!=1||b%100==11?1:0;case"jv":return 0!=b?1:0;case"mk":return 1==b||b%10==1?0:1;case"ach":case"ak":case"am":case"arn":case"br":case"fil":case"fr":case"gun":case"ln":case"mfe":case"mg":case"mi":case"oc":case"pt_BR":case"tg":case"ti":case"tr":case"uz":case"wa":case"zh":return b>1?1:0;case"lv":return b%10==1&&b%100!=11?0:0!=b?1:2;case"lt":return b%10==1&&b%100!=11?0:b%10>=2&&(10>b%100||b%100>=20)?1:2;case"be":case"bs":case"hr":case"ru":case"sr":case"uk":return b%10==1&&b%100!=11?0:b%10>=2&&4>=b%10&&(10>b%100||b%100>=20)?1:2;case"mnk":return 0==b?0:1==b?1:2;case"ro":return 1==b?0:0==b||b%100>0&&20>b%100?1:2;case"pl":return 1==b?0:b%10>=2&&4>=b%10&&(10>b%100||b%100>=20)?1:2;case"cs":case"sk":return 1==b?0:b>=2&&4>=b?1:2;case"sl":return b%100==1?1:b%100==2?2:b%100==3||b%100==4?3:0;case"mt":return 1==b?0:0==b||b%100>1&&11>b%100?1:b%100>10&&20>b%100?2:3;case"gd":return 1==b||11==b?0:2==b||12==b?1:b>2&&20>b?2:3;case"cy":return 1==b?0:2==b?1:8!=b&&11!=b?2:3;case"kw":return 1==b?0:2==b?1:3==b?2:3;case"ga":return 1==b?0:2==b?1:7>b?2:11>b?3:4;case"ar":return 0==b?0:1==b?1:2==b?2:b%100>=3&&10>=b%100?3:b%100>=11?4:5;default:return 1!=b?1:0}}}); // Source: public/lib/angular-moment/angular-moment.min.js "format global";"deps angular";"deps moment";!function(){"use strict";function a(a,b){return a.module("angularMoment",[]).constant("angularMomentConfig",{preprocess:null,timezone:"",format:null}).constant("moment",b).constant("amTimeAgoConfig",{withoutSuffix:!1,serverTime:null,titleFormat:null}).directive("amTimeAgo",["$window","moment","amMoment","amTimeAgoConfig","angularMomentConfig",function(b,c,d,e,f){return function(g,h,i){function j(){var a;if(e.serverTime){var b=(new Date).getTime(),d=b-u+e.serverTime;a=c(d)}else a=c();return a}function k(){q&&(b.clearTimeout(q),q=null)}function l(a){if(h.text(a.from(j(),s)),t&&!h.attr("title")&&h.attr("title",a.local().format(t)),!x){var c=Math.abs(j().diff(a,"minute")),d=3600;1>c?d=1:60>c?d=30:180>c&&(d=300),q=b.setTimeout(function(){l(a)},1e3*d)}}function m(a){y&&h.attr("datetime",a)}function n(){if(k(),o){var a=d.preprocessDate(o,v,r);l(a),m(a.toISOString())}}var o,p,q=null,r=f.format,s=e.withoutSuffix,t=e.titleFormat,u=(new Date).getTime(),v=f.preprocess,w=i.amTimeAgo.replace(/^::/,""),x=0===i.amTimeAgo.indexOf("::"),y="TIME"===h[0].nodeName.toUpperCase();p=g.$watch(w,function(a){return"undefined"==typeof a||null===a||""===a?(k(),void(o&&(h.text(""),m(""),o=null))):(o=a,n(),void(void 0!==a&&x&&p()))}),a.isDefined(i.amWithoutSuffix)&&g.$watch(i.amWithoutSuffix,function(a){"boolean"==typeof a?(s=a,n()):s=e.withoutSuffix}),i.$observe("amFormat",function(a){"undefined"!=typeof a&&(r=a,n())}),i.$observe("amPreprocess",function(a){v=a,n()}),g.$on("$destroy",function(){k()}),g.$on("amMoment:localeChanged",function(){n()})}}]).service("amMoment",["moment","$rootScope","$log","angularMomentConfig",function(b,c,d,e){var f=this;this.preprocessors={utc:b.utc,unix:b.unix},this.changeLocale=function(d){var e=(b.locale||b.lang)(d);return a.isDefined(d)&&(c.$broadcast("amMoment:localeChanged"),c.$broadcast("amMoment:languageChange")),e},this.changeLanguage=function(a){return d.warn("angular-moment: Usage of amMoment.changeLanguage() is deprecated. Please use changeLocale()"),f.changeLocale(a)},this.preprocessDate=function(c,f,g){return a.isUndefined(f)&&(f=e.preprocess),this.preprocessors[f]?this.preprocessors[f](c,g):(f&&d.warn("angular-moment: Ignoring unsupported value for preprocess: "+f),!isNaN(parseFloat(c))&&isFinite(c)?b(parseInt(c,10)):b(c,g))},this.applyTimezone=function(a){var b=e.timezone;return a&&b&&(a.tz?a=a.tz(b):d.warn("angular-moment: timezone specified but moment.tz() is undefined. Did you forget to include moment-timezone.js?")),a}}]).filter("amCalendar",["moment","amMoment",function(a,b){return function(c,d){if("undefined"==typeof c||null===c)return"";c=b.preprocessDate(c,d);var e=a(c);return e.isValid()?b.applyTimezone(e).calendar():""}}]).filter("amDateFormat",["moment","amMoment",function(a,b){return function(c,d,e){if("undefined"==typeof c||null===c)return"";c=b.preprocessDate(c,e);var f=a(c);return f.isValid()?b.applyTimezone(f).format(d):""}}]).filter("amDurationFormat",["moment",function(a){return function(b,c,d){return"undefined"==typeof b||null===b?"":a.duration(b,c).humanize(d)}}]).filter("amTimeAgo",["moment","amMoment",function(a,b){return function(c,d,e){if("undefined"==typeof c||null===c)return"";c=b.preprocessDate(c,d);var f=a(c);return f.isValid()?b.applyTimezone(f).fromNow(e):""}}])}"function"==typeof define&&define.amd?define("angular-moment",["angular","moment"],a):"undefined"!=typeof module&&module&&module.exports?a(angular,require("moment")):a(angular,window.moment)}(); //# sourceMappingURL=angular-moment.min.js.map