mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-07 17:23:56 -05:00
Merge from vscode aba87f135229c17c4624341b7a2499dcedafcb87 (#6430)
* Merge from vscode aba87f135229c17c4624341b7a2499dcedafcb87 * fix compile errors
This commit is contained in:
@@ -7,31 +7,27 @@ import * as DOM from 'vs/base/browser/dom';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
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 { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
|
||||
import { IWebviewService, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, Webview } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, Webview, WebviewEditorOverlay } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
|
||||
export class WebviewEditor extends BaseEditor {
|
||||
|
||||
public static readonly ID = 'WebviewEditor';
|
||||
|
||||
private _webview: Webview | undefined;
|
||||
private readonly _scopedContextKeyService = this._register(new MutableDisposable<IContextKeyService>());
|
||||
private _findWidgetVisible: IContextKey<boolean>;
|
||||
|
||||
private _editorFrame: HTMLElement;
|
||||
private _editorFrame?: HTMLElement;
|
||||
private _content?: HTMLElement;
|
||||
private _webviewContent: HTMLElement | undefined;
|
||||
|
||||
private readonly _webviewFocusTrackerDisposables = this._register(new DisposableStore());
|
||||
private readonly _onFocusWindowHandler = this._register(new MutableDisposable());
|
||||
@@ -39,22 +35,21 @@ export class WebviewEditor extends BaseEditor {
|
||||
private readonly _onDidFocusWebview = this._register(new Emitter<void>());
|
||||
public get onDidFocus(): Event<any> { return this._onDidFocusWebview.event; }
|
||||
|
||||
private _pendingMessages: any[] = [];
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IContextKeyService private _contextKeyService: IContextKeyService,
|
||||
@IWebviewService private readonly _webviewService: IWebviewService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IWindowService private readonly _windowService: IWindowService,
|
||||
@IStorageService storageService: IStorageService
|
||||
) {
|
||||
super(WebviewEditor.ID, telemetryService, themeService, storageService);
|
||||
if (_contextKeyService) {
|
||||
this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(_contextKeyService);
|
||||
}
|
||||
|
||||
this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(_contextKeyService);
|
||||
}
|
||||
|
||||
public get isWebviewEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected createEditor(parent: HTMLElement): void {
|
||||
@@ -63,58 +58,25 @@ export class WebviewEditor extends BaseEditor {
|
||||
parent.appendChild(this._content);
|
||||
}
|
||||
|
||||
private doUpdateContainer() {
|
||||
const webviewContainer = this.input && (this.input as WebviewEditorInput).container;
|
||||
if (webviewContainer && webviewContainer.parentElement) {
|
||||
const frameRect = this._editorFrame.getBoundingClientRect();
|
||||
const containerRect = webviewContainer.parentElement.getBoundingClientRect();
|
||||
|
||||
webviewContainer.style.position = 'absolute';
|
||||
webviewContainer.style.top = `${frameRect.top - containerRect.top}px`;
|
||||
webviewContainer.style.left = `${frameRect.left - containerRect.left}px`;
|
||||
webviewContainer.style.width = `${frameRect.width}px`;
|
||||
webviewContainer.style.height = `${frameRect.height}px`;
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._pendingMessages = [];
|
||||
|
||||
// Let the editor input dispose of the webview.
|
||||
this._webview = undefined;
|
||||
this._webviewContent = undefined;
|
||||
|
||||
if (this._content && this._content.parentElement) {
|
||||
this._content.parentElement.removeChild(this._content);
|
||||
if (this._content) {
|
||||
this._content.remove();
|
||||
this._content = undefined;
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public sendMessage(data: any): void {
|
||||
if (this._webview) {
|
||||
this._webview.sendMessage(data);
|
||||
} else {
|
||||
this._pendingMessages.push(data);
|
||||
}
|
||||
}
|
||||
public showFind() {
|
||||
if (this._webview) {
|
||||
this._webview.showFind();
|
||||
this.withWebview(webview => {
|
||||
webview.showFind();
|
||||
this._findWidgetVisible.set(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public hideFind() {
|
||||
this._findWidgetVisible.reset();
|
||||
if (this._webview) {
|
||||
this._webview.hideFind();
|
||||
}
|
||||
}
|
||||
|
||||
public get isWebviewEditor() {
|
||||
return true;
|
||||
this.withWebview(webview => webview.hideFind());
|
||||
}
|
||||
|
||||
public reload() {
|
||||
@@ -122,16 +84,15 @@ export class WebviewEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
public layout(_dimension: DOM.Dimension): void {
|
||||
this.withWebview(webview => {
|
||||
this.doUpdateContainer();
|
||||
webview.layout();
|
||||
});
|
||||
if (this.input && this.input instanceof WebviewEditorInput) {
|
||||
this.synchronizeWebviewContainerDimensions(this.input.webview);
|
||||
this.input.webview.layout();
|
||||
}
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
super.focus();
|
||||
if (!this._onFocusWindowHandler.value) {
|
||||
|
||||
// Make sure we restore focus when switching back to a VS Code window
|
||||
this._onFocusWindowHandler.value = this._windowService.onDidChangeFocus(focused => {
|
||||
if (focused && this._editorService.activeControl === this) {
|
||||
@@ -143,29 +104,20 @@ export class WebviewEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
public withWebview(f: (element: Webview) => void): void {
|
||||
if (this._webview) {
|
||||
f(this._webview);
|
||||
if (this.input && this.input instanceof WebviewEditorInput) {
|
||||
f(this.input.webview);
|
||||
}
|
||||
}
|
||||
|
||||
protected setEditorVisible(visible: boolean, group: IEditorGroup): void {
|
||||
if (this.input && this.input instanceof WebviewEditorInput) {
|
||||
const webview = this.input && (this.input as WebviewEditorInput).webview;
|
||||
if (webview) {
|
||||
if (visible) {
|
||||
this.input.claimWebview(this);
|
||||
webview.claim(this);
|
||||
} else {
|
||||
this.input.releaseWebview(this);
|
||||
}
|
||||
|
||||
this.updateWebview(this.input as WebviewEditorInput);
|
||||
}
|
||||
|
||||
if (this._webviewContent) {
|
||||
if (visible) {
|
||||
this._webviewContent.style.visibility = 'visible';
|
||||
this.doUpdateContainer();
|
||||
} else {
|
||||
this._webviewContent.style.visibility = 'hidden';
|
||||
webview.release(this);
|
||||
}
|
||||
this.claimWebview(this.input as WebviewEditorInput);
|
||||
}
|
||||
|
||||
super.setEditorVisible(visible, group);
|
||||
@@ -173,115 +125,69 @@ export class WebviewEditor extends BaseEditor {
|
||||
|
||||
public clearInput() {
|
||||
if (this.input && this.input instanceof WebviewEditorInput) {
|
||||
this.input.releaseWebview(this);
|
||||
this.input.webview.release(this);
|
||||
}
|
||||
|
||||
this._webview = undefined;
|
||||
this._webviewContent = undefined;
|
||||
this._pendingMessages = [];
|
||||
|
||||
super.clearInput();
|
||||
}
|
||||
|
||||
setInput(input: WebviewEditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
if (this.input) {
|
||||
(this.input as WebviewEditorInput).releaseWebview(this);
|
||||
this._webview = undefined;
|
||||
this._webviewContent = undefined;
|
||||
public async setInput(input: WebviewEditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
if (this.input && this.input instanceof WebviewEditorInput) {
|
||||
this.input.webview.release(this);
|
||||
}
|
||||
this._pendingMessages = [];
|
||||
return super.setInput(input, options, token)
|
||||
.then(() => input.resolve())
|
||||
.then(() => {
|
||||
if (token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
if (this.group) {
|
||||
input.updateGroup(this.group.id);
|
||||
}
|
||||
this.updateWebview(input);
|
||||
});
|
||||
|
||||
await super.setInput(input, options, token);
|
||||
await input.resolve();
|
||||
if (token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.group) {
|
||||
input.updateGroup(this.group.id);
|
||||
}
|
||||
|
||||
this.claimWebview(input);
|
||||
}
|
||||
|
||||
private updateWebview(input: WebviewEditorInput) {
|
||||
const webview = this.getWebview(input);
|
||||
input.claimWebview(this);
|
||||
webview.update(input.html, {
|
||||
allowScripts: input.options.enableScripts,
|
||||
localResourceRoots: input.options.localResourceRoots || this.getDefaultLocalResourceRoots(),
|
||||
portMappings: input.options.portMapping,
|
||||
}, !!input.options.retainContextWhenHidden);
|
||||
private claimWebview(input: WebviewEditorInput): void {
|
||||
input.webview.claim(this);
|
||||
|
||||
if (this._webviewContent) {
|
||||
this._webviewContent.style.visibility = 'visible';
|
||||
if (input.webview.options.enableFindWidget) {
|
||||
this._scopedContextKeyService.value = this._contextKeyService.createScoped(input.webview.container);
|
||||
this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(this._scopedContextKeyService.value);
|
||||
}
|
||||
|
||||
this.doUpdateContainer();
|
||||
if (this._content) {
|
||||
this._content.setAttribute('aria-flowto', input.webview.container.id);
|
||||
}
|
||||
|
||||
this.synchronizeWebviewContainerDimensions(input.webview);
|
||||
this.trackFocus(input.webview);
|
||||
}
|
||||
|
||||
private getDefaultLocalResourceRoots(): URI[] {
|
||||
const rootPaths = this._contextService.getWorkspace().folders.map(x => x.uri);
|
||||
const extension = (this.input as WebviewEditorInput).extension;
|
||||
if (extension) {
|
||||
rootPaths.push(extension.location);
|
||||
private synchronizeWebviewContainerDimensions(webview: WebviewEditorOverlay) {
|
||||
const webviewContainer = webview.container;
|
||||
if (webviewContainer && webviewContainer.parentElement && this._editorFrame) {
|
||||
const frameRect = this._editorFrame.getBoundingClientRect();
|
||||
const containerRect = webviewContainer.parentElement.getBoundingClientRect();
|
||||
|
||||
webviewContainer.style.position = 'absolute';
|
||||
webviewContainer.style.top = `${frameRect.top - containerRect.top}px`;
|
||||
webviewContainer.style.left = `${frameRect.left - containerRect.left}px`;
|
||||
webviewContainer.style.width = `${frameRect.width}px`;
|
||||
webviewContainer.style.height = `${frameRect.height}px`;
|
||||
}
|
||||
return rootPaths;
|
||||
}
|
||||
|
||||
private getWebview(input: WebviewEditorInput): Webview {
|
||||
if (this._webview) {
|
||||
return this._webview;
|
||||
}
|
||||
|
||||
this._webviewContent = input.container;
|
||||
|
||||
if (input.webview) {
|
||||
this._webview = input.webview;
|
||||
} else {
|
||||
if (input.options.enableFindWidget) {
|
||||
this._contextKeyService = this._register(this._contextKeyService.createScoped(this._webviewContent));
|
||||
this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService);
|
||||
}
|
||||
|
||||
this._webview = this._webviewService.createWebview(input.id,
|
||||
{
|
||||
allowSvgs: true,
|
||||
extension: input.extension,
|
||||
enableFindWidget: input.options.enableFindWidget
|
||||
}, {});
|
||||
this._webview.mountTo(this._webviewContent);
|
||||
input.webview = this._webview;
|
||||
|
||||
if (input.options.tryRestoreScrollPosition) {
|
||||
this._webview.initialScrollProgress = input.scrollYPercentage;
|
||||
}
|
||||
|
||||
this._webview.state = input.state ? input.state.state : undefined;
|
||||
|
||||
this._content!.setAttribute('aria-flowto', this._webviewContent.id);
|
||||
|
||||
this.doUpdateContainer();
|
||||
}
|
||||
|
||||
for (const message of this._pendingMessages) {
|
||||
this._webview.sendMessage(message);
|
||||
}
|
||||
this._pendingMessages = [];
|
||||
|
||||
this.trackFocus();
|
||||
|
||||
return this._webview;
|
||||
}
|
||||
|
||||
private trackFocus() {
|
||||
private trackFocus(webview: WebviewEditorOverlay): void {
|
||||
this._webviewFocusTrackerDisposables.clear();
|
||||
|
||||
// Track focus in webview content
|
||||
const webviewContentFocusTracker = DOM.trackFocus(this._webviewContent!);
|
||||
const webviewContentFocusTracker = DOM.trackFocus(webview.container);
|
||||
this._webviewFocusTrackerDisposables.add(webviewContentFocusTracker);
|
||||
this._webviewFocusTrackerDisposables.add(webviewContentFocusTracker.onDidFocus(() => this._onDidFocusWebview.fire()));
|
||||
|
||||
// Track focus in webview element
|
||||
this._webviewFocusTrackerDisposables.add(this._webview!.onDidFocus(() => this._onDidFocusWebview.fire()));
|
||||
this._webviewFocusTrackerDisposables.add(webview.onDidFocus(() => this._onDidFocusWebview.fire()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IEditorModel } from 'vs/platform/editor/common/editor';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { EditorInput, EditorModel, GroupIdentifier, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { Webview, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { WebviewEvents, WebviewInputOptions } from './webviewEditorService';
|
||||
import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/common/webview';
|
||||
|
||||
class WebviewIconsManager {
|
||||
private readonly _icons = new Map<string, { light: URI, dark: URI }>();
|
||||
@@ -53,77 +49,38 @@ class WebviewIconsManager {
|
||||
}
|
||||
}
|
||||
|
||||
export class WebviewEditorInput<State = any> extends EditorInput {
|
||||
|
||||
private readonly iconsManager = new WebviewIconsManager();
|
||||
export class WebviewEditorInput extends EditorInput {
|
||||
|
||||
public static readonly typeId = 'workbench.editors.webviewInput';
|
||||
|
||||
private static readonly iconsManager = new WebviewIconsManager();
|
||||
|
||||
private _name: string;
|
||||
private _iconPath?: { light: URI, dark: URI };
|
||||
private _options: WebviewInputOptions;
|
||||
private _html: string = '';
|
||||
private _currentWebviewHtml: string = '';
|
||||
public _events: WebviewEvents | undefined;
|
||||
private _container?: HTMLElement;
|
||||
private _webview?: Webview;
|
||||
private _webviewOwner: any;
|
||||
private readonly _webviewDisposables = this._register(new DisposableStore());
|
||||
private _group?: GroupIdentifier;
|
||||
private _scrollYPercentage: number = 0;
|
||||
private _state: State;
|
||||
|
||||
public readonly extension?: {
|
||||
readonly location: URI;
|
||||
readonly id: ExtensionIdentifier;
|
||||
};
|
||||
|
||||
constructor(
|
||||
public readonly id: string,
|
||||
public readonly viewType: string,
|
||||
name: string,
|
||||
options: WebviewInputOptions,
|
||||
state: State,
|
||||
events: WebviewEvents,
|
||||
extension: undefined | {
|
||||
public readonly extension: undefined | {
|
||||
readonly location: URI;
|
||||
readonly id: ExtensionIdentifier;
|
||||
},
|
||||
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
|
||||
public readonly webview: WebviewEditorOverlay,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._name = name;
|
||||
this._options = options;
|
||||
this._events = events;
|
||||
this._state = state;
|
||||
this.extension = extension;
|
||||
|
||||
this._register(webview); // The input owns this webview
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
return WebviewEditorInput.typeId;
|
||||
}
|
||||
|
||||
private readonly _onDidChangeIcon = this._register(new Emitter<void>());
|
||||
public readonly onDidChangeIcon = this._onDidChangeIcon.event;
|
||||
|
||||
public dispose() {
|
||||
this.disposeWebview();
|
||||
|
||||
if (this._container) {
|
||||
this._container.remove();
|
||||
this._container = undefined;
|
||||
}
|
||||
|
||||
if (this._events && this._events.onDispose) {
|
||||
this._events.onDispose();
|
||||
}
|
||||
this._events = undefined;
|
||||
|
||||
this._webview = undefined;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public getResource(): URI {
|
||||
return URI.from({
|
||||
scheme: 'webview-panel',
|
||||
@@ -154,7 +111,7 @@ export class WebviewEditorInput<State = any> extends EditorInput {
|
||||
|
||||
public set iconPath(value: { light: URI, dark: URI } | undefined) {
|
||||
this._iconPath = value;
|
||||
this.iconsManager.setIcons(this.id, value);
|
||||
WebviewEditorInput.iconsManager.setIcons(this.id, value);
|
||||
}
|
||||
|
||||
public matches(other: IEditorInput): boolean {
|
||||
@@ -165,145 +122,19 @@ export class WebviewEditorInput<State = any> extends EditorInput {
|
||||
return this._group;
|
||||
}
|
||||
|
||||
public get html(): string {
|
||||
return this._html;
|
||||
}
|
||||
|
||||
public set html(value: string) {
|
||||
if (value === this._currentWebviewHtml) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._html = value;
|
||||
|
||||
if (this._webview) {
|
||||
this._webview.html = value;
|
||||
this._currentWebviewHtml = value;
|
||||
}
|
||||
}
|
||||
|
||||
public get state(): State {
|
||||
return this._state;
|
||||
}
|
||||
|
||||
public set state(value: State) {
|
||||
this._state = value;
|
||||
}
|
||||
|
||||
public get options(): WebviewInputOptions {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
public setOptions(value: WebviewOptions) {
|
||||
this._options = {
|
||||
...this._options,
|
||||
...value
|
||||
};
|
||||
|
||||
if (this._webview) {
|
||||
this._webview.options = {
|
||||
allowScripts: this._options.enableScripts,
|
||||
localResourceRoots: this._options.localResourceRoots,
|
||||
portMappings: this._options.portMapping,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public resolve(): Promise<IEditorModel> {
|
||||
return Promise.resolve(new EditorModel());
|
||||
public async resolve(): Promise<IEditorModel> {
|
||||
return new EditorModel();
|
||||
}
|
||||
|
||||
public supportsSplitEditor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public get container(): HTMLElement {
|
||||
if (!this._container) {
|
||||
this._container = document.createElement('div');
|
||||
this._container.id = `webview-${this.id}`;
|
||||
const part = this._layoutService.getContainer(Parts.EDITOR_PART);
|
||||
part.appendChild(this._container);
|
||||
}
|
||||
return this._container;
|
||||
}
|
||||
|
||||
public get webview(): Webview | undefined {
|
||||
return this._webview;
|
||||
}
|
||||
|
||||
public set webview(value: Webview | undefined) {
|
||||
this._webviewDisposables.clear();
|
||||
|
||||
this._webview = value;
|
||||
if (!this._webview) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._webview.onDidClickLink(link => {
|
||||
if (this._events && this._events.onDidClickLink) {
|
||||
this._events.onDidClickLink(link, this._options);
|
||||
}
|
||||
}, null, this._webviewDisposables);
|
||||
|
||||
this._webview.onMessage(message => {
|
||||
if (this._events && this._events.onMessage) {
|
||||
this._events.onMessage(message);
|
||||
}
|
||||
}, null, this._webviewDisposables);
|
||||
|
||||
this._webview.onDidScroll(message => {
|
||||
this._scrollYPercentage = message.scrollYPercentage;
|
||||
}, null, this._webviewDisposables);
|
||||
|
||||
this._webview.onDidUpdateState(newState => {
|
||||
if (this._events && this._events.onDidUpdateWebviewState) {
|
||||
this._events.onDidUpdateWebviewState(newState);
|
||||
}
|
||||
}, null, this._webviewDisposables);
|
||||
}
|
||||
|
||||
public get scrollYPercentage() {
|
||||
return this._scrollYPercentage;
|
||||
}
|
||||
|
||||
public claimWebview(owner: any) {
|
||||
this._webviewOwner = owner;
|
||||
}
|
||||
|
||||
public releaseWebview(owner: any) {
|
||||
if (this._webviewOwner === owner) {
|
||||
this._webviewOwner = undefined;
|
||||
if (this._options.retainContextWhenHidden && this._container) {
|
||||
this._container.style.visibility = 'hidden';
|
||||
} else {
|
||||
this.disposeWebview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public disposeWebview() {
|
||||
// The input owns the webview and its parent
|
||||
if (this._webview) {
|
||||
this._webview.dispose();
|
||||
this._webview = undefined;
|
||||
}
|
||||
|
||||
this._webviewDisposables.clear();
|
||||
this._webviewOwner = undefined;
|
||||
|
||||
if (this._container) {
|
||||
this._container.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
this._currentWebviewHtml = '';
|
||||
}
|
||||
|
||||
public updateGroup(group: GroupIdentifier): void {
|
||||
this._group = group;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class RevivedWebviewEditorInput extends WebviewEditorInput {
|
||||
private _revived: boolean = false;
|
||||
|
||||
@@ -311,17 +142,14 @@ export class RevivedWebviewEditorInput extends WebviewEditorInput {
|
||||
id: string,
|
||||
viewType: string,
|
||||
name: string,
|
||||
options: WebviewInputOptions,
|
||||
state: any,
|
||||
events: WebviewEvents,
|
||||
extension: undefined | {
|
||||
readonly location: URI;
|
||||
readonly id: ExtensionIdentifier
|
||||
},
|
||||
private readonly reviver: (input: WebviewEditorInput) => Promise<void>,
|
||||
@IWorkbenchLayoutService partService: IWorkbenchLayoutService,
|
||||
webview: WebviewEditorOverlay,
|
||||
) {
|
||||
super(id, viewType, name, options, state, events, extension, partService);
|
||||
super(id, viewType, name, extension, webview);
|
||||
}
|
||||
|
||||
public async resolve(): Promise<IEditorModel> {
|
||||
|
||||
@@ -45,10 +45,10 @@ export class WebviewEditorInputFactory implements IEditorInputFactory {
|
||||
const data: SerializedWebview = {
|
||||
viewType: input.viewType,
|
||||
title: input.getName(),
|
||||
options: input.options,
|
||||
options: input.webview.options,
|
||||
extensionLocation: input.extension ? input.extension.location : undefined,
|
||||
extensionId: input.extension && input.extension.id ? input.extension.id.value : undefined,
|
||||
state: input.state,
|
||||
state: input.webview.state,
|
||||
iconPath: input.iconPath ? { light: input.iconPath.light, dark: input.iconPath.dark, } : undefined,
|
||||
group: input.group
|
||||
};
|
||||
@@ -68,12 +68,15 @@ export class WebviewEditorInputFactory implements IEditorInputFactory {
|
||||
const extensionLocation = reviveUri(data.extensionLocation);
|
||||
const extensionId = data.extensionId ? new ExtensionIdentifier(data.extensionId) : undefined;
|
||||
const iconPath = reviveIconPath(data.iconPath);
|
||||
return this._webviewService.reviveWebview(generateUuid(), data.viewType, data.title, iconPath, data.state, data.options, extensionLocation ? {
|
||||
const state = reviveState(data.state);
|
||||
|
||||
return this._webviewService.reviveWebview(generateUuid(), data.viewType, data.title, iconPath, state, data.options, extensionLocation ? {
|
||||
location: extensionLocation,
|
||||
id: extensionId
|
||||
} : undefined, data.group);
|
||||
}
|
||||
}
|
||||
|
||||
function reviveIconPath(data: SerializedIconPath | undefined) {
|
||||
if (!data) {
|
||||
return undefined;
|
||||
@@ -98,3 +101,21 @@ function reviveUri(data: string | UriComponents | undefined): URI | undefined {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function reviveState(state: unknown | undefined): undefined | string {
|
||||
if (!state) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof state === 'string') {
|
||||
return state;
|
||||
}
|
||||
|
||||
// Likely an old style state. Unwrap to a simple state object
|
||||
// Remove after 1.37
|
||||
if ('state' in (state as any) && typeof (state as any).state === 'string') {
|
||||
return (state as any).state;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -7,13 +7,14 @@ import { equals } from 'vs/base/common/arrays';
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IWebviewOptions, IWebviewPanelOptions } from 'vs/editor/common/modes';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { GroupIdentifier } from 'vs/workbench/common/editor';
|
||||
import { IWebviewService, WebviewOptions, WebviewContentOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ACTIVE_GROUP_TYPE, IEditorService, SIDE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { RevivedWebviewEditorInput, WebviewEditorInput } from './webviewEditorInput';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
export const IWebviewEditorService = createDecorator<IWebviewEditorService>('webviewEditorService');
|
||||
|
||||
@@ -35,7 +36,6 @@ export interface IWebviewEditorService {
|
||||
location: URI,
|
||||
id: ExtensionIdentifier
|
||||
},
|
||||
events: WebviewEvents
|
||||
): WebviewEditorInput;
|
||||
|
||||
reviveWebview(
|
||||
@@ -77,25 +77,20 @@ export interface WebviewReviver {
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
export interface WebviewEvents {
|
||||
onMessage?(message: any): void;
|
||||
onDispose?(): void;
|
||||
onDidClickLink?(link: URI, options: IWebviewOptions): void;
|
||||
onDidUpdateWebviewState?(newState: any): void;
|
||||
}
|
||||
|
||||
export interface WebviewInputOptions extends IWebviewOptions, IWebviewPanelOptions {
|
||||
tryRestoreScrollPosition?: boolean;
|
||||
export interface WebviewInputOptions extends WebviewOptions, WebviewContentOptions {
|
||||
readonly tryRestoreScrollPosition?: boolean;
|
||||
readonly retainContextWhenHidden?: boolean;
|
||||
readonly enableCommandUris?: boolean;
|
||||
}
|
||||
|
||||
export function areWebviewInputOptionsEqual(a: WebviewInputOptions, b: WebviewInputOptions): boolean {
|
||||
return a.enableCommandUris === b.enableCommandUris
|
||||
&& a.enableFindWidget === b.enableFindWidget
|
||||
&& a.enableScripts === b.enableScripts
|
||||
&& a.allowScripts === b.allowScripts
|
||||
&& a.retainContextWhenHidden === b.retainContextWhenHidden
|
||||
&& a.tryRestoreScrollPosition === b.tryRestoreScrollPosition
|
||||
&& (a.localResourceRoots === b.localResourceRoots || (Array.isArray(a.localResourceRoots) && Array.isArray(b.localResourceRoots) && equals(a.localResourceRoots, b.localResourceRoots, (a, b) => a.toString() === b.toString())))
|
||||
&& (a.portMapping === b.portMapping || (Array.isArray(a.portMapping) && Array.isArray(b.portMapping) && equals(a.portMapping, b.portMapping, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort)));
|
||||
&& (a.portMappings === b.portMappings || (Array.isArray(a.portMappings) && Array.isArray(b.portMappings) && equals(a.portMappings, b.portMappings, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort)));
|
||||
}
|
||||
|
||||
function canRevive(reviver: WebviewReviver, webview: WebviewEditorInput): boolean {
|
||||
@@ -132,6 +127,8 @@ export class WebviewEditorService implements IWebviewEditorService {
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IWebviewService private readonly _webviewService: IWebviewService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
) { }
|
||||
|
||||
public createWebview(
|
||||
@@ -139,14 +136,15 @@ export class WebviewEditorService implements IWebviewEditorService {
|
||||
viewType: string,
|
||||
title: string,
|
||||
showOptions: ICreateWebViewShowOptions,
|
||||
options: IWebviewOptions,
|
||||
options: WebviewInputOptions,
|
||||
extension: undefined | {
|
||||
location: URI,
|
||||
id: ExtensionIdentifier
|
||||
},
|
||||
events: WebviewEvents
|
||||
): WebviewEditorInput {
|
||||
const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, id, viewType, title, options, {}, events, extension);
|
||||
const webview = this.createWebiew(id, extension, options);
|
||||
|
||||
const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, id, viewType, title, extension, webview);
|
||||
this._editorService.openEditor(webviewInput, { pinned: true, preserveFocus: showOptions.preserveFocus }, showOptions.group);
|
||||
return webviewInput;
|
||||
}
|
||||
@@ -175,11 +173,14 @@ export class WebviewEditorService implements IWebviewEditorService {
|
||||
options: WebviewInputOptions,
|
||||
extension: undefined | {
|
||||
readonly location: URI,
|
||||
readonly id?: ExtensionIdentifier
|
||||
readonly id: ExtensionIdentifier
|
||||
},
|
||||
group: number | undefined,
|
||||
): WebviewEditorInput {
|
||||
const webviewInput = this._instantiationService.createInstance(RevivedWebviewEditorInput, id, viewType, title, options, state, {}, extension, async (webview: WebviewEditorInput): Promise<void> => {
|
||||
const webview = this.createWebiew(id, extension, options);
|
||||
webview.state = state;
|
||||
|
||||
const webviewInput = new RevivedWebviewEditorInput(id, viewType, title, extension, async (webview: WebviewEditorInput): Promise<void> => {
|
||||
const didRevive = await this.tryRevive(webview);
|
||||
if (didRevive) {
|
||||
return Promise.resolve(undefined);
|
||||
@@ -190,8 +191,10 @@ export class WebviewEditorService implements IWebviewEditorService {
|
||||
const promise = new Promise<void>(r => { resolve = r; });
|
||||
this._revivalPool.add(webview, resolve!);
|
||||
return promise;
|
||||
});
|
||||
}, webview);
|
||||
|
||||
webviewInput.iconPath = iconPath;
|
||||
|
||||
if (typeof group === 'number') {
|
||||
webviewInput.updateGroup(group);
|
||||
}
|
||||
@@ -213,7 +216,7 @@ export class WebviewEditorService implements IWebviewEditorService {
|
||||
webview: WebviewEditorInput
|
||||
): boolean {
|
||||
// Has no state, don't persist
|
||||
if (!webview.state) {
|
||||
if (!webview.webview.state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -237,4 +240,27 @@ export class WebviewEditorService implements IWebviewEditorService {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private createWebiew(id: string, extension: { location: URI; id: ExtensionIdentifier; } | undefined, options: WebviewInputOptions) {
|
||||
return this._webviewService.createWebviewEditorOverlay(id, {
|
||||
allowSvgs: true,
|
||||
extension: extension,
|
||||
enableFindWidget: options.enableFindWidget,
|
||||
retainContextWhenHidden: options.retainContextWhenHidden
|
||||
}, {
|
||||
...options,
|
||||
localResourceRoots: options.localResourceRoots || this.getDefaultLocalResourceRoots(extension),
|
||||
});
|
||||
}
|
||||
|
||||
private getDefaultLocalResourceRoots(extension: undefined | {
|
||||
location: URI,
|
||||
id: ExtensionIdentifier
|
||||
}): URI[] {
|
||||
const rootPaths = this._contextService.getWorkspace().folders.map(x => x.uri);
|
||||
if (extension) {
|
||||
rootPaths.push(extension.location);
|
||||
}
|
||||
return rootPaths;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ export class IFrameWebview extends Disposable implements Webview {
|
||||
}
|
||||
}
|
||||
|
||||
public set options(options: WebviewContentOptions) {
|
||||
public set contentOptions(options: WebviewContentOptions) {
|
||||
if (areWebviewInputOptionsEqual(options, this.content.options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,14 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IFrameWebview as WebviewElement } from 'vs/workbench/contrib/webview/browser/webviewElement';
|
||||
import { IWebviewService, WebviewOptions, WebviewContentOptions, Webview } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { IFrameWebview } from 'vs/workbench/contrib/webview/browser/webviewElement';
|
||||
import { IWebviewService, Webview, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
|
||||
export class WebviewService implements IWebviewService {
|
||||
_serviceBrand: any;
|
||||
@@ -18,10 +23,178 @@ export class WebviewService implements IWebviewService {
|
||||
id: string,
|
||||
options: WebviewOptions,
|
||||
contentOptions: WebviewContentOptions
|
||||
): Webview {
|
||||
return this._instantiationService.createInstance(WebviewElement,
|
||||
id,
|
||||
options,
|
||||
contentOptions);
|
||||
): WebviewElement {
|
||||
return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions);
|
||||
}
|
||||
|
||||
createWebviewEditorOverlay(
|
||||
id: string,
|
||||
options: WebviewOptions,
|
||||
contentOptions: WebviewContentOptions,
|
||||
): WebviewEditorOverlay {
|
||||
return this._instantiationService.createInstance(DynamicWebviewEditorOverlay, id, options, contentOptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Webview editor overlay that creates and destroys the underlying webview as needed.
|
||||
*/
|
||||
class DynamicWebviewEditorOverlay extends Disposable implements WebviewEditorOverlay {
|
||||
|
||||
private readonly _pendingMessages = new Set<any>();
|
||||
private readonly _webview = this._register(new MutableDisposable<WebviewElement>());
|
||||
private readonly _webviewEvents = this._register(new DisposableStore());
|
||||
|
||||
private _html: string = '';
|
||||
private _initialScrollProgress: number = 0;
|
||||
private _state: string | undefined = undefined;
|
||||
private _owner: any = undefined;
|
||||
|
||||
public constructor(
|
||||
private readonly id: string,
|
||||
public readonly options: WebviewOptions,
|
||||
private _contentOptions: WebviewContentOptions,
|
||||
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
|
||||
@IWebviewService private readonly _webviewService: IWebviewService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(toDisposable(() => this.container.remove()));
|
||||
}
|
||||
|
||||
@memoize
|
||||
public get container() {
|
||||
const container = document.createElement('div');
|
||||
container.id = `webview-${this.id}`;
|
||||
this._layoutService.getContainer(Parts.EDITOR_PART).appendChild(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
public claim(owner: any) {
|
||||
this._owner = owner;
|
||||
this.show();
|
||||
}
|
||||
|
||||
public release(owner: any) {
|
||||
if (this._owner !== owner) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._owner = undefined;
|
||||
this.container.style.visibility = 'hidden';
|
||||
if (!this.options.retainContextWhenHidden) {
|
||||
this._webview.clear();
|
||||
this._webviewEvents.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private show() {
|
||||
if (!this._webview.value) {
|
||||
const webview = this._webviewService.createWebview(this.id, this.options, this._contentOptions);
|
||||
this._webview.value = webview;
|
||||
webview.state = this._state;
|
||||
webview.html = this._html;
|
||||
|
||||
if (this.options.tryRestoreScrollPosition) {
|
||||
webview.initialScrollProgress = this._initialScrollProgress;
|
||||
}
|
||||
|
||||
this._webview.value.mountTo(this.container);
|
||||
|
||||
this._webviewEvents.clear();
|
||||
|
||||
webview.onDidFocus(() => {
|
||||
this._onDidFocus.fire();
|
||||
}, undefined, this._webviewEvents);
|
||||
|
||||
webview.onDidClickLink(x => {
|
||||
this._onDidClickLink.fire(x);
|
||||
}, undefined, this._webviewEvents);
|
||||
|
||||
webview.onDidScroll(x => {
|
||||
this._initialScrollProgress = x.scrollYPercentage;
|
||||
this._onDidScroll.fire(x);
|
||||
}, undefined, this._webviewEvents);
|
||||
|
||||
webview.onDidUpdateState(state => {
|
||||
this._state = state;
|
||||
this._onDidUpdateState.fire(state);
|
||||
}, undefined, this._webviewEvents);
|
||||
|
||||
webview.onMessage(x => {
|
||||
this._onMessage.fire(x);
|
||||
}, undefined, this._webviewEvents);
|
||||
|
||||
this._pendingMessages.forEach(msg => webview.sendMessage(msg));
|
||||
this._pendingMessages.clear();
|
||||
}
|
||||
this.container.style.visibility = 'visible';
|
||||
}
|
||||
|
||||
public get html(): string { return this._html; }
|
||||
public set html(value: string) {
|
||||
this._html = value;
|
||||
this.withWebview(webview => webview.html = value);
|
||||
}
|
||||
|
||||
public get initialScrollProgress(): number { return this._initialScrollProgress; }
|
||||
public set initialScrollProgress(value: number) {
|
||||
this._initialScrollProgress = value;
|
||||
this.withWebview(webview => webview.initialScrollProgress = value);
|
||||
}
|
||||
|
||||
public get state(): string | undefined { return this._state; }
|
||||
public set state(value: string | undefined) {
|
||||
this._state = value;
|
||||
this.withWebview(webview => webview.state = value);
|
||||
}
|
||||
|
||||
public get contentOptions(): WebviewContentOptions { return this._contentOptions; }
|
||||
public set contentOptions(value: WebviewContentOptions) {
|
||||
this._contentOptions = value;
|
||||
this.withWebview(webview => webview.contentOptions = value);
|
||||
}
|
||||
|
||||
private readonly _onDidFocus = this._register(new Emitter<void>());
|
||||
public readonly onDidFocus: Event<void> = this._onDidFocus.event;
|
||||
|
||||
private readonly _onDidClickLink = this._register(new Emitter<URI>());
|
||||
public readonly onDidClickLink: Event<URI> = this._onDidClickLink.event;
|
||||
|
||||
private readonly _onDidScroll = this._register(new Emitter<{ scrollYPercentage: number; }>());
|
||||
public readonly onDidScroll: Event<{ scrollYPercentage: number; }> = this._onDidScroll.event;
|
||||
|
||||
private readonly _onDidUpdateState = this._register(new Emitter<string | undefined>());
|
||||
public readonly onDidUpdateState: Event<string | undefined> = this._onDidUpdateState.event;
|
||||
|
||||
private readonly _onMessage = this._register(new Emitter<any>());
|
||||
public readonly onMessage: Event<any> = this._onMessage.event;
|
||||
|
||||
sendMessage(data: any): void {
|
||||
if (this._webview.value) {
|
||||
this._webview.value.sendMessage(data);
|
||||
} else {
|
||||
this._pendingMessages.add(data);
|
||||
}
|
||||
}
|
||||
|
||||
update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean): void {
|
||||
this._contentOptions = options;
|
||||
this._html = html;
|
||||
this.withWebview(webview => {
|
||||
webview.update(html, options, retainContextWhenHidden);
|
||||
});
|
||||
}
|
||||
|
||||
layout(): void { this.withWebview(webview => webview.layout()); }
|
||||
focus(): void { this.withWebview(webview => webview.focus()); }
|
||||
reload(): void { this.withWebview(webview => webview.reload()); }
|
||||
showFind(): void { this.withWebview(webview => webview.showFind()); }
|
||||
hideFind(): void { this.withWebview(webview => webview.hideFind()); }
|
||||
|
||||
private withWebview(f: (webview: Webview) => void): void {
|
||||
if (this._webview.value) {
|
||||
f(this._webview.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,10 @@ import { Event } from 'vs/base/common/event';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import * as nls from 'vs/nls';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
/**
|
||||
* Set when the find widget in a webview is visible.
|
||||
@@ -29,7 +29,13 @@ export interface IWebviewService {
|
||||
id: string,
|
||||
options: WebviewOptions,
|
||||
contentOptions: WebviewContentOptions,
|
||||
): Webview;
|
||||
): WebviewElement;
|
||||
|
||||
createWebviewEditorOverlay(
|
||||
id: string,
|
||||
options: WebviewOptions,
|
||||
contentOptions: WebviewContentOptions,
|
||||
): WebviewEditorOverlay;
|
||||
}
|
||||
|
||||
export const WebviewResourceScheme = 'vscode-resource';
|
||||
@@ -41,6 +47,8 @@ export interface WebviewOptions {
|
||||
readonly id?: ExtensionIdentifier;
|
||||
};
|
||||
readonly enableFindWidget?: boolean;
|
||||
readonly tryRestoreScrollPosition?: boolean;
|
||||
readonly retainContextWhenHidden?: boolean;
|
||||
}
|
||||
|
||||
export interface WebviewContentOptions {
|
||||
@@ -48,12 +56,13 @@ export interface WebviewContentOptions {
|
||||
readonly svgWhiteList?: string[];
|
||||
readonly localResourceRoots?: ReadonlyArray<URI>;
|
||||
readonly portMappings?: ReadonlyArray<modes.IWebviewPortMapping>;
|
||||
readonly enableCommandUris?: boolean;
|
||||
}
|
||||
|
||||
export interface Webview extends IDisposable {
|
||||
|
||||
html: string;
|
||||
options: WebviewContentOptions;
|
||||
contentOptions: WebviewContentOptions;
|
||||
initialScrollProgress: number;
|
||||
state: string | undefined;
|
||||
|
||||
@@ -65,13 +74,12 @@ export interface Webview extends IDisposable {
|
||||
|
||||
sendMessage(data: any): void;
|
||||
update(
|
||||
value: string,
|
||||
html: string,
|
||||
options: WebviewContentOptions,
|
||||
retainContextWhenHidden: boolean
|
||||
): void;
|
||||
|
||||
layout(): void;
|
||||
mountTo(parent: HTMLElement): void;
|
||||
focus(): void;
|
||||
reload(): void;
|
||||
|
||||
@@ -79,4 +87,16 @@ export interface Webview extends IDisposable {
|
||||
hideFind(): void;
|
||||
}
|
||||
|
||||
export interface WebviewElement extends Webview {
|
||||
mountTo(parent: HTMLElement): void;
|
||||
}
|
||||
|
||||
export interface WebviewEditorOverlay extends Webview {
|
||||
readonly container: HTMLElement;
|
||||
readonly options: WebviewOptions;
|
||||
|
||||
claim(owner: any): void;
|
||||
release(owner: any): void;
|
||||
}
|
||||
|
||||
export const webviewDeveloperCategory = nls.localize('developer', "Developer");
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as nls from 'vs/nls';
|
||||
import { Command, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||
import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||
|
||||
export class OpenWebviewDeveloperToolsAction extends Action {
|
||||
static readonly ID = 'workbench.action.webview.openDeveloperTools';
|
||||
@@ -86,11 +86,11 @@ function getActiveWebviewEditor(accessor: ServicesAccessor): WebviewEditor | und
|
||||
return activeControl.isWebviewEditor ? activeControl : undefined;
|
||||
}
|
||||
|
||||
function withActiveWebviewBasedWebview(accessor: ServicesAccessor, f: (webview: WebviewElement) => void): void {
|
||||
function withActiveWebviewBasedWebview(accessor: ServicesAccessor, f: (webview: ElectronWebviewBasedWebview) => void): void {
|
||||
const webViewEditor = getActiveWebviewEditor(accessor);
|
||||
if (webViewEditor) {
|
||||
webViewEditor.withWebview(webview => {
|
||||
if (webview instanceof WebviewElement) {
|
||||
if (webview instanceof ElectronWebviewBasedWebview) {
|
||||
f(webview);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -13,7 +13,6 @@ import { endsWith } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
|
||||
@@ -25,27 +24,6 @@ import { registerFileProtocol } from 'vs/workbench/contrib/webview/electron-brow
|
||||
import { areWebviewInputOptionsEqual } from '../browser/webviewEditorService';
|
||||
import { WebviewFindWidget } from '../browser/webviewFindWidget';
|
||||
|
||||
export interface WebviewPortMapping {
|
||||
readonly port: number;
|
||||
readonly resolvedPort: number;
|
||||
}
|
||||
|
||||
export interface WebviewOptions {
|
||||
readonly allowSvgs?: boolean;
|
||||
readonly extension?: {
|
||||
readonly location: URI;
|
||||
readonly id?: ExtensionIdentifier;
|
||||
};
|
||||
readonly enableFindWidget?: boolean;
|
||||
}
|
||||
|
||||
export interface WebviewContentOptions {
|
||||
readonly allowScripts?: boolean;
|
||||
readonly svgWhiteList?: string[];
|
||||
readonly localResourceRoots?: ReadonlyArray<URI>;
|
||||
readonly portMappings?: ReadonlyArray<WebviewPortMapping>;
|
||||
}
|
||||
|
||||
interface IKeydownEvent {
|
||||
key: string;
|
||||
keyCode: number;
|
||||
@@ -285,7 +263,7 @@ interface WebviewContent {
|
||||
readonly state: string | undefined;
|
||||
}
|
||||
|
||||
export class WebviewElement extends Disposable implements Webview {
|
||||
export class ElectronWebviewBasedWebview extends Disposable implements Webview {
|
||||
private _webview: Electron.WebviewTag | undefined;
|
||||
private _ready: Promise<void>;
|
||||
|
||||
@@ -508,7 +486,7 @@ export class WebviewElement extends Disposable implements Webview {
|
||||
};
|
||||
}
|
||||
|
||||
public set options(options: WebviewContentOptions) {
|
||||
public set contentOptions(options: WebviewContentOptions) {
|
||||
if (areWebviewInputOptionsEqual(options, this.content.options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,23 +4,24 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IWebviewService, Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||
import { WebviewService as BrowserWebviewService } from 'vs/workbench/contrib/webview/browser/webviewService';
|
||||
import { IWebviewService, WebviewContentOptions, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||
|
||||
export class WebviewService implements IWebviewService {
|
||||
export class WebviewService extends BrowserWebviewService implements IWebviewService {
|
||||
_serviceBrand: any;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
) { }
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
) {
|
||||
super(instantiationService);
|
||||
}
|
||||
|
||||
createWebview(
|
||||
_id: string,
|
||||
options: WebviewOptions,
|
||||
contentOptions: WebviewContentOptions
|
||||
): Webview {
|
||||
return this._instantiationService.createInstance(WebviewElement,
|
||||
options,
|
||||
contentOptions);
|
||||
): WebviewElement {
|
||||
return this.instantiationService.createInstance(ElectronWebviewBasedWebview, options, contentOptions);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user