@@ -22,9 +22,10 @@ import {
22
22
TemplatePortal ,
23
23
ConnectedPositionStrategy ,
24
24
HorizontalConnectionPos ,
25
- VerticalConnectionPos
25
+ VerticalConnectionPos ,
26
26
} from '../core' ;
27
27
import { Subscription } from 'rxjs/Subscription' ;
28
+ import { MenuPositionX , MenuPositionY } from './menu-positions' ;
28
29
29
30
/**
30
31
* This directive is intended to be used in conjunction with an md-menu tag. It is
@@ -44,6 +45,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
44
45
private _overlayRef : OverlayRef ;
45
46
private _menuOpen : boolean = false ;
46
47
private _backdropSubscription : Subscription ;
48
+ private _positionSubscription : Subscription ;
47
49
48
50
// tracking input type is necessary so it's possible to only auto-focus
49
51
// the first item of the list when the menu is opened via the keyboard
@@ -92,9 +94,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
92
94
this . _overlayRef . dispose ( ) ;
93
95
this . _overlayRef = null ;
94
96
95
- if ( this . _backdropSubscription ) {
96
- this . _backdropSubscription . unsubscribe ( ) ;
97
- }
97
+ this . _cleanUpSubscriptions ( ) ;
98
98
}
99
99
}
100
100
@@ -172,7 +172,9 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
172
172
private _createOverlay ( ) : void {
173
173
if ( ! this . _overlayRef ) {
174
174
this . _portal = new TemplatePortal ( this . menu . templateRef , this . _viewContainerRef ) ;
175
- this . _overlayRef = this . _overlay . create ( this . _getOverlayConfig ( ) ) ;
175
+ const config = this . _getOverlayConfig ( ) ;
176
+ this . _subscribeToPositions ( config . positionStrategy as ConnectedPositionStrategy ) ;
177
+ this . _overlayRef = this . _overlay . create ( config ) ;
176
178
}
177
179
}
178
180
@@ -190,20 +192,52 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
190
192
return overlayState ;
191
193
}
192
194
195
+ /**
196
+ * Listens to changes in the position of the overlay and sets the correct classes
197
+ * on the menu based on the new position. This ensures the animation origin is always
198
+ * correct, even if a fallback position is used for the overlay.
199
+ */
200
+ private _subscribeToPositions ( position : ConnectedPositionStrategy ) : void {
201
+ this . _positionSubscription = position . onPositionChange . subscribe ( ( change ) => {
202
+ const posX : MenuPositionX = change . connectionPair . originX === 'start' ? 'after' : 'before' ;
203
+ const posY : MenuPositionY = change . connectionPair . originY === 'top' ? 'below' : 'above' ;
204
+ this . menu . setPositionClasses ( posX , posY ) ;
205
+ } ) ;
206
+ }
207
+
193
208
/**
194
209
* This method builds the position strategy for the overlay, so the menu is properly connected
195
210
* to the trigger.
196
211
* @returns ConnectedPositionStrategy
197
212
*/
198
213
private _getPosition ( ) : ConnectedPositionStrategy {
199
- const positionX : HorizontalConnectionPos = this . menu . positionX === 'before' ? 'end' : 'start' ;
200
- const positionY : VerticalConnectionPos = this . menu . positionY === 'above' ? 'bottom' : 'top' ;
201
-
202
- return this . _overlay . position ( ) . connectedTo (
203
- this . _element ,
204
- { originX : positionX , originY : positionY } ,
205
- { overlayX : positionX , overlayY : positionY }
206
- ) ;
214
+ const [ posX , fallbackX ] : HorizontalConnectionPos [ ] =
215
+ this . menu . positionX === 'before' ? [ 'end' , 'start' ] : [ 'start' , 'end' ] ;
216
+
217
+ const [ posY , fallbackY ] : VerticalConnectionPos [ ] =
218
+ this . menu . positionY === 'above' ? [ 'bottom' , 'top' ] : [ 'top' , 'bottom' ] ;
219
+
220
+ return this . _overlay . position ( )
221
+ . connectedTo ( this . _element ,
222
+ { originX : posX , originY : posY } , { overlayX : posX , overlayY : posY } )
223
+ . withFallbackPosition (
224
+ { originX : fallbackX , originY : posY } ,
225
+ { overlayX : fallbackX , overlayY : posY } )
226
+ . withFallbackPosition (
227
+ { originX : posX , originY : fallbackY } ,
228
+ { overlayX : posX , overlayY : fallbackY } )
229
+ . withFallbackPosition (
230
+ { originX : fallbackX , originY : fallbackY } ,
231
+ { overlayX : fallbackX , overlayY : fallbackY } ) ;
232
+ }
233
+
234
+ private _cleanUpSubscriptions ( ) : void {
235
+ if ( this . _backdropSubscription ) {
236
+ this . _backdropSubscription . unsubscribe ( ) ;
237
+ }
238
+ if ( this . _positionSubscription ) {
239
+ this . _positionSubscription . unsubscribe ( ) ;
240
+ }
207
241
}
208
242
209
243
_handleMousedown ( event : MouseEvent ) : void {
0 commit comments