Add hook for extending built-in html renderer (#154316)

Fixes #153836

Lets extension register a hook that is invoked after the html element is renderered
This commit is contained in:
Matt Bierner 2022-07-11 08:21:02 -07:00 committed by GitHub
parent 678e59a7d4
commit 82687c84ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 7 deletions

View file

@ -17,7 +17,7 @@
"contributes": {
"notebookRenderer": [
{
"id": "vscode-builtin-notebook-renderer",
"id": "vscode.builtin-renderer",
"entrypoint": "./renderer-out/index.js",
"displayName": "VS Code Builtin Notebook Output Renderer",
"requiresMessaging": "never",

View file

@ -10,13 +10,16 @@ interface IDisposable {
dispose(): void;
}
interface HtmlRenderingHook {
postRender(element: HTMLElement): HTMLElement | undefined;
}
function clearContainer(container: HTMLElement) {
while (container.firstChild) {
container.removeChild(container.firstChild);
}
}
function renderImage(outputInfo: OutputItem, element: HTMLElement): IDisposable {
const blob = new Blob([outputInfo.data()], { type: outputInfo.mime });
const src = URL.createObjectURL(blob);
@ -64,12 +67,17 @@ const domEval = (container: Element) => {
}
};
function renderHTML(outputInfo: OutputItem, container: HTMLElement): void {
function renderHTML(outputInfo: OutputItem, container: HTMLElement, hooks: Iterable<HtmlRenderingHook>): void {
clearContainer(container);
let element: HTMLElement = document.createElement('div');
const htmlContent = outputInfo.text();
const element = document.createElement('div');
const trustedHtml = ttPolicy?.createHTML(htmlContent) ?? htmlContent;
element.innerHTML = trustedHtml as string;
for (const hook of hooks) {
element = hook.postRender(element) ?? element;
}
container.appendChild(element);
domEval(element);
}
@ -167,6 +175,8 @@ function renderText(outputInfo: OutputItem, container: HTMLElement, ctx: Rendere
export const activate: ActivationFunction<void> = (ctx) => {
const disposables = new Map<string, IDisposable>();
const htmlHooks = new Set<HtmlRenderingHook>();
const latestContext = ctx as (RendererContext<void> & { readonly settings: { readonly lineLimit: number } });
const style = document.createElement('style');
@ -210,6 +220,7 @@ export const activate: ActivationFunction<void> = (ctx) => {
}
`;
document.body.appendChild(style);
return {
renderOutputItem: (outputInfo, element) => {
switch (outputInfo.mime) {
@ -220,7 +231,7 @@ export const activate: ActivationFunction<void> = (ctx) => {
return;
}
renderHTML(outputInfo, element);
renderHTML(outputInfo, element, htmlHooks);
}
break;
case 'application/javascript':
@ -267,8 +278,6 @@ export const activate: ActivationFunction<void> = (ctx) => {
default:
break;
}
},
disposeOutputItem: (id: string | undefined) => {
if (id) {
@ -276,6 +285,14 @@ export const activate: ActivationFunction<void> = (ctx) => {
} else {
disposables.forEach(d => d.dispose());
}
},
registerHtmlRenderingHook: (hook: HtmlRenderingHook): IDisposable => {
htmlHooks.add(hook);
return {
dispose: () => {
htmlHooks.delete(hook);
}
};
}
};
};