Fixes navigation commands for webviews
Fixes #100536 These commands currently do not work because: - The use the `hasFocus` check in layout.ts - This looks at the active element and checks if the active element has a parent in the editor dom - However webviews are outside of the normal dom flow (since they cannot be reparented without being destroyred) To fix this, this PR adds allows dom node to point to their explicit parent using `setParentFlowTo`. Instead of a normal ancestor check, we then check ancestors while observing the flow to parents of node The webview element is then update to have a parent flow to that points at its editor node
This commit is contained in:
parent
6e2aa0bfb7
commit
3338ff4e18
3 changed files with 44 additions and 4 deletions
|
@ -661,6 +661,43 @@ export function isAncestor(testChild: Node | null, testAncestor: Node | null): b
|
|||
return false;
|
||||
}
|
||||
|
||||
const parentFlowToDataKey = 'parentFlowToElementId';
|
||||
|
||||
/**
|
||||
* Set an explicit parent to use for nodes that are not part of the
|
||||
* regular dom structure.
|
||||
*/
|
||||
export function setParentFlowTo(fromChildElement: HTMLElement, toParentElement: Element): void {
|
||||
fromChildElement.dataset[parentFlowToDataKey] = toParentElement.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if `testAncestor` is an ancessor of `testChild`, observing the explicit
|
||||
* parents set by `setParentFlowTo`.
|
||||
*/
|
||||
export function isAncestorUsingFlowTo(testChild: Node, testAncestor: Node): boolean {
|
||||
let node: Node | null = testChild;
|
||||
while (node) {
|
||||
if (node === testAncestor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node instanceof HTMLElement) {
|
||||
const flowToParentId = node.dataset[parentFlowToDataKey];
|
||||
if (typeof flowToParentId === 'string') {
|
||||
const flowToParentElement = document.getElementById(flowToParentId);
|
||||
if (flowToParentElement) {
|
||||
node = flowToParentElement;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function findParentWithClass(node: HTMLElement, clazz: string, stopAtClazzOrNode?: string | HTMLElement): HTMLElement | null {
|
||||
while (node && node.nodeType === node.ELEMENT_NODE) {
|
||||
if (node.classList.contains(clazz)) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { EventType, addDisposableListener, isAncestor, getClientArea, Dimension, position, size, IDimension } from 'vs/base/browser/dom';
|
||||
import { EventType, addDisposableListener, getClientArea, Dimension, position, size, IDimension, isAncestorUsingFlowTo } from 'vs/base/browser/dom';
|
||||
import { onDidChangeFullscreen, isFullscreen } from 'vs/base/browser/browser';
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
|
@ -999,7 +999,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||
|
||||
const container = this.getContainer(part);
|
||||
|
||||
return !!container && isAncestor(activeElement, container);
|
||||
return !!container && isAncestorUsingFlowTo(activeElement, container);
|
||||
}
|
||||
|
||||
focusPart(part: Parts): void {
|
||||
|
|
|
@ -8,18 +8,19 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
|||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { IEditorDropService } from 'vs/workbench/services/editor/browser/editorDropService';
|
||||
import { EditorInput, EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { WebviewInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInput';
|
||||
import { IEditorDropService } from 'vs/workbench/services/editor/browser/editorDropService';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { WebviewInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInput';
|
||||
|
||||
export class WebviewEditor extends EditorPane {
|
||||
|
||||
|
@ -54,6 +55,7 @@ export class WebviewEditor extends EditorPane {
|
|||
protected createEditor(parent: HTMLElement): void {
|
||||
const element = document.createElement('div');
|
||||
this._element = element;
|
||||
this._element.id = `webview-editor-element-${generateUuid()}`;
|
||||
parent.appendChild(element);
|
||||
}
|
||||
|
||||
|
@ -143,6 +145,7 @@ export class WebviewEditor extends EditorPane {
|
|||
|
||||
if (this._element) {
|
||||
this._element.setAttribute('aria-flowto', input.webview.container.id);
|
||||
DOM.setParentFlowTo(input.webview.container, this._element);
|
||||
}
|
||||
|
||||
this._webviewVisibleDisposables.clear();
|
||||
|
|
Loading…
Reference in a new issue