reactive sequence works now
This commit is contained in:
parent
46b1259498
commit
56a50679de
4 changed files with 137 additions and 25 deletions
|
|
@ -2,24 +2,61 @@
|
|||
import vdom, kdom, vstyles, karax, karaxdsl, jdict, jstrutils, reactive
|
||||
|
||||
type
|
||||
User = ref object
|
||||
User = ref object of ReactiveBase
|
||||
firstname, lastname: cstring
|
||||
|
||||
var gu = @[newReactive(User(firstname: "Some", lastname: "Body")),
|
||||
newReactive(User(firstname: "Some", lastname: "One")),
|
||||
newReactive(User(firstname: "Some", lastname: "Two"))]
|
||||
var gu = newRSeq(@[ (User(firstname: "Some", lastname: "Body")),
|
||||
(User(firstname: "Some", lastname: "One")),
|
||||
(User(firstname: "Some", lastname: "Two"))])
|
||||
var clicks = 0
|
||||
|
||||
proc renderUser(u: Reactive[User]): VNode {.track.} =
|
||||
result = buildHtml(button):
|
||||
text u.now.firstname & " " & u.now.lastname
|
||||
proc onclick(ev: Event; n: VNode) =
|
||||
inc clicks
|
||||
u <- User(firstname: "Another", lastname: &clicks)
|
||||
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
|
||||
|
||||
proc main(): VNode =
|
||||
result = buildHtml(tdiv):
|
||||
for i in 0..high(gu):
|
||||
renderUser(gu[i])
|
||||
let t = text(u.firstname & " " & u.lastname)
|
||||
observe(u, t.update(u.firstname & " " & u.lastname))
|
||||
t
|
||||
"""
|
||||
|
||||
setInitializer(main)
|
||||
proc renderUser(u: User): VNode = #{.track.} =
|
||||
proc inner(u: User): VNode =
|
||||
result = buildHtml(tdiv):
|
||||
text u.firstname & " " & u.lastname
|
||||
button:
|
||||
text "(X)"
|
||||
proc onclick(ev: Event; n: VNode) =
|
||||
#u.firstname = "kfdj"
|
||||
#u.lastname = &clicks
|
||||
#notifyObservers(u)
|
||||
gu.deleteElem(u)
|
||||
|
||||
result = inner(u)
|
||||
doTrack(u, result, inner(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
|
||||
|
||||
proc main(gu: RSeq[User]): VNode = #{.track.} =
|
||||
proc inner(gu: RSeq[User]): VNode =
|
||||
result = buildHtml(tdiv):
|
||||
vmap(gu, tdiv, renderUser)
|
||||
tdiv:
|
||||
button:
|
||||
text "Add User"
|
||||
proc onclick(ev: Event; n: VNode) =
|
||||
inc clicks
|
||||
gu.add User(firstname: "Added", lastname: &clicks)
|
||||
result = inner(gu)
|
||||
doTrack(gu, result, inner(gu))
|
||||
|
||||
proc init(): VNode = main(gu)
|
||||
|
||||
setInitializer(init)
|
||||
|
|
|
|||
|
|
@ -514,6 +514,24 @@ when defined(stats):
|
|||
result = m + 1
|
||||
inc total
|
||||
|
||||
proc runDel*(kxi: KaraxInstance; parent: VNode; position: int) =
|
||||
detach(parent[position])
|
||||
let current = parent.dom
|
||||
kxi.addPatch(pkRemove, current, current.childNodes[position], nil)
|
||||
parent.delete(position)
|
||||
applyPatch(kxi)
|
||||
|
||||
proc runIns*(kxi: KaraxInstance; parent, kid: VNode; position: int) =
|
||||
let current = parent.dom
|
||||
if position >= parent.len:
|
||||
kxi.addPatch(pkAppend, current, nil, kid)
|
||||
parent.add(kid)
|
||||
else:
|
||||
let before = current.childNodes[position]
|
||||
kxi.addPatch(pkInsertBefore, current, before, kid)
|
||||
parent.insert(kid, position)
|
||||
applyPatch(kxi)
|
||||
|
||||
proc runDiff*(kxi: KaraxInstance; oldNode, newNode: VNode) =
|
||||
let olddom = oldNode.dom
|
||||
discard diff(newNode, oldNode, nil, olddom, kxi)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ type
|
|||
s: seq[T]
|
||||
L: RInt
|
||||
|
||||
proc addSink[T](x: Reactive[T]; sink: proc(msg: Message; pos: int)) =
|
||||
proc addSink(x: ReactiveBase; sink: proc(msg: Message; pos: int)) =
|
||||
x.sinks.add sink
|
||||
|
||||
proc addSink(x: ReactiveBase; key: cstring; sink: proc(msg: Message; pos: int)) =
|
||||
|
|
@ -88,7 +88,7 @@ proc `<-`*[T](x: Reactive[T], val: T) =
|
|||
x.broadcast(Mark)
|
||||
x.broadcast(Changed)
|
||||
|
||||
proc changed*(x: ReactiveBase) =
|
||||
proc notifyObservers*(x: ReactiveBase) =
|
||||
x.broadcast(Mark)
|
||||
x.broadcast(Changed)
|
||||
|
||||
|
|
@ -125,10 +125,17 @@ proc newRSeq*[T](data: seq[T]): RSeq[T] =
|
|||
for i in 0..high(data):
|
||||
result.s[i] = data[i]
|
||||
|
||||
proc `[]=`[T](x: RSeq[T]; index: int; v: T) =
|
||||
proc `[]=`*[T](x: RSeq[T]; index: int; v: T) =
|
||||
x.s[index] = v
|
||||
|
||||
proc `[]`[T](x: RSeq[T]; index: int): T = x.s[index]
|
||||
proc `[]`*[T](x: RSeq[T]; index: int): T = x.s[index]
|
||||
proc len*[T](x: RSeq[T]): int = x.s.len
|
||||
|
||||
proc add*[T](x: RSeq[T]; y: T) =
|
||||
let position = x.s.len
|
||||
x.s.add(y)
|
||||
x.broadcast(Mark)
|
||||
x.broadcast(Inserted, position)
|
||||
|
||||
proc insert*[T](x: RSeq[T]; y: T; position = 0) =
|
||||
x.s.insert(y, position)
|
||||
|
|
@ -140,6 +147,16 @@ proc delete*[T](x: RSeq[T]; position = 0) =
|
|||
x.broadcast(Mark)
|
||||
x.broadcast(Deleted, position)
|
||||
|
||||
proc deleteElem*[T](x: RSeq[T]; y: T) =
|
||||
var position = -1
|
||||
for i in 0..<x.len:
|
||||
if x[i] == y:
|
||||
position = i; break
|
||||
if position >= 0:
|
||||
x.s.delete(position)
|
||||
x.broadcast(Mark)
|
||||
x.broadcast(Deleted, position)
|
||||
|
||||
proc map*[T, U](x: RSeq[T], f: proc(x: T): U): RSeq[U] =
|
||||
let xl = x.L.value
|
||||
let res = newRSeq[U](xl)
|
||||
|
|
@ -159,24 +176,60 @@ proc map*[T, U](x: RSeq[T], f: proc(x: T): U): RSeq[U] =
|
|||
import macros
|
||||
|
||||
template trackImpl(r: ReactiveBase; key: cstring; a, b: untyped) =
|
||||
when r is Reactive:
|
||||
when r is ReactiveBase:
|
||||
addSink r, key, proc(m: Message; pos: int) =
|
||||
if m == Changed:
|
||||
runDiff(kxi, a, b)
|
||||
|
||||
template doTrack*(r: ReactiveBase; a, b: untyped) {.dirty.} =
|
||||
bind addSink, Message, RSeq, Changed, Deleted, Inserted
|
||||
addSink r, proc(m: Message; pos: int) =
|
||||
#when r is RSeq:
|
||||
#echo "Message: ", m, " ", pos
|
||||
if m == Changed: karax.runDiff(kxi, a, b)
|
||||
|
||||
template doTrackResize*(r: ReactiveBase; a, b: untyped) {.dirty.} =
|
||||
bind addSink, Message, RSeq, Changed, Deleted, Inserted
|
||||
addSink r, proc(m: Message; pos: int) =
|
||||
#when r is RSeq:
|
||||
#echo "Message: ", m, " ", pos
|
||||
case m
|
||||
of Deleted: karax.runDel(kxi, a, pos)
|
||||
of Inserted:
|
||||
karax.runIns(kxi, a, b, pos)
|
||||
else: discard
|
||||
|
||||
template notifyImpl(r: untyped) =
|
||||
when r is ReactiveBase:
|
||||
notifyObservers(r)
|
||||
|
||||
proc root(n: NimNode): NimNode =
|
||||
result = n
|
||||
while result.kind in {nnkDotExpr, nnkBracketExpr}: result = result[0]
|
||||
|
||||
proc analyse(n: NimNode; paramList: seq[NimNode]): NimNode =
|
||||
result = n
|
||||
#if n.kind in {nnkAsgn, nnkFastAsgn}:
|
||||
#
|
||||
# n[0]
|
||||
#else:
|
||||
# recurse()
|
||||
|
||||
macro track*(procDef: untyped): untyped =
|
||||
let params = params(procDef)
|
||||
let key = lineInfo(procDef)
|
||||
var call = newCall(procDef.name)
|
||||
var trackings = newStmtList()
|
||||
for b in procDef.body: trackings.add b
|
||||
var paramList: seq[NimNode] = @[]
|
||||
for j in 1..<params.len:
|
||||
let x = params[j]
|
||||
expectKind x, nnkIdentDefs
|
||||
for i in 0..x.len-3:
|
||||
let param = x[i]
|
||||
call.add param
|
||||
trackings.add getAst(trackImpl(param, key, ident"result", call))
|
||||
for i in 0..x.len-3: paramList.add(x[i])
|
||||
|
||||
for b in procDef.body: trackings.add analyse(b, paramList)
|
||||
for param in paramList:
|
||||
call.add param
|
||||
trackings.add getAst(trackImpl(param, key, ident"result", call))
|
||||
|
||||
result = copyNimTree(procDef)
|
||||
result.body = trackings
|
||||
|
|
|
|||
|
|
@ -224,6 +224,10 @@ proc len*(x: VNode): int = x.kids.len
|
|||
proc `[]`*(x: VNode; idx: int): VNode = x.kids[idx]
|
||||
proc `[]=`*(x: VNode; idx: int; y: VNode) = x.kids[idx] = y
|
||||
proc add*(parent, kid: VNode) = parent.kids.add kid
|
||||
proc delete*(parent: VNode; position: int) =
|
||||
parent.kids.delete(position)
|
||||
proc insert*(parent, kid: VNode; position: int) =
|
||||
parent.kids.insert(kid, position)
|
||||
proc newVNode*(kind: VNodeKind): VNode = VNode(kind: kind, index: -1)
|
||||
|
||||
proc tree*(kind: VNodeKind; kids: varargs[VNode]): VNode =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue