diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index ad013173af7b72b4cf9917f13a8b66f774f7acc2..d883cc421bd30c1ff6fce2fb2c4f69fcda304d52 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -81,6 +81,10 @@ export class PagedList implements IDisposable { return this.list.getHTMLElement() === document.activeElement; } + domFocus(): void { + this.list.domFocus(); + } + get onDidFocus(): Event { return this.list.onDidFocus; } diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index be7c2da086cc6d9e7b8e9aa3cb6e0296dbe58ed9..5085813f79e62fdcf08814b2825582813374b5c7 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -447,7 +447,7 @@ export class QuickOpenWidget implements IModelProvider { // Transition into quick navigate mode if not yet done if (!this.quickNavigateConfiguration && quickNavigate) { this.quickNavigateConfiguration = quickNavigate; - this.tree.DOMFocus(); + this.tree.domFocus(); } // Navigate @@ -558,7 +558,7 @@ export class QuickOpenWidget implements IModelProvider { if (this.quickNavigateConfiguration) { this.inputContainer.hide(); this.builder.show(); - this.tree.DOMFocus(); + this.tree.domFocus(); } // Otherwise use normal UI @@ -783,7 +783,7 @@ export class QuickOpenWidget implements IModelProvider { // Clear Focus if (this.tree.isDOMFocused()) { - this.tree.DOMBlur(); + this.tree.domBlur(); } else if (this.inputBox.hasFocus()) { this.inputBox.blur(); } diff --git a/src/vs/base/parts/tree/browser/tree.ts b/src/vs/base/parts/tree/browser/tree.ts index 9ed4d108d3502aa596fbe22c68be6f41267094a7..0d66edf166760b282a3bffa306ee0417740653f4 100644 --- a/src/vs/base/parts/tree/browser/tree.ts +++ b/src/vs/base/parts/tree/browser/tree.ts @@ -60,7 +60,7 @@ export interface ITree { /** * Sets DOM focus on the tree. */ - DOMFocus(): void; + domFocus(): void; /** * Returns whether the tree has DOM focus. @@ -70,7 +70,7 @@ export interface ITree { /** * Removes DOM focus from the tree. */ - DOMBlur(): void; + domBlur(): void; /** * Refreshes an element. diff --git a/src/vs/base/parts/tree/browser/treeDefaults.ts b/src/vs/base/parts/tree/browser/treeDefaults.ts index 9f1cd3cd48d599d240d7afcf8330ae5e45e5de15..a4f43eb2ad7a383dbaf11f72e9085e0d8d3f203a 100644 --- a/src/vs/base/parts/tree/browser/treeDefaults.ts +++ b/src/vs/base/parts/tree/browser/treeDefaults.ts @@ -172,7 +172,7 @@ export class DefaultController implements _.IController { } eventish.stopPropagation(); - tree.DOMFocus(); + tree.domFocus(); tree.setSelection([element], payload); tree.setFocus(element, payload); @@ -458,7 +458,7 @@ export class CollapseAllAction extends Action { this.viewer.collapseAll(); this.viewer.clearSelection(); this.viewer.clearFocus(); - this.viewer.DOMFocus(); + this.viewer.domFocus(); this.viewer.focusFirst(); return TPromise.as(null); diff --git a/src/vs/base/parts/tree/browser/treeImpl.ts b/src/vs/base/parts/tree/browser/treeImpl.ts index 5306affe80c00e4e18a89c2e7a92cd8f066f4897..f7c9173df5a2b5686378a052bbf591ccb55321fb 100644 --- a/src/vs/base/parts/tree/browser/treeImpl.ts +++ b/src/vs/base/parts/tree/browser/treeImpl.ts @@ -126,7 +126,7 @@ export class Tree implements _.ITree { this.view.layout(height); } - public DOMFocus(): void { + public domFocus(): void { this.view.focus(); } @@ -134,7 +134,7 @@ export class Tree implements _.ITree { return this.view.isFocused(); } - public DOMBlur(): void { + public domBlur(): void { this.view.blur(); } diff --git a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts index 96e2ae6566dba525f3ddef420b9effaa195b87f1..839f6aa5e76e33fa20c4dfc6e6f37792bafb9d38 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts @@ -575,7 +575,7 @@ export class ReferenceWidget extends PeekViewWidget { } focus(): void { - this._tree.DOMFocus(); + this._tree.domFocus(); } protected _onTitleClick(e: MouseEvent): void { diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index 9500a954c6e62e21b033b66e56e65e32ccb5fb0b..f6eb4f24a61646aed28f92b09a28d012f545fb1e 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -198,7 +198,7 @@ class CustomTreeViewer extends Disposable implements ITreeViewer { } // Pass Focus to Viewer - this.tree.DOMFocus(); + this.tree.domFocus(); } } @@ -541,7 +541,7 @@ class TreeController extends WorkbenchTreeController { onHide: (wasCancelled?: boolean) => { if (wasCancelled) { - tree.DOMFocus(); + tree.domFocus(); } }, diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 95ad408e95efffe06dbb1167cc1316deeea14f22..93ca24c1b5b6c4cf8db5716f2dcf21ffc2aef093 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -161,7 +161,7 @@ export abstract class TreeViewsViewletPanel extends ViewsViewletPanel { } // Pass Focus to Viewer - this.tree.DOMFocus(); + this.tree.domFocus(); } dispose(): void { diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index ae4dc027589a8dde93f1c52c6fd384d6f38dbeac..43f5f4921046a23b8a695cc6f0128ccfab32b48c 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -170,7 +170,7 @@ export class CollapseAction extends Action { viewer.collapseAll(); viewer.clearSelection(); viewer.clearFocus(); - viewer.DOMFocus(); + viewer.domFocus(); viewer.focusFirst(); return TPromise.as(null); diff --git a/src/vs/workbench/electron-browser/commands.ts b/src/vs/workbench/electron-browser/commands.ts index 743df4104b1748e37ecb91c7e97ed789be837743..50a3c4d915ea206df3e8d7298a15ad242acdc49d 100644 --- a/src/vs/workbench/electron-browser/commands.ts +++ b/src/vs/workbench/electron-browser/commands.ts @@ -18,7 +18,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import URI from 'vs/base/common/uri'; import { IEditorOptions, Position as EditorPosition } from 'vs/platform/editor/common/editor'; -import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey } from 'vs/platform/list/browser/listService'; +import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget } from 'vs/platform/list/browser/listService'; import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { range } from 'vs/base/common/arrays'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -26,12 +26,25 @@ import { ITree } from 'vs/base/parts/tree/browser/tree'; // --- List Commands +function ensureDOMFocus(widget: ListWidget): void { + // it can happen that one of the commands is executed while + // DOM focus is within another focusable control within the + // list/tree item. therefor we should ensure that the + // list/tree has DOM focus again after the command ran. + if (widget && !widget.isDOMFocused()) { + widget.domFocus(); + } +} + export function registerCommands(): void { function focusDown(accessor: ServicesAccessor, arg2?: number): void { const focused = accessor.get(IListService).lastFocusedList; const count = typeof arg2 === 'number' ? arg2 : 1; + // Ensure DOM Focus + ensureDOMFocus(focused); + // List if (focused instanceof List || focused instanceof PagedList) { const list = focused; @@ -131,6 +144,9 @@ export function registerCommands(): void { const focused = accessor.get(IListService).lastFocusedList; const count = typeof arg2 === 'number' ? arg2 : 1; + // Ensure DOM Focus + ensureDOMFocus(focused); + // List if (focused instanceof List || focused instanceof PagedList) { const list = focused; @@ -261,6 +277,9 @@ export function registerCommands(): void { handler: (accessor) => { const focused = accessor.get(IListService).lastFocusedList; + // Ensure DOM Focus + ensureDOMFocus(focused); + // List if (focused instanceof List || focused instanceof PagedList) { const list = focused; @@ -287,6 +306,9 @@ export function registerCommands(): void { handler: (accessor) => { const focused = accessor.get(IListService).lastFocusedList; + // Ensure DOM Focus + ensureDOMFocus(focused); + // List if (focused instanceof List || focused instanceof PagedList) { const list = focused; @@ -324,6 +346,9 @@ export function registerCommands(): void { function listFocusFirst(accessor: ServicesAccessor, options?: { fromFocused: boolean }): void { const focused = accessor.get(IListService).lastFocusedList; + // Ensure DOM Focus + ensureDOMFocus(focused); + // List if (focused instanceof List || focused instanceof PagedList) { const list = focused; @@ -360,6 +385,9 @@ export function registerCommands(): void { function listFocusLast(accessor: ServicesAccessor, options?: { fromFocused: boolean }): void { const focused = accessor.get(IListService).lastFocusedList; + // Ensure DOM Focus + ensureDOMFocus(focused); + // List if (focused instanceof List || focused instanceof PagedList) { const list = focused; diff --git a/src/vs/workbench/parts/debug/browser/baseDebugView.ts b/src/vs/workbench/parts/debug/browser/baseDebugView.ts index 81e1c7d74838c2978f35e46775a5e566e72808de..c6d19251f14d858f43b7fbd215a04eb354b82d94 100644 --- a/src/vs/workbench/parts/debug/browser/baseDebugView.ts +++ b/src/vs/workbench/parts/debug/browser/baseDebugView.ts @@ -165,7 +165,7 @@ export function renderRenameBox(debugService: IDebugService, contextViewService: } } - tree.DOMFocus(); + tree.domFocus(); tree.setFocus(element); // need to remove the input box since this template will be reused. @@ -229,7 +229,7 @@ export class BaseDebugController extends WorkbenchTreeController { }), onHide: (wasCancelled?: boolean) => { if (wasCancelled) { - tree.DOMFocus(); + tree.domFocus(); } }, getActionsContext: () => element diff --git a/src/vs/workbench/parts/debug/electron-browser/debugHover.ts b/src/vs/workbench/parts/debug/electron-browser/debugHover.ts index c88f3ed0a6e266e3b5cec8c614d064ca2b30d2e4..be6ec7e4735433b675a4eff26adb29c051e431ad 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugHover.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugHover.ts @@ -281,7 +281,7 @@ export class DebugHoverWidget implements IContentWidget { this.scrollbar.scanDomNode(); if (focus) { this.editor.render(); - this.tree.DOMFocus(); + this.tree.domFocus(); } }); } diff --git a/src/vs/workbench/parts/files/electron-browser/fileActions.ts b/src/vs/workbench/parts/files/electron-browser/fileActions.ts index 3b3b3e5c975c8b088cc39aa4a5a6df5132528c4f..99311f97824f8b0eb16a6e8f8c7a6044eefca868 100644 --- a/src/vs/workbench/parts/files/electron-browser/fileActions.ts +++ b/src/vs/workbench/parts/files/electron-browser/fileActions.ts @@ -698,7 +698,7 @@ class BaseDeleteFileAction extends BaseFileAction { return this.choiceService.choose(Severity.Error, toErrorMessage(error, false), choices, choices.length - 1, true).then(choice => { // Focus back to tree - this.tree.DOMFocus(); + this.tree.domFocus(); if (this.useTrash) { @@ -878,7 +878,7 @@ class CopyFileAction extends BaseFileAction { this.tree.clearHighlight(); } - this.tree.DOMFocus(); + this.tree.domFocus(); return TPromise.as(null); } @@ -942,7 +942,7 @@ class PasteFileAction extends BaseFileAction { return void 0; }, error => this.onError(error)).then(() => { - this.tree.DOMFocus(); + this.tree.domFocus(); }); }, error => { this.onError(new Error(nls.localize('fileDeleted', "File to paste was deleted or moved meanwhile"))); @@ -1221,7 +1221,7 @@ export class FocusFilesExplorer extends Action { const view = viewlet.getExplorerView(); if (view) { view.setExpanded(true); - view.getViewer().DOMFocus(); + view.getViewer().domFocus(); } }); } diff --git a/src/vs/workbench/parts/files/electron-browser/fileCommands.ts b/src/vs/workbench/parts/files/electron-browser/fileCommands.ts index caffff2c5d558d8d88c4da4ae8f9620ffb7da0de..64efe0a1d094adf0d974b360afe5106c6c9940a7 100644 --- a/src/vs/workbench/parts/files/electron-browser/fileCommands.ts +++ b/src/vs/workbench/parts/files/electron-browser/fileCommands.ts @@ -340,7 +340,7 @@ CommandsRegistry.registerCommand({ // Remove highlight if (tree instanceof Tree) { tree.clearHighlight(); - tree.DOMFocus(); + tree.domFocus(); } globalResourceToCompare = getResourceForCommand(resource, listService, accessor.get(IWorkbenchEditorService)); diff --git a/src/vs/workbench/parts/files/electron-browser/views/explorerView.ts b/src/vs/workbench/parts/files/electron-browser/views/explorerView.ts index f025d71fee1f42a13410606632df06286f4cbea7..acac6760d6a7fe49f23e4f324973453e6d755fb1 100644 --- a/src/vs/workbench/parts/files/electron-browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/electron-browser/views/explorerView.ts @@ -299,7 +299,7 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView } // Pass Focus to Viewer - this.explorerViewer.DOMFocus(); + this.explorerViewer.domFocus(); keepFocus = true; } @@ -580,7 +580,7 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView // Ensure viewer has keyboard focus if event originates from viewer if (restoreFocus) { - this.explorerViewer.DOMFocus(); + this.explorerViewer.domFocus(); } }, errors.onUnexpectedError); } @@ -729,7 +729,7 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView } // Focus - this.explorerViewer.DOMFocus(); + this.explorerViewer.domFocus(); // Find resource to focus from active editor input if set let resourceToFocus: URI; diff --git a/src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts index 4ea35fb208922c7b0d3e6026222601ebe2c6f1ac..4cadfcc3d8323e33133bf83d8d818b174daf3dce 100644 --- a/src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts @@ -294,7 +294,7 @@ export class FileRenderer implements IRenderer { setTimeout(() => { if (!blur) { // https://github.com/Microsoft/vscode/issues/20269 - tree.DOMFocus(); + tree.domFocus(); } lifecycle.dispose(toDispose); container.removeChild(label.element); @@ -408,7 +408,7 @@ export class FileController extends WorkbenchTreeController implements IDisposab event.stopPropagation(); // Set DOM focus - tree.DOMFocus(); + tree.domFocus(); if (stat instanceof NewStatPlaceholder) { return true; } @@ -497,7 +497,7 @@ export class FileController extends WorkbenchTreeController implements IDisposab }, onHide: (wasCancelled?: boolean) => { if (wasCancelled) { - tree.DOMFocus(); + tree.domFocus(); } }, getActionsContext: () => selection && selection.indexOf(stat) >= 0 diff --git a/src/vs/workbench/parts/markers/browser/markersPanel.ts b/src/vs/workbench/parts/markers/browser/markersPanel.ts index 84b9cb51aae8ae9786b5d63a251b379700c30b03..24a9ca2c98ab7b2e1a25a90fb8d0717baf5f52f3 100644 --- a/src/vs/workbench/parts/markers/browser/markersPanel.ts +++ b/src/vs/workbench/parts/markers/browser/markersPanel.ts @@ -101,7 +101,7 @@ export class MarkersPanel extends Panel { } if (this.markersWorkbenchService.markersModel.hasFilteredResources()) { - this.tree.DOMFocus(); + this.tree.domFocus(); if (this.tree.getSelection().length === 0) { this.tree.focusFirst(); } diff --git a/src/vs/workbench/parts/markers/browser/markersTreeController.ts b/src/vs/workbench/parts/markers/browser/markersTreeController.ts index 8c6d21f3e6a708f9f579bb56738f5b2247aab0bd..fce03cf8240f2b22f39df61fdc328bb69d858d83 100644 --- a/src/vs/workbench/parts/markers/browser/markersTreeController.ts +++ b/src/vs/workbench/parts/markers/browser/markersTreeController.ts @@ -66,7 +66,7 @@ export class Controller extends WorkbenchTreeController { onHide: (wasCancelled?: boolean) => { if (wasCancelled) { - tree.DOMFocus(); + tree.domFocus(); } } }); diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index 75bb4be7c6f50292e0344c50231ca0454ae9b04e..004fede229ca558d45a89573c2f650178a6a3dd5 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -377,7 +377,7 @@ export class CollapseDeepestExpandedLevelAction extends Action { viewer.collapseDeepestExpandedLevel(); viewer.clearSelection(); viewer.clearFocus(); - viewer.DOMFocus(); + viewer.domFocus(); viewer.focusFirst(); } return TPromise.as(null); @@ -548,7 +548,7 @@ export class RemoveAction extends AbstractSearchAndReplaceAction { elementToRefresh = parent.count() === 0 ? parent.parent() : parent; } - this.viewer.DOMFocus(); + this.viewer.domFocus(); return this.viewer.refresh(elementToRefresh); } @@ -567,7 +567,7 @@ export class ReplaceAllAction extends AbstractSearchAndReplaceAction { if (nextFocusElement) { this.viewer.setFocus(nextFocusElement); } - this.viewer.DOMFocus(); + this.viewer.domFocus(); this.viewlet.open(this.fileMatch, true); }); } @@ -588,7 +588,7 @@ export class ReplaceAllInFolderAction extends AbstractSearchAndReplaceAction { if (nextFocusElement) { this.viewer.setFocus(nextFocusElement); } - this.viewer.DOMFocus(); + this.viewer.domFocus(); } } @@ -610,7 +610,7 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { this.viewer.setFocus(elementToFocus); } let elementToShowReplacePreview = this.getElementToShowReplacePreview(elementToFocus); - this.viewer.DOMFocus(); + this.viewer.domFocus(); if (!elementToShowReplacePreview || this.hasToOpenFile()) { this.viewlet.open(this.element, true); } else { diff --git a/src/vs/workbench/parts/search/browser/searchView.ts b/src/vs/workbench/parts/search/browser/searchView.ts index 0a3a95a4a892d9db335c3c1e345aa21e991ef08f..2341f979592f97ae04e5e7fe65fe054b5b904b2c 100644 --- a/src/vs/workbench/parts/search/browser/searchView.ts +++ b/src/vs/workbench/parts/search/browser/searchView.ts @@ -827,7 +827,7 @@ export class SearchView extends Viewlet implements IViewlet, IPanel { private selectTreeIfNotSelected(): void { if (this.tree.getInput()) { - this.tree.DOMFocus(); + this.tree.domFocus(); let selection = this.tree.getSelection(); if (selection.length === 0) { this.tree.focusNext();