├── .gitignore
├── .travis.yml
├── README.md
├── bower.json
├── gulpfile.js
├── karma.conf.js
├── modal.css
├── modal.js
├── modal.min.js
├── modal.min.js.map
├── modal.spec.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | bower_components/
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 0.10
4 | before_script:
5 | - export DISPLAY=:99.0
6 | - sh -e /etc/init.d/xvfb start
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # angular-modal [](https://travis-ci.org/btford/angular-modal)
2 |
3 | A modal factory service for AngularJS that makes it easy to add modals to your app.
4 |
5 |
6 | ## Install
7 |
8 | ```shell
9 | npm install angular-modal
10 | ```
11 |
12 | ## Usage
13 | 1. Include the `modal.js` script provided by this component into your app.
14 | 2. *Optional:* Include the `modal.css` style provided by this component into your html.
15 | 3. Add `btford.modal` as a module dependency to your app.
16 |
17 |
18 | ## Examples
19 |
20 | [Plunker demo](http://plnkr.co/edit/lJDNqafSCKdpMI8AjR0B?p=preview)
21 |
22 | ### Typical Use
23 |
24 | > app.js
25 |
26 | ```javascript
27 | angular.module('myApp', ['btford.modal']).
28 |
29 | // let's make a modal called `myModal`
30 | factory('myModal', function (btfModal) {
31 | return btfModal({
32 | controller: 'MyModalCtrl',
33 | controllerAs: 'modal',
34 | templateUrl: 'my-modal.html'
35 | });
36 | }).
37 |
38 | // typically you'll inject the modal service into its own
39 | // controller so that the modal can close itself
40 | controller('MyModalCtrl', function (myModal) {
41 | this.closeMe = myModal.deactivate;
42 | }).
43 |
44 | controller('MyCtrl', function (myModal) {
45 | this.showModal = myModal.activate;
46 | });
47 | ```
48 |
49 | > my-modal.html
50 |
51 | ```html
52 |
56 | ```
57 |
58 | > index.html
59 |
60 | ```html
61 |
64 | ```
65 |
66 | ### Cleaning up
67 |
68 | If you add any listeners within the modal's controller that are **outside the modal's `scope`**,
69 | you should remove them with `$scope.$on('$destroy', fn () { ... })` to avoid creating a memory leak.
70 |
71 | Building on the example above:
72 |
73 | > app.js
74 |
75 | ```javascript
76 | // ...
77 | controller('MyModalCtrl', function (myModal, $timeout) {
78 |
79 | var ctrl = this,
80 | timeoutId;
81 |
82 | ctrl.tickCount = 5;
83 |
84 | ctrl.closeMe = function () {
85 | cancelTick();
86 | myModal.deactivate();
87 | };
88 |
89 | function tick() {
90 | timeoutId = $timeout(function() {
91 | ctrl.tickCount -= 1;
92 | if (ctrl.tickCount <= 0) {
93 | ctrl.closeMe();
94 | } else {
95 | tick();
96 | }
97 | }, 1000);
98 | }
99 |
100 | function cancelTick() {
101 | $timeout.cancel(timeoutId);
102 | }
103 |
104 | $scope.$on('$destroy', cancelTick);
105 |
106 | tick();
107 | }).
108 | // ...
109 | ```
110 |
111 |
112 | ### Inline Options
113 |
114 | **Note:** The best practice is to use a separate file for the template and a separate declaration for
115 | the controller, but inlining these options might be more pragmatic for cases where the template or
116 | controller is just a couple lines.
117 |
118 | ```javascript
119 | angular.module('myApp', []).
120 |
121 | // let's make a modal called myModal
122 | factory('myModal', function (btfModal) {
123 | return btfModal({
124 | controller: function () {
125 | this.name = 'World';
126 | },
127 | controllerAs: 'ctrl',
128 | template: 'Hello {{ctrl.name}}
'
129 | });
130 | }).
131 |
132 | controller('MyCtrl', function (myModal) {
133 | this.showModal = myModal.activate;
134 | });
135 | ```
136 |
137 | ```html
138 |
141 | ```
142 |
143 |
144 | ## API
145 |
146 | ### `btfModal`
147 |
148 | The modal `factory`. Takes a configuration object as a parameter:
149 |
150 | ```javascript
151 | var modalService = btfModal({
152 | /* options */
153 | })
154 | ```
155 |
156 | And returns a `modalService` object that you can use to show/hide the modal (described below).
157 |
158 | The config object **must** either have a `template` or a `templateUrl` option.
159 |
160 | These options work just like the [route configuration in Angular's
161 | `$routeProvider`](http://docs.angularjs.org/api/ngRoute.$routeProvider#methods_when).
162 |
163 |
164 | #### `config.template`
165 | **string:** HTML string of the template to be used for this modal.
166 | Unless the template is very simple, you should probably use `config.templateUrl` instead.
167 |
168 | #### `config.templateUrl`
169 | **string (recommended):** URL to the HTML template to be used for this modal.
170 |
171 | #### `config.controller`
172 | **string|function (optional):** The name of a controller or a controller function.
173 |
174 | #### `config.controllerAs`
175 | **string (optional, recommended):** Makes the controller available on the scope of the modal as the given name.
176 |
177 | #### `config.container`
178 | **DOM Node (optional):** DOM node to prepend . Defaults to `document.body`.
179 |
180 |
181 | ### `modalService`
182 |
183 | A `modalService` has just two methods: `activate` and `deactivate`.
184 |
185 | #### `modalService.activate`
186 |
187 | Takes a hash of objects to add to the scope of the modal as locals.
188 | Adds the modal to the DOM by prepending it to the ``.
189 | Returns a promise that resolves once the modal is active.
190 |
191 | #### `modalService.deactivate`
192 |
193 | Removes the modal (DOM and scope) from the DOM.
194 | Returns a promise that resolves once the modal is removed.
195 |
196 | #### `modalService.active`
197 |
198 | Returns whether or not the modal is currently activated.
199 |
200 |
201 | ## Tests
202 |
203 | You can run the tests with [`karma`](http://karma-runner.github.io/0.10/index.html):
204 |
205 | ```shell
206 | karma start karma.conf.js
207 | ```
208 |
209 |
210 | ## License
211 | MIT
212 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-modal",
3 | "version": "0.5.0",
4 | "main": "modal.js",
5 | "ignore": [
6 | "**/.*",
7 | "node_modules",
8 | "components",
9 | "bower_components",
10 | "test",
11 | "tests"
12 | ],
13 | "dependencies": {
14 | "angular": "^1.3.14"
15 | },
16 | "devDependencies": {
17 | "angular-mocks": "^1.3.14"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | gutil = require('gulp-util'),
3 | uglify = require('gulp-uglify'),
4 | rename = require('gulp-rename');
5 |
6 | gulp.task('scripts', function() {
7 | return gulp.src('modal.js').
8 | pipe(rename('modal.min.js')).
9 | pipe(uglify({
10 | preserveComments: 'some',
11 | outSourceMap: true
12 | })).
13 | pipe(gulp.dest('.'));
14 | });
15 |
16 | gulp.task('default', function() {
17 | gulp.start('scripts');
18 | });
19 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config){
2 | config.set({
3 | basePath : './',
4 |
5 | files : [
6 | 'node_modules/angular/angular.js',
7 | 'node_modules/angular-mocks/angular-mocks.js',
8 | 'modal.js',
9 | 'modal.spec.js'
10 | ],
11 |
12 | autoWatch : true,
13 |
14 | frameworks: ['jasmine'],
15 |
16 | browsers : ['Chrome'],
17 |
18 | plugins : [
19 | 'karma-junit-reporter',
20 | 'karma-chrome-launcher',
21 | 'karma-firefox-launcher',
22 | 'karma-jasmine'
23 | ],
24 |
25 | junitReporter : {
26 | outputFile: 'test_out/unit.xml',
27 | suite: 'unit'
28 | }
29 |
30 | })}
--------------------------------------------------------------------------------
/modal.css:
--------------------------------------------------------------------------------
1 | /*
2 | * angular-modal v0.1.0
3 | * (c) 2013 Brian Ford http://briantford.com
4 | * License: MIT
5 | */
6 |
7 | .btf-modal {
8 | position: fixed;
9 | top: 50%;
10 | left: 50%;
11 | width: 50%;
12 | max-width: 550px;
13 | min-width: 330px;
14 | height: auto;
15 | z-index: 2000;
16 | -webkit-transform: translateX(-50%) translateY(-50%);
17 | -moz-transform: translateX(-50%) translateY(-50%);
18 | -ms-transform: translateX(-50%) translateY(-50%);
19 | transform: translateX(-50%) translateY(-50%);
20 | }
21 |
--------------------------------------------------------------------------------
/modal.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @license
3 | * angular-modal v0.5.0
4 | * (c) 2013 Brian Ford http://briantford.com
5 | * License: MIT
6 | */
7 |
8 | 'use strict';
9 |
10 | angular.module('btford.modal', []).
11 | factory('btfModal', ['$animate', '$compile', '$rootScope', '$controller', '$q', '$http', '$templateCache', modalFactoryFactory]);
12 |
13 | function modalFactoryFactory($animate, $compile, $rootScope, $controller, $q, $http, $templateCache) {
14 | return function modalFactory (config) {
15 | if (!(!config.template ^ !config.templateUrl)) {
16 | throw new Error('Expected modal to have exacly one of either `template` or `templateUrl`');
17 | }
18 |
19 | var template = config.template,
20 | controller = config.controller || null,
21 | controllerAs = config.controllerAs,
22 | container = angular.element(config.container || document.body),
23 | element = null,
24 | html,
25 | scope;
26 |
27 | if (config.template) {
28 | html = $q.when(config.template);
29 | } else {
30 | html = $http.get(config.templateUrl, {
31 | cache: $templateCache
32 | }).
33 | then(function (response) {
34 | return response.data;
35 | });
36 | }
37 |
38 | function activate (locals) {
39 | return html.then(function (html) {
40 | if (!element) {
41 | attach(html, locals);
42 | }
43 | });
44 | }
45 |
46 |
47 | function attach (html, locals) {
48 | element = angular.element(html);
49 | if (element.length === 0) {
50 | throw new Error('The template contains no elements; you need to wrap text nodes')
51 | }
52 | scope = $rootScope.$new();
53 | if (controller) {
54 | if (!locals) {
55 | locals = {};
56 | }
57 | locals.$scope = scope;
58 | var ctrl = $controller(controller, locals);
59 | if (controllerAs) {
60 | scope[controllerAs] = ctrl;
61 | }
62 | } else if (locals) {
63 | for (var prop in locals) {
64 | scope[prop] = locals[prop];
65 | }
66 | }
67 | $compile(element)(scope);
68 | return $animate.enter(element, container);
69 | }
70 |
71 | function deactivate () {
72 | if (!element) {
73 | return $q.when();
74 | }
75 | return $animate.leave(element).then(function () {
76 | scope.$destroy();
77 | scope = null;
78 | element.remove();
79 | element = null;
80 | });
81 | }
82 |
83 | function active () {
84 | return !!element;
85 | }
86 |
87 | return {
88 | activate: activate,
89 | deactivate: deactivate,
90 | active: active
91 | };
92 | };
93 | }
--------------------------------------------------------------------------------
/modal.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @license
3 | * angular-modal v0.5.0
4 | * (c) 2013 Brian Ford http://briantford.com
5 | * License: MIT
6 | */
7 | "use strict";function modalFactoryFactory(e,t,n,r,o,a,l){return function(c){function u(e){return p.then(function(t){v||i(t,e)})}function i(o,a){if(v=angular.element(o),0===v.length)throw new Error("The template contains no elements; you need to wrap text nodes");if(d=n.$new(),h){a||(a={}),a.$scope=d;var l=r(h,a);$&&(d[$]=l)}else if(a)for(var c in a)d[c]=a[c];return t(v)(d),e.enter(v,s)}function m(){return v?e.leave(v).then(function(){d.$destroy(),d=null,v.remove(),v=null}):o.when()}function f(){return!!v}if(!(!c.template^!c.templateUrl))throw new Error("Expected modal to have exacly one of either `template` or `templateUrl`");var p,d,h=(c.template,c.controller||null),$=c.controllerAs,s=angular.element(c.container||document.body),v=null;return p=c.template?o.when(c.template):a.get(c.templateUrl,{cache:l}).then(function(e){return e.data}),{activate:u,deactivate:m,active:f}}}angular.module("btford.modal",[]).factory("btfModal",["$animate","$compile","$rootScope","$controller","$q","$http","$templateCache",modalFactoryFactory]);
--------------------------------------------------------------------------------
/modal.min.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"modal.min.js.map","sources":["modal.min.js"],"names":["modalFactoryFactory","$animate","$compile","$rootScope","$controller","$q","$http","$templateCache","config","activate","locals","html","then","element","attach","angular","length","Error","scope","$new","controller","$scope","ctrl","controllerAs","prop","enter","container","deactivate","leave","$destroy","remove","when","active","template","templateUrl","document","body","get","cache","response","data","module","factory"],"mappings":";;;;;;AAOA,YAKA,SAASA,qBAAoBC,EAAUC,EAAUC,EAAYC,EAAaC,EAAIC,EAAOC,GACnF,MAAO,UAAuBC,GAwB5B,QAASC,GAAUC,GACjB,MAAOC,GAAKC,KAAK,SAAUD,GACpBE,GACHC,EAAOH,EAAMD,KAMnB,QAASI,GAAQH,EAAMD,GAErB,GADAG,EAAUE,QAAQF,QAAQF,GACH,IAAnBE,EAAQG,OACV,KAAM,IAAIC,OAAM,iEAGlB,IADAC,EAAQf,EAAWgB,OACfC,EAAY,CACTV,IACHA,MAEFA,EAAOW,OAASH,CAChB,IAAII,GAAOlB,EAAYgB,EAAYV,EAC/Ba,KACFL,EAAMK,GAAgBD,OAEnB,IAAIZ,EACT,IAAK,GAAIc,KAAQd,GACfQ,EAAMM,GAAQd,EAAOc,EAIzB,OADAtB,GAASW,GAASK,GACXjB,EAASwB,MAAMZ,EAASa,GAGjC,QAASC,KACP,MAAKd,GAGEZ,EAAS2B,MAAMf,GAASD,KAAK,WAClCM,EAAMW,WACNX,EAAQ,KACRL,EAAQiB,SACRjB,EAAU,OANHR,EAAG0B,OAUd,QAASC,KACP,QAASnB,EArEX,MAAOL,EAAOyB,UAAYzB,EAAO0B,aAC/B,KAAM,IAAIjB,OAAM,0EAGlB,IAKIN,GACAO,EALAE,GADgBZ,EAAOyB,SACPzB,EAAOY,YAAc,MACrCG,EAAgBf,EAAOe,aACvBG,EAAgBX,QAAQF,QAAQL,EAAOkB,WAAaS,SAASC,MAC7DvB,EAAgB,IAgEpB,OA3DEF,GADEH,EAAOyB,SACF5B,EAAG0B,KAAKvB,EAAOyB,UAEf3B,EAAM+B,IAAI7B,EAAO0B,aACtBI,MAAO/B,IAETK,KAAK,SAAU2B,GACb,MAAOA,GAASC,QAsDlB/B,SAAUA,EACVkB,WAAYA,EACZK,OAAQA,IAhFdjB,QAAQ0B,OAAO,mBACXC,QAAQ,YAAa,WAAY,WAAY,aAAc,cAAe,KAAM,QAAS,iBAAkB1C"}
--------------------------------------------------------------------------------
/modal.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('btfModal', function() {
4 | var container,
5 | btfModal,
6 | $rootScope;
7 |
8 | beforeEach(module('btford.modal'));
9 |
10 | beforeEach(function () {
11 | container = angular.element('');
12 | });
13 |
14 | afterEach(function() {
15 | container = null;
16 | });
17 |
18 | describe('without animations', function () {
19 | beforeEach(inject(function(_btfModal_, _$rootScope_, $templateCache) {
20 | btfModal = _btfModal_;
21 | $rootScope = _$rootScope_;
22 | $rootScope.greeting = 'こんばんは';
23 |
24 | $templateCache.put('test.html', [200, '{{greeting}}
', {}]);
25 | }));
26 |
27 | it('should not show a modal initially', function() {
28 | var modal = btfModal({
29 | templateUrl: 'test.html',
30 | container: container
31 | });
32 |
33 | $rootScope.$digest();
34 |
35 | expect(container.text()).toBe('');
36 | });
37 |
38 |
39 | it('should throw if called without a `template` or `templateUrl` option', function() {
40 | expect(function () { btfModal({}); }).toThrow();
41 | });
42 |
43 | it('should throw if called with a text node', function() {
44 | var modal = btfModal({
45 | template: 'hey'
46 | });
47 | expect(function () {
48 | modal.activate();
49 | $rootScope.$digest();
50 | }).toThrow();
51 | });
52 |
53 | it('should throw if called with both `template` and `templateUrl` options', function() {
54 | expect(function () {
55 | btfModal({
56 | template: 'foo',
57 | templateUrl: 'foo.html'
58 | });
59 | }).toThrow();
60 | });
61 |
62 | describe('#activate', function () {
63 | it('should show a modal when activated with `templateUrl`', function() {
64 | var modal = btfModal({
65 | templateUrl: 'test.html',
66 | container: container
67 | });
68 | modal.activate();
69 | $rootScope.$digest();
70 |
71 | expect(container.text()).toBe('こんばんは');
72 | });
73 |
74 | it('should show a modal when activated with `template`', function() {
75 | var modal = btfModal({
76 | template: '{{greeting}}',
77 | container: container
78 | });
79 |
80 | modal.activate();
81 | $rootScope.$digest();
82 |
83 | expect(container.text()).toBe('こんばんは');
84 | });
85 |
86 | it('should instantiate a controller via the `controller` option', function() {
87 | var modal = btfModal({
88 | template: '{{greeting}}',
89 | controller: function ($scope) {
90 | $scope.greeting = 'goodnight'
91 | },
92 | container: container
93 | });
94 |
95 | modal.activate();
96 | $rootScope.$digest();
97 |
98 | expect(container.text()).toBe('goodnight');
99 | });
100 |
101 | it('should expose a controller to the scope via the `controllerAs` option', function() {
102 | var modal = btfModal({
103 | template: '{{ctrl.greeting}}',
104 | controller: function () {
105 | this.greeting = 'boa noite'
106 | },
107 | controllerAs: 'ctrl',
108 | container: container
109 | });
110 |
111 | modal.activate();
112 | $rootScope.$digest();
113 |
114 | expect(container.text()).toBe('boa noite');
115 | });
116 |
117 | it('should pass locals to the controller scope', function() {
118 | var modal = btfModal({
119 | template: '{{ctrl.greeting}}',
120 | controller: function (greeting) {
121 | this.greeting = greeting;
122 | },
123 | controllerAs: 'ctrl',
124 | container: container
125 | });
126 |
127 | modal.activate({
128 | greeting: 'おはよう〜'
129 | });
130 | $rootScope.$digest();
131 |
132 | expect(container.text()).toBe('おはよう〜');
133 | });
134 |
135 | it('should pass locals to the modal scope if there is no controller', function() {
136 | var modal = btfModal({
137 | template: '{{greeting}}',
138 | container: container
139 | });
140 |
141 | modal.activate({
142 | greeting: 'bon soir'
143 | });
144 | $rootScope.$digest();
145 |
146 | expect(container.text()).toBe('bon soir');
147 | });
148 |
149 | it('should not activate multiple times', function() {
150 | var modal = btfModal({
151 | template: 'x',
152 | container: container
153 | });
154 |
155 | modal.activate();
156 | $rootScope.$digest();
157 | modal.activate();
158 | $rootScope.$digest();
159 |
160 | expect(container.text()).toBe('x');
161 | });
162 |
163 | it('should resolve a promise after activating', function() {
164 | var spy = jasmine.createSpy('activated');
165 |
166 | var modal = btfModal({
167 | template: 'x',
168 | container: container
169 | });
170 |
171 | modal.activate().then(spy);
172 | expect(spy).not.toHaveBeenCalled();
173 |
174 | $rootScope.$digest();
175 | expect(spy).toHaveBeenCalled();
176 | });
177 | });
178 |
179 |
180 | describe('#deactivate', function () {
181 | it('should remove a modal when deactivated', function() {
182 |
183 | var modal = btfModal({
184 | template: '{{greeting}}',
185 | container: container
186 | });
187 |
188 | modal.activate();
189 | $rootScope.$digest();
190 |
191 | modal.deactivate();
192 | $rootScope.$digest();
193 |
194 | expect(container.text()).toBe('');
195 | });
196 |
197 | it('should destroy the scope when deactivated', inject(function($browser) {
198 | var destroySpy = jasmine.createSpy('onDestroy');
199 |
200 | var modal = btfModal({
201 | template: '{{greeting}}',
202 | container: container,
203 | controller: function ($scope) {
204 | $scope.$on('$destroy', destroySpy);
205 | }
206 | });
207 |
208 | modal.activate();
209 | modal.deactivate().then(destroySpy);
210 | $browser.defer.flush();
211 |
212 | expect(destroySpy).toHaveBeenCalled();
213 | }));
214 |
215 | it('should resolve a promise after deactivating', inject(function($browser) {
216 | var spy = jasmine.createSpy('deactivated');
217 |
218 | var modal = btfModal({
219 | template: 'x',
220 | container: container
221 | });
222 |
223 | modal.activate();
224 | modal.deactivate().then(spy);
225 | $browser.defer.flush();
226 |
227 | expect(spy).toHaveBeenCalled();
228 | }));
229 |
230 | });
231 |
232 |
233 | describe('#active', function () {
234 | it('should return the state of the modal', inject(function($browser) {
235 |
236 | var modal = btfModal({
237 | template: '{{greeting}}',
238 | container: container
239 | });
240 |
241 | $rootScope.$digest();
242 | expect(modal.active()).toBe(false);
243 |
244 | modal.activate();
245 | $browser.defer.flush();
246 | expect(modal.active()).toBe(true);
247 | }));
248 | });
249 | });
250 |
251 |
252 | describe('with animations', function () {
253 | var $animate,
254 | modal;
255 |
256 | beforeEach(module('ngAnimateMock'));
257 |
258 | beforeEach(inject(function(btfModal, _$rootScope_, _$animate_) {
259 | $rootScope = _$rootScope_;
260 | $animate = _$animate_;
261 |
262 | modal = btfModal({
263 | template: 'animations!',
264 | container: container
265 | });
266 | }));
267 |
268 | it('should trigger an enter animation when activated', function () {
269 | modal.activate();
270 | $rootScope.$digest();
271 |
272 | var item = $animate.queue.shift();
273 | expect(item.event).toBe('enter');
274 | });
275 |
276 | it('should trigger a leave animation when deactivated', function () {
277 | modal.activate();
278 | $rootScope.$digest();
279 | $animate.queue.shift();
280 |
281 | modal.deactivate();
282 | $rootScope.$digest();
283 |
284 | var item = $animate.queue.shift();
285 | expect(item.event).toBe('leave');
286 | });
287 | });
288 |
289 | });
290 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-modal",
3 | "version": "0.5.0",
4 | "description": "easily add a modal to your angular app",
5 | "main": "modal.js",
6 | "scripts": {
7 | "test": "./node_modules/.bin/karma start karma.conf.js --browsers Firefox --single-run"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git://github.com/btford/angular-modal.git"
12 | },
13 | "keywords": [
14 | "angular",
15 | "angularjs",
16 | "modal"
17 | ],
18 | "author": "Brian Ford",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/btford/angular-modal/issues"
22 | },
23 | "devDependencies": {
24 | "angular": "^1.3.14",
25 | "angular-mocks": "^1.3.14",
26 | "gulp": "~3.5.5",
27 | "gulp-rename": "~1.2.0",
28 | "gulp-uglify": "~0.2.1",
29 | "gulp-util": "~2.2.14",
30 | "karma": "~0.10",
31 | "karma-junit-reporter": "~0.1.0"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------