UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

133 lines 5.02 kB
import { HasProps } from "./core/has_props"; import { isString, isPlainObject } from "./core/util/types"; import { dict } from "./core/util/object"; import { equals } from "./core/util/eq"; import { logger } from "./core/logging"; import { execute } from "./core/util/callbacks"; export class Model extends HasProps { static __name__ = "Model"; _js_callbacks; get is_syncable() { return this.syncable; } [equals](that, cmp) { return (cmp.structural ? true : cmp.eq(this.id, that.id)) && super[equals](that, cmp); } constructor(attrs) { super(attrs); } static { this.define(({ Any, Unknown, Bool, Str, List, Set, Dict, Nullable }) => ({ tags: [List(Unknown), []], name: [Nullable(Str), null], js_property_callbacks: [Dict(List(Any /*TODO*/)), {}], js_event_callbacks: [Dict(List(Any /*TODO*/)), {}], subscribed_events: [Set(Str), new globalThis.Set()], syncable: [Bool, true], })); } initialize() { super.initialize(); this._js_callbacks = new Map(); } connect_signals() { super.connect_signals(); this._update_property_callbacks(); this.connect(this.properties.js_property_callbacks.change, () => this._update_property_callbacks()); this.connect(this.properties.js_event_callbacks.change, () => this._update_event_callbacks()); this.connect(this.properties.subscribed_events.change, () => this._update_event_callbacks()); } /*protected*/ _process_event(event) { for (const callback of dict(this.js_event_callbacks).get(event.event_name) ?? []) { void execute(callback, event); } if (this.document != null && this.subscribed_events.has(event.event_name)) { this.document.event_manager.send_event(event); } } trigger_event(event) { if (this.document != null) { event.origin = this; this.document.event_manager.trigger(event); } } _update_event_callbacks() { if (this.document == null) { logger.warn("WARNING: Document not defined for updating event callbacks"); return; } this.document.event_manager.subscribed_models.add(this); } _update_property_callbacks() { const signal_for = (event) => { const [evt, attr = null] = event.split(":"); return attr != null ? this.properties[attr][evt] : this[evt]; }; for (const [event, callbacks] of this._js_callbacks) { const signal = signal_for(event); for (const cb of callbacks) { this.disconnect(signal, cb); } } this._js_callbacks.clear(); for (const [event, callbacks] of dict(this.js_property_callbacks)) { const wrappers = callbacks.map((cb) => () => execute(cb, this)); this._js_callbacks.set(event, wrappers); const signal = signal_for(event); for (const cb of wrappers) { this.connect(signal, cb); } } } _doc_attached() { super._doc_attached(); if (this.js_event_callbacks.size != 0 || this.subscribed_events.size != 0) { this._update_event_callbacks(); } } _doc_detached() { super._doc_detached(); this.document?.event_manager.subscribed_models.delete(this); } select(selector) { if (isString(selector)) { return [...this.references()].filter((ref) => ref instanceof Model && ref.name === selector); } else if (isPlainObject(selector) && "type" in selector) { return [...this.references()].filter((ref) => ref.type == selector.type); } else if (selector.prototype instanceof HasProps) { return [...this.references()].filter((ref) => ref instanceof selector); } else { throw new Error(`invalid selector ${selector}`); } } select_one(selector) { const result = this.select(selector); switch (result.length) { case 0: return null; case 1: return result[0]; default: throw new Error(`found multiple objects matching the given selector ${selector}`); } } get_one(selector) { const result = this.select_one(selector); if (result != null) { return result; } else { throw new Error(`could not find any objects matching the given selector ${selector}`); } } on_event(event, callback) { const name = isString(event) ? event : event.prototype.event_name; const js_event_callbacks = dict(this.js_event_callbacks); const callbacks = js_event_callbacks.get(name) ?? []; js_event_callbacks.set(name, [...callbacks, callback]); } } //# sourceMappingURL=model.js.map