Skip to content

Commit

Permalink
feat(modal): add option to disable animations
Browse files Browse the repository at this point in the history
Note: Move backdropClass logic into compile function because otherwise
modifying classes in the compile function is broken when using an interpolated
class attribute.

Fixes angular-ui#1007
Closes angular-ui#2725
  • Loading branch information
chrisirhc authored and fernando-sendMail committed Jul 16, 2015
1 parent f815cd9 commit e021a8b
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 72 deletions.
3 changes: 3 additions & 0 deletions src/modal/docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ Finally, a `modal.closing` event is broadcast to the modal scope before the moda
preventDefault on the event, then the modal will remain open. The $close and $dismiss methods return true if the
event was allowed. The event itself includes a parameter for the result/reason and a boolean parameter that indicates
whether the modal is being closed (true) or dismissed.

The `modalConfig` exposes the following global option for all modals/backdrops:

108 changes: 39 additions & 69 deletions src/modal/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ angular.module('ui.bootstrap.modal', [])
/**
* A helper directive for the $modal service. It creates a backdrop element.
*/
.directive('modalBackdrop', [
'$animate', '$modalStack',
function ($animate , $modalStack) {
.directive('modalBackdrop', ['$timeout', function ($timeout) {
return {
restrict: 'EA',
replace: true,
Expand All @@ -71,24 +69,21 @@ angular.module('ui.bootstrap.modal', [])
};

function linkFn(scope, element, attrs) {
if (attrs.modalInClass) {
$animate.addClass(element, attrs.modalInClass);
scope.animate = false;

scope.$on($modalStack.NOW_CLOSING_EVENT, function (e, setIsAsync) {
var done = setIsAsync();
$animate.removeClass(element, attrs.modalInClass).then(done);
});
}
//trigger CSS transitions
$timeout(function () {
scope.animate = true;
});
}
}])

.directive('modalWindow', [
'$modalStack', '$q', '$animate',
function ($modalStack , $q , $animate) {
.directive('modalWindow', ['$modalStack', '$q', function ($modalStack, $q) {
return {
restrict: 'EA',
scope: {
index: '@'
index: '@',
animate: '='
},
replace: true,
transclude: true,
Expand Down Expand Up @@ -124,14 +119,8 @@ angular.module('ui.bootstrap.modal', [])
});

modalRenderDeferObj.promise.then(function () {
if (attrs.modalInClass) {
$animate.addClass(element, attrs.modalInClass);

scope.$on($modalStack.NOW_CLOSING_EVENT, function (e, setIsAsync) {
var done = setIsAsync();
$animate.removeClass(element, attrs.modalInClass).then(done);
});
}
// trigger CSS transitions
scope.animate = true;

var inputsWithAutofocus = element[0].querySelectorAll('[autofocus]');
/**
Expand Down Expand Up @@ -180,21 +169,14 @@ angular.module('ui.bootstrap.modal', [])
};
})

.factory('$modalStack', [
'$animate', '$timeout', '$document', '$compile', '$rootScope',
'$q',
'$$stackedMap',
function ($animate , $timeout , $document , $compile , $rootScope ,
$q,
$$stackedMap) {
.factory('$modalStack', ['$animate', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap',
function ($animate, $timeout, $document, $compile, $rootScope, $$stackedMap) {

var OPENED_MODAL_CLASS = 'modal-open';

var backdropDomEl, backdropScope;
var openedWindows = $$stackedMap.createNew();
var $modalStack = {
NOW_CLOSING_EVENT: 'modal.stack.now-closing'
};
var $modalStack = {};

function backdropIndex() {
var topBackdropIndex = -1;
Expand All @@ -213,25 +195,19 @@ angular.module('ui.bootstrap.modal', [])
}
});

function removeModalWindow(modalInstance, elementToReceiveFocus) {
function removeModalWindow(modalInstance) {

var body = $document.find('body').eq(0);
var modalWindow = openedWindows.get(modalInstance).value;

//clean up the stack
openedWindows.remove(modalInstance);

//remove window DOM element
removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
checkRemoveBackdrop();
});

//move focus to specified element if available, or else to body
if (elementToReceiveFocus && elementToReceiveFocus.focus) {
elementToReceiveFocus.focus();
} else {
body.focus();
}
}

function checkRemoveBackdrop() {
Expand All @@ -247,24 +223,18 @@ angular.module('ui.bootstrap.modal', [])
}

function removeAfterAnimate(domEl, scope, done) {
var asyncDeferred;
var asyncPromise = null;
var setIsAsync = function () {
if (!asyncDeferred) {
asyncDeferred = $q.defer();
asyncPromise = asyncDeferred.promise;
}

return function asyncDone() {
asyncDeferred.resolve();
};
};
scope.$broadcast($modalStack.NOW_CLOSING_EVENT, setIsAsync);

// Note that it's intentional that asyncPromise might be null.
// That's when setIsAsync has not been called during the
// NOW_CLOSING_EVENT broadcast.
return $q.when(asyncPromise).then(afterAnimating);
// Closing animation
scope.animate = false;

if (domEl.attr('modal-animation') && $animate.enabled()) {
// transition out
domEl.one('$animate:close', function closeFn() {
$rootScope.$evalAsync(afterAnimating);
});
} else {
// Ensure this call is async
$timeout(afterAnimating);
}

function afterAnimating() {
if (afterAnimating.done) {
Expand Down Expand Up @@ -296,8 +266,6 @@ angular.module('ui.bootstrap.modal', [])

$modalStack.open = function (modalInstance, modal) {

var modalOpener = $document[0].activeElement;

openedWindows.add(modalInstance, {
deferred: modal.deferred,
renderDeferred: modal.renderDeferred,
Expand Down Expand Up @@ -335,7 +303,6 @@ angular.module('ui.bootstrap.modal', [])

var modalDomEl = $compile(angularDomEl)(modal.scope);
openedWindows.top().value.modalDomEl = modalDomEl;
openedWindows.top().value.modalOpener = modalOpener;
body.append(modalDomEl);
body.addClass(OPENED_MODAL_CLASS);
};
Expand All @@ -348,7 +315,7 @@ angular.module('ui.bootstrap.modal', [])
var modalWindow = openedWindows.get(modalInstance);
if (modalWindow && broadcastClosing(modalWindow, result, true)) {
modalWindow.value.deferred.resolve(result);
removeModalWindow(modalInstance, modalWindow.value.modalOpener);
removeModalWindow(modalInstance);
return true;
}
return !modalWindow;
Expand All @@ -358,7 +325,7 @@ angular.module('ui.bootstrap.modal', [])
var modalWindow = openedWindows.get(modalInstance);
if (modalWindow && broadcastClosing(modalWindow, reason, false)) {
modalWindow.value.deferred.reject(reason);
removeModalWindow(modalInstance, modalWindow.value.modalOpener);
removeModalWindow(modalInstance);
return true;
}
return !modalWindow;
Expand Down Expand Up @@ -390,17 +357,20 @@ angular.module('ui.bootstrap.modal', [])
var $modalProvider = {
options: {
animation: true,
backdrop: true, //can also be false or 'static'
backdrop: true, //can be also false or 'static'
keyboard: true
},
$get: ['$injector', '$rootScope', '$q', '$templateRequest', '$controller', '$modalStack',
function ($injector, $rootScope, $q, $templateRequest, $controller, $modalStack) {
$get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {

var $modal = {};

function getTemplatePromise(options) {
return options.template ? $q.when(options.template) :
$templateRequest(angular.isFunction(options.templateUrl) ? (options.templateUrl)() : options.templateUrl);
$http.get(angular.isFunction(options.templateUrl) ? (options.templateUrl)() : options.templateUrl,
{cache: $templateCache}).then(function (result) {
return result.data;
});
}

function getResolvePromises(resolves) {
Expand Down Expand Up @@ -488,8 +458,8 @@ angular.module('ui.bootstrap.modal', [])

templateAndResolvePromise.then(function () {
modalOpenedDeferred.resolve(true);
}, function (reason) {
modalOpenedDeferred.reject(reason);
}, function () {
modalOpenedDeferred.reject(false);
});

return modalInstance;
Expand Down
2 changes: 1 addition & 1 deletion template/modal/backdrop.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="modal-backdrop"
modal-animation-class="fade"
modal-in-class="in"
ng-class="{in: animate}"
ng-style="{'z-index': 1040 + (index && 1 || 0) + index*10}"
></div>
3 changes: 1 addition & 2 deletions template/modal/window.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<div modal-render="{{$isRendered}}" tabindex="-1" role="dialog" class="modal"
modal-animation-class="fade"
modal-in-class="in"
ng-style="{'z-index': 1050 + index*10, display: 'block'}" ng-click="close($event)">
ng-class="{in: animate}" ng-style="{'z-index': 1050 + index*10, display: 'block'}" ng-click="close($event)">
<div class="modal-dialog" ng-class="size ? 'modal-' + size : ''"><div class="modal-content" modal-transclude></div></div>
</div>

0 comments on commit e021a8b

Please sign in to comment.