Split out Webview from WebviewEditor in proposed API (#47370)

* Split out `Webview` from `WebviewEditor` in API

**Problem**
The current proposed `Webview` interface has a few methods and properties that are very editor specific, such as `.reveal` and `.onDidChangeViewState`. These properies will not make sense if we ever allow webview to be displayed in other locations, such as in widgets

**Proposal**
Split the concepts of a `Webview` and of a `WebveiwEditor`. A webview is the html content itself. A `WebviewEditor` is an editor that displays a `Webview`

This would allow us to easily add other types of `Webview` owning objects in the future without having to document that some methods only apply when a webview is used as an editor vs as a widget
This commit is contained in:
Matt Bierner
2018-04-11 11:49:02 -07:00
committed by GitHub
parent 485a469b94
commit 8cb7e80544
9 changed files with 230 additions and 148 deletions

View File

@@ -12,58 +12,35 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from './extHostTypes';
export class ExtHostWebview implements vscode.Webview {
private readonly _handle: WebviewHandle;
private readonly _viewType: string;
private readonly _proxy: MainThreadWebviewsShape;
private _title: string;
private _html: string;
private _options: vscode.WebviewOptions;
private _isDisposed: boolean = false;
private _viewColumn: vscode.ViewColumn;
private _active: boolean;
public readonly onMessageEmitter = new Emitter<any>();
public readonly onDidReceiveMessage: Event<any> = this.onMessageEmitter.event;
public readonly onDisposeEmitter = new Emitter<void>();
public readonly onDidDispose: Event<void> = this.onDisposeEmitter.event;
public readonly onDidChangeViewStateEmitter = new Emitter<vscode.WebviewOnDidChangeViewStateEvent>();
public readonly onDidChangeViewState: Event<vscode.WebviewOnDidChangeViewStateEvent> = this.onDidChangeViewStateEmitter.event;
public readonly onDidChangeViewStateEmitter = new Emitter<vscode.WebviewEditorOnDidChangeViewStateEvent>();
public readonly onDidChangeViewState: Event<vscode.WebviewEditorOnDidChangeViewStateEvent> = this.onDidChangeViewStateEmitter.event;
constructor(
handle: WebviewHandle,
proxy: MainThreadWebviewsShape,
viewType: string,
viewColumn: vscode.ViewColumn,
title: string,
options: vscode.WebviewOptions
) {
this._handle = handle;
this._proxy = proxy;
this._viewType = viewType;
this._viewColumn = viewColumn;
this._title = title;
this._options = options;
}
public dispose() {
if (this._isDisposed) {
return;
}
this._isDisposed = true;
this._proxy.$disposeWebview(this._handle);
this.onDisposeEmitter.dispose();
this.onMessageEmitter.dispose();
dispose() {
this.onDidChangeViewStateEmitter.dispose();
}
get viewType(): string {
this.assertNotDisposed();
return this._viewType;
}
get title(): string {
this.assertNotDisposed();
return this._title;
@@ -95,6 +72,84 @@ export class ExtHostWebview implements vscode.Webview {
return this._options;
}
public postMessage(message: any): Thenable<boolean> {
this.assertNotDisposed();
return this._proxy.$sendMessage(this._handle, message);
}
public reveal(viewColumn: vscode.ViewColumn): void {
this.assertNotDisposed();
this._proxy.$reveal(this._handle, typeConverters.fromViewColumn(viewColumn));
}
private assertNotDisposed() {
if (this._isDisposed) {
throw new Error('Webview is disposed');
}
}
}
export class ExtHostWebviewEditor implements vscode.WebviewEditor {
private readonly _handle: WebviewHandle;
private readonly _viewType: string;
private readonly _options: vscode.WebviewEditorOptions;
private readonly _proxy: MainThreadWebviewsShape;
private _isDisposed: boolean = false;
private _viewColumn: vscode.ViewColumn;
private _active: boolean;
public readonly onDisposeEmitter = new Emitter<void>();
public readonly onDidDispose: Event<void> = this.onDisposeEmitter.event;
public readonly onDidChangeViewStateEmitter = new Emitter<vscode.WebviewEditorOnDidChangeViewStateEvent>();
public readonly onDidChangeViewState: Event<vscode.WebviewEditorOnDidChangeViewStateEvent> = this.onDidChangeViewStateEmitter.event;
private _webview: ExtHostWebview;
constructor(
handle: WebviewHandle,
proxy: MainThreadWebviewsShape,
viewType: string,
title: string,
viewColumn: vscode.ViewColumn,
editorOptions: vscode.WebviewEditorOptions,
webviewOptions: vscode.WebviewOptions
) {
this._handle = handle;
this._proxy = proxy;
this._viewType = viewType;
this._options = editorOptions;
this._viewColumn = viewColumn;
this._webview = new ExtHostWebview(handle, proxy, title, webviewOptions);
}
public dispose() {
if (this._isDisposed) {
return;
}
this._isDisposed = true;
this._proxy.$disposeWebview(this._handle);
this.onDisposeEmitter.dispose();
this.onDidChangeViewStateEmitter.dispose();
}
get webview() {
this.assertNotDisposed();
return this._webview;
}
get viewType(): string {
this.assertNotDisposed();
return this._viewType;
}
get options() {
return this._options;
}
get viewColumn(): vscode.ViewColumn {
this.assertNotDisposed();
return this._viewColumn;
@@ -137,8 +192,8 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
private readonly _proxy: MainThreadWebviewsShape;
private readonly _webviews = new Map<WebviewHandle, ExtHostWebview>();
private readonly _serializers = new Map<string, vscode.WebviewSerializer>();
private readonly _webviews = new Map<WebviewHandle, ExtHostWebviewEditor>();
private readonly _serializers = new Map<string, vscode.WebviewEditorSerializer>();
constructor(
mainContext: IMainContext
@@ -150,20 +205,20 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
viewType: string,
title: string,
viewColumn: vscode.ViewColumn,
options: vscode.WebviewOptions,
options: vscode.WebviewEditorOptions & vscode.WebviewOptions,
extensionFolderPath: string
): vscode.Webview {
): vscode.WebviewEditor {
const handle = ExtHostWebviews.webviewHandlePool++ + '';
this._proxy.$createWebview(handle, viewType, title, typeConverters.fromViewColumn(viewColumn), options, extensionFolderPath);
const webview = new ExtHostWebview(handle, this._proxy, viewType, viewColumn, options);
const webview = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, viewColumn, options, options);
this._webviews.set(handle, webview);
return webview;
}
registerWebviewSerializer(
registerWebviewEditorSerializer(
viewType: string,
serializer: vscode.WebviewSerializer
serializer: vscode.WebviewEditorSerializer
): vscode.Disposable {
if (this._serializers.has(viewType)) {
throw new Error(`Serializer for '${viewType}' already registered`);
@@ -181,7 +236,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
$onMessage(handle: WebviewHandle, message: any): void {
const webview = this.getWebview(handle);
if (webview) {
webview.onMessageEmitter.fire(message);
webview.webview.onMessageEmitter.fire(message);
}
}
@@ -209,6 +264,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
$deserializeWebview(
webviewHandle: WebviewHandle,
viewType: string,
title: string,
state: any,
position: Position,
options: vscode.WebviewOptions
@@ -218,9 +274,9 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
return TPromise.wrapError(new Error(`No serializer found for '${viewType}'`));
}
const revivedWebview = new ExtHostWebview(webviewHandle, this._proxy, viewType, typeConverters.toViewColumn(position), options);
const revivedWebview = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeConverters.toViewColumn(position), options as vscode.WebviewEditorOptions, options as vscode.WebviewOptions);
this._webviews.set(webviewHandle, revivedWebview);
return serializer.deserializeWebview(revivedWebview, state);
return serializer.deserializeWebviewEditor(revivedWebview, state);
}
$serializeWebview(
@@ -236,10 +292,10 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
return TPromise.as(undefined);
}
return serialzer.serializeWebview(webview);
return serialzer.serializeWebviewEditor(webview);
}
private getWebview(handle: WebviewHandle): ExtHostWebview | undefined {
private getWebview(handle: WebviewHandle): ExtHostWebviewEditor | undefined {
return this._webviews.get(handle);
}
}