提交 9061cad5 编写于 作者: M Matt Bierner

Removing preview.html command

Fixes #62630
上级 491dd0fe
......@@ -74,23 +74,6 @@ suite('commands namespace tests', () => {
});
test('api-command: vscode.previewHtml', async function () {
let registration = workspace.registerTextDocumentContentProvider('speciale', {
provideTextDocumentContent(uri) {
return `content of URI <b>${uri.toString()}</b>`;
}
});
let virtualDocumentUri = Uri.parse('speciale://authority/path');
let title = 'A title';
const success = await commands.executeCommand('vscode.previewHtml', virtualDocumentUri, ViewColumn.Three, title);
assert.ok(success);
registration.dispose();
});
test('api-command: vscode.diff', function () {
let registration = workspace.registerTextDocumentContentProvider('sc', {
......
......@@ -36,19 +36,6 @@ function adjustHandler(handler: (executor: ICommandsExecutor, ...args: any[]) =>
};
}
export class PreviewHTMLAPICommand {
public static ID = 'vscode.previewHtml';
public static execute(executor: ICommandsExecutor, uri: URI, position?: vscode.ViewColumn, label?: string, options?: any): Promise<any> {
return executor.executeCommand('_workbench.previewHtml',
uri,
typeof position === 'number' && typeConverters.ViewColumn.from(position),
label,
options
);
}
}
CommandsRegistry.registerCommand(PreviewHTMLAPICommand.ID, adjustHandler(PreviewHTMLAPICommand.execute));
export class OpenFolderAPICommand {
public static ID = 'vscode.openFolder';
public static execute(executor: ICommandsExecutor, uri?: URI, forceNewWindow?: boolean): Promise<any> {
......
......@@ -175,23 +175,6 @@ export function createApiFactory(
};
})();
// Warn when trying to use the vscode.previewHtml command as it does not work properly in all scenarios and
// has security concerns.
const checkCommand = (() => {
let done = false;
const informOnce = () => {
if (!done) {
done = true;
window.showWarningMessage(localize('previewHtml.deprecated', "Extension '{0}' uses the 'vscode.previewHtml' command which is deprecated and will be removed soon. Please file an issue against this extension to update to use VS Code's webview API.", extension.identifier.value));
}
};
return (commandId: string) => {
if (commandId === 'vscode.previewHtml') {
informOnce();
}
return commandId;
};
})();
// namespace: commands
const commands: typeof vscode.commands = {
......@@ -232,7 +215,7 @@ export function createApiFactory(
});
}),
executeCommand<T>(id: string, ...args: any[]): Thenable<T> {
return extHostCommands.executeCommand<T>(checkCommand(id), ...args);
return extHostCommands.executeCommand<T>(id, ...args);
},
getCommands(filterInternal: boolean = false): Thenable<string[]> {
return extHostCommands.getCommands(filterInternal);
......
......@@ -15,7 +15,7 @@ import * as search from 'vs/workbench/contrib/search/common/search';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { CustomCodeAction } from 'vs/workbench/api/node/extHostLanguageFeatures';
import { ICommandsExecutor, PreviewHTMLAPICommand, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand } from './apiCommands';
import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand } from './apiCommands';
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
......@@ -219,20 +219,6 @@ export class ExtHostApiCommands {
};
};
this._register(PreviewHTMLAPICommand.ID, adjustHandler(PreviewHTMLAPICommand.execute), {
description: `
Render the HTML of the resource in an editor view.
See [working with the HTML preview](https://code.visualstudio.com/docs/extensionAPI/vscode-api-commands#working-with-the-html-preview) for more information about the HTML preview's integration with the editor and for best practices for extension authors.
`,
args: [
{ name: 'uri', description: 'Uri of the resource to preview.', constraint: (value: any) => value instanceof URI || typeof value === 'string' },
{ name: 'column', description: '(optional) Column in which to preview.', constraint: (value: any) => typeof value === 'undefined' || (typeof value === 'number' && typeof types.ViewColumn[value] === 'string') },
{ name: 'label', description: '(optional) An human readable string that is used as title for the preview.', constraint: (v: any) => typeof v === 'string' || typeof v === 'undefined' },
{ name: 'options', description: '(optional) Options for controlling webview environment.', constraint: (v: any) => typeof v === 'object' || typeof v === 'undefined' }
]
});
this._register(OpenFolderAPICommand.ID, adjustHandler(OpenFolderAPICommand.execute), {
description: 'Open a folder or workspace in the current window or new window depending on the newWindow argument. Note that opening in the same window will shutdown the current extension host process and start a new one on the given folder/workspace unless the newWindow parameter is set to true.',
args: [
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IHashService } from 'vs/workbench/services/hash/common/hashService';
export interface HtmlInputOptions {
readonly allowScripts?: boolean;
readonly allowSvgs?: boolean;
readonly svgWhiteList?: string[];
}
export function areHtmlInputOptionsEqual(left: HtmlInputOptions, right: HtmlInputOptions) {
return left.allowScripts === right.allowScripts && left.allowSvgs === right.allowSvgs;
}
export class HtmlInput extends ResourceEditorInput {
constructor(
name: string,
description: string,
resource: URI,
public readonly options: HtmlInputOptions,
@ITextModelService textModelResolverService: ITextModelService,
@IHashService hashService: IHashService
) {
super(name, description, resource, textModelResolverService, hashService);
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/shared/editor';
import { HtmlInput, HtmlInputOptions } from '../common/htmlInput';
import { HtmlPreviewPart } from './htmlPreviewPart';
import { Registry } from 'vs/platform/registry/common/platform';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
import { registerWebViewCommands } from 'vs/workbench/contrib/webview/electron-browser/webview.contribution';
// --- Register Editor
(Registry.as<IEditorRegistry>(EditorExtensions.Editors)).registerEditor(new EditorDescriptor(
HtmlPreviewPart,
HtmlPreviewPart.ID,
localize('html.editor.label', "Html Preview")),
[new SyncDescriptor(HtmlInput)]);
// --- Register Commands
CommandsRegistry.registerCommand('_workbench.previewHtml', function (
accessor: ServicesAccessor,
resource: URI | string,
position?: EditorViewColumn,
label?: string
) {
const uri = resource instanceof URI ? resource : URI.parse(resource);
label = label || uri.fsPath;
let input: HtmlInput | undefined;
const editorGroupService = accessor.get(IEditorGroupsService);
let targetGroup: IEditorGroup = editorGroupService.getGroup(viewColumnToEditorGroup(editorGroupService, position));
if (!targetGroup) {
targetGroup = editorGroupService.activeGroup;
}
// Find already opened HTML input if any
if (targetGroup) {
const editors = targetGroup.editors;
for (const editor of editors) {
const editorResource = editor.getResource();
if (editor instanceof HtmlInput && editorResource && editorResource.toString() === resource.toString()) {
input = editor;
break;
}
}
}
const extensionsWorkbenchService = accessor.get(IExtensionsWorkbenchService);
const inputOptions: HtmlInputOptions = {
allowScripts: true,
allowSvgs: true,
svgWhiteList: extensionsWorkbenchService.allowedBadgeProviders
};
// Otherwise, create new input and open it
if (!input) {
input = accessor.get(IInstantiationService).createInstance(HtmlInput, label, '', uri, inputOptions);
} else {
input.setName(label); // make sure to use passed in label
}
return accessor.get(IEditorService)
.openEditor(input, { pinned: true }, viewColumnToEditorGroup(editorGroupService, position))
.then(editor => true);
});
registerWebViewCommands(HtmlPreviewPart.ID);
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { Disposable, IDisposable, dispose, IReference } from 'vs/base/common/lifecycle';
import { EditorOptions, EditorInput, IEditorMemento } from 'vs/workbench/common/editor';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
import { HtmlInput, HtmlInputOptions, areHtmlInputOptionsEqual } from 'vs/workbench/contrib/html/common/htmlInput';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService';
import { Parts, IPartService } from 'vs/workbench/services/part/common/partService';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Dimension } from 'vs/base/browser/dom';
import { BaseWebviewEditor } from 'vs/workbench/contrib/webview/electron-browser/baseWebviewEditor';
import { WebviewElement, WebviewContentOptions } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Event, Emitter } from 'vs/base/common/event';
export interface HtmlPreviewEditorViewState {
scrollYPercentage: number;
}
/**
* An implementation of editor for showing HTML content in an IFrame by leveraging the HTML input.
*/
export class HtmlPreviewPart extends BaseWebviewEditor {
static readonly ID: string = 'workbench.editor.htmlPreviewPart';
static class: string = 'htmlPreviewPart';
private _webviewDisposables: IDisposable[];
private _modelRef?: IReference<ITextEditorModel>;
public get model() { return this._modelRef ? this._modelRef.object.textEditorModel : undefined; }
private _modelChangeSubscription = Disposable.None;
private _themeChangeSubscription = Disposable.None;
private _content: HTMLElement;
private _scrollYPercentage: number = 0;
private editorMemento: IEditorMemento<HtmlPreviewEditorViewState>;
private readonly _onDidFocusWebview = this._register(new Emitter<void>());
public get onDidFocus(): Event<any> { return this._onDidFocusWebview.event; }
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService,
@IContextKeyService contextKeyService: IContextKeyService,
@IOpenerService private readonly _openerService: IOpenerService,
@IPartService private readonly _partService: IPartService,
@IStorageService readonly _storageService: IStorageService,
@ITextModelService private readonly _textModelResolverService: ITextModelService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IEditorGroupsService readonly editorGroupService: IEditorGroupsService
) {
super(HtmlPreviewPart.ID, telemetryService, themeService, contextKeyService, _storageService);
this.editorMemento = this.getEditorMemento<HtmlPreviewEditorViewState>(editorGroupService, this.viewStateStorageKey);
}
dispose(): void {
// remove from dom
this._webviewDisposables = dispose(this._webviewDisposables);
// unhook listeners
this._themeChangeSubscription.dispose();
this._modelChangeSubscription.dispose();
// dispose model ref
dispose(this._modelRef);
super.dispose();
}
protected createEditor(parent: HTMLElement): void {
this._content = document.createElement('div');
this._content.style.position = 'absolute';
this._content.classList.add(HtmlPreviewPart.class);
parent.appendChild(this._content);
}
private get webview(): WebviewElement {
if (!this._webview) {
let webviewOptions: WebviewContentOptions = {};
if (this.input && this.input instanceof HtmlInput) {
webviewOptions = this.input.options;
}
this._webview = this._instantiationService.createInstance(WebviewElement,
this._partService.getContainer(Parts.EDITOR_PART),
{
useSameOriginForRoot: true
},
webviewOptions);
this._webview.mountTo(this._content);
if (this.input && this.input instanceof HtmlInput) {
const state = this.loadHTMLPreviewViewState(this.input);
this._scrollYPercentage = state ? state.scrollYPercentage : 0;
this.webview.initialScrollProgress = this._scrollYPercentage;
const resourceUri = this.input.getResource();
this.webview.baseUrl = resourceUri.toString(true);
}
this._webviewDisposables = [
this._webview,
this._webview.onDidClickLink(uri => this._openerService.open(uri)),
this._webview.onDidScroll(data => {
this._scrollYPercentage = data.scrollYPercentage;
}),
];
this._register(this._webview.onDidFocus(() => this._onDidFocusWebview.fire()));
}
return this._webview;
}
protected setEditorVisible(visible: boolean, group: IEditorGroup): void {
this._doSetVisible(visible);
super.setEditorVisible(visible, group);
}
private _doSetVisible(visible: boolean): void {
if (!visible) {
this._themeChangeSubscription.dispose();
this._modelChangeSubscription.dispose();
this._webviewDisposables = dispose(this._webviewDisposables);
this._webview = undefined;
} else {
this._themeChangeSubscription = this.themeService.onThemeChange(this.onThemeChange.bind(this));
if (this._hasValidModel()) {
this._modelChangeSubscription = this.model!.onDidChangeContent(() => this.webview.contents = this.model!.getLinesContent().join('\n'));
this.webview.contents = this.model!.getLinesContent().join('\n');
}
}
}
private _hasValidModel(): boolean {
return !!(this._modelRef && this.model && !this.model.isDisposed());
}
public layout(dimension: Dimension): void {
const { width, height } = dimension;
this._content.style.width = `${width}px`;
this._content.style.height = `${height}px`;
super.layout(dimension);
}
public clearInput(): void {
if (this.input instanceof HtmlInput) {
this.saveHTMLPreviewViewState(this.input, {
scrollYPercentage: this._scrollYPercentage
});
}
dispose(this._modelRef);
this._modelRef = undefined;
super.clearInput();
}
protected saveState(): void {
if (this.input instanceof HtmlInput) {
this.saveHTMLPreviewViewState(this.input, {
scrollYPercentage: this._scrollYPercentage
});
}
super.saveState();
}
public sendMessage(data: any): void {
this.webview.sendMessage(data);
}
public setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
if (this.input && this.input.matches(input) && this._hasValidModel() && this.input instanceof HtmlInput && input instanceof HtmlInput && areHtmlInputOptionsEqual(this.input.options, input.options)) {
return Promise.resolve(undefined);
}
let oldOptions: HtmlInputOptions | undefined = undefined;
if (this.input instanceof HtmlInput) {
oldOptions = this.input.options;
this.saveHTMLPreviewViewState(this.input, {
scrollYPercentage: this._scrollYPercentage
});
}
if (this._modelRef) {
this._modelRef.dispose();
}
this._modelChangeSubscription.dispose();
if (!(input instanceof HtmlInput)) {
return Promise.reject(new Error('Invalid input'));
}
return super.setInput(input, options, token).then(() => {
const resourceUri = input.getResource();
return this._textModelResolverService.createModelReference(resourceUri).then(ref => {
if (token.isCancellationRequested) {
return undefined;
}
const model = ref.object;
if (model instanceof BaseTextEditorModel) {
this._modelRef = ref;
}
if (!this.model) {
return Promise.reject(new Error(localize('html.voidInput', "Invalid editor input.")));
}
if (oldOptions && !areHtmlInputOptionsEqual(oldOptions, input.options)) {
this._doSetVisible(false);
}
this._modelChangeSubscription = this.model.onDidChangeContent(() => {
if (this.model) {
this._scrollYPercentage = 0;
this.webview.contents = this.model.getLinesContent().join('\n');
}
});
const state = this.loadHTMLPreviewViewState(input);
this._scrollYPercentage = state ? state.scrollYPercentage : 0;
this.webview.baseUrl = resourceUri.toString(true);
this.webview.options = input.options;
this.webview.contents = this.model.getLinesContent().join('\n');
this.webview.initialScrollProgress = this._scrollYPercentage;
return undefined;
});
});
}
private get viewStateStorageKey(): string {
return this.getId() + '.editorViewState';
}
private saveHTMLPreviewViewState(input: HtmlInput, editorViewState: HtmlPreviewEditorViewState): void {
this.editorMemento.saveEditorState(this.group!, input, editorViewState);
}
private loadHTMLPreviewViewState(input: HtmlInput): HtmlPreviewEditorViewState | undefined {
return this.editorMemento.loadEditorState(this.group!, input);
}
}
......@@ -98,9 +98,6 @@ import 'vs/workbench/contrib/markers/browser/markers.contribution';
// Comments
import 'vs/workbench/contrib/comments/electron-browser/comments.contribution';
// HTML Preview
import 'vs/workbench/contrib/html/electron-browser/html.contribution';
// URL Support
import 'vs/workbench/contrib/url/common/url.contribution';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册