@bokeh/bokehjs
Version:
Interactive, novel data visualization
118 lines • 3.8 kB
JavaScript
import { AbstractButton, AbstractButtonView } from "./abstract_button";
import { ButtonClick, MenuItemClick } from "../../core/bokeh_events";
import { div } from "../../core/dom";
import { isString } from "../../core/util/types";
import { execute } from "../../core/util/callbacks";
import * as buttons from "../../styles/buttons.css";
import dropdown_css from "../../styles/dropdown.css";
import carets_css, * as carets from "../../styles/caret.css";
import { DividerItem, Menu, MenuItem } from "../ui/menus";
import { build_view } from "../../core/build_views";
export class DropdownView extends AbstractButtonView {
static __name__ = "DropdownView";
_open = false;
menu;
stylesheets() {
return [...super.stylesheets(), dropdown_css, carets_css];
}
async lazy_initialize() {
await super.lazy_initialize();
await this._build_menu();
}
connect_signals() {
super.connect_signals();
const { menu } = this.model.properties;
this.on_change(menu, async () => {
const menu_open = this.menu.is_open;
await this._build_menu();
this.rerender();
if (menu_open) {
this._toggle_menu();
}
});
}
render() {
super.render();
const caret = div({ class: [carets.caret, carets.down] });
if (!this.model.is_split) {
this.button_el.append(caret);
}
else {
const toggle = this._render_button(caret);
toggle.classList.add(buttons.dropdown_toggle);
toggle.addEventListener("click", () => this._toggle_menu());
this.group_el.append(toggle);
}
}
async _build_menu() {
const menu_with_items = this.to_menu();
this.menu = await build_view(menu_with_items, { parent: this });
}
_toggle_menu() {
if (!this.menu.is_open) {
this.menu.show({ x: 0, y: this.button_el.offsetHeight });
}
else {
this.menu.hide();
}
}
click() {
if (!this.model.is_split) {
this._toggle_menu();
}
else {
this.menu.hide();
this.model.trigger_event(new ButtonClick());
super.click();
}
}
_item_click(i) {
this.menu.hide();
const item = this.model.menu[i];
if (item != null) {
const value_or_callback = isString(item) ? item : item[1];
if (isString(value_or_callback)) {
this.model.trigger_event(new MenuItemClick(value_or_callback));
}
else {
void execute(value_or_callback, this.model, { index: i });
}
}
}
to_menu() {
const items = this.model.menu.map((item, i) => {
if (item == null) {
return new DividerItem();
}
else {
const label = isString(item) ? item : item[0];
const menu_item = new MenuItem({
label,
action: () => { this._item_click(i); },
});
return menu_item;
}
});
return new Menu({ items });
}
}
export class Dropdown extends AbstractButton {
static __name__ = "Dropdown";
constructor(attrs) {
super(attrs);
}
static {
this.prototype.default_view = DropdownView;
this.define(({ Null, Bool, Str, List, Tuple, Or }) => ({
split: [Bool, false],
menu: [List(Or(Str, Tuple(Str, Or(Str /*TODO*/)), Null)), []],
}));
this.override({
label: "Dropdown",
});
}
get is_split() {
return this.split;
}
}
//# sourceMappingURL=dropdown.js.map