提交 d7e0604e 编写于 作者: M Matt Bierner

Prototype webview widget

Start prototyping a webview widget. Code is still super rough
上级 5a0ead58
......@@ -27,6 +27,11 @@
],
"contributes": {
"commands": [
{
"command": "unicorn",
"title": "🦄 unicorn",
"category": "Markdown"
},
{
"command": "markdown.showPreview",
"title": "%markdown.preview.title%",
......
......@@ -59,4 +59,12 @@ export function activate(context: vscode.ExtensionContext) {
logger.updateConfiguration();
previewManager.updateConfiguration();
}));
vscode.commands.registerCommand('unicorn', () => {
if (vscode.window.activeTextEditor) {
vscode.window.showWebviewWidget(vscode.window.activeTextEditor, vscode.window.activeTextEditor.selection.active, 'unicorn', 'Webview', {}).then(webview => {
webview.html = '<img src="https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif"/>';
});
}
});
}
......@@ -685,6 +685,8 @@ declare module 'vscode' {
* @param reviver Webview serializer.
*/
export function registerWebviewSerializer(viewType: string, reviver: WebviewSerializer): Disposable;
export function showWebviewWidget(editor: TextEditor, position: Position, viewType: string, title: string, options: WebviewOptions): Thenable<Webview>;
}
//#endregion
......
......@@ -18,7 +18,10 @@ import { IWebviewEditorService, WebviewInputOptions, WebviewReviver } from 'vs/w
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { ICodeEditor } from '../../../editor/browser/editorBrowser';
import { EDITOR_CONTRIBUTION_ID, WebviewWidgetContribution } from '../../parts/webview/electron-browser/webviewWidget';
import { extHostNamedCustomer } from './extHostCustomers';
import { WebviewElement } from 'vs/workbench/parts/webview/electron-browser/webviewElement';
@extHostNamedCustomer(MainContext.MainThreadWebviews)
export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviver {
......@@ -34,7 +37,8 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
private _toDispose: IDisposable[] = [];
private readonly _proxy: ExtHostWebviewsShape;
private readonly _webviews = new Map<WebviewHandle, WebviewEditorInput>();
private readonly _webviewInputs = new Map<WebviewHandle, WebviewEditorInput>();
private readonly _webviews = new Map<WebviewHandle, WebviewElement>();
private readonly _revivers = new Set<string>();
private _activeWebview: WebviewHandle | undefined = undefined;
......@@ -77,7 +81,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
state: undefined
};
this._webviews.set(handle, webview);
this._webviewInputs.set(handle, webview);
}
$disposeWebview(handle: WebviewHandle): void {
......@@ -92,7 +96,14 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
$setHtml(handle: WebviewHandle, value: string): void {
const webview = this.getWebview(handle);
webview.html = value;
if (webview) {
webview.html = value;
} else {
const webview = this._webviews.get(handle);
if (webview) {
webview.contents = value;
}
}
}
$reveal(handle: WebviewHandle, column: Position): void {
......@@ -122,11 +133,24 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._revivers.delete(viewType);
}
$showWebviewWidget(handle: WebviewHandle, editorId: string, lineNumber: number, viewType: string, options: WebviewInputOptions): void {
const editor = this._editorService.getActiveEditor();
if (editor && editor.getControl()) {
(editor.getControl() as ICodeEditor).getContribution<WebviewWidgetContribution>(EDITOR_CONTRIBUTION_ID).showWebviewWidget(lineNumber, 0, webview => {
this._webviews.set(handle, webview);
webview.onDidClickLink(uri => this.onDidClickLink(uri, webview.options));
webview.onMessage(message => this._proxy.$onMessage(handle, message));
});
}
return undefined;
}
reviveWebview(webview: WebviewEditorInput): TPromise<void> {
const viewType = webview.state.viewType;
return this._extensionService.activateByEvent(`onView:${viewType}`).then(() => {
const handle = 'revival-' + MainThreadWebviews.revivalPool++;
this._webviews.set(handle, webview);
this._webviewInputs.set(handle, webview);
webview._events = this.createWebviewEventDelegate(handle);
return this._proxy.$deserializeWebview(handle, webview.state.viewType, webview.state.state, webview.position, webview.options)
......@@ -142,7 +166,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
private _onWillShutdown(): TPromise<boolean> {
const toRevive: WebviewHandle[] = [];
this._webviews.forEach((view, key) => {
this._webviewInputs.forEach((view, key) => {
if (this.canRevive(view)) {
toRevive.push(key);
}
......@@ -158,7 +182,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
return TPromise.join(reviveResponses).then(results => {
for (const result of results) {
const view = this._webviews.get(result.handle);
const view = this._webviewInputs.get(result.handle);
if (view) {
if (result.state) {
view.state.state = result.state;
......@@ -184,10 +208,10 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
}
private getWebview(handle: WebviewHandle): WebviewEditorInput {
const webview = this._webviews.get(handle);
if (!webview) {
throw new Error('Unknown webview handle:' + handle);
}
const webview = this._webviewInputs.get(handle);
// if (!webview) {
// throw new Error('Unknown webview handle:' + handle);
// }
return webview;
}
......@@ -195,8 +219,8 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
const activeEditor = this._editorService.getActiveEditor();
let newActiveWebview: { input: WebviewEditorInput, handle: WebviewHandle } | undefined = undefined;
if (activeEditor && activeEditor.input instanceof WebviewEditorInput) {
for (const handle of map.keys(this._webviews)) {
const input = this._webviews.get(handle);
for (const handle of map.keys(this._webviewInputs)) {
const input = this._webviewInputs.get(handle);
if (input.matches(activeEditor.input)) {
newActiveWebview = { input, handle };
break;
......@@ -211,7 +235,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
// Broadcast view state update for currently active
if (typeof this._activeWebview !== 'undefined') {
const oldActiveWebview = this._webviews.get(this._activeWebview);
const oldActiveWebview = this._webviewInputs.get(this._activeWebview);
if (oldActiveWebview) {
this._proxy.$onDidChangeWeviewViewState(this._activeWebview, false, oldActiveWebview.position);
}
......
......@@ -421,6 +421,9 @@ export function createApiFactory(
}),
registerWebviewSerializer: proposedApiFunction(extension, (viewType: string, serializer: vscode.WebviewSerializer) => {
return extHostWebviews.registerWebviewSerializer(viewType, serializer);
}),
showWebviewWidget: proposedApiFunction(extension, (editor: vscode.TextEditor, position: vscode.Position, viewType: string, title: string, options: vscode.WebviewOptions) => {
return extHostWebviews.showWebviewWidget(editor, position.line, viewType, title, options);
})
};
......
......@@ -359,6 +359,8 @@ export interface MainThreadWebviewsShape extends IDisposable {
$registerSerializer(viewType: string): void;
$unregisterSerializer(viewType: string): void;
$showWebviewWidget(handle: WebviewHandle, editorId: string, lineNumber: number, viewType: string, options: vscode.WebviewOptions): void;
}
export interface ExtHostWebviewsShape {
......
......@@ -10,6 +10,7 @@ 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';
import { ExtHostTextEditor } from './extHostTextEditor';
export class ExtHostWebview implements vscode.Webview {
......@@ -141,7 +142,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
private readonly _serializers = new Map<string, vscode.WebviewSerializer>();
constructor(
mainContext: IMainContext
mainContext: IMainContext,
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadWebviews);
}
......@@ -178,6 +179,15 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
});
}
async showWebviewWidget(editor: vscode.TextEditor, lineNumber: number, viewType: string, title: string, options: vscode.WebviewOptions) {
const handle = ExtHostWebviews.webviewHandlePool++ + '';
this._proxy.$showWebviewWidget(handle, (editor as ExtHostTextEditor).id, lineNumber, viewType, options);
const webview = new ExtHostWebview(handle, this._proxy, viewType, undefined, options);
this._webviews.set(handle, webview);
return webview;
}
$onMessage(handle: WebviewHandle, message: any): void {
const webview = this.getWebview(handle);
if (webview) {
......
......@@ -184,6 +184,10 @@ export class WebviewElement {
parent.appendChild(this._webview);
}
public getDomNode() {
return this._webview;
}
public notifyFindWidgetFocusChanged(isFocused: boolean) {
this._contextKey.set(isFocused || document.activeElement === this._webview);
}
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { WebviewElement } from 'vs/workbench/parts/webview/electron-browser/webviewElement';
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
export const EDITOR_CONTRIBUTION_ID = 'editor.contrib.webview';
export class WebviewWidget extends ZoneWidget {
private _webview: WebviewElement;
constructor(
editor: ICodeEditor,
private readonly _delegate: (view: WebviewElement) => void,
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService private readonly _themeService: IThemeService,
@IPartService private readonly _partService: IPartService,
@IContextViewService private readonly _contextViewService: IContextViewService,
@IEnvironmentService private readonly _environmentService: IEnvironmentService
) {
super(editor, {});
// this._applyTheme(_themeService.getTheme());
// this._callOnDispose.push(_themeService.onThemeChange(this._applyTheme.bind(this)));
this.create();
}
protected _fillContainer(container: HTMLElement): void {
this._webview = new WebviewElement(
this._partService.getContainer(Parts.EDITOR_PART),
this._themeService,
this._environmentService,
this._contextViewService,
undefined,
undefined,
{
enableWrappedPostMessage: true,
useSameOriginForRoot: false
});
this._webview.mountTo(container);
const e = new DomScrollableElement(this._webview.getDomNode(), {});
e.getDomNode().style.width = '100%';
e.getDomNode().style.height = '100%';
container.appendChild(e.getDomNode());
this._delegate(this._webview);
}
}
export interface IWebviewWidgetContribution extends IEditorContribution {
showWebviewWidget(lineNumber: number, column: number, delegate: (view: WebviewElement) => void): void;
closeWebviewWidget(): void;
}
export class WebviewWidgetContribution implements IWebviewWidgetContribution {
private _webviewWidget: WebviewWidget;
constructor(
private editor: ICodeEditor,
@IInstantiationService private readonly instantiationService: IInstantiationService
) { }
showWebviewWidget(lineNumber: number, column: number, delegate: (view: WebviewElement) => void): void {
if (this._webviewWidget) {
this._webviewWidget.dispose();
}
this._webviewWidget = this.instantiationService.createInstance(WebviewWidget, this.editor, delegate);
this._webviewWidget.show({ lineNumber, column: 1 }, 20);
// this.webviewWidgetVisible.set(true);
}
public closeWebviewWidget(): void {
if (this._webviewWidget) {
this._webviewWidget.dispose();
this._webviewWidget = null;
// this.webviewWidgetVisible.reset();
this.editor.focus();
}
}
getId(): string {
return EDITOR_CONTRIBUTION_ID;
}
dispose(): void {
this.closeWebviewWidget();
}
}
registerEditorContribution(WebviewWidgetContribution);
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册