Files
vscode-debug-visualizer/extension/src/webview/InternalWebviewManager.ts
Henning Dieterichs d22e5d4111 Version 2.2.0.
* Adds support for custom injected scripts with automatic reload
* Refactors extension
2021-06-18 20:26:51 +02:00

140 lines
4.0 KiB
TypeScript

import { window, ViewColumn, WebviewPanel } from "vscode";
import { WebviewServer } from "./WebviewServer";
import { Disposable } from "@hediet/std/disposable";
import { WindowWithWebviewData } from "../webviewContract";
import { Config } from "../Config";
export const debugVisualizer = "debugVisualizer";
export class InternalWebviewManager {
private readonly openedWebviews = new Map<
WebviewPanel,
DebugVisualizerWebview
>();
public readonly dispose = Disposable.fn();
constructor(
private readonly server: WebviewServer,
private readonly config: Config
) {
this.dispose.track(
window.registerWebviewPanelSerializer(debugVisualizer, {
deserializeWebviewPanel: async (panel, state) => {
this.restore(panel);
},
})
);
this.dispose.track({
dispose: () => {
for (const panel of this.openedWebviews.keys()) {
panel.dispose();
}
},
});
}
public createNew(expression: string | undefined = undefined) {
const webviewPanel = window.createWebviewPanel(
debugVisualizer,
"Debug Visualizer",
ViewColumn.Two,
{
enableScripts: true,
retainContextWhenHidden: true,
portMapping: [
{
webviewPort: this.server.port,
extensionHostPort: this.server.port,
},
],
}
);
this.initializeView(webviewPanel, expression);
}
private restore(webviewPanel: WebviewPanel) {
this.initializeView(webviewPanel);
}
private initializeView(
webviewPanel: WebviewPanel,
expression: string | undefined = undefined
) {
webviewPanel.webview.html = getDebugVisualizerWebviewHtml(
this.server,
expression,
this.config
);
const view = new DebugVisualizerWebview(webviewPanel);
this.openedWebviews.set(webviewPanel, view);
webviewPanel.onDidDispose(() => {
this.openedWebviews.delete(webviewPanel);
});
}
}
export class DebugVisualizerWebview {
constructor(private readonly webviewPanel: WebviewPanel) {}
}
function getDebugVisualizerWebviewHtml(
server: WebviewServer,
initialExpression: string | undefined = undefined,
config: Config
) {
const isDev = !!process.env.USE_DEV_UI;
return `
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-inline' 'unsafe-eval'; script-src * 'unsafe-inline' 'unsafe-eval'; connect-src * 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src *; style-src * 'unsafe-inline'; worker-src * data: blob: data: 'unsafe-inline' 'unsafe-eval'; font-src * 'unsafe-inline' 'unsafe-eval' 'self' data: blob:;">
<style>
html { height: 100%; width: 100%; padding: 0; margin: 0; }
body { height: 100%; width: 100%; padding: 0; margin: 0; }
iframe { height: 100%; width: 100%; padding: 0; margin: 0; border: 0; display: block; }
</style>
</head>
<body>
<script>
Object.assign(window, ${JSON.stringify({
webviewData: {
serverSecret: server.secret,
serverPort: server.port,
publicPath: server.publicPath,
expression: initialExpression,
theme: config.theme,
},
} as WindowWithWebviewData)});
const api = window.VsCodeApi = acquireVsCodeApi();
window.addEventListener('message', event => {
if (event.source === window.frames[0]) {
if (event.data.command === "setState") {
// console.log("setState", event.data.state);
api.setState(event.data.state);
}
if (event.data.command === "getState") {
// console.log("getState, sent ", api.getState());
window.frames[0].postMessage({ command: "getStateResult", state: api.getState() }, "*");
}
}
});
</script>
${
isDev
? `<iframe sandbox="allow-top-navigation allow-scripts allow-same-origin allow-popups allow-pointer-lock allow-forms" src="${server.getWebviewPageUrl(
{
mode: "webviewIFrame",
expression: initialExpression,
}
)}"></iframe>`
: `<script type="text/javascript" src="${server.webviewBundleUrl}"></script>`
}
</body>
</html>
`;
}