starboard-notebook icon indicating copy to clipboard operation
starboard-notebook copied to clipboard

Evaluate all script (grand)children of HTML output to render output of Bokeh and Plotly

Open bartbroere opened this issue 1 year ago • 1 comments

(As discussed on the Discord server) to render plotly in Starboard Notebook I was coming up with this kind of hack: manually evaluating Javascript that was added to the DOM:

document.querySelectorAll('div.cell-bottom * script[type|="text/javascript"]').forEach(function(e) { eval(e.innerText); })

This PR is intended to start the discussion on if and how we might want to address this in Starboard Notebook itself. Right now libraries, like Bokeh and Plotly will not work out of the box, which is unfortunate.

We should also consider security implications of a fix similar to this one. Of course it helps if CORS and friends are configured properly, but there might be more risks besides stealing (session) data from a user by having them execute malicious code.

Plotly example

import pandas  # to populate the entry in sys.modules and keep plotly happy
import micropip
await micropip.install('plotly')
import plotly.express as px
from js import document

x = [1, 2, 3]
y = [1, 2, 3]
fig = px.scatter(x=x, y=y)
html = fig.to_html(
    include_plotlyjs=True,
    full_html=False,
    default_height='350px',
)

div = document.createElement('div')
div.innerHTML = html
div
document.querySelectorAll('div.cell-bottom * script[type|="text/javascript"]').forEach(function(e) { eval(e.innerText); })

Bokeh example

from bokeh.plotting import figure, show, save
from bokeh.io import output_file
from js import document

p = figure()
p.line([1, 2, 3], [1, 2, 3])
output_file('/tmp/output.html', mode='inline')
save(p)

# TODO bokeh probably has a better way to get this HTML out
with open('/tmp/output.html', 'r') as f:
    contents = f.read()
div = document.createElement('div')
div.innerHTML = contents
div
document.querySelectorAll('div.cell-bottom * script[type|="text/javascript"]').forEach(function(e) { eval(e.innerText); })

bartbroere avatar Apr 11 '23 12:04 bartbroere

Looks good to me!

I don't think it has security implications, the notebook should (always) be run in a sandbox (i.e. in an iframe), or one should trust the content if you want to embed it at the top level. Embedding at the top level (i.e. in the root page) is not really supported properly (and will require some cleanup/redesign, as now the CSS will surely clash, and perhaps some globals too).

Good to hear!

bartbroere avatar Apr 14 '23 10:04 bartbroere