98 lines
3.1 KiB
JavaScript
98 lines
3.1 KiB
JavaScript
|
|
const pyodideWorker = new Worker("./{{ name }}.js");
|
||
|
|
pyodideWorker.busy = false
|
||
|
|
pyodideWorker.queue = []
|
||
|
|
|
||
|
|
let patching = 0
|
||
|
|
|
||
|
|
function send_change(jsdoc, event) {
|
||
|
|
if ((event.setter_id != null && event.setter_id == 'py') || (patching > 0)) {
|
||
|
|
return
|
||
|
|
} else if (pyodideWorker.busy && event.model && event.attr) {
|
||
|
|
let events = []
|
||
|
|
for (const old_event of pyodideWorker.queue) {
|
||
|
|
if (!(old_event.model === event.model && old_event.attr === event.attr)) {
|
||
|
|
events.push(old_event)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
events.push(event)
|
||
|
|
pyodideWorker.queue = events
|
||
|
|
return
|
||
|
|
}
|
||
|
|
const patch = jsdoc.create_json_patch([event])
|
||
|
|
pyodideWorker.busy = true
|
||
|
|
pyodideWorker.postMessage({type: 'patch', patch: patch})
|
||
|
|
}
|
||
|
|
|
||
|
|
pyodideWorker.onmessage = async (event) => {
|
||
|
|
const msg = event.data
|
||
|
|
|
||
|
|
const body = document.getElementsByTagName('body')[0]
|
||
|
|
const loading_msgs = document.getElementsByClassName('pn-loading-msg')
|
||
|
|
if (msg.type === 'idle') {
|
||
|
|
if (pyodideWorker.queue.length) {
|
||
|
|
const patch = pyodideWorker.jsdoc.create_json_patch(pyodideWorker.queue)
|
||
|
|
pyodideWorker.busy = true
|
||
|
|
pyodideWorker.queue = []
|
||
|
|
pyodideWorker.postMessage({type: 'patch', patch: patch})
|
||
|
|
} else {
|
||
|
|
pyodideWorker.busy = false
|
||
|
|
}
|
||
|
|
} else if (msg.type === 'status') {
|
||
|
|
let loading_msg
|
||
|
|
if (loading_msgs.length) {
|
||
|
|
loading_msg = loading_msgs[0]
|
||
|
|
} else if (body.classList.contains('pn-loading')) {
|
||
|
|
loading_msg = document.createElement('div')
|
||
|
|
loading_msg.classList.add('pn-loading-msg')
|
||
|
|
body.appendChild(loading_msg)
|
||
|
|
}
|
||
|
|
if (loading_msg != null) {
|
||
|
|
loading_msg.innerHTML = msg.msg
|
||
|
|
}
|
||
|
|
} else if (msg.type === 'render') {
|
||
|
|
const docs_json = JSON.parse(msg.docs_json)
|
||
|
|
const render_items = JSON.parse(msg.render_items)
|
||
|
|
const root_ids = JSON.parse(msg.root_ids)
|
||
|
|
|
||
|
|
// Remap roots in message to element IDs
|
||
|
|
const root_els = document.querySelectorAll('[data-root-id]')
|
||
|
|
const data_roots = []
|
||
|
|
for (const el of root_els) {
|
||
|
|
el.innerHTML = ''
|
||
|
|
data_roots.push([el.getAttribute('data-root-id'), el.id])
|
||
|
|
}
|
||
|
|
data_roots.sort((a, b) => a[0]<b[0] ? -1: 1)
|
||
|
|
const roots = {}
|
||
|
|
for (let i=0; i<data_roots.length; i++) {
|
||
|
|
roots[root_ids[i]] = data_roots[i][1]
|
||
|
|
}
|
||
|
|
render_items[0]['roots'] = roots
|
||
|
|
render_items[0]['root_ids'] = root_ids
|
||
|
|
|
||
|
|
// Clear pre-rendered contents
|
||
|
|
Bokeh.index.roots.map((v) => v.remove())
|
||
|
|
|
||
|
|
// Embed content
|
||
|
|
const [views] = await Bokeh.embed.embed_items(docs_json, render_items)
|
||
|
|
|
||
|
|
// Remove loading spinner and message
|
||
|
|
body.classList.remove("pn-loading", "{{ loading_spinner }}")
|
||
|
|
for (const loading_msg of loading_msgs) {
|
||
|
|
loading_msg.remove()
|
||
|
|
}
|
||
|
|
|
||
|
|
// Setup bi-directional syncing
|
||
|
|
pyodideWorker.jsdoc = jsdoc = [...views.roots.values()][0].model.document
|
||
|
|
jsdoc.on_change(send_change.bind(null, jsdoc), false)
|
||
|
|
pyodideWorker.postMessage({'type': 'rendered'})
|
||
|
|
pyodideWorker.postMessage({'type': 'location', location: JSON.stringify(window.location)})
|
||
|
|
} else if (msg.type === 'patch') {
|
||
|
|
try {
|
||
|
|
patching += 1
|
||
|
|
pyodideWorker.jsdoc.apply_json_patch(msg.patch, msg.buffers)
|
||
|
|
} finally {
|
||
|
|
patching -= 1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|