@@ -208,7 +208,7 @@ function SidenavFocusDirective() {
208
208
* - `<md-sidenav md-is-locked-open="$mdMedia('min-width: 1000px')"></md-sidenav>`
209
209
* - `<md-sidenav md-is-locked-open="$mdMedia('sm')"></md-sidenav>` (locks open on small screens)
210
210
*/
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 , $window ) {
212
212
return {
213
213
restrict : 'E' ,
214
214
scope : {
@@ -229,6 +229,9 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate,
229
229
var lastParentOverFlow ;
230
230
var triggeringElement = null ;
231
231
var promise = $q . when ( true ) ;
232
+ var skipSidenav = false ;
233
+ var skipNextUpdate = false ;
234
+ var windowElement = angular . element ( $window ) ;
232
235
233
236
var isLockedOpenParsed = $parse ( attr . mdIsLockedOpen ) ;
234
237
var isLocked = function ( ) {
@@ -244,22 +247,59 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate,
244
247
245
248
$mdTheming . inherit ( backdrop , element ) ;
246
249
250
+ var throttleResize = $$rAF . throttle ( revalidateVisibility ) ;
251
+ windowElement . on ( 'resize' , throttleResize ) ;
252
+ revalidateVisibility ( ) ;
253
+
247
254
element . on ( '$destroy' , function ( ) {
248
255
backdrop . remove ( ) ;
249
256
sidenavCtrl . destroy ( ) ;
257
+ windowElement . off ( 'resize' , throttleResize ) ;
250
258
} ) ;
251
259
252
260
scope . $on ( '$destroy' , function ( ) {
261
+ windowElement . off ( 'resize' , throttleResize ) ;
253
262
backdrop . remove ( )
254
263
} ) ;
255
264
256
265
scope . $watch ( isLocked , updateIsLocked ) ;
257
266
scope . $watch ( 'isOpen' , updateIsOpen ) ;
258
267
259
268
269
+
260
270
// Publish special accessor for the Controller instance
261
271
sidenavCtrl . $toggleOpen = toggleOpen ;
262
272
273
+ function revalidateVisibility ( ) {
274
+ var lastValue = scope . isOpen ;
275
+ if ( attr . mdIsLockedOpen ) return ;
276
+
277
+ if ( isHidden ( true , true ) && scope . isOpen ) {
278
+ scope . isOpen = false ;
279
+ } else if ( ! isHidden ( true , true ) && ! scope . isOpen ) {
280
+ scope . isOpen = true ;
281
+ }
282
+
283
+ // If the revalidated isOpen Value got changed,
284
+ // we should apply it to the view without running the updateOpen watcher
285
+ if ( lastValue != scope . isOpen ) {
286
+ skipSidenav = true ;
287
+ if ( ! scope . $$phase ) scope . $apply ( ) ;
288
+ skipSidenav = false ;
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Checks the sidenav's hide state
294
+ * @param computedStyle Check Computed Style
295
+ * @param offsetParent Check Offset Parent
296
+ */
297
+ function isHidden ( computedStyle , offsetParent ) {
298
+ if ( computedStyle && window . getComputedStyle ( element [ 0 ] ) . display === 'none' ) return true ;
299
+ if ( offsetParent && element [ 0 ] . offsetParent == null ) return true ;
300
+ return false ;
301
+ }
302
+
263
303
/**
264
304
* Toggle the DOM classes to indicate `locked`
265
305
* @param isLocked
@@ -278,31 +318,51 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate,
278
318
* Toggle the SideNav view and attach/detach listeners
279
319
* @param isOpen
280
320
*/
281
- function updateIsOpen ( isOpen ) {
321
+ function updateIsOpen ( isOpen , oldValue ) {
322
+ if ( skipNextUpdate ) {
323
+ skipNextUpdate = false ;
324
+ return ;
325
+ }
326
+
282
327
// Support deprecated md-sidenav-focus attribute as fallback
283
328
var focusEl = $mdUtil . findFocusTarget ( element ) || $mdUtil . findFocusTarget ( element , '[md-sidenav-focus]' ) || element ;
284
329
var parent = element . parent ( ) ;
285
330
331
+ // Temporary remove md-closed class (won't affect the view, because it's outside of the viewport).
332
+ // And then check the visbility due hide attributes. So if the isOpen variable changes
333
+ // and a hide attribute is active we should revert the digest change
334
+ if ( ! skipSidenav ) {
335
+ var wasClosed = element . hasClass ( 'md-closed' ) ;
336
+ element . removeClass ( 'md-closed' ) ;
337
+ if ( isHidden ( true , false ) && ! skipSidenav ) {
338
+ element . toggleClass ( 'md-closed' , wasClosed ) ;
339
+ skipNextUpdate = true ;
340
+ scope . isOpen = ! ! oldValue ;
341
+ return ;
342
+ }
343
+ element . toggleClass ( 'md-closed' , wasClosed ) ;
344
+ }
345
+
286
346
parent [ isOpen ? 'on' : 'off' ] ( 'keydown' , onKeyDown ) ;
287
347
backdrop [ isOpen ? 'on' : 'off' ] ( 'click' , close ) ;
288
348
289
- if ( isOpen ) {
349
+ if ( isOpen && ! skipSidenav ) {
290
350
// Capture upon opening..
291
351
triggeringElement = $document [ 0 ] . activeElement ;
292
352
}
293
353
294
354
disableParentScroll ( isOpen ) ;
295
355
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 ( ) {
301
- // Perform focus when animations are ALL done...
302
- if ( scope . isOpen ) {
303
- focusEl && focusEl . focus ( ) ;
304
- }
305
- } ) ;
356
+ var actions = [ isOpen ? $animate . enter ( backdrop , parent ) : $animate . leave ( backdrop ) ] ;
357
+ if ( ! skipSidenav ) actions . push ( isOpen ? $animate . removeClass ( element , 'md-closed' ) : $animate . addClass ( element , 'md-closed' ) ) ;
358
+
359
+ return promise = $q . all ( actions )
360
+ . then ( function ( ) {
361
+ // Perform focus when animations are ALL done...
362
+ if ( scope . isOpen ) {
363
+ focusEl && focusEl . focus ( ) ;
364
+ }
365
+ } ) ;
306
366
}
307
367
308
368
/**
0 commit comments