mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
fix keyboard focus issues (#16206)
This commit is contained in:
@@ -33,7 +33,6 @@ export interface IPanelOptions {
|
|||||||
export interface IPanelView {
|
export interface IPanelView {
|
||||||
render(container: HTMLElement): void;
|
render(container: HTMLElement): void;
|
||||||
layout(dimension: DOM.Dimension): void;
|
layout(dimension: DOM.Dimension): void;
|
||||||
focus(): void;
|
|
||||||
remove?(): void;
|
remove?(): void;
|
||||||
onShow?(): void;
|
onShow?(): void;
|
||||||
onHide?(): void;
|
onHide?(): void;
|
||||||
@@ -184,15 +183,6 @@ export class TabbedPanel extends Disposable {
|
|||||||
let currentIndex = this._tabOrder.findIndex(x => x === tab.tab.identifier);
|
let currentIndex = this._tabOrder.findIndex(x => x === tab.tab.identifier);
|
||||||
this.focusNextTab(currentIndex - 1);
|
this.focusNextTab(currentIndex - 1);
|
||||||
}
|
}
|
||||||
if (event.equals(KeyCode.Tab)) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (this._shownTabId) {
|
|
||||||
const shownTab = this._tabMap.get(this._shownTabId);
|
|
||||||
if (shownTab) {
|
|
||||||
shownTab.tab.view.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const insertBefore = !isUndefinedOrNull(index) ? this.tabList.children.item(index) : undefined;
|
const insertBefore = !isUndefinedOrNull(index) ? this.tabList.children.item(index) : undefined;
|
||||||
@@ -401,15 +391,6 @@ export class TabbedPanel extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public focus(): void {
|
|
||||||
if (this._shownTabId) {
|
|
||||||
const tab = this._tabMap.get(this._shownTabId);
|
|
||||||
if (tab) {
|
|
||||||
tab.tab.view.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public set collapsed(val: boolean) {
|
public set collapsed(val: boolean) {
|
||||||
if (val === this._collapsed) {
|
if (val === this._collapsed) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -80,6 +80,23 @@ export class Table<T extends Slick.SlickData> extends Widget implements IDisposa
|
|||||||
this._container = document.createElement('div');
|
this._container = document.createElement('div');
|
||||||
this._container.className = 'monaco-table';
|
this._container.className = 'monaco-table';
|
||||||
this._register(DOM.addDisposableListener(this._container, DOM.EventType.FOCUS, () => {
|
this._register(DOM.addDisposableListener(this._container, DOM.EventType.FOCUS, () => {
|
||||||
|
if (!this.grid.getActiveCell() && this._data.getLength() > 0) {
|
||||||
|
// When the table receives focus and there are currently no active cell, the focus should go to the first focusable cell.
|
||||||
|
let cellToFocus = undefined;
|
||||||
|
for (let col = 0; col < this.columns.length; col++) {
|
||||||
|
// some cells are not keyboard focusable (e.g. row number column), we need to find the first focusable cell.
|
||||||
|
if (this.grid.canCellBeActive(0, col)) {
|
||||||
|
cellToFocus = {
|
||||||
|
row: 0,
|
||||||
|
cell: col
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cellToFocus) {
|
||||||
|
this.grid.setActiveCell(cellToFocus.row, cellToFocus.cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
clearTimeout(this._classChangeTimeout);
|
clearTimeout(this._classChangeTimeout);
|
||||||
this._classChangeTimeout = setTimeout(() => {
|
this._classChangeTimeout = setTimeout(() => {
|
||||||
this._container.classList.add('focused');
|
this._container.classList.add('focused');
|
||||||
@@ -121,6 +138,14 @@ export class Table<T extends Slick.SlickData> extends Widget implements IDisposa
|
|||||||
this.mapMouseEvent(this._grid.onHeaderClick, this._onHeaderClick);
|
this.mapMouseEvent(this._grid.onHeaderClick, this._onHeaderClick);
|
||||||
this.mapMouseEvent(this._grid.onDblClick, this._onDoubleClick);
|
this.mapMouseEvent(this._grid.onDblClick, this._onDoubleClick);
|
||||||
this._grid.onColumnsResized.subscribe(() => this._onColumnResize.fire());
|
this._grid.onColumnsResized.subscribe(() => this._onColumnResize.fire());
|
||||||
|
this._grid.onRendered.subscribe(() => {
|
||||||
|
if (!this._grid.getActiveCell()) {
|
||||||
|
this._container.tabIndex = this._data.getLength() > 0 ? 0 : -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this._grid.onActiveCellChanged.subscribe((e, data) => {
|
||||||
|
this._container.tabIndex = -1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public rerenderGrid() {
|
public rerenderGrid() {
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ export enum ComponentEventType {
|
|||||||
onComponentCreated,
|
onComponentCreated,
|
||||||
onCellAction,
|
onCellAction,
|
||||||
onEnterKeyPressed,
|
onEnterKeyPressed,
|
||||||
onInput
|
onInput,
|
||||||
|
onComponentLoaded
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -244,7 +244,8 @@ export enum ComponentEventType {
|
|||||||
onComponentCreated,
|
onComponentCreated,
|
||||||
onCellAction,
|
onCellAction,
|
||||||
onEnterKeyPressed,
|
onEnterKeyPressed,
|
||||||
onInput
|
onInput,
|
||||||
|
onComponentLoaded
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IComponentEventArgs {
|
export interface IComponentEventArgs {
|
||||||
|
|||||||
@@ -382,12 +382,9 @@ export abstract class Modal extends Disposable implements IThemable {
|
|||||||
* Set focusable elements in the modal dialog
|
* Set focusable elements in the modal dialog
|
||||||
*/
|
*/
|
||||||
public setInitialFocusedElement() {
|
public setInitialFocusedElement() {
|
||||||
// Try to find focusable element in dialog pane rather than overall container. _modalBodySection contains items in the pane for a wizard.
|
const focusableElements = getFocusableElements(this._modalDialog!);
|
||||||
// This ensures that we are setting the focus on a useful element in the form when possible.
|
if (focusableElements?.length > 0) {
|
||||||
const focusableElements = getFocusableElements(this._modalBodySection ?? this._bodyContainer!);
|
focusableElements[0].focus();
|
||||||
|
|
||||||
if (focusableElements && focusableElements.length > 0) {
|
|
||||||
(<HTMLElement>focusableElements[0]).focus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ export abstract class ComponentBase<TPropertyBag extends azdata.ComponentPropert
|
|||||||
this.modelStore.registerComponent(this);
|
this.modelStore.registerComponent(this);
|
||||||
this._validations.push(() => this.modelStore.validate(this));
|
this._validations.push(() => this.modelStore.validate(this));
|
||||||
}
|
}
|
||||||
|
this.fireEvent({
|
||||||
|
eventType: ComponentEventType.onComponentLoaded,
|
||||||
|
args: undefined
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract ngAfterViewInit(): void;
|
abstract ngAfterViewInit(): void;
|
||||||
|
|||||||
@@ -206,9 +206,6 @@ export class ChartView extends Disposable implements IPanelView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
focus(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
public set queryRunner(runner: QueryRunner) {
|
public set queryRunner(runner: QueryRunner) {
|
||||||
this._queryRunner = runner;
|
this._queryRunner = runner;
|
||||||
this.fetchData();
|
this.fetchData();
|
||||||
|
|||||||
@@ -362,8 +362,7 @@ export class ProfilerEditor extends EditorPane {
|
|||||||
title: nls.localize('text', "Text"),
|
title: nls.localize('text', "Text"),
|
||||||
view: {
|
view: {
|
||||||
layout: dim => this._editor.layout(dim),
|
layout: dim => this._editor.layout(dim),
|
||||||
render: parent => parent.appendChild(editorContainer),
|
render: parent => parent.appendChild(editorContainer)
|
||||||
focus: () => this._editor.focus()
|
|
||||||
},
|
},
|
||||||
tabSelectedHandler: expandPanel
|
tabSelectedHandler: expandPanel
|
||||||
});
|
});
|
||||||
@@ -417,8 +416,7 @@ export class ProfilerEditor extends EditorPane {
|
|||||||
title: nls.localize('details', "Details"),
|
title: nls.localize('details', "Details"),
|
||||||
view: {
|
view: {
|
||||||
layout: dim => this._detailTable.layout(dim),
|
layout: dim => this._detailTable.layout(dim),
|
||||||
render: parent => parent.appendChild(detailTableContainer),
|
render: parent => parent.appendChild(detailTableContainer)
|
||||||
focus: () => this._detailTable.focus()
|
|
||||||
},
|
},
|
||||||
tabSelectedHandler: expandPanel
|
tabSelectedHandler: expandPanel
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -63,9 +63,6 @@ export class QueryModelViewTabView implements IPanelView {
|
|||||||
public layout(dimension: Dimension): void {
|
public layout(dimension: Dimension): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
public focus(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
public get componentId(): string {
|
public get componentId(): string {
|
||||||
return this.state.componentId;
|
return this.state.componentId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,10 +44,6 @@ class MessagesView extends Disposable implements IPanelView {
|
|||||||
this.messagePanel.layout(dimension);
|
this.messagePanel.layout(dimension);
|
||||||
}
|
}
|
||||||
|
|
||||||
focus(): void {
|
|
||||||
this.messagePanel.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear() {
|
public clear() {
|
||||||
this.messagePanel.clear();
|
this.messagePanel.clear();
|
||||||
}
|
}
|
||||||
@@ -83,10 +79,6 @@ class ResultsView extends Disposable implements IPanelView {
|
|||||||
this.gridPanel.layout(dimension);
|
this.gridPanel.layout(dimension);
|
||||||
}
|
}
|
||||||
|
|
||||||
focus(): void {
|
|
||||||
this.gridPanel.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear() {
|
public clear() {
|
||||||
this.gridPanel.clear();
|
this.gridPanel.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,10 +58,6 @@ export class QueryPlanView implements IPanelView {
|
|||||||
this.container.style.height = dimension.height + 'px';
|
this.container.style.height = dimension.height + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
public focus() {
|
|
||||||
this.container.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear() {
|
public clear() {
|
||||||
if (this.qp) {
|
if (this.qp) {
|
||||||
this.qp.xml = undefined;
|
this.qp.xml = undefined;
|
||||||
|
|||||||
@@ -47,13 +47,6 @@ export class QueryPlanEditor extends EditorPane {
|
|||||||
this.view.render(parent);
|
this.view.render(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets focus on this editor. Specifically, it sets the focus on the hosted text editor.
|
|
||||||
*/
|
|
||||||
public override focus(): void {
|
|
||||||
this.view.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the internal variable keeping track of the editor's size, and re-calculates the sash position.
|
* Updates the internal variable keeping track of the editor's size, and re-calculates the sash position.
|
||||||
* To be called when the container of this editor changes size.
|
* To be called when the container of this editor changes size.
|
||||||
|
|||||||
@@ -77,10 +77,6 @@ export class TopOperationsView extends Disposable implements IPanelView {
|
|||||||
this.table.layout(dimension);
|
this.table.layout(dimension);
|
||||||
}
|
}
|
||||||
|
|
||||||
public focus(): void {
|
|
||||||
this.table.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear() {
|
public clear() {
|
||||||
this.dataView.clear();
|
this.dataView.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -281,10 +281,6 @@ export class ConnectionBrowserView extends Disposable implements IPanelView {
|
|||||||
this.treeContainer.style.height = `${treeHeight}px`;
|
this.treeContainer.style.height = `${treeHeight}px`;
|
||||||
this.tree.layout(treeHeight, dimension.width);
|
this.tree.layout(treeHeight, dimension.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
focus(): void {
|
|
||||||
this.filterInput.focus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITreeItemFromProvider {
|
export interface ITreeItemFromProvider {
|
||||||
|
|||||||
@@ -191,9 +191,6 @@ export class ConnectionDialogWidget extends Modal {
|
|||||||
},
|
},
|
||||||
layout: (dimension: DOM.Dimension) => {
|
layout: (dimension: DOM.Dimension) => {
|
||||||
this._recentConnectionTree.layout(dimension.height - DOM.getTotalHeight(this._recentConnectionActionBarContainer));
|
this._recentConnectionTree.layout(dimension.height - DOM.getTotalHeight(this._recentConnectionActionBarContainer));
|
||||||
},
|
|
||||||
focus: () => {
|
|
||||||
this._actionbar.focus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { DialogPane } from 'sql/workbench/services/dialog/browser/dialogPane';
|
|||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { IBootstrapParams } from 'sql/workbench/services/bootstrap/common/bootstrapParams';
|
import { IBootstrapParams } from 'sql/workbench/services/bootstrap/common/bootstrapParams';
|
||||||
import { ComponentEventType } from 'sql/platform/dashboard/browser/interfaces';
|
import { ComponentEventType } from 'sql/platform/dashboard/browser/interfaces';
|
||||||
|
import { getFocusableElements } from 'sql/base/browser/dom';
|
||||||
|
|
||||||
export interface LayoutRequestParams {
|
export interface LayoutRequestParams {
|
||||||
modelViewId?: string;
|
modelViewId?: string;
|
||||||
@@ -20,6 +21,7 @@ export interface DialogComponentParams extends IBootstrapParams {
|
|||||||
validityChangedCallback: (valid: boolean) => void;
|
validityChangedCallback: (valid: boolean) => void;
|
||||||
onLayoutRequested: Event<LayoutRequestParams>;
|
onLayoutRequested: Event<LayoutRequestParams>;
|
||||||
dialogPane: DialogPane;
|
dialogPane: DialogPane;
|
||||||
|
setInitialFocus: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -62,12 +64,20 @@ export class DialogContainer implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
|
const element = <HTMLElement>this._el.nativeElement;
|
||||||
this._modelViewContent.onEvent(event => {
|
this._modelViewContent.onEvent(event => {
|
||||||
if (event.isRootComponent && event.eventType === ComponentEventType.validityChanged) {
|
if (event.isRootComponent && event.eventType === ComponentEventType.validityChanged) {
|
||||||
this._params.validityChangedCallback(event.args);
|
this._params.validityChangedCallback(event.args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set focus to the first focusable elements when the content is loaded and the focus is not currently inside the content area
|
||||||
|
if (this._params.setInitialFocus && event.isRootComponent && event.eventType === ComponentEventType.onComponentLoaded && !element.contains(document.activeElement)) {
|
||||||
|
const focusableElements = getFocusableElements(element);
|
||||||
|
if (focusableElements?.length > 0) {
|
||||||
|
focusableElements[0].focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
let element = <HTMLElement>this._el.nativeElement;
|
|
||||||
element.style.height = '100%';
|
element.style.height = '100%';
|
||||||
element.style.width = '100%';
|
element.style.width = '100%';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
|
|||||||
import { IThemable } from 'vs/base/common/styler';
|
import { IThemable } from 'vs/base/common/styler';
|
||||||
import { attachTabbedPanelStyler } from 'sql/workbench/common/styler';
|
import { attachTabbedPanelStyler } from 'sql/workbench/common/styler';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
|
import { getFocusableElements } from 'sql/base/browser/dom';
|
||||||
|
|
||||||
export class DialogPane extends Disposable implements IThemable {
|
export class DialogPane extends Disposable implements IThemable {
|
||||||
private _tabbedPanel: TabbedPanel | undefined;
|
private _tabbedPanel: TabbedPanel | undefined;
|
||||||
@@ -44,6 +45,7 @@ export class DialogPane extends Disposable implements IThemable {
|
|||||||
private _themeService: IThemeService,
|
private _themeService: IThemeService,
|
||||||
public displayPageTitle: boolean,
|
public displayPageTitle: boolean,
|
||||||
public description?: string,
|
public description?: string,
|
||||||
|
private setInitialFocus: boolean = true
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@@ -56,7 +58,7 @@ export class DialogPane extends Disposable implements IThemable {
|
|||||||
this._body = DOM.append(container, DOM.$('div.dialogModal-pane'));
|
this._body = DOM.append(container, DOM.$('div.dialogModal-pane'));
|
||||||
if (typeof this._content === 'string' || this._content.length < 2) {
|
if (typeof this._content === 'string' || this._content.length < 2) {
|
||||||
let modelViewId = typeof this._content === 'string' ? this._content : this._content[0].content;
|
let modelViewId = typeof this._content === 'string' ? this._content : this._content[0].content;
|
||||||
this.initializeModelViewContainer(this._body, modelViewId);
|
this.initializeModelViewContainer(this._body, modelViewId, undefined, this.setInitialFocus);
|
||||||
} else {
|
} else {
|
||||||
this._tabbedPanel = new TabbedPanel(this._body);
|
this._tabbedPanel = new TabbedPanel(this._body);
|
||||||
attachTabbedPanelStyler(this._tabbedPanel, this._themeService);
|
attachTabbedPanelStyler(this._tabbedPanel, this._themeService);
|
||||||
@@ -67,7 +69,8 @@ export class DialogPane extends Disposable implements IThemable {
|
|||||||
let tabContainer = document.createElement('div');
|
let tabContainer = document.createElement('div');
|
||||||
tabContainer.style.display = 'none';
|
tabContainer.style.display = 'none';
|
||||||
this._body.appendChild(tabContainer);
|
this._body.appendChild(tabContainer);
|
||||||
this.initializeModelViewContainer(tabContainer, tab.content, tab);
|
// Only set initial focus when the tab is active one.
|
||||||
|
this.initializeModelViewContainer(tabContainer, tab.content, tab, this.setInitialFocus && tabIndex === this._selectedTabIndex);
|
||||||
this._tabbedPanel!.onTabChange(e => {
|
this._tabbedPanel!.onTabChange(e => {
|
||||||
tabContainer.style.height = (this.getTabDimension().height - this._tabbedPanel!.headersize) + 'px';
|
tabContainer.style.height = (this.getTabDimension().height - this._tabbedPanel!.headersize) + 'px';
|
||||||
this._onLayoutChange.fire({ modelViewId: tab.content });
|
this._onLayoutChange.fire({ modelViewId: tab.content });
|
||||||
@@ -83,8 +86,7 @@ export class DialogPane extends Disposable implements IThemable {
|
|||||||
container.appendChild(tabContainer);
|
container.appendChild(tabContainer);
|
||||||
tabContainer.style.display = 'block';
|
tabContainer.style.display = 'block';
|
||||||
},
|
},
|
||||||
layout: (dimension) => { this.getTabDimension(); },
|
layout: (dimension) => { this.getTabDimension(); }
|
||||||
focus: () => { this.focus(); }
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -113,7 +115,7 @@ export class DialogPane extends Disposable implements IThemable {
|
|||||||
/**
|
/**
|
||||||
* Bootstrap angular for the dialog's model view controller with the given model view ID
|
* Bootstrap angular for the dialog's model view controller with the given model view ID
|
||||||
*/
|
*/
|
||||||
private initializeModelViewContainer(bodyContainer: HTMLElement, modelViewId: string, tab?: DialogTab) {
|
private initializeModelViewContainer(bodyContainer: HTMLElement, modelViewId: string, tab?: DialogTab, setInitialFocus: boolean = true) {
|
||||||
this._instantiationService.invokeFunction<void, any[]>(bootstrapAngular,
|
this._instantiationService.invokeFunction<void, any[]>(bootstrapAngular,
|
||||||
DialogModule,
|
DialogModule,
|
||||||
bodyContainer,
|
bodyContainer,
|
||||||
@@ -127,7 +129,8 @@ export class DialogPane extends Disposable implements IThemable {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLayoutRequested: this._onLayoutChange.event,
|
onLayoutRequested: this._onLayoutChange.event,
|
||||||
dialogPane: this
|
dialogPane: this,
|
||||||
|
setInitialFocus: setInitialFocus
|
||||||
} as DialogComponentParams,
|
} as DialogComponentParams,
|
||||||
undefined,
|
undefined,
|
||||||
(moduleRef: NgModuleRef<{}>) => {
|
(moduleRef: NgModuleRef<{}>) => {
|
||||||
@@ -147,8 +150,10 @@ export class DialogPane extends Disposable implements IThemable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private focus(): void {
|
private focus(): void {
|
||||||
let focusedElement = <HTMLElement>this._body.querySelector('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled])');
|
const focusableElements = getFocusableElements(this._body);
|
||||||
focusedElement ? focusedElement.focus() : this._body.focus();
|
if (focusableElements?.length > 0) {
|
||||||
|
focusableElements[0].focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -133,8 +133,8 @@ export class WizardModal extends Modal {
|
|||||||
this._mpContainer = append(this._body, $('div.dialog-message-and-page-container'));
|
this._mpContainer = append(this._body, $('div.dialog-message-and-page-container'));
|
||||||
this._pageContainer = append(this._mpContainer, $('div.dialogModal-page-container'));
|
this._pageContainer = append(this._mpContainer, $('div.dialogModal-page-container'));
|
||||||
|
|
||||||
this._wizard.pages.forEach(page => {
|
this._wizard.pages.forEach((page, index) => {
|
||||||
this.registerPage(page);
|
this.registerPage(page, index === 0); // only do auto-focus for the first page.
|
||||||
});
|
});
|
||||||
this._wizard.onPageAdded(page => {
|
this._wizard.onPageAdded(page => {
|
||||||
this.registerPage(page);
|
this.registerPage(page);
|
||||||
@@ -167,8 +167,8 @@ export class WizardModal extends Modal {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerPage(page: WizardPage): void {
|
private registerPage(page: WizardPage, setInitialFocus: boolean = false): void {
|
||||||
let dialogPane = new DialogPane(page.title, page.content, valid => page.notifyValidityChanged(valid), this._instantiationService, this._themeService, this._wizard.displayPageTitles, page.description);
|
let dialogPane = new DialogPane(page.title, page.content, valid => page.notifyValidityChanged(valid), this._instantiationService, this._themeService, this._wizard.displayPageTitles, page.description, setInitialFocus);
|
||||||
dialogPane.createBody(this._pageContainer);
|
dialogPane.createBody(this._pageContainer);
|
||||||
this._dialogPanes.set(page, dialogPane);
|
this._dialogPanes.set(page, dialogPane);
|
||||||
page.onUpdate(() => this.setButtonsForPage(this._wizard.currentPage));
|
page.onUpdate(() => this.setButtonsForPage(this._wizard.currentPage));
|
||||||
|
|||||||
@@ -334,8 +334,7 @@ export class RestoreDialog extends Modal {
|
|||||||
render: c => {
|
render: c => {
|
||||||
DOM.append(c, generalTab);
|
DOM.append(c, generalTab);
|
||||||
},
|
},
|
||||||
layout: () => { },
|
layout: () => { }
|
||||||
focus: () => this._restoreFromSelectBox ? this._restoreFromSelectBox.focus() : generalTab.focus()
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -346,8 +345,7 @@ export class RestoreDialog extends Modal {
|
|||||||
layout: () => { },
|
layout: () => { },
|
||||||
render: c => {
|
render: c => {
|
||||||
c.appendChild(fileContentElement);
|
c.appendChild(fileContentElement);
|
||||||
},
|
}
|
||||||
focus: () => this._optionsMap[this._relocateDatabaseFilesOption] ? this._optionsMap[this._relocateDatabaseFilesOption].focus() : fileContentElement.focus()
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -358,8 +356,7 @@ export class RestoreDialog extends Modal {
|
|||||||
layout: () => { },
|
layout: () => { },
|
||||||
render: c => {
|
render: c => {
|
||||||
c.appendChild(optionsContentElement);
|
c.appendChild(optionsContentElement);
|
||||||
},
|
}
|
||||||
focus: () => this._optionsMap[this._withReplaceDatabaseOption] ? this._optionsMap[this._withReplaceDatabaseOption].focus() : optionsContentElement.focus()
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user