Skip to content

Commit

Permalink
support multiple models of the same type
Browse files Browse the repository at this point in the history
  • Loading branch information
hhaensel committed Nov 10, 2024
1 parent 737c2e4 commit 14bb9b1
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 23 deletions.
51 changes: 31 additions & 20 deletions src/Elements.jl
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ function vue_integration(::Type{M};
debounce::Int = Stipple.JS_DEBOUNCE_TIME,
transport::Module = Genie.WebChannels)::String where {M<:ReactiveModel}
model = Base.invokelatest(M)

app = "window[appName]"
vue_app = json(model |> Stipple.render)
vue_app = replace(vue_app, "\"$(getchannel(model))\"" => Stipple.channel_js_name)

Expand Down Expand Up @@ -159,7 +159,7 @@ function vue_integration(::Type{M};
string(
"
function initStipple(rootSelector){
function initStipple$vue_app_name(appName, rootSelector){
// components = Stipple.init($( core_theme ? "{theme: '$theme'}" : "" ));
const app = Vue.createApp($( replace(vue_app, "'$(Stipple.UNDEFINED_PLACEHOLDER)'"=>Stipple.UNDEFINED_VALUE) ))
/* Object.entries(components).forEach(([key, value]) => {
Expand All @@ -175,10 +175,12 @@ function vue_integration(::Type{M};
Object.entries(app.prototype).forEach(([key, value]) => {
app.config.globalProperties[key] = value
});
window.$vue_app_name = window.GENIEMODEL = app.mount(rootSelector);
$app = 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;
$app.WebChannel = Genie.AllWebChannels[channelIndex];
$app.WebChannel.parent = $app;
$app.channel_ = $app.WebChannel.channel;
channelIndex++;
} // end of initStipple
Expand All @@ -188,12 +190,12 @@ function vue_integration(::Type{M};

"
function initWatchers(){
function initWatchers$vue_app_name(app){
"

,
join(
[Stipple.watch(string("window.", vue_app_name), field, Stipple.channel_js_name, debounce, model) for field in fieldnames(Stipple.get_concrete_type(M))
[Stipple.watch("app", field, Stipple.channel_js_name, debounce, model) for field in fieldnames(Stipple.get_concrete_type(M))
if Stipple.has_frontend_watcher(field, model)]
)
,
Expand All @@ -207,21 +209,21 @@ function vue_integration(::Type{M};

"""
window.parse_payload = function(payload){
window.parse_payload = function(WebChannel, payload){
if (payload.key) {
window.$(vue_app_name).updateField(payload.key, payload.value);
WebChannel.parent.updateField(payload.key, payload.value);
}
}
function app_$(vue_app_name)_ready() {
$vue_app_name.isready = true;
Genie.Revivers.addReviver(window.$(vue_app_name).revive_jsfunction);
function app_ready(app) {
app.isready = true;
Genie.Revivers.addReviver(app.revive_jsfunction);
$(transport == Genie.WebChannels &&
"
try {
if (Genie.Settings.webchannels_keepalive_frequency > 0) {
clearInterval($vue_app_name.keepalive_interval);
$vue_app_name.keepalive_interval = setInterval(keepalive, Genie.Settings.webchannels_keepalive_frequency);
clearInterval(app.keepalive_interval);
app.keepalive_interval = setInterval(keepalive, Genie.Settings.webchannels_keepalive_frequency);
}
} catch (e) {
if (Genie.Settings.env === 'dev') {
Expand All @@ -235,14 +237,23 @@ function vue_integration(::Type{M};
}
};
if ( window.autorun === undefined || window.autorun === true ) {
initStipple('#$vue_app_name');
initWatchers();
function create$vue_app_name() {
window.counter$vue_app_name = window.counter$vue_app_name || 0
appName = '$vue_app_name' + ((counter$vue_app_name == 0) ? '' : '-' + window.counter$vue_app_name)
counter$vue_app_name++
$vue_app_name.WebChannel.subscriptionHandlers.push(function(event) {
app_$(vue_app_name)_ready();
});
if ( window.autorun === undefined || window.autorun === true ) {
initStipple$vue_app_name(appName, '#' + appName);
initWatchers$vue_app_name($app);
$app.WebChannel.subscriptionHandlers.push(function(event) {
app_ready($app);
});
}
}
// create$vue_app_name()
// is called via scipt with addEventListener to support multiple apps
"""
)

Expand Down
13 changes: 10 additions & 3 deletions src/Layout.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,21 @@ function page(model::Union{M, Vector{M}}, args...;
else
""
end
counter = Dict{DataType, Int}()

function rootselector(m::M) where M <:ReactiveModel
AM = Stipple.get_abstract_type(M)
counter[AM] = get(counter, AM, -1) + 1
return (counter[AM] == 0) ? vm(m) : "$(vm(m))-$(counter[AM])"
end

layout(
[
join(prepend)
pagetemplate([Genie.Renderer.Html.div(id = vm(m), ui, args[2:end]...; class = class, kwargs...) for (m, ui) in zip(model, uis)]...)
pagetemplate([Genie.Renderer.Html.div(id = rootselector(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,
core_theme = core_theme)
partial, title, style, head_content, channel, core_theme)
end

const app = page
Expand Down
7 changes: 7 additions & 0 deletions src/Stipple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,12 @@ function channelscript(channel::String) :: String
"""])
end

function initscript(vue_app_name) :: String
Genie.Renderer.Html.script(["""
// script id: $(randstring(64))
document.addEventListener("DOMContentLoaded", () => window.create$vue_app_name() );
"""])
end

"""
function deps(channel::String = Genie.config.webchannels_default_route)
Expand All @@ -863,6 +869,7 @@ function deps(m::M) :: Vector{String} where {M<:ReactiveModel}
channel = getchannel(m)
output = [
channelscript(channel),
initscript(vm(m)),
(is_channels_webtransport() ? Genie.Assets.channels_script_tag(channel) : Genie.Assets.webthreads_script_tag(channel)),
Genie.Renderer.Html.script(src = Genie.Assets.asset_path(assets_config, :js, file="underscore-min")),
Genie.Renderer.Html.script(src = Genie.Assets.asset_path(assets_config, :js, file=(Genie.Configuration.isprod() ? "vue.global.prod" : "vue.global"))),
Expand Down

0 comments on commit 14bb9b1

Please sign in to comment.