Skip to content
6 changes: 5 additions & 1 deletion src/Elements.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export root, elem, vm, @if, @else, @elseif, @for, @text, @bind, @data, @on, @cli
# deprecated exports
export @iif, @els, @elsiif, @recur

export @jsexpr, JSExpr, js_quote_replace, ∥, ∧
export @jsexpr, JSExpr, js_quote_replace, ∥, ∧, jse_str

export stylesheet, kw_to_str
export add_plugins, remove_plugins
Expand Down Expand Up @@ -475,6 +475,10 @@ macro jsexpr(expr)
:(JSExpr($ex))
end

macro jse_str(expr)
JSExpr(expr)
end

"""
@if(expr)

Expand Down
10 changes: 5 additions & 5 deletions src/ReactiveTools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1346,12 +1346,12 @@ function vue_options(hook_type, args...)
expr = args[1]
quote
let M = Stipple.@type
Stipple.$(Symbol("js_$hook_type"))(::M) = $expr
Stipple.$(Symbol("js_$hook_type"))(::Type{<:M}) = $expr
end
end |> esc
elseif length(args) == 2
T, expr = args[1], args[2]
esc(:(Stipple.$(Symbol("js_$hook_type"))(::$T) = $expr))
esc(:(Stipple.$(Symbol("js_$hook_type"))(::Type{<:$T}) = $expr))
else
error("Invalid number of arguments for vue options")
end
Expand Down Expand Up @@ -1464,7 +1464,7 @@ macro client_data(expr)

esc(quote
let M = Stipple.@type
Stipple.client_data(::M) = $output
Stipple.client_data(::Type{<:M}) = $output
end
end)
end
Expand All @@ -1481,7 +1481,7 @@ macro client_data(M, expr)
push!(output.args, e)
end

:(Stipple.client_data(::$(esc(M))) = $(esc(output)))
:(Stipple.client_data(::Type{<:$(esc(M))}) = $(esc(output)))
end

macro add_client_data(expr)
Expand All @@ -1500,7 +1500,7 @@ macro add_client_data(expr)
let M = Stipple.@type
cd_old = Stipple.client_data(M())
cd_new = $output
Stipple.client_data(::M) = merge(d1, d2)
Stipple.client_data(::Type{<:M}) = merge(d1, d2)
end
end)
end
Expand Down
74 changes: 41 additions & 33 deletions src/stipple/jsmethods.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
function js_methods(app::T) where {T<:ReactiveModel}
function js_methods(::Type{<:T}) where {T<:ReactiveModel}

Defines js functions for the `methods` section of the vue element.
Expected result types of the function are
Expand All @@ -12,7 +12,7 @@ Expected result types of the function are
### Example 1

```julia
js_methods(::MyDashboard) = \"\"\"
js_methods(::Type{<:MyDashboard}) = \"\"\"
mysquare: function (x) {
return x^2
}
Expand All @@ -23,18 +23,17 @@ js_methods(::MyDashboard) = \"\"\"
```
### Example 2
```
js_methods(::MyDashboard) = Dict(:f => "function(x) { console.log('x: ' + x) })
js_methods(::Type{<:MyDashboard}) = Dict(:f => "function(x) { console.log('x: ' + x) })
```
### Example 3
```
js_greet() = :greet => "function(name) {console.log('Hello ' + name)}"
js_bye() = :bye => "function() {console.log('Bye!')}"
js_methods(::MyDashboard) = [js_greet, js_bye]
js_methods(::Type{<:MyDashboard}) = [js_greet, js_bye]
```
"""
function js_methods(app::T)::String where {T<:ReactiveModel}
""
end
js_methods(::DataType) = ""
js_methods(::T) where T = js_methods(T)

# deprecated, now part of the model
function js_methods_events()::String
Expand All @@ -51,7 +50,7 @@ function js_methods_events()::String
end

"""
function js_computed(app::T) where {T<:ReactiveModel}
function js_computed(::Type{<:T}) where {T<:ReactiveModel}

Defines js functions for the `computed` section of the vue element.
These properties are updated every time on of the inner parameters changes its value.
Expand All @@ -72,14 +71,13 @@ js_computed(app::MyDashboard) = \"\"\"
\"\"\"
```
"""
function js_computed(app::T)::String where {T<:ReactiveModel}
""
end
js_computed(::DataType) = ""
js_computed(::T) where T = js_computed(T)

const jscomputed = js_computed

