How include a javascript library in a Bokeh extension

Background

I’m trying to create a bokeh extension by wrapping http://tabulator.info/

The .js library is available here https://unpkg.com/[email protected]/dist/js/tabulator.min.js

Question

My question is where should I import the .js library and why?

Options

As far as I can see I have several options.

  1. __java__script attribute of bokeh python model.
  2. npm install it and import in top of bokeh typescript model
  3. Include it in a script tag like you show in the Wrapping a JavaScript library — Bokeh 2.4.2 Documentation example.

My guess is that 1. should be the approach.

But if I don’t do 2. then I get errors when I panel build/ bokeh build tabulator in the .ts model.

I have a feeling that 3. is deprecated. But I am not sure.

Preliminary Code

tabulator.ts

// See https://docs.bokeh.org/en/latest/docs/reference/models/layouts.html
import { HTMLBox, HTMLBoxView } from "@bokehjs/models/layouts/html_box"

// See https://docs.bokeh.org/en/latest/docs/reference/core/properties.html
import * as p from "@bokehjs/core/properties"

// The view of the Bokeh extension/ HTML element
// Here you can define how to render the model as well as react to model changes or View events.
export class TabulatorView extends HTMLBoxView {
    model: Tabulator
    // objectElement: any // Element

    connect_signals(): void {
        super.connect_signals()

        this.connect(this.model.properties.configuration.change, () => {
            this.render();
        })
    }

    render(): void {
        console.log("render")
        console.log(this.model)
        super.render()
        // var table = new Tabulator(this.el, this.model.configuration)
        // this.objectElement.addEventListener("click", () => {this.model.clicks+=1;}, false)
    }
}

export namespace Tabulator {
    export type Attrs = p.AttrsOf<Props>
    export type Props = HTMLBox.Props & {
        configuration: p.Property<any>,
        data: p.Property<any>
        selected_indicies: p.Property<number[]>
    }
}

export interface Tabulator extends Tabulator.Attrs { }

// The Bokeh .ts model corresponding to the Bokeh .py model
export class Tabulator extends HTMLBox {
    properties: Tabulator.Props

    constructor(attrs?: Partial<Tabulator.Attrs>) {
        super(attrs)
    }

    static init_Tabulator(): void {
        this.prototype.default_view = TabulatorView;

        this.define<Tabulator.Props>({
            configuration: [p.Any, ],
            data: [p.Any, ],
            selected_indicies: [p.Any, []]
        })
    }
}

tabulator.py

"""Implementation of the Tabulator pane.

See http://tabulator.info/
"""

from bokeh.core import properties
from bokeh.models import ColumnDataSource
from bokeh.models.layouts import HTMLBox

JS_SRC = "https://unpkg.com/[email protected]/dist/js/tabulator.min.js"
MOMENT_SRC = "https://unpkg.com/[email protected]/moment.js"

CSS_HREFS = {
    "default": "https://unpkg.com/[email protected]/dist/css/tabulator.min.css",
    "site": "https://unpkg.com/[email protected]/dist/css/site.min.css",
    "simple": "https://unpkg.com/[email protected]/dist/css/tabulator_simple.min.css",
    "midnight": "https://unpkg.com/[email protected]/dist/css/tabulator_midnight.min.css",
    "modern": "https://unpkg.com/[email protected]/dist/css/tabulator_modern.min.css",
    "bootstrap": "https://unpkg.com/[email protected]/dist/css/bootstrap/tabulator_bootstrap.min.css",
    "bootstrap4": "https://unpkg.com/[email protected]/dist/css/bootstrap/tabulator_bootstrap4.min.css",
    "semantic-ui": "https://unpkg.com/[email protected]/dist/css/semantic-ui/tabulator_semantic-ui.min.css",
    "bulma": "https://unpkg.com/[email protected]/dist/css/bulma/tabulator_bulma.min.css",
    "materialize": "https://unpkg.com/[email protected]/dist/css/materialize/tabulator_materialize.min.css",
}

class Tabulator(HTMLBox):
    """A Bokeh Model that enables easy use of Tabulator tables

    See http://tabulator.info/
    """
    __javascript__ = [
        JS_SRC,
        MOMENT_SRC,
    ]
    __css__ = [CSS_HREFS["default"]]

    configuration = properties.Dict(properties.String, properties.Any)
    data = properties.Instance(ColumnDataSource)
    selected_indicies = properties.List(properties.Int)

A bonus question is how to handle that Tabulator is loaded by the .js library. But I would also like to call my Bokeh model Tabulator :slight_smile:

My guess is that the Katex extension example follows best practice

@MarcSkovMadsen I don’t think you have to rely on CDN loads if you don’t want to, AFAIK you can use build to bundle everything together up front. @mateusz is the best person to comment, but you can also refer to the examples here:

bokeh/examples/custom at branch-2.2 · bokeh/bokeh · GitHub

1 Like