Added custom confirm modal dialog box

This commit is contained in:
Luke Vella 2015-01-14 00:21:39 +01:00
parent 0320185ce5
commit 6ad493a079
31 changed files with 909 additions and 41 deletions

View file

@ -14,10 +14,7 @@ var EventSchema = new Schema({
type : Date,
default : Date.now
},
updated : {
type : Date,
default : Date.now
},
updated : Date,
title : String,
dates : [Date],
emails : [String],

View file

@ -20,6 +20,7 @@
"bootstrap-datepicker": "~1.3.0",
"angular-ui-router": "~0.2.13",
"angular-resource": "~1.3.6",
"ngFx": "~1.0.5"
"ngFx": "~1.0.5",
"angular-modal": "~0.4.0"
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
angular.module('rallly')
.controller('EditEventCtrl', function($scope, $http, $state, $timeout, Event){
.controller('EditEventCtrl', function($scope, $http, $state, $timeout, Event, ConfirmModal){
var id = $state.params.id
$scope.event = Event.get({id:id}, function(data){
var dates = [];
@ -20,16 +20,23 @@ angular.module('rallly')
$scope.submit = function(){
if ($scope.didChange()){
if ($scope.didChangeDates() ){
if (confirm("Changing the dates will reset all entries by the participants. Are you sure you want to proceed?")){
update();
}
var modal = new ConfirmModal({
title : 'Hold up!',
message : 'Changing the dates will reset all entries by the participants. Are you sure you want to do that?',
confirmText : 'Yes, I\'m sure',
isDestructive : true,
confirm : function(){
update();
}
});
modal.show();
} else {
update();
}
}
}
var update = function(){
$scope.event.participants = [];
Event.update({
id : id
}, $scope.event,

View file

@ -1,5 +1,5 @@
angular.module('rallly')
.controller('EventCtrl', function($scope, $http, $state, Event, Participant){
.controller('EventCtrl', function($scope, $http, $state, Event, Participant, ConfirmModal){
$(".nav-link").removeClass('active');
var id = $state.params.id;
$scope.participant = {};
@ -13,12 +13,21 @@ angular.module('rallly')
$state.go('notfound');
});
$scope.delete = function(participant){
if (confirm("Are you sure you want to remove "+participant.name+"?")){
Participant.remove({ id : id , pid : participant._id }, function(event){
$scope.event = event;
});
}
var modal = new ConfirmModal({
title : 'Delete "'+participant.name+'"?',
message : 'Are you sure you want to remove '+participant.name+' from the poll?',
confirmText : 'Yes - delete',
cancelText : 'No - nevermind',
isDestructive : true,
confirm : function(){
Participant.remove({ id : id , pid : participant._id }, function(event){
$scope.event = event;
});
}
});
modal.show();
}
$scope.defaults = [];
$scope.editEvent = function(){
@ -46,4 +55,6 @@ angular.module('rallly')
$scope.participant = {};
});
}
}).controller('DeleteModalCtrl', function(){
});

View file

@ -25,7 +25,7 @@ angular.module('rallly')
restrict : 'A',
require : 'ngModel',
link : function(scope, el, attrs, ngModel){
$(el).datepicker({
angular.element(el).datepicker({
multidate : true,
todayHighlight: true,
format : 'dd/mm/yyyy'
@ -40,10 +40,10 @@ angular.module('rallly')
});
scope.clearDates = function(){
$(el).datepicker('setDate', null)
angular.element(el).datepicker('setDate', null)
};
scope.unsetDate = function(date){
$(el).datepicker('setDates', scope.event.dates.filter(function(el){
angular.element(el).datepicker('setDates', scope.event.dates.filter(function(el){
return el != date;
}));
};

View file

@ -0,0 +1,28 @@
angular.module('rallly')
.filter('elapsed', function(){
return function(date){
if (!date) return;
var time = Date.parse(date),
timeNow = new Date().getTime(),
difference = timeNow - time,
seconds = Math.floor(difference / 1000),
minutes = Math.floor(seconds / 60),
hours = Math.floor(minutes / 60),
days = Math.floor(hours / 24);
if (days > 1) {
return days + " days ago";
} else if (days == 1) {
return "1 day ago"
} else if (hours > 1) {
return hours + " hours ago";
} else if (hours == 1) {
return "an hour ago";
} else if (minutes > 1) {
return minutes + " minutes ago";
} else if (minutes == 1){
return "a minute ago";
} else {
return "a few seconds ago";
}
}
})

View file

@ -1,4 +1,4 @@
angular.module('rallly', ['ui.router','ngResource','ngFx'])
angular.module('rallly', ['ui.router','ngResource','ngFx','btford.modal'])
.config(function($stateProvider, $urlRouterProvider, $locationProvider){
$locationProvider.html5Mode(true);
$urlRouterProvider.otherwise("/notfound")

View file

@ -0,0 +1,29 @@
angular.module('rallly')
.factory('ConfirmModal', function(btfModal){
return function(config){
var modal;
modal = btfModal({
templateUrl : 'templates/confirmmodal.html',
controllerAs : 'modal',
controller : function(){
this.title = config.title
this.message = config.message;
this.confirm = function(){
if (config.confirm) config.confirm();
modal.deactivate();
}
this.cancel = modal.deactivate;
this.confirmText = config.confirmText || 'Confirm';
this.cancelText = config.cancelText || 'Cancel';
this.isDestructive = config.isDestructive;
}
});
this.show = function(){
modal.activate();
}
this.destroy = function(){
modal.deactivate();
}
}
});

View file

@ -15,7 +15,7 @@
font-weight:600;
color: $dark-gray-clr;
text-decoration:none;
padding: em(8px) em(20px);
padding: em(8px) em(15px);
&.disabled {
cursor:default;
opacity: 0.5;

View file

@ -0,0 +1,42 @@
.rl-modal {
background:white;
position: fixed;
top: 50%;
box-shadow: 0 0 5px rgba(black, 0.5);
left: 50%;
width: 50%;
max-width: 400px;
display:inline-block;
min-width: 200px;
height: auto;
z-index: 2000;
overflow:hidden;
border-radius: 5px;
@include transform(translateX(-50%) translateY(-50%));
.rl-modal-message {
padding: 0 20px 20px 20px;
font-size: em(12px);
color: $body-clr;
}
.rl-modal-title {
padding:20px 20px 5px 20px;
font-size: em(18px);
}
.rl-modal-actions {
border-top:1px solid #ddd;
background: #F9FAFA;
text-align:right;
padding: em(10px) em(20px);
}
}
.rl-modal-overlay {
position:fixed;
z-index: 1000;
top:0;
left:0;
width:100%;
height:100%;
background:transparent;
}

View file

@ -18,6 +18,7 @@ body {
@import "partials/buttons";
@import "partials/type";
@import "partials/form";
@import "partials/modal";
@import "partials/datepicker";
@import "partials/event";
@import "partials/newevent";

View file

@ -1,7 +1,8 @@
<div style="max-width:500px">
<div style="max-width:600px">
<h1>What is Rallly?</h1>
<h2>Rallly is a collaborative scheduling service that makes deciding on a date fast and easy.</h2>
<div class="rl-page-desc">Rallly is a collaborative scheduling service that makes deciding on a date fast and easy.</div>
<h2>Hi, I'm Luke!</h2>
<p>
Hi, my name is Luke and I created Rallly as side project to help me learn some new technologies. I decided to publish it because I thought other people might find it useful. Rallly is a completely free service. In fact it is even open source. You can look at the latest source code on Github.
I created Rallly as side project to help me learn some new technologies. I decided to publish it because I thought other people might find it useful. Rallly is a completely free service. In fact it is even open source. You can look at the latest source code on Github.
</p>
</div>

View file

@ -0,0 +1,12 @@
<div class="rl-modal-overlay" ng-click="modal.cancel()"></div>
<div class="rl-modal">
<div class="rl-modal-title">{{modal.title}}</div>
<div class="rl-modal-message">
{{modal.message}}
</div>
<div class="rl-modal-actions">
<button ng-click="modal.confirm()" class="btn-primary" ng-class="{danger : modal.isDestructive}">{{modal.confirmText}}</button>
<button ng-click="modal.cancel()" class="btn-primary">{{modal.cancelText}}</button>
</div>
</div>

View file

@ -1,5 +1,4 @@
<h1>Editing: {{event.title}}</h1>
<h1>Edit Event</h1>
<div class="rl-page-desc">
You can makes changes to your existing event by changing the fields in the form below. When you're ready click save.
</div>

View file

@ -3,10 +3,10 @@
<h1 class="fx-rotate-clock">{{event.title}}</h1>
<ul class="event-detail-list">
<li class="event-created-by">
Created by <a href="{{event.creator.email}}">{{event.creator.name}}</a> on {{event.created | date : 'medium'}}
Created by <a href="{{event.creator.email}}">{{event.creator.name}}</a> - {{event.created | elapsed}}
</li>
<li>
Last updated {{event.updated | date : 'medium'}}
<li ng-show="event.updated">
Updated {{event.updated | elapsed}}
</li>
<li ng-show="event.location" class="event-location">
{{event.location}}
@ -24,7 +24,7 @@
<th class="event-poll-participants">
{{event.participants.length}} participants
</th>
<th class="center" ng-repeat="date in event.dates">
<th width="70" class="center" ng-repeat="date in event.dates">
<div class="daticon">
<div class="dow">
{{date | date: 'EEE'}}

View file

@ -1,7 +0,0 @@
<h1>Good Job!</h1>
<p>
Your event has been created. An email has been sent to all the participants with a link to the event page. Make sure you visit the page and vote on the dates yourself.
</p>
<h2>Here's the link</h2>
<h1>{{eventUrl}}</h1>
<a class="btn-primary" href="{{eventUrl}}">Go to Event Page</a>

30
public/vendor/angular-modal/.bower.json vendored Normal file
View file

@ -0,0 +1,30 @@
{
"name": "angular-modal",
"version": "0.4.0",
"main": "modal.js",
"ignore": [
"**/.*",
"node_modules",
"components",
"bower_components",
"test",
"tests"
],
"dependencies": {
"angular": "~1.2.13"
},
"devDependencies": {
"angular-mocks": "~1.2.13"
},
"homepage": "https://github.com/btford/angular-modal",
"_release": "0.4.0",
"_resolution": {
"type": "version",
"tag": "v0.4.0",
"commit": "ecbdc657bfe0c4ad6281aee0c1432278f10c5026"
},
"_source": "git://github.com/btford/angular-modal.git",
"_target": "~0.4.0",
"_originalSource": "angular-modal",
"_direct": true
}

211
public/vendor/angular-modal/README.md vendored Normal file
View file

@ -0,0 +1,211 @@
# angular-modal [![Build Status](https://travis-ci.org/btford/angular-modal.png)](https://travis-ci.org/btford/angular-modal)
A modal factory service for AngularJS that makes it easy to add modals to your app.
## Install
```shell
bower install angular-modal
```
## Usage
1. Include the `modal.js` script provided by this component into your app.
2. *Optional:* Include the `modal.css` style provided by this component into your html.
3. Add `btford.modal` as a module dependency to your app.
## Examples
[Plunker demo](http://plnkr.co/edit/lJDNqafSCKdpMI8AjR0B?p=preview)
### Typical Use
> app.js
```javascript
angular.module('myApp', ['btford.modal']).
// let's make a modal called `myModal`
factory('myModal', function (btfModal) {
return btfModal({
controller: 'MyModalCtrl',
controllerAs: 'modal',
templateUrl: 'my-modal.html'
});
}).
// typically you'll inject the modal service into its own
// controller so that the modal can close itself
controller('MyModalCtrl', function (myModal) {
this.closeMe = myModal.deactivate;
}).
controller('MyCtrl', function (myModal) {
this.showModal = myModal.activate;
});
```
> my-modal.html
```html
<div class="btf-modal">
<h3>Hello {{name}}</h3>
<p><a href ng-click="modal.closeMe()">Close Me</a></p>
</div>
```
> index.html
```html
<div ng-app="myApp" ng-controller="MyCtrl as ctrl">
<a href ng-click="ctrl.showModal()">Show the modal</a>
</div>
```
### Cleaning up
If you add any listeners within the modal's controller that are **outside the modal's `scope`**,
you should remove them with `$scope.$on('$destroy', fn () { ... })` to avoid creating a memory leak.
Building on the example above:
> app.js
```javascript
// ...
controller('MyModalCtrl', function (myModal, $timeout) {
var ctrl = this,
timeoutId;
ctrl.tickCount = 5;
ctrl.closeMe = function () {
cancelTick();
myModal.deactivate();
};
function tick() {
timeoutId = $timeout(function() {
ctrl.tickCount -= 1;
if (ctrl.tickCount <= 0) {
ctrl.closeMe();
} else {
tick();
}
}, 1000);
}
function cancelTick() {
$timeout.cancel(timeoutId);
}
$scope.$on('$destroy', cancelTick);
tick();
}).
// ...
```
### Inline Options
**Note:** The best practice is to use a separate file for the template and a separate declaration for
the controller, but inlining these options might be more pragmatic for cases where the template or
controller is just a couple lines.
```javascript
angular.module('myApp', []).
// let's make a modal called myModal
factory('myModal', function (btfModal) {
return btfModal({
controller: function () {
this.name = 'World';
},
controllerAs: 'ctrl',
template: '<div class="btf-modal">Hello {{ctrl.name}}</div>'
});
}).
controller('MyCtrl', function (myModal) {
this.showModal = myModal.activate;
});
```
```html
<div ng-app="myApp" ng-controller="MyCtrl">
<a href ng-click="ctrl.showModal()">Show the modal</a>
</div>
```
## API
### `btfModal`
The modal `factory`. Takes a configuration object as a parameter:
```javascript
var modalService = btfModal({
/* options */
})
```
And returns a `modalService` object that you can use to show/hide the modal (described below).
The config object **must** either have a `template` or a `templateUrl` option.
These options work just like the [route configuration in Angular's
`$routeProvider`](http://docs.angularjs.org/api/ngRoute.$routeProvider#methods_when).
#### `config.template`
**string:** HTML string of the template to be used for this modal.
Unless the template is very simple, you should probably use `config.templateUrl` instead.
#### `config.templateUrl`
**string (recommended):** URL to the HTML template to be used for this modal.
#### `config.controller`
**string|function (optional):** The name of a controller or a controller function.
#### `config.controllerAs`
**string (optional, recommended):** Makes the controller available on the scope of the modal as the given name.
#### `config.container`
**DOM Node (optional):** DOM node to prepend . Defaults to `document.body`.
### `modalService`
A `modalService` has just two methods: `activate` and `deactivate`.
#### `modalService.activate`
Takes a hash of objects to add to the scope of the modal as locals.
Adds the modal to the DOM by prepending it to the `<body>`.
Returns a promise that resolves once the modal is active.
#### `modalService.deactivate`
Removes the modal (DOM and scope) from the DOM.
Returns a promise that resolves once the modal is removed.
#### `modalService.active`
Returns whether or not the modal is currently activated.
## Tests
You can run the tests with [`karma`](http://karma-runner.github.io/0.10/index.html):
```shell
karma start karma.conf.js
```
## License
MIT

19
public/vendor/angular-modal/bower.json vendored Normal file
View file

@ -0,0 +1,19 @@
{
"name": "angular-modal",
"version": "0.4.0",
"main": "modal.js",
"ignore": [
"**/.*",
"node_modules",
"components",
"bower_components",
"test",
"tests"
],
"dependencies": {
"angular": "~1.2.13"
},
"devDependencies": {
"angular-mocks": "~1.2.13"
}
}

20
public/vendor/angular-modal/gulpfile.js vendored Normal file
View file

@ -0,0 +1,20 @@
var gulp = require('gulp'),
gutil = require('gulp-util'),
uglify = require('gulp-uglify'),
rename = require("gulp-rename"),
ngmin = require('gulp-ngmin');
gulp.task('scripts', function() {
return gulp.src('modal.js').
pipe(rename('modal.min.js')).
pipe(ngmin()).
pipe(uglify({
preserveComments: 'some',
outSourceMap: true
})).
pipe(gulp.dest('.'));
});
gulp.task('default', function() {
gulp.start('scripts');
});

View file

@ -0,0 +1,30 @@
module.exports = function(config){
config.set({
basePath : './',
files : [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'modal.js',
'modal.spec.js'
],
autoWatch : true,
frameworks: ['jasmine'],
browsers : ['Chrome'],
plugins : [
'karma-junit-reporter',
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-jasmine'
],
junitReporter : {
outputFile: 'test_out/unit.xml',
suite: 'unit'
}
})}

20
public/vendor/angular-modal/modal.css vendored Normal file
View file

@ -0,0 +1,20 @@
/*
* angular-modal v0.1.0
* (c) 2013 Brian Ford http://briantford.com
* License: MIT
*/
.btf-modal {
position: fixed;
top: 50%;
left: 50%;
width: 50%;
max-width: 550px;
min-width: 330px;
height: auto;
z-index: 2000;
-webkit-transform: translateX(-50%) translateY(-50%);
-moz-transform: translateX(-50%) translateY(-50%);
-ms-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
}

89
public/vendor/angular-modal/modal.js vendored Normal file
View file

@ -0,0 +1,89 @@
/*
* @license
* angular-modal v0.4.0
* (c) 2013 Brian Ford http://briantford.com
* License: MIT
*/
'use strict';
angular.module('btford.modal', []).
factory('btfModal', function ($animate, $compile, $rootScope, $controller, $q, $http, $templateCache) {
return function modalFactory (config) {
if (!(!config.template ^ !config.templateUrl)) {
throw new Error('Expected modal to have exacly one of either `template` or `templateUrl`');
}
var template = config.template,
controller = config.controller || angular.noop,
controllerAs = config.controllerAs,
container = angular.element(config.container || document.body),
element = null,
html,
scope;
if (config.template) {
var deferred = $q.defer();
deferred.resolve(config.template);
html = deferred.promise;
} else {
html = $http.get(config.templateUrl, {
cache: $templateCache
}).
then(function (response) {
return response.data;
});
}
function activate (locals) {
return html.then(function (html) {
if (!element) {
attach(html, locals);
}
});
}
function attach (html, locals) {
element = angular.element(html);
if (element.length === 0) {
throw new Error('The template contains no elements; you need to wrap text nodes')
}
$animate.enter(element, container);
scope = $rootScope.$new();
if (locals) {
for (var prop in locals) {
scope[prop] = locals[prop];
}
}
var ctrl = $controller(controller, { $scope: scope });
if (controllerAs) {
scope[controllerAs] = ctrl;
}
$compile(element)(scope);
}
function deactivate () {
var deferred = $q.defer();
if (element) {
$animate.leave(element, function () {
scope.$destroy();
element = null;
deferred.resolve();
});
} else {
deferred.resolve();
}
return deferred.promise;
}
function active () {
return !!element;
}
return {
activate: activate,
deactivate: deactivate,
active: active
};
};
});

View file

@ -0,0 +1,7 @@
/*
* @license
* angular-modal v0.4.0
* (c) 2013 Brian Ford http://briantford.com
* License: MIT
*/
"use strict";angular.module("btford.modal",[]).factory("btfModal",["$animate","$compile","$rootScope","$controller","$q","$http","$templateCache",function(e,t,r,n,o,a,l){return function(c){function i(e){return p.then(function(t){$||u(t,e)})}function u(o,a){if($=angular.element(o),0===$.length)throw new Error("The template contains no elements; you need to wrap text nodes");if(e.enter($,h),d=r.$new(),a)for(var l in a)d[l]=a[l];var c=n(s,{$scope:d});v&&(d[v]=c),t($)(d)}function m(){var t=o.defer();return $?e.leave($,function(){d.$destroy(),$=null,t.resolve()}):t.resolve(),t.promise}function f(){return!!$}if(!(!c.template^!c.templateUrl))throw new Error("Expected modal to have exacly one of either `template` or `templateUrl`");var p,d,s=(c.template,c.controller||angular.noop),v=c.controllerAs,h=angular.element(c.container||document.body),$=null;if(c.template){var g=o.defer();g.resolve(c.template),p=g.promise}else p=a.get(c.templateUrl,{cache:l}).then(function(e){return e.data});return{activate:i,deactivate:m,active:f}}}]);

View file

@ -0,0 +1 @@
{"version":3,"file":"modal.min.js.map","sources":["modal.min.js"],"names":["angular","module","factory","$animate","$compile","$rootScope","$controller","$q","$http","$templateCache","config","activate","locals","html","then","element","attach","length","Error","enter","container","scope","$new","prop","ctrl","controller","$scope","controllerAs","deactivate","deferred","defer","leave","$destroy","resolve","promise","active","template","templateUrl","noop","document","body","get","cache","response","data"],"mappings":";;;;;;AAMA,YACAA,SAAQC,OAAO,mBAAoBC,QAAQ,YACzC,WACA,WACA,aACA,cACA,KACA,QACA,iBACA,SAAUC,EAAUC,EAAUC,EAAYC,EAAaC,EAAIC,EAAOC,GAChE,MAAO,UAAsBC,GAc3B,QAASC,GAASC,GAChB,MAAOC,GAAKC,KAAK,SAAUD,GACpBE,GACHC,EAAOH,EAAMD,KAInB,QAASI,GAAOH,EAAMD,GAEpB,GADAG,EAAUf,QAAQe,QAAQF,GACH,IAAnBE,EAAQE,OACV,KAAM,IAAIC,OAAM,iEAIlB,IAFAf,EAASgB,MAAMJ,EAASK,GACxBC,EAAQhB,EAAWiB,OACfV,EACF,IAAK,GAAIW,KAAQX,GACfS,EAAME,GAAQX,EAAOW,EAGzB,IAAIC,GAAOlB,EAAYmB,GAAcC,OAAQL,GACzCM,KACFN,EAAMM,GAAgBH,GAExBpB,EAASW,GAASM,GAEpB,QAASO,KACP,GAAIC,GAAWtB,EAAGuB,OAUlB,OATIf,GACFZ,EAAS4B,MAAMhB,EAAS,WACtBM,EAAMW,WACNjB,EAAU,KACVc,EAASI,YAGXJ,EAASI,UAEJJ,EAASK,QAElB,QAASC,KACP,QAASpB,EApDX,MAAOL,EAAO0B,UAAY1B,EAAO2B,aAC/B,KAAM,IAAInB,OAAM,0EAElB,IAAoML,GAAMQ,EAA1KI,GAAjBf,EAAO0B,SAAuB1B,EAAOe,YAAczB,QAAQsC,MAAMX,EAAejB,EAAOiB,aAAcP,EAAYpB,QAAQe,QAAQL,EAAOU,WAAamB,SAASC,MAAOzB,EAAU,IAC9L,IAAIL,EAAO0B,SAAU,CACnB,GAAIP,GAAWtB,EAAGuB,OAClBD,GAASI,QAAQvB,EAAO0B,UACxBvB,EAAOgB,EAASK,YAEhBrB,GAAOL,EAAMiC,IAAI/B,EAAO2B,aAAeK,MAAOjC,IAAkBK,KAAK,SAAU6B,GAC7E,MAAOA,GAASC,MA4CpB,QACEjC,SAAUA,EACViB,WAAYA,EACZO,OAAQA"}

View file

@ -0,0 +1,286 @@
'use strict';
describe('btfModal', function() {
var container,
btfModal,
$rootScope;
beforeEach(module('btford.modal'));
beforeEach(function () {
container = angular.element('<div></div>');
});
afterEach(function() {
container = null;
});
describe('without animations', function () {
beforeEach(inject(function(_btfModal_, _$rootScope_, $templateCache) {
btfModal = _btfModal_;
$rootScope = _$rootScope_;
$rootScope.greeting = 'こんばんは';
$templateCache.put('test.html', [200, '<div>{{greeting}}</div>', {}]);
}));
it('should not show a modal initially', function() {
var modal = btfModal({
templateUrl: 'test.html',
container: container
});
$rootScope.$digest();
expect(container.text()).toBe('');
});
it('should throw if called without a `template` or `templateUrl` option', function() {
expect(function () { btfModal({}); }).toThrow();
});
it('should throw if called with a text node', function() {
var modal = btfModal({
template: 'hey'
});
expect(function () {
modal.activate();
$rootScope.$digest();
}).toThrow();
});
it('should throw if called with both `template` and `templateUrl` options', function() {
expect(function () {
btfModal({
template: 'foo',
templateUrl: 'foo.html'
});
}).toThrow();
});
describe('#activate', function () {
it('should show a modal when activated with `templateUrl`', function() {
var modal = btfModal({
templateUrl: 'test.html',
container: container
});
modal.activate();
$rootScope.$digest();
expect(container.text()).toBe('こんばんは');
});
it('should show a modal when activated with `template`', function() {
var modal = btfModal({
template: '<span>{{greeting}}</span>',
container: container
});
modal.activate();
$rootScope.$digest();
expect(container.text()).toBe('こんばんは');
});
it('should instantiate a controller via the `controller` option', function() {
var modal = btfModal({
template: '<span>{{greeting}}</span>',
controller: function ($scope) {
$scope.greeting = 'goodnight'
},
container: container
});
modal.activate();
$rootScope.$digest();
expect(container.text()).toBe('goodnight');
});
it('should expose a controller to the scope via the `controllerAs` option', function() {
var modal = btfModal({
template: '<span>{{ctrl.greeting}}</span>',
controller: function () {
this.greeting = 'boa noite'
},
controllerAs: 'ctrl',
container: container
});
modal.activate();
$rootScope.$digest();
expect(container.text()).toBe('boa noite');
});
it('should pass locals to the modal scope', function() {
var modal = btfModal({
template: '<span>{{greeting}}</span>',
container: container
});
modal.activate({
greeting: 'bon soir'
});
$rootScope.$digest();
expect(container.text()).toBe('bon soir');
});
it('should not activate multiple times', function() {
var modal = btfModal({
template: '<span>x</span>',
container: container
});
modal.activate();
$rootScope.$digest();
modal.activate();
$rootScope.$digest();
expect(container.text()).toBe('x');
});
it('should resolve a promise after activating', function() {
var spy = jasmine.createSpy('activated');
var modal = btfModal({
template: '<span>x</span>',
container: container
});
modal.activate().then(spy);
expect(spy).not.toHaveBeenCalled();
$rootScope.$digest();
expect(spy).toHaveBeenCalled();
});
});
describe('#deactivate', function () {
it('should remove a modal when deactivated', function() {
var modal = btfModal({
template: '<span>{{greeting}}</span>',
container: container
});
modal.activate();
$rootScope.$digest();
modal.deactivate();
$rootScope.$digest();
expect(container.text()).toBe('');
});
it('should destroy the scope when deactivated', inject(function($$asyncCallback) {
var destroySpy = jasmine.createSpy('onDestroy');
var modal = btfModal({
template: '<span>{{greeting}}</span>',
container: container,
controller: function ($scope) {
$scope.$on('$destroy', destroySpy);
}
});
modal.activate();
$rootScope.$digest();
expect(destroySpy).not.toHaveBeenCalled();
modal.deactivate();
$rootScope.$digest();
$$asyncCallback.flush();
expect(destroySpy).toHaveBeenCalled();
}));
it('should resolve a promise after deactivating', inject(function($$asyncCallback) {
var spy = jasmine.createSpy('deactivated');
var modal = btfModal({
template: '<span>x</span>',
container: container
});
modal.activate();
$rootScope.$digest();
modal.deactivate().then(spy);
expect(spy).not.toHaveBeenCalled();
$$asyncCallback.flush();
$rootScope.$digest();
expect(spy).toHaveBeenCalled();
}));
});
describe('#active', function () {
it('should return the state of the modal', inject(function($$asyncCallback) {
var modal = btfModal({
template: '<span>{{greeting}}</span>',
container: container
});
$rootScope.$digest();
expect(modal.active()).toBe(false);
modal.activate();
$rootScope.$digest();
expect(modal.active()).toBe(true);
modal.deactivate();
$rootScope.$digest();
$$asyncCallback.flush();
expect(modal.active()).toBe(false);
}));
});
});
describe('with animations', function () {
var $animate,
modal;
beforeEach(module('ngAnimateMock'));
beforeEach(inject(function(btfModal, _$rootScope_, _$animate_) {
$rootScope = _$rootScope_;
$animate = _$animate_;
modal = btfModal({
template: '<span>animations!</span>',
container: container
});
}));
it('should trigger an enter animation when activated', function () {
modal.activate();
$rootScope.$digest();
var item = $animate.queue.shift();
expect(item.event).toBe('enter');
});
it('should trigger a leave animation when deactivated', function () {
modal.activate();
$rootScope.$digest();
$animate.queue.shift();
modal.deactivate();
$rootScope.$digest();
var item = $animate.queue.shift();
expect(item.event).toBe('leave');
});
});
});

View file

@ -0,0 +1,33 @@
{
"name": "angular-modal",
"version": "0.4.0",
"description": "easily add a modal to your angular app",
"main": "modal.js",
"scripts": {
"test": "./node_modules/.bin/bower install && ./node_modules/.bin/karma start karma.conf.js --browsers Firefox --single-run"
},
"repository": {
"type": "git",
"url": "git://github.com/btford/angular-modal.git"
},
"keywords": [
"angular",
"angularjs",
"modal"
],
"author": "Brian Ford",
"license": "MIT",
"bugs": {
"url": "https://github.com/btford/angular-modal/issues"
},
"devDependencies": {
"karma": "~0.10",
"karma-junit-reporter": "~0.1.0",
"bower": "~1.2.7",
"gulp": "~3.5.5",
"gulp-util": "~2.2.14",
"gulp-uglify": "~0.2.1",
"gulp-rename": "~1.2.0",
"gulp-ngmin": "~0.1.2"
}
}

View file

@ -9,6 +9,7 @@
<script type="text/javascript" src="/vendor/angular-resource/angular-resource.min.js"></script>
<script type="text/javascript" src="/vendor/angular-ui-router/release/angular-ui-router.min.js"></script>
<script type="text/javascript" src="/vendor/ngFx/dist/ngFx.min.js"></script>
<script type="text/javascript" src="/vendor/angular-modal/modal.min.js"></script>
<script type="text/javascript" src="/build/app.js"></script>
</head>
<body>