@bokeh/bokehjs
Version:
Interactive, novel data visualization
114 lines • 3.83 kB
JavaScript
import { DOMElement, DOMElementView } from "./dom_element";
import { UIElement } from "../ui/ui_element";
import { build_views, remove_views } from "../../core/build_views";
import { span } from "../../core/dom";
import { assert } from "../../core/util/assert";
import { isString, isArray } from "../../core/util/types";
import { Str, Ref, Or } from "../../core/kinds";
const HTMLRef = Or(Ref(DOMElement), Ref(UIElement));
const HTMLMarkup = Str;
export class HTMLView extends DOMElementView {
static __name__ = "HTMLView";
_refs = new Map();
get refs() {
const { html, refs } = this.model;
return [
...isArray(html) ? html.filter((item) => !isString(item)) : [],
...refs,
];
}
async _update_refs() {
await build_views(this._refs, this.refs);
}
children_views() {
return [...super.children_views(), ...this._refs.values()];
}
async lazy_initialize() {
await super.lazy_initialize();
await this._update_refs();
}
remove() {
remove_views(this._refs);
super.remove();
}
connect_signals() {
super.connect_signals();
const { refs, html } = this.model.properties;
this.on_change([refs, html], async () => {
await this._update_refs();
this.render();
});
}
render() {
super.render();
const html = (() => {
const { html } = this.model;
if (isArray(html)) {
return html.map((item) => isString(item) ? item : `<ref id="${item.id}"></ref>`).join("");
}
else {
return html;
}
})();
const nodes = (() => {
if (isString(html)) {
return this.parse_html(html);
}
else {
return [html];
}
})();
this.el.append(...nodes);
this.finish();
}
parse_html(html) {
const parser = new DOMParser();
const document = parser.parseFromString(html, "text/html");
const iter = document.createNodeIterator(document, NodeFilter.SHOW_ELEMENT, (node) => {
return node.nodeName.toLowerCase() == "ref" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
});
let node;
next_node: while ((node = iter.nextNode()) != null) {
assert(node instanceof Element);
const id = node.getAttribute("id");
if (id != null) {
for (const [model, view] of this._refs) {
if (model.id == id) {
view.render();
node.replaceWith(view.el);
continue next_node;
}
}
node.replaceWith(span(`<not found: id=${id}>`));
continue;
}
const name = node.getAttribute("name");
if (name != null) {
for (const [model, view] of this._refs) {
if (model.name == name) {
view.render();
node.replaceWith(view.el);
continue next_node;
}
}
node.replaceWith(span(`<not found: name=${name}>`));
continue;
}
}
return [...document.body.childNodes];
}
}
export class HTML extends DOMElement {
static __name__ = "HTML";
constructor(attrs) {
super(attrs);
}
static {
this.prototype.default_view = HTMLView;
this.define(({ Node, List, Or }) => ({
html: [Or(Node, HTMLMarkup, List(Or(HTMLMarkup, HTMLRef)))],
refs: [List(HTMLRef), []],
}));
}
}
//# sourceMappingURL=html.js.map