Add acquireVsCodeApi to get handle to vscode api inside webview

Fixes #48540
This commit is contained in:
Matt Bierner 2018-04-25 22:27:51 -07:00
parent 6d7bb1a174
commit 82d97b4c3c
8 changed files with 155 additions and 118 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3,33 +3,48 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { MessagePoster } from './messaging';
import { getSettings } from './settings';
import { getStrings } from './strings';
import { postCommand } from './messaging';
/**
* Shows an alert when there is a content security policy violation.
*/
export class CspAlerter {
private didShow = false;
private didHaveCspWarning = false;
private messaging?: MessagePoster;
constructor() {
document.addEventListener('securitypolicyviolation', () => {
this.showCspWarning();
this.onCspWarning();
});
window.addEventListener('message', (event) => {
if (event && event.data && event.data.name === 'vscode-did-block-svg') {
this.showCspWarning();
this.onCspWarning();
}
});
}
public setPoster(poster: MessagePoster) {
this.messaging = poster;
if (this.didHaveCspWarning) {
this.showCspWarning();
}
}
private onCspWarning() {
this.didHaveCspWarning = true;
this.showCspWarning();
}
private showCspWarning() {
const strings = getStrings();
const settings = getSettings();
if (this.didShow || settings.disableSecurityWarnings) {
if (this.didShow || settings.disableSecurityWarnings || !this.messaging) {
return;
}
this.didShow = true;
@ -42,7 +57,7 @@ export class CspAlerter {
notification.setAttribute('role', 'button');
notification.setAttribute('aria-label', strings.cspAlertMessageLabel);
notification.onclick = () => {
postCommand('markdown.showPreviewSecuritySelector', [settings.source]);
this.messaging!.postCommand('markdown.showPreviewSecuritySelector', [settings.source]);
};
document.body.appendChild(notification);
}

View file

@ -3,17 +3,27 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { getSettings } from './settings';
import { postCommand, postMessage } from './messaging';
import { onceDocumentLoaded } from './events';
import { getEditorLineNumberForPageOffset, scrollToRevealSourceLine } from './scroll-sync';
import { ActiveLineMarker } from './activeLineMarker';
import { onceDocumentLoaded } from './events';
import { createPosterForVsCode } from './messaging';
import { getEditorLineNumberForPageOffset, scrollToRevealSourceLine } from './scroll-sync';
import { getSettings } from './settings';
import throttle = require('lodash.throttle');
declare var acquireVsCodeApi: any;
var scrollDisabled = true;
const marker = new ActiveLineMarker();
const settings = getSettings();
const vscode = acquireVsCodeApi();
vscode.postMessage({});
const messaging = createPosterForVsCode(vscode);
window.cspAlerter.setPoster(messaging);
window.styleLoadingMonitor.setPoster(messaging);
onceDocumentLoaded(() => {
if (settings.scrollPreviewWithEditor) {
setTimeout(() => {
@ -75,7 +85,7 @@ document.addEventListener('dblclick', event => {
const offset = event.pageY;
const line = getEditorLineNumberForPageOffset(offset);
if (typeof line === 'number' && !isNaN(line)) {
postMessage('didClick', { line: Math.floor(line) });
messaging.postMessage('didClick', { line: Math.floor(line) });
}
});
@ -92,7 +102,7 @@ document.addEventListener('click', event => {
}
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 }]);
messaging.postCommand('_markdown.openDocumentLink', [{ path, fragment }]);
event.preventDefault();
event.stopPropagation();
break;
@ -110,7 +120,7 @@ if (settings.scrollEditorWithPreview) {
} else {
const line = getEditorLineNumberForPageOffset(window.scrollY);
if (typeof line === 'number' && !isNaN(line)) {
postMessage('revealLine', { line });
messaging.postMessage('revealLine', { line });
}
}
}, 50));

View file

@ -2,10 +2,13 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { postCommand } from './messaging';
import { MessagePoster } from './messaging';
export class StyleLoadingMonitor {
private unloadedStyles: string[] = [];
private finishedLoading: boolean = false;
private poster?: MessagePoster;
constructor() {
const onStyleLoadError = (event: any) => {
@ -25,7 +28,17 @@ export class StyleLoadingMonitor {
if (!this.unloadedStyles.length) {
return;
}
postCommand('_markdown.onPreviewStyleLoadError', [this.unloadedStyles]);
this.finishedLoading = true;
if (this.poster) {
this.poster.postCommand('_markdown.onPreviewStyleLoadError', [this.unloadedStyles]);
}
});
}
public setPoster(poster: MessagePoster): void {
this.poster = poster;
if (this.finishedLoading) {
poster.postCommand('_markdown.onPreviewStyleLoadError', [this.unloadedStyles]);
}
}
}

View file

@ -5,22 +5,31 @@
import { getSettings } from './settings';
declare var vscode: any;
export interface MessagePoster {
/**
* Post a message to the markdown extension
*/
postMessage(type: string, body: object): void;
/**
* Post a message to the markdown extension
*/
export function postMessage(type: string, body: object) {
vscode.postMessage({
type,
source: getSettings().source,
body
});
/**
* Post a command to be executed to the markdown extension
*/
postCommand(command: string, args: any[]): void;
}
/**
* Post a command to be executed to the markdown extension
*/
export function postCommand(command: string, args: any[]) {
postMessage('command', { command, args });
}
export const createPosterForVsCode = (vscode: any) => {
return new class implements MessagePoster {
postMessage(type: string, body: object): void {
vscode.postMessage({
type,
source: getSettings().source,
body
});
}
postCommand(command: string, args: any[]) {
this.postMessage('command', { command, args });
}
};
};

View file

@ -6,8 +6,12 @@
import { CspAlerter } from './csp';
import { StyleLoadingMonitor } from './loading';
// tslint:disable-next-line:no-unused-expression
new CspAlerter();
declare global {
interface Window {
cspAlerter: CspAlerter;
styleLoadingMonitor: StyleLoadingMonitor;
}
}
// tslint:disable-next-line:no-unused-expression
new StyleLoadingMonitor();
window.cspAlerter = new CspAlerter();
window.styleLoadingMonitor = new StyleLoadingMonitor();

View file

@ -178,15 +178,25 @@
if (enableWrappedPostMessage) {
const defaultScript = newDocument.createElement('script');
defaultScript.textContent = `
const vscode = Object.freeze((function() {
const acquireVsCodeApi = (function() {
const originalPostMessage = window.parent.postMessage.bind(window.parent);
return {
postMessage: function(msg) {
return originalPostMessage(msg, '*');
let acquired = false;
return () => {
if (acquired) {
throw new Error('An instance of the VS Code API has already been acquired');
}
acquired = true;
return Object.freeze({
postMessage: function(msg) {
return originalPostMessage(msg, '*');
}
});
};
})());
})();
delete window.parent;
delete window.top;
delete window.frameElement;
`;
if (newDocument.head.hasChildNodes()) {