AbstractPlutoDingetjes.jl
An abstract package to be implemented by packages/people who create widgets (or other dingetjes) for Pluto. If you are just happy using Pluto to make cool stuff, you probably don't want to use this package directly. This package is not necessary to create widgets in Pluto, but it can add more advanced functionality to your widgets. See the Interactivity sample notebook inside Pluto's main menu to learn more!
Bonds
AbstractPlutoDingetjes.Bonds.initial_value
โ Method.The initial value of a bond. In a notebook containing @bind x my_widget
, this will be used in two cases:
- The value of
x
will be set tox = PlutoAbstractDingetjes.initial_value(my_widget)
during the@bind
call. This initial value will be used in cells that usex
, until the widget is rendered in the browser and the first value is received. - When running a notebook file without Pluto, e.g.
shell> julia my_notebook.jl
, this value will be used forx
.
When not overloaded for your widget, it defaults to returning missing
.
Example
struct MySlider
range::AbstractRange{<:Real}
end
Base.show(io::IO, m::MIME"text/html", s::MySlider) = show(io, m, HTML("<input type=range min=$(first(s.values)) step=$(step(s.values)) max=$(last(s.values))>"))
PlutoAbstractDingetjes.Bonds.initial_value(s::MySlider) = first(s.range)
# Add the following for the same functionality on Pluto versions TODO and below. Will be ignored in future Pluto versions. See the compat info below.
Base.get(s::MySlider) = first(s.range)
If you are also using transform_value
for your widget, then the value returned by initial_value
should be the value after transformation.
This feature only works in Pluto version TODO: NOT RELEASED YET or above.
Older versions of Pluto used a Base.get
overload for this (to avoid the need for the AbstractPlutoDingetjes
package, but we changed our minds ๐). To support all versions of Pluto, use both methods of declaring the initial value.
Use AbstractPlutoDingetjes.is_supported_by_display
if you want to check support inside your widget.
AbstractPlutoDingetjes.Bonds.possible_values
โ Method.The possible values of a bond. This is used when generating precomputed PlutoSliderServer states, see https://github.com/JuliaPluto/PlutoSliderServer.jl/pull/29. Not relevant outside of this use (for now...).
The returned value should be an iterable object that you can call length
on (like a Vector
or a Generator
without filter) or return InfinitePossibilities()
if this set is inifinite.
Examples
struct MySlider
range::AbstractRange{<:Real}
end
Base.show(io::IO, m::MIME"text/html", s::MySlider) = show(io, m, HTML("<input type=range min=$(first(s.values)) step=$(step(s.values)) max=$(last(s.values))>"))
PlutoAbstractDingetjes.Bonds.possible_values(s::MySlider) = s.range
struct MyTextBox end
Base.show(io::IO, m::MIME"text/html", s::MyTextBox) = show(io, m, HTML("<input type=text>"))
PlutoAbstractDingetjes.Bonds.possible_values(s::MySlider) = PlutoAbstractDingetjes.Bonds.InfinitePossibilities()
If you are also using transform_value
for your widget, then the values returned by possible_values
should be the values before transformation.
This feature only works in Pluto version TODO: NOT RELEASED YET or above.
AbstractPlutoDingetjes.Bonds.transform_value
โ Method.Transform a value received from the browser before assigning it to the bound julia variable. In a notebook containing @bind x my_widget
, Pluto will run x = PlutoAbstractDingetjes.Bonds.transform_value(my_widget, $value_from_javascript)
. Without this hook, widgets in JavaScript can only return simple types (numbers, dictionaries, vectors) into bound variables.
When not overloaded for your widget, it defaults to returning the value unchanged, i.e. x = $value_from_javascript
.
Example
struct MyVectorSlider
values::Vector{<:Any} # note! a vector of arbitrary objects, not just numbers
end
Base.show(io::IO, m::MIME"text/html", s::MyVectorSlider) = show(io, m, HTML("<input type=range min=1 max=$(length(s.values))>"))
PlutoAbstractDingetjes.Bonds.transform_value(s::MySlider, value_from_javascript::Int) = s.values[value_from_javascript]
This feature only works in Pluto version TODO: NOT RELEASED YET or above. Values are not transformed in older versions.
Use AbstractPlutoDingetjes.is_supported_by_display
if you want to check support inside your widget.
AbstractPlutoDingetjes.Bonds.validate_value
โ Method.Validate a value received from the browser before "doing the pluto thing". In a notebook containing @bind x my_widget
, Pluto will run PlutoAbstractDingetjes.Bonds.validate_value(my_widget, $value_from_javascript)
. If the result is false
, then the value from JavaScript is considered "invalid" or "insecure", and no further code will be executed.
This is a protection measure when using your widget on a public PlutoSliderServer, where people could write fake requests that set bonds to arbitrary values.
The returned value should be a Boolean
.
Example
struct MySlider
range::AbstractRange{<:Real}
end
Base.show(io::IO, m::MIME"text/html", s::MySlider) = show(io, m, HTML("<input type=range min=$(first(s.values)) step=$(step(s.values)) max=$(last(s.values))>"))
PlutoAbstractDingetjes.Bonds.validate_value(s::MySlider, x::Any) = x isa Real && first(s.range) <= x <= last(s.range)
If you are also using transform_value
for your widget, then the value validated by validate_value
will be the value before transformation.
Be sure to add a dispatch for validate_value(s::MyWidget, x::Any)
, not just for validate_value(s::MyWidget, x::ExpectedType)
, since this would return the fallback value true
when x
is not of the expected type.
This feature only works in Pluto version TODO: NOT RELEASED YET or above.
Return InfinitePossibilities()
from your overload of possible_values
to signify that your bond has no finite set of possible values.
AbstractPlutoDingetjes.Bonds.NotGiven
โ Type.NotGiven()
is the default return value of possible_values(::Any)
.
Extras
AbstractPlutoDingetjes.is_inside_pluto
โ Method.is_inside_pluto(io::IO)::Bool
Are we rendering inside a Pluto notebook?
This function should be used inside a Base.show
method, and the first argument should be the io
provided to the Base.show
method.
AbstractPlutoDingetjes.is_inside_pluto
โ Method.is_inside_pluto()::Bool
Are we running inside a Pluto notebook?
AbstractPlutoDingetjes.is_supported_by_display
โ Method.is_supported_by_display(io::IO, f::Union{Function,Module})::Bool
Check whether the current runtime/display (Pluto) supports a given feature from AbstractPlutoDingetjes
(i.e. is the Pluto version new enough). This function should be used inside a Base.show
method. The first argument should be the io
provided to the Base.show
method, and the second argument is the feature to check.
You can use this information to:
- Error the show method of your widget if the runtime/display does not support the required features, or
- Render a simpler version of your widget that does not depend on the advanced Pluto features.
Example
import AbstractPlutoDingetjes: is_supported_by_display, Bonds
struct MyCoolDingetje
values::Vector
end
function Base.show(io::IO, m::MIME"text/html", d::MyCoolDingetje)
if !(is_supported_by_display(io, Bonds.initial_value) && is_supported_by_display(io, Bonds.transform_value))
error("This widget does not work in the current version of Pluto.")
end
write(io, html"...")
end
See also: is_inside_pluto
.