"""
function js_watch(app::T) where {T<:ReactiveModel}
function js_watch(::Type{<:T}) where {T<:ReactiveModel}

Defines js functions for the `watch` section of the vue element.
These functions are called every time the respective property changes.
Expand All @@ -95,7 +93,7 @@ Expected result types of the function are
Updates the `fullName` every time `firstName` or `lastName` changes.

```julia
js_watch(app::MyDashboard) = \"\"\"
js_watch(::Type{<:MyDashboard}) = \"\"\"
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
Expand All @@ -105,14 +103,13 @@ js_watch(app::MyDashboard) = \"\"\"
\"\"\"
```
"""
function js_watch(m::T)::String where {T<:ReactiveModel}
""
end
js_watch(::DataType) = ""
js_watch(::T) where T = js_watch(T)

const jswatch = js_watch

"""
function client_data(app::T)::String where {T<:ReactiveModel}
function client_data(::Type{<:MyApp})::String

Defines additional data that will only be visible by the browser.

Expand All @@ -122,13 +119,21 @@ In order to use the data you most probably also want to define [`js_methods`](@r

```julia
import Stipple.client_data
client_data(m::Example) = client_data(client_name = js"null", client_age = js"null", accept = false)
client_data(::Type{<:Example}) = client_data(client_name = js"null", client_age = js"null", accept = false)
```
will define the additional fields `client_name`, `client_age` and `accept` for models of type `Example`.
These definitions should, of course, not overlap with existing fields of your model.
### Note
Previously we defined the client_data function differently. This will continue to work,
but the new way might have some advantages in the future for mixins. Here is the old way:
```julia
client_data(::Example) = client_data(client_name = js"null", client_age = js"null", accept = false)
```
will define the additional fields `client_name`, `client_age` and `accept` for the model `Example`. These should, of course, not overlap with existing fields of your model.
"""
client_data(app::T) where T <: ReactiveModel = Dict{String, Any}()
client_data(::Type{<:ReactiveModel}) = Dict{String, Any}()
client_data(::T) where T = client_data(T)

client_data(;kwargs...) = Dict{String, Any}([String(k) => v for (k, v) in kwargs]...)
client_data(; kwargs...) = Dict{String, Any}([String(k) => v for (k, v) in kwargs]...)

for (f, field) in (
(:js_before_create, :beforeCreate), (:js_created, :created), (:js_before_mount, :beforeMount), (:js_mounted, :mounted),
Expand All @@ -138,7 +143,7 @@ for (f, field) in (
field_str = string(field)
Core.eval(@__MODULE__, quote
"""
function $($f)(app::T)::Union{Function, String, Vector} where {T<:ReactiveModel}
function $($f)(::Type{<:T})::Union{Function, String, Vector} where {T<:ReactiveModel}

Defines js statements for the `$($field_str)` section of the vue element.

Expand All @@ -150,7 +155,7 @@ for (f, field) in (
### Example 1

```julia
$($f)(app::MyDashboard) = \"\"\"
$($f)(::Type{<:MyDashboard}) = \"\"\"
if (this.cameraon) { startcamera() }
\"\"\"
```
Expand All @@ -161,17 +166,22 @@ for (f, field) in (
startcamera() = "if (this.cameraon) { startcamera() }"
stopcamera() = "if (this.cameraon) { stopcamera() }"

$($f)(app::MyDashboard) = [startcamera, stopcamera]
$($f)(::Type{<:MyDashboard}) = [startcamera, stopcamera]
```
Checking the result can be done in the following way
```
julia> render(MyApp())[:$($field_str)]
JSONText("function(){\n if (this.cameraon) { startcamera() }\n\n if (this.cameraon) { stopcamera() }\n}")
```
### Note
Previously we defined the function differently. This will continue to work,
but the new way might have some advantages in the future for mixins. Here is the old way:
```julia
$($f)(::MyDashboard) = [startcamera, stopcamera]
```
"""
function $f(app::T)::String where {T<:ReactiveModel}
""
end
$f(::DataType)::String = ""
$f(::T) where T = $f(T)
end)
end

Expand Down Expand Up @@ -253,13 +263,11 @@ function js_initscript(initscript::String)
"""
end

function js_created_auto(x)
""
end
js_created_auto(::DataType) = ""
js_created_auto(::T) where T = js_created_auto(T)

function js_watch_auto(x)
""
end
js_watch_auto(::DataType) = ""
js_watch_auto(::T) where T = js_watch_auto(T)

# methods to be used directly as arguments to js_methods

Expand Down
Loading
Loading