First of all, I don't know much about the Pluto inside or JavaScript. Please correct me if there is any misunderstanding.
For example, the SVGJS backend of Gadfly outputs a <svg> with embedded <script>s (cf. http://gadflyjl.org/v1.3/man/backends/#Interactive-SVGs-1). However, there are some problems in using the interactive feature.
<img>Since Pluto uses <img> to display SVG images, interactive features are not available. This problem can be solved by changing the output format to MIME"text/html" (in the packages or user code).
SVGScriptElementSVG's <script> element (SVGScriptElement) is similar to HTML's <script>, but they are not identical in the specifications.
The problem is that SVGScriptElement does not have the src attribute. (Some implementations may support it, though.) Thus, node.src in the following lines may be undefined, and (node.src != "") will be true.
https://github.com/fonsp/Pluto.jl/blob/b113783ac2673822598a6ee8c4e0abd02797521c/frontend/components/CellOutput.js#L157-L161
This problem should be solved by changing the condition to if (node.src). Of course, we can do a more strict check.
An SVG image may contain multiple <script> elements. They are usually assumed to share an environment. However, the separation is currently done based on node.id.
https://github.com/fonsp/Pluto.jl/blob/b113783ac2673822598a6ee8c4e0abd02797521c/frontend/components/CellOutput.js#L180
I don't know of a versatile solution to this, but I think that we could loosen up the scope a bit more, as shown below.
let script_id = node.id ? node.id : node.parentNode.id
The SVGJS backend of Gadfly uses Snap.svg. Snap.svg uses the AMD (Asynchronous Module Definition) for module management.
Now that ES Modules are widely supported, the AMD is an old technology, but some JavaScript libraries still use the AMD and RequireJS. This can lead to the following problem.
The libraries which use the AMD usually register a module object in the global environment when the AMD is not available. In general, this can cause problems with conflicts between multiple versions, but as far as the libraries are used in a single Pluto notebook, I think they rarely cause conflicts.
However, on the Pluto front-end, the default environment (this) is undefined. This can cause an error in code which assumes that this is the global environment, i.e., window.
https://github.com/fonsp/Pluto.jl/blob/b113783ac2673822598a6ee8c4e0abd02797521c/frontend/components/CellOutput.js#L183
I don't think polluting the global environment is a good idea. However, it would be better to share a Node object of some kind (e.g. root_node) with the same script_id instead of undefined.
innerHTMLI think textContent is more appropriate than innerHTML.
https://github.com/fonsp/Pluto.jl/blob/b113783ac2673822598a6ee8c4e0abd02797521c/frontend/components/CellOutput.js#L188
Do you have an example notebook using Gadfly?
Rendering svg's in img tags has several benefits we are not keen on getting rid of, and I want to see how much is actually broken when rendering Gadfly as html.
Okay tried it myself ๐
Your feedback it totally valid, we're still on a bit of a crossroad between "Supporting all inline html and script" and "Make writing html and scripts in Pluto itself fun". Most likely we will end on the side of "Supporting all inline html and script" though, and when doing that your points will be very helpful :)
Until we have this covered, you can wrap the snippet in <html> tags, so Pluto will render it in an iframe
# โโโก af27fc22-0964-11eb-0382-8343faea368e
using Gadfly
# โโโก 09a1b2ba-0965-11eb-2f11-73708c4a8bd9
HTMLDocument(plot(y=[1,2,3]))
# โโโก 0751415a-0966-11eb-07d0-69316a9b61c8
struct HTMLDocument
embedded
end
# โโโก 062f3880-0967-11eb-3c2c-1db7aa9d40b8
function Base.show(io::IO, mime::MIME"text/html", doc::HTMLDocument)
println(io, "<html>")
show(io, mime, doc.embedded)
println(io, "</html>")
end
Oh, sorry. I mentioned Gadfly just because I thought it was a well-known package, but as for "1. Static <img>", Gadfly should already output SVGs as HTML, as you get. :sweat_smile:
Perhaps the only essential issue is AMD support.
Yeah, I was expecting all AMD packages to be imported with <script src="...">, never seen an AMD package just placed in a <script>...</script> tag ๐ I'll keep you posted
1: we will not change this behaviour. Your suggestion is correct: a package that wants scripts to work should output the html mime type.
2: fixed in https://github.com/fonsp/Pluto.jl/commit/694526bb2ac9ae9ae0cad8b55c70505ebde1bb1d
3: I am not sure what you mean with "environment", but our ID tracking is only used for a pluto-specific (additional) feature. It should be unrelated
4 & 5: this is a good point. Let's make that the focus of this issue
6: you must have misread something
Thank you for your response and the fix.
6: you must have misread something
Please explain in a little more detail. The innerHTML is for HTML and should not be used for anything other than HTML.
Ah it is I who misread. Still I don't think this matters.
Still I don't think this matters.
Yes. So I placed it at the end (i.e. 6.). However, in SVG, an XML format, <script> is often used with CDATA, and innerHTML causes unintentional escaping.
### A Pluto.jl notebook ###
# v0.12.6
using Markdown
using InteractiveUtils
# โโโก 10303500-1cc2-11eb-22fc-6711d6ea7162
struct MyStruct end
# โโโก 2f160ee0-1cc2-11eb-0db8-9f9c1b645189
Base.showable(::MIME"text/html", ::MyStruct) = true
# โโโก 54186492-1cc2-11eb-109d-c31ef1da0c3c
function Base.show(io::IO, ::MIME"text/html", ::MyStruct)
write(io, """
<html>
<body>
<svg width="20mm" height="15mm" viewBox="0,0,20,15">
<script><![CDATA[
if (1 > 0) {
console.log(document.getElementById("my-circle"));
}
]]></script>
<circle fill="green" cx="10" cy="7" r="5" id="my-circle" />
</svg>
</body>
</html>
""")
end
# โโโก 051d1660-1cdb-11eb-3e3f-01545ab6cb41
MyStruct()
# โโโก Cell order:
# โ โ10303500-1cc2-11eb-22fc-6711d6ea7162
# โ โ2f160ee0-1cc2-11eb-0db8-9f9c1b645189
# โ โ54186492-1cc2-11eb-109d-c31ef1da0c3c
# โ โ051d1660-1cdb-11eb-3e3f-01545ab6cb41
Ah okay, your original wording made it sound like a style comment. We'll change it
We reverted to this === window for classic <script>s with no id set. And innerHTML ๐ innerText
Most helpful comment
Ah okay, your original wording made it sound like a style comment. We'll change it