Move code to awx/ui/client

This commit is contained in:
Joe Fiorini
2015-07-27 10:19:14 -04:00
parent e50d997577
commit 98a37a354a
3915 changed files with 2196 additions and 12520 deletions
@@ -0,0 +1,19 @@
{
"name": "angular-animate",
"version": "1.2.23",
"main": "./angular-animate.js",
"dependencies": {
"angular": "1.2.23"
},
"homepage": "https://github.com/angular/bower-angular-animate",
"_release": "1.2.23",
"_resolution": {
"type": "version",
"tag": "v1.2.23",
"commit": "a5b1e7109e5b9a0276540cdafc92d6fedfec8da5"
},
"_source": "git://github.com/angular/bower-angular-animate.git",
"_target": "~1.2.23",
"_originalSource": "angular-animate",
"_direct": true
}
@@ -0,0 +1,54 @@
# bower-angular-animate
This repo is for distribution on `bower`. The source for this module is in the
[main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngAnimate).
Please file issues and pull requests against that repo.
## Install
Install with `bower`:
```shell
bower install angular-animate
```
Add a `<script>` to your `index.html`:
```html
<script src="/bower_components/angular-animate/angular-animate.js"></script>
```
And add `ngAnimate` as a dependency for your app:
```javascript
angular.module('myApp', ['ngAnimate']);
```
## Documentation
Documentation is available on the
[AngularJS docs site](http://docs.angularjs.org/api/ngAnimate).
## License
The MIT License
Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,28 @@
/*
AngularJS v1.2.23
(c) 2010-2014 Google, Inc. http://angularjs.org
License: MIT
*/
(function(F,e,O){'use strict';e.module("ngAnimate",["ng"]).directive("ngAnimateChildren",function(){return function(G,s,g){g=g.ngAnimateChildren;e.isString(g)&&0===g.length?s.data("$$ngAnimateChildren",!0):G.$watch(g,function(e){s.data("$$ngAnimateChildren",!!e)})}}).factory("$$animateReflow",["$$rAF","$document",function(e,s){return function(g){return e(function(){g()})}}]).config(["$provide","$animateProvider",function(G,s){function g(e){for(var g=0;g<e.length;g++){var l=e[g];if(l.nodeType==aa)return l}}
function B(l){return e.element(g(l))}var m=e.noop,u=e.forEach,P=s.$$selectors,aa=1,l="$$ngAnimateState",V="$$ngAnimateChildren",J="ng-animate",n={running:!0};G.decorator("$animate",["$delegate","$injector","$sniffer","$rootElement","$$asyncCallback","$rootScope","$document",function(z,F,$,R,E,H,O){function K(a){var b=a.data(l)||{};b.running=!0;a.data(l,b)}function L(a){if(a){var b=[],c={};a=a.substr(1).split(".");($.transitions||$.animations)&&b.push(F.get(P[""]));for(var d=0;d<a.length;d++){var f=
a[d],e=P[f];e&&!c[f]&&(b.push(F.get(e)),c[f]=!0)}return b}}function G(a,b,c){function d(a,b){var c=a[b],d=a["before"+b.charAt(0).toUpperCase()+b.substr(1)];if(c||d)return"leave"==b&&(d=c,c=null),n.push({event:b,fn:c}),h.push({event:b,fn:d}),!0}function f(b,d,e){var f=[];u(b,function(a){a.fn&&f.push(a)});var g=0;u(f,function(b,l){var C=function(){a:{if(d){(d[l]||m)();if(++g<f.length)break a;d=null}e()}};switch(b.event){case "setClass":d.push(b.fn(a,A,k,C));break;case "addClass":d.push(b.fn(a,A||c,
C));break;case "removeClass":d.push(b.fn(a,k||c,C));break;default:d.push(b.fn(a,C))}});d&&0===d.length&&e()}var g=a[0];if(g){var l="setClass"==b,p=l||"addClass"==b||"removeClass"==b,A,k;e.isArray(c)&&(A=c[0],k=c[1],c=A+" "+k);var x=a.attr("class")+" "+c;if(M(x)){var t=m,w=[],h=[],q=m,y=[],n=[],x=(" "+x).replace(/\s+/g,".");u(L(x),function(a){!d(a,b)&&l&&(d(a,"addClass"),d(a,"removeClass"))});return{node:g,event:b,className:c,isClassBased:p,isSetClassOperation:l,before:function(a){t=a;f(h,w,function(){t=
m;a()})},after:function(a){q=a;f(n,y,function(){q=m;a()})},cancel:function(){w&&(u(w,function(a){(a||m)(!0)}),t(!0));y&&(u(y,function(a){(a||m)(!0)}),q(!0))}}}}}function r(a,b,c,d,f,g,n){function p(d){var e="$animate:"+d;q&&(q[e]&&0<q[e].length)&&E(function(){c.triggerHandler(e,{event:a,className:b})})}function A(){p("before")}function m(){p("after")}function x(){p("close");n&&E(function(){n()})}function t(){t.hasBeenRun||(t.hasBeenRun=!0,g())}function w(){if(!w.hasBeenRun){w.hasBeenRun=!0;var d=
c.data(l);d&&(h&&h.isClassBased?k(c,b):(E(function(){var d=c.data(l)||{};r==d.index&&k(c,b,a)}),c.data(l,d)));x()}}var h=G(c,a,b);if(h){b=h.className;var q=e.element._data(h.node),q=q&&q.events;d||(d=f?f.parent():c.parent());var y=c.data(l)||{};f=y.active||{};var z=y.totalActive||0,C=y.last,D;h.isClassBased&&(D=y.running||y.disabled||C&&!C.isClassBased);if(D||N(c,d))t(),A(),m(),w();else{d=!1;if(0<z){D=[];if(h.isClassBased)"setClass"==C.event?(D.push(C),k(c,b)):f[b]&&(v=f[b],v.event==a?d=!0:(D.push(v),
k(c,b)));else if("leave"==a&&f["ng-leave"])d=!0;else{for(var v in f)D.push(f[v]),k(c,v);f={};z=0}0<D.length&&u(D,function(a){a.cancel()})}!h.isClassBased||(h.isSetClassOperation||d)||(d="addClass"==a==c.hasClass(b));if(d)t(),A(),m(),x();else{if("leave"==a)c.one("$destroy",function(a){a=e.element(this);var b=a.data(l);b&&(b=b.active["ng-leave"])&&(b.cancel(),k(a,"ng-leave"))});c.addClass(J);var r=Y++;z++;f[b]=h;c.data(l,{last:h,active:f,index:r,totalActive:z});A();h.before(function(d){var e=c.data(l);
d=d||!e||!e.active[b]||h.isClassBased&&e.active[b].event!=a;t();!0===d?w():(m(),h.after(w))})}}}else t(),A(),m(),w()}function T(a){if(a=g(a))a=e.isFunction(a.getElementsByClassName)?a.getElementsByClassName(J):a.querySelectorAll("."+J),u(a,function(a){a=e.element(a);(a=a.data(l))&&a.active&&u(a.active,function(a){a.cancel()})})}function k(a,b){if(g(a)==g(R))n.disabled||(n.running=!1,n.structural=!1);else if(b){var c=a.data(l)||{},d=!0===b;!d&&(c.active&&c.active[b])&&(c.totalActive--,delete c.active[b]);
if(d||!c.totalActive)a.removeClass(J),a.removeData(l)}}function N(a,b){if(n.disabled)return!0;if(g(a)==g(R))return n.running;var c,d,f;do{if(0===b.length)break;var m=g(b)==g(R),k=m?n:b.data(l)||{};if(k.disabled)return!0;m&&(f=!0);!1!==c&&(m=b.data(V),e.isDefined(m)&&(c=m));d=d||k.running||k.last&&!k.last.isClassBased}while(b=b.parent());return!f||!c&&d}var Y=0;R.data(l,n);H.$$postDigest(function(){H.$$postDigest(function(){n.running=!1})});var Q=s.classNameFilter(),M=Q?function(a){return Q.test(a)}:
function(){return!0};return{enter:function(a,b,c,d){a=e.element(a);b=b&&e.element(b);c=c&&e.element(c);K(a);z.enter(a,b,c);H.$$postDigest(function(){a=B(a);r("enter","ng-enter",a,b,c,m,d)})},leave:function(a,b){a=e.element(a);T(a);K(a);H.$$postDigest(function(){r("leave","ng-leave",B(a),null,null,function(){z.leave(a)},b)})},move:function(a,b,c,d){a=e.element(a);b=b&&e.element(b);c=c&&e.element(c);T(a);K(a);z.move(a,b,c);H.$$postDigest(function(){a=B(a);r("move","ng-move",a,b,c,m,d)})},addClass:function(a,
b,c){a=e.element(a);a=B(a);r("addClass",b,a,null,null,function(){z.addClass(a,b)},c)},removeClass:function(a,b,c){a=e.element(a);a=B(a);r("removeClass",b,a,null,null,function(){z.removeClass(a,b)},c)},setClass:function(a,b,c,d){a=e.element(a);a=B(a);r("setClass",[b,c],a,null,null,function(){z.setClass(a,b,c)},d)},enabled:function(a,b){switch(arguments.length){case 2:if(a)k(b);else{var c=b.data(l)||{};c.disabled=!0;b.data(l,c)}break;case 1:n.disabled=!a;break;default:a=!n.disabled}return!!a}}}]);s.register("",
["$window","$sniffer","$timeout","$$animateReflow",function(l,n,s,B){function E(a,U){S&&S();W.push(U);S=B(function(){u(W,function(a){a()});W=[];S=null;v={}})}function H(a,U){var b=g(a);a=e.element(b);Z.push(a);b=Date.now()+U;b<=da||(s.cancel(ca),da=b,ca=s(function(){G(Z);Z=[]},U,!1))}function G(a){u(a,function(a){(a=a.data(q))&&(a.closeAnimationFn||m)()})}function K(a,b){var c=b?v[b]:null;if(!c){var d=0,e=0,f=0,g=0,m,k,h,q;u(a,function(a){if(a.nodeType==aa){a=l.getComputedStyle(a)||{};h=a[I+P];d=
Math.max(L(h),d);q=a[I+x];m=a[I+t];e=Math.max(L(m),e);k=a[p+t];g=Math.max(L(k),g);var b=L(a[p+P]);0<b&&(b*=parseInt(a[p+w],10)||1);f=Math.max(b,f)}});c={total:0,transitionPropertyStyle:q,transitionDurationStyle:h,transitionDelayStyle:m,transitionDelay:e,transitionDuration:d,animationDelayStyle:k,animationDelay:g,animationDuration:f};b&&(v[b]=c)}return c}function L(a){var b=0;a=e.isString(a)?a.split(/\s*,\s*/):[];u(a,function(a){b=Math.max(parseFloat(a)||0,b)});return b}function J(a){var b=a.parent(),
c=b.data(h);c||(b.data(h,++ba),c=ba);return c+"-"+g(a).getAttribute("class")}function r(a,b,c,d){var e=J(b),f=e+" "+c,l=v[f]?++v[f].total:0,k={};if(0<l){var h=c+"-stagger",k=e+" "+h;(e=!v[k])&&b.addClass(h);k=K(b,k);e&&b.removeClass(h)}d=d||function(a){return a()};b.addClass(c);var h=b.data(q)||{},n=d(function(){return K(b,f)});d=n.transitionDuration;e=n.animationDuration;if(0===d&&0===e)return b.removeClass(c),!1;b.data(q,{running:h.running||0,itemIndex:l,stagger:k,timings:n,closeAnimationFn:m});
a=0<h.running||"setClass"==a;0<d&&T(b,c,a);0<e&&(0<k.animationDelay&&0===k.animationDuration)&&(g(b).style[p]="none 0s");return!0}function T(a,b,c){"ng-enter"!=b&&("ng-move"!=b&&"ng-leave"!=b)&&c?a.addClass(y):g(a).style[I+x]="none"}function k(a,b){var c=I+x,d=g(a);d.style[c]&&0<d.style[c].length&&(d.style[c]="");a.removeClass(y)}function N(a){var b=p;a=g(a);a.style[b]&&0<a.style[b].length&&(a.style[b]="")}function Y(a,b,d,e){function k(a){b.off(x,l);b.removeClass(m);c(b,d);a=g(b);for(var e in s)a.style.removeProperty(s[e])}
function l(a){a.stopPropagation();var b=a.originalEvent||a;a=b.$manualTimeStamp||b.timeStamp||Date.now();b=parseFloat(b.elapsedTime.toFixed(V));Math.max(a-z,0)>=y&&b>=v&&e()}var h=g(b);a=b.data(q);if(-1!=h.getAttribute("class").indexOf(d)&&a){var m="";u(d.split(" "),function(a,b){m+=(0<b?" ":"")+a+"-active"});var n=a.stagger,p=a.timings,t=a.itemIndex,v=Math.max(p.transitionDuration,p.animationDuration),w=Math.max(p.transitionDelay,p.animationDelay),y=w*D,z=Date.now(),x=A+" "+X,r="",s=[];if(0<p.transitionDuration){var B=
p.transitionPropertyStyle;-1==B.indexOf("all")&&(r+=f+"transition-property: "+B+";",r+=f+"transition-duration: "+p.transitionDurationStyle+";",s.push(f+"transition-property"),s.push(f+"transition-duration"))}0<t&&(0<n.transitionDelay&&0===n.transitionDuration&&(r+=f+"transition-delay: "+Q(p.transitionDelayStyle,n.transitionDelay,t)+"; ",s.push(f+"transition-delay")),0<n.animationDelay&&0===n.animationDuration&&(r+=f+"animation-delay: "+Q(p.animationDelayStyle,n.animationDelay,t)+"; ",s.push(f+"animation-delay")));
0<s.length&&(p=h.getAttribute("style")||"",h.setAttribute("style",p+"; "+r));b.on(x,l);b.addClass(m);a.closeAnimationFn=function(){k();e()};h=(t*(Math.max(n.animationDelay,n.transitionDelay)||0)+(w+v)*C)*D;a.running++;H(b,h);return k}e()}function Q(a,b,c){var d="";u(a.split(","),function(a,e){d+=(0<e?",":"")+(c*b+parseInt(a,10))+"s"});return d}function M(a,b,d,e){if(r(a,b,d,e))return function(a){a&&c(b,d)}}function a(a,b,d,e){if(b.data(q))return Y(a,b,d,e);c(b,d);e()}function b(b,c,d,e){var f=M(b,
c,d);if(f){var g=f;E(c,function(){k(c,d);N(c);g=a(b,c,d,e)});return function(a){(g||m)(a)}}e()}function c(a,b){a.removeClass(b);var c=a.data(q);c&&(c.running&&c.running--,c.running&&0!==c.running||a.removeData(q))}function d(a,b){var c="";a=e.isArray(a)?a:a.split(/\s+/);u(a,function(a,d){a&&0<a.length&&(c+=(0<d?" ":"")+a+b)});return c}var f="",I,X,p,A;F.ontransitionend===O&&F.onwebkittransitionend!==O?(f="-webkit-",I="WebkitTransition",X="webkitTransitionEnd transitionend"):(I="transition",X="transitionend");
F.onanimationend===O&&F.onwebkitanimationend!==O?(f="-webkit-",p="WebkitAnimation",A="webkitAnimationEnd animationend"):(p="animation",A="animationend");var P="Duration",x="Property",t="Delay",w="IterationCount",h="$$ngAnimateKey",q="$$ngAnimateCSS3Data",y="ng-animate-block-transitions",V=3,C=1.5,D=1E3,v={},ba=0,W=[],S,ca=null,da=0,Z=[];return{enter:function(a,c){return b("enter",a,"ng-enter",c)},leave:function(a,c){return b("leave",a,"ng-leave",c)},move:function(a,c){return b("move",a,"ng-move",
c)},beforeSetClass:function(a,b,c,e){var f=d(c,"-remove")+" "+d(b,"-add"),g=M("setClass",a,f,function(d){var e=a.attr("class");a.removeClass(c);a.addClass(b);d=d();a.attr("class",e);return d});if(g)return E(a,function(){k(a,f);N(a);e()}),g;e()},beforeAddClass:function(a,b,c){var e=M("addClass",a,d(b,"-add"),function(c){a.addClass(b);c=c();a.removeClass(b);return c});if(e)return E(a,function(){k(a,b);N(a);c()}),e;c()},setClass:function(b,c,e,f){e=d(e,"-remove");c=d(c,"-add");return a("setClass",b,
e+" "+c,f)},addClass:function(b,c,e){return a("addClass",b,d(c,"-add"),e)},beforeRemoveClass:function(a,b,c){var e=M("removeClass",a,d(b,"-remove"),function(c){var d=a.attr("class");a.removeClass(b);c=c();a.attr("class",d);return c});if(e)return E(a,function(){k(a,b);N(a);c()}),e;c()},removeClass:function(b,c,e){return a("removeClass",b,d(c,"-remove"),e)}}}])}])})(window,window.angular);
//# sourceMappingURL=angular-animate.min.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
{
"name": "angular-animate",
"version": "1.2.23",
"main": "./angular-animate.js",
"dependencies": {
"angular": "1.2.23"
}
}
@@ -0,0 +1,26 @@
{
"name": "angular-codemirror",
"version": "1.0.2",
"dependencies": {
"angular": "latest",
"angular-route": "latest",
"jquery": "latest",
"jqueryui": "latest",
"components-font-awesome": "latest",
"twitter": "latest",
"js-yaml": "latest",
"jsonlint": "latest",
"codemirror": "latest"
},
"homepage": "https://github.com/chouseknecht/angular-codemirror",
"_release": "1.0.2",
"_resolution": {
"type": "version",
"tag": "v1.0.2",
"commit": "94b7aac548b036f4fbd94e56129ed9574e472616"
},
"_source": "git://github.com/chouseknecht/angular-codemirror.git",
"_target": "~1.0.2",
"_originalSource": "angular-codemirror",
"_direct": true
}
@@ -0,0 +1,2 @@
bower_components/
node_modules/
@@ -0,0 +1,21 @@
{
// Details: https://github.com/victorporof/Sublime-JSHint#using-your-own-jshintrc-options
// Example: https://github.com/jshint/jshint/blob/master/examples/.jshintrc
// Documentation: http://www.jshint.com/docs/
"browser": true,
"jquery": true,
"esnext": true,
"globalstrict": true,
"globals": { "angular":false, "alert":true, "CodeMirror":false, "jsyaml":false },
"strict": false,
"quotmark": false,
"smarttabs": true,
"trailing": true,
"undef": true,
"unused": true,
"eqeqeq": true,
"indent": 4,
"onevar": true,
"newcap": false
}
@@ -0,0 +1,24 @@
AngularCodeMirror
================
Copyright (c) 2014 Chris Houseknecht
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy
of angular-codemirror and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@@ -0,0 +1,29 @@
AngularCodeMirror
=================
Incorporate [CodeMirror](http://www.codemirror.net) into your AngularJS app. Presents the editor in a resizable, draggable modal dialog styled with Twitter Bootstrap. Pass in any valid CodeMirror options to make the editor fit your app needs.
Installation:
-------------
bower install angular-codemirror
Example App:
------------
With [Node.js](http://nodejs.org) installed, you can run the sample app locally. Clone the repo to a local projects directory, install package dependencies, and then run with the included server:
cd projects
git clone git@github.com:chouseknecht/angular-codemirror.git
cd angular-codemirror
bower install
node ./scripts/web-server.js
Point your browser to http://localhost:8000/app/index.html. Click the code editor link.
How To:
-------
If you installed with Bower, then all the dependencies will exist in bower_components. See app/index.html for a template of how to include all the needed .js and .css files. If you want to install dependencies manually, review bower.json for a list of what's needed.
Check the CodeMirror documentation to see what needs to be included for the mode and options you choose. Again, if you installed with Bower, then everything you need should be found under bower_components.
Incorporate into your Angular app by following the example in app/js/sampleApp.js.
@@ -0,0 +1,68 @@
/*********************************************
* Copyright (c) 2013-2014 Chris Houseknecht
*
* SampleForm.js
*
* Demonstrate some of the things you can do with angular-forms.js to
* generate clean, consistent forms in your app.
*
*/
body {
padding-bottom: 80px;
}
#parse-type-group {
margin: 15px 0;
}
#parse-type-label {
display: inline-block;
padding-right: 10px;
font-weight: bold;
}
textarea {
resize: none;
}
a,
a:active,
a:link,
a:hover {
text-decoration: none;
}
.external-editor-link {
display: inline-block;
margin-left: 20px;
}
/*.ui-dialog-titlebar-close {
color: #000;
border: none;
background-color: transparent;
}*/
.red-txt {
color: #dd1b16;
}
.navbar-default .navbar-brand {
font-size: 24px;
color: #000;
}
.navigation {
margin-top: 20px;
padding-right: 15px;
}
.footer {
margin-top: 30px;
}
.footer .navbar-brand {
margin-bottom: 20px;
padding-right: 0;
}
@@ -0,0 +1,70 @@
<!doctype html>
<html lang="en" ng-app="sampleApp">
<head>
<meta charset="utf-8">
<title>AngularCodeMirror | Sample application</title>
<link rel="stylesheet" href="/bower_components/twitter/dist/css/bootstrap.min.css" >
<link rel="stylesheet" href="/bower_components/components-font-awesome/css/font-awesome.min.css" >
<link rel="stylesheet" href="/bower_components/jqueryui/themes/redmond/jquery-ui.min.css" >
<link rel="stylesheet" href="/bower_components/codemirror/lib/codemirror.css" >
<link rel="stylesheet" href="/bower_components/codemirror/theme/elegant.css" >
<link rel="stylesheet" href="/bower_components/codemirror/addon/lint/lint.css" >
<link rel="stylesheet" href="/lib/AngularCodeMirror.css" >
<link rel="stylesheet" href="/app/css/sampleApp.css" >
<script src="/bower_components/angular/angular.min.js"></script>
<script src="/bower_components/angular-route/angular-route.min.js"></script>
<script src="/app/js/sampleApp.js"></script>
<script src="/lib/AngularCodeMirror.js"></script>
</head>
<body>
<nav class="navbar navbar-default" role="navigation">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#nb-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Angular CodeMirror</a>
</div>
</div>
</nav>
<div class="container">
<div id="main-view" ng-view></div>
</div>
<div class="footer navbar-default navbar-fixed-bottom">
<div class="container">
<div class="row">
<div class="col-lg-12">
<a class="navbar-brand pull-right" href="/">Angular CodeMirror</a>
</div>
</div>
</div>
</div>
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/bower_components/jqueryui/ui/minified/jquery-ui.min.js"></script>
<script src="/bower_components/twitter/dist/js/bootstrap.min.js"></script>
<!-- bits to support code mirror -->
<script src="/bower_components/js-yaml/js-yaml.min.js"></script>
<script src="/bower_components/jsonlint/lib/jsonlint.js"></script>
<script src="/bower_components/codemirror/lib/codemirror.js"></script>
<script src="/bower_components/codemirror/mode/javascript/javascript.js"></script>
<script src="/bower_components/codemirror/mode/yaml/yaml.js"></script>
<script src="/bower_components/codemirror/addon/lint/lint.js"></script>
<script src="/bower_components/codemirror/addon/lint/json-lint.js"></script>
<script src="/lib/yaml-lint.js"></script>
<script src="/bower_components/codemirror/addon/edit/closebrackets.js"></script>
<script src="/bower_components/codemirror/addon/edit/matchbrackets.js"></script>
<script src="/bower_components/codemirror/addon/selection/active-line.js"></script>
</body>
</html>
+135
View File
@@ -0,0 +1,135 @@
/**********************************************
* sampleApp.js
*
* Copyright (c) 2013-2014 Chris Houseknecht
*
* Distributed under The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
'use strict';
angular.module('sampleApp', ['ngRoute', 'AngularCodeMirrorModule'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'partials/main.html',
controller: 'sampleController'
})
.otherwise({
redirectTo: '/'
});
}])
.controller('sampleController', ['$scope', 'AngularCodeMirror', function($scope, AngularCodeMirror) {
$scope.parseType = 'json';
$scope.codeValue = '{}';
var container = document.getElementById('main-view'),
modes = {
yaml: {
mode:"text/x-yaml",
matchBrackets: true,
autoCloseBrackets: true,
styleActiveLine: true,
lineNumbers: true,
gutters: ["CodeMirror-lint-markers"],
lint: true
},
json: {
mode: "application/json",
styleActiveLine: true,
matchBrackets: true,
autoCloseBrackets: true,
lineNumbers: true,
gutters: ["CodeMirror-lint-markers"],
lint: true
}
},
codeMirror = AngularCodeMirror();
codeMirror.addModes(modes);
$scope.parseTypeChange = function() {
var json_obj;
if ($scope.parseType === 'json') {
// converting yaml to json
try {
json_obj = jsyaml.load($scope.codeValue);
if ($.isEmptyObject(json_obj)) {
$scope.codeValue = "{}";
}
else {
$scope.codeValue = JSON.stringify(json_obj, null, " ");
}
}
catch (e) {
alert('Failed to parse valid YAML. ' + e.message);
setTimeout( function() { $scope.$apply( function() { $scope.parseType = 'yaml'; }); }, 500);
}
}
else {
// convert json to yaml
try {
json_obj = JSON.parse($scope.codeValue);
if ($.isEmptyObject(json_obj)) {
$scope.codeValue = '---';
}
else {
$scope.codeValue = jsyaml.safeDump(json_obj);
}
}
catch (e) {
alert('Failed to parse valid JSON. ' + e.message);
setTimeout( function() { $scope.$apply( function() { $scope.parseType = 'json'; }); }, 500 );
}
}
};
$scope.showCodeEditor = function() {
var title = 'Edit ' + $scope.parseType.toUpperCase();
codeMirror.show({
scope: $scope,
container: container,
mode: $scope.parseType,
model: 'codeValue',
title: title
});
};
}])
.directive('afTooltip', [ function() {
return {
link: function(scope, element, attrs) {
var placement = (attrs.placement) ? attrs.placement : 'top';
$(element).tooltip({
html: true,
placement: placement,
title: attrs.afTooltip,
trigger: 'hover',
container: 'body'
});
}
};
}]);
@@ -0,0 +1,20 @@
<div class="row">
<div class="col-lg-12">
<h4>CodeMirror Example</h4>
<div id="parse-type-group">
<div id="parse-type-label">Parse Type:</div>
<label class="radio-inline"><input type="radio" name="parsetype" value="json" ng-model="parseType"
ng-change="parseTypeChange()">JSON</label>
<label class="radio-inline"><input type="radio" name="parsetype" value="yaml" ng-model="parseType"
ng-change="parseTypeChange()">YAML</label>
<a class="external-editor-link" ng-click="showCodeEditor('code')" data-placement="top"
af-tooltip="View in code editor" href=""><i class="fa fa-external-link"></i> Code Editor</a>
</div>
<form>
<div class="form-group">
<textarea rows="10" name="code" id="code_textarea" class="form-control" ng-model="codeValue"></textarea>
</div>
</form>
</div><!-- col-lg-12 -->
</div><!-- row -->
@@ -0,0 +1,15 @@
{
"name": "angular-codemirror",
"version": "0.0.3",
"dependencies": {
"angular": "latest",
"angular-route": "latest",
"jquery": "latest",
"jqueryui": "latest",
"components-font-awesome": "latest",
"twitter": "latest",
"js-yaml": "latest",
"jsonlint": "latest",
"codemirror": "latest"
}
}
@@ -0,0 +1,111 @@
/**********************************************
* AngularCodeMirror.css
*
* CodeMirror.css overrides
*
* Copyright (c) 2014 Chris Houseknecht
*
* The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of angular-codemirror and associated files and documentation (the "Software"),
* to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
.CodeMirror {
height: auto;
}
.CodeMirror-activeline-background {
background-color: #f7f7f7;
}
/* Modal dialog overrides to make jqueryui dialog blend in with Twitter.
Why? Twitter's modal is not draggable or resizable, which is not very
useful for a code editor */
.ui-dialog-title {
font-size: 22px;
color: #1778c3;
font-weight: bold;
line-height: normal;
}
.ui-dialog .close {
font-size: 18px;
font-weight: bold;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1;
opacity: .7;
text-shadow: 0 1px 0 #ffffff;
}
.ui-dialog .ui-widget-header {
border-radius: 0;
border: none;
border-bottom: 1px solid #A9A9A9;
height: 55px;
}
.ui-dialog .ui-dialog-titlebar {
padding-bottom: 0;
padding-top: 12px;
}
.ui-dialog .ui-dialog-titlebar {
background-image: none;
background-color: #ffffff;
border-color: #ffffff;
color: #A9A9A9;
}
.ui-dialog .ui-resizable-se {
right: 5px;
bottom: 5px;
background-position: -80px -224px;
color: #171717;
}
.ui-dialog-buttonset button.btn.btn-default.ui-state-hover,
.ui-dialog-buttonset button.btn.btn-default.ui-state-active,
.ui-dialog-buttonset button.btn.btn-default.ui-state-focus {
font-weight: normal;
}
.ui-dialog-buttonset button.btn.btn-primary.ui-state-hover,
.ui-dialog-buttonset button.btn.btn-primary.ui-state-active,
.ui-dialog-buttonset button.btn.btn-primary.ui-state-focus {
background-image: none;
color: #ffffff;
background-color: #2a6496;
border-color: #285e8e;
text-decoration: none;
font-weight: normal;
}
/* Bring the overlay above any TB fixed navs and darken it to match */
.ui-widget-overlay.ui-front {
background-image: none;
background-color: #000;
opacity: .6;
z-index: 1040;
}
/* Make sure code editor dialog is always at top of stack */
[aria-describedby=af-code-editor-modal].ui-front {
z-index: 2050;
}
.CodeMirror-lint-tooltip {
z-index: 2060;
}
@@ -0,0 +1,188 @@
/**********************************************
* AngularCodeMirror.js
*
* Copyright (c) 2014 Chris Houseknecht
*
* The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of angular-codemirror and associated files and documentation (the "Software"),
* to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
'use strict';
angular.module('AngularCodeMirrorModule', [])
.factory('AngularCodeMirror', [ function() {
return function() {
var fn = function() {
this.myCodeMirror = null;
this.element = null;
this.showTextArea = function(params) {
var self = this,
element = (typeof params.element === "object") ? params.element : document.getElementById(params.element),
scope = params.scope,
model = params.model,
mode = params.mode,
onReady = params.onReady,
onChange = params.onChange,
height = 0;
self.element = $(element);
// We don't want to touch the original textarea. Angular likely has a model and other listeners
// attached to it. In prior iterations attaching CodeMirror to it seemed to go bad, so we'll insert a
// <div> under it, hide the textarea and let CodeMirror attach to the <div>.
if ($('#cm-' + model + '-container').length > 0) {
$('#cm-' + model + '-container').empty();
}
else {
self.element.after("<div id=\"cm-" + model + "-container\"></div>");
}
// Calc the height of the text area- our CodeMirror should match.
height += self.element.attr('rows') * parseInt($(self.element).css('line-height').replace(/px/,''),10);
height += parseInt(self.element.css('padding-top').replace(/px|%/,''),10) +
parseInt(self.element.css('padding-bottom').replace(/px|%/,''),10);
height += 2; //for the border
// hide
self.element.hide();
// Initialize CodeMirror
self.modes[mode].value = scope[model];
self.myCodeMirror = CodeMirror(document.getElementById('cm-' + model + '-container'), self.modes[mode]);
// Adjust the height
$('.CodeMirror').css({ 'min-height': height, 'max-height': height });
self.myCodeMirror.setSize(null, height);
// This doesn't work without a setTimeout
setTimeout(function() {
self.myCodeMirror.refresh();
if (onReady) {
onReady();
}
}, 500);
// Update the model on change
self.myCodeMirror.on('change', function() {
setTimeout(function() {
scope.$apply(function(){
scope[model] = self.myCodeMirror.getValue();
if (onChange) {
onChange();
}
});
}, 500);
});
};
this.getValue = function() {
var self = this;
return self.myCodeMirror.getValue();
};
this.destroy = function() {
// Intended for use with showTextArea. This will get ride of CM and put the
// textarea back to normal
var self = this;
$('.CodeMirror').empty().remove();
if (self.element) {
self.element.show();
}
};
this.showModal = function(params) {
var self = this,
scope = params.scope,
target = (typeof params.container === "string") ? document.getElementById(params.container) : params.container,
mode = params.mode,
model = params.model,
title = params.title || 'Code Editor',
modes = self.modes;
this.html = "<div id=\"af-code-editor-modal\"><div id=\"af-code\"></div>\n</div>\n";
if ($('#af-code-editor-modal').length === 0) {
$(target).append(this.html);
}
else {
$('#af-code-editor-modal').remove();
$(target).append(this.html);
}
$('#af-code-editor-modal').dialog({
title: title,
resizable: true,
width: Math.ceil($(window).width() * 0.9),
height: Math.ceil($(window).height() * 0.8),
position: "center",
show: true,
closeOnEscape: true,
modal: true,
autoOpen: true,
buttons: [
{ text: "Cancel", id: "af-code-edit-cancel", click: function() { $(this).dialog('close'); } },
{ text: "OK", id: "af-code-edit-ok", click:
function() {
scope.$apply(function() { scope[model] = self.myCodeMirror.getValue(); });
$(this).dialog('close');
}
}
],
open: function() {
var self = $('.ui-dialog[aria-describedby="af-code-editor-modal"]'),
idx, options;
// bring the overlay up to just below the new window
idx = self.css('z-index');
$('.ui-widget-overlay').css({ 'z-index': idx - 1});
// fix buttons- make them more twittery
self.find('.ui-dialog-titlebar button').empty().attr({'class': 'close'}).text('x');
$('#af-code-edit-cancel').attr({ "class": "btn btn-default" }).empty().html("<i class=\"fa fa-times\"></i> Cancel");
$('#af-code-edit-ok').attr({ "class": "btn btn-primary" }).empty().html("<i class=\"fa fa-check\"></i> Save");
// initialize CodeMirror
options = modes[mode];
options.value = scope[model];
self.myCodeMirror = CodeMirror(document.getElementById('af-code'), options);
}
});
};
// Don't maintain modes here. Use this.addModes() to set/override available modes
this.modes = {};
// Add or override available modes.
this.addModes = function(obj) {
for (var key in obj) {
if (this.modes[key]) {
delete this.modes[key];
}
this.modes[key] = angular.copy(obj[key]);
}
};
};
return new fn();
};
}]);
+15
View File
@@ -0,0 +1,15 @@
// Add YAML lint support to CodeMirror. Submitted pull request #2266
// Depends on js-yaml.js from https://github.com/nodeca/js-yaml
// declare global: jsyaml
CodeMirror.registerHelper("lint", "yaml", function(text) {
var found = [];
try { jsyaml.load(text); }
catch(e) {
var loc = e.mark;
found.push({ from: CodeMirror.Pos(loc.line, loc.column), to: CodeMirror.Pos(loc.line, loc.column), message: e.message });
}
return found;
});
CodeMirror.yamlValidator = CodeMirror.lint.yaml; // deprecated
+12
View File
@@ -0,0 +1,12 @@
#!/bin/bash
#
# Minify angular-forms.js
#
# ./compile.sh
#
if [ -f ../angular-forms.min.js ]; then
rm ../angular-forms.min.js
fi
java -jar ../bower_components/closure-compiler/compiler.jar --js ../angular-forms.js --js_output_file ../angular-forms.min.js
+244
View File
@@ -0,0 +1,244 @@
#!/usr/bin/env node
var util = require('util'),
http = require('http'),
fs = require('fs'),
url = require('url'),
events = require('events');
var DEFAULT_PORT = 8000;
function main(argv) {
new HttpServer({
'GET': createServlet(StaticServlet),
'HEAD': createServlet(StaticServlet)
}).start(Number(argv[2]) || DEFAULT_PORT);
}
function escapeHtml(value) {
return value.toString().
replace('<', '&lt;').
replace('>', '&gt;').
replace('"', '&quot;');
}
function createServlet(Class) {
var servlet = new Class();
return servlet.handleRequest.bind(servlet);
}
/**
* An Http server implementation that uses a map of methods to decide
* action routing.
*
* @param {Object} Map of method => Handler function
*/
function HttpServer(handlers) {
this.handlers = handlers;
this.server = http.createServer(this.handleRequest_.bind(this));
}
HttpServer.prototype.start = function(port) {
this.port = port;
this.server.listen(port);
util.puts('Http Server running at http://localhost:' + port + '/');
};
HttpServer.prototype.parseUrl_ = function(urlString) {
var parsed = url.parse(urlString);
parsed.pathname = url.resolve('/', parsed.pathname);
return url.parse(url.format(parsed), true);
};
HttpServer.prototype.handleRequest_ = function(req, res) {
var logEntry = req.method + ' ' + req.url;
if (req.headers['user-agent']) {
logEntry += ' ' + req.headers['user-agent'];
}
util.puts(logEntry);
req.url = this.parseUrl_(req.url);
var handler = this.handlers[req.method];
if (!handler) {
res.writeHead(501);
res.end();
} else {
handler.call(this, req, res);
}
};
/**
* Handles static content.
*/
function StaticServlet() {}
StaticServlet.MimeMap = {
'txt': 'text/plain',
'html': 'text/html',
'css': 'text/css',
'xml': 'application/xml',
'json': 'application/json',
'js': 'application/javascript',
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'gif': 'image/gif',
'png': 'image/png',
  'svg': 'image/svg+xml'
};
StaticServlet.prototype.handleRequest = function(req, res) {
var self = this;
var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){
return String.fromCharCode(parseInt(hex, 16));
});
var parts = path.split('/');
if (parts[parts.length-1].charAt(0) === '.')
return self.sendForbidden_(req, res, path);
fs.stat(path, function(err, stat) {
if (err)
return self.sendMissing_(req, res, path);
if (stat.isDirectory())
return self.sendDirectory_(req, res, path);
return self.sendFile_(req, res, path);
});
}
StaticServlet.prototype.sendError_ = function(req, res, error) {
res.writeHead(500, {
'Content-Type': 'text/html'
});
res.write('<!doctype html>\n');
res.write('<title>Internal Server Error</title>\n');
res.write('<h1>Internal Server Error</h1>');
res.write('<pre>' + escapeHtml(util.inspect(error)) + '</pre>');
util.puts('500 Internal Server Error');
util.puts(util.inspect(error));
};
StaticServlet.prototype.sendMissing_ = function(req, res, path) {
path = path.substring(1);
res.writeHead(404, {
'Content-Type': 'text/html'
});
res.write('<!doctype html>\n');
res.write('<title>404 Not Found</title>\n');
res.write('<h1>Not Found</h1>');
res.write(
'<p>The requested URL ' +
escapeHtml(path) +
' was not found on this server.</p>'
);
res.end();
util.puts('404 Not Found: ' + path);
};
StaticServlet.prototype.sendForbidden_ = function(req, res, path) {
path = path.substring(1);
res.writeHead(403, {
'Content-Type': 'text/html'
});
res.write('<!doctype html>\n');
res.write('<title>403 Forbidden</title>\n');
res.write('<h1>Forbidden</h1>');
res.write(
'<p>You do not have permission to access ' +
escapeHtml(path) + ' on this server.</p>'
);
res.end();
util.puts('403 Forbidden: ' + path);
};
StaticServlet.prototype.sendRedirect_ = function(req, res, redirectUrl) {
res.writeHead(301, {
'Content-Type': 'text/html',
'Location': redirectUrl
});
res.write('<!doctype html>\n');
res.write('<title>301 Moved Permanently</title>\n');
res.write('<h1>Moved Permanently</h1>');
res.write(
'<p>The document has moved <a href="' +
redirectUrl +
'">here</a>.</p>'
);
res.end();
util.puts('301 Moved Permanently: ' + redirectUrl);
};
StaticServlet.prototype.sendFile_ = function(req, res, path) {
var self = this;
var file = fs.createReadStream(path);
res.writeHead(200, {
'Content-Type': StaticServlet.
MimeMap[path.split('.').pop()] || 'text/plain'
});
if (req.method === 'HEAD') {
res.end();
} else {
file.on('data', res.write.bind(res));
file.on('close', function() {
res.end();
});
file.on('error', function(error) {
self.sendError_(req, res, error);
});
}
};
StaticServlet.prototype.sendDirectory_ = function(req, res, path) {
var self = this;
if (path.match(/[^\/]$/)) {
req.url.pathname += '/';
var redirectUrl = url.format(url.parse(url.format(req.url)));
return self.sendRedirect_(req, res, redirectUrl);
}
fs.readdir(path, function(err, files) {
if (err)
return self.sendError_(req, res, error);
if (!files.length)
return self.writeDirectoryIndex_(req, res, path, []);
var remaining = files.length;
files.forEach(function(fileName, index) {
fs.stat(path + '/' + fileName, function(err, stat) {
if (err)
return self.sendError_(req, res, err);
if (stat.isDirectory()) {
files[index] = fileName + '/';
}
if (!(--remaining))
return self.writeDirectoryIndex_(req, res, path, files);
});
});
});
};
StaticServlet.prototype.writeDirectoryIndex_ = function(req, res, path, files) {
path = path.substring(1);
res.writeHead(200, {
'Content-Type': 'text/html'
});
if (req.method === 'HEAD') {
res.end();
return;
}
res.write('<!doctype html>\n');
res.write('<title>' + escapeHtml(path) + '</title>\n');
res.write('<style>\n');
res.write(' ol { list-style-type: none; font-size: 1.2em; }\n');
res.write('</style>\n');
res.write('<h1>Directory: ' + escapeHtml(path) + '</h1>');
res.write('<ol>');
files.forEach(function(fileName) {
if (fileName.charAt(0) !== '.') {
res.write('<li><a href="' +
escapeHtml(fileName) + '">' +
escapeHtml(fileName) + '</a></li>');
}
});
res.write('</ol>');
res.end();
};
// Must be last,
main(process.argv);
@@ -0,0 +1,18 @@
{
"name": "angular-cookies",
"version": "1.2.15-build.2398+sha.4bab3d8",
"main": "./angular-cookies.js",
"dependencies": {
"angular": "1.2.15-build.2398+sha.4bab3d8"
},
"homepage": "https://github.com/angular/bower-angular-cookies",
"_release": "1.2.15-build.2398+sha.4bab3d8",
"_resolution": {
"type": "version",
"tag": "v1.2.15-build.2398+sha.4bab3d8",
"commit": "8ca6ddfbd86f4bda921fa3d22e8d2e7d7e9b04d4"
},
"_source": "git://github.com/angular/bower-angular-cookies.git",
"_target": "~1.2.12",
"_originalSource": "angular-cookies"
}
@@ -0,0 +1,54 @@
# bower-angular-cookies
This repo is for distribution on `bower`. The source for this module is in the
[main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngCookies).
Please file issues and pull requests against that repo.
## Install
Install with `bower`:
```shell
bower install angular-cookies
```
Add a `<script>` to your `index.html`:
```html
<script src="/bower_components/angular-cookies/angular-cookies.js"></script>
```
And add `ngCookies` as a dependency for your app:
```javascript
angular.module('myApp', ['ngCookies']);
```
## Documentation
Documentation is available on the
[AngularJS docs site](http://docs.angularjs.org/api/ngCookies).
## License
The MIT License
Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+197
View File
@@ -0,0 +1,197 @@
/**
* @license AngularJS v1.2.15-build.2398+sha.4bab3d8
* (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular, undefined) {'use strict';
/**
* @ngdoc module
* @name ngCookies
* @description
*
* # ngCookies
*
* The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies.
*
*
* <div doc-module-components="ngCookies"></div>
*
* See {@link ngCookies.$cookies `$cookies`} and
* {@link ngCookies.$cookieStore `$cookieStore`} for usage.
*/
angular.module('ngCookies', ['ng']).
/**
* @ngdoc service
* @name $cookies
*
* @description
* Provides read/write access to browser's cookies.
*
* Only a simple Object is exposed and by adding or removing properties to/from
* this object, new cookies are created/deleted at the end of current $eval.
*
* Requires the {@link ngCookies `ngCookies`} module to be installed.
*
* @example
<example>
<file name="index.html">
<script>
function ExampleController($cookies) {
// Retrieving a cookie
var favoriteCookie = $cookies.myFavorite;
// Setting a cookie
$cookies.myFavorite = 'oatmeal';
}
</script>
</file>
</example>
*/
factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
var cookies = {},
lastCookies = {},
lastBrowserCookies,
runEval = false,
copy = angular.copy,
isUndefined = angular.isUndefined;
//creates a poller fn that copies all cookies from the $browser to service & inits the service
$browser.addPollFn(function() {
var currentCookies = $browser.cookies();
if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl
lastBrowserCookies = currentCookies;
copy(currentCookies, lastCookies);
copy(currentCookies, cookies);
if (runEval) $rootScope.$apply();
}
})();
runEval = true;
//at the end of each eval, push cookies
//TODO: this should happen before the "delayed" watches fire, because if some cookies are not
// strings or browser refuses to store some cookies, we update the model in the push fn.
$rootScope.$watch(push);
return cookies;
/**
* Pushes all the cookies from the service to the browser and verifies if all cookies were
* stored.
*/
function push() {
var name,
value,
browserCookies,
updated;
//delete any cookies deleted in $cookies
for (name in lastCookies) {
if (isUndefined(cookies[name])) {
$browser.cookies(name, undefined);
}
}
//update all cookies updated in $cookies
for(name in cookies) {
value = cookies[name];
if (!angular.isString(value)) {
if (angular.isDefined(lastCookies[name])) {
cookies[name] = lastCookies[name];
} else {
delete cookies[name];
}
} else if (value !== lastCookies[name]) {
$browser.cookies(name, value);
updated = true;
}
}
//verify what was actually stored
if (updated){
updated = false;
browserCookies = $browser.cookies();
for (name in cookies) {
if (cookies[name] !== browserCookies[name]) {
//delete or reset all cookies that the browser dropped from $cookies
if (isUndefined(browserCookies[name])) {
delete cookies[name];
} else {
cookies[name] = browserCookies[name];
}
updated = true;
}
}
}
}
}]).
/**
* @ngdoc service
* @name $cookieStore
* @requires $cookies
*
* @description
* Provides a key-value (string-object) storage, that is backed by session cookies.
* Objects put or retrieved from this storage are automatically serialized or
* deserialized by angular's toJson/fromJson.
*
* Requires the {@link ngCookies `ngCookies`} module to be installed.
*
* @example
*/
factory('$cookieStore', ['$cookies', function($cookies) {
return {
/**
* @ngdoc method
* @name $cookieStore#get
*
* @description
* Returns the value of given cookie key
*
* @param {string} key Id to use for lookup.
* @returns {Object} Deserialized cookie value.
*/
get: function(key) {
var value = $cookies[key];
return value ? angular.fromJson(value) : value;
},
/**
* @ngdoc method
* @name $cookieStore#put
*
* @description
* Sets a value for given cookie key
*
* @param {string} key Id for the `value`.
* @param {Object} value Value to be stored.
*/
put: function(key, value) {
$cookies[key] = angular.toJson(value);
},
/**
* @ngdoc method
* @name $cookieStore#remove
*
* @description
* Remove given cookie
*
* @param {string} key Id of the key-value pair to delete.
*/
remove: function(key) {
delete $cookies[key];
}
};
}]);
})(window, window.angular);
@@ -0,0 +1,8 @@
/*
AngularJS v1.2.15-build.2398+sha.4bab3d8
(c) 2010-2014 Google, Inc. http://angularjs.org
License: MIT
*/
(function(p,f,n){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(d,b){var c={},g={},h,k=!1,l=f.copy,m=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,l(a,g),l(a,c),k&&d.$apply())})();k=!0;d.$watch(function(){var a,e,d;for(a in g)m(c[a])&&b.cookies(a,n);for(a in c)(e=c[a],f.isString(e))?e!==g[a]&&(b.cookies(a,e),d=!0):f.isDefined(g[a])?c[a]=g[a]:delete c[a];if(d)for(a in e=b.cookies(),c)c[a]!==e[a]&&(m(e[a])?delete c[a]:c[a]=e[a])});
return c}]).factory("$cookieStore",["$cookies",function(d){return{get:function(b){return(b=d[b])?f.fromJson(b):b},put:function(b,c){d[b]=f.toJson(c)},remove:function(b){delete d[b]}}}])})(window,window.angular);
//# sourceMappingURL=angular-cookies.min.js.map
@@ -0,0 +1,8 @@
{
"version":3,
"file":"angular-cookies.min.js",
"lineCount":7,
"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAmBtCD,CAAAE,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,QAAA,CA2BW,UA3BX,CA2BuB,CAAC,YAAD,CAAe,UAAf,CAA2B,QAAS,CAACC,CAAD,CAAaC,CAAb,CAAuB,CAAA,IACxEC,EAAU,EAD8D,CAExEC,EAAc,EAF0D,CAGxEC,CAHwE,CAIxEC,EAAU,CAAA,CAJ8D,CAKxEC,EAAOV,CAAAU,KALiE,CAMxEC,EAAcX,CAAAW,YAGlBN,EAAAO,UAAA,CAAmB,QAAQ,EAAG,CAC5B,IAAIC,EAAiBR,CAAAC,QAAA,EACjBE,EAAJ,EAA0BK,CAA1B,GACEL,CAGA,CAHqBK,CAGrB,CAFAH,CAAA,CAAKG,CAAL,CAAqBN,CAArB,CAEA,CADAG,CAAA,CAAKG,CAAL,CAAqBP,CAArB,CACA,CAAIG,CAAJ,EAAaL,CAAAU,OAAA,EAJf,CAF4B,CAA9B,CAAA,EAUAL,EAAA,CAAU,CAAA,CAKVL,EAAAW,OAAA,CASAC,QAAa,EAAG,CAAA,IACVC,CADU,CAEVC,CAFU,CAIVC,CAGJ,KAAKF,CAAL,GAAaV,EAAb,CACMI,CAAA,CAAYL,CAAA,CAAQW,CAAR,CAAZ,CAAJ,EACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBhB,CAAvB,CAKJ,KAAIgB,CAAJ,GAAYX,EAAZ,CAEE,CADAY,CACK,CADGZ,CAAA,CAAQW,CAAR,CACH,CAAAjB,CAAAoB,SAAA,CAAiBF,CAAjB,CAAL,EAMWA,CANX,GAMqBX,CAAA,CAAYU,CAAZ,CANrB,GAOEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBC,CAAvB,CACA,CAAAC,CAAA,CAAU,CAAA,CARZ,EACMnB,CAAAqB,UAAA,CAAkBd,CAAA,CAAYU,CAAZ,CAAlB,CAAJ,CACEX,CAAA,CAAQW,CAAR,CADF,CACkBV,CAAA,CAAYU,CAAZ,CADlB,CAGE,OAAOX,CAAA,CAAQW,CAAR,CASb,IAAIE,CAAJ,CAIE,IAAKF,CAAL,GAFAK,EAEahB,CAFID,CAAAC,QAAA,EAEJA,CAAAA,CAAb,CACMA,CAAA,CAAQW,CAAR,CAAJ,GAAsBK,CAAA,CAAeL,CAAf,CAAtB,GAEMN,CAAA,CAAYW,CAAA,CAAeL,CAAf,CAAZ,CAAJ,CACE,OAAOX,CAAA,CAAQW,CAAR,CADT,CAGEX,CAAA,CAAQW,CAAR,CAHF,CAGkBK,CAAA,CAAeL,CAAf,CALpB,CAlCU,CAThB,CAEA;MAAOX,EA1BqE,CAA3D,CA3BvB,CAAAH,QAAA,CA2HW,cA3HX,CA2H2B,CAAC,UAAD,CAAa,QAAQ,CAACoB,CAAD,CAAW,CAErD,MAAO,KAWAC,QAAQ,CAACC,CAAD,CAAM,CAEjB,MAAO,CADHP,CACG,CADKK,CAAA,CAASE,CAAT,CACL,EAAQzB,CAAA0B,SAAA,CAAiBR,CAAjB,CAAR,CAAkCA,CAFxB,CAXd,KA0BAS,QAAQ,CAACF,CAAD,CAAMP,CAAN,CAAa,CACxBK,CAAA,CAASE,CAAT,CAAA,CAAgBzB,CAAA4B,OAAA,CAAeV,CAAf,CADQ,CA1BrB,QAuCGW,QAAQ,CAACJ,CAAD,CAAM,CACpB,OAAOF,CAAA,CAASE,CAAT,CADa,CAvCjB,CAF8C,CAAhC,CA3H3B,CAnBsC,CAArC,CAAA,CA+LE1B,MA/LF,CA+LUA,MAAAC,QA/LV;",
"sources":["angular-cookies.js"],
"names":["window","angular","undefined","module","factory","$rootScope","$browser","cookies","lastCookies","lastBrowserCookies","runEval","copy","isUndefined","addPollFn","currentCookies","$apply","$watch","push","name","value","updated","isString","isDefined","browserCookies","$cookies","get","key","fromJson","put","toJson","remove"]
}
@@ -0,0 +1,8 @@
{
"name": "angular-cookies",
"version": "1.2.15-build.2398+sha.4bab3d8",
"main": "./angular-cookies.js",
"dependencies": {
"angular": "1.2.15-build.2398+sha.4bab3d8"
}
}
@@ -0,0 +1,31 @@
{
"author": "Francesco Pontillo",
"name": "angular-filters",
"description": "A collection of filters for AngularJS.",
"version": "1.1.0",
"homepage": "https://github.com/frapontillo/angular-filters",
"repository": {
"type": "git",
"url": "git://github.com/frapontillo/angular-filters.git"
},
"main": "./dist/angular-filters.min.js",
"dependencies": {
"angular": "1.2.10"
},
"devDependencies": {
"angular-mocks": "1.2.10"
},
"resolutions": {
"angular": "1.2.10"
},
"_release": "1.1.0",
"_resolution": {
"type": "version",
"tag": "1.1.0",
"commit": "ecd468b898f99786e90c4631835e83ef93a2d743"
},
"_source": "git://github.com/frapontillo/angular-filters.git",
"_target": "~1.1.0",
"_originalSource": "angular-filters",
"_direct": true
}
@@ -0,0 +1,3 @@
.idea
node_modules
bower_components
@@ -0,0 +1,26 @@
{
"node": true,
"browser": true,
"esnext": true,
"bitwise": true,
"camelcase": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"indent": 2,
"latedef": true,
"newcap": true,
"noarg": true,
"quotmark": "single",
"regexp": true,
"undef": true,
"unused": true,
"strict": true,
"trailing": true,
"smarttabs": true,
"globals": {
"angular": false,
"$": false,
"jQuery": false
}
}
@@ -0,0 +1,12 @@
language: node_js
node_js:
- "0.10.15"
before_install:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- npm install -g grunt-cli karma bower
- npm install
- bower install
script: "grunt"
@@ -0,0 +1,32 @@
CHANGELOG
=========
#### v1.1.0
- Added `property` filter
- Added `join` filter
- Updated to angular 1.2.10
#### v1.0.1
- Improved tests and stability
- Rewritten build process
#### v1.0.0
- Main module renamed to `frapontillo.ex.filters` in order to adhere with the [Angular Component Specification draft](https://github.com/PascalPrecht/angular-component-spec).
- Added `bool` filter.
- Upgraded bower information, node packages and Karma test runner.
#### v0.0.2
- Added `firstNotNull`, `lastNotNull`, `max`, `min`.
- Test set complete.
- TravisCI is working.
#### v0.0.1
- First release.
- `default` filter is the only filter at the moment.
- Unit testing with grunt, testacular and gruntacular configured.
- `defaultSpec` test written.
+109
View File
@@ -0,0 +1,109 @@
'use strict';
module.exports = function(grunt) {
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
// configurable paths
var yeomanConfig = {
src: 'src',
dist: 'dist',
test: 'test'
};
grunt.initConfig({
yeoman: yeomanConfig,
pkg: grunt.file.readJSON('package.json'),
dev: {
reporters: 'dots'
},
karma : {
options: {
configFile: 'karma.conf.js',
singleRun: true
},
travis: {
browsers: ['PhantomJS']
},
local: {
browsers: ['Chrome']
},
dev: {
singleRun: false
}
},
jshint: {
options: {
jshintrc: '.jshintrc'
},
src: [
'Gruntfile.js',
'<%= yeoman.src %>/**/*.js'
],
test: {
src: ['<%= yeoman.test %>/**/*.js'],
options: {
jshintrc: 'test/.jshintrc'
}
}
},
meta: {
banner: '/**\n' + ' * <%= pkg.description %>\n' +
' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' +
' * @author <%= pkg.author.name %>\n' +
' * @link <%= pkg.homepage %>\n' +
' * @license <%= _.pluck(pkg.licenses, "type").join(", ") %>\n**/\n\n'
},
clean: {
dist: {
files: [{
dot: true,
src: [
'<%= yeoman.dist %>/*',
'!<%= yeoman.dist %>/.git*'
]
}]
},
temp: {
src: ['<%= yeoman.dist %>/.temp']
}
},
ngmin: {
dist: {
expand: true,
cwd: '<%= yeoman.src %>',
src: ['**/*.js'],
dest: '<%= yeoman.dist %>/.temp'
}
},
concat: {
options: {
banner: '<%= meta.banner %>\'use strict\';\n',
process: function(src, filepath) {
return '// Source: ' + filepath + '\n' +
src.replace(/(^|\n)[ \t]*('use strict'|"use strict");?\s*/g, '$1');
}
},
build: {
src: ['common/*.js', '<%= yeoman.dist %>/.temp/**/*.js'],
dest: '<%= yeoman.dist %>/<%= pkg.name %>.js'
}
},
uglify: {
options: {
banner: '<%= meta.banner %>'
},
build: {
src: ['<%= yeoman.dist %>/<%= pkg.name %>.js'],
dest: '<%= yeoman.dist %>/<%= pkg.name %>.min.js'
}
}
});
grunt.registerTask('test', ['jshint', 'karma:unit']);
grunt.registerTask('test-travis', ['jshint', 'karma:travis']);
grunt.registerTask('build', ['clean', 'ngmin', 'concat', 'uglify', 'clean:temp']);
grunt.registerTask('travis', ['test-travis', 'build']);
grunt.registerTask('default', ['test-travis', 'build']);
};
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+200
View File
@@ -0,0 +1,200 @@
angular-filters [![Build Status](https://travis-ci.org/frapontillo/angular-filters.png?branch=master)](https://travis-ci.org/frapontillo/angular-filters)
===============
A collection of useful filters for [AngularJS](http://angularjs.org/).
You can install the latest version of `angular-filters` with `bower`:
```bash
$ bower install angular-filters
```
Then, simply include `./dist/angular-filters.js` or `./dist/angular-filters.min.js` in your Web app and inject the module `frapontillo.ex.filters` in your application.
## Filters specs
The included filters are:
- [`bool:trueValue:falseValue`](#bool)
- [`default:defaultValue`](#default)
- [`firstNotNull`](#firstnotnull)
- [`lastNotNull`](#lastnotnull)
- [`max`](#max)
- [`min`](#min)
- [`property`](#property)
- [`join`](#join)
### bool
The `bool` filter allows to **specify true and false values** to show depending on the input value. The second parameter will be returned if and only if the first parameter is `true`; the third parameter will be returned if and only if the first parameter is `false`.
This filter can be used to print a specific message depending on a boolean value.
Use it as follows:
```html
<p>{{ someBoolValue | bool:'Candies!':'No candies :(' }}</p>
```
```javascript
$scope.returnValue = $filter('bool')($scope.someBoolValue, 'Candies!', 'No candies :(');
```
### default
The `default` filter allows to **specify a default fallback value** if an object is one of the following:
- `null`
- `undefined`
- empty string, `''`
Please notice that if a value equals to `0`, the default value won't be returned, as `0` is accepted.
This filter is useful when another filter return is not safe and when you want to display a fallback value.
Use it as follows:
```html
<p>{{ someValue | number:2 | default:'No value is available.' }}</p>
```
```javascript
$scope.returnValue = $filter('default')
($filter('number')($scope.someValue, 2), 'No value is available.');
```
### firstNotNull
The `firstNotNull` filter returns the **first element from an array** that is neither `null` or `undefined`. This means it returns all numbers and strings, even if empty. It returns `undefined` if all values aren't set or if the array is empty.
Use it as follows:
```html
<p>{{ myValues | firstNotNull }}</p>
```
```javascript
$scope.firstValue = $filter('firstNotNull')($scope.myValues);
```
### lastNotNull
The `lastNotNull` filter returns the **last element from an array** that is neither `null` or `undefined`. This means it returns all numbers and strings, even if empty. It returns `undefined` if all values aren't set or if the array is empty.
Use it as follows:
```html
<p>{{ myValues | lastNotNull }}</p>
```
```javascript
$scope.firstValue = $filter('lastNotNull')($scope.myValues);
```
### max
The `max` filter returns the **maximum value from an array** that is neither `null` or `undefined`. It returns `undefined` if all values aren't set or if the array is empty.
Use it as follows:
```html
<p>{{ myValues | max }}</p>
```
```javascript
$scope.maxValue = $filter('max')($scope.myValues);
```
### min
The `min` filter returns the **minimum value from an array** that is neither `null` or `undefined`. It returns `undefined` if all values aren't set or if the array is empty.
Use it as follows:
```html
<p>{{ myValues | min }}</p>
```
```javascript
$scope.minValue = $filter('min')($scope.myValues);
```
### property
The `property` filter returns an **array with only the specified property from the original objects**, not altering the `null` or `undefined` values.
Use it as follows:
```html
<p>{{ myObjects | property:'myText' }}</p>
```
```javascript
$scope.allTheTexts = $filter('property')($scope.myObjects, 'myText');
```
### join
The `join` filter returns **the original array as a string, with its elements joined with the specified separator**, if any, otherwise defaulting to the comma `,`.
Use it as follows:
```html
<p>{{ myValues | join:', ' }}</p>
```
```javascript
$scope.joinedValues = $filter('join')($scope.myValues, ', ');
```
## Development
### Test and build
To test and build the distribution files yourself, do the following:
```shell
npm install -g grunt-cli karma bower
npm install
bower install
grunt
```
These are the available grunt task:
* `karma:travis`, run karma tests once, on PhantomJS
* `karma:local`, run karma tests once, on Chrome
* `karma:dev`, run karma tests indefinitely after every file change, on Chrome
* `jshint:src`, run jshint on every source file
* `jshint:test`, run jshint on every test file
* `clean:dist`, clean the distribution directory
* `clean:temp`, clean the temporary directory
* `ngmin`, prepares every angular file into the `dist/.temp` directory
* `concat`, concatenates the module declaration and the `ngmin`-ified file from the `dist/.temp` into the `dist` directory, adding the banner
* `uglify`, minifies the output file in the `dist` directory, adding the banner
* `build`, builds the regular and minified file
* `test-travis`, runs `jshint` and `karma:travis`
Use the default task by calling `grunt` to run tests on PhantomJS and builds the regular and minified file.
### Contribute
To contribute, please follow the generic [AngularJS Contributing Guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md), with the only exception to send the PR to the `develop` branch instead of `master`.
## License
```
Copyright 2014 Francesco Pontillo
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
@@ -0,0 +1,21 @@
{
"author": "Francesco Pontillo",
"name": "angular-filters",
"description": "A collection of filters for AngularJS.",
"version": "1.1.0",
"homepage": "https://github.com/frapontillo/angular-filters",
"repository": {
"type": "git",
"url": "git://github.com/frapontillo/angular-filters.git"
},
"main": "./dist/angular-filters.min.js",
"dependencies": {
"angular": "1.2.10"
},
"devDependencies": {
"angular-mocks": "1.2.10"
},
"resolutions": {
"angular": "1.2.10"
}
}
+2
View File
@@ -0,0 +1,2 @@
angular.module('frapontillo.ex.filters', []);
angular.module('frapontillo', ['ex.filters']);
@@ -0,0 +1,101 @@
/**
* A collection of filters for AngularJS.
* @version v1.1.0 - 2014-01-30
* @author Francesco Pontillo
* @link https://github.com/frapontillo/angular-filters
* @license Apache License 2.0
**/
'use strict';
// Source: common/module.js
angular.module('frapontillo.ex.filters', []);
angular.module('frapontillo', ['ex.filters']);
// Source: dist/.temp/filters/bool/bool.js
angular.module('frapontillo.ex.filters').filter('bool', function () {
return function (input, valueTrue, valueFalse) {
return input !== true ? valueFalse : valueTrue;
};
});
// Source: dist/.temp/filters/default/default.js
angular.module('frapontillo.ex.filters').filter('default', function () {
return function (input, value) {
if (input !== null && input !== undefined && (input !== '' || angular.isNumber(input))) {
return input;
}
return value || '';
};
});
// Source: dist/.temp/filters/firstNotNull/firstNotNull.js
angular.module('frapontillo.ex.filters').filter('firstNotNull', function () {
return function (input) {
if (input) {
var l = input.length - 1;
for (var i = 0; i <= l; i++) {
if (input[i] !== undefined && input[i] !== null) {
return input[i];
}
}
}
};
});
// Source: dist/.temp/filters/join/join.js
angular.module('frapontillo.ex.filters').filter('join', function () {
return function (array, separator) {
if (!array) {
return '';
}
return array.join(separator);
};
});
// Source: dist/.temp/filters/lastNotNull/lastNotNull.js
angular.module('frapontillo.ex.filters').filter('lastNotNull', function () {
return function (input) {
if (input) {
var l = input.length - 1;
for (var i = l; i >= 0; i--) {
if (input[i] !== undefined) {
return input[i];
}
}
}
};
});
// Source: dist/.temp/filters/max/max.js
angular.module('frapontillo.ex.filters').filter('max', function () {
return function (input) {
var out;
if (input) {
for (var i in input) {
if (input[i] > out || out === undefined || out === null) {
out = input[i];
}
}
}
return out;
};
});
// Source: dist/.temp/filters/min/min.js
angular.module('frapontillo.ex.filters').filter('min', function () {
return function (input) {
var out;
if (input) {
for (var i in input) {
if (input[i] < out || out === undefined || out === null) {
out = input[i];
}
}
}
return out;
};
});
// Source: dist/.temp/filters/property/property.js
angular.module('frapontillo.ex.filters').filter('property', function () {
return function (array, property) {
var newArray = [];
angular.forEach(array, function (element) {
var evalProperty = element[property];
newArray.push(evalProperty);
});
return newArray;
};
});
@@ -0,0 +1,9 @@
/**
* A collection of filters for AngularJS.
* @version v1.1.0 - 2014-01-30
* @author Francesco Pontillo
* @link https://github.com/frapontillo/angular-filters
* @license Apache License 2.0
**/
"use strict";angular.module("frapontillo.ex.filters",[]),angular.module("frapontillo",["ex.filters"]),angular.module("frapontillo.ex.filters").filter("bool",function(){return function(a,b,c){return a!==!0?c:b}}),angular.module("frapontillo.ex.filters").filter("default",function(){return function(a,b){return null===a||void 0===a||""===a&&!angular.isNumber(a)?b||"":a}}),angular.module("frapontillo.ex.filters").filter("firstNotNull",function(){return function(a){if(a)for(var b=a.length-1,c=0;b>=c;c++)if(void 0!==a[c]&&null!==a[c])return a[c]}}),angular.module("frapontillo.ex.filters").filter("join",function(){return function(a,b){return a?a.join(b):""}}),angular.module("frapontillo.ex.filters").filter("lastNotNull",function(){return function(a){if(a)for(var b=a.length-1,c=b;c>=0;c--)if(void 0!==a[c])return a[c]}}),angular.module("frapontillo.ex.filters").filter("max",function(){return function(a){var b;if(a)for(var c in a)(a[c]>b||void 0===b||null===b)&&(b=a[c]);return b}}),angular.module("frapontillo.ex.filters").filter("min",function(){return function(a){var b;if(a)for(var c in a)(a[c]<b||void 0===b||null===b)&&(b=a[c]);return b}}),angular.module("frapontillo.ex.filters").filter("property",function(){return function(a,b){var c=[];return angular.forEach(a,function(a){var d=a[b];c.push(d)}),c}});
@@ -0,0 +1,72 @@
// Karma configuration
// Generated on Tue Aug 27 2013 11:58:44 GMT+0200 (ora legale Europa occidentale)
module.exports = function(config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
// frameworks to use
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'common/module.js',
'src/**/*.js',
'test/*/*Spec.js'
],
// list of files to exclude
exclude: [
],
// test results reporter to use
// possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_DEBUG,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['Chrome'],
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false
});
};
@@ -0,0 +1,44 @@
{
"author": {
"name": "Francesco Pontillo",
"email": "francescopontillo@gmail.com",
"url": "https://github.com/frapontillo"
},
"name": "angular-filters",
"description": "A collection of filters for AngularJS.",
"version": "1.1.0",
"homepage": "https://github.com/frapontillo/angular-filters",
"repository": {
"type": "git",
"url": "git://github.com/frapontillo/angular-filters.git"
},
"keywords": [
"angularjs",
"angular",
"filter"
],
"bugs": {
"url": "https://github.com/frapontillo/angular-filters/issues"
},
"licenses": [
{
"type": "Apache License 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
],
"readmeFilename": "README.md",
"engines": {
"node": ">= 0.10.15"
},
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-jshint": "~0.6.0",
"grunt-contrib-uglify": "~0.2.7",
"grunt-karma": "~0.6.2",
"matchdep": "~0.3.0",
"grunt-ngmin": "0.0.3"
}
}
@@ -0,0 +1,9 @@
'use strict';
angular.module('frapontillo.ex.filters')
.filter('bool', function() {
return function(input, valueTrue, valueFalse) {
return input !== true ? valueFalse : valueTrue;
};
}
);
@@ -0,0 +1,12 @@
'use strict';
angular.module('frapontillo.ex.filters')
.filter('default', function() {
return function(input, value) {
if (input !== null && input !== undefined && (input !== '' || angular.isNumber(input))) {
return input;
}
return value || '';
};
}
);
@@ -0,0 +1,16 @@
'use strict';
angular.module('frapontillo.ex.filters')
.filter('firstNotNull', function() {
return function(input) {
if (input) {
var l = input.length - 1;
for (var i = 0; i <= l; i++) {
if (input[i] !== undefined && input[i] !== null) {
return input[i];
}
}
}
};
}
);
@@ -0,0 +1,12 @@
'use strict';
angular.module('frapontillo.ex.filters')
.filter('join', function() {
return function(array, separator) {
if (!array) {
return '';
}
return array.join(separator);
};
}
);
@@ -0,0 +1,16 @@
'use strict';
angular.module('frapontillo.ex.filters')
.filter('lastNotNull', function() {
return function(input) {
if (input) {
var l = input.length - 1;
for (var i = l; i >= 0; i--) {
if (input[i] !== undefined) {
return input[i];
}
}
}
};
}
);
@@ -0,0 +1,17 @@
'use strict';
angular.module('frapontillo.ex.filters')
.filter('max', function() {
return function(input) {
var out;
if (input) {
for (var i in input) {
if (input[i] > out || out === undefined || out === null) {
out = input[i];
}
}
}
return out;
};
}
);
@@ -0,0 +1,17 @@
'use strict';
angular.module('frapontillo.ex.filters')
.filter('min', function() {
return function(input) {
var out;
if (input) {
for (var i in input) {
if (input[i] < out || out === undefined || out === null) {
out = input[i];
}
}
}
return out;
};
}
);
@@ -0,0 +1,15 @@
'use strict';
angular.module('frapontillo.ex.filters')
.filter('property', function() {
return function(array, property) {
var newArray = [];
// for each object in the array
angular.forEach(array, function(element) {
var evalProperty = element[property];
newArray.push(evalProperty);
});
return newArray;
};
}
);
@@ -0,0 +1,35 @@
{
"node": true,
"browser": true,
"esnext": true,
"bitwise": true,
"camelcase": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"indent": 2,
"latedef": true,
"newcap": true,
"noarg": true,
"quotmark": "single",
"regexp": true,
"undef": true,
"unused": true,
"strict": true,
"trailing": true,
"smarttabs": true,
"globals": {
"after": false,
"afterEach": false,
"angular": false,
"before": false,
"beforeEach": false,
"browser": false,
"describe": false,
"expect": false,
"inject": false,
"it": false,
"spyOn": false
}
}
+34
View File
@@ -0,0 +1,34 @@
'use strict';
describe('bool', function () {
var boolFilter;
beforeEach(module('frapontillo.ex.filters'));
beforeEach(inject(function ($filter) {
boolFilter = $filter('bool');
}));
it('should match the true value', function () {
expect(boolFilter(true, 1, 0)).toEqual(1);
});
it('should match the false value', function () {
expect(boolFilter(false, 1, 0)).toEqual(0);
});
it('should match a string to the false value', function () {
expect(boolFilter('true', 1, 0)).toEqual(0);
});
it('should match the empty string to the false value', function () {
expect(boolFilter('', 1, 0)).toEqual(0);
});
it('should match undefined to the false value', function () {
expect(boolFilter(undefined, 1, 0)).toEqual(0);
});
it('should match null to the false value', function () {
expect(boolFilter(null, 1, 0)).toEqual(0);
});
});
@@ -0,0 +1,47 @@
'use strict';
describe('default', function () {
var defaultFilter;
var numberFilter;
beforeEach(module('frapontillo.ex.filters'));
beforeEach(inject(function ($filter) {
defaultFilter = $filter('default');
numberFilter = $filter('number');
}));
it('should return the number 1337', function () {
var inputVal = 1337;
expect(defaultFilter(inputVal)).toEqual(1337);
});
it('should return a "default" string', function () {
var inputVal;
var defaultVal = 'default';
expect(defaultFilter(inputVal, defaultVal)).toEqual('default');
});
it('should return a "default" string', function () {
var inputVal = null;
var defaultVal = 'default';
expect(defaultFilter(inputVal, defaultVal)).toEqual('default');
});
it('should return the number 0', function () {
var inputVal = 0;
var defaultVal = 'default';
expect(defaultFilter(inputVal, defaultVal)).toEqual(0);
});
it('should return the string "13.37"', function () {
var inputVal = '13.3678787';
var defaultVal = 'N.A.';
expect(defaultFilter(numberFilter(inputVal, 2), defaultVal)).toEqual('13.37');
});
it('should return a "N.A." string', function () {
var inputVal;
var defaultVal = 'N.A.';
expect(defaultFilter(numberFilter(inputVal, 2), defaultVal)).toEqual(defaultVal);
});
});
@@ -0,0 +1,28 @@
'use strict';
describe('firstNotNull', function () {
var firstNotNullFilter;
beforeEach(module('frapontillo.ex.filters'));
beforeEach(inject(function ($filter) {
firstNotNullFilter = $filter('firstNotNull');
}));
it('should return the number 1337', function () {
expect(firstNotNullFilter([
null, undefined, 1337, 0
])).toEqual(1337);
});
it('should return the number 0', function () {
expect(firstNotNullFilter([
null, 0, undefined, 3
])).toEqual(0);
});
it('should return undefined', function () {
expect(firstNotNullFilter([
null, undefined
])).toEqual(undefined);
});
});
+30
View File
@@ -0,0 +1,30 @@
'use strict';
describe('join', function () {
var joinFilter;
beforeEach(module('frapontillo.ex.filters'));
beforeEach(inject(function ($filter) {
joinFilter = $filter('join');
}));
it('should return \'this is a simple test\'', function () {
expect(joinFilter(['this', 'is', 'a', 'simple', 'test'], ' ')).toEqual('this is a simple test');
});
it('should return the empty string for an undefined array', function () {
expect(joinFilter(undefined, '')).toEqual('');
});
it('should return the empty string for an empty array', function () {
expect(joinFilter([], '')).toEqual('');
});
it('should return \'0123456789\'', function () {
expect(joinFilter([0,1,2,3,4,5,6,7,8,9], '')).toEqual('0123456789');
});
it('should default to the comma separator and return \'0,1,2,3,4,5,6,7,8,9\'', function () {
expect(joinFilter([0,1,2,3,4,5,6,7,8,9])).toEqual('0,1,2,3,4,5,6,7,8,9');
});
});
@@ -0,0 +1,28 @@
'use strict';
describe('lastNotNull', function () {
var lastNotNullFilter;
beforeEach(module('frapontillo.ex.filters'));
beforeEach(inject(function ($filter) {
lastNotNullFilter = $filter('lastNotNull');
}));
it('should return the number 0', function () {
expect(lastNotNullFilter([
null, undefined, 1337, 0
])).toEqual(0);
});
it('should return the number 1337', function () {
expect(lastNotNullFilter([
null, 0, 1337, undefined
])).toEqual(1337);
});
it('should return undefined', function () {
expect(lastNotNullFilter([
null, undefined
])).toEqual(undefined);
});
});
+28
View File
@@ -0,0 +1,28 @@
'use strict';
describe('max', function () {
var maxFilter;
beforeEach(module('frapontillo.ex.filters'));
beforeEach(inject(function ($filter) {
maxFilter = $filter('max');
}));
it('should return the number 1337', function () {
expect(maxFilter([
null, undefined, 1337, 0
])).toEqual(1337);
});
it('should return the number 1337', function () {
expect(maxFilter([
null, 0, 1337, undefined
])).toEqual(1337);
});
it('should return undefined', function () {
expect(maxFilter([
null, undefined
])).toEqual(undefined);
});
});
+28
View File
@@ -0,0 +1,28 @@
'use strict';
describe('min', function () {
var minFilter;
beforeEach(module('frapontillo.ex.filters'));
beforeEach(inject(function ($filter) {
minFilter = $filter('min');
}));
it('should return the number 0', function () {
expect(minFilter([
null, undefined, 1337, 0
])).toEqual(0);
});
it('should return the number 1', function () {
expect(minFilter([
null, 1, 1337, undefined
])).toEqual(1);
});
it('should return undefined', function () {
expect(minFilter([
null, undefined
])).toEqual(undefined);
});
});
@@ -0,0 +1,42 @@
'use strict';
describe('property', function () {
var propertyFilter;
var testArray = [
{id:0, text:'zero'},
{id:1, text:'one'},
{id:2, text:'two'},
{id:3, text:'three'},
{id:4, text:'four'},
{id:5, text:'five'},
{id:6, text:'six'}
];
var makeArray = function() {
return angular.copy(testArray);
};
beforeEach(module('frapontillo.ex.filters'));
beforeEach(inject(function ($filter) {
propertyFilter = $filter('property');
}));
it('should return the \'id\' properties', function () {
var filteredArray = propertyFilter(makeArray(), 'id');
expect(filteredArray[0]).toEqual(0);
expect(filteredArray.length).toEqual(7);
});
it('should return elements with only the \'text\' property', function () {
var filteredArray = propertyFilter(makeArray(), 'text');
expect(filteredArray[0]).toEqual('zero');
expect(filteredArray.length).toEqual(7);
});
it('should return empty elements', function () {
var filteredArray = propertyFilter(makeArray(), 'something else');
expect(filteredArray[0]).toEqual(undefined);
expect(filteredArray.length).toEqual(7);
});
});
+45
View File
@@ -0,0 +1,45 @@
{
"name": "angular-md5",
"version": "0.1.7",
"main": "angular-md5.js",
"description": "A md5 crypto component for Angular.js",
"author": [
{
"name": "Patrick Stapleton",
"email": "github@gdi2290.com",
"url": "www.gdi2290.com"
}
],
"keywords": [
"PatrickJS",
"gdi2290",
"angular.js",
"angularjs",
"angular",
"crypto",
"md5"
],
"ignore": [
"**/.*",
"*.yml",
"*.xml",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"angular": "*"
},
"homepage": "https://github.com/gdi2290/angular-md5",
"_release": "0.1.7",
"_resolution": {
"type": "version",
"tag": "v0.1.7",
"commit": "9ab48b3a7911ba19c86670040ae7ded6fd2b14f7"
},
"_source": "git://github.com/gdi2290/angular-md5.git",
"_target": "~0.1.7",
"_originalSource": "angular-md5",
"_direct": true
}
+129
View File
@@ -0,0 +1,129 @@
'use strict';
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt);
require('time-grunt')(grunt);
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
bwr: grunt.file.readJSON('bower.json'),
nodeunit: {
files: ['test/**/*_test.js']
},
jshint: {
options: {
jshintrc: '.jshintrc'
},
gruntfile: {
src: 'Gruntfile.js'
},
lib: {
src: ['<%= bwr.name %>']
},
test: {
src: ['test/**/*.js']
}
},
clean: ['.tmp/'],
concat: {
dist:{}
},
ngmin: {
dist: {
files: {
'.tmp/<%= bwr.name %>.js': ['./lib/index.js', './lib/*/*.js']
}
}
},
uglify: {
options: {
report: 'min',
enclose: {
'this': 'window',
'this.angular': 'angular',
'void 0': 'undefined'
},
banner: '/*\n <%= bwr.name %> - v<%= bwr.version %> \n ' +
'<%= grunt.template.today("yyyy-mm-dd") %>\n*/\n'+
'',
},
dist: {
options: {
beautify: false,
mangle: true,
compress: {
global_defs: {
'DEBUG': false
},
dead_code: true
},
sourceMap: '<%= bwr.name %>.min.js.map'
},
files: {
'<%= bwr.name %>.min.js': ['./lib/index.js', './lib/*/*.js']
}
},
src: {
options: {
beautify: true,
mangle: false,
compress: false
},
files: {
'<%= bwr.name %>.js': ['./lib/index.js', './lib/*/*.js']
}
},
buildDist: {
options: {
beautify: false,
mangle: true,
compress: {
global_defs: {
'DEBUG': false
},
dead_code: true
},
sourceMap: '<%= bwr.name %>.min.js.map'
},
files: {
'<%= bwr.name %>.min.js': '.tmp/<%= bwr.name %>.js'
}
},
buildSrc: {
options: {
beautify: {
indent_level: 2,
beautify: true
},
mangle: false,
compress: false
},
files: {
'<%= bwr.name %>.js': '.tmp/<%= bwr.name %>.js'
}
}
}
});
// Testing task
grunt.registerTask('test', [
]);
// Build task
grunt.registerTask('build', [
'clean',
'concat',
'ngmin:dist',
'uglify:buildSrc',
'uglify:buildDist'
]);
// Default task
grunt.registerTask('default', [
'build'
]);
};
+36
View File
@@ -0,0 +1,36 @@
# angular-md5 [![Build Status](https://travis-ci.org/gdi2290/angular-md5.png?branch=master)](https://travis-ci.org/gdi2290/angular-md5)
md5 for Angular.js and Gravatar filter
#How do I add this to my project?
You can download angular-md5 by:
* (prefered) Using bower and running `bower install angular-md5 --save`
* Using npm and running `npm install angular-md5 --save`
* Downloading it manually by clicking [here to download development unminified version](https://raw.github.com/gdi2290/angular-md5/master/angular-md5.js)
````html
<body ng-app="YOUR_APP" ng-controller="MainCtrl">
<img src="http://www.gravatar.com/avatar/{{ email | gravatar }}">
<input type="email" ng-model="email" placeholder="Email Address">
{{ message }}
</body>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.min.js"></script>
<script src="app/bower_components/angular-md5/angular-md5.js"></script>
<script>
angular.module('YOUR_APP', [
'angular-md5', // you may also use 'ngMd5' or 'gdi2290.md5'
'controllers'
]);
angular.module('controllers', [])
.controller('MainCtrl', ['$scope', 'md5', function($scope, md5) {
$scope.$watch('email' ,function() {
$scope.message = 'Your email Hash is: ' + md5.createHash($scope.email || '');
});
}]);
</script>
````
+200
View File
@@ -0,0 +1,200 @@
/*
angular-md5 - v0.1.7
2014-01-20
*/
(function(window, angular, undefined) {
angular.module("angular-md5", [ "gdi2290.md5" ]);
angular.module("ngMd5", [ "gdi2290.md5" ]);
angular.module("gdi2290.md5", [ "gdi2290.gravatar-filter", "gdi2290.md5-service", "gdi2290.md5-filter" ]);
"use strict";
angular.module("gdi2290.gravatar-filter", []).filter("gravatar", [ "md5", function(md5) {
var cache = {};
return function(text, defaultText) {
if (!cache[text]) {
defaultText = defaultText ? md5.createHash(defaultText.toString().toLowerCase()) : "";
cache[text] = text ? md5.createHash(text.toString().toLowerCase()) : defaultText;
}
return cache[text];
};
} ]);
"use strict";
angular.module("gdi2290.md5-filter", []).filter("md5", [ "md5", function(md5) {
return function(text) {
return text ? md5.createHash(text.toString().toLowerCase()) : text;
};
} ]);
"use strict";
angular.module("gdi2290.md5-service", []).factory("md5", [ function() {
var md5 = {
createHash: function(str) {
var xl;
var rotateLeft = function(lValue, iShiftBits) {
return lValue << iShiftBits | lValue >>> 32 - iShiftBits;
};
var addUnsigned = function(lX, lY) {
var lX4, lY4, lX8, lY8, lResult;
lX8 = lX & 2147483648;
lY8 = lY & 2147483648;
lX4 = lX & 1073741824;
lY4 = lY & 1073741824;
lResult = (lX & 1073741823) + (lY & 1073741823);
if (lX4 & lY4) {
return lResult ^ 2147483648 ^ lX8 ^ lY8;
}
if (lX4 | lY4) {
if (lResult & 1073741824) {
return lResult ^ 3221225472 ^ lX8 ^ lY8;
} else {
return lResult ^ 1073741824 ^ lX8 ^ lY8;
}
} else {
return lResult ^ lX8 ^ lY8;
}
};
var _F = function(x, y, z) {
return x & y | ~x & z;
};
var _G = function(x, y, z) {
return x & z | y & ~z;
};
var _H = function(x, y, z) {
return x ^ y ^ z;
};
var _I = function(x, y, z) {
return y ^ (x | ~z);
};
var _FF = function(a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _GG = function(a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _HH = function(a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _II = function(a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var convertToWordArray = function(str) {
var lWordCount;
var lMessageLength = str.length;
var lNumberOfWords_temp1 = lMessageLength + 8;
var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - lNumberOfWords_temp1 % 64) / 64;
var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
var lWordArray = new Array(lNumberOfWords - 1);
var lBytePosition = 0;
var lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - lByteCount % 4) / 4;
lBytePosition = lByteCount % 4 * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | str.charCodeAt(lByteCount) << lBytePosition;
lByteCount++;
}
lWordCount = (lByteCount - lByteCount % 4) / 4;
lBytePosition = lByteCount % 4 * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | 128 << lBytePosition;
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
};
var wordToHex = function(lValue) {
var wordToHexValue = "", wordToHexValue_temp = "", lByte, lCount;
for (lCount = 0; lCount <= 3; lCount++) {
lByte = lValue >>> lCount * 8 & 255;
wordToHexValue_temp = "0" + lByte.toString(16);
wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2);
}
return wordToHexValue;
};
var x = [], k, AA, BB, CC, DD, a, b, c, d, S11 = 7, S12 = 12, S13 = 17, S14 = 22, S21 = 5, S22 = 9, S23 = 14, S24 = 20, S31 = 4, S32 = 11, S33 = 16, S34 = 23, S41 = 6, S42 = 10, S43 = 15, S44 = 21;
x = convertToWordArray(str);
a = 1732584193;
b = 4023233417;
c = 2562383102;
d = 271733878;
xl = x.length;
for (k = 0; k < xl; k += 16) {
AA = a;
BB = b;
CC = c;
DD = d;
a = _FF(a, b, c, d, x[k + 0], S11, 3614090360);
d = _FF(d, a, b, c, x[k + 1], S12, 3905402710);
c = _FF(c, d, a, b, x[k + 2], S13, 606105819);
b = _FF(b, c, d, a, x[k + 3], S14, 3250441966);
a = _FF(a, b, c, d, x[k + 4], S11, 4118548399);
d = _FF(d, a, b, c, x[k + 5], S12, 1200080426);
c = _FF(c, d, a, b, x[k + 6], S13, 2821735955);
b = _FF(b, c, d, a, x[k + 7], S14, 4249261313);
a = _FF(a, b, c, d, x[k + 8], S11, 1770035416);
d = _FF(d, a, b, c, x[k + 9], S12, 2336552879);
c = _FF(c, d, a, b, x[k + 10], S13, 4294925233);
b = _FF(b, c, d, a, x[k + 11], S14, 2304563134);
a = _FF(a, b, c, d, x[k + 12], S11, 1804603682);
d = _FF(d, a, b, c, x[k + 13], S12, 4254626195);
c = _FF(c, d, a, b, x[k + 14], S13, 2792965006);
b = _FF(b, c, d, a, x[k + 15], S14, 1236535329);
a = _GG(a, b, c, d, x[k + 1], S21, 4129170786);
d = _GG(d, a, b, c, x[k + 6], S22, 3225465664);
c = _GG(c, d, a, b, x[k + 11], S23, 643717713);
b = _GG(b, c, d, a, x[k + 0], S24, 3921069994);
a = _GG(a, b, c, d, x[k + 5], S21, 3593408605);
d = _GG(d, a, b, c, x[k + 10], S22, 38016083);
c = _GG(c, d, a, b, x[k + 15], S23, 3634488961);
b = _GG(b, c, d, a, x[k + 4], S24, 3889429448);
a = _GG(a, b, c, d, x[k + 9], S21, 568446438);
d = _GG(d, a, b, c, x[k + 14], S22, 3275163606);
c = _GG(c, d, a, b, x[k + 3], S23, 4107603335);
b = _GG(b, c, d, a, x[k + 8], S24, 1163531501);
a = _GG(a, b, c, d, x[k + 13], S21, 2850285829);
d = _GG(d, a, b, c, x[k + 2], S22, 4243563512);
c = _GG(c, d, a, b, x[k + 7], S23, 1735328473);
b = _GG(b, c, d, a, x[k + 12], S24, 2368359562);
a = _HH(a, b, c, d, x[k + 5], S31, 4294588738);
d = _HH(d, a, b, c, x[k + 8], S32, 2272392833);
c = _HH(c, d, a, b, x[k + 11], S33, 1839030562);
b = _HH(b, c, d, a, x[k + 14], S34, 4259657740);
a = _HH(a, b, c, d, x[k + 1], S31, 2763975236);
d = _HH(d, a, b, c, x[k + 4], S32, 1272893353);
c = _HH(c, d, a, b, x[k + 7], S33, 4139469664);
b = _HH(b, c, d, a, x[k + 10], S34, 3200236656);
a = _HH(a, b, c, d, x[k + 13], S31, 681279174);
d = _HH(d, a, b, c, x[k + 0], S32, 3936430074);
c = _HH(c, d, a, b, x[k + 3], S33, 3572445317);
b = _HH(b, c, d, a, x[k + 6], S34, 76029189);
a = _HH(a, b, c, d, x[k + 9], S31, 3654602809);
d = _HH(d, a, b, c, x[k + 12], S32, 3873151461);
c = _HH(c, d, a, b, x[k + 15], S33, 530742520);
b = _HH(b, c, d, a, x[k + 2], S34, 3299628645);
a = _II(a, b, c, d, x[k + 0], S41, 4096336452);
d = _II(d, a, b, c, x[k + 7], S42, 1126891415);
c = _II(c, d, a, b, x[k + 14], S43, 2878612391);
b = _II(b, c, d, a, x[k + 5], S44, 4237533241);
a = _II(a, b, c, d, x[k + 12], S41, 1700485571);
d = _II(d, a, b, c, x[k + 3], S42, 2399980690);
c = _II(c, d, a, b, x[k + 10], S43, 4293915773);
b = _II(b, c, d, a, x[k + 1], S44, 2240044497);
a = _II(a, b, c, d, x[k + 8], S41, 1873313359);
d = _II(d, a, b, c, x[k + 15], S42, 4264355552);
c = _II(c, d, a, b, x[k + 6], S43, 2734768916);
b = _II(b, c, d, a, x[k + 13], S44, 1309151649);
a = _II(a, b, c, d, x[k + 4], S41, 4149444226);
d = _II(d, a, b, c, x[k + 11], S42, 3174756917);
c = _II(c, d, a, b, x[k + 2], S43, 718787259);
b = _II(b, c, d, a, x[k + 9], S44, 3951481745);
a = addUnsigned(a, AA);
b = addUnsigned(b, BB);
c = addUnsigned(c, CC);
d = addUnsigned(d, DD);
}
var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
return temp.toLowerCase();
}
};
return md5;
} ]);
})(window, window.angular, void 0);
+7
View File
@@ -0,0 +1,7 @@
/*
angular-md5 - v0.1.7
2014-01-20
*/
!function(a,b){b.module("angular-md5",["gdi2290.md5"]),b.module("ngMd5",["gdi2290.md5"]),b.module("gdi2290.md5",["gdi2290.gravatar-filter","gdi2290.md5-service","gdi2290.md5-filter"]),b.module("gdi2290.gravatar-filter",[]).filter("gravatar",["md5",function(a){var b={};return function(c,d){return b[c]||(d=d?a.createHash(d.toString().toLowerCase()):"",b[c]=c?a.createHash(c.toString().toLowerCase()):d),b[c]}}]),b.module("gdi2290.md5-filter",[]).filter("md5",["md5",function(a){return function(b){return b?a.createHash(b.toString().toLowerCase()):b}}]),b.module("gdi2290.md5-service",[]).factory("md5",[function(){var a={createHash:function(a){var b,c,d,e,f,g,h,i,j,k,l=function(a,b){return a<<b|a>>>32-b},m=function(a,b){var c,d,e,f,g;return e=2147483648&a,f=2147483648&b,c=1073741824&a,d=1073741824&b,g=(1073741823&a)+(1073741823&b),c&d?2147483648^g^e^f:c|d?1073741824&g?3221225472^g^e^f:1073741824^g^e^f:g^e^f},n=function(a,b,c){return a&b|~a&c},o=function(a,b,c){return a&c|b&~c},p=function(a,b,c){return a^b^c},q=function(a,b,c){return b^(a|~c)},r=function(a,b,c,d,e,f,g){return a=m(a,m(m(n(b,c,d),e),g)),m(l(a,f),b)},s=function(a,b,c,d,e,f,g){return a=m(a,m(m(o(b,c,d),e),g)),m(l(a,f),b)},t=function(a,b,c,d,e,f,g){return a=m(a,m(m(p(b,c,d),e),g)),m(l(a,f),b)},u=function(a,b,c,d,e,f,g){return a=m(a,m(m(q(b,c,d),e),g)),m(l(a,f),b)},v=function(a){for(var b,c=a.length,d=c+8,e=(d-d%64)/64,f=16*(e+1),g=new Array(f-1),h=0,i=0;c>i;)b=(i-i%4)/4,h=i%4*8,g[b]=g[b]|a.charCodeAt(i)<<h,i++;return b=(i-i%4)/4,h=i%4*8,g[b]=g[b]|128<<h,g[f-2]=c<<3,g[f-1]=c>>>29,g},w=function(a){var b,c,d="",e="";for(c=0;3>=c;c++)b=a>>>8*c&255,e="0"+b.toString(16),d+=e.substr(e.length-2,2);return d},x=[],y=7,z=12,A=17,B=22,C=5,D=9,E=14,F=20,G=4,H=11,I=16,J=23,K=6,L=10,M=15,N=21;for(x=v(a),h=1732584193,i=4023233417,j=2562383102,k=271733878,b=x.length,c=0;b>c;c+=16)d=h,e=i,f=j,g=k,h=r(h,i,j,k,x[c+0],y,3614090360),k=r(k,h,i,j,x[c+1],z,3905402710),j=r(j,k,h,i,x[c+2],A,606105819),i=r(i,j,k,h,x[c+3],B,3250441966),h=r(h,i,j,k,x[c+4],y,4118548399),k=r(k,h,i,j,x[c+5],z,1200080426),j=r(j,k,h,i,x[c+6],A,2821735955),i=r(i,j,k,h,x[c+7],B,4249261313),h=r(h,i,j,k,x[c+8],y,1770035416),k=r(k,h,i,j,x[c+9],z,2336552879),j=r(j,k,h,i,x[c+10],A,4294925233),i=r(i,j,k,h,x[c+11],B,2304563134),h=r(h,i,j,k,x[c+12],y,1804603682),k=r(k,h,i,j,x[c+13],z,4254626195),j=r(j,k,h,i,x[c+14],A,2792965006),i=r(i,j,k,h,x[c+15],B,1236535329),h=s(h,i,j,k,x[c+1],C,4129170786),k=s(k,h,i,j,x[c+6],D,3225465664),j=s(j,k,h,i,x[c+11],E,643717713),i=s(i,j,k,h,x[c+0],F,3921069994),h=s(h,i,j,k,x[c+5],C,3593408605),k=s(k,h,i,j,x[c+10],D,38016083),j=s(j,k,h,i,x[c+15],E,3634488961),i=s(i,j,k,h,x[c+4],F,3889429448),h=s(h,i,j,k,x[c+9],C,568446438),k=s(k,h,i,j,x[c+14],D,3275163606),j=s(j,k,h,i,x[c+3],E,4107603335),i=s(i,j,k,h,x[c+8],F,1163531501),h=s(h,i,j,k,x[c+13],C,2850285829),k=s(k,h,i,j,x[c+2],D,4243563512),j=s(j,k,h,i,x[c+7],E,1735328473),i=s(i,j,k,h,x[c+12],F,2368359562),h=t(h,i,j,k,x[c+5],G,4294588738),k=t(k,h,i,j,x[c+8],H,2272392833),j=t(j,k,h,i,x[c+11],I,1839030562),i=t(i,j,k,h,x[c+14],J,4259657740),h=t(h,i,j,k,x[c+1],G,2763975236),k=t(k,h,i,j,x[c+4],H,1272893353),j=t(j,k,h,i,x[c+7],I,4139469664),i=t(i,j,k,h,x[c+10],J,3200236656),h=t(h,i,j,k,x[c+13],G,681279174),k=t(k,h,i,j,x[c+0],H,3936430074),j=t(j,k,h,i,x[c+3],I,3572445317),i=t(i,j,k,h,x[c+6],J,76029189),h=t(h,i,j,k,x[c+9],G,3654602809),k=t(k,h,i,j,x[c+12],H,3873151461),j=t(j,k,h,i,x[c+15],I,530742520),i=t(i,j,k,h,x[c+2],J,3299628645),h=u(h,i,j,k,x[c+0],K,4096336452),k=u(k,h,i,j,x[c+7],L,1126891415),j=u(j,k,h,i,x[c+14],M,2878612391),i=u(i,j,k,h,x[c+5],N,4237533241),h=u(h,i,j,k,x[c+12],K,1700485571),k=u(k,h,i,j,x[c+3],L,2399980690),j=u(j,k,h,i,x[c+10],M,4293915773),i=u(i,j,k,h,x[c+1],N,2240044497),h=u(h,i,j,k,x[c+8],K,1873313359),k=u(k,h,i,j,x[c+15],L,4264355552),j=u(j,k,h,i,x[c+6],M,2734768916),i=u(i,j,k,h,x[c+13],N,1309151649),h=u(h,i,j,k,x[c+4],K,4149444226),k=u(k,h,i,j,x[c+11],L,3174756917),j=u(j,k,h,i,x[c+2],M,718787259),i=u(i,j,k,h,x[c+9],N,3951481745),h=m(h,d),i=m(i,e),j=m(j,f),k=m(k,g);var O=w(h)+w(i)+w(j)+w(k);return O.toLowerCase()}};return a}])}(this,this.angular,void 0);
//# sourceMappingURL=angular-md5.min.js.map
File diff suppressed because one or more lines are too long
+34
View File
@@ -0,0 +1,34 @@
{
"name": "angular-md5",
"version": "0.1.7",
"main": "angular-md5.js",
"description": "A md5 crypto component for Angular.js",
"author": [
{
"name": "Patrick Stapleton",
"email": "github@gdi2290.com",
"url": "www.gdi2290.com"
}
],
"keywords": [
"PatrickJS",
"gdi2290",
"angular.js",
"angularjs",
"angular",
"crypto",
"md5"
],
"ignore": [
"**/.*",
"*.yml",
"*.xml",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"angular": "*"
}
}
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<title>Angular md5</title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<script src="../angular-md5.js"></script>
</head>
<body ng-app="YOUR_APP" ng-controller="MainCtrl" ng-cloak>
<img ng-src="http://www.gravatar.com/avatar/{{ email | gravatar }}">
<input type="email" ng-model="email" placeholder="Email Address" autofocus>
Your email Hash is: {{ message }}
<!--
<script src="app/bower_components/angular-md5/angular-md5.js"></script>
-->
<script>
angular.module('YOUR_APP', [
'angular-md5', // you may also use 'ngMd5' or 'gdi2290.md5'
'controllers'
]);
angular.module('controllers', [])
.controller('MainCtrl', ['$scope', 'md5', function($scope, md5) {
$scope.$watch('email' ,function() {
$scope.message = md5.createHash($scope.email || '');
});
}]);
</script>
</body>
</html>
+13
View File
@@ -0,0 +1,13 @@
'use strict';
angular.module('gdi2290.gravatar-filter', [])
.filter('gravatar', function(md5) {
var cache = {};
return function(text, defaultText) {
if (!cache[text]) {
defaultText = (defaultText) ? md5.createHash(defaultText.toString().toLowerCase()) : '';
cache[text] = (text) ? md5.createHash(text.toString().toLowerCase()) : defaultText;
}
return cache[text];
};
});
+8
View File
@@ -0,0 +1,8 @@
'use strict';
angular.module('gdi2290.md5-filter', [])
.filter('md5', function(md5) {
return function(text) {
return (text) ? md5.createHash(text.toString().toLowerCase()) : text;
};
});
+8
View File
@@ -0,0 +1,8 @@
angular.module('angular-md5', ['gdi2290.md5']);
angular.module('ngMd5', ['gdi2290.md5']);
angular.module('gdi2290.md5', [
'gdi2290.gravatar-filter',
'gdi2290.md5-service',
'gdi2290.md5-filter'
]);
+215
View File
@@ -0,0 +1,215 @@
'use strict';
angular.module('gdi2290.md5-service', [])
.factory('md5', [function() {
var md5 = {
createHash: function(str) {
var xl;
var rotateLeft = function (lValue, iShiftBits) {
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
};
var addUnsigned = function (lX, lY) {
var lX4, lY4, lX8, lY8, lResult;
lX8 = (lX & 0x80000000);
lY8 = (lY & 0x80000000);
lX4 = (lX & 0x40000000);
lY4 = (lY & 0x40000000);
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
if (lX4 & lY4) {
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
}
if (lX4 | lY4) {
if (lResult & 0x40000000) {
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
} else {
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
}
} else {
return (lResult ^ lX8 ^ lY8);
}
};
var _F = function (x, y, z) {
return (x & y) | ((~x) & z);
};
var _G = function (x, y, z) {
return (x & z) | (y & (~z));
};
var _H = function (x, y, z) {
return (x ^ y ^ z);
};
var _I = function (x, y, z) {
return (y ^ (x | (~z)));
};
var _FF = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _GG = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _HH = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _II = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var convertToWordArray = function (str) {
var lWordCount;
var lMessageLength = str.length;
var lNumberOfWords_temp1 = lMessageLength + 8;
var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
var lWordArray = new Array(lNumberOfWords - 1);
var lBytePosition = 0;
var lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount) << lBytePosition));
lByteCount++;
}
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
};
var wordToHex = function (lValue) {
var wordToHexValue = '',
wordToHexValue_temp = '',
lByte, lCount;
for (lCount = 0; lCount <= 3; lCount++) {
lByte = (lValue >>> (lCount * 8)) & 255;
wordToHexValue_temp = '0' + lByte.toString(16);
wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2);
}
return wordToHexValue;
};
var x = [],
k, AA, BB, CC, DD, a, b, c, d, S11 = 7,
S12 = 12,
S13 = 17,
S14 = 22,
S21 = 5,
S22 = 9,
S23 = 14,
S24 = 20,
S31 = 4,
S32 = 11,
S33 = 16,
S34 = 23,
S41 = 6,
S42 = 10,
S43 = 15,
S44 = 21;
//str = this.utf8_encode(str);
x = convertToWordArray(str);
a = 0x67452301;
b = 0xEFCDAB89;
c = 0x98BADCFE;
d = 0x10325476;
xl = x.length;
for (k = 0; k < xl; k += 16) {
AA = a;
BB = b;
CC = c;
DD = d;
a = _FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
d = _FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
c = _FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
b = _FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
a = _FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
d = _FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
c = _FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
b = _FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
a = _FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
d = _FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
c = _FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
b = _FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
a = _FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
d = _FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
c = _FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
b = _FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
a = _GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
d = _GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
c = _GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
b = _GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
a = _GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
d = _GG(d, a, b, c, x[k + 10], S22, 0x2441453);
c = _GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
b = _GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
a = _GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
d = _GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
c = _GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
b = _GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
a = _GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
d = _GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
c = _GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
b = _GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
a = _HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
d = _HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
c = _HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
b = _HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
a = _HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
d = _HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
c = _HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
b = _HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
a = _HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
d = _HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
c = _HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
b = _HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
a = _HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
d = _HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
c = _HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
b = _HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
a = _II(a, b, c, d, x[k + 0], S41, 0xF4292244);
d = _II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
c = _II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
b = _II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
a = _II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
d = _II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
c = _II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
b = _II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
a = _II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
d = _II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
c = _II(c, d, a, b, x[k + 6], S43, 0xA3014314);
b = _II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
a = _II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
d = _II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
c = _II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
b = _II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
a = addUnsigned(a, AA);
b = addUnsigned(b, BB);
c = addUnsigned(c, CC);
d = addUnsigned(d, DD);
}
var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
return temp.toLowerCase();
}
};
return md5;
}]);
@@ -0,0 +1,45 @@
{
"name": "angular-md5",
"version": "0.1.7",
"main": "angular-md5.js",
"description": "A md5 crypto component for Angular.js",
"homepage": "https://github.com/gdi2290/angular-md5",
"bugs": "https://github.com/gdi2290/angular-md5/issues",
"author": {
"name": "Patrick Stapleton",
"email": "github@gdi2290.com",
"url": "www.gdi2290.com"
},
"repository": {
"type": "git",
"url": "git@github.com:gdi2290/angular-md5.git"
},
"keywords": [
"PatrickJS",
"gdi2290",
"angular.js",
"angularjs",
"angular",
"crypto",
"md5"
],
"licenses": [
{
"type": "MIT"
}
],
"dependencies": {},
"devDependencies": {
"load-grunt-tasks": "~0.1.0",
"time-grunt": "~0.1.0",
"grunt": "*",
"grunt-contrib-copy": "*",
"grunt-contrib-watch": "~0.5.0",
"grunt-contrib-concat": "*",
"grunt-contrib-uglify": "*",
"grunt-contrib-connect": "*",
"grunt-contrib-jshint": "~0.6.0",
"grunt-ngmin": "*",
"grunt-contrib-clean": "~0.5.0"
}
}
@@ -0,0 +1,19 @@
{
"name": "angular-mocks",
"version": "1.2.23",
"main": "./angular-mocks.js",
"dependencies": {
"angular": "1.2.23"
},
"homepage": "https://github.com/angular/bower-angular-mocks",
"_release": "1.2.23",
"_resolution": {
"type": "version",
"tag": "v1.2.23",
"commit": "f15ecc4f747ba1df3e75374a8d76494086dbcb38"
},
"_source": "git://github.com/angular/bower-angular-mocks.git",
"_target": "~1.2.23",
"_originalSource": "angular-mocks",
"_direct": true
}
+42
View File
@@ -0,0 +1,42 @@
# bower-angular-mocks
This repo is for distribution on `bower`. The source for this module is in the
[main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngMock).
Please file issues and pull requests against that repo.
## Install
Install with `bower`:
```shell
bower install angular-mocks
```
## Documentation
Documentation is available on the
[AngularJS docs site](http://docs.angularjs.org/guide/dev_guide.unit-testing).
## License
The MIT License
Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,8 @@
{
"name": "angular-mocks",
"version": "1.2.23",
"main": "./angular-mocks.js",
"dependencies": {
"angular": "1.2.23"
}
}
@@ -0,0 +1,32 @@
{
"name": "angular-moment",
"version": "0.10.1",
"description": "Moment.JS directives & filters for AngularJS (timeago alternative)",
"author": "Uri Shaked",
"license": "MIT",
"homepage": "http://github.com/urish/angular-moment",
"main": "./angular-moment.js",
"ignore": [],
"dependencies": {
"angular": ">=1.2.0 <1.5.0",
"moment": ">=2.8.0 <2.11.0"
},
"devDependencies": {
"angular-mocks": "1.3.x",
"moment-timezone": "0.3.1"
},
"repository": {
"type": "git",
"url": "git://github.com/urish/angular-moment.git"
},
"_release": "0.10.1",
"_resolution": {
"type": "version",
"tag": "0.10.1",
"commit": "8910240ee1872478a1b318d2d800c1c073526c37"
},
"_source": "git://github.com/urish/angular-moment.git",
"_target": "~0.10.1",
"_originalSource": "angular-moment",
"_direct": true
}
@@ -0,0 +1,24 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# Change these settings to your own preference
indent_style = tab
indent_size = 4
# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{package.json,bower.json}]
indent_style=space
indent_size=2
[*.md]
trim_trailing_whitespace = false
@@ -0,0 +1,4 @@
/.idea
/bower_components
/node_modules
/coverage
@@ -0,0 +1,26 @@
{
"node": true,
"browser": true,
"esnext": true,
"bitwise": true,
"camelcase": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"indent": 2,
"latedef": true,
"newcap": true,
"noarg": true,
"quotmark": "single",
"regexp": true,
"undef": true,
"unused": true,
"strict": true,
"trailing": true,
"smarttabs": true,
"maxdepth": 2,
"maxcomplexity": 10,
"globals": {
"angular": false
}
}
@@ -0,0 +1,4 @@
.idea
bower_components
node_modules
coverage
@@ -0,0 +1,7 @@
language: node_js
node_js:
- "0.10"
before_script:
- npm run bower
after_success:
- cat ./coverage/*/lcov.info | ./node_modules/coveralls/bin/coveralls.js
@@ -0,0 +1,131 @@
# Changelog
## 0.10.1 - 2015-05-01
- Fix broken SystemJS/JSPM support (see [#104](https://github.com/urish/angular-moment/issues/104))
## 0.10.0 - 2015-04-10
- Breaking change: removed one-time binding for `am-time-ago` in favor of AngularJS 1.3's one time binding ([#122](https://github.com/urish/angular-moment/issues/122))
- Remove support for AngularJS 1.0.x and 1.1.x.
- Support moment.js v2.10.x
- Support for displaying full dates in `am-time-ago` (see [#75](https://github.com/urish/angular-moment/issues/75))
- Support Angular Core's style CommonJS standard ([#123](https://github.com/urish/angular-moment/pull/123), contributed by [seanhealy](https://github.com/seanhealy))
- Added an optional timezone parameter to amDateFormat ([#90](https://github.com/urish/angular-moment/pull/90), contributed by [robertbrooker](https://github.com/robertbrooker))
## 0.9.2 - 2015-03-17
- Critical fix: npm install angular-moment fails ([#121](https://github.com/urish/angular-moment/issues/121))
## 0.9.1 - 2015-03-17
- Add support for locale strings customization ([#102](https://github.com/urish/angular-moment/pull/102), contributed by [vosi](https://github.com/vosi))
- Add `amDifference` filter ([#120](https://github.com/urish/angular-moment/pull/120), contributed by [ajhodges](https://github.com/ajhodges))
- Support for changing the timezone via `amMoment.changeTimezone()` ([#92](https://github.com/urish/angular-moment/issues/92))
- Support for AngularJS 1.4.x
- Remove explicit module name for RequireJS ([#112](https://github.com/urish/angular-moment/pull/112), contributed by [WilliamCarter](https://github.com/WilliamCarter))
## 0.9.0 - 2015-01-11
- Support moment.js v2.9.0. See [here](https://gist.github.com/ichernev/0c9a9b49951111a27ce7) for changelog.
- Removed support for older moment.js versions. Only 2.8.0 and newer versions are now supported.
- Removed deprecated method: `amMoment.changeLanguage()`. Use `amMoment.changeLocale()` instead.
- Removed deprecated event: `amMoment:languageChange`. Listen for `amMoment:localeChange` instead.
- Filters are now stateful by default (fixes [#97](https://github.com/urish/angular-moment/issues/97)).
- The project is now available on [NuGet](https://www.nuget.org/packages/angular-moment/) ([#99](https://github.com/urish/angular-moment/pull/99), contributed by [markvp](https://github.com/markvp)).
## 0.8.3 - 2014-12-08
- `amTimeAgo` filter ([#96](https://github.com/urish/angular-moment/pull/96), contributed by [maxklenk](https://github.com/maxklenk))
- Show formatted time as element title ([#78](https://github.com/urish/angular-moment/pull/78), contributed by [ctesene](https://github.com/ctesene))
- Support commonjs and browserify ([#95](https://github.com/urish/angular-moment/pull/95), contributed by [Pencroff](https://github.com/Pencroff))
- SystemJS Loader support ([#85](https://github.com/urish/angular-moment/pull/85), contributed by [capaj](https://github.com/capaj))
## 0.8.2 - 2014-09-07
- `amMoment.changeLanguage()` was deprecated in favor of `amMoment.changeLocale()` (following [a change](http://momentjs.com/docs/#/i18n/changing-locale/) introduced in moment v2.8.1)
- Bugfix: changing the locale emitted a deprecation warning (see [#76](https://github.com/urish/angular-moment/issues/76) for details).
## 0.8.1 - 2014-09-01
- Support moment.js v2.8.0. See [here](https://gist.github.com/ichernev/ac3899324a5fa6c8c9b4) for changelog.
- Support moment-timezone v0.2.1. See [here](https://github.com/moment/moment-timezone/blob/develop/changelog.md#021-2014-08-02) for changelog.
- Bugfix: `updateTime()` is called too often for future dates ([#73](https://github.com/urish/angular-moment/issues/73))
## 0.8.0 - 2014-07-26
- Generate source map for the minified version ([#50](https://github.com/urish/angular-moment/issues/50))
- Add support HTML `<time>` element - set the `datetime` attribute ([#41](https://github.com/urish/angular-moment/pull/41), contributed by [gsklee](https://github.com/gsklee))
- Add default format (angularMomentConfig.format config property) ([#52](https://github.com/urish/angular-moment/pull/52), contributed by [otang](https://github.com/otang))
- Add `serverTime` configuration option ([#53](https://github.com/urish/angular-moment/pull/53), contributed by [Facundo Pedrazzini](https://github.com/Facuu7))
- Implement one-time binding for `am-time-ago` ([#54](https://github.com/urish/angular-moment/pull/54), contributed by [Ephi Gabay](https://github.com/ephigabay))
- Support moment.js v2.7.0. See [here](https://gist.github.com/ichernev/b0a3d456d5a84c9901d7) for changelog.
- Support moment-timezone v0.1.0. See [here](https://github.com/moment/moment-timezone/blob/develop/changelog.md#010-2014-06-23) for changelog.
## 0.7.1 - 2014-05-16
- bugfix: Preprocess set in configuration not used by filters ([#49](https://github.com/urish/angular-moment/issues/49))
## 0.7.0 - 2014-04-19
- Use `moment` as an injectable constant instead of relying on `$window.moment` ([#35](https://github.com/urish/angular-moment/pull/35), contributed by [just-boris](https://github.com/just-boris))
- Require.js support ([#36](https://github.com/urish/angular-moment/issues/36))
- Add am-preprocess attribute to support unix and utc timestamps ([#38](https://github.com/urish/angular-moment/pull/38), contributed by [jspaper](https://github.com/jspaper))
- NGDoc documentation ([#40](https://github.com/urish/angular-moment/issues/40))
- Enable support for AngularJS 1.3.x in bower.json
- Support moment.js v2.6.0. See [here](https://gist.github.com/ichernev/10544682) for changelog.
## 0.6.2 - 2014-02-05
- Add `amMoment` service with a `changeLanguage()` method ([#32](https://github.com/urish/angular-moment/pull/32), contributed by [Ornthalas](https://github.com/Ornthalas))
- bower.json: Move `moment-timezone` to devDependencies (fixes [#34](https://github.com/urish/angular-moment/issues/34))
## 0.6.1 - 2014-01-31
- Add optional timezone support to `amCalendar` and `amDateFormat` filters ([#27](https://github.com/urish/angular-moment/pull/27), contributed by [kayhadrin](https://github.com/kayhadrin))
- Happy Year of the Horse!
## 0.6.0 - 2013-12-24
- Add optional `am-without-suffix` attribute to `am-time-ago` ([#22](https://github.com/urish/angular-moment/issues/22), contributed by [hramaker](https://github.com/hramaker))
- Support moment.js v2.5.0. See [here](https://gist.github.com/ichernev/8104451) for changelog.
- Merry Christmas!
## 0.5.2 - 2013-11-17
- Add `amCalendar` filter ([#24](https://github.com/urish/angular-moment/issues/24), contributed by [OndraM](https://github.com/OndraM))
## 0.5.1 - 2013-11-09
- Add `amDuration` filter ([#20](https://github.com/urish/angular-moment/issues/20), contributed by [gabrielstuff](https://github.com/gabrielstuff))
## 0.5.0 - 2013-11-02
- Use $window.setTimeout instead of $timeout, fixes protractor synchronization issue ([#19](https://github.com/urish/angular-moment/issues/19))
## 0.4.2 - 2013-10-30
- Add settings constant for configuring moment.js withoutSuffix-option ([#18](https://github.com/urish/angular-moment/pull/18))
## 0.4.1 - 2013-10-27
- Support moment.js v2.4.0. See [here](https://github.com/moment/moment/#240) for changelog.
## 0.4.0 - 2013-10-08
- Support moment.js v2.3.0. See [here](https://gist.github.com/ichernev/6864354) for possibly breaking changes.
## 0.3.0 - 2013-10-07
- Bugfix: `am-time-ago` support for empty string ([#15](https://github.com/urish/angular-moment/issues/15))
- Behavior change: `am-time-ago` will only change the text once there is date
## 0.2.2 - 2013-09-29
- Add support for passing unix timestamp as a string to `amDateFormat` filter ([#14](https://github.com/urish/angular-moment/issues/14))
## 0.2.1 - 2013-09-13
- Fix an issue with tests failing on a different timezone
- Support moment 2.2.x, AngularJS 1.2
## 0.2.0 - 2013-08-22
- Add optional `am-format` attribute to `am-time-ago` ([#11](https://github.com/urish/angular-moment/issues/11))
- Add new `amDateFormat` filter ([#12](https://github.com/urish/angular-moment/issues/12))
- Add changelog file
## 0.1.1 - 2013-06-08
- Fix to support iOS ([#2](https://github.com/urish/angular-moment/pull/2), contributed by [giuseppeaiello](https://github.com/giuseppeaiello))
## 0.1.0 - 2013-05-27
- Initial release
@@ -0,0 +1,68 @@
# Contributing Guide
Contributing to `angular-moment` is fairly easy. This document shows you how to
get the project, run all provided tests and generate a production ready build.
It also covers provided grunt tasks, that help you developing on `angular-moment`.
## Dependencies
To make sure, that the following instructions work, please install the following dependencies
on you machine:
- Node.js
- npm
- Git
## Installation
To get the source of `angular-moment` clone the git repository via:
`git clone https://github.com/urish/angular-moment`
This will clone the complete source to your local machine. Navigate to the project folder
and install all needed dependencies via **npm**:
`npm install`
To complete the installation, install the frontend (bower) dependencies by running the
following command:
`npm run bower`
Well done! angular-moment is now installed and ready to be built.
## Building
`angular-moment` comes with a few **grunt tasks** which help you to automate
the development process. The following grunt tasks are provided:
#### grunt test
`npm test` executes (as you might thought) the unit tests, which are located
in `tests.js`. The task uses the **karma** test runner to executes the tests with
the **jasmine testing framework**. This task also checks the coding using **jshint**.
#### grunt build
`npm run build` updates the minified version of the code (angular-moment.min.js). It also
checks the code using **jshint**.
## Contributing/Submitting changes
- Checkout a new branch based on `master` and name it to what you intend to do:
- Example:
````
$ git checkout -b BRANCH_NAME
````
- Use one branch per fix/feature
- Make your changes
- Make sure to provide a spec for unit tests (in `tests.js`)
- Run your tests with `npm test`
- When all tests pass, everything's fine
- Commit your changes
- Please provide a git message which explains what you've done
- Commit to the forked repository
- Make a pull request
If you follow these instructions, your PR will land pretty safety in the main repo!
+62
View File
@@ -0,0 +1,62 @@
/* License: MIT.
* Copyright (C) 2013, 2014, 2015, Uri Shaked.
*/
'use strict';
module.exports = function (grunt) {
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
grunt.initConfig({
karma: {
unit: {
configFile: 'karma.conf.js',
singleRun: true
}
},
jshint: {
options: {
jshintrc: '.jshintrc'
},
all: [
'Gruntfile.js',
'angular-moment.js',
'tests.js'
]
},
uglify: {
dist: {
options: {
sourceMap: true
},
files: {
'angular-moment.min.js': 'angular-moment.js'
}
}
},
ngdocs: {
options: {
startPage: '/',
title: false,
html5Mode: false
},
api: {
src: 'angular-moment.js',
title: 'angular-moment API Documentation'
}
}
});
grunt.registerTask('test', [
'jshint',
'karma'
]);
grunt.registerTask('build', [
'jshint',
'uglify'
]);
grunt.registerTask('default', ['build']);
};
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-2015 Uri Shaked and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+141
View File
@@ -0,0 +1,141 @@
angular-moment
==============
AngularJS directive and filters for [Moment.JS](http://www.momentjs.com).
Copyright (C) 2013, 2014, 2015, Uri Shaked <uri@urish.org>
[![Build Status](https://travis-ci.org/urish/angular-moment.png?branch=master)](https://travis-ci.org/urish/angular-moment)
[![Coverage Status](https://coveralls.io/repos/urish/angular-moment/badge.png)](https://coveralls.io/r/urish/angular-moment)
Installation
------------
You can choose your preferred method of installation:
* Through bower: `bower install angular-moment --save`
* Through npm: `npm install angular-moment --save`
* Through NuGet: `Install-Package angular-moment`
* From a CDN: [jsDelivr](https://cdn.jsdelivr.net/angular.moment/0.10.1/angular-moment.min.js) or [CDNJS](https://cdnjs.cloudflare.com/ajax/libs/angular-moment/0.10.1/angular-moment.min.js)
* Download from github: [angular-moment.min.js](https://raw.github.com/urish/angular-moment/master/angular-moment.min.js)
Usage
-----
Include both moment.js and angular-moment.js in your application.
```html
<script src="components/moment/moment.js"></script>
<script src="components/angular-moment/angular-moment.js"></script>
```
Add the module `angularMoment` as a dependency to your app module:
```js
var myapp = angular.module('myapp', ['angularMoment']);
```
If you need internationalization support, load specified moment.js locale file first:
```html
<script src="components/moment/locale/de.js"></script>
```
Then call the `amMoment.changeLocale()` method (e.g. inside your app's run() callback):
```js
myapp.run(function(amMoment) {
amMoment.changeLocale('de');
});
```
### Configuration
Parameter `preprocess`(e.g: `unix`, `utc`) would pre-execute before.
```js
angular.module('myapp').constant('angularMomentConfig', {
preprocess: 'unix', // optional
timezone: 'Europe/London' // optional
});
```
### Timeago directive
Use am-time-ago directive to format your relative timestamps. For example:
```html
<span am-time-ago="message.time"></span>
<span am-time-ago="message.time" am-preprocess="unix"></span>
```
angular-moment will dynamically update the span to indicate how much time
passed since the message was created. So, if your controller contains the following
code:
```js
$scope.message = {
text: 'hello world!',
time: new Date()
};
```
The user will initially see "a few seconds ago", and about a minute
after the span will automatically update with the text "a minute ago",
etc.
### amDateFormat filter
Format dates using moment.js format() method. Example:
```html
<span>{{message.time | amDateFormat:'dddd, MMMM Do YYYY, h:mm:ss a'}}</span>
```
This snippet will format the given time as "Monday, October 7th 2013, 12:36:29 am".
For more information about Moment.JS formatting options, see the
[docs for the format() function](http://momentjs.com/docs/#/displaying/format/).
### amCalendar filter
Format dates using moment.js calendar() method. Example:
```html
<span>{{message.time | amCalendar}}</span>
```
This snippet will format the given time as e.g. "Today 2:30 AM" or "Last Monday 2:30 AM" etc..
For more information about Moment.JS calendar time format, see the
[docs for the calendar() function](http://momentjs.com/docs/#/displaying/calendar-time/).
### amDifference filter
Get the difference between two dates in milliseconds.
Parameters are date, units and usePrecision. Date defaults to current date. Example:
```html
<span>Scheduled {{message.createdAt | amDifference : null : 'days' }} days from now</span>
```
This snippet will return the number of days between the current date and the date filtered.
For more information about Moment.JS difference function, see the
[docs for the diff() function](http://momentjs.com/docs/#/displaying/difference/).
### Time zone support
The `amDateFormat` and `amCalendar` filters can be configured to display dates aligned
to a specific timezone. You can configure the timezone using the following syntax:
```js
angular.module('myapp').constant('angularMomentConfig', {
timezone: 'Name of Timezone' // e.g. 'Europe/London'
});
```
Remember to include `moment-timezone.js` in your project, otherwise the custom timezone
functionality will not be available. You will also need to include a timezone data file that
you can create using the [Timezone Data Builder](http://momentjs.com/timezone/data/)
or simply download from [here](https://rawgithub.com/qw4n7y/7282780/raw/6ae3b334b295f93047e8f3ad300db6bc4387e235/moment-timezone-data.js).
License
----
Released under the terms of the [MIT License](LICENSE).
+563
View File
@@ -0,0 +1,563 @@
/* angular-moment.js / v0.10.1 / (c) 2013, 2014, 2015 Uri Shaked / MIT Licence */
'format amd';
/* global define */
(function () {
'use strict';
function angularMoment(angular, moment) {
/**
* @ngdoc overview
* @name angularMoment
*
* @description
* angularMoment module provides moment.js functionality for angular.js apps.
*/
return angular.module('angularMoment', [])
/**
* @ngdoc object
* @name angularMoment.config:angularMomentConfig
*
* @description
* Common configuration of the angularMoment module
*/
.constant('angularMomentConfig', {
/**
* @ngdoc property
* @name angularMoment.config.angularMomentConfig#preprocess
* @propertyOf angularMoment.config:angularMomentConfig
* @returns {string} The default preprocessor to apply
*
* @description
* Defines a default preprocessor to apply (e.g. 'unix', 'etc', ...). The default value is null,
* i.e. no preprocessor will be applied.
*/
preprocess: null, // e.g. 'unix', 'utc', ...
/**
* @ngdoc property
* @name angularMoment.config.angularMomentConfig#timezone
* @propertyOf angularMoment.config:angularMomentConfig
* @returns {string} The default timezone
*
* @description
* The default timezone (e.g. 'Europe/London'). Empty string by default (does not apply
* any timezone shift).
*/
timezone: '',
/**
* @ngdoc property
* @name angularMoment.config.angularMomentConfig#format
* @propertyOf angularMoment.config:angularMomentConfig
* @returns {string} The pre-conversion format of the date
*
* @description
* Specify the format of the input date. Essentially it's a
* default and saves you from specifying a format in every
* element. Overridden by element attr. Null by default.
*/
format: null,
/**
* @ngdoc property
* @name angularMoment.config.angularMomentConfig#statefulFilters
* @propertyOf angularMoment.config:angularMomentConfig
* @returns {boolean} Whether angular-moment filters should be stateless (or not)
*
* @description
* Specifies whether the filters included with angular-moment are stateful.
* Stateful filters will automatically re-evaluate whenever you change the timezone
* or language settings, but may negatively impact performance. true by default.
*/
statefulFilters: true
})
/**
* @ngdoc object
* @name angularMoment.object:moment
*
* @description
* moment global (as provided by the moment.js library)
*/
.constant('moment', moment)
/**
* @ngdoc object
* @name angularMoment.config:amTimeAgoConfig
* @module angularMoment
*
* @description
* configuration specific to the amTimeAgo directive
*/
.constant('amTimeAgoConfig', {
/**
* @ngdoc property
* @name angularMoment.config.amTimeAgoConfig#withoutSuffix
* @propertyOf angularMoment.config:amTimeAgoConfig
* @returns {boolean} Whether to include a suffix in am-time-ago directive
*
* @description
* Defaults to false.
*/
withoutSuffix: false,
/**
* @ngdoc property
* @name angularMoment.config.amTimeAgoConfig#serverTime
* @propertyOf angularMoment.config:amTimeAgoConfig
* @returns {number} Server time in milliseconds since the epoch
*
* @description
* If set, time ago will be calculated relative to the given value.
* If null, local time will be used. Defaults to null.
*/
serverTime: null,
/**
* @ngdoc property
* @name angularMoment.config.amTimeAgoConfig#titleFormat
* @propertyOf angularMoment.config:amTimeAgoConfig
* @returns {string} The format of the date to be displayed in the title of the element. If null,
* the directive set the title of the element.
*
* @description
* The format of the date used for the title of the element. null by default.
*/
titleFormat: null,
/**
* @ngdoc property
* @name angularMoment.config.amTimeAgoConfig#fullDateThreshold
* @propertyOf angularMoment.config:amTimeAgoConfig
* @returns {number} The minimum number of days for showing a full date instead of relative time
*
* @description
* The threshold for displaying a full date. The default is null, which means the date will always
* be relative, and full date will never be displayed.
*/
fullDateThreshold: null,
/**
* @ngdoc property
* @name angularMoment.config.amTimeAgoConfig#fullDateFormat
* @propertyOf angularMoment.config:amTimeAgoConfig
* @returns {string} The format to use when displaying a full date.
*
* @description
* Specify the format of the date when displayed as full date. null by default.
*/
fullDateFormat: null
})
/**
* @ngdoc directive
* @name angularMoment.directive:amTimeAgo
* @module angularMoment
*
* @restrict A
*/
.directive('amTimeAgo', ['$window', 'moment', 'amMoment', 'amTimeAgoConfig', 'angularMomentConfig', function ($window, moment, amMoment, amTimeAgoConfig, angularMomentConfig) {
return function (scope, element, attr) {
var activeTimeout = null;
var currentValue;
var currentFormat = angularMomentConfig.format;
var withoutSuffix = amTimeAgoConfig.withoutSuffix;
var titleFormat = amTimeAgoConfig.titleFormat;
var fullDateThreshold = amTimeAgoConfig.fullDateThreshold;
var fullDateFormat = amTimeAgoConfig.fullDateFormat;
var localDate = new Date().getTime();
var preprocess = angularMomentConfig.preprocess;
var modelName = attr.amTimeAgo;
var isTimeElement = ('TIME' === element[0].nodeName.toUpperCase());
function getNow() {
var now;
if (amTimeAgoConfig.serverTime) {
var localNow = new Date().getTime();
var nowMillis = localNow - localDate + amTimeAgoConfig.serverTime;
now = moment(nowMillis);
}
else {
now = moment();
}
return now;
}
function cancelTimer() {
if (activeTimeout) {
$window.clearTimeout(activeTimeout);
activeTimeout = null;
}
}
function updateTime(momentInstance) {
var daysAgo = getNow().diff(momentInstance, 'day');
var showFullDate = fullDateThreshold && daysAgo >= fullDateThreshold;
if (showFullDate) {
element.text(momentInstance.format(fullDateFormat));
} else {
element.text(momentInstance.from(getNow(), withoutSuffix));
}
if (titleFormat && !element.attr('title')) {
element.attr('title', momentInstance.local().format(titleFormat));
}
if (!showFullDate) {
var howOld = Math.abs(getNow().diff(momentInstance, 'minute'));
var secondsUntilUpdate = 3600;
if (howOld < 1) {
secondsUntilUpdate = 1;
} else if (howOld < 60) {
secondsUntilUpdate = 30;
} else if (howOld < 180) {
secondsUntilUpdate = 300;
}
activeTimeout = $window.setTimeout(function () {
updateTime(momentInstance);
}, secondsUntilUpdate * 1000);
}
}
function updateDateTimeAttr(value) {
if (isTimeElement) {
element.attr('datetime', value);
}
}
function updateMoment() {
cancelTimer();
if (currentValue) {
var momentValue = amMoment.preprocessDate(currentValue, preprocess, currentFormat);
updateTime(momentValue);
updateDateTimeAttr(momentValue.toISOString());
}
}
scope.$watch(modelName, function (value) {
if ((typeof value === 'undefined') || (value === null) || (value === '')) {
cancelTimer();
if (currentValue) {
element.text('');
updateDateTimeAttr('');
currentValue = null;
}
return;
}
currentValue = value;
updateMoment();
});
if (angular.isDefined(attr.amWithoutSuffix)) {
scope.$watch(attr.amWithoutSuffix, function (value) {
if (typeof value === 'boolean') {
withoutSuffix = value;
updateMoment();
} else {
withoutSuffix = amTimeAgoConfig.withoutSuffix;
}
});
}
attr.$observe('amFormat', function (format) {
if (typeof format !== 'undefined') {
currentFormat = format;
updateMoment();
}
});
attr.$observe('amPreprocess', function (newValue) {
preprocess = newValue;
updateMoment();
});
attr.$observe('amFullDateThreshold', function (newValue) {
fullDateThreshold = newValue;
updateMoment();
});
attr.$observe('amFullDateFormat', function (newValue) {
fullDateFormat = newValue;
updateMoment();
});
scope.$on('$destroy', function () {
cancelTimer();
});
scope.$on('amMoment:localeChanged', function () {
updateMoment();
});
};
}])
/**
* @ngdoc service
* @name angularMoment.service.amMoment
* @module angularMoment
*/
.service('amMoment', ['moment', '$rootScope', '$log', 'angularMomentConfig', function (moment, $rootScope, $log, angularMomentConfig) {
/**
* @ngdoc property
* @name angularMoment:amMoment#preprocessors
* @module angularMoment
*
* @description
* Defines the preprocessors for the preprocessDate method. By default, the following preprocessors
* are defined: utc, unix.
*/
this.preprocessors = {
utc: moment.utc,
unix: moment.unix
};
/**
* @ngdoc function
* @name angularMoment.service.amMoment#changeLocale
* @methodOf angularMoment.service.amMoment
*
* @description
* Changes the locale for moment.js and updates all the am-time-ago directive instances
* with the new locale. Also broadcasts an `amMoment:localeChanged` event on $rootScope.
*
* @param {string} locale Locale code (e.g. en, es, ru, pt-br, etc.)
* @param {object} customization object of locale strings to override
*/
this.changeLocale = function (locale, customization) {
var result = moment.locale(locale, customization);
if (angular.isDefined(locale)) {
$rootScope.$broadcast('amMoment:localeChanged');
}
return result;
};
/**
* @ngdoc function
* @name angularMoment.service.amMoment#changeTimezone
* @methodOf angularMoment.service.amMoment
*
* @description
* Changes the default timezone for amCalendar, amDateFormat and amTimeAgo. Also broadcasts an
* `amMoment:timezoneChanged` event on $rootScope.
*
* @param {string} timezone Timezone name (e.g. UTC)
*/
this.changeTimezone = function (timezone) {
angularMomentConfig.timezone = timezone;
$rootScope.$broadcast('amMoment:timezoneChanged');
};
/**
* @ngdoc function
* @name angularMoment.service.amMoment#preprocessDate
* @methodOf angularMoment.service.amMoment
*
* @description
* Preprocess a given value and convert it into a Moment instance appropriate for use in the
* am-time-ago directive and the filters.
*
* @param {*} value The value to be preprocessed
* @param {string} preprocess The name of the preprocessor the apply (e.g. utc, unix)
* @param {string=} format Specifies how to parse the value (see {@link http://momentjs.com/docs/#/parsing/string-format/})
* @return {Moment} A value that can be parsed by the moment library
*/
this.preprocessDate = function (value, preprocess, format) {
if (angular.isUndefined(preprocess)) {
preprocess = angularMomentConfig.preprocess;
}
if (this.preprocessors[preprocess]) {
return this.preprocessors[preprocess](value, format);
}
if (preprocess) {
$log.warn('angular-moment: Ignoring unsupported value for preprocess: ' + preprocess);
}
if (!isNaN(parseFloat(value)) && isFinite(value)) {
// Milliseconds since the epoch
return moment(parseInt(value, 10));
}
// else just returns the value as-is.
return moment(value, format);
};
/**
* @ngdoc function
* @name angularMoment.service.amMoment#applyTimezone
* @methodOf angularMoment.service.amMoment
*
* @description
* Apply a timezone onto a given moment object - if moment-timezone.js is included
* Otherwise, it'll not apply any timezone shift.
*
* @param {Moment} aMoment a moment() instance to apply the timezone shift to
* @param {string=} timezone The timezone to apply. If none given, will apply the timezone
* configured in angularMomentConfig.timezone.
*
* @returns {Moment} The given moment with the timezone shift applied
*/
this.applyTimezone = function (aMoment, timezone) {
timezone = timezone || angularMomentConfig.timezone;
if (aMoment && timezone) {
if (aMoment.tz) {
aMoment = aMoment.tz(timezone);
} else {
$log.warn('angular-moment: timezone specified but moment.tz() is undefined. Did you forget to include moment-timezone.js?');
}
}
return aMoment;
};
}])
/**
* @ngdoc filter
* @name angularMoment.filter:amCalendar
* @module angularMoment
*/
.filter('amCalendar', ['moment', 'amMoment', 'angularMomentConfig', function (moment, amMoment, angularMomentConfig) {
function amCalendarFilter(value, preprocess) {
if (typeof value === 'undefined' || value === null) {
return '';
}
value = amMoment.preprocessDate(value, preprocess);
var date = moment(value);
if (!date.isValid()) {
return '';
}
return amMoment.applyTimezone(date).calendar();
}
// Since AngularJS 1.3, filters have to explicitly define being stateful
// (this is no longer the default).
amCalendarFilter.$stateful = angularMomentConfig.statefulFilters;
return amCalendarFilter;
}])
/**
* @ngdoc filter
* @name angularMoment.filter:amDifference
* @module angularMoment
*/
.filter('amDifference', ['moment', 'amMoment', 'angularMomentConfig', function (moment, amMoment, angularMomentConfig) {
function amDifferenceFilter(value, otherValue, unit, usePrecision, preprocessValue, preprocessOtherValue) {
if (typeof value === 'undefined' || value === null) {
return '';
}
value = amMoment.preprocessDate(value, preprocessValue);
var date = moment(value);
if (!date.isValid()) {
return '';
}
var date2;
if (typeof otherValue === 'undefined' || otherValue === null) {
date2 = moment();
} else {
otherValue = amMoment.preprocessDate(otherValue, preprocessOtherValue);
date2 = moment(otherValue);
if (!date2.isValid()) {
return '';
}
}
return amMoment.applyTimezone(date).diff(amMoment.applyTimezone(date2), unit, usePrecision);
}
amDifferenceFilter.$stateful = angularMomentConfig.statefulFilters;
return amDifferenceFilter;
}])
/**
* @ngdoc filter
* @name angularMoment.filter:amDateFormat
* @module angularMoment
* @function
*/
.filter('amDateFormat', ['moment', 'amMoment', 'angularMomentConfig', function (moment, amMoment, angularMomentConfig) {
function amDateFormatFilter(value, format, preprocess, timezone) {
if (typeof value === 'undefined' || value === null) {
return '';
}
value = amMoment.preprocessDate(value, preprocess);
var date = moment(value);
if (!date.isValid()) {
return '';
}
return amMoment.applyTimezone(date, timezone).format(format);
}
amDateFormatFilter.$stateful = angularMomentConfig.statefulFilters;
return amDateFormatFilter;
}])
/**
* @ngdoc filter
* @name angularMoment.filter:amDurationFormat
* @module angularMoment
* @function
*/
.filter('amDurationFormat', ['moment', 'angularMomentConfig', function (moment, angularMomentConfig) {
function amDurationFormatFilter(value, format, suffix) {
if (typeof value === 'undefined' || value === null) {
return '';
}
return moment.duration(value, format).humanize(suffix);
}
amDurationFormatFilter.$stateful = angularMomentConfig.statefulFilters;
return amDurationFormatFilter;
}])
/**
* @ngdoc filter
* @name angularMoment.filter:amTimeAgo
* @module angularMoment
* @function
*/
.filter('amTimeAgo', ['moment', 'amMoment', 'angularMomentConfig', function (moment, amMoment, angularMomentConfig) {
function amTimeAgoFilter(value, preprocess, suffix) {
if (typeof value === 'undefined' || value === null) {
return '';
}
value = amMoment.preprocessDate(value, preprocess);
var date = moment(value);
if (!date.isValid()) {
return '';
}
return amMoment.applyTimezone(date).fromNow(suffix);
}
amTimeAgoFilter.$stateful = angularMomentConfig.statefulFilters;
return amTimeAgoFilter;
}]);
}
if (typeof define === 'function' && define.amd) {
define(['angular', 'moment'], angularMoment);
} else if (typeof module !== 'undefined' && module && module.exports) {
angularMoment(angular, require('moment'));
module.exports = 'angularMoment';
} else {
angularMoment(angular, window.moment);
}
})();
@@ -0,0 +1,2 @@
"format amd";!function(){"use strict";function a(a,b){return a.module("angularMoment",[]).constant("angularMomentConfig",{preprocess:null,timezone:"",format:null,statefulFilters:!0}).constant("moment",b).constant("amTimeAgoConfig",{withoutSuffix:!1,serverTime:null,titleFormat:null,fullDateThreshold:null,fullDateFormat: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-v+e.serverTime;a=c(d)}else a=c();return a}function k(){p&&(b.clearTimeout(p),p=null)}function l(a){var c=j().diff(a,"day"),d=t&&c>=t;if(h.text(d?a.format(u):a.from(j(),r)),s&&!h.attr("title")&&h.attr("title",a.local().format(s)),!d){var e=Math.abs(j().diff(a,"minute")),f=3600;1>e?f=1:60>e?f=30:180>e&&(f=300),p=b.setTimeout(function(){l(a)},1e3*f)}}function m(a){y&&h.attr("datetime",a)}function n(){if(k(),o){var a=d.preprocessDate(o,w,q);l(a),m(a.toISOString())}}var o,p=null,q=f.format,r=e.withoutSuffix,s=e.titleFormat,t=e.fullDateThreshold,u=e.fullDateFormat,v=(new Date).getTime(),w=f.preprocess,x=i.amTimeAgo,y="TIME"===h[0].nodeName.toUpperCase();g.$watch(x,function(a){return"undefined"==typeof a||null===a||""===a?(k(),void(o&&(h.text(""),m(""),o=null))):(o=a,void n())}),a.isDefined(i.amWithoutSuffix)&&g.$watch(i.amWithoutSuffix,function(a){"boolean"==typeof a?(r=a,n()):r=e.withoutSuffix}),i.$observe("amFormat",function(a){"undefined"!=typeof a&&(q=a,n())}),i.$observe("amPreprocess",function(a){w=a,n()}),i.$observe("amFullDateThreshold",function(a){t=a,n()}),i.$observe("amFullDateFormat",function(a){u=a,n()}),g.$on("$destroy",function(){k()}),g.$on("amMoment:localeChanged",function(){n()})}}]).service("amMoment",["moment","$rootScope","$log","angularMomentConfig",function(b,c,d,e){this.preprocessors={utc:b.utc,unix:b.unix},this.changeLocale=function(d,e){var f=b.locale(d,e);return a.isDefined(d)&&c.$broadcast("amMoment:localeChanged"),f},this.changeTimezone=function(a){e.timezone=a,c.$broadcast("amMoment:timezoneChanged")},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,b){return b=b||e.timezone,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","angularMomentConfig",function(a,b,c){function d(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():""}return d.$stateful=c.statefulFilters,d}]).filter("amDifference",["moment","amMoment","angularMomentConfig",function(a,b,c){function d(c,d,e,f,g,h){if("undefined"==typeof c||null===c)return"";c=b.preprocessDate(c,g);var i=a(c);if(!i.isValid())return"";var j;if("undefined"==typeof d||null===d)j=a();else if(d=b.preprocessDate(d,h),j=a(d),!j.isValid())return"";return b.applyTimezone(i).diff(b.applyTimezone(j),e,f)}return d.$stateful=c.statefulFilters,d}]).filter("amDateFormat",["moment","amMoment","angularMomentConfig",function(a,b,c){function d(c,d,e,f){if("undefined"==typeof c||null===c)return"";c=b.preprocessDate(c,e);var g=a(c);return g.isValid()?b.applyTimezone(g,f).format(d):""}return d.$stateful=c.statefulFilters,d}]).filter("amDurationFormat",["moment","angularMomentConfig",function(a,b){function c(b,c,d){return"undefined"==typeof b||null===b?"":a.duration(b,c).humanize(d)}return c.$stateful=b.statefulFilters,c}]).filter("amTimeAgo",["moment","amMoment","angularMomentConfig",function(a,b,c){function d(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):""}return d.$stateful=c.statefulFilters,d}])}"function"==typeof define&&define.amd?define(["angular","moment"],a):"undefined"!=typeof module&&module&&module.exports?(a(angular,require("moment")),module.exports="angularMoment"):a(angular,window.moment)}();
//# sourceMappingURL=angular-moment.min.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>angular-moment</id>
<version>0.10.1</version>
<title>Angular Moment</title>
<authors>urish</authors>
<projectUrl>https://github.com/urish/angular-moment</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Moment.JS directives for AngularJS (timeago and more)</description>
<summary>Moment.JS directives for AngularJS (timeago and more).</summary>
<releaseNotes />
<copyright />
<dependencies>
<dependency id="Moment.js" version="2.10.2" />
</dependencies>
<tags>AngularJS MomentJS Moment</tags>
</metadata>
<files>
<file src="angular-moment.js" target="content\Scripts\angular-moment.js" />
<file src="angular-moment.min.js" target="content\Scripts\angular-moment.min.js" />
<file src="angular-moment.min.js.map" target="content\Scripts\angular-moment.min.js.map" />
</files>
</package>
@@ -0,0 +1,23 @@
{
"name": "angular-moment",
"version": "0.10.1",
"description": "Moment.JS directives & filters for AngularJS (timeago alternative)",
"author": "Uri Shaked",
"license": "MIT",
"homepage": "http://github.com/urish/angular-moment",
"main": "./angular-moment.js",
"ignore": [
],
"dependencies": {
"angular": ">=1.2.0 <1.5.0",
"moment": ">=2.8.0 <2.11.0"
},
"devDependencies": {
"angular-mocks": "1.3.x",
"moment-timezone": "0.3.1"
},
"repository": {
"type": "git",
"url": "git://github.com/urish/angular-moment.git"
}
}
@@ -0,0 +1,36 @@
/* License: MIT.
* Copyright (C) 2013, 2014, 2015, Uri Shaked.
*/
'use strict';
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
logLevel: config.LOG_INFO,
browsers: ['PhantomJS'],
autoWatch: true,
reporters: ['dots', 'coverage'],
files: [
'bower_components/angular/angular.js',
'bower_components/moment/moment.js',
'bower_components/moment/{locale,lang}/fr.js',
'bower_components/moment-timezone/moment-timezone.js',
'angular-moment.js',
// angular-mocks defines a global variable named 'module' which confuses moment-timezone.js.
// Therefore, it must be included after moment-timezone.js.
'bower_components/angular-mocks/angular-mocks.js',
'tests.js'
],
preprocessors: {
'angular-moment.js': 'coverage'
},
coverageReporter: {
type: 'lcov',
dir: 'coverage/'
}
});
};
@@ -0,0 +1,35 @@
{
"name": "angular-moment",
"version": "0.10.1",
"main": "angular-moment.js",
"repository": {
"type": "git",
"url": "http://github.com/urish/angular-moment.git"
},
"dependencies": {
"moment": ">=2.8.0 <2.11.0"
},
"devDependencies": {
"bower": "^1.3.12",
"coveralls": "~2.11.0",
"grunt": "~0.4.1",
"grunt-cli": "^0.1.13",
"grunt-contrib-jshint": "~0.11.0",
"grunt-contrib-uglify": "0.8.1",
"grunt-karma": "~0.10.1",
"grunt-ngdocs": "^0.2.7",
"karma": "~0.12.0",
"karma-coverage": "~0.2.0",
"karma-jasmine": "~0.3.5",
"karma-phantomjs-launcher": "~0.1.1",
"load-grunt-tasks": "3.1.0"
},
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"bower": "node_modules/.bin/bower install",
"test": "node_modules/.bin/grunt test",
"build": "node_modules/.bin/grunt build"
}
}
+725
View File
@@ -0,0 +1,725 @@
/* License: MIT.
* Copyright (C) 2013, 2014, 2015, Uri Shaked.
*/
/* global describe, inject, module, beforeEach, afterEach, it, expect, spyOn, jasmine */
'use strict';
describe('module angularMoment', function () {
var $rootScope, $compile, $window, $filter, moment, amTimeAgoConfig, originalTimeAgoConfig, angularMomentConfig,
originalAngularMomentConfig, amMoment;
beforeEach(module('angularMoment'));
beforeEach(inject(function ($injector) {
$rootScope = $injector.get('$rootScope');
$compile = $injector.get('$compile');
$window = $injector.get('$window');
$filter = $injector.get('$filter');
moment = $injector.get('moment');
amMoment = $injector.get('amMoment');
amTimeAgoConfig = $injector.get('amTimeAgoConfig');
angularMomentConfig = $injector.get('angularMomentConfig');
originalTimeAgoConfig = angular.copy(amTimeAgoConfig);
originalAngularMomentConfig = angular.copy(angularMomentConfig);
// Ensure the locale of moment.js is set to en by default
(moment.locale || moment.lang)('en');
// Add a sample timezones for tests
moment.tz.add('UTC|UTC|0|0|');
moment.tz.add('Pacific/Tahiti|LMT TAHT|9W.g a0|01|-2joe1.I');
}));
afterEach(function () {
// Restore original configuration after each test
angular.copy(originalTimeAgoConfig, amTimeAgoConfig);
angular.copy(originalAngularMomentConfig, angularMomentConfig);
jasmine.clock().uninstall();
});
describe('am-time-ago directive', function () {
it('should change the text of the element to "a few seconds ago" when given unix timestamp', function () {
$rootScope.testDate = new Date().getTime() / 1000;
var element = angular.element('<span am-time-ago="testDate" am-preprocess="unix"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
});
it('should change the text of the element to "a few seconds ago" when given current time', function () {
$rootScope.testDate = new Date();
var element = angular.element('<span am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
});
it('should change the text of the div to "3 minutes ago" when given a date 3 minutes ago', function () {
$rootScope.testDate = new Date(new Date().getTime() - 3 * 60 * 1000);
var element = angular.element('<div am-time-ago="testDate"></div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('3 minutes ago');
});
it('should change the text of the div to "2 hours ago" when given a date 2 hours ago', function () {
$rootScope.testDate = new Date(new Date().getTime() - 2 * 60 * 60 * 1000);
var element = angular.element('<div am-time-ago="testDate"></div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('2 hours ago');
});
it('should change the text of the div to "one year ago" when given a date one year ago', function () {
var today = new Date();
$rootScope.testDate = new Date(today.getFullYear() - 1, today.getMonth(), today.getDate());
var element = angular.element('<div am-time-ago="testDate"></div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a year ago');
});
it('should parse correctly numeric dates as milliseconds since the epoch', function () {
$rootScope.testDate = new Date().getTime();
var element = angular.element('<div am-time-ago="testDate"></div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
});
it('should update the value if date changes on scope', function () {
var today = new Date();
$rootScope.testDate = new Date(today.getFullYear() - 1, today.getMonth(), today.getDate()).getTime();
var element = angular.element('<div am-time-ago="testDate"></div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a year ago');
$rootScope.testDate = new Date();
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
});
it('should update the span text as time passes', function (done) {
$rootScope.testDate = new Date(new Date().getTime() - 44000);
var element = angular.element('<div am-time-ago="testDate"></div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
var waitsInterval = setInterval(function () {
// Wait until $rootScope.date is more than 45 seconds old
if (new Date().getTime() - $rootScope.testDate.getTime() < 45000) {
return;
}
clearInterval(waitsInterval);
$rootScope.$digest();
expect(element.text()).toBe('a minute ago');
done();
}, 50);
});
it('should schedule the update timer to one hour ahead for date in the far future (#73)', function () {
$rootScope.testDate = new Date(new Date().getTime() + 86400000);
jasmine.clock().install();
spyOn($window, 'setTimeout');
var element = angular.element('<div am-time-ago="testDate"></div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect($window.setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 3600000);
});
describe('bindonce', function () {
it('should change the text of the div to "3 minutes ago" when given a date 3 minutes ago with one time binding', function () {
$rootScope.testDate = new Date(new Date().getTime() - 3 * 60 * 1000);
var element = angular.element('<div am-time-ago="::testDate"></div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('3 minutes ago');
});
it('should parse correctly numeric dates as milliseconds since the epoch with one time binding', function () {
$rootScope.testDate = new Date().getTime();
var element = angular.element('<div am-time-ago="::testDate"></div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
});
it('should not update the value if date changes on scope when using one time binding', function () {
var today = new Date();
$rootScope.testDate = new Date(today.getFullYear() - 1, today.getMonth(), today.getDate()).getTime();
var element = angular.element('<div am-time-ago="::testDate"></div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a year ago');
$rootScope.testDate = new Date();
$rootScope.$digest();
expect(element.text()).toBe('a year ago');
});
});
it('should handle undefined data', function () {
$rootScope.testDate = null;
var element = angular.element('<div am-time-ago="testDate"></div>');
element = $compile(element)($rootScope);
var digest = function () {
$rootScope.$digest();
};
expect(digest).not.toThrow();
});
it('should remove the element text and cancel the timer when an empty string is given (#15)', function () {
$rootScope.testDate = new Date().getTime();
var element = angular.element('<div am-time-ago="testDate"></div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
$rootScope.testDate = '';
spyOn($window, 'clearTimeout').and.callThrough();
$rootScope.$digest();
expect($window.clearTimeout).toHaveBeenCalled();
expect(element.text()).toBe('');
});
it('should not change the contents of the element until a date is given', function () {
$rootScope.testDate = null;
var element = angular.element('<div am-time-ago="testDate">Initial text</div>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('Initial text');
$rootScope.testDate = new Date().getTime();
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
});
it('should cancel the timer when the scope is destroyed', function () {
var scope = $rootScope.$new();
$rootScope.testDate = new Date();
var element = angular.element('<span am-time-ago="testDate"></span>');
element = $compile(element)(scope);
$rootScope.$digest();
spyOn($window, 'clearTimeout').and.callThrough();
scope.$destroy();
expect($window.clearTimeout).toHaveBeenCalled();
});
it('should generate a time string without suffix when configured to do so', function () {
amTimeAgoConfig.withoutSuffix = true;
$rootScope.testDate = new Date();
var element = angular.element('<span am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds');
});
it('should generate update the text following a locale change via amMoment.changeLocale() method', function () {
$rootScope.testDate = new Date();
var element = angular.element('<span am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
amMoment.changeLocale('fr');
expect(element.text()).toBe('il y a quelques secondes');
});
it('should update the `datetime` attr if applied to a TIME element', function () {
$rootScope.testDate = Date.UTC(2012, 8, 20, 15, 20, 12);
var element = angular.element('<time am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.attr('datetime')).toBe('2012-09-20T15:20:12.000Z');
});
describe('setting the element title', function () {
it('should not set the title attribute of the element to the date by default', function () {
$rootScope.testDate = new Date().getTime() / 1000;
var element = angular.element('<span am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.attr('title')).toBeUndefined();
});
it('should not change the title attribute of the element if the element already has a title', function () {
amTimeAgoConfig.titleFormat = 'MMMM Do YYYY, h:mm:ss a';
$rootScope.testDate = new Date().getTime() / 1000;
var element = angular.element('<span am-time-ago="testDate" title="test"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.attr('title')).toBe('test');
});
it('should set the title attribute of the element to the formatted date as per the config', function () {
amTimeAgoConfig.titleFormat = 'MMMM Do YYYY, h:mm:ss a';
$rootScope.testDate = new Date().getTime() / 1000;
var element = angular.element('<span am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
var testDateWithCustomFormatting = moment($rootScope.testDate).format(amTimeAgoConfig.titleFormat);
expect(element.attr('title')).toBe(testDateWithCustomFormatting);
});
describe('full date support', function () {
it('should display relative time if the date is recent', function () {
amTimeAgoConfig.fullDateThreshold = 7;
$rootScope.testDate = new Date(new Date().getTime() - 2 * 24 * 60 * 60 * 1000);
var element = angular.element('<span am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('2 days ago');
});
it('should display full time if the date is past the threshold', function () {
amTimeAgoConfig.fullDateThreshold = 7;
$rootScope.testDate = new Date(2012, 5, 5);
var element = angular.element('<span am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toMatch(/^2012-06-05T00:00:00\+\d\d:\d\d$/);
});
it('should display full time using the given format', function () {
amTimeAgoConfig.fullDateThreshold = 7;
amTimeAgoConfig.fullDateFormat = 'YYYY,DD,MM';
$rootScope.testDate = new Date(2010, 1, 8);
var element = angular.element('<span am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('2010,08,02');
});
it('should support changing the full date threshold through attribute', function () {
$rootScope.threshold = 7;
$rootScope.testDate = new Date(new Date().getTime() - 12 * 24 * 60 * 60 * 1000);
var element = angular.element('<span am-time-ago="testDate" am-full-date-threshold="{{threshold}}"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe(moment($rootScope.testDate).format());
$rootScope.threshold = 20;
$rootScope.$digest();
expect(element.text()).toBe('12 days ago');
});
it('should support setting the full date format through attribute', function () {
amTimeAgoConfig.fullDateThreshold = 7;
$rootScope.testDate = new Date(2013, 11, 15);
var element = angular.element('<span am-time-ago="testDate" am-full-date-format="YYYY-MM-DD"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('2013-12-15');
});
});
});
describe('am-without-suffix attribute', function () {
it('should generate a time string without suffix when true', function () {
$rootScope.testDate = new Date();
var element = angular.element('<span am-time-ago="testDate" am-without-suffix="true"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds');
});
it('should generate a time string with suffix when false', function () {
amTimeAgoConfig.withoutSuffix = true;
$rootScope.testDate = new Date();
var element = angular.element('<span am-time-ago="testDate" am-without-suffix="false"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
});
it('should support expressions', function () {
$rootScope.testDate = new Date();
$rootScope.withSuffix = false;
var element = angular.element('<span am-time-ago="testDate" am-without-suffix="!withSuffix"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds');
$rootScope.withSuffix = true;
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
});
it('should ignore non-boolean values', function () {
$rootScope.testDate = new Date();
$rootScope.withoutSuffix = 'string';
var element = angular.element('<span am-time-ago="testDate" am-without-suffix="withoutSuffix"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a few seconds ago');
});
});
describe('am-format attribute', function () {
it('should support custom date format', function () {
var today = new Date();
$rootScope.testDate = today.getFullYear() + '#' + today.getDate() + '#' + today.getMonth();
var element = angular.element('<span am-time-ago="testDate" am-format="YYYY#DD#MM"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a month ago');
});
it('should support angular expressions in date format', function () {
var today = new Date();
$rootScope.testDate = today.getMonth() + '@' + today.getFullYear() + '@' + today.getDate();
var element = angular.element('<span am-time-ago="testDate" am-format="{{dateFormat}}"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
$rootScope.dateFormat = 'MM@YYYY@DD';
$rootScope.$digest();
expect(element.text()).toBe('a month ago');
});
});
describe('format config property', function () {
it('should be used when no `am-format` attribute is found', function () {
angularMomentConfig.format = 'MM@YYYY@DD';
var today = new Date();
$rootScope.testDate = today.getMonth() + '@' + today.getFullYear() + '@' + today.getDate();
var element = angular.element('<span am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a month ago');
});
it('should be overridable by `am-format` attribute', function () {
angularMomentConfig.format = 'YYYY@MM@@DD';
var today = new Date();
$rootScope.testDate = today.getMonth() + '@' + today.getFullYear() + '@' + today.getDate();
var element = angular.element('<span am-format="MM@YYYY@DD" am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('a month ago');
});
});
describe('serverTime configuration', function () {
it('should calculate time ago in respect to the configured server time', function () {
amTimeAgoConfig.serverTime = Date.UTC(2014, 5, 12, 5, 22, 11);
$rootScope.testDate = Date.UTC(2014, 5, 12, 9, 22, 11);
var element = angular.element('<span am-time-ago="testDate"></span>');
element = $compile(element)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('in 4 hours');
});
});
});
describe('amCalendar filter', function () {
var amCalendar;
beforeEach(function () {
amCalendar = $filter('amCalendar');
});
it('should convert today date to calendar form', function () {
var today = new Date();
var testDate = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 13, 33, 33);
expect(amCalendar(testDate)).toBe('Today at 1:33 PM');
});
it('should convert date in long past to calendar form', function () {
expect(amCalendar(new Date(2012, 2, 25, 13, 14, 15))).toBe('03/25/2012');
});
it('should gracefully handle undefined values', function () {
expect(amCalendar()).toBe('');
});
it('should accept a numeric unix timestamp (milliseconds since the epoch) as input', function () {
expect(amCalendar(new Date(2012, 0, 22, 4, 46, 54).getTime())).toBe('01/22/2012');
});
it('should respect the configured timezone', function () {
angularMomentConfig.timezone = 'Pacific/Tahiti';
expect(amCalendar(Date.UTC(2012, 0, 22, 4, 46, 54))).toBe('01/21/2012');
});
it('should apply the "utc" preprocessor when the string "utc" is given in the second argument', function () {
expect(amCalendar(Date.UTC(2012, 0, 22, 0, 0, 0), 'utc')).toBe('01/22/2012');
expect(amCalendar(Date.UTC(2012, 0, 22, 23, 59, 59), 'utc')).toBe('01/22/2012');
});
it('should apply the "unix" preprocessor if angularMomentConfig.preprocess is set to "unix" and no preprocessor is given', function () {
var unixDate = new Date(1970, 0, 2, 10, 0, 0).getTime() / 1000;
angularMomentConfig.preprocess = 'unix';
expect(amCalendar(unixDate)).toBe('01/02/1970');
});
it('should ignore the default preprocessor if we explicity give it null in the second argument', function () {
var unixDate = new Date(1970, 0, 1, 10, 0, 0).getTime();
angularMomentConfig.preprocess = 'unix';
expect(amCalendar(unixDate, null)).toBe('01/01/1970');
});
it('should gracefully handle the case where timezone is given but moment-timezone is not loaded', function () {
angularMomentConfig.timezone = 'Pacific/Tahiti';
var originalMomentTz = moment.fn.tz;
try {
delete moment.fn.tz;
expect(amCalendar(new Date(2012, 0, 22, 4, 46, 54).getTime())).toBe('01/22/2012');
} finally {
moment.fn.tz = originalMomentTz;
moment.fn.tz = originalMomentTz;
}
});
it('should return an empty string for invalid input', function () {
expect(amCalendar('blah blah')).toBe('');
});
});
describe('amDifference filter', function () {
var amDifference;
beforeEach(function () {
amDifference = $filter('amDifference');
});
it('should take the difference of two dates in milliseconds', function () {
var today = new Date(2012, 0, 22, 0, 0, 0);
var testDate = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 13, 33, 33);
expect(amDifference(testDate, today)).toBe(48813000);
});
it('should support passing "years", "months", "days", etc as a units parameter', function () {
var test = new Date(2012, 0, 22, 4, 46, 54);
var testDate1 = new Date(2013, 0, 22, 4, 46, 54);
expect(amDifference(testDate1, test, 'years')).toBe(1);
var testDate2 = new Date(2012, 1, 22, 4, 46, 54);
expect(amDifference(testDate2, test, 'months')).toBe(1);
var testDate3 = new Date(2012, 0, 23, 4, 46, 54);
expect(amDifference(testDate3, test, 'days')).toBe(1);
});
it('should allow rounding to be disabled via parameter', function () {
var test = new Date(2012, 0, 22, 4, 46, 54);
var testDate1 = new Date(test.getFullYear() + 1, test.getMonth() + 6, test.getDate());
expect(amDifference(testDate1, test, 'years')).toBe(1);
expect(amDifference(testDate1, test, 'years', true)).toBeCloseTo(1.5);
});
it('dates from the future should return negative values', function () {
var today = new Date(2012, 0, 22, 4, 46, 54);
var testDate = new Date(2013, 0, 22, 4, 46, 54);
expect(String(amDifference(today, testDate))).toContain('-');
});
it('should gracefully handle undefined values', function () {
expect(amDifference()).toBe('');
});
it('should accept a numeric unix timestamp (milliseconds since the epoch) as input', function () {
expect(amDifference(new Date(2012, 0, 22, 4, 46, 55).getTime(), new Date(2012, 0, 22, 4, 46, 54).getTime())).toBe(1000);
});
it('should apply the "utc" preprocessor when the string "utc" is given as a preprocessor argument', function () {
expect(amDifference([2012, 0, 22, 0, 0, 1], Date.UTC(2012, 0, 22, 0, 0, 0), null, null, 'utc')).toBe(1000);
expect(amDifference(Date.UTC(2012, 0, 22, 0, 0, 1), [2012, 0, 22, 0, 0, 0], null, null, null, 'utc')).toBe(1000);
});
it('should apply the "unix" preprocessor if angularMomentConfig.preprocess is set to "unix" and no preprocessor is given', function () {
angularMomentConfig.preprocess = 'unix';
expect(amDifference(100001, 100000)).toBe(1000);
});
it('should return an empty string for invalid input', function () {
expect(amDifference('blah blah')).toBe('');
});
});
describe('amDateFormat filter', function () {
var amDateFormat;
beforeEach(function () {
amDateFormat = $filter('amDateFormat');
});
it('should support displaying format', function () {
var today = new Date();
var expectedResult = today.getDate() + '.' + (today.getMonth() + 1) + '.' + today.getFullYear();
expect(amDateFormat(today, 'D.M.YYYY')).toBe(expectedResult);
});
it('should gracefully handle undefined values', function () {
expect(amDateFormat(undefined, 'D.M.YYYY')).toBe('');
});
it('should accept a numeric unix timestamp (milliseconds since the epoch) as input', function () {
var timestamp = new Date(2012, 0, 22, 12, 46, 54).getTime();
expect(amDateFormat(timestamp, '(HH,mm,ss);MM.DD.YYYY')).toBe('(12,46,54);01.22.2012');
});
it('should gracefully handle string unix timestamp as input', function () {
var strTimestamp = String(new Date(2012, 0, 22, 12, 46, 54).getTime());
expect(amDateFormat(strTimestamp, '(HH,mm,ss);MM.DD.YYYY')).toBe('(12,46,54);01.22.2012');
});
it('should respect the configured timezone', function () {
angularMomentConfig.timezone = 'Pacific/Tahiti';
var timestamp = Date.UTC(2012, 0, 22, 12, 46, 54);
expect(amDateFormat(timestamp, '(HH,mm,ss);MM.DD.YYYY')).toBe('(02,46,54);01.22.2012');
});
it('should respect the timezone parameter', function () {
var timestamp = Date.UTC(2012, 0, 22, 12, 46, 54);
expect(amDateFormat(timestamp, '(HH,mm,ss);MM.DD.YYYY', 'utc', 'Pacific/Tahiti')).toBe('(02,46,54);01.22.2012');
});
it('should return an empty string for invalid input', function () {
expect(amDateFormat('blah blah', '(HH,mm,ss);MM.DD.YYYY')).toBe('');
});
});
describe('amDurationFormat filter', function () {
var amDurationFormat;
beforeEach(function () {
amDurationFormat = $filter('amDurationFormat');
});
it('should support return the given duration as text', function () {
expect(amDurationFormat(1000, 'milliseconds')).toBe('a few seconds');
});
it('should support return a day given 24 hours', function () {
expect(amDurationFormat(24, 'hours')).toBe('a day');
});
it('should add prefix the result with the word "in" if the third parameter (suffix) is true', function () {
expect(amDurationFormat(1, 'minutes', true)).toBe('in a minute');
});
it('should add suffix the result with the word "ago" if the duration is negative and the third parameter is true', function () {
expect(amDurationFormat(-1, 'minutes', true)).toBe('a minute ago');
});
it('should gracefully handle undefined values for duration', function () {
expect(amDurationFormat(undefined, 'minutes')).toBe('');
});
});
describe('amTimeAgo filter', function () {
var amTimeAgo;
beforeEach(function () {
amTimeAgo = $filter('amTimeAgo');
});
it('should support return the time ago as text', function () {
var date = new Date();
expect(amTimeAgo(date)).toBe('a few seconds ago');
});
it('should remove suffix from the result if the third parameter (suffix) is true', function () {
var date = new Date();
expect(amTimeAgo(date, null, true)).toBe('a few seconds');
});
it('should gracefully handle undefined values', function () {
expect(amTimeAgo()).toBe('');
});
it('should gracefully handle invalid input', function () {
expect(amTimeAgo('noDate')).toBe('');
});
});
describe('amMoment service', function () {
describe('#changeLocale', function () {
it('should convert today\'s date to custom calendar format', function () {
var today = new Date();
amMoment.changeLocale('en', {calendar: {sameDay: '[This Day]'}});
var amCalendar = $filter('amCalendar');
var testDate = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 13, 33, 33);
expect(amCalendar(testDate)).toBe('This Day');
});
it('should return the current locale', function () {
expect(amMoment.changeLocale()).toBe('en');
});
it('should broadcast an angularMoment:localeChanged event on the root scope if a locale is specified', function () {
var eventBroadcasted = false;
$rootScope.$on('amMoment:localeChanged', function () {
eventBroadcasted = true;
});
amMoment.changeLocale('fr');
expect(eventBroadcasted).toBe(true);
});
it('should not broadcast an angularMoment:localeChanged event on the root scope if no locale is specified', function () {
var eventBroadcasted = false;
$rootScope.$on('amMoment:localeChanged', function () {
eventBroadcasted = true;
});
amMoment.changeLocale();
expect(eventBroadcasted).toBe(false);
});
});
describe('#changeTimezone', function () {
it('Should update the current timezone', function () {
amMoment.changeTimezone('UTC');
expect(amMoment.applyTimezone(moment()).utcOffset()).toBe(0);
amMoment.changeTimezone('Pacific/Tahiti');
expect(amMoment.applyTimezone(moment()).utcOffset()).toBe(-600);
});
it('should broadcast an angularMoment:timezoneChanged event on the root scope with the new timezone value', function () {
var eventBroadcasted = false;
$rootScope.$on('amMoment:timezoneChanged', function () {
eventBroadcasted = true;
});
amMoment.changeTimezone('UTC');
expect(eventBroadcasted).toBe(true);
});
});
describe('#preprocessDate', function () {
it('should call a custom preprocessor that was registered on amMoment.preprocessors', function () {
var testDate = new Date(2013, 0, 22, 12, 46, 54);
var meeting = {
name: 'Budget plan',
date: testDate
};
amMoment.preprocessors.foobar = function (value) {
return moment(value.date);
};
expect(amMoment.preprocessDate(meeting, 'foobar').valueOf()).toEqual(testDate.getTime());
});
it('should issue a warning if an unsupported preprocessor is used and fall-back to default processing', inject(function ($log) {
var testDate = new Date(2014, 0, 22, 12, 46, 54);
spyOn($log, 'warn');
expect(amMoment.preprocessDate(testDate.getTime(), 'blabla').valueOf()).toEqual(testDate.getTime());
expect($log.warn).toHaveBeenCalledWith('angular-moment: Ignoring unsupported value for preprocess: blabla');
}));
});
});
describe('amTimeAgoConfig constant', function () {
it('should generate time with suffix by default', function () {
expect(amTimeAgoConfig.withoutSuffix).toBe(false);
});
});
describe('angularMomentConfig constant', function () {
it('should have an empty timezone value by default', function () {
expect(angularMomentConfig.timezone).toBe('');
});
it('should have an empty preprocess value by default', function () {
expect(angularMomentConfig.preprocess).toBe(null);
});
});
});
@@ -0,0 +1,18 @@
{
"name": "angular-resource",
"version": "1.2.15-build.2398+sha.4bab3d8",
"main": "./angular-resource.js",
"dependencies": {
"angular": "1.2.15-build.2398+sha.4bab3d8"
},
"homepage": "https://github.com/angular/bower-angular-resource",
"_release": "1.2.15-build.2398+sha.4bab3d8",
"_resolution": {
"type": "version",
"tag": "v1.2.15-build.2398+sha.4bab3d8",
"commit": "c20e7f87b0f788322c1c1920f1646a116389fa8d"
},
"_source": "git://github.com/angular/bower-angular-resource.git",
"_target": "~1.2.12",
"_originalSource": "angular-resource"
}
@@ -0,0 +1,54 @@
# bower-angular-resource
This repo is for distribution on `bower`. The source for this module is in the
[main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngResource).
Please file issues and pull requests against that repo.
## Install
Install with `bower`:
```shell
bower install angular-resource
```
Add a `<script>` to your `index.html`:
```html
<script src="/bower_components/angular-resource/angular-resource.js"></script>
```
And add `ngResource` as a dependency for your app:
```javascript
angular.module('myApp', ['ngResource']);
```
## Documentation
Documentation is available on the
[AngularJS docs site](http://docs.angularjs.org/api/ngResource).
## License
The MIT License
Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+597
View File
@@ -0,0 +1,597 @@
/**
* @license AngularJS v1.2.15-build.2398+sha.4bab3d8
* (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular, undefined) {'use strict';
var $resourceMinErr = angular.$$minErr('$resource');
// Helper functions and regex to lookup a dotted path on an object
// stopping at undefined/null. The path must be composed of ASCII
// identifiers (just like $parse)
var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;
function isValidDottedPath(path) {
return (path != null && path !== '' && path !== 'hasOwnProperty' &&
MEMBER_NAME_REGEX.test('.' + path));
}
function lookupDottedPath(obj, path) {
if (!isValidDottedPath(path)) {
throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
}
var keys = path.split('.');
for (var i = 0, ii = keys.length; i < ii && obj !== undefined; i++) {
var key = keys[i];
obj = (obj !== null) ? obj[key] : undefined;
}
return obj;
}
/**
* Create a shallow copy of an object and clear other fields from the destination
*/
function shallowClearAndCopy(src, dst) {
dst = dst || {};
angular.forEach(dst, function(value, key){
delete dst[key];
});
for (var key in src) {
if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
dst[key] = src[key];
}
}
return dst;
}
/**
* @ngdoc module
* @name ngResource
* @description
*
* # ngResource
*
* The `ngResource` module provides interaction support with RESTful services
* via the $resource service.
*
*
* <div doc-module-components="ngResource"></div>
*
* See {@link ngResource.$resource `$resource`} for usage.
*/
/**
* @ngdoc service
* @name $resource
* @requires $http
*
* @description
* A factory which creates a resource object that lets you interact with
* [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
*
* The returned resource object has action methods which provide high-level behaviors without
* the need to interact with the low level {@link ng.$http $http} service.
*
* Requires the {@link ngResource `ngResource`} module to be installed.
*
* @param {string} url A parametrized URL template with parameters prefixed by `:` as in
* `/user/:username`. If you are using a URL with a port number (e.g.
* `http://example.com:8080/api`), it will be respected.
*
* If you are using a url with a suffix, just add the suffix, like this:
* `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
* or even `$resource('http://example.com/resource/:resource_id.:format')`
* If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
* collapsed down to a single `.`. If you need this sequence to appear and not collapse then you
* can escape it with `/\.`.
*
* @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
* `actions` methods. If any of the parameter value is a function, it will be executed every time
* when a param value needs to be obtained for a request (unless the param was overridden).
*
* Each key value in the parameter object is first bound to url template if present and then any
* excess keys are appended to the url search query after the `?`.
*
* Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
* URL `/path/greet?salutation=Hello`.
*
* If the parameter value is prefixed with `@` then the value of that parameter is extracted from
* the data object (useful for non-GET operations).
*
* @param {Object.<Object>=} actions Hash with declaration of custom action that should extend
* the default set of resource actions. The declaration should be created in the format of {@link
* ng.$http#usage_parameters $http.config}:
*
* {action1: {method:?, params:?, isArray:?, headers:?, ...},
* action2: {method:?, params:?, isArray:?, headers:?, ...},
* ...}
*
* Where:
*
* - **`action`** {string} The name of action. This name becomes the name of the method on
* your resource object.
* - **`method`** {string} HTTP request method. Valid methods are: `GET`, `POST`, `PUT`,
* `DELETE`, and `JSONP`.
* - **`params`** {Object=} Optional set of pre-bound parameters for this action. If any of
* the parameter value is a function, it will be executed every time when a param value needs to
* be obtained for a request (unless the param was overridden).
* - **`url`** {string} action specific `url` override. The url templating is supported just
* like for the resource-level urls.
* - **`isArray`** {boolean=} If true then the returned object for this action is an array,
* see `returns` section.
* - **`transformRequest`**
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}`
* transform function or an array of such functions. The transform function takes the http
* request body and headers and returns its transformed (typically serialized) version.
* - **`transformResponse`**
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}`
* transform function or an array of such functions. The transform function takes the http
* response body and headers and returns its transformed (typically deserialized) version.
* - **`cache`** `{boolean|Cache}` If true, a default $http cache will be used to cache the
* GET request, otherwise if a cache instance built with
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
* caching.
* - **`timeout`** `{number|Promise}` timeout in milliseconds, or {@link ng.$q promise} that
* should abort the request when resolved.
* - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
* XHR object. See
* [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
* for more information.
* - **`responseType`** - `{string}` - see
* [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
* - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
* `response` and `responseError`. Both `response` and `responseError` interceptors get called
* with `http response` object. See {@link ng.$http $http interceptors}.
*
* @returns {Object} A resource "class" object with methods for the default set of resource actions
* optionally extended with custom `actions`. The default set contains these actions:
* ```js
* { 'get': {method:'GET'},
* 'save': {method:'POST'},
* 'query': {method:'GET', isArray:true},
* 'remove': {method:'DELETE'},
* 'delete': {method:'DELETE'} };
* ```
*
* Calling these methods invoke an {@link ng.$http} with the specified http method,
* destination and parameters. When the data is returned from the server then the object is an
* instance of the resource class. The actions `save`, `remove` and `delete` are available on it
* as methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
* read, update, delete) on server-side data like this:
* ```js
* var User = $resource('/user/:userId', {userId:'@id'});
* var user = User.get({userId:123}, function() {
* user.abc = true;
* user.$save();
* });
* ```
*
* It is important to realize that invoking a $resource object method immediately returns an
* empty reference (object or array depending on `isArray`). Once the data is returned from the
* server the existing reference is populated with the actual data. This is a useful trick since
* usually the resource is assigned to a model which is then rendered by the view. Having an empty
* object results in no rendering, once the data arrives from the server then the object is
* populated with the data and the view automatically re-renders itself showing the new data. This
* means that in most cases one never has to write a callback function for the action methods.
*
* The action methods on the class object or instance object can be invoked with the following
* parameters:
*
* - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
* - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
* - non-GET instance actions: `instance.$action([parameters], [success], [error])`
*
* Success callback is called with (value, responseHeaders) arguments. Error callback is called
* with (httpResponse) argument.
*
* Class actions return empty instance (with additional properties below).
* Instance actions return promise of the action.
*
* The Resource instances and collection have these additional properties:
*
* - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
* instance or collection.
*
* On success, the promise is resolved with the same resource instance or collection object,
* updated with data from server. This makes it easy to use in
* {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
* rendering until the resource(s) are loaded.
*
* On failure, the promise is resolved with the {@link ng.$http http response} object, without
* the `resource` property.
*
* - `$resolved`: `true` after first server interaction is completed (either with success or
* rejection), `false` before that. Knowing if the Resource has been resolved is useful in
* data-binding.
*
* @example
*
* # Credit card resource
*
* ```js
// Define CreditCard class
var CreditCard = $resource('/user/:userId/card/:cardId',
{userId:123, cardId:'@id'}, {
charge: {method:'POST', params:{charge:true}}
});
// We can retrieve a collection from the server
var cards = CreditCard.query(function() {
// GET: /user/123/card
// server returns: [ {id:456, number:'1234', name:'Smith'} ];
var card = cards[0];
// each item is an instance of CreditCard
expect(card instanceof CreditCard).toEqual(true);
card.name = "J. Smith";
// non GET methods are mapped onto the instances
card.$save();
// POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
// server returns: {id:456, number:'1234', name: 'J. Smith'};
// our custom method is mapped as well.
card.$charge({amount:9.99});
// POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
});
// we can create an instance as well
var newCard = new CreditCard({number:'0123'});
newCard.name = "Mike Smith";
newCard.$save();
// POST: /user/123/card {number:'0123', name:'Mike Smith'}
// server returns: {id:789, number:'0123', name: 'Mike Smith'};
expect(newCard.id).toEqual(789);
* ```
*
* The object returned from this function execution is a resource "class" which has "static" method
* for each action in the definition.
*
* Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
* `headers`.
* When the data is returned from the server then the object is an instance of the resource type and
* all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
* operations (create, read, update, delete) on server-side data.
```js
var User = $resource('/user/:userId', {userId:'@id'});
var user = User.get({userId:123}, function() {
user.abc = true;
user.$save();
});
```
*
* It's worth noting that the success callback for `get`, `query` and other methods gets passed
* in the response that came from the server as well as $http header getter function, so one
* could rewrite the above example and get access to http headers as:
*
```js
var User = $resource('/user/:userId', {userId:'@id'});
User.get({userId:123}, function(u, getResponseHeaders){
u.abc = true;
u.$save(function(u, putResponseHeaders) {
//u => saved user object
//putResponseHeaders => $http header getter
});
});
```
* # Creating a custom 'PUT' request
* In this example we create a custom method on our resource to make a PUT request
* ```js
* var app = angular.module('app', ['ngResource', 'ngRoute']);
*
* // Some APIs expect a PUT request in the format URL/object/ID
* // Here we are creating an 'update' method
* app.factory('Notes', ['$resource', function($resource) {
* return $resource('/notes/:id', null,
* {
* 'update': { method:'PUT' }
* });
* }]);
*
* // In our controller we get the ID from the URL using ngRoute and $routeParams
* // We pass in $routeParams and our Notes factory along with $scope
* app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
function($scope, $routeParams, Notes) {
* // First get a note object from the factory
* var note = Notes.get({ id:$routeParams.id });
* $id = note.id;
*
* // Now call update passing in the ID first then the object you are updating
* Notes.update({ id:$id }, note);
*
* // This will PUT /notes/ID with the note object in the request payload
* }]);
* ```
*/
angular.module('ngResource', ['ng']).
factory('$resource', ['$http', '$q', function($http, $q) {
var DEFAULT_ACTIONS = {
'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'}
};
var noop = angular.noop,
forEach = angular.forEach,
extend = angular.extend,
copy = angular.copy,
isFunction = angular.isFunction;
/**
* We need our custom method because encodeURIComponent is too aggressive and doesn't follow
* http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
* segments:
* segment = *pchar
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
* pct-encoded = "%" HEXDIG HEXDIG
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
* / "*" / "+" / "," / ";" / "="
*/
function encodeUriSegment(val) {
return encodeUriQuery(val, true).
replace(/%26/gi, '&').
replace(/%3D/gi, '=').
replace(/%2B/gi, '+');
}
/**
* This method is intended for encoding *key* or *value* parts of query component. We need a
* custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
* have to be encoded per http://tools.ietf.org/html/rfc3986:
* query = *( pchar / "/" / "?" )
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* pct-encoded = "%" HEXDIG HEXDIG
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
* / "*" / "+" / "," / ";" / "="
*/
function encodeUriQuery(val, pctEncodeSpaces) {
return encodeURIComponent(val).
replace(/%40/gi, '@').
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
}
function Route(template, defaults) {
this.template = template;
this.defaults = defaults || {};
this.urlParams = {};
}
Route.prototype = {
setUrlParams: function(config, params, actionUrl) {
var self = this,
url = actionUrl || self.template,
val,
encodedVal;
var urlParams = self.urlParams = {};
forEach(url.split(/\W/), function(param){
if (param === 'hasOwnProperty') {
throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
}
if (!(new RegExp("^\\d+$").test(param)) && param &&
(new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
urlParams[param] = true;
}
});
url = url.replace(/\\:/g, ':');
params = params || {};
forEach(self.urlParams, function(_, urlParam){
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
if (angular.isDefined(val) && val !== null) {
encodedVal = encodeUriSegment(val);
url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
return encodedVal + p1;
});
} else {
url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
leadingSlashes, tail) {
if (tail.charAt(0) == '/') {
return tail;
} else {
return leadingSlashes + tail;
}
});
}
});
// strip trailing slashes and set the url
url = url.replace(/\/+$/, '') || '/';
// then replace collapse `/.` if found in the last URL path segment before the query
// E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
url = url.replace(/\/\.(?=\w+($|\?))/, '.');
// replace escaped `/\.` with `/.`
config.url = url.replace(/\/\\\./, '/.');
// set params - delegate param encoding to $http
forEach(params, function(value, key){
if (!self.urlParams[key]) {
config.params = config.params || {};
config.params[key] = value;
}
});
}
};
function resourceFactory(url, paramDefaults, actions) {
var route = new Route(url);
actions = extend({}, DEFAULT_ACTIONS, actions);
function extractParams(data, actionParams){
var ids = {};
actionParams = extend({}, paramDefaults, actionParams);
forEach(actionParams, function(value, key){
if (isFunction(value)) { value = value(); }
ids[key] = value && value.charAt && value.charAt(0) == '@' ?
lookupDottedPath(data, value.substr(1)) : value;
});
return ids;
}
function defaultResponseInterceptor(response) {
return response.resource;
}
function Resource(value){
shallowClearAndCopy(value || {}, this);
}
forEach(actions, function(action, name) {
var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
Resource[name] = function(a1, a2, a3, a4) {
var params = {}, data, success, error;
/* jshint -W086 */ /* (purposefully fall through case statements) */
switch(arguments.length) {
case 4:
error = a4;
success = a3;
//fallthrough
case 3:
case 2:
if (isFunction(a2)) {
if (isFunction(a1)) {
success = a1;
error = a2;
break;
}
success = a2;
error = a3;
//fallthrough
} else {
params = a1;
data = a2;
success = a3;
break;
}
case 1:
if (isFunction(a1)) success = a1;
else if (hasBody) data = a1;
else params = a1;
break;
case 0: break;
default:
throw $resourceMinErr('badargs',
"Expected up to 4 arguments [params, data, success, error], got {0} arguments",
arguments.length);
}
/* jshint +W086 */ /* (purposefully fall through case statements) */
var isInstanceCall = this instanceof Resource;
var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
var httpConfig = {};
var responseInterceptor = action.interceptor && action.interceptor.response ||
defaultResponseInterceptor;
var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
undefined;
forEach(action, function(value, key) {
if (key != 'params' && key != 'isArray' && key != 'interceptor') {
httpConfig[key] = copy(value);
}
});
if (hasBody) httpConfig.data = data;
route.setUrlParams(httpConfig,
extend({}, extractParams(data, action.params || {}), params),
action.url);
var promise = $http(httpConfig).then(function(response) {
var data = response.data,
promise = value.$promise;
if (data) {
// Need to convert action.isArray to boolean in case it is undefined
// jshint -W018
if (angular.isArray(data) !== (!!action.isArray)) {
throw $resourceMinErr('badcfg', 'Error in resource configuration. Expected ' +
'response to contain an {0} but got an {1}',
action.isArray?'array':'object', angular.isArray(data)?'array':'object');
}
// jshint +W018
if (action.isArray) {
value.length = 0;
forEach(data, function(item) {
value.push(new Resource(item));
});
} else {
shallowClearAndCopy(data, value);
value.$promise = promise;
}
}
value.$resolved = true;
response.resource = value;
return response;
}, function(response) {
value.$resolved = true;
(error||noop)(response);
return $q.reject(response);
});
promise = promise.then(
function(response) {
var value = responseInterceptor(response);
(success||noop)(value, response.headers);
return value;
},
responseErrorInterceptor);
if (!isInstanceCall) {
// we are creating instance / collection
// - set the initial promise
// - return the instance / collection
value.$promise = promise;
value.$resolved = false;
return value;
}
// instance call
return promise;
};
Resource.prototype['$' + name] = function(params, success, error) {
if (isFunction(params)) {
error = success; success = params; params = {};
}
var result = Resource[name].call(this, params, this, success, error);
return result.$promise || result;
};
});
Resource.bind = function(additionalParamDefaults){
return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
};
return Resource;
}
return resourceFactory;
}]);
})(window, window.angular);
@@ -0,0 +1,13 @@
/*
AngularJS v1.2.15-build.2398+sha.4bab3d8
(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<c&&k!==A;f++){var g=a[f];k=null!==k?k[g]:A}}else k=b;e[d]=k});return e}function e(a){return a.resource}function f(a){D(a||{},this)}var F=new c(n);l=x({},B,l);s(l,function(h,d){var c=/^(POST|PUT|PATCH)$/i.test(h.method);f[d]=function(b,d,k,w){var q={},n,l,y;switch(arguments.length){case 4:y=w,l=k;case 3:case 2:if(u(d)){if(u(b)){l=
b;y=d;break}l=d;y=k}else{q=b;n=d;l=k;break}case 1:u(b)?l=b:c?n=b:q=b;break;case 0:break;default:throw v("badargs",arguments.length);}var t=this instanceof f,m=t?n:h.isArray?[]:new f(n),z={},B=h.interceptor&&h.interceptor.response||e,C=h.interceptor&&h.interceptor.responseError||A;s(h,function(a,b){"params"!=b&&("isArray"!=b&&"interceptor"!=b)&&(z[b]=G(a))});c&&(z.data=n);F.setUrlParams(z,x({},r(n,h.params||{}),q),h.url);q=p(z).then(function(b){var d=b.data,k=m.$promise;if(d){if(a.isArray(d)!==!!h.isArray)throw v("badcfg",
h.isArray?"array":"object",a.isArray(d)?"array":"object");h.isArray?(m.length=0,s(d,function(b){m.push(new f(b))})):(D(d,m),m.$promise=k)}m.$resolved=!0;b.resource=m;return b},function(b){m.$resolved=!0;(y||E)(b);return g.reject(b)});q=q.then(function(b){var a=B(b);(l||E)(a,b.headers);return a},C);return t?q:(m.$promise=q,m.$resolved=!1,m)};f.prototype["$"+d]=function(b,a,k){u(b)&&(k=a,a=b,b={});b=f[d].call(this,b,this,a,k);return b.$promise||b}});f.bind=function(a){return t(n,x({},w,a),l)};return f}
var B={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},E=a.noop,s=a.forEach,x=a.extend,G=a.copy,u=a.isFunction;c.prototype={setUrlParams:function(c,g,l){var r=this,e=l||r.template,f,p,h=r.urlParams={};s(e.split(/\W/),function(a){if("hasOwnProperty"===a)throw v("badname");!/^\d+$/.test(a)&&(a&&RegExp("(^|[^\\\\]):"+a+"(\\W|$)").test(e))&&(h[a]=!0)});e=e.replace(/\\:/g,":");g=g||{};s(r.urlParams,function(d,c){f=g.hasOwnProperty(c)?
g[c]:r.defaults[c];a.isDefined(f)&&null!==f?(p=encodeURIComponent(f).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"%20").replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),e=e.replace(RegExp(":"+c+"(\\W|$)","g"),function(a,c){return p+c})):e=e.replace(RegExp("(/?):"+c+"(\\W|$)","g"),function(a,c,d){return"/"==d.charAt(0)?d:c+d})});e=e.replace(/\/+$/,"")||"/";e=e.replace(/\/\.(?=\w+($|\?))/,".");c.url=e.replace(/\/\\\./,"/.");s(g,function(a,
e){r.urlParams[e]||(c.params=c.params||{},c.params[e]=a)})}};return t}])})(window,window.angular);
//# sourceMappingURL=angular-resource.min.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
{
"name": "angular-resource",
"version": "1.2.15-build.2398+sha.4bab3d8",
"main": "./angular-resource.js",
"dependencies": {
"angular": "1.2.15-build.2398+sha.4bab3d8"
}
}

Some files were not shown because too many files have changed in this diff Show More