Files
azuredatastudio/src/vs/workbench/api/node/extHostWebview.ts
2018-06-05 11:24:51 -07:00

300 lines
8.3 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { MainContext, MainThreadWebviewsShape, IMainContext, ExtHostWebviewsShape, WebviewPanelHandle } from './extHost.protocol';
import * as vscode from 'vscode';
import { Event, Emitter } from 'vs/base/common/event';
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import { Position } from 'vs/platform/editor/common/editor';
import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from './extHostTypes';
export class ExtHostWebview implements vscode.Webview {
private readonly _handle: WebviewPanelHandle;
private readonly _proxy: MainThreadWebviewsShape;
private _html: string;
private _options: vscode.WebviewOptions;
private _isDisposed: boolean = false;
readonly _onMessageEmitter = new Emitter<any>();
public readonly onDidReceiveMessage: Event<any> = this._onMessageEmitter.event;
constructor(
handle: WebviewPanelHandle,
proxy: MainThreadWebviewsShape,
options: vscode.WebviewOptions
) {
this._handle = handle;
this._proxy = proxy;
this._options = options;
}
dispose() {
this._onMessageEmitter.dispose();
}
get html(): string {
this.assertNotDisposed();
return this._html;
}
set html(value: string) {
this.assertNotDisposed();
if (this._html !== value) {
this._html = value;
this._proxy.$setHtml(this._handle, value);
}
}
get options(): vscode.WebviewOptions {
this.assertNotDisposed();
return this._options;
}
public postMessage(message: any): Thenable<boolean> {
this.assertNotDisposed();
return this._proxy.$postMessage(this._handle, message);
}
private assertNotDisposed() {
if (this._isDisposed) {
throw new Error('Webview is disposed');
}
}
}
export class ExtHostWebviewPanel implements vscode.WebviewPanel {
private readonly _handle: WebviewPanelHandle;
private readonly _proxy: MainThreadWebviewsShape;
private readonly _viewType: string;
private _title: string;
private readonly _options: vscode.WebviewPanelOptions;
private readonly _webview: ExtHostWebview;
private _isDisposed: boolean = false;
private _viewColumn: vscode.ViewColumn;
private _visible: boolean = true;
readonly _onDisposeEmitter = new Emitter<void>();
public readonly onDidDispose: Event<void> = this._onDisposeEmitter.event;
readonly _onDidChangeViewStateEmitter = new Emitter<vscode.WebviewPanelOnDidChangeViewStateEvent>();
public readonly onDidChangeViewState: Event<vscode.WebviewPanelOnDidChangeViewStateEvent> = this._onDidChangeViewStateEmitter.event;
constructor(
handle: WebviewPanelHandle,
proxy: MainThreadWebviewsShape,
viewType: string,
title: string,
viewColumn: vscode.ViewColumn,
editorOptions: vscode.WebviewPanelOptions,
webview: ExtHostWebview
) {
this._handle = handle;
this._proxy = proxy;
this._viewType = viewType;
this._options = editorOptions;
this._viewColumn = viewColumn;
this._title = title;
this._webview = webview;
}
public dispose() {
if (this._isDisposed) {
return;
}
this._isDisposed = true;
this._onDisposeEmitter.fire();
this._proxy.$disposeWebview(this._handle);
this._webview.dispose();
this._onDisposeEmitter.dispose();
this._onDidChangeViewStateEmitter.dispose();
}
get webview() {
this.assertNotDisposed();
return this._webview;
}
get viewType(): string {
this.assertNotDisposed();
return this._viewType;
}
get title(): string {
this.assertNotDisposed();
return this._title;
}
set title(value: string) {
this.assertNotDisposed();
if (this._title !== value) {
this._title = value;
this._proxy.$setTitle(this._handle, value);
}
}
get options() {
return this._options;
}
get viewColumn(): vscode.ViewColumn {
this.assertNotDisposed();
return this._viewColumn;
}
_setViewColumn(value: vscode.ViewColumn) {
this.assertNotDisposed();
this._viewColumn = value;
}
get visible(): boolean {
this.assertNotDisposed();
return this._visible;
}
_setVisible(value: boolean) {
this.assertNotDisposed();
this._visible = value;
}
public postMessage(message: any): Thenable<boolean> {
this.assertNotDisposed();
return this._proxy.$postMessage(this._handle, message);
}
public reveal(viewColumn?: vscode.ViewColumn): void {
this.assertNotDisposed();
this._proxy.$reveal(this._handle, viewColumn ? typeConverters.fromViewColumn(viewColumn) : undefined);
}
private assertNotDisposed() {
if (this._isDisposed) {
throw new Error('Webview is disposed');
}
}
}
export class ExtHostWebviews implements ExtHostWebviewsShape {
private static webviewHandlePool = 1;
private readonly _proxy: MainThreadWebviewsShape;
private readonly _webviewPanels = new Map<WebviewPanelHandle, ExtHostWebviewPanel>();
private readonly _serializers = new Map<string, vscode.WebviewPanelSerializer>();
constructor(
mainContext: IMainContext
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadWebviews);
}
createWebview(
viewType: string,
title: string,
viewColumn: vscode.ViewColumn,
options: (vscode.WebviewPanelOptions & vscode.WebviewOptions) | undefined,
extensionFolderPath: string
): vscode.WebviewPanel {
options = options || {};
const handle = ExtHostWebviews.webviewHandlePool++ + '';
this._proxy.$createWebviewPanel(handle, viewType, title, typeConverters.fromViewColumn(viewColumn), options, extensionFolderPath);
const webview = new ExtHostWebview(handle, this._proxy, options);
const panel = new ExtHostWebviewPanel(handle, this._proxy, viewType, title, viewColumn, options, webview);
this._webviewPanels.set(handle, panel);
return panel;
}
registerWebviewPanelSerializer(
viewType: string,
serializer: vscode.WebviewPanelSerializer
): vscode.Disposable {
if (this._serializers.has(viewType)) {
throw new Error(`Serializer for '${viewType}' already registered`);
}
this._serializers.set(viewType, serializer);
this._proxy.$registerSerializer(viewType);
return new Disposable(() => {
this._serializers.delete(viewType);
this._proxy.$unregisterSerializer(viewType);
});
}
$onMessage(handle: WebviewPanelHandle, message: any): void {
const panel = this.getWebviewPanel(handle);
if (panel) {
panel.webview._onMessageEmitter.fire(message);
}
}
$onDidChangeWebviewPanelViewState(handle: WebviewPanelHandle, visible: boolean, position: Position): void {
const panel = this.getWebviewPanel(handle);
if (panel) {
const viewColumn = typeConverters.toViewColumn(position);
if (panel.visible !== visible || panel.viewColumn !== viewColumn) {
panel._setVisible(visible);
panel._setViewColumn(viewColumn);
panel._onDidChangeViewStateEmitter.fire({ webviewPanel: panel });
}
}
}
$onDidDisposeWebviewPanel(handle: WebviewPanelHandle): Thenable<void> {
const panel = this.getWebviewPanel(handle);
if (panel) {
panel.dispose();
this._webviewPanels.delete(handle);
}
return TPromise.as(void 0);
}
$deserializeWebviewPanel(
webviewHandle: WebviewPanelHandle,
viewType: string,
title: string,
state: any,
position: Position,
options: vscode.WebviewOptions & vscode.WebviewPanelOptions
): Thenable<void> {
const serializer = this._serializers.get(viewType);
if (!serializer) {
return TPromise.wrapError(new Error(`No serializer found for '${viewType}'`));
}
const webview = new ExtHostWebview(webviewHandle, this._proxy, options);
const revivedPanel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeConverters.toViewColumn(position), options, webview);
this._webviewPanels.set(webviewHandle, revivedPanel);
return serializer.deserializeWebviewPanel(revivedPanel, state);
}
$serializeWebviewPanel(
webviewHandle: WebviewPanelHandle
): Thenable<any> {
const panel = this.getWebviewPanel(webviewHandle);
if (!panel) {
return TPromise.as(undefined);
}
const serialzer = this._serializers.get(panel.viewType);
if (!serialzer) {
return TPromise.as(undefined);
}
return serialzer.serializeWebviewPanel(panel);
}
private getWebviewPanel(handle: WebviewPanelHandle): ExtHostWebviewPanel | undefined {
return this._webviewPanels.get(handle);
}
}