Skip to content
This repository has been archived by the owner on Aug 29, 2023. It is now read-only.

Commit

Permalink
fix(dialog, backdrop): fill-stretch backdrop to scrolled viewport and…
Browse files Browse the repository at this point in the history
… center dialog

For scrolled containers and non-body parents,
- the backdrop will now stretch to fill the viewport
- the dialog container resizes to fill the viewPort
- the dialog properly centers within the dialog container

BREAKING CHANGES: md-dialog-container hides overrflow, menu/select click catchers are now positioned absolute.

Previous:

```css
md-backdrop.md-click-catcher {
  position:fixed;
}

.md-dialog-container {
  overflow: auto;
}
```

Updated:

```css
md-backdrop.md-click-catcher {
  position:absolute;
}

.md-dialog-container {
  overflow: hidden;
}
```

Closes #3894.
  • Loading branch information
ThomasBurleson committed Jul 27, 2015
1 parent d270684 commit b71fdfb
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 27 deletions.
22 changes: 17 additions & 5 deletions src/components/backdrop/backdrop.js
Expand Up @@ -19,7 +19,7 @@

angular
.module('material.components.backdrop', ['material.core'])
.directive('mdBackdrop', function BackdropDirective($mdTheming, $animate, $rootElement, $window, $log, $$rAF) {
.directive('mdBackdrop', function BackdropDirective($mdTheming, $animate, $rootElement, $window, $log, $$rAF, $document) {
var ERROR_CSS_POSITION = "<md-backdrop> may not work properly in a scrolled, static-positioned parent container.";

return {
Expand All @@ -28,17 +28,28 @@ angular
};

function postLink(scope, element, attrs) {

// If body scrolling has been disabled using mdUtil.disableBodyScroll(),
// adjust the 'backdrop' height to account for the fixed 'body' top offset
var body = $window.getComputedStyle($document[0].body);
if ( body.position == 'fixed') {
var hViewport = parseInt(body.height,10) + Math.abs(parseInt(body.top,10));
element.css({
height : hViewport + 'px'
});
}

// backdrop may be outside the $rootElement, tell ngAnimate to animate regardless
if( $animate.pin ) $animate.pin(element,$rootElement);

$$rAF(function(){

// Often $animate.enter() is used to append the backDrop element
// so let's wait until $animate is done...

var parent = element.parent()[0];
if ( parent ) {
var position = $window.getComputedStyle(parent).getPropertyValue('position');
if (position == 'static') {
var styles = $window.getComputedStyle(parent);
if (styles.position == 'static') {
// backdrop uses position:absolute and will not work properly with parent position:static (default)
$log.warn( ERROR_CSS_POSITION );
}
Expand All @@ -47,5 +58,6 @@ angular
$mdTheming.inherit(element, element.parent());
});

};
}

});
2 changes: 1 addition & 1 deletion src/components/backdrop/backdrop.scss
Expand Up @@ -30,7 +30,7 @@ md-backdrop {
right: 0;

&.md-click-catcher {
position: fixed;
position: absolute;
}

&.md-opaque.ng-leave {
Expand Down
50 changes: 35 additions & 15 deletions src/components/dialog/dialog.js
Expand Up @@ -430,7 +430,7 @@ function MdDialogProvider($$interimElementProvider) {
}

/* @ngInject */
function dialogDefaultOptions($mdDialog, $mdAria, $mdUtil, $mdConstant, $animate, $document) {
function dialogDefaultOptions($mdDialog, $mdAria, $mdUtil, $mdConstant, $animate, $document, $window, $rootElement) {
return {
hasBackdrop: true,
isolateScope: true,
Expand Down Expand Up @@ -464,6 +464,10 @@ function MdDialogProvider($$interimElementProvider) {
focusOnOpen();
});

/**
* For alerts, focus on content... otherwise focus on
* the close button (or equivalent)
*/
function focusOnOpen() {
if (options.focusOnOpen) {
var target = (options.$type === 'alert') ? element.find('md-dialog-content') : findCloseButton();
Expand Down Expand Up @@ -502,6 +506,11 @@ function MdDialogProvider($$interimElementProvider) {
});
}

/**
* Capture originator/trigger element information (if available)
* and the parent container for the dialog; defaults to the $rootElement
* unless overridden in the options.parent
*/
function captureSourceAndParent(element, options) {
var origin = { element: null, bounds: null, focus: angular.noop };
options.origin = angular.extend({ }, origin, options.origin || {} );
Expand All @@ -519,7 +528,7 @@ function MdDialogProvider($$interimElementProvider) {
}

// In case the user provides a raw dom element, always wrap it in jqLite
options.parent = angular.element(options.parent);
options.parent = angular.element(options.parent || $rootElement);

if (options.disableParentScroll) {
options.restoreScroll = $mdUtil.disableScrollAround(element,options.parent);
Expand Down Expand Up @@ -597,16 +606,7 @@ function MdDialogProvider($$interimElementProvider) {
function showBackdrop(scope, element, options) {

if (options.hasBackdrop) {
// Fix for IE 10
var docElement = $document[0].documentElement;
var hasScrollTop = (options.parent[0] == $document[0].body) && (docElement && docElement.scrollTop);
var computeFrom = hasScrollTop ? angular.element(docElement) : options.parent;
var parentOffset = computeFrom.prop('scrollTop');

element.css('top', parentOffset + 'px');

options.backdrop = $mdUtil.createBackdrop(scope, "md-dialog-backdrop md-opaque");

$animate.enter(options.backdrop, options.parent);
}

Expand Down Expand Up @@ -701,19 +701,39 @@ function MdDialogProvider($$interimElementProvider) {
}
}

/**
* Ensure the dialog container fill-stretches to the viewport
*/
function adjustDialogContainer(container, options) {

var isFixed = $window.getComputedStyle($document[0].body).position == 'fixed';
var backdrop = options.backdrop ? $window.getComputedStyle(options.backdrop[0]) : null;
var height = backdrop ? Math.ceil(Math.abs(parseInt(backdrop.height,10))) : 0;

container.css({
top: (isFixed ? $mdUtil.scrollTop(options.parent)/2 : 0) + 'px',
height: height ? height +'px' : '100%'
});

return container;
}

/**
* Dialog open and pop-in animation
*/
function dialogPopIn(container, options ) {
options.parent.append(container);

// Add the `md-dialog-container` to the DOM
options.parent.append( container );
adjustDialogContainer(container,options);

var dialogEl = container.find('md-dialog');
var animator = $mdUtil.dom.animator ;
var buildTranslateToOrigin = animator.calculateZoomToOrigin;
var translateOptions = { transitionInClass :'md-transition-in' , transitionOutClass : 'md-transition-out' };

var dialogEl = container.find('md-dialog');
var from = animator.toTransformCss( buildTranslateToOrigin(dialogEl, options.origin) );
var to = animator.toTransformCss(""); // defaults to center display (or parent or $rootElement)
var to = animator.toTransformCss( "" ); // defaults to center display (or parent or $rootElement)


return animator
.translate3d(dialogEl,from,to,translateOptions)
Expand Down
1 change: 1 addition & 0 deletions src/components/dialog/dialog.scss
Expand Up @@ -13,6 +13,7 @@ $dialog-padding: $baseline-grid * 3;
width: 100%;
height: 100%;
z-index: $z-index-dialog;
overflow: hidden;
}

md-dialog {
Expand Down
12 changes: 7 additions & 5 deletions src/core/services/interimElement/interimElement.js
Expand Up @@ -491,15 +491,17 @@ function InterimElementProvider() {
* Search for parent at insertion time, if not specified
*/
function findParent(element, options) {
var parent = options.parent;

// Search for parent at insertion time, if not specified
if (angular.isFunction(parent)) {
parent = parent(options.scope, element, options);
} else if (angular.isString(parent)) {
parent = angular.element($document[0].querySelector(parent));
if (angular.isFunction(options.parent)) {
parent = options.parent(options.scope, element, options);
} else if (angular.isString(options.parent)) {
parent = angular.element($document[0].querySelector(options.parent));
} else {
parent = angular.element(options.parent);
}


// If parent querySelector/getter function fails, or it's just null,
// find a default.
if (!(parent || {}).length) {
Expand Down
15 changes: 14 additions & 1 deletion src/core/util/util.js
Expand Up @@ -46,6 +46,19 @@ angular.module('material.core')
return results;
},

/**
* Calculate the positive scroll offset
*/
scrollTop : function(element) {
element = angular.element(element || $document[0].body);

var body = (element[0] == $document[0].body) ? $document[0].body : undefined;
var scrollTop = body ? body.scrollTop + body.parentElement.scrollTop : 0;

// Calculate the positive scroll offset
return scrollTop || Math.abs(element[0].getBoundingClientRect().top);
},

// Disables scroll around the passed element.
disableScrollAround: function (element, parent) {
$mdUtil.disableScrollAround._count = $mdUtil.disableScrollAround._count || 0;
Expand Down Expand Up @@ -109,7 +122,7 @@ angular.module('material.core')
var htmlNode = body.parentNode;
var restoreHtmlStyle = htmlNode.getAttribute('style') || '';
var restoreBodyStyle = body.getAttribute('style') || '';
var scrollOffset = body.scrollTop + body.parentElement.scrollTop;
var scrollOffset = $mdUtil.scrollTop(body);
var clientWidth = body.clientWidth;

if (body.scrollHeight > body.clientHeight) {
Expand Down

0 comments on commit b71fdfb

Please sign in to comment.