diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 56fab72bd52fcc2e3f9f4de33378e86386846b9f..fb93bbe302784221352b451a9ed7dd18acd1d541 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -134,6 +134,10 @@ "name": "vs/workbench/parts/watermark", "project": "vscode-workbench" }, + { + "name": "vs/workbench/parts/webview", + "project": "vscode-workbench" + }, { "name": "vs/workbench/parts/welcome", "project": "vscode-workbench" diff --git a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts index 04175b0e589c2dfb421f5a1c0a63a120d3efaaac..f1624d0b6f21f0ef74c3598f09adeceb112618c3 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts @@ -5,420 +5,19 @@ 'use strict'; import * as map from 'vs/base/common/map'; -import { TPromise } from 'vs/base/common/winjs.base'; import { MainThreadWebviewsShape, MainContext, IExtHostContext, ExtHostContext, ExtHostWebviewsShape, WebviewHandle } from 'vs/workbench/api/node/extHost.protocol'; -import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; +import { dispose, Disposable } from 'vs/base/common/lifecycle'; import { extHostNamedCustomer } from './extHostCustomers'; -import { EditorInput, EditorModel, EditorOptions } from 'vs/workbench/common/editor'; -import { IEditorModel, Position } from 'vs/platform/editor/common/editor'; +import { Position } from 'vs/platform/editor/common/editor'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { WebviewEditor as BaseWebviewEditor, KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS, KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from 'vs/workbench/parts/html/browser/webviewEditor'; -import { Builder, Dimension } from 'vs/base/browser/builder'; -import { Webview } from 'vs/workbench/parts/html/browser/webview'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; -import { IStorageService } from 'vs/platform/storage/common/storage'; -import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; -import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { localize } from 'vs/nls'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import * as vscode from 'vscode'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import URI from 'vs/base/common/uri'; -import DOM = require('vs/base/browser/dom'); -import Event, { Emitter } from 'vs/base/common/event'; - - -interface WebviewEvents { - onMessage(message: any): void; - onDidChangePosition(newPosition: Position): void; - onDispose(): void; - onDidClickLink(link: URI, options: vscode.WebviewOptions): void; -} - -class WebviewInput extends EditorInput { - private static handlePool = 0; - - private readonly _resource: URI; - private _name: string; - private _options: vscode.WebviewOptions; - private _html: string; - private _currentWebviewHtml: string = ''; - private _events: WebviewEvents | undefined; - private _container: HTMLElement; - private _webview: Webview | undefined; - private _webviewOwner: any; - private _webviewDisposables: IDisposable[] = []; - private _position: Position; - - - public static create( - resource: URI, - name: string, - position: Position, - options: vscode.WebviewOptions, - html: string, - events: WebviewEvents, - partService: IPartService - ): WebviewInput { - const id = WebviewInput.handlePool++; - const webviewContainer = document.createElement('div'); - webviewContainer.id = `webview-${id}`; - - partService.getContainer(Parts.EDITOR_PART).appendChild(webviewContainer); - - return new WebviewInput(resource, name, position, options, html, events, webviewContainer, undefined); - } - - constructor( - resource: URI, - name: string, - position: Position, - options: vscode.WebviewOptions, - html: string, - events: WebviewEvents, - container: HTMLElement, - webview: Webview | undefined - ) { - super(); - this._resource = resource; - this._name = name; - this._position = position; - this._options = options; - this._html = html; - this._events = events; - - this._container = container; - this._webview = webview; - } - - public getTypeId(): string { - return 'webview'; - } - - public dispose() { - this.disposeWebview(); - - if (this._container) { - this._container.remove(); - this._container = undefined; - } - - if (this._events) { - this._events.onDispose(); - this._events = undefined; - } - - super.dispose(); - } - - public getResource(): URI { - return this._resource; - } - - public getName(): string { - return this._name; - } - - public setName(value: string): void { - this._name = value; - this._onDidChangeLabel.fire(); - } - - public get position(): Position { - return this._position; - } - - public get html(): string { - return this._html; - } - - public setHtml(value: string): void { - if (value === this._currentWebviewHtml) { - return; - } - - this._html = value; - - if (this._webview) { - this._webview.contents = value; - this._currentWebviewHtml = value; - } - } - - public get options(): vscode.WebviewOptions { - return this._options; - } - - public set options(value: vscode.WebviewOptions) { - this._options = value; - } - - public resolve(refresh?: boolean): TPromise { - return TPromise.as(new EditorModel()); - } - - public supportsSplitEditor() { - return false; - } - - public get container(): HTMLElement { - return this._container; - } - - public get webview(): Webview | undefined { - return this._webview; - } - - public set webview(value: Webview) { - this._webviewDisposables = dispose(this._webviewDisposables); - - this._webview = value; - - this._webview.onDidClickLink(link => { - if (this._events) { - this._events.onDidClickLink(link, this._options); - } - }, null, this._webviewDisposables); - - this._webview.onMessage(message => { - if (this._events) { - this._events.onMessage(message); - } - }, null, this._webviewDisposables); - } - - public claimWebview(owner: any) { - this._webviewOwner = owner; - } - - public releaseWebview(owner: any) { - if (this._webviewOwner === owner) { - this._webviewOwner = undefined; - if (this._options.retainContextWhenHidden) { - this.container.style.visibility = 'hidden'; - } else { - this.disposeWebview(); - } - } - } - - public disposeWebview() { - // The input owns the webview and its parent - if (this._webview) { - this._webview.dispose(); - this._webview = undefined; - } - - this._webviewDisposables = dispose(this._webviewDisposables); - - this._webviewOwner = undefined; - this.container.style.visibility = 'hidden'; - - this._currentWebviewHtml = ''; - } - - public onDidChangePosition(position: Position) { - if (this._events) { - this._events.onDidChangePosition(position); - } - this._position = position; - } -} - -class WebviewEditor extends BaseWebviewEditor { - - public static readonly ID = 'WebviewEditor'; - - private editorFrame: HTMLElement; - private webviewContent: HTMLElement; - private _onDidFocusWebview: Emitter; - private _webviewFocusTracker?: DOM.IFocusTracker; - private _webviewFocusListenerDisposable?: IDisposable; - - constructor( - @ITelemetryService telemetryService: ITelemetryService, - @IStorageService storageService: IStorageService, - @IThemeService themeService: IThemeService, - @IContextKeyService private _contextKeyService: IContextKeyService, - @IPartService private readonly _partService: IPartService, - @IContextViewService private readonly _contextViewService: IContextViewService, - @IEnvironmentService private readonly _environmentService: IEnvironmentService, - @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService - ) { - super(WebviewEditor.ID, telemetryService, themeService, storageService, _contextKeyService); - - this._onDidFocusWebview = new Emitter(); - } - - protected createEditor(parent: Builder): void { - this.editorFrame = parent.getHTMLElement(); - this.content = document.createElement('div'); - parent.append(this.content); - } - - private doUpdateContainer() { - const webviewContainer = this.input && (this.input as WebviewInput).container; - if (webviewContainer) { - const frameRect = this.editorFrame.getBoundingClientRect(); - const containerRect = webviewContainer.parentElement.getBoundingClientRect(); - - webviewContainer.style.position = 'absolute'; - webviewContainer.style.top = `${frameRect.top - containerRect.top}px`; - webviewContainer.style.left = `${frameRect.left - containerRect.left}px`; - webviewContainer.style.width = `${frameRect.width}px`; - webviewContainer.style.height = `${frameRect.height}px`; - } - } - - public layout(dimension: Dimension): void { - if (this._webview) { - this.doUpdateContainer(); - } - super.layout(dimension); - } - - public dispose(): void { - // Let the editor input dispose of the webview. - this._webview = undefined; - this.webviewContent = undefined; - - this._onDidFocusWebview.dispose(); - - if (this._webviewFocusTracker) { - this._webviewFocusTracker.dispose(); - } - - if (this._webviewFocusListenerDisposable) { - this._webviewFocusListenerDisposable.dispose(); - } - - super.dispose(); - } - - public sendMessage(data: any): void { - if (this._webview) { - this._webview.sendMessage(data); - } - } - - public get onDidFocus(): Event { - return this._onDidFocusWebview.event; - } - - protected setEditorVisible(visible: boolean, position?: Position): void { - if (this.input && this.input instanceof WebviewInput) { - if (visible) { - this.input.claimWebview(this); - } else { - this.input.releaseWebview(this); - } - - this.updateWebview(this.input as WebviewInput); - } - - if (this.webviewContent) { - if (visible) { - this.webviewContent.style.visibility = 'visible'; - this.doUpdateContainer(); - } else { - this.webviewContent.style.visibility = 'hidden'; - } - } - - super.setEditorVisible(visible, position); - } - - public clearInput() { - if (this.input && this.input instanceof WebviewInput) { - this.input.releaseWebview(this); - } - - this._webview = undefined; - this.webviewContent = undefined; - - super.clearInput(); - } - - async setInput(input: WebviewInput, options: EditorOptions): TPromise { - if (this.input && this.input.matches(input)) { - return undefined; - } - - if (this.input && this.input.getResource().fsPath !== input.getResource().fsPath) { - (this.input as WebviewInput).releaseWebview(this); - this._webview = undefined; - this.webviewContent = undefined; - } - - await super.setInput(input, options); - - input.onDidChangePosition(this.position); - this.updateWebview(input); - } - - private updateWebview(input: WebviewInput) { - const webview = this.getWebview(input); - input.claimWebview(this); - webview.options = { - allowScripts: input.options.enableScripts, - enableWrappedPostMessage: true, - useSameOriginForRoot: false, - localResourceRoots: (input && input.options.localResourceRoots) || this._contextService.getWorkspace().folders.map(x => x.uri) - }; - input.setHtml(input.html); - this.webviewContent.style.visibility = 'visible'; - this.doUpdateContainer(); - } - - private getWebview(input: WebviewInput): Webview { - if (this._webview) { - return this._webview; - } - - this.webviewContent = input.container; - const existing = input.webview; - if (existing) { - this._webview = existing; - return existing; - } - - this._webviewFocusTracker = DOM.trackFocus(this.webviewContent); - this._webviewFocusListenerDisposable = this._webviewFocusTracker.onDidFocus(() => { - this._onDidFocusWebview.fire(); - }); - - this._contextKeyService = this._contextKeyService.createScoped(this.webviewContent); - this.contextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS.bindTo(this._contextKeyService); - this.findInputFocusContextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED.bindTo(this._contextKeyService); - this.findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService); - - this._webview = new Webview( - this.webviewContent, - this._partService.getContainer(Parts.EDITOR_PART), - this.themeService, - this._environmentService, - this._contextViewService, - this.contextKey, - this.findInputFocusContextKey, - { - enableWrappedPostMessage: true, - useSameOriginForRoot: false - }); - input.webview = this._webview; - - this.content.setAttribute('aria-flowto', this.webviewContent.id); - - this.doUpdateContainer(); - return this._webview; - } -} +import { WebviewInput } from 'vs/workbench/parts/webview/electron-browser/webviewInput'; +import { WebviewEditor } from 'vs/workbench/parts/webview/electron-browser/webviewEditor'; @extHostNamedCustomer(MainContext.MainThreadWebviews) @@ -550,9 +149,3 @@ export class MainThreadWebviews implements MainThreadWebviewsShape { } } } - -(Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor( - WebviewEditor, - WebviewEditor.ID, - localize('webview.editor.label', "webview editor")), - [new SyncDescriptor(WebviewInput)]); diff --git a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts index 04a9a71e29289ebc389eae8dd5e9abbde3a17ec4..916b4c531ce965d6394e9611b9ec172017e2759f 100644 --- a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts +++ b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts @@ -122,12 +122,6 @@ export class ReleaseNotesEditor extends WebviewEditor { super.dispose(); } - protected getViewState() { - return { - scrollYPercentage: this.scrollYPercentage - }; - } - public clearInput(): void { if (this.input instanceof ReleaseNotesInput) { this.saveViewState(this.input.version, { diff --git a/src/vs/workbench/parts/update/electron-browser/update.ts b/src/vs/workbench/parts/update/electron-browser/update.ts index 467c5b27d4587d13f27356511ddac2d81759d108..fbadd74907dfc61ff12f69de8a3b5e220999e125 100644 --- a/src/vs/workbench/parts/update/electron-browser/update.ts +++ b/src/vs/workbench/parts/update/electron-browser/update.ts @@ -45,7 +45,7 @@ const NotNowAction = new Action( const releaseNotesCache: { [version: string]: TPromise; } = Object.create(null); -export function loadReleaseNotes(accessor: ServicesAccessor, version: string): TPromise { +function loadReleaseNotes(accessor: ServicesAccessor, version: string): TPromise { const requestService = accessor.get(IRequestService); const keybindingService = accessor.get(IKeybindingService); const match = /^(\d+\.\d+)\./.exec(version); diff --git a/src/vs/workbench/parts/webview/electron-browser/webview.contribution.ts b/src/vs/workbench/parts/webview/electron-browser/webview.contribution.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a02b53af5fc1882604b61058f1be382226ceb3f --- /dev/null +++ b/src/vs/workbench/parts/webview/electron-browser/webview.contribution.ts @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; +import { WebviewEditor } from './webviewEditor'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { WebviewInput } from './webviewInput'; +import { localize } from 'vs/nls'; + +(Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor( + WebviewEditor, + WebviewEditor.ID, + localize('webview.editor.label', "webview editor")), + [new SyncDescriptor(WebviewInput)]); \ No newline at end of file diff --git a/src/vs/workbench/parts/webview/electron-browser/webviewEditor.ts b/src/vs/workbench/parts/webview/electron-browser/webviewEditor.ts new file mode 100644 index 0000000000000000000000000000000000000000..342df663ce824d0397bd6a88aeb97988c359153e --- /dev/null +++ b/src/vs/workbench/parts/webview/electron-browser/webviewEditor.ts @@ -0,0 +1,214 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { TPromise } from 'vs/base/common/winjs.base'; +import { IDisposable, } from 'vs/base/common/lifecycle'; +import { EditorOptions } from 'vs/workbench/common/editor'; +import { Position } from 'vs/platform/editor/common/editor'; +import { WebviewEditor as BaseWebviewEditor, KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS, KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from 'vs/workbench/parts/html/browser/webviewEditor'; +import { Builder, Dimension } from 'vs/base/browser/builder'; +import { Webview } from 'vs/workbench/parts/html/browser/webview'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import DOM = require('vs/base/browser/dom'); +import Event, { Emitter } from 'vs/base/common/event'; +import { WebviewInput } from 'vs/workbench/parts/webview/electron-browser/webviewInput'; + +export class WebviewEditor extends BaseWebviewEditor { + + public static readonly ID = 'WebviewEditor'; + + private editorFrame: HTMLElement; + private webviewContent: HTMLElement; + private _onDidFocusWebview: Emitter; + private _webviewFocusTracker?: DOM.IFocusTracker; + private _webviewFocusListenerDisposable?: IDisposable; + + constructor( + @ITelemetryService telemetryService: ITelemetryService, + @IStorageService storageService: IStorageService, + @IThemeService themeService: IThemeService, + @IContextKeyService private _contextKeyService: IContextKeyService, + @IPartService private readonly _partService: IPartService, + @IContextViewService private readonly _contextViewService: IContextViewService, + @IEnvironmentService private readonly _environmentService: IEnvironmentService, + @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService + ) { + super(WebviewEditor.ID, telemetryService, themeService, storageService, _contextKeyService); + + this._onDidFocusWebview = new Emitter(); + } + + protected createEditor(parent: Builder): void { + this.editorFrame = parent.getHTMLElement(); + this.content = document.createElement('div'); + parent.append(this.content); + } + + private doUpdateContainer() { + const webviewContainer = this.input && (this.input as WebviewInput).container; + if (webviewContainer) { + const frameRect = this.editorFrame.getBoundingClientRect(); + const containerRect = webviewContainer.parentElement.getBoundingClientRect(); + + webviewContainer.style.position = 'absolute'; + webviewContainer.style.top = `${frameRect.top - containerRect.top}px`; + webviewContainer.style.left = `${frameRect.left - containerRect.left}px`; + webviewContainer.style.width = `${frameRect.width}px`; + webviewContainer.style.height = `${frameRect.height}px`; + } + } + + public layout(dimension: Dimension): void { + if (this._webview) { + this.doUpdateContainer(); + } + super.layout(dimension); + } + + public dispose(): void { + // Let the editor input dispose of the webview. + this._webview = undefined; + this.webviewContent = undefined; + + this._onDidFocusWebview.dispose(); + + if (this._webviewFocusTracker) { + this._webviewFocusTracker.dispose(); + } + + if (this._webviewFocusListenerDisposable) { + this._webviewFocusListenerDisposable.dispose(); + } + + super.dispose(); + } + + public sendMessage(data: any): void { + if (this._webview) { + this._webview.sendMessage(data); + } + } + + public get onDidFocus(): Event { + return this._onDidFocusWebview.event; + } + + protected setEditorVisible(visible: boolean, position?: Position): void { + if (this.input && this.input instanceof WebviewInput) { + if (visible) { + this.input.claimWebview(this); + } else { + this.input.releaseWebview(this); + } + + this.updateWebview(this.input as WebviewInput); + } + + if (this.webviewContent) { + if (visible) { + this.webviewContent.style.visibility = 'visible'; + this.doUpdateContainer(); + } else { + this.webviewContent.style.visibility = 'hidden'; + } + } + + super.setEditorVisible(visible, position); + } + + public clearInput() { + if (this.input && this.input instanceof WebviewInput) { + this.input.releaseWebview(this); + } + + this._webview = undefined; + this.webviewContent = undefined; + + super.clearInput(); + } + + async setInput(input: WebviewInput, options: EditorOptions): TPromise { + if (this.input && this.input.matches(input)) { + return undefined; + } + + if (this.input && this.input.getResource().fsPath !== input.getResource().fsPath) { + (this.input as WebviewInput).releaseWebview(this); + this._webview = undefined; + this.webviewContent = undefined; + } + + await super.setInput(input, options); + + input.onDidChangePosition(this.position); + this.updateWebview(input); + } + + private updateWebview(input: WebviewInput) { + const webview = this.getWebview(input); + input.claimWebview(this); + webview.options = { + allowScripts: input.options.enableScripts, + enableWrappedPostMessage: true, + useSameOriginForRoot: false, + localResourceRoots: (input && input.options.localResourceRoots) || this._contextService.getWorkspace().folders.map(x => x.uri) + }; + input.setHtml(input.html); + this.webviewContent.style.visibility = 'visible'; + this.doUpdateContainer(); + } + + private getWebview(input: WebviewInput): Webview { + if (this._webview) { + return this._webview; + } + + this.webviewContent = input.container; + const existing = input.webview; + if (existing) { + this._webview = existing; + return existing; + } + + this._webviewFocusTracker = DOM.trackFocus(this.webviewContent); + this._webviewFocusListenerDisposable = this._webviewFocusTracker.onDidFocus(() => { + this._onDidFocusWebview.fire(); + }); + + this._contextKeyService = this._contextKeyService.createScoped(this.webviewContent); + this.contextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS.bindTo(this._contextKeyService); + this.findInputFocusContextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED.bindTo(this._contextKeyService); + this.findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService); + + this._webview = new Webview( + this.webviewContent, + this._partService.getContainer(Parts.EDITOR_PART), + this.themeService, + this._environmentService, + this._contextViewService, + this.contextKey, + this.findInputFocusContextKey, + { + enableWrappedPostMessage: true, + useSameOriginForRoot: false + }); + input.webview = this._webview; + + this.content.setAttribute('aria-flowto', this.webviewContent.id); + + this.doUpdateContainer(); + return this._webview; + } +} + diff --git a/src/vs/workbench/parts/webview/electron-browser/webviewInput.ts b/src/vs/workbench/parts/webview/electron-browser/webviewInput.ts new file mode 100644 index 0000000000000000000000000000000000000000..c96a211d1f918070738ac27eaf3070474df52845 --- /dev/null +++ b/src/vs/workbench/parts/webview/electron-browser/webviewInput.ts @@ -0,0 +1,212 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { TPromise } from 'vs/base/common/winjs.base'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { EditorInput, EditorModel } from 'vs/workbench/common/editor'; +import { IEditorModel, Position } from 'vs/platform/editor/common/editor'; +import { Webview } from 'vs/workbench/parts/html/browser/webview'; +import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; +import * as vscode from 'vscode'; +import URI from 'vs/base/common/uri'; + +export interface WebviewEvents { + onMessage(message: any): void; + onDidChangePosition(newPosition: Position): void; + onDispose(): void; + onDidClickLink(link: URI, options: vscode.WebviewOptions): void; +} + +export class WebviewInput extends EditorInput { + private static handlePool = 0; + + private readonly _resource: URI; + private _name: string; + private _options: vscode.WebviewOptions; + private _html: string; + private _currentWebviewHtml: string = ''; + private _events: WebviewEvents | undefined; + private _container: HTMLElement; + private _webview: Webview | undefined; + private _webviewOwner: any; + private _webviewDisposables: IDisposable[] = []; + private _position: Position; + + + public static create( + resource: URI, + name: string, + position: Position, + options: vscode.WebviewOptions, + html: string, + events: WebviewEvents, + partService: IPartService + ): WebviewInput { + const id = WebviewInput.handlePool++; + const webviewContainer = document.createElement('div'); + webviewContainer.id = `webview-${id}`; + + partService.getContainer(Parts.EDITOR_PART).appendChild(webviewContainer); + + return new WebviewInput(resource, name, position, options, html, events, webviewContainer, undefined); + } + + constructor( + resource: URI, + name: string, + position: Position, + options: vscode.WebviewOptions, + html: string, + events: WebviewEvents, + container: HTMLElement, + webview: Webview | undefined + ) { + super(); + this._resource = resource; + this._name = name; + this._position = position; + this._options = options; + this._html = html; + this._events = events; + + this._container = container; + this._webview = webview; + } + + public getTypeId(): string { + return 'webview'; + } + + public dispose() { + this.disposeWebview(); + + if (this._container) { + this._container.remove(); + this._container = undefined; + } + + if (this._events) { + this._events.onDispose(); + this._events = undefined; + } + + super.dispose(); + } + + public getResource(): URI { + return this._resource; + } + + public getName(): string { + return this._name; + } + + public setName(value: string): void { + this._name = value; + this._onDidChangeLabel.fire(); + } + + public get position(): Position { + return this._position; + } + + public get html(): string { + return this._html; + } + + public setHtml(value: string): void { + if (value === this._currentWebviewHtml) { + return; + } + + this._html = value; + + if (this._webview) { + this._webview.contents = value; + this._currentWebviewHtml = value; + } + } + + public get options(): vscode.WebviewOptions { + return this._options; + } + + public set options(value: vscode.WebviewOptions) { + this._options = value; + } + + public resolve(refresh?: boolean): TPromise { + return TPromise.as(new EditorModel()); + } + + public supportsSplitEditor() { + return false; + } + + public get container(): HTMLElement { + return this._container; + } + + public get webview(): Webview | undefined { + return this._webview; + } + + public set webview(value: Webview) { + this._webviewDisposables = dispose(this._webviewDisposables); + + this._webview = value; + + this._webview.onDidClickLink(link => { + if (this._events) { + this._events.onDidClickLink(link, this._options); + } + }, null, this._webviewDisposables); + + this._webview.onMessage(message => { + if (this._events) { + this._events.onMessage(message); + } + }, null, this._webviewDisposables); + } + + public claimWebview(owner: any) { + this._webviewOwner = owner; + } + + public releaseWebview(owner: any) { + if (this._webviewOwner === owner) { + this._webviewOwner = undefined; + if (this._options.retainContextWhenHidden) { + this.container.style.visibility = 'hidden'; + } else { + this.disposeWebview(); + } + } + } + + public disposeWebview() { + // The input owns the webview and its parent + if (this._webview) { + this._webview.dispose(); + this._webview = undefined; + } + + this._webviewDisposables = dispose(this._webviewDisposables); + + this._webviewOwner = undefined; + this.container.style.visibility = 'hidden'; + + this._currentWebviewHtml = ''; + } + + public onDidChangePosition(position: Position) { + if (this._events) { + this._events.onDidChangePosition(position); + } + this._position = position; + } +} diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 002fc32062a892c71f896871f78cb5ac25c4a1f3..6f2e0dec4595107a4764081b532619828304073d 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -68,6 +68,8 @@ import 'vs/workbench/parts/markers/browser/markersPanel'; // can be packaged sep import 'vs/workbench/parts/html/browser/html.contribution'; +import 'vs/workbench/parts/webview/electron-browser/webview.contribution'; + import 'vs/workbench/parts/welcome/walkThrough/electron-browser/walkThrough.contribution'; import 'vs/workbench/parts/extensions/electron-browser/extensions.contribution';