diff --git a/src/karax.nim b/src/karax.nim index 3c41d7e..5edda89 100644 --- a/src/karax.nim +++ b/src/karax.nim @@ -132,7 +132,8 @@ proc vnodeToDom(n: VNode; kxi: KaraxInstance): Node = assert x.renderImpl != nil if x.expanded == nil: x.expanded = x.renderImpl(x) - x.updatedImpl(x) + # x.updatedImpl(x, nil) + assert x.expanded != nil result = vnodeToDom(x.expanded, kxi) attach n return result @@ -197,7 +198,7 @@ proc eq(a, b: VNode): EqResult = if a.text != b.text: return different let x = VComponent(b) assert x.changedImpl != nil - return if x.changedImpl(x): changed else: identical + return if x.changedImpl(x, VComponent(a)): changed else: identical if not sameAttrs(a, b): return different if a.class != b.class: return different if not eq(a.style, b.style): return similar @@ -282,6 +283,7 @@ 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 @@ -359,9 +361,11 @@ proc diff(newNode, oldNode: VNode; parent, current: Node; kxi: KaraxInstance): E of changed: assert oldNode.kind == VNodeKind.component let x = VComponent(oldNode) + x.updatedImpl(x, VComponent newNode) let oldExpanded = x.expanded x.expanded = x.renderImpl(x) - x.updatedImpl(x) + x.version = VComponent(newNode).version + #x.updatedImpl(x) if oldExpanded == nil: detach(oldNode) kxi.addPatch(pkReplace, parent, current, x.expanded) diff --git a/src/vdom.nim b/src/vdom.nim index b0f7293..bbb4eac 100644 --- a/src/vdom.nim +++ b/src/vdom.nim @@ -124,14 +124,13 @@ type VComponent* = ref object of VNode ## The abstract class for every karax component. renderImpl*: proc(self: VComponent): VNode - changedImpl*: proc(self: VComponent): bool - updatedImpl*: proc(self: VComponent) + changedImpl*: proc(self, newInstance: VComponent): bool + updatedImpl*: proc(self, newInstance: VComponent) onAttachImpl*: proc(self: VComponent) onDetachImpl*: proc(self: VComponent) 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. expanded*: VNode ## Do not touch. Used by karax. The VDOM the component ## expanded to. @@ -153,19 +152,19 @@ proc vthunk*(name: cstring; args: varargs[VNode, vn]): VNode = proc dthunk*(name: cstring; args: varargs[VNode, vn]): VNode = VNode(kind: VNodeKind.dthunk, text: name, key: -1, kids: @args) -proc defaultChangedImpl*(v: VComponent): bool = +proc defaultChangedImpl*(v, newInstance: VComponent): bool = ## The default implementation of 'changed'. - result = v.version != v.renderedVersion + result = v.version != newInstance.version -proc defaultUpdatedImpl*(v: VComponent) = - v.renderedVersion = v.version +proc defaultUpdatedImpl*(v, newInstance: VComponent) = + discard template newComponent*[T](t: typeDesc[T]; render: (proc(self: VComponent): VNode) not nil, onAttach: proc(self: VComponent) = nil, onDetach: proc(self: VComponent) = nil, - changed: (proc(self: VComponent): bool) = defaultChangedImpl, - updated: proc(self: VComponent) = defaultUpdatedImpl): T = + changed: (proc(self, newInstance: VComponent): bool) = defaultChangedImpl, + updated: proc(self, newInstance: VComponent) = defaultUpdatedImpl): T = ## Use this template to create new components. T(kind: VNodeKind.component, key: -1, text: cstring(astToStr(t)), renderImpl: render, diff --git a/tests/blur.nim b/tests/blur.nim index 844ab8b..3823f93 100644 --- a/tests/blur.nim +++ b/tests/blur.nim @@ -41,18 +41,33 @@ proc render(x: VComponent): VNode = proc onchanged(ev: Event; n: VNode) = if self.onchange != nil and self.value != n.value: 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 setValue(x: TextInput; value: cstring) = +# x.value = value +# markDirty(x) + +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) + +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"", onchange: proc(v: cstring) = nil): TextInput = - result = newComponent(TextInput, render) + result = newComponent(TextInput, render, changed=changed, updated=update) result.style = style result.value = value result.onchange = onchange @@ -76,32 +91,25 @@ proc renderComb(self: VComponent): VNode = 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) +when false: + proc changed(self: VComponent): bool = + let self = Combined(self) + result = self.a.changedImpl(self.a) or self.b.changedImpl(self.b) -proc newCombined*(style: VStyle = VStyle()): Combined = - result = newComponent(Combined, renderComb, changed=changed) - result.a = newTextInput(style, "AAA") - result.b = newTextInput(style, "BBB") + proc newCombined*(style: VStyle = VStyle()): Combined = + result = newComponent(Combined, renderComb, changed=changed) + result.a = newTextInput(style, "AAA") + result.b = newTextInput(style, "BBB") var persons: seq[cstring] = @[cstring"Karax", "Abathur", "Fenix"] selected = -1 errmsg = cstring"" - ti = newTextInput(VStyle(), "", proc (v: cstring) = - if v.len > 0: - if selected >= 0: persons[selected] = v - errmsg = "" - else: - errmsg = "name must not be empty" - ) proc renderPerson(text: cstring, index: int): VNode = proc select(ev: Event, n: VNode) = selected = index - ti.setValue(persons[selected]) result = buildHtml(): tdiv(onClick=select): @@ -113,7 +121,13 @@ proc createDom(): VNode = for index, text in persons.pairs: renderPerson(text, index) tdiv: - ti + newTextInput(VStyle(), if selected >= 0: persons[selected] else: "", proc (v: cstring) = + if v.len > 0: + if selected >= 0: persons[selected] = v + errmsg = "" + else: + errmsg = "name must not be empty" + ) tdiv: text errmsg