Skip to content

Commit

Permalink
Merge pull request #240 from GenieFramework/hh-revivers
Browse files Browse the repository at this point in the history
refactor reviver
  • Loading branch information
hhaensel authored Nov 18, 2023
2 parents 89ce9a9 + 36f3724 commit a0bebcf
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 20 deletions.
19 changes: 6 additions & 13 deletions assets/js/watchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,13 @@ const watcherMixin = {

const reviveMixin = {
methods: {
revive_payload: function(obj) {
if (typeof obj === 'object') {
for (var key in obj) {
if ( (typeof obj[key] === 'object') && (obj[key]!=null) && !(obj[key].jsfunction) ) {
this.revive_payload(obj[key])
} else {
if ( (obj[key]!=null) && (obj[key].jsfunction) ) {
obj[key] = Function(obj[key].jsfunction.arguments, obj[key].jsfunction.body)
}
}
}
revive_jsfunction: function (k, v) {
if ( (typeof v==='object') && (v!=null) && (v.jsfunction) ) {
return Function(v.jsfunction.arguments, v.jsfunction.body)
} else {
return v
}
return obj;
}
}
}
}

Expand Down
15 changes: 11 additions & 4 deletions src/Elements.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ using MacroTools
import Genie.Renderer.Html: HTMLString, normal_element

export root, elem, vm, @if, @else, @elseif, @for, @text, @bind, @data, @on, @click, @showif
export stylesheet, kw_to_str
export stylesheet, kw_to_str, js_add_reviver

# deprecated
export @iif, @elsiif, @els, @recur
Expand Down Expand Up @@ -41,6 +41,14 @@ end

const vm = root

function js_add_reviver(revivername::String)
"""
Genie.WebChannels.subscriptionHandlers.push(function(event) {
Genie.Revivers.addReviver($revivername);
});
"""
end

#===#

"""
Expand Down Expand Up @@ -97,14 +105,13 @@ function vue_integration(::Type{M};
window.parse_payload = function(payload){
if (payload.key) {
window.$(vue_app_name).revive_payload(payload)
window.$(vue_app_name).updateField(payload.key, payload.value);
window.$(vue_app_name).updateField(payload.key, payload.value);
}
}
function app_ready() {
$vue_app_name.isready = true;
Genie.Revivers.addReviver(window.$(vue_app_name).revive_jsfunction);
$(transport == Genie.WebChannels &&
"
try {
Expand Down
68 changes: 68 additions & 0 deletions src/ReactiveTools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export @readonly, @private, @in, @out, @jsfn, @readonly!, @private!, @in!, @out!
#definition of handlers/events
export @onchange, @onbutton, @event, @notify

# definition of dependencies
export @deps, @clear_deps

# deletion
export @clear, @clear_vars, @clear_handlers

Expand Down Expand Up @@ -1302,4 +1305,69 @@ macro modelstorage()
end |> esc
end

"""
@deps f
Add a function f to the dependencies of the current app.
------------------------
@deps M::Module
Add the dependencies of the module M to the dependencies of the current app.
"""
macro deps(expr)
quote
Stipple.deps!(Stipple.@type(), $expr)
end |> esc
end

"""
@deps(MyApp::ReactiveModel, f::Function)
Add a function f to the dependencies of the app MyApp.
The module needs to define a function `deps()`.
------------------------
@deps(MyApp::ReactiveModel, M::Module)
Add the dependencies of the module M to the dependencies of the app MyApp.
The module needs to define a function `deps()`.
"""
macro deps(M, expr)
quote
Stipple.deps!($M, $expr)
end |> esc
end

"""
@clear_deps
Delete all dependencies of the current app.
------------------------
@clear_deps MyApp
Delete all dependencies of the app MyApp.
"""
macro clear_deps()
quote
Stipple.clear_deps!(Stipple.@type())
end |> esc
end

macro clear_deps(M)
quote
Stipple.clear_deps!($M)
end |> esc
end

end
37 changes: 35 additions & 2 deletions src/Stipple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -731,11 +731,21 @@ end
function injectdeps(output::Vector{AbstractString}, M::Type{<:ReactiveModel}) :: Vector{AbstractString}
for (key, f) in DEPS
key isa DataType && key <: ReactiveModel && continue
# exclude keys starting with '_'
key isa Symbol && startswith("$key", '_') && continue
push!(output, f()...)
end
AM = get_abstract_type(M)
haskey(DEPS, AM) && push!(output, DEPS[AM]()...)

if haskey(DEPS, AM)
# DEPS[AM] contains the stipple-generated deps
push!(output, DEPS[AM]()...)
# furthermore, include deps who's keys start with "_<name of the ReactiveModel>_"
model_prefix = "_$(vm(AM))_"
for (key, f) in DEPS
key isa Symbol || continue
startswith("$key", model_prefix) && push!(output, f()...)
end
end
output
end

Expand Down Expand Up @@ -774,6 +784,29 @@ function deps!(m::Any, f::Function)
DEPS[m] = f
end

function deps!(m::Any, M::Module)
DEPS[m] = M.deps
end

function deps!(M::Type{<:ReactiveModel}, f::Function; extra_deps = true)
key = extra_deps ? Symbol("_$(vm(M))_$(nameof(f))") : M
DEPS[key] = f isa Function ? f : f.deps
end

deps!(M::Type{<:ReactiveModel}, modul::Module; extra_deps = true) = deps!(M, modul.deps; extra_deps)

deps!(m::Any, v::Vector{Union{Function, Module}}) = deps!.(Ref(m), v)
deps!(m::Any, t::Tuple) = [deps!(m, f) for f in t]
deps!(m, args...) = [deps!(m, f) for f in args]

function clear_deps!(M::Type{<:ReactiveModel})
delete!(DEPS, M)
model_prefix = "_$(vm(M))_"
for k in keys(Stipple.DEPS)
k isa Symbol && startswith("$k", model_prefix) && delete!(DEPS, k)
end
end

@specialize

"""
Expand Down
23 changes: 22 additions & 1 deletion src/stipple/rendering.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,27 @@ function julia_to_vue(field, mapping_keys = mapping_keys()) :: String
end
end

"""
jsrender(x, args...)
Defines separate rendering for the Vue instance. This method is only necessary for non-standard types that
are not transmittable by regular json. Such types need a reviver to be transmitted via json and (optionally)
a render method that is only applied for the rendering of the model.
The model is not transmitted via json but via a js-file. So there it is possible to define non-serializable values.
### Example
```
Stipple.render(z::Complex) = Dict(:mathjs => "Complex", :re => z.re, :im => z.im)
function Stipple.jsrender(z::Union{Complex, R{<:Complex}}, args...)
JSONText("math.complex('\$(replace(strip(repr(Observables.to_value(z)), '"'), 'm' => ""))')")
end
Stipple.stipple_parse(::Complex, z::Dict{String, Any}) = float(z["re"]) + z["im"]
```
"""
jsrender(x, args...) = render(x, args...)
jsrender(r::Reactive, args...) = jsrender(getfield(getfield(r,:o), :val), args...)

"""
function Stipple.render(app::M, fieldname::Union{Symbol,Nothing} = nothing)::Dict{Symbol,Any} where {M<:ReactiveModel}
Expand All @@ -107,7 +128,7 @@ function Stipple.render(app::M)::Dict{Symbol,Any} where {M<:ReactiveModel}
occursin(SETTINGS.private_pattern, String(field)) && continue
f isa Reactive && f.r_mode == PRIVATE && continue

result[julia_to_vue(field)] = Stipple.render(f, field)
result[julia_to_vue(field)] = Stipple.jsrender(f, field)
end

vue = Dict( :el => JSONText("rootSelector"),
Expand Down

0 comments on commit a0bebcf

Please sign in to comment.