'Attach a CustomJS callback to an arbitrary BokehJS model event.
On the BokehJS side, change events for model properties have the
form ``"change:property_name"``. As a convenience, if the event name
passed to this method is also the name of a property on the model,
then it will be prefixed with ``"change:"`` automatically:
.. code:: python
# these two are equivalent
source.js_on_change(\'data\', callback)
source.js_on_change(\'change:data\', callback)
However, there are other kinds of events that can be useful to respond
to, in addition to property change events. For example to run a
callback whenever data is streamed to a ``ColumnDataSource``, use the
``"stream"`` event on the source:
.. code:: python
source.js_on_change(\'streaming\', callback)'

def js_on_change(self, event, *callbacks):

    if (len(callbacks) == 0):
        raise ValueError('js_on_change    takes    an    event    name    and    one    or    more    callbacks,    got    only    one    parameter')
    from bokeh.models.callbacks import CustomJS
    if (not all((isinstance(x, CustomJS) for x in callbacks))):
        raise ValueError('not    all    callback    values    are    CustomJS    instances')
    if (event in self.properties()):
        event = ('change:%s' % event)
    from bokeh.models.sources import ColumnarDataSource
    if isinstance(self, ColumnarDataSource):
        if (event == 'stream'):
            deprecated((0, 12, 6), "ColumnarDataSource.js_on_change('stream',    ...)", "'streaming'")
            event = 'streaming'
        elif (event == 'patch'):
            event = 'patching'
            deprecated((0, 12, 6), "ColumnarDataSource.js_on_change('patch',    ...)", "'patching'")
    if (event not in self.js_property_callbacks):
        self.js_property_callbacks[event] = []
    for callback in callbacks:
        if (callback in self.js_property_callbacks[event]):
            continue
        self.js_property_callbacks[event].append(callback)
