diff --git a/examples/subsession_integration.jl b/examples/subsession_integration.jl new file mode 100644 index 00000000..4268ef96 --- /dev/null +++ b/examples/subsession_integration.jl @@ -0,0 +1,63 @@ +using HTTP +using Bonito: App, Styles, Observable +using Bonito.DOM +using Random +using Colors +using Base.Threads: @spawn +using Dates: Dates + + +function html(app; kwargs...) + io = IOBuffer() + show_html(io, app; kwargs...) + take!(io) +end + +function main() + # start a blocking server + session_root_storage = Dict() + rng = Random.default_rng() + HTTP.listen() do http::HTTP.Stream + HTTP.setstatus(http, 200) + HTTP.startwrite(http) + req_uri = HTTP.URI(http.message.target) + if req_uri.path == "/fragment" + params = HTTP.queryparams(req_uri) + sid = params["sid"] + session = session_root_storage[params["sid"]] + color = rand(RGB{Float64}) + css = Styles( + "background-color" => color, + ) + app = App() do + date_obs::Observable{String} = Observable("unset") + @async begin + while true + date_obs[] = string(Dates.now()) + sleep(1) + end + end + DOM.div(map(date -> "date: $(date); sid: $(sid)", date_obs), style=css) + end + app_html = html(app; parent=session) + write(http, app_html) + else + root_app = App(_ -> DOM.div("")) + app_html = html(root_app) + session = root_app.session[] + session_root_storage[session.id] = session + write(http, "") + write(http, "") + write(http, "

fragment insertion

") + write(http, "") + write(http, "
") + write(http, app_html) + write(http, "
") + write(http, "") + end + end +end + +if abspath(PROGRAM_FILE) == @__FILE__ + main() +end diff --git a/src/Bonito.jl b/src/Bonito.jl index 61ce2803..5d9fdf2f 100644 --- a/src/Bonito.jl +++ b/src/Bonito.jl @@ -70,7 +70,7 @@ include("interactive.jl") # Core functionality export Page, Session, App, DOM, SVG, @js_str, ES6Module, Asset, CSS export Slider, Button, TextField, NumberInput, Checkbox, RangeSlider, CodeEditor -export browser_display, configure_server!, Server, html, route!, online_url, use_electron_display +export browser_display, configure_server!, Server, show_html, html, route!, online_url, use_electron_display export Observable, on, onany, bind_global export linkjs, evaljs, evaljs_value, onjs export NoServer, AssetFolder, HTTPAssetServer, DocumenterAssets diff --git a/src/display.jl b/src/display.jl index 642bd73c..6a3287d3 100644 --- a/src/display.jl +++ b/src/display.jl @@ -59,12 +59,11 @@ end get_io_context(io::IO) = nothing get_io_context(io::IOContext) = io -function Base.show(io::IO, ::Union{MIME"text/html", MIME"application/prs.juno.plotpane+html"}, app::App) +function show_html(io::IO, app::App; parent=CURRENT_SESSION[]) ctx = get_io_context(io) session = nothing - if !isnothing(CURRENT_SESSION[]) + if !isnothing(parent) # We render in a subsession - parent = CURRENT_SESSION[] sub = Session(parent; title=app.title) sub.io_context[] = ctx dom = session_dom(sub, app) @@ -93,6 +92,10 @@ function Base.show(io::IO, ::Union{MIME"text/html", MIME"application/prs.juno.pl return sub end +function Base.show(io::IO, ::Union{MIME"text/html", MIME"application/prs.juno.plotpane+html"}, app::App) + show_html(io, app) +end + function print_as_page(io::IO, dom::Node) println(io, "") # use Hyperscript directly to avoid the additional Bonito attributes