diff --git a/experiments/nextgen.nim b/experiments/nextgen.nim index 40acf04..0fa76bb 100644 --- a/experiments/nextgen.nim +++ b/experiments/nextgen.nim @@ -1,13 +1,12 @@ import vdom, kdom, vstyles, karax, karaxdsl, jdict, jstrutils, reactive -proc newTextInput*(text: RString; focus: RBool): VNode {.track.} = +proc textInput*(text: RString; focus: RBool): VNode {.track.} = 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! @@ -30,29 +29,49 @@ var gu = newRSeq(@[ (User(firstname: "Some", lastname: "Body")), (User(firstname: "Some", lastname: "Two"))]) var prevSelected: User = nil #newReactive[User](nil) -proc toUI*(): RString = +proc unselect() = + if prevSelected != nil: + prevSelected.selected = false + notifyObservers(prevSelected) + prevSelected = nil + +proc select(u: User) = + unselect() + u.selected = true + notifyObservers(u) + prevSelected = u + +proc toUI*(isFirstname: bool): RString = result = RString() result.subscribe proc (v: cstring) = if v.len > 0: let p = prevSelected #selected.value if p != nil: - # XXX what's happening here? - p.firstname = v + if isFirstName: + p.firstname = v + else: + p.lastname = v notifyObservers(p) + unselect() errmsg <- "" else: errmsg <- "name must not be empty" -var inp = toUI() +var firstname = toUI(true) +var lastname = toUI(false) proc adaptFocus(def = false): RBool = result = RBool() result.value = def - result.subscribe proc (hasFocus: bool) = - if not hasFocus: - inp.notifyObservers() + when false: + result.subscribe proc (hasFocus: bool) = + if not hasFocus: + unselect() + firstname.notifyObservers() + lastname.notifyObservers() -var focus = adaptFocus() +var focusA = adaptFocus() +var focusB = adaptFocus() proc styler(): VStyle = result = style( @@ -61,7 +80,7 @@ proc styler(): VStyle = (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.border, cstring"solid 8px " & (if focusA.value: cstring"red" else: cstring"black")), (StyleAttr.fontSize, cstring"12px"), (StyleAttr.fontWeight, cstring"600") ) @@ -88,22 +107,19 @@ template observe(s: cstring): RString = proc renderUser(u: User): VNode {.track.} = result = buildHtml(tdiv): - let displayName = u.firstname & " " & u.lastname if u.selected: - # == selected.value: - !(inp <- displayName) - newTextInput inp, focus + !(firstname <- u.firstname) + tdiv: + textInput firstname, focusA + !(lastname <- u.lastname) + tdiv: + textInput lastname, focusB 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 + select(u) + text u.firstname & " " & u.lastname button: text "(x)" proc onclick(ev: Event; n: VNode) = diff --git a/src/reactive.nim b/src/reactive.nim index 5d793c5..ded1779 100644 --- a/src/reactive.nim +++ b/src/reactive.nim @@ -52,8 +52,11 @@ proc addSink(x: ReactiveBase; sink: proc(msg: Message; pos: int)) = inc rid x.id = rid +var inhibited: int + proc broadcast(x: ReactiveBase, msg: Message; pos = 0) = - for s in x.sinks: s(msg, pos) + if inhibited == 0: + for s in x.sinks: s(msg, pos) var toTrack: proc (msg: Message; pos: int) = nil @@ -220,10 +223,12 @@ proc map*[T, U](x: RSeq[T], f: proc(x: T): U): RSeq[U] = import macros template protect(r: ReactiveBase; body: untyped) = - var tmp: seq[proc(msg: Message, pos: int)] - swap(r.sinks, tmp) + #var tmp: seq[proc(msg: Message, pos: int)] + #swap(r.sinks, tmp) + inc inhibited body - swap(r.sinks, tmp) + dec inhibited + #swap(r.sinks, tmp) template trackImpl(r: ReactiveBase; key: cstring; a, b: untyped) = when r is ReactiveBase: