diff --git a/experiments/carousel.html b/experiments/carousel.html
new file mode 100644
index 0000000..979dd38
--- /dev/null
+++ b/experiments/carousel.html
@@ -0,0 +1,15 @@
+
+
+
+
+ Carousel app
+
+
+
+
+
+
+
+
+
+
diff --git a/experiments/example.nim b/experiments/carousel.nim
similarity index 89%
rename from experiments/example.nim
rename to experiments/carousel.nim
index fa1e739..a820be7 100644
--- a/experiments/example.nim
+++ b/experiments/carousel.nim
@@ -1,3 +1,4 @@
+## This demo shows how you can develop your own stateful components with Karax.
import vdom, vstyles, karax, karaxdsl, jdict, jstrutils, kdom
@@ -7,7 +8,6 @@ type
cntdown, myid: int
timer: TimeOut
list: seq[cstring]
- change: bool
const ticksUntilChange = 5
@@ -24,11 +24,10 @@ proc render(x: VComponent): VNode =
self.cntdown = ticksUntilChange
else:
self.timer = setTimeout(docount, 30)
- self.change = true
+ markDirty(self)
redraw()
proc onclick(ev: Event; n: VNode) =
- self.change = false
if self.timer != nil:
clearTimeout(self.timer)
self.timer = setTimeout(docount, 30)
@@ -51,12 +50,8 @@ proc render(x: VComponent): VNode =
var gid: int
-proc changed(c: VComponent): bool =
- let x = Carousel(c)
- result = x.change
-
proc carousel(): Carousel =
- result = newComponent(Carousel, render, changed)
+ result = newComponent(Carousel, render)
result.list = images
result.cntdown = ticksUntilChange
result.myid = gid
diff --git a/experiments/example.nims b/experiments/carousel.nims
similarity index 100%
rename from experiments/example.nims
rename to experiments/carousel.nims
diff --git a/experiments/example.html b/experiments/example.html
deleted file mode 100644
index 2303d95..0000000
--- a/experiments/example.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
- Todo app
-
-
-
-
-
-
-
-
-
-
diff --git a/src/karax.nim b/src/karax.nim
index 42be93f..57c5162 100644
--- a/src/karax.nim
+++ b/src/karax.nim
@@ -225,6 +225,7 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode;
assert oldNode.kind == VNodeKind.component
let x = VComponent(oldNode)
n = vnodeToDom(x.renderImpl(x), kxi)
+ x.updatedImpl(x)
result = true
else:
detach(oldNode)
diff --git a/src/vdom.nim b/src/vdom.nim
index 8c19ea2..4edcd4e 100644
--- a/src/vdom.nim
+++ b/src/vdom.nim
@@ -119,11 +119,16 @@ type
dom*: Node ## the attached real DOM node. Can be 'nil' if the virtual node
## is not part of the virtual DOM anymore.
- VComponent* = ref object of VNode
+ 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)
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.
proc value*(n: VNode): cstring = n.text
proc `value=`*(n: VNode; v: cstring) = n.text = v
@@ -143,15 +148,28 @@ 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 =
+ ## The default implementation of 'changed'.
+ result = v.version != v.renderedVersion
+
+proc defaultUpdatedImpl*(v: VComponent) =
+ v.renderedVersion = v.version
+
template newComponent*[T](t: typeDesc[T];
render: (proc(self: VComponent): VNode) not nil,
- changed: (proc(self: VComponent): bool) not nil,
onAttach: proc(self: VComponent) = nil,
- onDetach: proc(self: VComponent) = nil): T =
+ onDetach: proc(self: VComponent) = nil,
+ changed: (proc(self: VComponent): bool) = defaultChangedImpl,
+ updated: proc(self: VComponent) = defaultUpdatedImpl): T =
## Use this template to create new components.
T(kind: VNodeKind.component, key: -1,
text: cstring(astToStr(t)), renderImpl: render,
- changedImpl: changed, onAttachImpl: onAttach, onDetachImpl: onDetach)
+ changedImpl: changed, updatedImpl: updated,
+ onAttachImpl: onAttach, onDetachImpl: onDetach)
+
+template markDirty*(c: VComponent) =
+ ## mark the component as dirty so that it is re-rendered.
+ inc c.version
proc setAttr*(n: VNode; key: cstring; val: cstring = "") =
if n.attrs.isNil: