From 403f90edd67c5fc213cfe4e44f8f8f6370a949b9 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 22 Jul 2019 11:53:19 -0700 Subject: [PATCH] Extract DynamicWebviewEditorOverlay to own file --- .../browser/dynamicWebviewEditorOverlay.ts | 166 +++++++++++++++++ .../contrib/webview/browser/webviewService.ts | 175 +----------------- 2 files changed, 168 insertions(+), 173 deletions(-) create mode 100644 src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts diff --git a/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts new file mode 100644 index 00000000000..c86d25f7724 --- /dev/null +++ b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts @@ -0,0 +1,166 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. 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 { 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'; + +/** + * Webview editor overlay that creates and destroys the underlying webview as needed. + */ +export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEditorOverlay { + + private readonly _pendingMessages = new Set(); + private readonly _webview = this._register(new MutableDisposable()); + 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.onMessage(x => { this._onMessage.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); + + 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()); + public readonly onDidFocus: Event = this._onDidFocus.event; + + private readonly _onDidClickLink = this._register(new Emitter()); + public readonly onDidClickLink: Event = 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()); + public readonly onDidUpdateState: Event = this._onDidUpdateState.event; + + private readonly _onMessage = this._register(new Emitter()); + public readonly onMessage: Event = 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()); } + + public getInnerWebview() { + return this._webview.value; + } + + private withWebview(f: (webview: Webview) => void): void { + if (this._webview.value) { + f(this._webview.value); + } + } +} diff --git a/src/vs/workbench/contrib/webview/browser/webviewService.ts b/src/vs/workbench/contrib/webview/browser/webviewService.ts index 2ffed7621a3..1995a857f5e 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewService.ts @@ -3,14 +3,10 @@ * Licensed under the MIT License. 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 } 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'; +import { IWebviewService, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; +import { DynamicWebviewEditorOverlay } from './dynamicWebviewEditorOverlay'; export class WebviewService implements IWebviewService { _serviceBrand: any; @@ -35,170 +31,3 @@ export class WebviewService implements IWebviewService { 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(); - private readonly _webview = this._register(new MutableDisposable()); - 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()); - public readonly onDidFocus: Event = this._onDidFocus.event; - - private readonly _onDidClickLink = this._register(new Emitter()); - public readonly onDidClickLink: Event = 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()); - public readonly onDidUpdateState: Event = this._onDidUpdateState.event; - - private readonly _onMessage = this._register(new Emitter()); - public readonly onMessage: Event = 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()); } - - public getInnerWebview() { - return this._webview.value; - } - - private withWebview(f: (webview: Webview) => void): void { - if (this._webview.value) { - f(this._webview.value); - } - } -} \ No newline at end of file