diff --git a/src/Elements.jl b/src/Elements.jl index 9b9dc12..4f4947c 100644 --- a/src/Elements.jl +++ b/src/Elements.jl @@ -130,7 +130,6 @@ 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) @@ -157,103 +156,88 @@ function vue_integration(::Type{M}; output = string( - " - - function initStipple$vue_app_name(appName, rootSelector, channel){ - // 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]) => { - app.component(key, value) - }); */ - Stipple.init( app, $( core_theme ? "{theme: '$theme'}" : "" )); - $globalcomps - $comps - // gather legacy global options - app.prototype = {} - $(plugins(M)) - // apply legacy global options - Object.entries(app.prototype).forEach(([key, value]) => { - app.config.globalProperties[key] = value - }); - $app = window.GENIEMODEL = app.mount(rootSelector); - window.channelIndex = window.channelIndex || 0; - $app.WebChannel = Genie.initWebChannel(channel); - $app.WebChannel.parent = $app; - $app.channel_ = channel; - - channelIndex++; - } // end of initStipple - - " - - , - - " - - function initWatchers$vue_app_name(app){ - " - - , - join( - [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)] - ) - , - - " - } // end of initWatchers - - " - - , - """ - - window.parse_payload = function(WebChannel, payload){ - if (payload.key) { - WebChannel.parent.updateField(payload.key, payload.value); + window.parse_payload = function(WebChannel, payload){ + if (payload.key) { + WebChannel.parent.updateField(payload.key, payload.value); + } } - } - - function app_ready(app) { - if (app.WebChannel == Genie.AllWebChannels[0]) Genie.Revivers.addReviver(app.revive_jsfunction); - app.isready = true; - $(transport == Genie.WebChannels && - " - try { - if (Genie.Settings.webchannels_keepalive_frequency > 0) { - keepaliveTimer(app.WebChannel, 0); + + function app_ready(app) { + if (app.WebChannel == Genie.AllWebChannels[0]) Genie.Revivers.addReviver(app.revive_jsfunction); + app.isready = true; + """, + transport == Genie.WebChannels && + """ + try { + if (Genie.Settings.webchannels_keepalive_frequency > 0) { + keepaliveTimer(app.WebChannel, 0); + } + } catch (e) { + if (Genie.Settings.env === 'dev') { + console.error('Error setting WebSocket keepalive interval: ' + e); + } } - } catch (e) { + """, + """ if (Genie.Settings.env === 'dev') { - console.error('Error setting WebSocket keepalive interval: ' + e); + console.info('App starting'); } - } - ") + }; - if (Genie.Settings.env === 'dev') { - console.info('App starting'); - } - }; + function initStipple$vue_app_name(appName, rootSelector, channel){ + // 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]) => { + app.component(key, value) + }); */ + Stipple.init( app, $( core_theme ? "{theme: '$theme'}" : "" )); + $globalcomps + $comps + // gather legacy global options + app.prototype = {} + $(plugins(M)) + // apply legacy global options + Object.entries(app.prototype).forEach(([key, value]) => { + app.config.globalProperties[key] = value + }); + + const stippleApp = window[appName] = window.GENIEMODEL = app.mount(rootSelector); + stippleApp.WebChannel = Genie.initWebChannel(channel); + stippleApp.WebChannel.parent = stippleApp; + stippleApp.channel_ = channel; + + return stippleApp; + } // end of initStipple + + function initWatchers$vue_app_name(app){ + """, + join( + [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)] + ), + + """ + } // end of initWatchers - function create$vue_app_name(channel) { - window.counter$vue_app_name = window.counter$vue_app_name || 1 - const appName = '$vue_app_name' + ((counter$vue_app_name == 1) ? '' : '_' + window.counter$vue_app_name) - rootSelector = '#$vue_app_name' + ((counter$vue_app_name == 1) ? '' : '-' + window.counter$vue_app_name) - counter$vue_app_name++ + function create$vue_app_name(channel) { + window.counter$vue_app_name = window.counter$vue_app_name || 1 + const appName = '$vue_app_name' + ((counter$vue_app_name == 1) ? '' : '_' + window.counter$vue_app_name) + const rootSelector = '#$vue_app_name' + ((counter$vue_app_name == 1) ? '' : '-' + window.counter$vue_app_name) + counter$vue_app_name++ - if ( window.autorun === undefined || window.autorun === true ) { - initStipple$vue_app_name(appName, rootSelector, channel); - initWatchers$vue_app_name($app); + if ( window.autorun === undefined || window.autorun === true ) { + app = initStipple$vue_app_name(appName, rootSelector, channel); + initWatchers$vue_app_name(app); - $app.WebChannel.subscriptionHandlers.push(function(event) { - app_ready($app); - }); + app.WebChannel.subscriptionHandlers.push(function(event) { + app_ready(app); + }); + } } - } - // create$vue_app_name() - // is called via scipt with addEventListener to support multiple apps + // create$vue_app_name() + // is called via script with addEventListener to support multiple apps """ ) diff --git a/src/Stipple.jl b/src/Stipple.jl index 0f2873a..4240aba 100644 --- a/src/Stipple.jl +++ b/src/Stipple.jl @@ -845,7 +845,7 @@ function injectdeps(output::Vector{AbstractString}, M::Type{<:ReactiveModel}) :: output end - +# no longer needed, replaced by initscript function channelscript(channel::String) :: String Genie.Renderer.Html.script([""" document.addEventListener('DOMContentLoaded', () => window.Genie.initWebChannel('$dchannel') ); @@ -866,7 +866,6 @@ Outputs the HTML code necessary for injecting the dependencies in the page (the function deps(m::M) :: Vector{String} where {M<:ReactiveModel} channel = getchannel(m) output = [ - # channelscript(channel), initscript(vm(m), channel), (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")),