diff --git a/src/vs/base/browser/ui/list/list.ts b/src/vs/base/browser/ui/list/list.ts index 53df874292d..12f7d3df8c7 100644 --- a/src/vs/base/browser/ui/list/list.ts +++ b/src/vs/base/browser/ui/list/list.ts @@ -29,4 +29,10 @@ export interface IListEvent { export interface IListMouseEvent extends MouseEvent { element: T; index: number; +} + +export interface IListContextMenuEvent { + element: T; + index: number; + anchor: HTMLElement | { x: number; y: number; }; } \ No newline at end of file diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 8cbae824f80..fd11b9414fe 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -11,9 +11,9 @@ import * as DOM from 'vs/base/browser/dom'; import { EventType as TouchEventType } from 'vs/base/browser/touch'; import { KeyCode } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import Event, { Emitter, EventBufferer, chain, mapEvent, fromCallback } from 'vs/base/common/event'; +import Event, { Emitter, EventBufferer, chain, mapEvent, fromCallback, createEmptyEvent, any } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; -import { IDelegate, IRenderer, IListEvent, IListMouseEvent } from './list'; +import { IDelegate, IRenderer, IListEvent, IListMouseEvent, IListContextMenuEvent } from './list'; import { ListView, IListViewOptions } from './listView'; export interface IIdentityProvider { @@ -227,6 +227,10 @@ class MouseController implements IDisposable { private disposables: IDisposable[]; + @memoize get onContextMenu(): Event> { + return fromCallback(handler => this.view.addListener('contextmenu', handler)); + } + constructor( private list: List, private view: ListView @@ -287,8 +291,9 @@ export class List implements ISpliceable, IDisposable { return mapEvent(this.eventBufferer.wrapEvent(this.selection.onChange), e => this.toListEvent(e)); } - @memoize get onContextMenu(): Event> { - return fromCallback(handler => this.view.addListener('contextmenu', handler)); + private _onContextMenu: Event> = createEmptyEvent(); + get onContextMenu(): Event> { + return this._onContextMenu; } private _onOpen = new Emitter(); @@ -342,7 +347,13 @@ export class List implements ISpliceable, IDisposable { } if (typeof options.mouseSupport !== 'boolean' || options.mouseSupport) { - this.disposables.push(new MouseController(this, this.view)); + const controller = new MouseController(this, this.view); + this.disposables.push(controller); + + this._onContextMenu = any( + this._onContextMenu, + mapEvent(controller.onContextMenu, ({ element, index, clientX, clientY }) => ({ element, index, anchor: { x: clientX + 1, y: clientY } })) + ); } this.onFocusChange(this._onFocusChange, this, this.disposables); diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 9b6548dd0ad..d6d78abbec5 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -490,4 +490,8 @@ export function buffer(event: Event, nextTick = false, buffer: T[] = []): }); return emitter.event; +} + +export function createEmptyEvent(): Event { + return (listener, thisArgs = null, disposables?) => ({ dispose: () => null }); } \ No newline at end of file diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index e189a56b2a6..0c17de38ad8 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -17,7 +17,7 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { List } from 'vs/base/browser/ui/list/listWidget'; -import { IDelegate, IRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list'; +import { IDelegate, IRenderer, IListContextMenuEvent } from 'vs/base/browser/ui/list/list'; import { VIEWLET_ID } from 'vs/workbench/parts/scm/common/scm'; import { FileLabel } from 'vs/workbench/browser/labels'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; @@ -308,7 +308,7 @@ export class SCMViewlet extends Viewlet { return createActionItem(action, this.keybindingService, this.messageService); } - private onListContextMenu(e: IListMouseEvent): void { + private onListContextMenu(e: IListContextMenuEvent): void { const element = e.element; let actions: IAction[]; @@ -319,7 +319,7 @@ export class SCMViewlet extends Viewlet { } this.contextMenuService.showContextMenu({ - getAnchor: () => ({ x: e.clientX + 1, y: e.clientY }), + getAnchor: () => e.anchor, getActions: () => TPromise.as(actions) }); }