Skip to content

Commit e5a9ea2

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 e5a9ea2

File tree

1 file changed

+50
-8
lines changed

1 file changed

+50
-8
lines changed

src/components/sidenav/sidenav.js

+50-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,46 @@ 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) && scope.isOpen == true) scope.isOpen = false;
276+
else if (!isHidden(element, 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) {
286+
if (!compute) return element[0].offsetParent == null;
287+
return window.getComputedStyle(element[0]).display === 'none';
288+
}
289+
263290
/**
264291
* Toggle the DOM classes to indicate `locked`
265292
* @param isLocked
@@ -278,26 +305,41 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate,
278305
* Toggle the SideNav view and attach/detach listeners
279306
* @param isOpen
280307
*/
281-
function updateIsOpen(isOpen) {
308+
function updateIsOpen(isOpen, oldValue) {
309+
if (skipNextUpdate) {
310+
skipNextUpdate = false;
311+
return;
312+
}
313+
282314
// Support deprecated md-sidenav-focus attribute as fallback
283315
var focusEl = $mdUtil.findFocusTarget(element) || $mdUtil.findFocusTarget(element,'[md-sidenav-focus]') || element;
284316
var parent = element.parent();
285317

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

289-
if ( isOpen ) {
332+
if ( isOpen && !skipSidenav) {
290333
// Capture upon opening..
291334
triggeringElement = $document[0].activeElement;
292335
}
293336

294337
disableParentScroll(isOpen);
295338

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() {
339+
var actions = [isOpen ? $animate.enter(backdrop, parent) : $animate.leave(backdrop)];
340+
if (!skipSidenav) actions.push($animate[isOpen ? 'removeClass' : 'addClass'](element, 'md-closed'));
341+
342+
return promise = $q.all(actions).then(function() {
301343
// Perform focus when animations are ALL done...
302344
if (scope.isOpen) {
303345
focusEl && focusEl.focus();

0 commit comments

Comments
 (0)