Created
February 21, 2013 21:44
-
-
Save ajoslin/5008546 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The `$dialogProvider` can be used to configure global defaults for your | |
// `$dialog` service. | |
var dialogModule = angular.module('ui.bootstrap.dialog', ['ui.bootstrap.transition']); | |
dialogModule.controller('MessageBoxController', ['$scope', 'dialog', 'model', function($scope, dialog, model){ | |
$scope.title = model.title; | |
$scope.message = model.message; | |
$scope.buttons = model.buttons; | |
$scope.close = function(res){ | |
dialog.close(res); | |
}; | |
}]); | |
dialogModule.provider("$dialog", function(){ | |
// The default options for all dialogs. | |
var defaults = { | |
bodyElement: null, //Pass in an element to override this | |
backdrop: true, | |
dialogClass: 'modal', | |
backdropClass: 'modal-backdrop', | |
transitionClass: 'fade', | |
triggerClass: 'in', | |
dialogOpenClass: 'modal-open', | |
resolve:{}, | |
backdropFade: false, | |
dialogFade:false, | |
keyboard: true, // close with esc key | |
backdropClick: true // only in conjunction with backdrop=true | |
/* other options: template, templateUrl, controller */ | |
}; | |
var globalOptions = {}; | |
var activeBackdrops = {value : 0}; | |
// The `options({})` allows global configuration of all dialogs in the application. | |
// | |
// var app = angular.module('App', ['ui.bootstrap.dialog'], function($dialogProvider){ | |
// // don't close dialog when backdrop is clicked by default | |
// $dialogProvider.options({backdropClick: false}); | |
// }); | |
this.options = function(value){ | |
globalOptions = value; | |
}; | |
// Returns the actual `$dialog` service that is injected in controllers | |
this.$get = ["$http", "$document", "$compile", "$rootScope", "$controller", "$templateCache", "$q", "$transition", "$injector", | |
function ($http, $document, $compile, $rootScope, $controller, $templateCache, $q, $transition, $injector) { | |
function createElement(clazz) { | |
var el = angular.element("<div>"); | |
el.addClass(clazz); | |
return el; | |
} | |
// The `Dialog` class represents a modal dialog. The dialog class can be invoked by providing an options object | |
// containing at lest template or templateUrl and controller: | |
// | |
// var d = new Dialog({templateUrl: 'foo.html', controller: 'BarController'}); | |
// | |
// Dialogs can also be created using templateUrl and controller as distinct arguments: | |
// | |
// var d = new Dialog('path/to/dialog.html', MyDialogController); | |
function Dialog(opts) { | |
var self = this, options = this.options = angular.extend({}, defaults, globalOptions, opts); | |
var body = options.bodyElement || $document.find('body'); | |
this.backdropEl = createElement(options.backdropClass); | |
if(options.backdropFade){ | |
this.backdropEl.addClass(options.transitionClass); | |
this.backdropEl.removeClass(options.triggerClass); | |
} | |
this.modalEl = createElement(options.dialogClass); | |
if(options.dialogFade){ | |
this.modalEl.addClass(options.transitionClass); | |
this.modalEl.removeClass(options.triggerClass); | |
} | |
this.handledEscapeKey = function(e) { | |
if (e.which === 27) { | |
self.close(); | |
e.preventDefault(); | |
self.$scope.$apply(); | |
} | |
}; | |
this.handleBackDropClick = function(e) { | |
self.close(); | |
e.preventDefault(); | |
self.$scope.$apply(); | |
}; | |
} | |
// The `isOpen()` method returns wether the dialog is currently visible. | |
Dialog.prototype.isOpen = function(){ | |
return this._open; | |
}; | |
// The `open(templateUrl, controller)` method opens the dialog. | |
// Use the `templateUrl` and `controller` arguments if specifying them at dialog creation time is not desired. | |
Dialog.prototype.open = function(templateUrl, controller){ | |
var self = this, options = this.options; | |
if(templateUrl){ | |
options.templateUrl = templateUrl; | |
} | |
if(controller){ | |
options.controller = controller; | |
} | |
if(!(options.template || options.templateUrl)) { | |
throw new Error('Dialog.open expected template or templateUrl, neither found. Use options or open method to specify them.'); | |
} | |
this._loadResolves().then(function(locals) { | |
var $scope = locals.$scope = self.$scope = locals.$scope ? locals.$scope : $rootScope.$new(); | |
self.modalEl.html(locals.$template); | |
if (self.options.controller) { | |
var ctrl = $controller(self.options.controller, locals); | |
self.modalEl.contents().data('ngControllerController', ctrl); | |
} | |
$compile(self.modalEl)($scope); | |
self._addElementsToDom(); | |
body.addClass(self.options.dialogOpenClass); | |
// trigger tranisitions | |
setTimeout(function(){ | |
if(self.options.dialogFade){ self.modalEl.addClass(self.options.triggerClass); } | |
if(self.options.backdropFade){ self.backdropEl.addClass(self.options.triggerClass); } | |
}); | |
self._bindEvents(); | |
}); | |
this.deferred = $q.defer(); | |
return this.deferred.promise; | |
}; | |
// closes the dialog and resolves the promise returned by the `open` method with the specified result. | |
Dialog.prototype.close = function(result){ | |
var self = this; | |
var fadingElements = this._getFadingElements(); | |
body.removeClass(self.options.dialogOpenClass); | |
if(fadingElements.length > 0){ | |
for (var i = fadingElements.length - 1; i >= 0; i--) { | |
$transition(fadingElements[i], removeTriggerClass).then(onCloseComplete); | |
} | |
return; | |
} | |
this._onCloseComplete(result); | |
function removeTriggerClass(el){ | |
el.removeClass(self.options.triggerClass); | |
} | |
function onCloseComplete(){ | |
if(self._open){ | |
self._onCloseComplete(result); | |
} | |
} | |
}; | |
Dialog.prototype._getFadingElements = function(){ | |
var elements = []; | |
if(this.options.dialogFade){ | |
elements.push(this.modalEl); | |
} | |
if(this.options.backdropFade){ | |
elements.push(this.backdropEl); | |
} | |
return elements; | |
}; | |
Dialog.prototype._bindEvents = function() { | |
if(this.options.keyboard){ body.bind('keydown', this.handledEscapeKey); } | |
if(this.options.backdrop && this.options.backdropClick){ this.backdropEl.bind('click', this.handleBackDropClick); } | |
}; | |
Dialog.prototype._unbindEvents = function() { | |
if(this.options.keyboard){ body.unbind('keydown', this.handledEscapeKey); } | |
if(this.options.backdrop && this.options.backdropClick){ this.backdropEl.unbind('click', this.handleBackDropClick); } | |
}; | |
Dialog.prototype._onCloseComplete = function(result) { | |
this._removeElementsFromDom(); | |
this._unbindEvents(); | |
this.deferred.resolve(result); | |
}; | |
Dialog.prototype._addElementsToDom = function(){ | |
body.append(this.modalEl); | |
if(this.options.backdrop) { | |
if (activeBackdrops.value === 0) { | |
body.append(this.backdropEl); | |
} | |
activeBackdrops.value++; | |
} | |
this._open = true; | |
}; | |
Dialog.prototype._removeElementsFromDom = function(){ | |
this.modalEl.remove(); | |
if(this.options.backdrop) { | |
activeBackdrops.value--; | |
if (activeBackdrops.value === 0) { | |
this.backdropEl.remove(); | |
} | |
} | |
this._open = false; | |
}; | |
// Loads all `options.resolve` members to be used as locals for the controller associated with the dialog. | |
Dialog.prototype._loadResolves = function(){ | |
var values = [], keys = [], templatePromise, self = this; | |
if (this.options.template) { | |
templatePromise = $q.when(this.options.template); | |
} else if (this.options.templateUrl) { | |
templatePromise = $http.get(this.options.templateUrl, {cache:$templateCache}) | |
.then(function(response) { return response.data; }); | |
} | |
angular.forEach(this.options.resolve || [], function(value, key) { | |
keys.push(key); | |
values.push(angular.isString(value) ? $injector.get(value) : $injector.invoke(value)); | |
}); | |
keys.push('$template'); | |
values.push(templatePromise); | |
return $q.all(values).then(function(values) { | |
var locals = {}; | |
angular.forEach(values, function(value, index) { | |
locals[keys[index]] = value; | |
}); | |
locals.dialog = self; | |
return locals; | |
}); | |
}; | |
// The actual `$dialog` service that is injected in controllers. | |
return { | |
// Creates a new `Dialog` with the specified options. | |
dialog: function(opts){ | |
return new Dialog(opts); | |
}, | |
// creates a new `Dialog` tied to the default message box template and controller. | |
// | |
// Arguments `title` and `message` are rendered in the modal header and body sections respectively. | |
// The `buttons` array holds an object with the following members for each button to include in the | |
// modal footer section: | |
// | |
// * `result`: the result to pass to the `close` method of the dialog when the button is clicked | |
// * `label`: the label of the button | |
// * `cssClass`: additional css class(es) to apply to the button for styling | |
messageBox: function(title, message, buttons){ | |
return new Dialog({templateUrl: 'template/dialog/message.html', controller: 'MessageBoxController', resolve: | |
{model: function() { | |
return { | |
title: title, | |
message: message, | |
buttons: buttons | |
}; | |
} | |
}}); | |
} | |
}; | |
}]; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment