diff --git a/experiments/nextgen.nim b/experiments/nextgen.nim index d311eb9..40acf04 100644 --- a/experiments/nextgen.nim +++ b/experiments/nextgen.nim @@ -1,7 +1,7 @@ import vdom, kdom, vstyles, karax, karaxdsl, jdict, jstrutils, reactive -proc newTextInput*(text: RString; focus: RBool): VNode = +proc newTextInput*(text: RString; focus: RBool): VNode {.track.} = proc onFlip(ev: Event; target: VNode) = focus <- not focus.value @@ -23,20 +23,22 @@ var type User = ref object of ReactiveBase firstname, lastname: cstring + selected: bool var gu = newRSeq(@[ (User(firstname: "Some", lastname: "Body")), (User(firstname: "Some", lastname: "One")), (User(firstname: "Some", lastname: "Two"))]) -var selected = newReactive[User](nil) +var prevSelected: User = nil #newReactive[User](nil) proc toUI*(): RString = result = RString() result.subscribe proc (v: cstring) = if v.len > 0: - if selected >= 0: + let p = prevSelected #selected.value + if p != nil: # XXX what's happening here? - persons[selected].firstname = v - notifyObservers(persons[selected]) + p.firstname = v + notifyObservers(p) errmsg <- "" else: errmsg <- "name must not be empty" @@ -76,20 +78,31 @@ discard """ 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; selected: RBool): VNode = +proc renderUser(u: User): VNode {.track.} = result = buildHtml(tdiv): - let displayName = observe(u.firstname & " " & u.lastname) - if selected == u: - newTextInput displayName, focus + let displayName = u.firstname & " " & u.lastname + if u.selected: + # == selected.value: + !(inp <- displayName) + newTextInput inp, focus else: + button: + text "..." + proc onclick(ev: Event; n: VNode) = + if prevSelected != nil: + prevSelected.selected = false + notifyObservers(prevSelected) + u.selected = true + notifyObservers(u) + prevSelected = u text displayName button: text "(x)" @@ -103,6 +116,25 @@ template vmap(x: RSeq; elem, f: untyped): VNode = 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.. 0: + # x.sinks[0] = sink + #else: + x.sinks.add sink + if x.id == 0: + inc rid + x.id = rid proc broadcast(x: ReactiveBase, msg: Message; pos = 0) = for s in x.sinks: s(msg, pos) @@ -93,7 +93,7 @@ proc notifyObservers*(x: ReactiveBase) = x.broadcast(Mark) x.broadcast(Changed) -proc subscribeVal*[T](x: Reactive[T], f: proc(x: T)) = +proc subscribe*[T](x: Reactive[T], f: proc(x: T)) = let reactor = proc (msg: Message, pos: int) = case msg: of Mark: discard @@ -186,11 +186,10 @@ 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) = +template trackImpl(r: ReactiveBase; a, b: untyped) = when r is ReactiveBase: - addSink r, key, proc(m: Message; pos: int) = - if m == Changed: - runDiff(kxi, a, b) + addSink r, proc(m: Message; pos: int) = + if m == Changed: karax.runDiff(kxi, a, b) template doTrack*(r: ReactiveBase; a, b: untyped) {.dirty.} = bind addSink, Message, RSeq, Changed, Deleted, Inserted @@ -207,40 +206,30 @@ template doTrackResize*(r: ReactiveBase; a, b: untyped) {.dirty.} = case m of Deleted: karax.runDel(kxi, a, pos) of Inserted: + let it {.used.} = r[pos] 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() - var paramList: seq[NimNode] = @[] + var inner = copyNimTree(procDef) + inner[0] = ident($procDef.name & "Inner") + var call = newCall(inner[0]) + trackings.add inner + trackings.add newAssignment(ident"result", call) + for j in 1..