8
8
9
9
import {
10
10
Directive ,
11
- Input ,
12
- ViewContainerRef ,
13
- Output ,
14
11
EventEmitter ,
15
- Optional ,
16
- OnDestroy ,
17
12
Inject ,
18
13
Injectable ,
19
14
InjectionToken ,
15
+ Input ,
16
+ OnDestroy ,
17
+ Optional ,
18
+ Output ,
19
+ ViewContainerRef ,
20
20
} from '@angular/core' ;
21
21
import { Directionality } from '@angular/cdk/bidi' ;
22
22
import {
23
- OverlayRef ,
23
+ ConnectedPosition ,
24
+ FlexibleConnectedPositionStrategy ,
24
25
Overlay ,
25
26
OverlayConfig ,
26
- FlexibleConnectedPositionStrategy ,
27
- ConnectedPosition ,
27
+ OverlayRef ,
28
28
} 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' ;
33
33
import { CdkMenuPanel } from './menu-panel' ;
34
34
import { MenuStack } from './menu-stack' ;
35
35
import { throwExistingMenuStackError } from './menu-errors' ;
@@ -152,6 +152,10 @@ export class CdkContextMenuTrigger implements OnDestroy {
152
152
* @param coordinates where to open the context menu
153
153
*/
154
154
open ( coordinates : ContextMenuCoordinates ) {
155
+ this . _open ( coordinates , false ) ;
156
+ }
157
+
158
+ private _open ( coordinates : ContextMenuCoordinates , ignoreFirstOutsideAuxClick : boolean ) {
155
159
if ( this . disabled ) {
156
160
return ;
157
161
} else if ( this . isOpen ( ) ) {
@@ -176,7 +180,7 @@ export class CdkContextMenuTrigger implements OnDestroy {
176
180
}
177
181
178
182
this . _overlayRef . attach ( this . _getMenuContent ( ) ) ;
179
- this . _subscribeToOutsideClicks ( ) ;
183
+ this . _subscribeToOutsideClicks ( ignoreFirstOutsideAuxClick ) ;
180
184
}
181
185
}
182
186
@@ -200,7 +204,7 @@ export class CdkContextMenuTrigger implements OnDestroy {
200
204
event . stopPropagation ( ) ;
201
205
202
206
this . _contextMenuTracker . update ( this ) ;
203
- this . open ( { x : event . clientX , y : event . clientY } ) ;
207
+ this . _open ( { x : event . clientX , y : event . clientY } , true ) ;
204
208
205
209
// A context menu can be triggered via a mouse right click or a keyboard shortcut.
206
210
if ( event . button === 2 ) {
@@ -285,16 +289,20 @@ export class CdkContextMenuTrigger implements OnDestroy {
285
289
* Subscribe to the overlays outside pointer events stream and handle closing out the stack if a
286
290
* click occurs outside the menus.
287
291
*/
288
- private _subscribeToOutsideClicks ( ) {
292
+ private _subscribeToOutsideClicks ( ignoreFirstAuxClick : boolean ) {
289
293
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
+ } ) ;
298
306
}
299
307
}
300
308
0 commit comments