wip; nothing works
This commit is contained in:
parent
56a50679de
commit
9fce711bd6
3 changed files with 107 additions and 30 deletions
|
|
@ -1,6 +1,25 @@
|
||||||
|
|
||||||
import vdom, kdom, vstyles, karax, karaxdsl, jdict, jstrutils, reactive
|
import vdom, kdom, vstyles, karax, karaxdsl, jdict, jstrutils, reactive
|
||||||
|
|
||||||
|
proc newTextInput*(text: RString; focus: RBool): VNode =
|
||||||
|
proc onFlip(ev: Event; target: VNode) =
|
||||||
|
focus <- not focus.value
|
||||||
|
|
||||||
|
proc onKeyupEnter(ev: Event; target: VNode) =
|
||||||
|
text <- target.value
|
||||||
|
#text.notifyObservers()
|
||||||
|
|
||||||
|
proc onkeyup(ev: Event; n: VNode) =
|
||||||
|
# keep displayValue up to date, but do not tell the client yet!
|
||||||
|
text.value = n.value
|
||||||
|
|
||||||
|
result = buildHtml(input(`type`="text",
|
||||||
|
value=text.value, onblur=onFlip, onfocus=onFlip,
|
||||||
|
onkeyupenter=onkeyupenter, onkeyup=onkeyup, setFocus=focus.value))
|
||||||
|
|
||||||
|
var
|
||||||
|
errmsg = rstr("")
|
||||||
|
|
||||||
type
|
type
|
||||||
User = ref object of ReactiveBase
|
User = ref object of ReactiveBase
|
||||||
firstname, lastname: cstring
|
firstname, lastname: cstring
|
||||||
|
|
@ -8,6 +27,43 @@ type
|
||||||
var gu = newRSeq(@[ (User(firstname: "Some", lastname: "Body")),
|
var gu = newRSeq(@[ (User(firstname: "Some", lastname: "Body")),
|
||||||
(User(firstname: "Some", lastname: "One")),
|
(User(firstname: "Some", lastname: "One")),
|
||||||
(User(firstname: "Some", lastname: "Two"))])
|
(User(firstname: "Some", lastname: "Two"))])
|
||||||
|
var selected = newReactive[User](nil)
|
||||||
|
|
||||||
|
proc toUI*(): RString =
|
||||||
|
result = RString()
|
||||||
|
result.subscribe proc (v: cstring) =
|
||||||
|
if v.len > 0:
|
||||||
|
if selected >= 0:
|
||||||
|
# XXX what's happening here?
|
||||||
|
persons[selected].firstname = v
|
||||||
|
notifyObservers(persons[selected])
|
||||||
|
errmsg <- ""
|
||||||
|
else:
|
||||||
|
errmsg <- "name must not be empty"
|
||||||
|
|
||||||
|
var inp = toUI()
|
||||||
|
|
||||||
|
proc adaptFocus(def = false): RBool =
|
||||||
|
result = RBool()
|
||||||
|
result.value = def
|
||||||
|
result.subscribe proc (hasFocus: bool) =
|
||||||
|
if not hasFocus:
|
||||||
|
inp.notifyObservers()
|
||||||
|
|
||||||
|
var focus = adaptFocus()
|
||||||
|
|
||||||
|
proc styler(): VStyle =
|
||||||
|
result = style(
|
||||||
|
(StyleAttr.position, cstring"relative"),
|
||||||
|
(StyleAttr.paddingLeft, cstring"10px"),
|
||||||
|
(StyleAttr.paddingRight, cstring"5px"),
|
||||||
|
(StyleAttr.height, cstring"30px"),
|
||||||
|
(StyleAttr.lineHeight, cstring"30px"),
|
||||||
|
(StyleAttr.border, cstring"solid 8px " & (if focus.value: cstring"red" else: cstring"black")),
|
||||||
|
(StyleAttr.fontSize, cstring"12px"),
|
||||||
|
(StyleAttr.fontWeight, cstring"600")
|
||||||
|
)
|
||||||
|
|
||||||
var clicks = 0
|
var clicks = 0
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
|
|
@ -22,20 +78,23 @@ discard """
|
||||||
t
|
t
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc renderUser(u: User): VNode = #{.track.} =
|
template observe(s: cstring): RString =
|
||||||
proc inner(u: User): VNode =
|
let tmp = rstr(s)
|
||||||
result = buildHtml(tdiv):
|
u.subscribeSelf proc () =
|
||||||
text u.firstname & " " & u.lastname
|
tmp <- s
|
||||||
button:
|
temp
|
||||||
text "(X)"
|
|
||||||
proc onclick(ev: Event; n: VNode) =
|
|
||||||
#u.firstname = "kfdj"
|
|
||||||
#u.lastname = &clicks
|
|
||||||
#notifyObservers(u)
|
|
||||||
gu.deleteElem(u)
|
|
||||||
|
|
||||||
result = inner(u)
|
proc renderUser(u: User; selected: RBool): VNode =
|
||||||
doTrack(u, result, inner(u))
|
result = buildHtml(tdiv):
|
||||||
|
let displayName = observe(u.firstname & " " & u.lastname)
|
||||||
|
if selected == u:
|
||||||
|
newTextInput displayName, focus
|
||||||
|
else:
|
||||||
|
text displayName
|
||||||
|
button:
|
||||||
|
text "(x)"
|
||||||
|
proc onclick(ev: Event; n: VNode) =
|
||||||
|
gu.deleteElem(u)
|
||||||
|
|
||||||
template vmap(x: RSeq; elem, f: untyped): VNode =
|
template vmap(x: RSeq; elem, f: untyped): VNode =
|
||||||
let tmp = buildHtml(elem):
|
let tmp = buildHtml(elem):
|
||||||
|
|
@ -44,18 +103,18 @@ template vmap(x: RSeq; elem, f: untyped): VNode =
|
||||||
doTrackResize(x, tmp, f(x[pos]))
|
doTrackResize(x, tmp, f(x[pos]))
|
||||||
tmp
|
tmp
|
||||||
|
|
||||||
proc main(gu: RSeq[User]): VNode = #{.track.} =
|
proc main(gu: RSeq[User]): VNode =
|
||||||
proc inner(gu: RSeq[User]): VNode =
|
|
||||||
result = buildHtml(tdiv):
|
result = buildHtml(tdiv):
|
||||||
vmap(gu, tdiv, renderUser)
|
|
||||||
tdiv:
|
tdiv:
|
||||||
button:
|
button:
|
||||||
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(firstname: "Added", lastname: &clicks)
|
||||||
result = inner(gu)
|
tdiv:
|
||||||
doTrack(gu, result, inner(gu))
|
text errmsg
|
||||||
|
vmap(gu, tdiv, renderUser)
|
||||||
|
|
||||||
|
|
||||||
proc init(): VNode = main(gu)
|
proc init(): VNode = main(gu)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ type
|
||||||
Mark
|
Mark
|
||||||
Inserted
|
Inserted
|
||||||
Deleted
|
Deleted
|
||||||
|
Replaced
|
||||||
|
|
||||||
State = object
|
State = object
|
||||||
stale: int
|
stale: int
|
||||||
|
|
@ -70,7 +71,7 @@ template wrapObserver(f: untyped) =
|
||||||
of Mark:
|
of Mark:
|
||||||
if state.stale == 0: x.broadcast(msg, pos)
|
if state.stale == 0: x.broadcast(msg, pos)
|
||||||
inc state.stale
|
inc state.stale
|
||||||
of Inserted, Deleted:
|
of Inserted, Deleted, Replaced:
|
||||||
dec state.stale
|
dec state.stale
|
||||||
if state.stale == 0:
|
if state.stale == 0:
|
||||||
x.broadcast(msg, pos)
|
x.broadcast(msg, pos)
|
||||||
|
|
@ -92,12 +93,20 @@ proc notifyObservers*(x: ReactiveBase) =
|
||||||
x.broadcast(Mark)
|
x.broadcast(Mark)
|
||||||
x.broadcast(Changed)
|
x.broadcast(Changed)
|
||||||
|
|
||||||
proc subscribe[T](x: Reactive[T], f: proc(x: T)) =
|
proc subscribeVal*[T](x: Reactive[T], f: proc(x: T)) =
|
||||||
let reactor = proc (msg: Message, pos: int) =
|
let reactor = proc (msg: Message, pos: int) =
|
||||||
case msg:
|
case msg:
|
||||||
of Mark: discard
|
of Mark: discard
|
||||||
of Changed, Unchanged: f(x.value)
|
of Changed, Unchanged: f(x.value)
|
||||||
of Inserted, Deleted: discard
|
of Inserted, Deleted, Replaced: discard
|
||||||
|
x.addSink reactor
|
||||||
|
|
||||||
|
proc subscribeSelf*[T: ReactiveBase](x: T, f: proc()) =
|
||||||
|
let reactor = proc (msg: Message, pos: int) =
|
||||||
|
case msg:
|
||||||
|
of Mark: discard
|
||||||
|
of Changed, Unchanged: f()
|
||||||
|
of Inserted, Deleted, Replaced: discard
|
||||||
x.addSink reactor
|
x.addSink reactor
|
||||||
|
|
||||||
template lift1(op: untyped) =
|
template lift1(op: untyped) =
|
||||||
|
|
@ -127,6 +136,8 @@ proc newRSeq*[T](data: seq[T]): RSeq[T] =
|
||||||
|
|
||||||
proc `[]=`*[T](x: RSeq[T]; index: int; v: T) =
|
proc `[]=`*[T](x: RSeq[T]; index: int; v: T) =
|
||||||
x.s[index] = v
|
x.s[index] = v
|
||||||
|
x.broadcast(Mark)
|
||||||
|
x.broadcast(Replaced, index)
|
||||||
|
|
||||||
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 len*[T](x: RSeq[T]): int = x.s.len
|
||||||
|
|
|
||||||
11
src/vdom.nim
11
src/vdom.nim
|
|
@ -239,8 +239,15 @@ proc tree*(kind: VNodeKind; attrs: openarray[(cstring, cstring)];
|
||||||
result = tree(kind, kids)
|
result = tree(kind, kids)
|
||||||
for a in attrs: result.setAttr(a[0], a[1])
|
for a in attrs: result.setAttr(a[0], a[1])
|
||||||
|
|
||||||
proc text*(s: string): VNode = VNode(kind: VNodeKind.text, text: cstring(s), index: -1)
|
proc rawtext*(s: string): VNode = VNode(kind: VNodeKind.text, text: cstring(s), index: -1)
|
||||||
proc text*(s: cstring): VNode = VNode(kind: VNodeKind.text, text: s, index: -1)
|
proc rawtext*(s: cstring): VNode = VNode(kind: VNodeKind.text, text: s, index: -1)
|
||||||
|
|
||||||
|
import reactive
|
||||||
|
|
||||||
|
proc text*(s: RString): VNode =
|
||||||
|
result = VNode(kind: VNodeKind.text, text: s, index: -1)
|
||||||
|
s.subscribe proc(v: cstring) =
|
||||||
|
result.dom.value = v
|
||||||
|
|
||||||
iterator items*(n: VNode): VNode =
|
iterator items*(n: VNode): VNode =
|
||||||
for i in 0..<n.kids.len: yield n.kids[i]
|
for i in 0..<n.kids.len: yield n.kids[i]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue