diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 8dbb86be09a..bbc9aac5da3 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -1084,3 +1084,34 @@ export function hide(...elements: HTMLElement[]): void { element.style.display = 'none'; } } + +function findParentWithAttribute (node:HTMLElement, attribute:string):HTMLElement { + while (node) { + if (node.hasAttribute(attribute)) { + return node; + } + + node = node.parentNode; + } + + return null; +} + +export function removeTabIndexAndUpdateFocus(node: HTMLElement): void { + if (!node || !node.hasAttribute('tabIndex')) { + return; + } + + // If we are the currently focused element and tabIndex is removed, + // standard DOM behavior is to move focus to the element. We + // typically never want that, rather put focus to the closest element + // in the hierarchy of the parent DOM nodes. + if (document.activeElement === node) { + let parentFocusable = findParentWithAttribute(node.parentElement, 'tabIndex'); + if (parentFocusable) { + parentFocusable.focus(); + } + } + + this.$e.removeAttribute('tabindex'); +} \ No newline at end of file diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 975d2835f84..ac0ffe614a1 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -295,7 +295,7 @@ export class ActionItem extends BaseActionItem { } else { this.builder.addClass('disabled'); this.$e.addClass('disabled'); - this.$e.removeAttribute('tabindex'); + DOM.removeTabIndexAndUpdateFocus(this.$e.getHTMLElement()); } } diff --git a/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts index bd72ee3af24..067abb2e606 100644 --- a/src/vs/base/browser/ui/button/button.ts +++ b/src/vs/base/browser/ui/button/button.ts @@ -70,7 +70,7 @@ export class Button extends EventEmitter { } else { this.$el.addClass('disabled'); this.$el.attr('aria-disabled', String(true)); - this.$el.removeAttribute('tabIndex'); + DOM.removeTabIndexAndUpdateFocus(this.$el.getHTMLElement()); } } diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index 9500eff32c2..31677c97384 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -8,6 +8,7 @@ import 'vs/css!./checkbox'; import * as nls from 'vs/nls'; +import DOM = require('vs/base/browser/dom'); import {KeyCode} from 'vs/base/common/keyCodes'; import {Widget} from 'vs/base/browser/ui/widget'; import {StandardKeyboardEvent} from 'vs/base/browser/keyboardEvent'; @@ -90,7 +91,7 @@ export class Checkbox extends Widget { } public disable(): void { - this.domNode.removeAttribute('tabIndex'); + DOM.removeTabIndexAndUpdateFocus(this.domNode); this.domNode.setAttribute('aria-disabled', String(true)); } } diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index 162c0f98a86..54a7911023a 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -811,8 +811,7 @@ export class QuickOpenWidget implements IModelProvider { const relatedTarget = (e).relatedTarget; if (!this.quickNavigateConfiguration && DOM.isAncestor(relatedTarget, this.builder.getHTMLElement())) { - this.inputBox.focus(); // user clicked somewhere into quick open, so we restore focus to input - return; + return; // user clicked somewhere into quick open widget, do not close thereby } this.isLoosingFocus = true;