Skip to content

Commit

Permalink
cleanup ipywidgets with hack into Pluto itself
Browse files Browse the repository at this point in the history
  • Loading branch information
schlichtanders committed Sep 11, 2024
1 parent d56f285 commit 29327d4
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "JolinPluto"
uuid = "5b0b4ef8-f4e6-4363-b674-3f031f7b9530"
authors = ["Stephan Sahm <[email protected]> and contributors"]
version = "0.1.85"
version = "0.1.86"

[deps]
AbstractPlutoDingetjes = "6e696c72-6542-2067-7265-42206c756150"
Expand Down
27 changes: 19 additions & 8 deletions ext/PythonCallExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,16 @@ end
# ipywidgets support
# ==================

# global initialization needed for ipywidgets
# global initialization needed for ipywidgets - this is now also included in Pluto base, so no need for this here any longer
# the downside was that on reload, this was not really executed in the correct order.
# still somewhen it would be nice for a package like this to create a __pluto_init__ hook or similar to ingest this in a more modular way

"""
IPyWidget_init()
Initialize javascript for ipywidgets to work inside Pluto.
"""
JolinPluto.IPyWidget_init() = @htl """
IPyWidget_init() = @htl """
<!-- Load RequireJS, used by the IPywidgets for dependency management -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"
Expand All @@ -94,6 +97,7 @@ JolinPluto.IPyWidget_init() = @htl """
crossorigin="anonymous">
</script>
<!-- Patch IPywidgets WidgetView to trigger Pluto events. -->
<script>
(()=>{
"use strict";
Expand All @@ -110,7 +114,14 @@ JolinPluto.IPyWidget_init() = @htl """
</script>
"""

function Base.show(io::IO, m::MIME"text/html", w::JolinPluto.IPyWidget)
# Python specific stuff

""" Wrap an ipywidget to be used in Pluto """
struct IPyWidget
wi
end

function Base.show(io::IO, m::MIME"text/html", w::IPyWidget)
e = PythonCall.pyimport("ipywidgets.embed")
data = e.embed_data(views=[w.wi], state=e.dependency_state([w.wi]))
show(io, m, @htl """
Expand All @@ -124,7 +135,7 @@ function Base.show(io::IO, m::MIME"text/html", w::JolinPluto.IPyWidget)
div.value = $(pyconvert(Any, w.wi.value))
if((window.require == null) || window.specified){
div.innerHTML = '<p>⚠️ Activate ipywidgets by running the following once inside Pluto ⚠️ <pre><code>from juliacall import Main as jl<br/>jl.seval("using Jolin")<br/>jl.IPyWidget_init() # <-- this is important</code></pre> </p>'
div.innerHTML = '<p>Couldn't find ipywidgets javascript dependencies. This should not happen, please contact <a href="mailto:[email protected]">[email protected]</a>. </p>'
}
// TODO renderWidgets(div) has the advantage that no duplicates appear
Expand Down Expand Up @@ -160,15 +171,15 @@ function Base.show(io::IO, m::MIME"text/html", w::JolinPluto.IPyWidget)
""")
end

function AbstractPlutoDingetjes.Bonds.initial_value(w::JolinPluto.IPyWidget)
function AbstractPlutoDingetjes.Bonds.initial_value(w::IPyWidget)
return pyconvert(Any, w.wi.value)
end

function pyshow_rule_ipywidgets(io::IO, mime::String, x::Py)
mime == "text/html" || return false
pyissubclass(pytype(x), @pyconst(pyimport("ipywidgets").widgets.ValueWidget)) || return false
try
show(io, mime, JolinPluto.IPyWidget(x))
show(io, mime, IPyWidget(x))
return true
catch exc
if exc isa PyException
Expand All @@ -183,7 +194,7 @@ end
JolinPluto.viewof(def::AbstractString, ui::Py) = JolinPluto.viewof(Symbol(def), ui)
function JolinPluto.viewof(def::Symbol, ui::Py)
if pyissubclass(pytype(ui), @pyconst(pyimport("ipywidgets").widgets.ValueWidget))
JolinPluto.viewof(def, JolinPluto.IPyWidget(ui))
JolinPluto.viewof(def, IPyWidget(ui))
else
@invoke JolinPluto.viewof(def::Symbol, ui::Any)
end
Expand All @@ -202,7 +213,7 @@ end

# Here an alternative implementation which unfortunately does not really work because if the same is used multiple times, on the first load it will actually
# interfere with one another so that all widgets are duplicated 3 to 10 times, depending on how many widgets load the common dependency in parallel.
# function Base.show(io::IO, m::MIME"text/html", w::JolinPluto.IPyWidget)
# function Base.show(io::IO, m::MIME"text/html", w::IPyWidget)
# e = PythonCall.pyimport("ipywidgets.embed")
# data = e.embed_data(views=[w.wi], state=e.dependency_state([w.wi]))
# show(io, m, @htl """
Expand Down
1 change: 0 additions & 1 deletion src/JolinPluto.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export Setter, @get, @cell_ids_create_wrapper, @cell_ids_push!
export cell_ids_create_wrapper, cell_ids_push!, cell_ids_push
export MD, format_html, _HTML
export viewof
export IPyWidget, IPyWidget_init

using Dates, HTTP, JSON3, Git, JWTs, UUIDs, Base64
using HypertextLiteral, Continuables
Expand Down
11 changes: 0 additions & 11 deletions src/languages.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,3 @@ function lang_set_global end
Gets the given variable from the respective language side.
"""
function lang_get_global end



# Python specific stuff

function IPyWidget_init end

""" Wrap an ipywidget to be used in Pluto """
struct IPyWidget
wi
end

0 comments on commit 29327d4

Please sign in to comment.