sane markDirty() mechanism for components
This commit is contained in:
parent
c86916e37d
commit
d9648be60c
6 changed files with 41 additions and 27 deletions
15
experiments/carousel.html
Normal file
15
experiments/carousel.html
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Carousel app</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body id="body">
|
||||||
|
|
||||||
|
<div id="ROOT" />
|
||||||
|
|
||||||
|
<script type="text/javascript" src="nimcache/carousel.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -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
|
import vdom, vstyles, karax, karaxdsl, jdict, jstrutils, kdom
|
||||||
|
|
||||||
|
|
@ -7,7 +8,6 @@ type
|
||||||
cntdown, myid: int
|
cntdown, myid: int
|
||||||
timer: TimeOut
|
timer: TimeOut
|
||||||
list: seq[cstring]
|
list: seq[cstring]
|
||||||
change: bool
|
|
||||||
|
|
||||||
const ticksUntilChange = 5
|
const ticksUntilChange = 5
|
||||||
|
|
||||||
|
|
@ -24,11 +24,10 @@ proc render(x: VComponent): VNode =
|
||||||
self.cntdown = ticksUntilChange
|
self.cntdown = ticksUntilChange
|
||||||
else:
|
else:
|
||||||
self.timer = setTimeout(docount, 30)
|
self.timer = setTimeout(docount, 30)
|
||||||
self.change = true
|
markDirty(self)
|
||||||
redraw()
|
redraw()
|
||||||
|
|
||||||
proc onclick(ev: Event; n: VNode) =
|
proc onclick(ev: Event; n: VNode) =
|
||||||
self.change = false
|
|
||||||
if self.timer != nil:
|
if self.timer != nil:
|
||||||
clearTimeout(self.timer)
|
clearTimeout(self.timer)
|
||||||
self.timer = setTimeout(docount, 30)
|
self.timer = setTimeout(docount, 30)
|
||||||
|
|
@ -51,12 +50,8 @@ proc render(x: VComponent): VNode =
|
||||||
|
|
||||||
var gid: int
|
var gid: int
|
||||||
|
|
||||||
proc changed(c: VComponent): bool =
|
|
||||||
let x = Carousel(c)
|
|
||||||
result = x.change
|
|
||||||
|
|
||||||
proc carousel(): Carousel =
|
proc carousel(): Carousel =
|
||||||
result = newComponent(Carousel, render, changed)
|
result = newComponent(Carousel, render)
|
||||||
result.list = images
|
result.list = images
|
||||||
result.cntdown = ticksUntilChange
|
result.cntdown = ticksUntilChange
|
||||||
result.myid = gid
|
result.myid = gid
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Todo app</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body id="body">
|
|
||||||
|
|
||||||
<div id="ROOT" />
|
|
||||||
|
|
||||||
<script type="text/javascript" src="nimcache/example.js"></script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -225,6 +225,7 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode;
|
||||||
assert oldNode.kind == VNodeKind.component
|
assert oldNode.kind == VNodeKind.component
|
||||||
let x = VComponent(oldNode)
|
let x = VComponent(oldNode)
|
||||||
n = vnodeToDom(x.renderImpl(x), kxi)
|
n = vnodeToDom(x.renderImpl(x), kxi)
|
||||||
|
x.updatedImpl(x)
|
||||||
result = true
|
result = true
|
||||||
else:
|
else:
|
||||||
detach(oldNode)
|
detach(oldNode)
|
||||||
|
|
|
||||||
26
src/vdom.nim
26
src/vdom.nim
|
|
@ -119,11 +119,16 @@ type
|
||||||
dom*: Node ## the attached real DOM node. Can be 'nil' if the virtual node
|
dom*: Node ## the attached real DOM node. Can be 'nil' if the virtual node
|
||||||
## is not part of the virtual DOM anymore.
|
## 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
|
renderImpl*: proc(self: VComponent): VNode
|
||||||
changedImpl*: proc(self: VComponent): bool
|
changedImpl*: proc(self: VComponent): bool
|
||||||
|
updatedImpl*: proc(self: VComponent)
|
||||||
onAttachImpl*: proc(self: VComponent)
|
onAttachImpl*: proc(self: VComponent)
|
||||||
onDetachImpl*: 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): cstring = n.text
|
||||||
proc `value=`*(n: VNode; v: cstring) = n.text = v
|
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 =
|
proc dthunk*(name: cstring; args: varargs[VNode, vn]): VNode =
|
||||||
VNode(kind: VNodeKind.dthunk, text: name, key: -1, kids: @args)
|
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];
|
template newComponent*[T](t: typeDesc[T];
|
||||||
render: (proc(self: VComponent): VNode) not nil,
|
render: (proc(self: VComponent): VNode) not nil,
|
||||||
changed: (proc(self: VComponent): bool) not nil,
|
|
||||||
onAttach: proc(self: VComponent) = 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.
|
## Use this template to create new components.
|
||||||
T(kind: VNodeKind.component, key: -1,
|
T(kind: VNodeKind.component, key: -1,
|
||||||
text: cstring(astToStr(t)), renderImpl: render,
|
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 = "") =
|
proc setAttr*(n: VNode; key: cstring; val: cstring = "") =
|
||||||
if n.attrs.isNil:
|
if n.attrs.isNil:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue