Skip to content

Commit

Permalink
feat(sidenav): track sidenav vissibilty and enter / leave backdrop if…
Browse files Browse the repository at this point in the history
… needed.

- Revert scope value if sidenav is shown.
- Throttle Resize Events

Fixes angular#4595
  • Loading branch information
devversion committed Dec 28, 2015
1 parent 8ef798f commit b20bdf3
Showing 1 changed file with 55 additions and 8 deletions.
63 changes: 55 additions & 8 deletions src/components/sidenav/sidenav.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ function SidenavFocusDirective() {
* - `<md-sidenav md-is-locked-open="$mdMedia('min-width: 1000px')"></md-sidenav>`
* - `<md-sidenav md-is-locked-open="$mdMedia('sm')"></md-sidenav>` (locks open on small screens)
*/
function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate, $compile, $parse, $log, $q, $document) {
function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate, $compile, $parse, $log, $q, $document, $$rAF) {
return {
restrict: 'E',
scope: {
Expand All @@ -229,6 +229,9 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate,
var lastParentOverFlow;
var triggeringElement = null;
var promise = $q.when(true);
var skipSidenav = false;
var skipNextUpdate = false;
var $window = angular.element(window);

var isLockedOpenParsed = $parse(attr.mdIsLockedOpen);
var isLocked = function() {
Expand All @@ -244,22 +247,49 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate,

$mdTheming.inherit(backdrop, element);

var throttleResize = $$rAF.throttle(revalidateVisibility);
$window.on('resize', throttleResize);
revalidateVisibility();

element.on('$destroy', function() {
backdrop.remove();
sidenavCtrl.destroy();
$window.off('resize', throttleResize);
});

scope.$on('$destroy', function(){
$window.off('resize', throttleResize);
backdrop.remove()
});

scope.$watch(isLocked, updateIsLocked);
scope.$watch('isOpen', updateIsOpen);



// Publish special accessor for the Controller instance
sidenavCtrl.$toggleOpen = toggleOpen;

function revalidateVisibility() {
var lastValue = scope.isOpen;
if (isHidden(element, true, true) && scope.isOpen == true) scope.isOpen = false;

This comment has been minimized.

Copy link
@EladBezalel

EladBezalel Dec 31, 2015

brackets, scope.isOpen == true is the same as scope.isOpen and ternary operator

else if (!isHidden(element, true, true) && scope.isOpen == false) scope.isOpen = true;

if (lastValue != scope.isOpen) {
skipSidenav = true;
if (!scope.$$phase) scope.$apply();
skipSidenav = false;
}
}

function isHidden(element, compute, both) {

This comment has been minimized.

Copy link
@EladBezalel

EladBezalel Dec 31, 2015

why do you get compute if in all your uses you send true?
also, what is both? please document this function

if (!compute || both) {
if (element[0].offsetParent == null) return true;
if (!both) return false;
}
return window.getComputedStyle(element[0]).display === 'none';
}

/**
* Toggle the DOM classes to indicate `locked`
* @param isLocked
Expand All @@ -278,26 +308,43 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate,
* Toggle the SideNav view and attach/detach listeners
* @param isOpen
*/
function updateIsOpen(isOpen) {
function updateIsOpen(isOpen, oldValue) {
if (skipNextUpdate) {
skipNextUpdate = false;
return;
}

// Support deprecated md-sidenav-focus attribute as fallback
var focusEl = $mdUtil.findFocusTarget(element) || $mdUtil.findFocusTarget(element,'[md-sidenav-focus]') || element;
var parent = element.parent();

// little hack to check show abbility

This comment has been minimized.

Copy link
@EladBezalel

EladBezalel Dec 31, 2015

please explain more

if (!skipSidenav) {
var wasClosed = element.hasClass('md-closed');
element.removeClass('md-closed');
if (isHidden(element, true) && !skipSidenav) {
element.toggleClass('md-closed', wasClosed);
skipNextUpdate = true;
scope.isOpen = oldValue;
return;
}
element.toggleClass('md-closed', wasClosed);
}

parent[isOpen ? 'on' : 'off']('keydown', onKeyDown);
backdrop[isOpen ? 'on' : 'off']('click', close);

if ( isOpen ) {
if ( isOpen && !skipSidenav) {
// Capture upon opening..
triggeringElement = $document[0].activeElement;
}

disableParentScroll(isOpen);

return promise = $q.all([
isOpen ? $animate.enter(backdrop, parent) : $animate.leave(backdrop),
$animate[isOpen ? 'removeClass' : 'addClass'](element, 'md-closed')
])
.then(function() {
var actions = [isOpen ? $animate.enter(backdrop, parent) : $animate.leave(backdrop)];
if (!skipSidenav) actions.push($animate[isOpen ? 'removeClass' : 'addClass'](element, 'md-closed'));

This comment has been minimized.

Copy link
@EladBezalel

EladBezalel Dec 31, 2015

I'd prefer:

 actions.push(isOpen ? $animate.removeClass(element, 'md-closed') : $animate,addClass(element, 'md-closed'))

This comment has been minimized.

Copy link
@devversion

devversion Jan 1, 2016

Author Owner

I reused the old line, but this line looks more clear. :)


return promise = $q.all(actions).then(function() {
// Perform focus when animations are ALL done...
if (scope.isOpen) {
focusEl && focusEl.focus();
Expand Down

0 comments on commit b20bdf3

Please sign in to comment.