@bokeh/bokehjs
Version:
Interactive, novel data visualization
574 lines • 17.7 kB
JavaScript
import { isBoolean, isNumber, isString, isArray, isPlainObject } from "./util/types";
import { entries } from "./util/object";
import { BBox } from "./util/bbox";
import { compose_stylesheet, apply_styles } from "./css";
import { logger } from "./logging";
const _element = (tag) => {
return (attrs = {}, ...children) => {
const element = document.createElement(tag);
if (!isPlainObject(attrs)) {
children = [attrs, ...children];
attrs = {};
}
else {
attrs = { ...attrs };
}
if (attrs.class != null) {
const classes = (() => {
if (isString(attrs.class)) {
return attrs.class.split(/\s+/);
}
else {
return attrs.class;
}
})();
for (const cls of classes) {
if (cls != null) {
element.classList.add(cls);
}
}
delete attrs.class;
}
if (attrs.style != null) {
if (isString(attrs.style)) {
element.setAttribute("style", attrs.style);
}
else {
apply_styles(element.style, attrs.style);
}
delete attrs.style;
}
if (attrs.data != null) {
for (const [key, data] of entries(attrs.data)) {
if (data != null) {
element.dataset[key] = data;
}
}
delete attrs.data;
}
for (const [attr, value] of entries(attrs)) {
if (value == null) {
continue;
}
else if (isBoolean(value)) {
element.toggleAttribute(attr, value);
}
else if (isNumber(value)) {
element.setAttribute(attr, `${value}`);
}
else if (isString(value)) {
element.setAttribute(attr, value);
}
else {
logger.warn(`unable to set attribute: ${attr} = ${value}`);
}
}
function append(child) {
if (isString(child)) {
element.append(document.createTextNode(child));
}
else if (child instanceof Node) {
element.append(child);
}
else if (child instanceof NodeList || child instanceof HTMLCollection) {
element.append(...child);
}
else if (child != null && child !== false) {
throw new Error(`expected a DOM element, string, false or null, got ${JSON.stringify(child)}`);
}
}
for (const child of children) {
if (isArray(child)) {
for (const _child of child) {
append(_child);
}
}
else {
append(child);
}
}
return element;
};
};
export function create_element(tag, attrs, ...children) {
return _element(tag)(attrs, ...children);
}
export const a = _element("a");
export const abbr = _element("abbr");
export const address = _element("address");
export const area = _element("area");
export const article = _element("article");
export const aside = _element("aside");
export const audio = _element("audio");
export const b = _element("b");
export const base = _element("base");
export const bdi = _element("bdi");
export const bdo = _element("bdo");
export const blockquote = _element("blockquote");
export const body = _element("body");
export const br = _element("br");
export const button = _element("button");
export const canvas = _element("canvas");
export const caption = _element("caption");
export const cite = _element("cite");
export const code = _element("code");
export const col = _element("col");
export const colgroup = _element("colgroup");
export const data = _element("data");
export const datalist = _element("datalist");
export const dd = _element("dd");
export const del = _element("del");
export const details = _element("details");
export const dfn = _element("dfn");
export const dialog = _element("dialog");
export const div = _element("div");
export const dl = _element("dl");
export const dt = _element("dt");
export const em = _element("em");
export const embed = _element("embed");
export const fieldset = _element("fieldset");
export const figcaption = _element("figcaption");
export const figure = _element("figure");
export const footer = _element("footer");
export const form = _element("form");
export const h1 = _element("h1");
export const h2 = _element("h2");
export const h3 = _element("h3");
export const h4 = _element("h4");
export const h5 = _element("h5");
export const h6 = _element("h6");
export const head = _element("head");
export const header = _element("header");
export const hgroup = _element("hgroup");
export const hr = _element("hr");
export const html = _element("html");
export const i = _element("i");
export const iframe = _element("iframe");
export const img = _element("img");
export const input = _element("input");
export const ins = _element("ins");
export const kbd = _element("kbd");
export const label = _element("label");
export const legend = _element("legend");
export const li = _element("li");
export const link = _element("link");
export const main = _element("main");
export const map = _element("map");
export const mark = _element("mark");
export const menu = _element("menu");
export const meta = _element("meta");
export const meter = _element("meter");
export const nav = _element("nav");
export const noscript = _element("noscript");
export const object = _element("object");
export const ol = _element("ol");
export const optgroup = _element("optgroup");
export const option = _element("option");
export const output = _element("output");
export const p = _element("p");
export const picture = _element("picture");
export const pre = _element("pre");
export const progress = _element("progress");
export const q = _element("q");
export const rp = _element("rp");
export const rt = _element("rt");
export const ruby = _element("ruby");
export const s = _element("s");
export const samp = _element("samp");
export const script = _element("script");
export const search = _element("search");
export const section = _element("section");
export const select = _element("select");
export const slot = _element("slot");
export const small = _element("small");
export const source = _element("source");
export const span = _element("span");
export const strong = _element("strong");
export const style = _element("style");
export const sub = _element("sub");
export const summary = _element("summary");
export const sup = _element("sup");
export const table = _element("table");
export const tbody = _element("tbody");
export const td = _element("td");
export const template = _element("template");
export const textarea = _element("textarea");
export const tfoot = _element("tfoot");
export const th = _element("th");
export const thead = _element("thead");
export const time = _element("time");
export const title = _element("title");
export const tr = _element("tr");
export const track = _element("track");
export const u = _element("u");
export const ul = _element("ul");
export const video = _element("video");
export const wbr = _element("wbr");
export function createSVGElement(tag, attrs = null, ...children) {
const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
for (const [attr, value] of entries(attrs ?? {})) {
if (value == null || value === false) {
continue;
}
element.setAttribute(attr, value);
}
function append(child) {
if (isString(child)) {
element.appendChild(document.createTextNode(child));
}
else if (child instanceof Node) {
element.appendChild(child);
}
else if (child instanceof NodeList || child instanceof HTMLCollection) {
for (const el of child) {
element.appendChild(el);
}
}
else if (child != null && child !== false) {
throw new Error(`expected a DOM element, string, false or null, got ${JSON.stringify(child)}`);
}
}
for (const child of children) {
if (isArray(child)) {
for (const _child of child) {
append(_child);
}
}
else {
append(child);
}
}
return element;
}
export function text(str) {
return document.createTextNode(str);
}
export function nbsp() {
return text("\u00a0");
}
export function prepend(element, ...nodes) {
const first = element.firstChild;
for (const node of nodes) {
element.insertBefore(node, first);
}
}
export function empty(node, attrs = false) {
let child;
while ((child = node.firstChild) != null) {
node.removeChild(child);
}
if (attrs && node instanceof Element) {
for (const attr of node.attributes) {
node.removeAttributeNode(attr);
}
}
}
export function contains(element, child) {
/**
* Like Node.contains(), but traverses Shadow DOM boundaries.
*/
let current = child;
while (current.parentNode != null) {
const parent = current.parentNode;
if (parent == element) {
return true;
}
else if (parent instanceof ShadowRoot) {
current = parent.host;
}
else {
current = parent;
}
}
return false;
}
export function display(element, display = true) {
element.style.display = display ? "" : "none";
}
export function undisplay(element) {
element.style.display = "none";
}
export function show(element) {
element.style.visibility = "";
}
export function hide(element) {
element.style.visibility = "hidden";
}
export function offset_bbox(element) {
const { top, left, width, height } = element.getBoundingClientRect();
return new BBox({
left: left + scrollX - document.documentElement.clientLeft,
top: top + scrollY - document.documentElement.clientTop,
width,
height,
});
}
export function parent(el, selector) {
let node = el;
while ((node = node.parentElement) != null) {
if (node.matches(selector)) {
return node;
}
}
return null;
}
function num(value) {
const num = parseFloat(value);
return isFinite(num) ? num : 0;
}
export function extents(el) {
const style = getComputedStyle(el);
return {
border: {
top: num(style.borderTopWidth),
bottom: num(style.borderBottomWidth),
left: num(style.borderLeftWidth),
right: num(style.borderRightWidth),
},
margin: {
top: num(style.marginTop),
bottom: num(style.marginBottom),
left: num(style.marginLeft),
right: num(style.marginRight),
},
padding: {
top: num(style.paddingTop),
bottom: num(style.paddingBottom),
left: num(style.paddingLeft),
right: num(style.paddingRight),
},
};
}
export function size(el) {
const rect = el.getBoundingClientRect();
return {
width: Math.ceil(rect.width),
height: Math.ceil(rect.height),
};
}
export function scroll_size(el) {
return {
width: Math.ceil(el.scrollWidth),
height: Math.ceil(el.scrollHeight),
};
}
export function outer_size(el) {
const { margin: { left, right, top, bottom } } = extents(el);
const { width, height } = size(el);
return {
width: Math.ceil(width + left + right),
height: Math.ceil(height + top + bottom),
};
}
export function content_size(el) {
const { left, top } = el.getBoundingClientRect();
const { padding } = extents(el);
let width = 0;
let height = 0;
for (const child of (el.shadowRoot ?? el).children) {
const rect = child.getBoundingClientRect();
width = Math.max(width, Math.ceil(rect.left - left - padding.left + rect.width));
height = Math.max(height, Math.ceil(rect.top - top - padding.top + rect.height));
}
return { width, height };
}
export function bounding_box(el) {
const { x, y, width, height } = el.getBoundingClientRect();
return new BBox({ x, y, width, height });
}
export function box_size(el) {
const { width, height } = el.getBoundingClientRect();
return { width, height };
}
export function position(el, box, margin) {
const { style } = el;
style.left = `${box.x}px`;
style.top = `${box.y}px`;
style.width = `${box.width}px`;
style.height = `${box.height}px`;
if (margin == null) {
style.margin = "";
}
else {
const { top, right, bottom, left } = margin;
style.margin = `${top}px ${right}px ${bottom}px ${left}px`;
}
}
export class ClassList {
class_list;
static __name__ = "ClassList";
constructor(class_list) {
this.class_list = class_list;
}
get values() {
const values = [];
for (let i = 0; i < this.class_list.length; i++) {
const item = this.class_list.item(i);
if (item != null) {
values.push(item);
}
}
return values;
}
has(cls) {
return this.class_list.contains(cls);
}
add(...classes) {
for (const cls of classes) {
this.class_list.add(cls);
}
return this;
}
remove(...classes) {
for (const cls of classes) {
if (isArray(cls)) {
cls.forEach((cls) => this.class_list.remove(cls));
}
else {
this.class_list.remove(cls);
}
}
return this;
}
clear() {
for (const cls of this.values) {
this.class_list.remove(cls);
}
return this;
}
toggle(cls, activate) {
return this.class_list.toggle(cls, activate);
}
}
export function classes(el) {
return new ClassList(el.classList);
}
export function toggle_attribute(el, attr, state) {
if (state == null) {
state = !el.hasAttribute(attr);
}
if (state) {
el.setAttribute(attr, "true");
}
else {
el.removeAttribute(attr);
}
}
export var MouseButton;
(function (MouseButton) {
MouseButton[MouseButton["None"] = 0] = "None";
MouseButton[MouseButton["Primary"] = 1] = "Primary";
MouseButton[MouseButton["Secondary"] = 2] = "Secondary";
MouseButton[MouseButton["Auxiliary"] = 4] = "Auxiliary";
MouseButton[MouseButton["Left"] = 1] = "Left";
MouseButton[MouseButton["Right"] = 2] = "Right";
MouseButton[MouseButton["Middle"] = 4] = "Middle";
})(MouseButton || (MouseButton = {}));
export class StyleSheet {
static __name__ = "StyleSheet";
el;
install(el) {
el.append(this.el);
}
uninstall() {
this.el.remove();
}
}
export class InlineStyleSheet extends StyleSheet {
persistent;
static __name__ = "InlineStyleSheet";
el = style();
constructor(css, id, persistent = false) {
super();
this.persistent = persistent;
if (isString(css)) {
this._update(css);
}
else if (css != null) {
this._update(compose_stylesheet(css));
}
if (id != null) {
this.el.dataset.css = id;
}
}
get css() {
return this.el.textContent ?? "";
}
_update(css) {
this.el.textContent = css;
}
clear() {
this.replace("");
}
_to_css(css, styles) {
if (styles == null) {
return css;
}
else {
return compose_stylesheet({ [css]: styles });
}
}
replace(css, styles) {
this._update(this._to_css(css, styles));
}
prepend(css, styles) {
this._update(`${this._to_css(css, styles)}\n${this.css}`);
}
append(css, styles) {
this._update(`${this.css}\n${this._to_css(css, styles)}`);
}
remove() {
this.el.remove();
}
}
export class GlobalInlineStyleSheet extends InlineStyleSheet {
static __name__ = "GlobalInlineStyleSheet";
install() {
if (!this.el.isConnected) {
document.head.appendChild(this.el);
}
}
}
export class ImportedStyleSheet extends StyleSheet {
static __name__ = "ImportedStyleSheet";
el;
constructor(url) {
super();
this.el = link({ rel: "stylesheet", href: url });
}
replace(url) {
this.el.href = url;
}
remove() {
this.el.remove();
}
}
export class GlobalImportedStyleSheet extends ImportedStyleSheet {
static __name__ = "GlobalImportedStyleSheet";
install() {
if (!this.el.isConnected) {
document.head.appendChild(this.el);
}
}
}
export async function dom_ready() {
if (document.readyState == "loading") {
return new Promise((resolve, _reject) => {
document.addEventListener("DOMContentLoaded", () => resolve(), { once: true });
});
}
}
export function px(value) {
return isNumber(value) ? `${value}px` : value;
}
export const supports_adopted_stylesheets = "adoptedStyleSheets" in ShadowRoot.prototype;
export function has_focus(el) {
const root = el.getRootNode();
if (root instanceof ShadowRoot || root instanceof Document) {
return root.activeElement === el;
}
else {
return false;
}
}
//# sourceMappingURL=dom.js.map