Skip to content

Commit

Permalink
[dialog] fix #5859: apply overlay keyboard events to the top most dialog
Browse files Browse the repository at this point in the history
Signed-off-by: Anton Kosyakov <anton.kosyakov@typefox.io>
  • Loading branch information
akosyakov committed Aug 7, 2019
1 parent 62fe752 commit 7e7428f
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 3 deletions.
60 changes: 57 additions & 3 deletions packages/core/src/browser/dialogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
import { injectable, inject } from 'inversify';
import { Disposable, MaybePromise, CancellationTokenSource } from '../common';
import { Key } from './keyboard/keys';
import { Widget, BaseWidget, Message } from './widgets';
import { Widget, BaseWidget, Message, addKeyListener } from './widgets';
import { FrontendApplicationContribution } from './frontend-application';

@injectable()
export class DialogProps {
Expand Down Expand Up @@ -51,6 +52,59 @@ export namespace DialogError {
}
}

@injectable()
export class DialogOverlayService implements FrontendApplicationContribution {

protected static INSTANCE: DialogOverlayService;

static get(): DialogOverlayService {
return DialogOverlayService.INSTANCE;
}

// tslint:disable-next-line:no-any
protected readonly dialogs: AbstractDialog<any>[] = [];

constructor() {
addKeyListener(document.body, Key.ENTER, e => this.handleEnter(e));
addKeyListener(document.body, Key.ESCAPE, e => this.handleEscape(e));
}

initialize(): void {
DialogOverlayService.INSTANCE = this;
}

// tslint:disable-next-line:no-any
protected get currentDialog(): AbstractDialog<any> | undefined {
return this.dialogs[0];
}

// tslint:disable-next-line:no-any
push(dialog: AbstractDialog<any>): Disposable {
this.dialogs.unshift(dialog);
return Disposable.create(() => {
const index = this.dialogs.indexOf(dialog);
if (index > -1) {
this.dialogs.splice(index, 1);
}
});
}

protected handleEscape(event: KeyboardEvent): boolean | void {
const dialog = this.currentDialog;
if (dialog) {
dialog['handleEscape'](event);
}
}

protected handleEnter(event: KeyboardEvent): boolean | void {
const dialog = this.currentDialog;
if (dialog) {
dialog['handleEnter'](event);
}
}

}

@injectable()
export abstract class AbstractDialog<T> extends BaseWidget {

Expand Down Expand Up @@ -144,8 +198,8 @@ export abstract class AbstractDialog<T> extends BaseWidget {
this.addAcceptAction(this.acceptButton, 'click');
}
this.addCloseAction(this.closeCrossNode, 'click');
this.addKeyListener(document.body, Key.ESCAPE, e => this.handleEscape(e));
this.addKeyListener(document.body, Key.ENTER, e => this.handleEnter(e));
// TODO: use DI always to create dialog instances
this.toDisposeOnDetach.push(DialogOverlayService.get().push(this));
}

protected handleEscape(event: KeyboardEvent): boolean | void {
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/browser/frontend-application-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import { ApplicationShellMouseTracker } from './shell/application-shell-mouse-tr
import { ViewContainer, ViewContainerIdentifier } from './view-container';
import { QuickViewService } from './quick-view-service';
import { QuickTitleBar } from './quick-open/quick-title-bar';
import { DialogOverlayService } from './dialogs';

export const frontendApplicationModule = new ContainerModule((bind, unbind, isBound, rebind) => {
const themeService = ThemeService.get();
Expand Down Expand Up @@ -253,6 +254,9 @@ export const frontendApplicationModule = new ContainerModule((bind, unbind, isBo

bind(QuickViewService).toSelf().inSingletonScope();
bind(QuickOpenContribution).toService(QuickViewService);

bind(DialogOverlayService).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(DialogOverlayService);
});

export function bindMessageService(bind: interfaces.Bind): interfaces.BindingWhenOnSyntax<MessageService> {
Expand Down

0 comments on commit 7e7428f

Please sign in to comment.