@bokeh/bokehjs
Version:
Interactive, novel data visualization
133 lines • 5.02 kB
JavaScript
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