ha-frontend/src/components/ha-markdown-element.ts

74 lines
1.8 KiB
TypeScript

import { ReactiveElement } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { renderMarkdown } from "../resources/render-markdown";
@customElement("ha-markdown-element")
class HaMarkdownElement extends ReactiveElement {
@property() public content?;
@property({ type: Boolean }) public allowSvg = false;
@property({ type: Boolean }) public breaks = false;
protected createRenderRoot() {
return this;
}
protected update(changedProps) {
super.update(changedProps);
if (this.content !== undefined) {
this._render();
}
}
private async _render() {
this.innerHTML = await renderMarkdown(
this.content,
{
breaks: this.breaks,
gfm: true,
},
{
allowSvg: this.allowSvg,
}
);
this._resize();
const walker = document.createTreeWalker(
this,
NodeFilter.SHOW_ELEMENT,
null
);
while (walker.nextNode()) {
const node = walker.currentNode;
// Open external links in a new window
if (
node instanceof HTMLAnchorElement &&
node.host !== document.location.host
) {
node.target = "_blank";
// protect referrer on external links and deny window.opener access for security reasons
// (see https://mathiasbynens.github.io/rel-noopener/)
node.rel = "noreferrer noopener";
// Fire a resize event when images loaded to notify content resized
} else if (node instanceof HTMLImageElement) {
node.addEventListener("load", this._resize);
}
}
}
private _resize = () => fireEvent(this, "iron-resize");
}
declare global {
interface HTMLElementTagNameMap {
"ha-markdown-element": HaMarkdownElement;
}
}