nextgen example now uses the makeReactive macro
This commit is contained in:
parent
db0bba2c3f
commit
e70924c88e
2 changed files with 40 additions and 71 deletions
|
|
@ -19,26 +19,25 @@ proc textInput*(text: RString; focus: RBool): VNode {.track.} =
|
||||||
var
|
var
|
||||||
errmsg = rstr("")
|
errmsg = rstr("")
|
||||||
|
|
||||||
type
|
makeReactive:
|
||||||
User = ref object of ReactiveBase
|
type
|
||||||
firstname, lastname: cstring
|
User = ref object
|
||||||
selected: bool
|
firstname, lastname: cstring
|
||||||
|
selected: bool
|
||||||
|
|
||||||
var gu = newRSeq(@[ (User(firstname: "Some", lastname: "Body")),
|
var gu = newRSeq(@[ (User(rawFirstname: "Some", rawLastname: "Body")),
|
||||||
(User(firstname: "Some", lastname: "One")),
|
(User(rawFirstname: "Some", rawLastname: "One")),
|
||||||
(User(firstname: "Some", lastname: "Two"))])
|
(User(rawFirstname: "Some", rawLastname: "Two"))])
|
||||||
var prevSelected: User = nil #newReactive[User](nil)
|
var prevSelected: User = nil #newReactive[User](nil)
|
||||||
|
|
||||||
proc unselect() =
|
proc unselect() =
|
||||||
if prevSelected != nil:
|
if prevSelected != nil:
|
||||||
prevSelected.selected = false
|
prevSelected.selected = false
|
||||||
notifyObservers(prevSelected)
|
|
||||||
prevSelected = nil
|
prevSelected = nil
|
||||||
|
|
||||||
proc select(u: User) =
|
proc select(u: User) =
|
||||||
unselect()
|
unselect()
|
||||||
u.selected = true
|
u.selected = true
|
||||||
notifyObservers(u)
|
|
||||||
prevSelected = u
|
prevSelected = u
|
||||||
|
|
||||||
proc toUI*(isFirstname: bool): RString =
|
proc toUI*(isFirstname: bool): RString =
|
||||||
|
|
@ -51,14 +50,13 @@ proc toUI*(isFirstname: bool): RString =
|
||||||
p.firstname = v
|
p.firstname = v
|
||||||
else:
|
else:
|
||||||
p.lastname = v
|
p.lastname = v
|
||||||
notifyObservers(p)
|
|
||||||
unselect()
|
unselect()
|
||||||
errmsg <- ""
|
errmsg <- ""
|
||||||
else:
|
else:
|
||||||
errmsg <- "name must not be empty"
|
errmsg <- "name must not be empty"
|
||||||
|
|
||||||
var firstname = toUI(true)
|
var inpFirstname = toUI(true)
|
||||||
var lastname = toUI(false)
|
var inpLastname = toUI(false)
|
||||||
|
|
||||||
proc adaptFocus(def = false): RBool =
|
proc adaptFocus(def = false): RBool =
|
||||||
result = RBool()
|
result = RBool()
|
||||||
|
|
@ -67,8 +65,6 @@ proc adaptFocus(def = false): RBool =
|
||||||
result.subscribe proc (hasFocus: bool) =
|
result.subscribe proc (hasFocus: bool) =
|
||||||
if not hasFocus:
|
if not hasFocus:
|
||||||
unselect()
|
unselect()
|
||||||
firstname.notifyObservers()
|
|
||||||
lastname.notifyObservers()
|
|
||||||
|
|
||||||
var focusA = adaptFocus()
|
var focusA = adaptFocus()
|
||||||
var focusB = adaptFocus()
|
var focusB = adaptFocus()
|
||||||
|
|
@ -87,33 +83,15 @@ proc styler(): VStyle =
|
||||||
|
|
||||||
var clicks = 0
|
var clicks = 0
|
||||||
|
|
||||||
discard """
|
|
||||||
# Text gets a *reactive* string in the first place!
|
|
||||||
# Text can register and knows how to update itself!
|
|
||||||
proc toReact(): RString =
|
|
||||||
observe(u):
|
|
||||||
u.firstname & u.lastname
|
|
||||||
|
|
||||||
let t = text(u.firstname & " " & u.lastname)
|
|
||||||
observe(u, t.update(u.firstname & " " & u.lastname))
|
|
||||||
t
|
|
||||||
|
|
||||||
template observe(s: cstring): RString =
|
|
||||||
let tmp = rstr(s)
|
|
||||||
u.subscribeSelf proc () =
|
|
||||||
tmp <- s
|
|
||||||
temp
|
|
||||||
"""
|
|
||||||
|
|
||||||
proc renderUser(u: User): VNode {.track.} =
|
proc renderUser(u: User): VNode {.track.} =
|
||||||
result = buildHtml(tdiv):
|
result = buildHtml(tdiv):
|
||||||
if u.selected:
|
if u.selected:
|
||||||
firstname <- u.firstname
|
inpFirstname <- u.firstname
|
||||||
tdiv:
|
tdiv:
|
||||||
textInput firstname, focusA
|
textInput inpFirstname, focusA
|
||||||
lastname <- u.lastname
|
inpLastname <- u.lastname
|
||||||
tdiv:
|
tdiv:
|
||||||
textInput lastname, focusB
|
textInput inpLastname, focusB
|
||||||
else:
|
else:
|
||||||
button:
|
button:
|
||||||
text "..."
|
text "..."
|
||||||
|
|
@ -125,32 +103,6 @@ proc renderUser(u: User): VNode {.track.} =
|
||||||
proc onclick(ev: Event; n: VNode) =
|
proc onclick(ev: Event; n: VNode) =
|
||||||
gu.deleteElem(u)
|
gu.deleteElem(u)
|
||||||
|
|
||||||
template vmap(x: RSeq; elem, f: untyped): VNode =
|
|
||||||
let tmp = buildHtml(elem):
|
|
||||||
for i in 0..<len(x):
|
|
||||||
f(x[i])
|
|
||||||
doTrackResize(x, tmp, f(x[pos]))
|
|
||||||
tmp
|
|
||||||
|
|
||||||
template vmapIt(x: RSeq; elem, call: untyped): VNode =
|
|
||||||
var it {.inject}: type(x[0])
|
|
||||||
let tmp = buildHtml(elem):
|
|
||||||
for i in 0..<len(x):
|
|
||||||
it = x[i]
|
|
||||||
call
|
|
||||||
doTrackResize(x, tmp, call)
|
|
||||||
tmp
|
|
||||||
|
|
||||||
proc hasNativeNode(parent, x: Node): bool =
|
|
||||||
if parent == x: return true
|
|
||||||
for i in 0..<parent.len:
|
|
||||||
if hasNativeNode(parent[i], x): return true
|
|
||||||
|
|
||||||
proc text*(s: RString): VNode =
|
|
||||||
result = text(s.value)
|
|
||||||
s.subscribe proc(v: cstring) =
|
|
||||||
if result.dom != nil: result.dom.nodeValue = v
|
|
||||||
|
|
||||||
proc main(gu: RSeq[User]): VNode =
|
proc main(gu: RSeq[User]): VNode =
|
||||||
result = buildHtml(tdiv):
|
result = buildHtml(tdiv):
|
||||||
tdiv:
|
tdiv:
|
||||||
|
|
@ -158,7 +110,7 @@ proc main(gu: RSeq[User]): VNode =
|
||||||
text "Add User"
|
text "Add User"
|
||||||
proc onclick(ev: Event; n: VNode) =
|
proc onclick(ev: Event; n: VNode) =
|
||||||
inc clicks
|
inc clicks
|
||||||
gu.add User(firstname: "Added", lastname: &clicks)
|
gu.add User(rawFirstname: "Added", rawLastname: &clicks)
|
||||||
tdiv:
|
tdiv:
|
||||||
text errmsg
|
text errmsg
|
||||||
vmapIt(gu, tdiv, renderUser(it))
|
vmapIt(gu, tdiv, renderUser(it))
|
||||||
|
|
|
||||||
|
|
@ -283,16 +283,10 @@ macro track*(procDef: untyped): untyped =
|
||||||
when defined(debugKaraxDsl):
|
when defined(debugKaraxDsl):
|
||||||
echo repr result
|
echo repr result
|
||||||
|
|
||||||
macro mut(t: typed): untyped =
|
|
||||||
if getType(t).typeKind == ntyRef:
|
|
||||||
result = t
|
|
||||||
else:
|
|
||||||
result = newTree(nnkVarTy, t)
|
|
||||||
|
|
||||||
proc generatePrivateAccessors(name, hidden, typ, fieldTyp: NimNode): NimNode =
|
proc generatePrivateAccessors(name, hidden, typ, fieldTyp: NimNode): NimNode =
|
||||||
template helper(name, hidden, typ, fieldTyp) {.dirty.} =
|
template helper(name, hidden, typ, fieldTyp) {.dirty.} =
|
||||||
proc name(self: typ): fieldTyp = self.hidden
|
proc name(self: typ): fieldTyp = self.hidden
|
||||||
proc `name=`(self: mut typ; val: fieldTyp) =
|
proc `name=`(self: typ; val: fieldTyp) =
|
||||||
self.hidden = val
|
self.hidden = val
|
||||||
notifyObservers(self)
|
notifyObservers(self)
|
||||||
result = getAst(helper(name, hidden, typ, fieldTyp))
|
result = getAst(helper(name, hidden, typ, fieldTyp))
|
||||||
|
|
@ -300,7 +294,7 @@ proc generatePrivateAccessors(name, hidden, typ, fieldTyp: NimNode): NimNode =
|
||||||
proc generatePublicAccessors(name, hidden, typ, fieldTyp: NimNode): NimNode =
|
proc generatePublicAccessors(name, hidden, typ, fieldTyp: NimNode): NimNode =
|
||||||
template helper(name, hidden, typ, fieldTyp) {.dirty.} =
|
template helper(name, hidden, typ, fieldTyp) {.dirty.} =
|
||||||
proc name*(self: typ): fieldTyp = self.hidden
|
proc name*(self: typ): fieldTyp = self.hidden
|
||||||
proc `name=`*(self: mut typ; val: fieldTyp) =
|
proc `name=`*(self: typ; val: fieldTyp) =
|
||||||
self.hidden = val
|
self.hidden = val
|
||||||
notifyObservers(self)
|
notifyObservers(self)
|
||||||
result = getAst(helper(name, hidden, typ, fieldTyp))
|
result = getAst(helper(name, hidden, typ, fieldTyp))
|
||||||
|
|
@ -335,6 +329,29 @@ macro makeReactive*(n: untyped): untyped =
|
||||||
when defined(debugKaraxDsl):
|
when defined(debugKaraxDsl):
|
||||||
echo repr result
|
echo repr result
|
||||||
|
|
||||||
|
import vdom
|
||||||
|
|
||||||
|
template vmap*(x: RSeq; elem, f: untyped): VNode =
|
||||||
|
let tmp = buildHtml(elem):
|
||||||
|
for i in 0..<len(x):
|
||||||
|
f(x[i])
|
||||||
|
doTrackResize(x, tmp, f(x[pos]))
|
||||||
|
tmp
|
||||||
|
|
||||||
|
template vmapIt*(x: RSeq; elem, call: untyped): VNode =
|
||||||
|
var it {.inject}: type(x[0])
|
||||||
|
let tmp = buildHtml(elem):
|
||||||
|
for i in 0..<len(x):
|
||||||
|
it = x[i]
|
||||||
|
call
|
||||||
|
doTrackResize(x, tmp, call)
|
||||||
|
tmp
|
||||||
|
|
||||||
|
proc text*(s: RString): VNode =
|
||||||
|
result = text(s.value)
|
||||||
|
s.subscribe proc(v: cstring) =
|
||||||
|
if result.dom != nil: result.dom.nodeValue = v
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
makeReactive:
|
makeReactive:
|
||||||
type
|
type
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue