From 98727ab1e57935e7f8c50b9a53cf5083922e1a70 Mon Sep 17 00:00:00 2001 From: hhaensel Date: Sat, 9 Nov 2024 23:47:46 +0100 Subject: [PATCH] support multi-model pages --- assets/js/watchers.js | 4 ++-- src/Elements.jl | 11 +++++++---- src/Layout.jl | 18 ++++++++++++------ src/Stipple.jl | 9 ++++++--- src/stipple/rendering.jl | 2 +- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/assets/js/watchers.js b/assets/js/watchers.js index 6d87f2d6..a9b6214e 100644 --- a/assets/js/watchers.js +++ b/assets/js/watchers.js @@ -67,7 +67,7 @@ const watcherMixin = { }, push: function (field) { - Genie.WebChannels.sendMessageTo(CHANNEL, 'watchers', {'payload': { + Genie.WebChannels.sendMessageTo(this.channel_, 'watchers', {'payload': { 'field': field, 'newval': this[field], 'oldval': null, @@ -110,7 +110,7 @@ const eventMixin = { if (event_data === undefined) { event_data = {} } console.debug('event: ' + JSON.stringify(event_data) + ":" + event_handler) if (mode=='addclient') { event_data._addclient = true} - Genie.WebChannels.sendMessageTo(window.CHANNEL, 'events', { + Genie.WebChannels.sendMessageTo(this.channel_, 'events', { 'event': { 'name': event_handler, 'event': event_data diff --git a/src/Elements.jl b/src/Elements.jl index 08c61980..e2152fd3 100644 --- a/src/Elements.jl +++ b/src/Elements.jl @@ -176,6 +176,10 @@ function vue_integration(::Type{M}; app.config.globalProperties[key] = value }); window.$vue_app_name = window.GENIEMODEL = app.mount(rootSelector); + window.channelIndex = window.channelIndex || 0; + $vue_app_name.WebChannel = Genie.AllWebChannels[channelIndex]; + $vue_app_name.channel_ = $vue_app_name.WebChannel.channel; + channelIndex++; } // end of initStipple " @@ -209,8 +213,7 @@ function vue_integration(::Type{M}; } } - function app_ready() { - $vue_app_name.channel_ = window.CHANNEL; + function app_$(vue_app_name)_ready() { $vue_app_name.isready = true; Genie.Revivers.addReviver(window.$(vue_app_name).revive_jsfunction); $(transport == Genie.WebChannels && @@ -236,8 +239,8 @@ function vue_integration(::Type{M}; initStipple('#$vue_app_name'); initWatchers(); - Genie.WebChannels.subscriptionHandlers.push(function(event) { - app_ready(); + $vue_app_name.WebChannel.subscriptionHandlers.push(function(event) { + app_$(vue_app_name)_ready(); }); } """ diff --git a/src/Layout.jl b/src/Layout.jl index 86be5b9a..4d1d03e2 100644 --- a/src/Layout.jl +++ b/src/Layout.jl @@ -41,18 +41,19 @@ julia> layout([ "Hello\n" ``` """ -function layout(output::Union{S,Vector}, m::M; +function layout(output::Union{S,Vector}, m::Union{M, Vector{M}}; partial::Bool = false, title::String = "", class::String = "", style::String = "", head_content::Union{AbstractString, Vector{<:AbstractString}} = "", channel::String = Stipple.channel_js_name, core_theme::Bool = true)::ParsedHTMLString where {M<:ReactiveModel, S<:AbstractString} isa(output, Vector) && (output = join(output, '\n')) + m isa Vector || (m = [m]) content = [ output theme(; core_theme) - Stipple.deps(m) - ] + Stipple.deps.(m)... + ] |> union partial && return content @@ -84,17 +85,22 @@ julia> page(:elemid, [ "\n
Hello
\n" ``` """ -function page(model::M, args...; +function page(model::Union{M, Vector{M}}, args...; partial::Bool = false, title::String = "", class::String = "container", style::String = "", channel::String = Genie.config.webchannels_default_route, head_content::Union{AbstractString, Vector{<:AbstractString}} = "", prepend::Union{S,Vector} = "", append::Union{T,Vector} = [], core_theme::Bool = true, kwargs...)::ParsedHTMLString where {M<:Stipple.ReactiveModel, S<:AbstractString,T<:AbstractString} - + model isa Vector || (model = [model]) + uis = if !isempty(args) + args[1] isa Vector ? args[1] : [args[1]] + else + "" + end layout( [ join(prepend) - Genie.Renderer.Html.div(id = vm(M), args...; class = class, kwargs...) + [Genie.Renderer.Html.div(id = vm(m), ui, args[2:end]...; class = class, kwargs...) for (m, ui) in zip(model, uis)]... join(append) ], model; partial = partial, title = title, style = style, head_content = head_content, channel = channel, diff --git a/src/Stipple.jl b/src/Stipple.jl index 71ec16ac..b2463f7f 100644 --- a/src/Stipple.jl +++ b/src/Stipple.jl @@ -342,10 +342,10 @@ changed on the frontend, it is pushed over to the backend using `channel`, at a function watch(vue_app_name::String, fieldname::Symbol, channel::String, debounce::Int, model::M; jsfunction::String = "")::String where {M<:ReactiveModel} js_channel = isempty(channel) ? "window.Genie.Settings.webchannels_default_route" : - (channel == Stipple.channel_js_name ? Stipple.channel_js_name : "'$channel'") + "$vue_app_name.channel_" isempty(jsfunction) && - (jsfunction = "Genie.WebChannels.sendMessageTo($js_channel, 'watchers', {'payload': {'field':'$fieldname', 'newval': newVal, 'oldval': oldVal, 'sesstoken': document.querySelector(\"meta[name='sesstoken']\")?.getAttribute('content')}});") + (jsfunction = "$vue_app_name.WebChannel.sendMessageTo($js_channel, 'watchers', {'payload': {'field':'$fieldname', 'newval': newVal, 'oldval': oldVal, 'sesstoken': document.querySelector(\"meta[name='sesstoken']\")?.getAttribute('content')}});") output = IOBuffer() if fieldname == :isready @@ -847,7 +847,10 @@ end function channelscript(channel::String) :: String - Genie.Renderer.Html.script(["window.CHANNEL = '$(channel)';"]) + Genie.Renderer.Html.script([""" + window.CHANNEL = '$(channel)'; + if (window.Genie) Genie.init_webchannel('$(channel)'); + """]) end diff --git a/src/stipple/rendering.jl b/src/stipple/rendering.jl index 156d078c..fc9c7913 100644 --- a/src/stipple/rendering.jl +++ b/src/stipple/rendering.jl @@ -135,7 +135,7 @@ function Stipple.render(app::M)::Dict{Symbol,Any} where {M<:ReactiveModel} for field in fieldnames(typeof(app)) f = getfield(app, field) - occursin(SETTINGS.private_pattern, String(field)) && continue + field != CHANNELFIELDNAME && occursin(SETTINGS.private_pattern, String(field)) && continue f isa Reactive && f.r_mode == PRIVATE && continue result[field] = Stipple.jsrender(f, field)