提交 82084be1 编写于 作者: M Matt Bierner

Switch to use `vscode-resource` scheme in webviews

Fixes #45784
上级 a2ac383f
此差异已折叠。
......@@ -267,6 +267,13 @@
"fileMatch": "package.json",
"url": "./schemas/package.schema.json"
}
],
"markdown.previewStyles": [
"./media/markdown.css",
"./media/tomorrow.css"
],
"markdown.previewScripts": [
"./media/index.js"
]
},
"scripts": {
......
......@@ -90,8 +90,8 @@ document.addEventListener('click', event => {
if (node.getAttribute('href').startsWith('#')) {
break;
}
if (node.href.startsWith('file://') || node.href.startsWith('vscode-workspace-resource:')) {
const [path, fragment] = node.href.replace(/^(file:\/\/|vscode-workspace-resource:)/i, '').split('#');
if (node.href.startsWith('file://') || node.href.startsWith('vscode-resource:')) {
const [path, fragment] = node.href.replace(/^(file:\/\/|vscode-resource:)/i, '').split('#');
postCommand('_markdown.openDocumentLink', [{ path, fragment }]);
event.preventDefault();
event.stopPropagation();
......
......@@ -11,7 +11,7 @@ import { Logger } from './logger';
import { CommandManager } from './commandManager';
import * as commands from './commands/index';
import { loadDefaultTelemetryReporter } from './telemetryReporter';
import { loadMarkdownExtensions } from './markdownExtensions';
import { getMarkdownExtensionContributions } from './markdownExtensions';
import LinkProvider from './features/documentLinkProvider';
import MDDocumentSymbolProvider from './features/documentSymbolProvider';
import { MarkdownContentProvider } from './features/previewContentProvider';
......@@ -23,16 +23,17 @@ export function activate(context: vscode.ExtensionContext) {
const telemetryReporter = loadDefaultTelemetryReporter();
context.subscriptions.push(telemetryReporter);
const contributions = getMarkdownExtensionContributions();
const cspArbiter = new ExtensionContentSecurityPolicyArbiter(context.globalState, context.workspaceState);
const engine = new MarkdownEngine();
const engine = new MarkdownEngine(contributions);
const logger = new Logger();
const selector = 'markdown';
const contentProvider = new MarkdownContentProvider(engine, context, cspArbiter, logger);
loadMarkdownExtensions(contentProvider, engine);
const contentProvider = new MarkdownContentProvider(engine, context, cspArbiter, contributions, logger);
const previewManager = new MarkdownPreviewManager(contentProvider, logger);
const previewManager = new MarkdownPreviewManager(contentProvider, logger, contributions);
context.subscriptions.push(previewManager);
context.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(selector, new MDDocumentSymbolProvider(engine)));
......
......@@ -13,6 +13,7 @@ import { disposeAll } from '../util/dispose';
import * as nls from 'vscode-nls';
import { getVisibleLine, MarkdownFileTopmostLineMonitor } from '../util/topmostLineMonitor';
import { MarkdownPreviewConfigurationManager } from './previewConfig';
import { MarkdownContributions } from '../markdownExtensions';
const localize = nls.loadMessageBundle();
export class MarkdownPreview {
......@@ -37,7 +38,8 @@ export class MarkdownPreview {
private readonly contentProvider: MarkdownContentProvider,
private readonly previewConfigurations: MarkdownPreviewConfigurationManager,
private readonly logger: Logger,
topmostLineMonitor: MarkdownFileTopmostLineMonitor
topmostLineMonitor: MarkdownFileTopmostLineMonitor,
private readonly contributions: MarkdownContributions
) {
this.uri = vscode.Uri.parse(`${MarkdownPreview.previewScheme}:${MarkdownPreview.previewCount++}`);
this.webview = vscode.window.createWebview(
......@@ -251,16 +253,18 @@ export class MarkdownPreview {
}
private getLocalResourceRoots(resource: vscode.Uri): vscode.Uri[] {
const baseRoots = this.contributions.previewResourceRoots;
const folder = vscode.workspace.getWorkspaceFolder(resource);
if (folder) {
return [folder.uri];
return baseRoots.concat(folder.uri);
}
if (!resource.scheme || resource.scheme === 'file') {
return [vscode.Uri.file(path.dirname(resource.fsPath))];
return baseRoots.concat(vscode.Uri.file(path.dirname(resource.fsPath)));
}
return [];
return baseRoots;
}
private onDidScrollPreview(line: number) {
......
......@@ -13,6 +13,7 @@ const localize = nls.loadMessageBundle();
import { Logger } from '../logger';
import { ContentSecurityPolicyArbiter, MarkdownPreviewSecurityLevel } from '../security';
import { MarkdownPreviewConfigurationManager, MarkdownPreviewConfiguration } from './previewConfig';
import { MarkdownContributions } from '../markdownExtensions';
/**
* Strings used inside the markdown preview.
......@@ -35,24 +36,14 @@ const previewStrings = {
};
export class MarkdownContentProvider {
private readonly extraStyles: Array<vscode.Uri> = [];
private readonly extraScripts: Array<vscode.Uri> = [];
constructor(
private readonly engine: MarkdownEngine,
private readonly context: vscode.ExtensionContext,
private readonly cspArbiter: ContentSecurityPolicyArbiter,
private readonly extensionPreviewResourceProvider: MarkdownContributions,
private readonly logger: Logger
) { }
public addScript(resource: vscode.Uri): void {
this.extraScripts.push(resource);
}
public addStyle(resource: vscode.Uri): void {
this.extraStyles.push(resource);
}
public async provideTextDocumentContent(
markdownDocument: vscode.TextDocument,
previewConfigurations: MarkdownPreviewConfigurationManager,
......@@ -85,7 +76,7 @@ export class MarkdownContentProvider {
<meta id="vscode-markdown-preview-data" data-settings="${JSON.stringify(initialData).replace(/"/g, '&quot;')}" data-strings="${JSON.stringify(previewStrings).replace(/"/g, '&quot;')}">
<script src="${this.extensionResourcePath('pre.js')}" nonce="${nonce}"></script>
${this.getStyles(sourceUri, nonce, config)}
<base href="${markdownDocument.uri.with({ scheme: 'vscode-workspace-resource' }).toString(true)}">
<base href="${markdownDocument.uri.with({ scheme: 'vscode-resource' }).toString(true)}">
</head>
<body class="vscode-body ${config.scrollBeyondLastLine ? 'scrollBeyondLastLine' : ''} ${config.wordWrap ? 'wordWrap' : ''} ${config.markEditorSelection ? 'showEditorSelection' : ''}">
${body}
......@@ -97,7 +88,7 @@ export class MarkdownContentProvider {
private extensionResourcePath(mediaFile: string): string {
return vscode.Uri.file(this.context.asAbsolutePath(path.join('media', mediaFile)))
.with({ scheme: 'vscode-extension-resource' })
.with({ scheme: 'vscode-resource' })
.toString();
}
......@@ -115,7 +106,7 @@ export class MarkdownContentProvider {
// Use href as file URI if it is absolute
if (path.isAbsolute(href) || hrefUri.scheme === 'file') {
return vscode.Uri.file(href)
.with({ scheme: 'vscode-workspace-resource' })
.with({ scheme: 'vscode-resource' })
.toString();
}
......@@ -123,13 +114,13 @@ export class MarkdownContentProvider {
let root = vscode.workspace.getWorkspaceFolder(resource);
if (root) {
return vscode.Uri.file(path.join(root.uri.fsPath, href))
.with({ scheme: 'vscode-workspace-resource' })
.with({ scheme: 'vscode-resource' })
.toString();
}
// Otherwise look relative to the markdown file
return vscode.Uri.file(path.join(path.dirname(resource.fsPath), href))
.with({ scheme: 'vscode-workspace-resource' })
.with({ scheme: 'vscode-resource' })
.toString();
}
......@@ -153,10 +144,7 @@ export class MarkdownContentProvider {
}
private getStyles(resource: vscode.Uri, nonce: string, config: MarkdownPreviewConfiguration): string {
const baseStyles = [
this.extensionResourcePath('markdown.css'),
this.extensionResourcePath('tomorrow.css')
].concat(this.extraStyles.map(resource => resource.toString()));
const baseStyles = this.extensionPreviewResourceProvider.previewStyles.map(resource => resource.toString());
return `${baseStyles.map(href => `<link rel="stylesheet" type="text/css" href="${href}">`).join('\n')}
${this.getSettingsOverrideStyles(nonce, config)}
......@@ -164,7 +152,7 @@ export class MarkdownContentProvider {
}
private getScripts(nonce: string): string {
const scripts = [this.extensionResourcePath('index.js')].concat(this.extraScripts.map(resource => resource.toString()));
const scripts = this.extensionPreviewResourceProvider.previewScripts.map(resource => resource.toString());
return scripts
.map(source => `<script async src="${source}" nonce="${nonce}" charset="UTF-8"></script>`)
.join('\n');
......@@ -173,14 +161,14 @@ export class MarkdownContentProvider {
private getCspForResource(resource: vscode.Uri, nonce: string): string {
switch (this.cspArbiter.getSecurityLevelForResource(resource)) {
case MarkdownPreviewSecurityLevel.AllowInsecureContent:
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-workspace-resource: vscode-extension-resource: http: https: data:; media-src vscode-workspace-resource: vscode-extension-resource: http: https: data:; script-src 'nonce-${nonce}'; style-src vscode-workspace-resource: 'unsafe-inline' http: https: data: vscode-extension-resource:; font-src vscode-workspace-resource: vscode-extension-resource: http: https: data:;">`;
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: http: https: data:; media-src vscode-resource: http: https: data:; script-src 'nonce-${nonce}'; style-src vscode-resource: 'unsafe-inline' http: https: data:; font-src vscode-resource: http: https: data:;">`;
case MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent:
return '';
case MarkdownPreviewSecurityLevel.Strict:
default:
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-workspace-resource: vscode-extension-resource: https: data:; media-src vscode-workspace-resource: vscode-extension-resource: https: data:; script-src 'nonce-${nonce}'; style-src vscode-workspace-resource: 'unsafe-inline' https: data: vscode-extension-resource:; font-src vscode-workspace-resource: vscode-extension-resource: https: data:;">`;
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https: data:; media-src vscode-resource: https: data:; script-src 'nonce-${nonce}'; style-src vscode-resource: 'unsafe-inline' https: data:; font-src vscode-resource: https: data:;">`;
}
}
}
......@@ -12,6 +12,7 @@ import { disposeAll } from '../util/dispose';
import { MarkdownFileTopmostLineMonitor } from '../util/topmostLineMonitor';
import { isMarkdownFile } from '../util/file';
import { MarkdownPreviewConfigurationManager } from './previewConfig';
import { MarkdownContributions } from '../markdownExtensions';
export class MarkdownPreviewManager {
private static readonly markdownPreviewActiveContextKey = 'markdownPreviewFocus';
......@@ -24,7 +25,8 @@ export class MarkdownPreviewManager {
public constructor(
private readonly contentProvider: MarkdownContentProvider,
private readonly logger: Logger
private readonly logger: Logger,
private readonly contributions: MarkdownContributions
) {
vscode.window.onDidChangeActiveEditor(editor => {
vscode.commands.executeCommand('setContext', MarkdownPreviewManager.markdownPreviewActiveContextKey,
......@@ -122,7 +124,8 @@ export class MarkdownPreviewManager {
this.contentProvider,
this.previewConfigurations,
this.logger,
this.topmostLineMonitor);
this.topmostLineMonitor,
this.contributions);
preview.onDispose(() => {
const existing = this.previews.indexOf(preview!);
......
......@@ -7,6 +7,7 @@ import * as vscode from 'vscode';
import * as path from 'path';
import { Slug } from './tableOfContentsProvider';
import { MarkdownIt, Token } from 'markdown-it';
import { MarkdownContributions } from './markdownExtensions';
const FrontMatterRegex = /^---\s*[^]*?(-{3}|\.{3})\s*/;
......@@ -17,15 +18,9 @@ export class MarkdownEngine {
private currentDocument?: vscode.Uri;
private plugins: Array<(md: any) => any> = [];
public addPlugin(factory: (md: any) => any): void {
if (this.md) {
this.usePlugin(factory);
} else {
this.plugins.push(factory);
}
}
public constructor(
private readonly extensionPreviewResourceProvider: MarkdownContributions
) { }
private usePlugin(factory: (md: any) => any): void {
try {
......@@ -57,10 +52,9 @@ export class MarkdownEngine {
slugify: (header: string) => Slug.fromHeading(header).value
});
for (const plugin of this.plugins) {
this.usePlugin(plugin);
for (const plugin of this.extensionPreviewResourceProvider.markdownItPlugins) {
this.usePlugin(await plugin);
}
this.plugins = [];
for (const renderName of ['paragraph_open', 'heading_open', 'image', 'code_block', 'blockquote_open', 'list_item_open']) {
this.addLineNumberRenderer(this.md, renderName);
......@@ -154,7 +148,7 @@ export class MarkdownEngine {
fragment: Slug.fromHeading(fragment).value
});
}
return normalizeLink(uri.with({ scheme: 'vscode-workspace-resource' }).toString(true));
return normalizeLink(uri.with({ scheme: 'vscode-resource' }).toString(true));
} else if (!uri.scheme && !uri.path && uri.fragment) {
return normalizeLink(uri.with({
fragment: Slug.fromHeading(uri.fragment).value
......
......@@ -6,76 +6,115 @@
import * as vscode from 'vscode';
import * as path from 'path';
import { MarkdownContentProvider } from './features/previewContentProvider';
import { MarkdownEngine } from './markdownEngine';
const resolveExtensionResources = (extension: vscode.Extension<any>, resourcePath: string): vscode.Uri => {
return vscode.Uri.file(path.join(extension.extensionPath, resourcePath))
.with({ scheme: 'vscode-extension-resource' });
.with({ scheme: 'vscode-resource' });
};
export interface MarkdownContributions {
readonly previewScripts: vscode.Uri[];
readonly previewStyles: vscode.Uri[];
readonly markdownItPlugins: Thenable<(md: any) => any>[];
readonly previewResourceRoots: vscode.Uri[];
}
export function loadMarkdownExtensions(
contentProvider: MarkdownContentProvider,
engine: MarkdownEngine
) {
for (const extension of vscode.extensions.all) {
const contributes = extension.packageJSON && extension.packageJSON.contributes;
if (!contributes) {
continue;
}
class MarkdownExtensionContributions implements MarkdownContributions {
private readonly _scripts: vscode.Uri[] = [];
private readonly _styles: vscode.Uri[] = [];
private readonly _previewResourceRoots: vscode.Uri[] = [];
private readonly _plugins: Thenable<(md: any) => any>[] = [];
tryLoadPreviewStyles(contributes, contentProvider, extension);
tryLoadPreviewScripts(contributes, contentProvider, extension);
tryLoadMarkdownItPlugins(contributes, extension, engine);
private _loaded = false;
public get previewScripts(): vscode.Uri[] {
this.ensureLoaded();
return this._scripts;
}
public get previewStyles(): vscode.Uri[] {
this.ensureLoaded();
return this._styles;
}
public get previewResourceRoots(): vscode.Uri[] {
this.ensureLoaded();
return this._previewResourceRoots;
}
public get markdownItPlugins(): Thenable<(md: any) => any>[] {
this.ensureLoaded();
return this._plugins;
}
}
function tryLoadMarkdownItPlugins(
contributes: any,
extension: vscode.Extension<any>,
engine: MarkdownEngine
) {
if (contributes['markdown.markdownItPlugins']) {
extension.activate().then(() => {
if (extension.exports && extension.exports.extendMarkdownIt) {
engine.addPlugin((md: any) => extension.exports.extendMarkdownIt(md));
private ensureLoaded() {
if (this._loaded) {
return;
}
this._loaded = true;
for (const extension of vscode.extensions.all) {
const contributes = extension.packageJSON && extension.packageJSON.contributes;
if (!contributes) {
continue;
}
this.tryLoadPreviewStyles(contributes, extension);
this.tryLoadPreviewScripts(contributes, extension);
this.tryLoadMarkdownItPlugins(contributes, extension);
if (contributes['markdown.previewScripts'] || contributes['markdown.previewStyles']) {
this._previewResourceRoots.push(vscode.Uri.file(extension.extensionPath));
}
});
}
}
}
function tryLoadPreviewScripts(
contributes: any,
contentProvider: MarkdownContentProvider,
extension: vscode.Extension<any>
) {
const scripts = contributes['markdown.previewScripts'];
if (scripts && Array.isArray(scripts)) {
for (const script of scripts) {
try {
contentProvider.addScript(resolveExtensionResources(extension, script));
} catch (e) {
// noop
private tryLoadMarkdownItPlugins(
contributes: any,
extension: vscode.Extension<any>
) {
if (contributes['markdown.markdownItPlugins']) {
this._plugins.push(extension.activate().then(() => {
if (extension.exports && extension.exports.extendMarkdownIt) {
return (md: any) => extension.exports.extendMarkdownIt(md);
}
return (md: any) => md;
}));
}
}
private tryLoadPreviewScripts(
contributes: any,
extension: vscode.Extension<any>
) {
const scripts = contributes['markdown.previewScripts'];
if (scripts && Array.isArray(scripts)) {
for (const script of scripts) {
try {
this._scripts.push(resolveExtensionResources(extension, script));
} catch (e) {
// noop
}
}
}
}
}
function tryLoadPreviewStyles(
contributes: any,
contentProvider: MarkdownContentProvider,
extension: vscode.Extension<any>
) {
const styles = contributes['markdown.previewStyles'];
if (styles && Array.isArray(styles)) {
for (const style of styles) {
try {
contentProvider.addStyle(resolveExtensionResources(extension, style));
} catch (e) {
// noop
private tryLoadPreviewStyles(
contributes: any,
extension: vscode.Extension<any>
) {
const styles = contributes['markdown.previewStyles'];
if (styles && Array.isArray(styles)) {
for (const style of styles) {
try {
this._styles.push(resolveExtensionResources(extension, style));
} catch (e) {
// noop
}
}
}
}
}
export function getMarkdownExtensionContributions(): MarkdownContributions {
return new MarkdownExtensionContributions();
}
\ No newline at end of file
......@@ -9,13 +9,14 @@ import 'mocha';
import { TableOfContentsProvider } from '../tableOfContentsProvider';
import { MarkdownEngine } from '../markdownEngine';
import { MarkdownContributions } from '../markdownExtensions';
const testFileName = vscode.Uri.parse('test.md');
suite('markdown.TableOfContentsProvider', () => {
test('Lookup should not return anything for empty document', async () => {
const doc = new InMemoryDocument(testFileName, '');
const provider = new TableOfContentsProvider(new MarkdownEngine(), doc);
const provider = new TableOfContentsProvider(newEngine(), doc);
assert.strictEqual(await provider.lookup(''), undefined);
assert.strictEqual(await provider.lookup('foo'), undefined);
......@@ -23,7 +24,7 @@ suite('markdown.TableOfContentsProvider', () => {
test('Lookup should not return anything for document with no headers', async () => {
const doc = new InMemoryDocument(testFileName, 'a *b*\nc');
const provider = new TableOfContentsProvider(new MarkdownEngine(), doc);
const provider = new TableOfContentsProvider(newEngine(), doc);
assert.strictEqual(await provider.lookup(''), undefined);
assert.strictEqual(await provider.lookup('foo'), undefined);
......@@ -33,7 +34,7 @@ suite('markdown.TableOfContentsProvider', () => {
test('Lookup should return basic #header', async () => {
const doc = new InMemoryDocument(testFileName, `# a\nx\n# c`);
const provider = new TableOfContentsProvider(new MarkdownEngine(), doc);
const provider = new TableOfContentsProvider(newEngine(), doc);
{
const entry = await provider.lookup('a');
......@@ -52,7 +53,7 @@ suite('markdown.TableOfContentsProvider', () => {
test('Lookups should be case in-sensitive', async () => {
const doc = new InMemoryDocument(testFileName, `# fOo\n`);
const provider = new TableOfContentsProvider(new MarkdownEngine(), doc);
const provider = new TableOfContentsProvider(newEngine(), doc);
assert.strictEqual((await provider.lookup('fOo'))!.line, 0);
assert.strictEqual((await provider.lookup('foo'))!.line, 0);
......@@ -61,7 +62,7 @@ suite('markdown.TableOfContentsProvider', () => {
test('Lookups should ignore leading and trailing white-space, and collapse internal whitespace', async () => {
const doc = new InMemoryDocument(testFileName, `# f o o \n`);
const provider = new TableOfContentsProvider(new MarkdownEngine(), doc);
const provider = new TableOfContentsProvider(newEngine(), doc);
assert.strictEqual((await provider.lookup('f o o'))!.line, 0);
assert.strictEqual((await provider.lookup(' f o o'))!.line, 0);
......@@ -76,7 +77,7 @@ suite('markdown.TableOfContentsProvider', () => {
test('should normalize special characters #44779', async () => {
const doc = new InMemoryDocument(testFileName, `# Indentação\n`);
const provider = new TableOfContentsProvider(new MarkdownEngine(), doc);
const provider = new TableOfContentsProvider(newEngine(), doc);
assert.strictEqual((await provider.lookup('indentacao'))!.line, 0);
});
......@@ -136,3 +137,15 @@ class InMemoryDocument implements vscode.TextDocument {
throw new Error('Method not implemented.');
}
}
function newEngine(): MarkdownEngine {
return new MarkdownEngine(new class implements MarkdownContributions {
readonly previewScripts: vscode.Uri[] = [];
readonly previewStyles: vscode.Uri[] = [];
readonly previewResourceRoots: vscode.Uri[] = [];
readonly markdownItPlugins: Promise<(md: any) => any>[] = [];
});
}
......@@ -519,9 +519,9 @@ declare module 'vscode' {
readonly retainContextWhenHidden?: boolean;
/**
* Root paths from which the webview can load local (filesystem) resources using the `vscode-workspace-resource:` scheme.
* Root paths from which the webview can load local (filesystem) resources using the `vscode-resource:` scheme.
*
* Default to the root folders of the current workspace.
* Default to the root folders of the current workspace plus the extension's install directory.
*
* Pass in an empty array to disallow access to any local resources.
*/
......
......@@ -2,7 +2,6 @@
* 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 * as map from 'vs/base/common/map';
import { MainThreadWebviewsShape, MainContext, IExtHostContext, ExtHostContext, ExtHostWebviewsShape, WebviewHandle } from 'vs/workbench/api/node/extHost.protocol';
......@@ -47,7 +46,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape {
this._toDispose = dispose(this._toDispose);
}
$createWebview(handle: WebviewHandle, uri: URI, title: string, column: Position, options: vscode.WebviewOptions): void {
$createWebview(handle: WebviewHandle, uri: URI, title: string, column: Position, options: vscode.WebviewOptions, extensionFolderPath: string): void {
const webviewInput = new WebviewInput(URI.revive(uri), title, options, '', {
onMessage: message => this._proxy.$onMessage(handle, message),
onDidChangePosition: position => this._proxy.$onDidChangePosition(handle, position),
......
......@@ -413,7 +413,7 @@ export function createApiFactory(
return extHostDecorations.registerDecorationProvider(provider, extension.id);
}),
createWebview: proposedApiFunction(extension, (uri: vscode.Uri, title: string, column: vscode.ViewColumn, options: vscode.WebviewOptions) => {
return extHostWebviews.createWebview(uri, title, column, options);
return extHostWebviews.createWebview(uri, title, column, options, extension.extensionFolderPath);
}),
onDidChangeActiveEditor: proposedApiFunction(extension, (listener, thisArg?, disposables?) => {
return extHostDocumentsAndEditors.onDidChangeActiveEditor(listener, thisArg, disposables);
......
......@@ -345,7 +345,7 @@ export interface MainThreadTelemetryShape extends IDisposable {
export type WebviewHandle = number;
export interface MainThreadWebviewsShape extends IDisposable {
$createWebview(handle: WebviewHandle, uri: URI, title: string, column: EditorPosition, options: vscode.WebviewOptions): void;
$createWebview(handle: WebviewHandle, uri: URI, title: string, column: EditorPosition, options: vscode.WebviewOptions, extensionFolderPath: string): void;
$disposeWebview(handle: WebviewHandle): void;
$show(handle: WebviewHandle, column: EditorPosition): void;
$setTitle(handle: WebviewHandle, value: string): void;
......
......@@ -132,10 +132,11 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
uri: vscode.Uri,
title: string,
viewColumn: vscode.ViewColumn,
options: vscode.WebviewOptions
options: vscode.WebviewOptions,
extensionFolderPath: string
): vscode.Webview {
const handle = ExtHostWebviews.handlePool++;
this._proxy.$createWebview(handle, uri, title, typeConverters.fromViewColumn(viewColumn), options);
this._proxy.$createWebview(handle, uri, title, typeConverters.fromViewColumn(viewColumn), options, extensionFolderPath);
const webview = new ExtHostWebview(handle, this._proxy, uri, viewColumn, options);
this._webviews.set(handle, webview);
......
......@@ -3,8 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import Event, { Emitter } from 'vs/base/common/event';
......@@ -328,17 +326,7 @@ export class Webview {
appRootUri
]);
const extensionPaths = [
URI.file(this._environmentService.extensionsPath),
appRootUri,
];
if (this._environmentService.extensionDevelopmentPath) {
extensionPaths.push(URI.file(this._environmentService.extensionDevelopmentPath));
}
registerFileProtocol(contents, 'vscode-extension-resource', () => extensionPaths);
registerFileProtocol(contents, 'vscode-workspace-resource', () =>
registerFileProtocol(contents, 'vscode-resource', () =>
(this._options.localResourceRoots || [])
);
}
......@@ -443,7 +431,6 @@ function registerFileProtocol(
callback({ path: normalizedPath });
return;
}
}
callback({ error: 'Cannot load resource outside of protocol root' });
}, (error) => {
......
......@@ -12,7 +12,7 @@ import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer';
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 { ServicesAccessor } 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';
......@@ -56,7 +56,6 @@ export class ReleaseNotesManager {
public constructor(
@IEditorGroupService private readonly _editorGroupService: IEditorGroupService,
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IKeybindingService private readonly _keybindingService: IKeybindingService,
@IModeService private readonly _modeService: IModeService,
@IOpenerService private readonly _openerService: IOpenerService,
......@@ -85,7 +84,7 @@ export class ReleaseNotesManager {
}
} else {
const uri = URI.parse('release-notes:' + version);
this._currentReleaseNotes = this._instantiationService.createInstance(WebviewInput, uri, title, { tryRestoreScrollPosition: true }, html, {
this._currentReleaseNotes = new WebviewInput(uri, title, { tryRestoreScrollPosition: true }, html, {
onDidClickLink: uri => this.onDidClickLink(uri),
onDispose: () => { this._currentReleaseNotes = undefined; }
}, this._partService);
......
......@@ -22,6 +22,7 @@ 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';
import URI from 'vs/base/common/uri';
export class WebviewEditor extends BaseWebviewEditor {
......@@ -162,7 +163,7 @@ export class WebviewEditor extends BaseWebviewEditor {
allowSvgs: true,
enableWrappedPostMessage: true,
useSameOriginForRoot: false,
localResourceRoots: (input && input.options.localResourceRoots) || this._contextService.getWorkspace().folders.map(x => x.uri)
localResourceRoots: input.options.localResourceRoots || this.getDefaultLocalResourceRoots()
};
input.setHtml(input.html);
......@@ -173,6 +174,14 @@ export class WebviewEditor extends BaseWebviewEditor {
this.doUpdateContainer();
}
private getDefaultLocalResourceRoots(): URI[] {
const rootPaths = this._contextService.getWorkspace().folders.map(x => x.uri);
if ((this.input as WebviewInput).extensionFolderPath) {
rootPaths.push((this.input as WebviewInput).extensionFolderPath);
}
return rootPaths;
}
private getWebview(input: WebviewInput): Webview {
if (this._webview) {
return this._webview;
......
......@@ -40,6 +40,7 @@ export class WebviewInput extends EditorInput {
private _webviewDisposables: IDisposable[] = [];
private _position?: Position;
private _scrollYPercentage: number = 0;
public readonly extensionFolderPath: URI | undefined;
constructor(
resource: URI,
......@@ -47,7 +48,8 @@ export class WebviewInput extends EditorInput {
options: WebviewInputOptions,
html: string,
events: WebviewEvents,
partService: IPartService
partService: IPartService,
extensionFolderPath?: string
) {
super();
this._resource = resource;
......@@ -56,6 +58,10 @@ export class WebviewInput extends EditorInput {
this._html = html;
this._events = events;
if (extensionFolderPath) {
this.extensionFolderPath = URI.file(extensionFolderPath);
}
const id = WebviewInput.handlePool++;
this._container = document.createElement('div');
this._container.id = `webview-${id}`;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册