Here is a minimal working example I managed to make work using the MutationObserver API
@htl """
<script id="osctest">
let div = this ?? document.createElement("div")
if (this == null) {
div.classList.toggle('oscillator-container',true)
let id = $(join(rand("abcdefghilmnopqrstuvz",8)))
div.id = id
div.ctx = new AudioContext()
div.osc = new OscillatorNode(div.ctx)
div.osc.connect(div.ctx.destination); div.osc.start()
const observer = new MutationObserver((entries) => {
for (const entry of entries) {
for (const added of entry.addedNodes) {
if (added instanceof Element && added.classList.contains('oscillator-container') && added.id != id) {
console.log('Found a manual rerun! Disconnecting...')
div.osc.stop()
div.ctx.close()
observer.disconnect()
}
}
}
})
observer.observe(currentScript.closest('div.raw-html-wrapper'), {childList: true})
}
div.osc.frequency.setValueAtTime($freq, div.ctx.currentTime)
return div
</script>
"""
The main idea is to assign a unique id to the div you are generating in the script only upon manual re-run (when this == null) and then attach a MutationObserver to the pluto-output wrapper that monitors addition and deletion of children.
As soon as a new div with the oscillator-container class is added and has an id which is different from the one you generated together with the MutationObserver, I assume that a manual rerun has been triggered and I can disconnect everything.
Seems to work, don’t know if there are better ways to achieve this though.