Skip to content

Commit b8a1b66

Browse files
committed
Merge branch 'listcontextmenu'
2 parents d784938 + a20fe85 commit b8a1b66

2 files changed

Lines changed: 27 additions & 10 deletions

File tree

src/vs/base/browser/ui/list/listWidget.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -353,14 +353,24 @@ function isSelectionChangeEvent(event: IListMouseEvent<any> | IListTouchEvent<an
353353
class MouseController<T> implements IDisposable {
354354

355355
private multipleSelectionSupport: boolean;
356+
private didJustPressContextMenuKey: boolean = false;
356357
private disposables: IDisposable[] = [];
357358

358359
@memoize get onContextMenu(): Event<IListContextMenuEvent<T>> {
359-
const fromKeyboard = chain(domEvent(this.view.domNode, 'keydown'))
360+
const fromKeydown = chain(domEvent(this.view.domNode, 'keydown'))
360361
.map(e => new StandardKeyboardEvent(e))
361-
.filter(e => this.list.getFocus().length > 0)
362-
.filter(e => e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10))
363-
.map(e => {
362+
.filter(e => this.didJustPressContextMenuKey = e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10))
363+
.filter(e => { e.preventDefault(); e.stopPropagation(); return false; })
364+
.event as Event<any>;
365+
366+
const fromKeyup = chain(domEvent(this.view.domNode, 'keyup'))
367+
.filter(() => {
368+
const didJustPressContextMenuKey = this.didJustPressContextMenuKey;
369+
this.didJustPressContextMenuKey = false;
370+
return didJustPressContextMenuKey;
371+
})
372+
.filter(() => this.list.getFocus().length > 0)
373+
.map(() => {
364374
const index = this.list.getFocus()[0];
365375
const element = this.view.element(index);
366376
const anchor = this.view.domElement(index);
@@ -370,10 +380,11 @@ class MouseController<T> implements IDisposable {
370380
.event;
371381

372382
const fromMouse = chain(this.view.onContextMenu)
383+
.filter(() => !this.didJustPressContextMenuKey)
373384
.map(({ element, index, browserEvent }) => ({ element, index, anchor: { x: browserEvent.clientX + 1, y: browserEvent.clientY } }))
374385
.event;
375386

376-
return anyEvent<IListContextMenuEvent<T>>(fromKeyboard, fromMouse);
387+
return anyEvent<IListContextMenuEvent<T>>(fromKeydown, fromKeyup, fromMouse);
377388
}
378389

379390
constructor(
@@ -655,10 +666,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
655666
return mapEvent(this.eventBufferer.wrapEvent(this.selection.onChange), e => this.toListEvent(e));
656667
}
657668

658-
private _onContextMenu: Event<IListContextMenuEvent<T>> = Event.None;
659-
get onContextMenu(): Event<IListContextMenuEvent<T>> {
660-
return this._onContextMenu;
661-
}
669+
readonly onContextMenu: Event<IListContextMenuEvent<T>> = Event.None;
662670

663671
private _onOpen = new Emitter<number[]>();
664672
@memoize get onOpen(): Event<IListEvent<T>> {
@@ -731,7 +739,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
731739
if (typeof options.mouseSupport !== 'boolean' || options.mouseSupport) {
732740
const controller = new MouseController(this, this.view, options);
733741
this.disposables.push(controller);
734-
this._onContextMenu = controller.onContextMenu;
742+
this.onContextMenu = controller.onContextMenu;
735743
}
736744

737745
this.onFocusChange(this._onFocusChange, this, this.disposables);

src/vs/base/common/event.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ export class EventBufferer {
365365
export interface IChainableEvent<T> {
366366
event: Event<T>;
367367
map<O>(fn: (i: T) => O): IChainableEvent<O>;
368+
forEach(fn: (i: T) => void): IChainableEvent<T>;
368369
filter(fn: (e: T) => boolean): IChainableEvent<T>;
369370
on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;
370371
}
@@ -373,6 +374,10 @@ export function mapEvent<I, O>(event: Event<I>, map: (i: I) => O): Event<O> {
373374
return (listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables);
374375
}
375376

377+
export function forEach<I>(event: Event<I>, each: (i: I) => void): Event<I> {
378+
return (listener, thisArgs = null, disposables?) => event(i => { each(i); listener.call(thisArgs, i); }, null, disposables);
379+
}
380+
376381
export function filterEvent<T>(event: Event<T>, filter: (e: T) => boolean): Event<T> {
377382
return (listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables);
378383
}
@@ -387,6 +392,10 @@ class ChainableEvent<T> implements IChainableEvent<T> {
387392
return new ChainableEvent(mapEvent(this._event, fn));
388393
}
389394

395+
forEach(fn: (i: T) => void): IChainableEvent<T> {
396+
return new ChainableEvent(forEach(this._event, fn));
397+
}
398+
390399
filter(fn: (e: T) => boolean): IChainableEvent<T> {
391400
return new ChainableEvent(filterEvent(this._event, fn));
392401
}

0 commit comments

Comments
 (0)