UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

574 lines 17.7 kB
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