Skip to content

Commit b20bdf3

Browse files
committed
feat(sidenav): track sidenav vissibilty and enter / leave backdrop if needed.
- Revert scope value if sidenav is shown. - Throttle Resize Events Fixes angular#4595
1 parent 8ef798f commit b20bdf3

File tree

1 file changed

+55
-8
lines changed

1 file changed

+55
-8
lines changed

src/components/sidenav/sidenav.js

+55-8
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ function SidenavFocusDirective() {
208208
* - `<md-sidenav md-is-locked-open="$mdMedia('min-width: 1000px')"></md-sidenav>`
209209
* - `<md-sidenav md-is-locked-open="$mdMedia('sm')"></md-sidenav>` (locks open on small screens)
210210
*/
211-
function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate, $compile, $parse, $log, $q, $document) {
211+
function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate, $compile, $parse, $log, $q, $document, $$rAF) {
212212
return {
213213
restrict: 'E',
214214
scope: {
@@ -229,6 +229,9 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate,
229229
var lastParentOverFlow;
230230
var triggeringElement = null;
231231
var promise = $q.when(true);
232+
var skipSidenav = false;
233+
var skipNextUpdate = false;
234+
var $window = angular.element(window);
232235

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

245248
$mdTheming.inherit(backdrop, element);
246249

250+
var throttleResize = $$rAF.throttle(revalidateVisibility);
251+
$window.on('resize', throttleResize);
252+
revalidateVisibility();
253+
247254
element.on('$destroy', function() {
248255
backdrop.remove();
249256
sidenavCtrl.destroy();
257+
$window.off('resize', throttleResize);
250258
});
251259

252260
scope.$on('$destroy', function(){
261+
$window.off('resize', throttleResize);
253262
backdrop.remove()
254263
});
255264

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

259268

269+
260270
// Publish special accessor for the Controller instance
261271
sidenavCtrl.$toggleOpen = toggleOpen;
262272

273+
function revalidateVisibility() {
274+
var lastValue = scope.isOpen;
275+
if (isHidden(element, true, true) && scope.isOpen == true) scope.isOpen = false;
276+
else if (!isHidden(element, true, true) && scope.isOpen == false) scope.isOpen = true;
277+
278+
if (lastValue != scope.isOpen) {
279+
skipSidenav = true;
280+
if (!scope.$$phase) scope.$apply();
281+
skipSidenav = false;
282+
}
283+
}
284+
285+
function isHidden(element, compute, both) {
286+
if (!compute || both) {
287+
if (element[0].offsetParent == null) return true;
288+
if (!both) return false;
289+
}
290+
return window.getComputedStyle(element[0]).display === 'none';
291+
}
292+
263293
/**
264294
* Toggle the DOM classes to indicate `locked`
265295
* @param isLocked
@@ -278,26 +308,43 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate,
278308
* Toggle the SideNav view and attach/detach listeners
279309
* @param isOpen
280310
*/
281-
function updateIsOpen(isOpen) {
311+
function updateIsOpen(isOpen, oldValue) {
312+
if (skipNextUpdate) {
313+
skipNextUpdate = false;
314+
return;
315+
}
316+
282317
// Support deprecated md-sidenav-focus attribute as fallback
283318
var focusEl = $mdUtil.findFocusTarget(element) || $mdUtil.findFocusTarget(element,'[md-sidenav-focus]') || element;
284319
var parent = element.parent();
285320

321+
// little hack to check show abbility
322+
if (!skipSidenav) {
323+
var wasClosed = element.hasClass('md-closed');
324+
element.removeClass('md-closed');
325+
if (isHidden(element, true) && !skipSidenav) {
326+
element.toggleClass('md-closed', wasClosed);
327+
skipNextUpdate = true;
328+
scope.isOpen = oldValue;
329+
return;
330+
}
331+
element.toggleClass('md-closed', wasClosed);
332+
}
333+
286334
parent[isOpen ? 'on' : 'off']('keydown', onKeyDown);
287335
backdrop[isOpen ? 'on' : 'off']('click', close);
288336

289-
if ( isOpen ) {
337+
if ( isOpen && !skipSidenav) {
290338
// Capture upon opening..
291339
triggeringElement = $document[0].activeElement;
292340
}
293341

294342
disableParentScroll(isOpen);
295343

296-
return promise = $q.all([
297-
isOpen ? $animate.enter(backdrop, parent) : $animate.leave(backdrop),
298-
$animate[isOpen ? 'removeClass' : 'addClass'](element, 'md-closed')
299-
])
300-
.then(function() {
344+
var actions = [isOpen ? $animate.enter(backdrop, parent) : $animate.leave(backdrop)];
345+
if (!skipSidenav) actions.push($animate[isOpen ? 'removeClass' : 'addClass'](element, 'md-closed'));
346+
347+
return promise = $q.all(actions).then(function() {
301348
// Perform focus when animations are ALL done...
302349
if (scope.isOpen) {
303350
focusEl && focusEl.focus();

0 commit comments

Comments
 (0)