88
99import {
1010 Directive ,
11- Input ,
12- ViewContainerRef ,
13- Output ,
1411 EventEmitter ,
15- Optional ,
16- OnDestroy ,
1712 Inject ,
1813 Injectable ,
1914 InjectionToken ,
15+ Input ,
16+ OnDestroy ,
17+ Optional ,
18+ Output ,
19+ ViewContainerRef ,
2020} from '@angular/core' ;
2121import { Directionality } from '@angular/cdk/bidi' ;
2222import {
23- OverlayRef ,
23+ ConnectedPosition ,
24+ FlexibleConnectedPositionStrategy ,
2425 Overlay ,
2526 OverlayConfig ,
26- FlexibleConnectedPositionStrategy ,
27- ConnectedPosition ,
27+ OverlayRef ,
2828} from '@angular/cdk/overlay' ;
29- import { TemplatePortal , Portal } from '@angular/cdk/portal' ;
30- import { coerceBooleanProperty , BooleanInput } from '@angular/cdk/coercion' ;
31- import { Subject , merge } from 'rxjs' ;
32- import { takeUntil } from 'rxjs/operators' ;
29+ import { Portal , TemplatePortal } from '@angular/cdk/portal' ;
30+ import { BooleanInput , coerceBooleanProperty } from '@angular/cdk/coercion' ;
31+ import { merge , partition , Subject } from 'rxjs' ;
32+ import { skip , takeUntil } from 'rxjs/operators' ;
3333import { CdkMenuPanel } from './menu-panel' ;
3434import { MenuStack } from './menu-stack' ;
3535import { throwExistingMenuStackError } from './menu-errors' ;
@@ -152,6 +152,10 @@ export class CdkContextMenuTrigger implements OnDestroy {
152152 * @param coordinates where to open the context menu
153153 */
154154 open ( coordinates : ContextMenuCoordinates ) {
155+ this . _open ( coordinates , false ) ;
156+ }
157+
158+ private _open ( coordinates : ContextMenuCoordinates , ignoreFirstOutsideAuxClick : boolean ) {
155159 if ( this . disabled ) {
156160 return ;
157161 } else if ( this . isOpen ( ) ) {
@@ -176,7 +180,7 @@ export class CdkContextMenuTrigger implements OnDestroy {
176180 }
177181
178182 this . _overlayRef . attach ( this . _getMenuContent ( ) ) ;
179- this . _subscribeToOutsideClicks ( ) ;
183+ this . _subscribeToOutsideClicks ( ignoreFirstOutsideAuxClick ) ;
180184 }
181185 }
182186
@@ -200,7 +204,7 @@ export class CdkContextMenuTrigger implements OnDestroy {
200204 event . stopPropagation ( ) ;
201205
202206 this . _contextMenuTracker . update ( this ) ;
203- this . open ( { x : event . clientX , y : event . clientY } ) ;
207+ this . _open ( { x : event . clientX , y : event . clientY } , true ) ;
204208
205209 // A context menu can be triggered via a mouse right click or a keyboard shortcut.
206210 if ( event . button === 2 ) {
@@ -285,16 +289,20 @@ export class CdkContextMenuTrigger implements OnDestroy {
285289 * Subscribe to the overlays outside pointer events stream and handle closing out the stack if a
286290 * click occurs outside the menus.
287291 */
288- private _subscribeToOutsideClicks ( ) {
292+ private _subscribeToOutsideClicks ( ignoreFirstAuxClick : boolean ) {
289293 if ( this . _overlayRef ) {
290- this . _overlayRef
291- . outsidePointerEvents ( )
292- . pipe ( takeUntil ( this . _stopOutsideClicksListener ) )
293- . subscribe ( event => {
294- if ( ! isClickInsideMenuOverlay ( event . target as Element ) ) {
295- this . _menuStack . closeAll ( ) ;
296- }
297- } ) ;
294+ let outsideClicks = this . _overlayRef . outsidePointerEvents ( ) ;
295+ // If the menu was triggered by the `contextmenu` event, skip the first `auxclick` event
296+ // because it fires when the mouse is released on the same click that opened the menu.
297+ if ( ignoreFirstAuxClick ) {
298+ const [ auxClicks , nonAuxClicks ] = partition ( outsideClicks , ( { type} ) => type === 'auxclick' ) ;
299+ outsideClicks = merge ( nonAuxClicks , auxClicks . pipe ( skip ( 1 ) ) ) ;
300+ }
301+ outsideClicks . pipe ( takeUntil ( this . _stopOutsideClicksListener ) ) . subscribe ( event => {
302+ if ( ! isClickInsideMenuOverlay ( event . target as Element ) ) {
303+ this . _menuStack . closeAll ( ) ;
304+ }
305+ } ) ;
298306 }
299307 }
300308
0 commit comments