提交 42d9a26e 编写于 作者: M Matt Bierner

Moving more shared code into webviewbase

上级 e461a7c1
......@@ -12,6 +12,8 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { WebviewExtensionDescription, WebviewOptions, WebviewContentOptions } from 'vs/workbench/contrib/webview/browser/webview';
import { URI } from 'vs/base/common/uri';
import { areWebviewInputOptionsEqual } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService';
import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/common/themeing';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export const enum WebviewMessageChannels {
onmessage = 'onmessage',
......@@ -37,6 +39,9 @@ export abstract class BaseWebview<T extends HTMLElement> extends Disposable {
private _element: T | undefined;
protected get element(): T | undefined { return this._element; }
private _focused: boolean;
protected get focused(): boolean { return this._focused; }
private readonly _ready: Promise<void>;
protected content: WebviewContent;
......@@ -44,10 +49,14 @@ export abstract class BaseWebview<T extends HTMLElement> extends Disposable {
public extension: WebviewExtensionDescription | undefined;
constructor(
// TODO: matb, this should not be protected. The only reason it needs to be is that the base class ends up using it in the call to createElement
protected readonly id: string,
options: WebviewOptions,
contentOptions: WebviewContentOptions,
private readonly webviewThemeDataProvider: WebviewThemeDataProvider,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IEnvironmentService private readonly _environementService: IEnvironmentService,
@IWorkbenchEnvironmentService protected readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
) {
super();
......@@ -88,6 +97,22 @@ export abstract class BaseWebview<T extends HTMLElement> extends Disposable {
this._register(this.on(WebviewMessageChannels.doReload, () => {
this.reload();
}));
this._register(this.on(WebviewMessageChannels.doUpdateState, (state: any) => {
this.state = state;
this._onDidUpdateState.fire(state);
}));
this._register(this.on(WebviewMessageChannels.didFocus, () => {
this.handleFocusChange(true);
}));
this._register(this.on(WebviewMessageChannels.didBlur, () => {
this.handleFocusChange(false);
}));
this.style();
this._register(webviewThemeDataProvider.onThemeDataChanged(this.style, this));
}
dispose(): void {
......@@ -111,6 +136,16 @@ export abstract class BaseWebview<T extends HTMLElement> extends Disposable {
private readonly _onDidScroll = this._register(new Emitter<{ readonly scrollYPercentage: number; }>());
public readonly onDidScroll = this._onDidScroll.event;
private readonly _onDidUpdateState = this._register(new Emitter<string | undefined>());
public readonly onDidUpdateState = this._onDidUpdateState.event;
private readonly _onDidFocus = this._register(new Emitter<void>());
public readonly onDidFocus = this._onDidFocus.event;
public sendMessage(data: any): void {
this._send('message', data);
}
protected _send(channel: string, data?: any): void {
this._ready
.then(() => this.postMessage(channel, data))
......@@ -196,4 +231,16 @@ export abstract class BaseWebview<T extends HTMLElement> extends Disposable {
...this.extraContentOptions
});
}
protected style(): void {
const { styles, activeTheme } = this.webviewThemeDataProvider.getWebviewThemeData();
this._send('styles', { styles, activeTheme });
}
protected handleFocusChange(isFocused: boolean): void {
this._focused = isFocused;
if (isFocused) {
this._onDidFocus.fire();
}
}
}
......@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { addDisposableListener } from 'vs/base/browser/dom';
import { Emitter } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
import { isWeb } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
......@@ -21,24 +20,23 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
export class IFrameWebview extends BaseWebview<HTMLIFrameElement> implements Webview {
private _focused = false;
private readonly _portMappingManager: WebviewPortMappingManager;
constructor(
private readonly id: string,
id: string,
options: WebviewOptions,
contentOptions: WebviewContentOptions,
private readonly webviewThemeDataProvider: WebviewThemeDataProvider,
webviewThemeDataProvider: WebviewThemeDataProvider,
@ITunnelService tunnelService: ITunnelService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IFileService private readonly fileService: IFileService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@ITelemetryService telemetryService: ITelemetryService,
@IEnvironmentService environementService: IEnvironmentService,
@IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService,
) {
super(options, contentOptions, telemetryService, environementService);
if (!this.useExternalEndpoint && (!environmentService.options || typeof environmentService.webviewExternalEndpoint !== 'string')) {
super(id, options, contentOptions, webviewThemeDataProvider, telemetryService, environementService, workbenchEnvironmentService);
if (!this.useExternalEndpoint && (!workbenchEnvironmentService.options || typeof workbenchEnvironmentService.webviewExternalEndpoint !== 'string')) {
throw new Error('To use iframe based webviews, you must configure `environmentService.webviewExternalEndpoint`');
}
......@@ -48,19 +46,6 @@ export class IFrameWebview extends BaseWebview<HTMLIFrameElement> implements Web
tunnelService
));
this._register(this.on(WebviewMessageChannels.doUpdateState, (state: any) => {
this.state = state;
this._onDidUpdateState.fire(state);
}));
this._register(this.on(WebviewMessageChannels.didFocus, () => {
this.handleFocusChange(true);
}));
this._register(this.on(WebviewMessageChannels.didBlur, () => {
this.handleFocusChange(false);
}));
this._register(this.on(WebviewMessageChannels.loadResource, (entry: any) => {
const rawPath = entry.path;
const normalizedPath = decodeURIComponent(rawPath);
......@@ -71,9 +56,6 @@ export class IFrameWebview extends BaseWebview<HTMLIFrameElement> implements Web
this._register(this.on(WebviewMessageChannels.loadLocalhost, (entry: any) => {
this.localLocalhost(entry.origin);
}));
this.style();
this._register(webviewThemeDataProvider.onThemeDataChanged(this.style, this));
}
protected createElement(options: WebviewOptions) {
......@@ -88,7 +70,7 @@ export class IFrameWebview extends BaseWebview<HTMLIFrameElement> implements Web
}
private get externalEndpoint(): string {
const endpoint = this.environmentService.webviewExternalEndpoint!.replace('{{uuid}}', this.id);
const endpoint = this.workbenchEnvironmentService.webviewExternalEndpoint!.replace('{{uuid}}', this.id);
if (endpoint[endpoint.length - 1] === '/') {
return endpoint.slice(0, endpoint.length - 1);
}
......@@ -121,23 +103,6 @@ export class IFrameWebview extends BaseWebview<HTMLIFrameElement> implements Web
};
}
private handleFocusChange(isFocused: boolean): void {
this._focused = isFocused;
if (this._focused) {
this._onDidFocus.fire();
}
}
private readonly _onDidFocus = this._register(new Emitter<void>());
public readonly onDidFocus = this._onDidFocus.event;
private readonly _onDidUpdateState = this._register(new Emitter<string | undefined>());
public readonly onDidUpdateState = this._onDidUpdateState.event;
sendMessage(data: any): void {
this._send('message', data);
}
focus(): void {
if (this.element) {
this.element.focus();
......@@ -156,19 +121,6 @@ export class IFrameWebview extends BaseWebview<HTMLIFrameElement> implements Web
throw new Error('Method not implemented.');
}
public set state(state: string | undefined) {
this.content = {
html: this.content.html,
options: this.content.options,
state,
};
}
private style(): void {
const { styles, activeTheme } = this.webviewThemeDataProvider.getWebviewThemeData();
this._send('styles', { styles, activeTheme });
}
private async loadResource(requestPath: string, uri: URI) {
try {
const result = await loadLocalResource(uri, this.fileService, this.extension ? this.extension.location : undefined,
......
......@@ -23,6 +23,7 @@ import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/common/th
import { registerFileProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols';
import { WebviewFindDelegate, WebviewFindWidget } from '../browser/webviewFindWidget';
import { BaseWebview, WebviewMessageChannels } from 'vs/workbench/contrib/webview/browser/baseWebviewElement';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
interface IKeydownEvent {
key: string;
......@@ -230,24 +231,21 @@ export class ElectronWebviewBasedWebview extends BaseWebview<WebviewTag> impleme
private _webviewFindWidget: WebviewFindWidget | undefined;
private _findStarted: boolean = false;
private _focused = false;
private readonly _onDidFocus = this._register(new Emitter<void>());
public readonly onDidFocus: Event<void> = this._onDidFocus.event;
public extension: WebviewExtensionDescription | undefined;
constructor(
id: string,
options: WebviewOptions,
contentOptions: WebviewContentOptions,
private readonly webviewThemeDataProvider: WebviewThemeDataProvider,
private readonly _webviewThemeDataProvider: WebviewThemeDataProvider,
@IInstantiationService instantiationService: IInstantiationService,
@IFileService fileService: IFileService,
@ITunnelService tunnelService: ITunnelService,
@ITelemetryService telemetryService: ITelemetryService,
@IEnvironmentService environementService: IEnvironmentService,
@IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService,
) {
super(options, contentOptions, telemetryService, environementService);
super(id, options, contentOptions, _webviewThemeDataProvider, telemetryService, environementService, workbenchEnvironmentService);
const webviewAndContents = this._register(new WebviewTagHandle(this.element!));
const session = this._register(new WebviewSession(webviewAndContents));
......@@ -272,7 +270,7 @@ export class ElectronWebviewBasedWebview extends BaseWebview<WebviewTag> impleme
}));
this._register(addDisposableListener(this.element!, 'dom-ready', () => {
// Workaround for https://github.com/electron/electron/issues/14474
if (this.element && (this._focused || document.activeElement === this.element)) {
if (this.element && (this.focused || document.activeElement === this.element)) {
this.element.blur();
this.element.focus();
}
......@@ -307,19 +305,6 @@ export class ElectronWebviewBasedWebview extends BaseWebview<WebviewTag> impleme
}
}));
this._register(this.on(WebviewMessageChannels.doUpdateState, (state: any) => {
this.state = state;
this._onDidUpdateState.fire(state);
}));
this._register(this.on(WebviewMessageChannels.didFocus, () => {
this.handleFocusChange(true);
}));
this._register(this.on(WebviewMessageChannels.didBlur, () => {
this.handleFocusChange(false);
}));
this._register(addDisposableListener(this.element!, 'devtools-opened', () => {
this._send('devtools-opened');
}));
......@@ -331,9 +316,6 @@ export class ElectronWebviewBasedWebview extends BaseWebview<WebviewTag> impleme
this._hasFindResult.fire(e.result.matches > 0);
}));
}
this.style();
this._register(webviewThemeDataProvider.onThemeDataChanged(this.style, this));
}
protected createElement(options: WebviewOptions) {
......@@ -366,9 +348,6 @@ export class ElectronWebviewBasedWebview extends BaseWebview<WebviewTag> impleme
parent.appendChild(this.element);
}
private readonly _onDidUpdateState = this._register(new Emitter<string | undefined>());
public readonly onDidUpdateState = this._onDidUpdateState.event;
protected postMessage(channel: string, data?: any): void {
if (this.element) {
this.element.send(channel, data);
......@@ -390,23 +369,11 @@ export class ElectronWebviewBasedWebview extends BaseWebview<WebviewTag> impleme
this.handleFocusChange(true);
}
private handleFocusChange(isFocused: boolean): void {
this._focused = isFocused;
if (isFocused) {
this._onDidFocus.fire();
}
}
public sendMessage(data: any): void {
this._send('message', data);
}
private style(): void {
const { styles, activeTheme } = this.webviewThemeDataProvider.getWebviewThemeData();
this._send('styles', { styles, activeTheme });
protected style(): void {
super.style();
if (this._webviewFindWidget) {
this._webviewFindWidget.updateTheme(this.webviewThemeDataProvider.getTheme());
this._webviewFindWidget.updateTheme(this._webviewThemeDataProvider.getTheme());
}
}
......
......@@ -32,7 +32,7 @@ export class ElectronWebviewService implements IWebviewService {
if (useExternalEndpoint) {
return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions, this.webviewThemeDataProvider);
} else {
return this._instantiationService.createInstance(ElectronWebviewBasedWebview, options, contentOptions, this.webviewThemeDataProvider);
return this._instantiationService.createInstance(ElectronWebviewBasedWebview, id, options, contentOptions, this.webviewThemeDataProvider);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册