diff --git a/src/karax.nim b/src/karax.nim index 5edda89..3fb0fc4 100644 --- a/src/karax.nim +++ b/src/karax.nim @@ -283,7 +283,6 @@ proc diff(newNode, oldNode: VNode; parent, current: Node; kxi: KaraxInstance): E if newNode.events.len != 0 or oldNode.events.len != 0: mergeEvents(newNode, oldNode, kxi) if oldNode.kind == VNodeKind.input or oldNode.kind == VNodeKind.textarea: - echo "comparing ", oldNode.text != newNode.text if oldNode.text != newNode.text: oldNode.text = newNode.text oldNode.dom.value = newNode.text @@ -364,8 +363,8 @@ proc diff(newNode, oldNode: VNode; parent, current: Node; kxi: KaraxInstance): E x.updatedImpl(x, VComponent newNode) let oldExpanded = x.expanded x.expanded = x.renderImpl(x) - x.version = VComponent(newNode).version - #x.updatedImpl(x) + x.renderedVersion = x.version + #echo "expanding ", x.debugId if oldExpanded == nil: detach(oldNode) kxi.addPatch(pkReplace, parent, current, x.expanded) diff --git a/src/vdom.nim b/src/vdom.nim index bbb4eac..997b059 100644 --- a/src/vdom.nim +++ b/src/vdom.nim @@ -131,8 +131,11 @@ type version*: int ## Update this to trigger a redraw by karax. Usually you ## should call 'markDirty' instead which is an alias for ## 'inc version'. + renderedVersion*: int ## Do not touch. Used by karax. The last version of the + ## component we rendered. expanded*: VNode ## Do not touch. Used by karax. The VDOM the component ## expanded to. + debugId*: int proc value*(n: VNode): cstring = n.text proc `value=`*(n: VNode; v: cstring) = n.text = v @@ -154,11 +157,16 @@ proc dthunk*(name: cstring; args: varargs[VNode, vn]): VNode = proc defaultChangedImpl*(v, newInstance: VComponent): bool = ## The default implementation of 'changed'. - result = v.version != newInstance.version + result = v.version != v.renderedVersion proc defaultUpdatedImpl*(v, newInstance: VComponent) = discard +var gid = 0 +proc getDebugId(): int = + inc(gid) + gid + template newComponent*[T](t: typeDesc[T]; render: (proc(self: VComponent): VNode) not nil, onAttach: proc(self: VComponent) = nil, @@ -169,7 +177,8 @@ template newComponent*[T](t: typeDesc[T]; T(kind: VNodeKind.component, key: -1, text: cstring(astToStr(t)), renderImpl: render, changedImpl: changed, updatedImpl: updated, - onAttachImpl: onAttach, onDetachImpl: onDetach) + onAttachImpl: onAttach, onDetachImpl: onDetach, + debugId: getDebugId()) template markDirty*(c: VComponent) = ## mark the component as dirty so that it is re-rendered. diff --git a/tests/blur.nim b/tests/blur.nim index 3823f93..25c0b24 100644 --- a/tests/blur.nim +++ b/tests/blur.nim @@ -1,7 +1,7 @@ import vdom, kdom, vstyles, karax, karaxdsl, jdict, jstrutils type TextInput* = ref object of VComponent - value: cstring + value, guid: cstring isActive: bool onchange: proc (value: cstring) @@ -35,63 +35,60 @@ proc render(x: VComponent): VNode = proc flip(ev: Event; n: VNode) = self.isActive = not self.isActive - kout cstring"onflip", n.value + echo "flip! ", self.isActive, " id: ", self.debugId, " version ", self.version markDirty(self) proc onchanged(ev: Event; n: VNode) = - if self.onchange != nil and self.value != n.value: + if self.onchange != nil: self.onchange n.value - #self.value = n.value + self.value = n.value result = buildHtml(tdiv(style=style)): input(style=inputStyle, value=self.value, onblur=flip, onfocus=flip, onkeyup=onchanged) -#proc setValue(x: TextInput; value: cstring) = -# x.value = value -# markDirty(x) +proc changed(current, next: VComponent): bool = + let current = TextInput(current) + let next = TextInput(next) + if current.guid != next.guid: + result = true + else: + result = defaultChangedImpl(current, next) proc update(current, next: VComponent) = let current = TextInput(current) let next = TextInput(next) - if not current.isActive: - current.value = next.value - echo "updated! ", current.value - else: - echo "not updated! ", current.value - #markDirty(current) + current.value = next.value + current.guid = next.guid + next.isActive = current.isActive -proc changed(current, next: VComponent): bool = - let current = TextInput(current) - let next = TextInput(next) - result = next.value != current.value or true - -proc newTextInput*(style: VStyle = VStyle(); value: cstring = cstring"", +proc newTextInput*(style: VStyle = VStyle(); guid: cstring; value: cstring = cstring"", onchange: proc(v: cstring) = nil): TextInput = result = newComponent(TextInput, render, changed=changed, updated=update) result.style = style result.value = value result.onchange = onchange - -type - Combined = ref object of VComponent - a, b: TextInput - -proc renderComb(self: VComponent): VNode = - let self = Combined(self) - - proc bu(ev: Event; n: VNode) = - self.a.value = "" - self.b.value = "" - markDirty(self.a) - markDirty(self.b) - - result = buildHtml(tdiv(style=self.style)): - self.a - self.b - button(onclick=bu): - text "reset" + result.guid = guid when false: + type + Combined = ref object of VComponent + a, b: TextInput + + proc renderComb(self: VComponent): VNode = + let self = Combined(self) + + proc bu(ev: Event; n: VNode) = + self.a.value = "" + self.b.value = "" + markDirty(self.a) + markDirty(self.b) + + result = buildHtml(tdiv(style=self.style)): + self.a + self.b + button(onclick=bu): + text "reset" + proc changed(self: VComponent): bool = let self = Combined(self) result = self.a.changedImpl(self.a) or self.b.changedImpl(self.b) @@ -121,7 +118,7 @@ proc createDom(): VNode = for index, text in persons.pairs: renderPerson(text, index) tdiv: - newTextInput(VStyle(), if selected >= 0: persons[selected] else: "", proc (v: cstring) = + newTextInput(VStyle(), &selected, if selected >= 0: persons[selected] else: "", proc (v: cstring) = if v.len > 0: if selected >= 0: persons[selected] = v errmsg = ""