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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
let x = VComponent(oldNode)
|
||||
n = vnodeToDom(x.renderImpl(x), kxi)
|
||||
x.updatedImpl(x)
|
||||
result = true
|
||||
else:
|
||||
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
|
||||
## 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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue