diff --git a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts index 4cbf81889ff..9bebcff3b53 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts @@ -48,7 +48,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape { } $createWebview(handle: WebviewHandle, uri: URI, title: string, column: Position, options: vscode.WebviewOptions): void { - const webviewInput = new WebviewInput(URI.revive(uri), title, column, options, '', { + const webviewInput = new WebviewInput(URI.revive(uri), title, options, '', { onMessage: message => this._proxy.$onMessage(handle, message), onDidChangePosition: position => this._proxy.$onDidChangePosition(handle, position), onDispose: () => { diff --git a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts index 916b4c531ce..82fc3eab9dc 100644 --- a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts +++ b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts @@ -7,31 +7,32 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { marked } from 'vs/base/common/marked/marked'; -import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; -import { Builder } from 'vs/base/browser/builder'; -import { append, $ } from 'vs/base/browser/dom'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ReleaseNotesInput } from './releaseNotesInput'; -import { EditorOptions } from 'vs/workbench/common/editor'; -import { Webview } from 'vs/workbench/parts/html/browser/webview'; -import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IModeService } from 'vs/editor/common/services/modeService'; import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer'; -import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; -import { WebviewEditor } from 'vs/workbench/parts/html/browser/webviewEditor'; -import { IStorageService } from 'vs/platform/storage/common/storage'; -import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IMode, TokenizationRegistry } from 'vs/editor/common/modes'; +import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { KeybindingIO } from 'vs/workbench/services/keybinding/common/keybindingIO'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IRequestService } from 'vs/platform/request/node/request'; 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 { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { WebviewInput } from 'vs/workbench/parts/webview/electron-browser/webviewInput'; import { onUnexpectedError } from 'vs/base/common/errors'; import { addGAParameters } from 'vs/platform/telemetry/node/telemetryNodeUtils'; -import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization'; +import URI from 'vs/base/common/uri'; +import { asText } from 'vs/base/node/request'; +import * as nls from 'vs/nls'; +import { OS } from 'vs/base/common/platform'; +import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; function renderBody( body: string, - css: string + css: string, + scrollProgress: number = 0 ): string { const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-core-resource://'); return ` @@ -47,97 +48,112 @@ function renderBody( `; } -export class ReleaseNotesEditor extends WebviewEditor { - static readonly ID: string = 'workbench.editor.releaseNotes'; +const releaseNotesCache: { [version: string]: TPromise; } = Object.create(null); - private contentDisposables: IDisposable[] = []; - private scrollYPercentage: number = 0; +function loadReleaseNotes(accessor: ServicesAccessor, version: string): TPromise { + const requestService = accessor.get(IRequestService); + const keybindingService = accessor.get(IKeybindingService); + const match = /^(\d+\.\d+)\./.exec(version); - constructor( - @ITelemetryService telemetryService: ITelemetryService, - @IStorageService storageService: IStorageService, - @IContextKeyService contextKeyService: IContextKeyService, - @IThemeService protected readonly themeService: IThemeService, - @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IOpenerService private readonly openerService: IOpenerService, - @IModeService private readonly modeService: IModeService, - @IPartService private readonly partService: IPartService, - @IContextViewService private readonly _contextViewService: IContextViewService - ) { - super(ReleaseNotesEditor.ID, telemetryService, themeService, storageService, contextKeyService); + if (!match) { + return TPromise.wrapError(new Error('not found')); } - createEditor(parent: Builder): void { - const container = parent.getHTMLElement(); - this.content = append(container, $('.release-notes', { 'style': 'height: 100%; position: relative; overflow: hidden;' })); - } + const versionLabel = match[1].replace(/\./g, '_'); + const baseUrl = 'https://code.visualstudio.com/raw'; + const url = `${baseUrl}/v${versionLabel}.md`; + const unassigned = nls.localize('unassigned', "unassigned"); - async setInput(input: ReleaseNotesInput, options: EditorOptions): TPromise { - if (this.input && this.input.matches(input)) { - return undefined; - } + const patchKeybindings = (text: string): string => { + const kb = (match: string, kb: string) => { + const keybinding = keybindingService.lookupKeybinding(kb); - const { text } = input; - - this.contentDisposables = dispose(this.contentDisposables); - this.content.innerHTML = ''; - - await super.setInput(input, options); - - const body = await this.renderBody(text); - this._webview = new Webview( - this.content, - this.partService.getContainer(Parts.EDITOR_PART), - this.themeService, - this.environmentService, - this._contextViewService, - this.contextKey, - this.findInputFocusContextKey, - {}); - - if (this.input && this.input instanceof ReleaseNotesInput) { - const state = this.loadViewState(this.input.version); - if (state) { - this._webview.initialScrollProgress = state.scrollYPercentage; + if (!keybinding) { + return unassigned; } - } - this._webview.contents = body; + return keybinding.getLabel(); + }; - this._webview.onDidClickLink(link => { - addGAParameters(this.telemetryService, this.environmentService, link, 'ReleaseNotes') - .then(updated => this.openerService.open(updated)) - .then(null, onUnexpectedError); - }, null, this.contentDisposables); - this._webview.onDidScroll(event => { - this.scrollYPercentage = event.scrollYPercentage; - }, null, this.contentDisposables); - this.contentDisposables.push(this._webview); - this.contentDisposables.push(toDisposable(() => this._webview = null)); + const kbstyle = (match: string, kb: string) => { + const keybinding = KeybindingIO.readKeybinding(kb, OS); + + if (!keybinding) { + return unassigned; + } + + const resolvedKeybindings = keybindingService.resolveKeybinding(keybinding); + + if (resolvedKeybindings.length === 0) { + return unassigned; + } + + return resolvedKeybindings[0].getLabel(); + }; + + return text + .replace(/kb\(([a-z.\d\-]+)\)/gi, kb) + .replace(/kbstyle\(([^\)]+)\)/gi, kbstyle); + }; + + if (!releaseNotesCache[version]) { + releaseNotesCache[version] = requestService.request({ url }) + .then(asText) + .then(text => patchKeybindings(text)); } - dispose(): void { - this.contentDisposables = dispose(this.contentDisposables); - super.dispose(); + return releaseNotesCache[version]; +} + +export class ReleaseNotesManager { + + private _currentReleaseNotes: WebviewInput | undefined; + + public constructor( + @IWorkbenchEditorService private readonly _editorService: IWorkbenchEditorService, + @IEditorGroupService private readonly _editorGroupService: IEditorGroupService, + @IEnvironmentService private readonly _environmentService: IEnvironmentService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @IModeService private readonly _modeService: IModeService, + @IOpenerService private readonly _openerService: IOpenerService, + @IPartService private readonly _partService: IPartService, + @ITelemetryService private readonly _telemetryService: ITelemetryService, + ) { } + + public async show( + accessor: ServicesAccessor, + version: string + ): TPromise { + const releaseNoteText = await loadReleaseNotes(accessor, version); + const html = await this.renderBody(releaseNoteText); + const title = nls.localize('releaseNotesInputName', "Release Notes: {0}", version); + + if (this._currentReleaseNotes) { + this._currentReleaseNotes.setName(title); + this._currentReleaseNotes.setHtml(html); + const activeEditor = this._editorService.getActiveEditor(); + if (activeEditor && activeEditor.position !== this._currentReleaseNotes.position) { + this._editorGroupService.moveEditor(this._currentReleaseNotes, this._currentReleaseNotes.position, activeEditor.position, { preserveFocus: true }); + } else { + this._editorService.openEditor(this._currentReleaseNotes, { preserveFocus: true }); + } + } else { + const uri = URI.parse('release-notes:' + version); + this._currentReleaseNotes = this._instantiationService.createInstance(WebviewInput, uri, title, { tryRestoreScrollPosition: true }, html, { + onDidClickLink: uri => this.onDidClickLink(uri), + onDispose: () => { this._currentReleaseNotes = undefined; } + }, this._partService); + await this._editorService.openEditor(this._currentReleaseNotes, { pinned: true }); + } + + return true; } - public clearInput(): void { - if (this.input instanceof ReleaseNotesInput) { - this.saveViewState(this.input.version, { - scrollYPercentage: this.scrollYPercentage - }); - } - super.clearInput(); - } - - public shutdown(): void { - if (this.input instanceof ReleaseNotesInput) { - this.saveViewState(this.input.version, { - scrollYPercentage: this.scrollYPercentage - }); - } - super.shutdown(); + private onDidClickLink(uri: URI) { + addGAParameters(this._telemetryService, this._environmentService, uri, 'ReleaseNotes') + .then(updated => this._openerService.open(updated)) + .then(null, onUnexpectedError); } private async renderBody(text: string) { @@ -156,8 +172,8 @@ export class ReleaseNotesEditor extends WebviewEditor { const result: TPromise[] = []; const renderer = new marked.Renderer(); renderer.code = (code, lang) => { - const modeId = this.modeService.getModeIdForLanguageName(lang); - result.push(this.modeService.getOrCreateMode(modeId)); + const modeId = this._modeService.getModeIdForLanguageName(lang); + result.push(this._modeService.getOrCreateMode(modeId)); return ''; }; @@ -165,7 +181,7 @@ export class ReleaseNotesEditor extends WebviewEditor { await TPromise.join(result); renderer.code = (code, lang) => { - const modeId = this.modeService.getModeIdForLanguageName(lang); + const modeId = this._modeService.getModeIdForLanguageName(lang); return `${tokenizeToString(code, modeId)}`; }; return renderer; diff --git a/src/vs/workbench/parts/update/electron-browser/releaseNotesInput.ts b/src/vs/workbench/parts/update/electron-browser/releaseNotesInput.ts deleted file mode 100644 index 7be415c613b..00000000000 --- a/src/vs/workbench/parts/update/electron-browser/releaseNotesInput.ts +++ /dev/null @@ -1,52 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { localize } from 'vs/nls'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { EditorInput } from 'vs/workbench/common/editor'; -import URI from 'vs/base/common/uri'; - -export class ReleaseNotesInput extends EditorInput { - - static readonly ID = 'workbench.releaseNotes.input'; - - get version(): string { return this._version; } - get text(): string { return this._text; } - - constructor(private _version: string, private _text: string) { - super(); - } - - getResource(): URI { - return URI.from({ scheme: 'release-notes', path: `${this._version}.release-notes` }); - } - - getTypeId(): string { - return ReleaseNotesInput.ID; - } - - getName(): string { - return localize('releaseNotesInputName', "Release Notes: {0}", this.version); - } - - matches(other: any): boolean { - if (!(other instanceof ReleaseNotesInput)) { - return false; - } - - const otherInput = other as ReleaseNotesInput; - return this.version === otherInput.version; - } - - resolve(refresh?: boolean): TPromise { - return TPromise.as(null); - } - - supportsSplitEditor(): boolean { - return false; - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/update/electron-browser/update.contribution.ts b/src/vs/workbench/parts/update/electron-browser/update.contribution.ts index 73400b9d5c1..1a2d956f296 100644 --- a/src/vs/workbench/parts/update/electron-browser/update.contribution.ts +++ b/src/vs/workbench/parts/update/electron-browser/update.contribution.ts @@ -5,20 +5,15 @@ 'use strict'; -import * as nls from 'vs/nls'; import 'vs/css!./media/update.contribution'; import 'vs/platform/update/node/update.config.contribution'; import * as platform from 'vs/base/common/platform'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { ReleaseNotesEditor } from 'vs/workbench/parts/update/electron-browser/releaseNotesEditor'; -import { ReleaseNotesInput } from 'vs/workbench/parts/update/electron-browser/releaseNotesInput'; import { IGlobalActivityRegistry, GlobalActivityExtensions } from 'vs/workbench/common/activity'; -import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, Win3264BitContribution } from './update'; -import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; Registry.as(WorkbenchExtensions.Workbench) @@ -33,14 +28,5 @@ Registry.as(GlobalActivityExtensions) .registerActivity(UpdateContribution); // Editor -const editorDescriptor = new EditorDescriptor( - ReleaseNotesEditor, - ReleaseNotesEditor.ID, - nls.localize('release notes', "Release notes") -); - -Registry.as(EditorExtensions.Editors) - .registerEditor(editorDescriptor, [new SyncDescriptor(ReleaseNotesInput)]); - Registry.as(ActionExtensions.WorkbenchActions) .registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), 'Show Release Notes'); diff --git a/src/vs/workbench/parts/update/electron-browser/update.ts b/src/vs/workbench/parts/update/electron-browser/update.ts index fbadd74907d..bdea885df04 100644 --- a/src/vs/workbench/parts/update/electron-browser/update.ts +++ b/src/vs/workbench/parts/update/electron-browser/update.ts @@ -16,24 +16,19 @@ import product from 'vs/platform/node/product'; import URI from 'vs/base/common/uri'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IActivityService, NumberBadge, IBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; -import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { ReleaseNotesInput } from 'vs/workbench/parts/update/electron-browser/releaseNotesInput'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IGlobalActivity } from 'vs/workbench/common/activity'; -import { IRequestService } from 'vs/platform/request/node/request'; -import { asText } from 'vs/base/node/request'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { KeybindingIO } from 'vs/workbench/services/keybinding/common/keybindingIO'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IUpdateService, State as UpdateState, StateType, IUpdate } from 'vs/platform/update/common/update'; import * as semver from 'semver'; -import { OS } from 'vs/base/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IChoiceService } from 'vs/platform/dialogs/common/dialogs'; import { IWindowService } from 'vs/platform/windows/common/windows'; +import { ReleaseNotesManager } from './releaseNotesEditor'; const NotNowAction = new Action( 'update.later', @@ -43,61 +38,14 @@ const NotNowAction = new Action( () => TPromise.as(true) ); -const releaseNotesCache: { [version: string]: TPromise; } = Object.create(null); +let releaseNotesManager: ReleaseNotesManager | undefined = undefined; -function loadReleaseNotes(accessor: ServicesAccessor, version: string): TPromise { - const requestService = accessor.get(IRequestService); - const keybindingService = accessor.get(IKeybindingService); - const match = /^(\d+\.\d+)\./.exec(version); - - if (!match) { - return TPromise.wrapError(new Error('not found')); +function showReleaseNotes(instantiationService: IInstantiationService, version: string) { + if (!releaseNotesManager) { + releaseNotesManager = instantiationService.createInstance(ReleaseNotesManager); } - const versionLabel = match[1].replace(/\./g, '_'); - const baseUrl = 'https://code.visualstudio.com/raw'; - const url = `${baseUrl}/v${versionLabel}.md`; - const unassigned = nls.localize('unassigned', "unassigned"); - - const patchKeybindings = (text: string): string => { - const kb = (match: string, kb: string) => { - const keybinding = keybindingService.lookupKeybinding(kb); - - if (!keybinding) { - return unassigned; - } - - return keybinding.getLabel(); - }; - - const kbstyle = (match: string, kb: string) => { - const keybinding = KeybindingIO.readKeybinding(kb, OS); - - if (!keybinding) { - return unassigned; - } - - const resolvedKeybindings = keybindingService.resolveKeybinding(keybinding); - - if (resolvedKeybindings.length === 0) { - return unassigned; - } - - return resolvedKeybindings[0].getLabel(); - }; - - return text - .replace(/kb\(([a-z.\d\-]+)\)/gi, kb) - .replace(/kbstyle\(([^\)]+)\)/gi, kbstyle); - }; - - if (!releaseNotesCache[version]) { - releaseNotesCache[version] = requestService.request({ url }) - .then(asText) - .then(text => patchKeybindings(text)); - } - - return releaseNotesCache[version]; + return instantiationService.invokeFunction(accessor => releaseNotesManager.show(accessor, version)); } export class OpenLatestReleaseNotesInBrowserAction extends Action { @@ -120,7 +68,6 @@ export abstract class AbstractShowReleaseNotesAction extends Action { id: string, label: string, private version: string, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IInstantiationService private instantiationService: IInstantiationService ) { super(id, label, null, true); @@ -133,9 +80,7 @@ export abstract class AbstractShowReleaseNotesAction extends Action { this.enabled = false; - return this.instantiationService.invokeFunction(loadReleaseNotes, this.version) - .then(text => this.editorService.openEditor(this.instantiationService.createInstance(ReleaseNotesInput, this.version, text), { pinned: true })) - .then(() => true) + return showReleaseNotes(this.instantiationService, this.version) .then(null, () => { const action = this.instantiationService.createInstance(OpenLatestReleaseNotesInBrowserAction); return action.run().then(() => false); @@ -147,10 +92,9 @@ export class ShowReleaseNotesAction extends AbstractShowReleaseNotesAction { constructor( version: string, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IInstantiationService instantiationService: IInstantiationService ) { - super('update.showReleaseNotes', nls.localize('releaseNotes', "Release Notes"), version, editorService, instantiationService); + super('update.showReleaseNotes', nls.localize('releaseNotes', "Release Notes"), version, instantiationService); } } @@ -162,10 +106,9 @@ export class ShowCurrentReleaseNotesAction extends AbstractShowReleaseNotesActio constructor( id = ShowCurrentReleaseNotesAction.ID, label = ShowCurrentReleaseNotesAction.LABEL, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IInstantiationService instantiationService: IInstantiationService ) { - super(id, label, pkg.version, editorService, instantiationService); + super(id, label, pkg.version, instantiationService); } } @@ -184,9 +127,8 @@ export class ProductContribution implements IWorkbenchContribution { // was there an update? if so, open release notes if (!environmentService.skipReleaseNotes && product.releaseNotesUrl && lastVersion && pkg.version !== lastVersion) { - instantiationService.invokeFunction(loadReleaseNotes, pkg.version).then( - text => editorService.openEditor(instantiationService.createInstance(ReleaseNotesInput, pkg.version, text), { pinned: true }), - () => { + showReleaseNotes(instantiationService, lastVersion) + .then(() => { notificationService.notify({ severity: severity.Info, message: nls.localize('read the release notes', "Welcome to {0} v{1}! Would you like to read the Release Notes?", product.nameLong, pkg.version), diff --git a/src/vs/workbench/parts/webview/electron-browser/webviewEditor.ts b/src/vs/workbench/parts/webview/electron-browser/webviewEditor.ts index 342df663ce8..8ef51e490ec 100644 --- a/src/vs/workbench/parts/webview/electron-browser/webviewEditor.ts +++ b/src/vs/workbench/parts/webview/electron-browser/webviewEditor.ts @@ -205,6 +205,10 @@ export class WebviewEditor extends BaseWebviewEditor { }); input.webview = this._webview; + if (input.options.tryRestoreScrollPosition) { + this._webview.initialScrollProgress = input.scrollYPercentage; + } + this.content.setAttribute('aria-flowto', this.webviewContent.id); this.doUpdateContainer(); diff --git a/src/vs/workbench/parts/webview/electron-browser/webviewInput.ts b/src/vs/workbench/parts/webview/electron-browser/webviewInput.ts index 30bc7896e6e..4d6c64fdd9d 100644 --- a/src/vs/workbench/parts/webview/electron-browser/webviewInput.ts +++ b/src/vs/workbench/parts/webview/electron-browser/webviewInput.ts @@ -8,17 +8,21 @@ 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 { IEditorModel, Position, IEditorInput } 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; + onMessage?(message: any): void; + onDidChangePosition?(newPosition: Position): void; + onDispose?(): void; + onDidClickLink?(link: URI, options: vscode.WebviewOptions): void; +} + +export interface WebviewInputOptions extends vscode.WebviewOptions { + tryRestoreScrollPosition?: boolean; } export class WebviewInput extends EditorInput { @@ -26,7 +30,7 @@ export class WebviewInput extends EditorInput { private readonly _resource: URI; private _name: string; - private _options: vscode.WebviewOptions; + private _options: WebviewInputOptions; private _html: string; private _currentWebviewHtml: string = ''; private _events: WebviewEvents | undefined; @@ -34,13 +38,13 @@ export class WebviewInput extends EditorInput { private _webview: Webview | undefined; private _webviewOwner: any; private _webviewDisposables: IDisposable[] = []; - private _position: Position; + private _position?: Position; + private _scrollYPercentage: number = 0; constructor( resource: URI, name: string, - position: Position, - options: vscode.WebviewOptions, + options: WebviewInputOptions, html: string, events: WebviewEvents, partService: IPartService @@ -48,7 +52,6 @@ export class WebviewInput extends EditorInput { super(); this._resource = resource; this._name = name; - this._position = position; this._options = options; this._html = html; this._events = events; @@ -93,7 +96,11 @@ export class WebviewInput extends EditorInput { this._onDidChangeLabel.fire(); } - public get position(): Position { + matches(other: IEditorInput): boolean { + return other && other instanceof WebviewInput && other.getResource().fsPath === this.getResource().fsPath; + } + + public get position(): Position | undefined { return this._position; } @@ -114,11 +121,11 @@ export class WebviewInput extends EditorInput { } } - public get options(): vscode.WebviewOptions { + public get options(): WebviewInputOptions { return this._options; } - public set options(value: vscode.WebviewOptions) { + public set options(value: WebviewInputOptions) { this._options = value; } @@ -144,16 +151,24 @@ export class WebviewInput extends EditorInput { this._webview = value; this._webview.onDidClickLink(link => { - if (this._events) { + if (this._events && this._events.onDidClickLink) { this._events.onDidClickLink(link, this._options); } }, null, this._webviewDisposables); this._webview.onMessage(message => { - if (this._events) { + if (this._events && this._events.onMessage) { this._events.onMessage(message); } }, null, this._webviewDisposables); + + this._webview.onDidScroll(message => { + this._scrollYPercentage = message.scrollYPercentage; + }, null, this._webviewDisposables); + } + + public get scrollYPercentage() { + return this._scrollYPercentage; } public claimWebview(owner: any) { @@ -187,7 +202,7 @@ export class WebviewInput extends EditorInput { } public onDidChangePosition(position: Position) { - if (this._events) { + if (this._events && this._events.onDidChangePosition) { this._events.onDidChangePosition(position); } this._position = position;