Compare commits
21 commits
master
...
diffDomNew
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e88f9e4c96 | ||
|
|
ae448f947f | ||
|
|
1b56477e59 | ||
|
|
78a47158a1 | ||
|
|
e63a7dbb21 | ||
|
|
cd78f5085f | ||
|
|
4c582d7c06 | ||
|
|
d3e1d28c89 | ||
|
|
91679f8ae6 | ||
|
|
8bdaab3f82 | ||
|
|
ebccc4e9a1 | ||
|
|
ed70a0cbfc | ||
|
|
393c336f90 | ||
|
|
e434517dd1 | ||
|
|
2b9880a9a2 | ||
|
|
f5e9db55c3 | ||
|
|
a304322286 | ||
|
|
443b24de3e | ||
|
|
41df9b769f | ||
|
|
1ad978804c | ||
|
|
23fc331626 |
8 changed files with 424 additions and 87 deletions
286
src/karax.nim
286
src/karax.nim
|
|
@ -123,6 +123,9 @@ proc replaceById(id: cstring; newTree: Node) =
|
||||||
#newTree.id = id
|
#newTree.id = id
|
||||||
|
|
||||||
proc equalsShallow(a, b: VNode): bool =
|
proc equalsShallow(a, b: VNode): bool =
|
||||||
|
if a.key == -1 and b.key == -1:
|
||||||
|
return eq(a, b)
|
||||||
|
else:
|
||||||
if a.kind != b.kind: return false
|
if a.kind != b.kind: return false
|
||||||
if a.id != b.id: return false
|
if a.id != b.id: return false
|
||||||
if a.key != b.key: return false
|
if a.key != b.key: return false
|
||||||
|
|
@ -130,25 +133,11 @@ proc equalsShallow(a, b: VNode): bool =
|
||||||
if a.text != b.text: return false
|
if a.text != b.text: return false
|
||||||
elif a.kind == VNodeKind.vthunk or a.kind == VNodeKind.dthunk:
|
elif a.kind == VNodeKind.vthunk or a.kind == VNodeKind.dthunk:
|
||||||
if a.text != b.text: return false
|
if a.text != b.text: return false
|
||||||
if a.len != b.len: return false
|
|
||||||
for i in 0..<a.len:
|
|
||||||
if not equalsShallow(a[i], b[i]): return false
|
|
||||||
if not sameAttrs(a, b): return false
|
if not sameAttrs(a, b): return false
|
||||||
if a.class != b.class: return false
|
if a.class != b.class: return false
|
||||||
# XXX test event listeners here?
|
# XXX test event listeners here?
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc equalsTree(a, b: VNode): bool =
|
|
||||||
when false:
|
|
||||||
# hashing is too fragile now with component support:
|
|
||||||
if not a.validHash:
|
|
||||||
a.calcHash()
|
|
||||||
if not b.validHash:
|
|
||||||
b.calcHash()
|
|
||||||
return a.hash == b.hash
|
|
||||||
else:
|
|
||||||
result = eq(a, b)
|
|
||||||
|
|
||||||
proc updateDirtyElements(parent, current: Node, newNode: VNode) =
|
proc updateDirtyElements(parent, current: Node, newNode: VNode) =
|
||||||
if newNode.key >= 0 and isDirty(newNode.key):
|
if newNode.key >= 0 and isDirty(newNode.key):
|
||||||
unmarkDirty(newNode.key)
|
unmarkDirty(newNode.key)
|
||||||
|
|
@ -164,7 +153,77 @@ proc updateDirtyElements(parent, current: Node, newNode: VNode) =
|
||||||
# leave early if we know there cannot be anything left to do:
|
# leave early if we know there cannot be anything left to do:
|
||||||
#if dirtyCount <= 0: return
|
#if dirtyCount <= 0: return
|
||||||
|
|
||||||
proc updateElement(parent, current: Node, newNode, oldNode: VNode) =
|
proc printChildren(parent: Node): cstring =
|
||||||
|
discard
|
||||||
|
# if parent != nil and parent.hasChildNodes:
|
||||||
|
# var it = parent.firstChild
|
||||||
|
# result = ""
|
||||||
|
# while it != nil:
|
||||||
|
# if it.id == nil:
|
||||||
|
# result.add(" nil")
|
||||||
|
# else:
|
||||||
|
# result.add(" " & $it.id)
|
||||||
|
# it = it.nextSibling
|
||||||
|
|
||||||
|
proc printChildren(parent: VNode): cstring =
|
||||||
|
discard
|
||||||
|
# if parent != nil:
|
||||||
|
# result = ""
|
||||||
|
# for i in 0..parent.len-1:
|
||||||
|
# if parent[i] == nil or parent[i].id == nil:
|
||||||
|
# result.add(" nil")
|
||||||
|
# else:
|
||||||
|
# result.add(" " & $(parent[i].id))
|
||||||
|
|
||||||
|
proc print(s: cstring, ident: int) =
|
||||||
|
discard
|
||||||
|
# var result = ""
|
||||||
|
# for i in 0..ident:
|
||||||
|
# result.add " "
|
||||||
|
# result.add(s)
|
||||||
|
# kout cstring(result)
|
||||||
|
|
||||||
|
proc longestIncreasingSubsequence(a: seq[int]): seq[int] =
|
||||||
|
if len(a) == 0:
|
||||||
|
return @[]
|
||||||
|
|
||||||
|
result.add 0
|
||||||
|
var parent = newSeq[int](len(a))
|
||||||
|
for i in 0..<len(a):
|
||||||
|
var j = result[len(result) - 1]
|
||||||
|
if a[j] < a[i]:
|
||||||
|
parent[i] = j
|
||||||
|
result.add(i)
|
||||||
|
continue
|
||||||
|
|
||||||
|
var left = 0
|
||||||
|
var right = len(result) - 1
|
||||||
|
|
||||||
|
while left < right:
|
||||||
|
var mid = (left + right) div 2
|
||||||
|
if a[result[mid]] < a[i]:
|
||||||
|
left = mid + 1
|
||||||
|
else:
|
||||||
|
right = mid
|
||||||
|
|
||||||
|
if a[i] < a[result[left]]:
|
||||||
|
if left > 0:
|
||||||
|
parent[i] = result[left - 1]
|
||||||
|
result[left] = i
|
||||||
|
|
||||||
|
var pos = len(result)
|
||||||
|
var v = result[pos - 1]
|
||||||
|
while pos > 0:
|
||||||
|
result[pos] = v
|
||||||
|
v = parent[v]
|
||||||
|
dec pos
|
||||||
|
|
||||||
|
proc updateElement(parent, current: Node, newNode, oldNode: VNode, ident: int = 0) =
|
||||||
|
if newNode.key != -1:
|
||||||
|
kout cstring($newNode.key)
|
||||||
|
if oldNode.key != -1:
|
||||||
|
kout cstring($oldNode.key)
|
||||||
|
newNode.dom = oldNode.dom
|
||||||
if not equalsShallow(newNode, oldNode):
|
if not equalsShallow(newNode, oldNode):
|
||||||
detach(oldNode)
|
detach(oldNode)
|
||||||
let n = vnodeToDom(newNode)
|
let n = vnodeToDom(newNode)
|
||||||
|
|
@ -188,36 +247,177 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode) =
|
||||||
detach(oldNode[i])
|
detach(oldNode[i])
|
||||||
current.removeChild(current.lastChild)
|
current.removeChild(current.lastChild)
|
||||||
else:
|
else:
|
||||||
var commonPrefix = 0
|
#kout cstring("start")
|
||||||
while commonPrefix < minLength and
|
print("----------------", ident)
|
||||||
equalsTree(newNode[commonPrefix], oldNode[commonPrefix]):
|
print("----------------", ident)
|
||||||
inc commonPrefix
|
var before = printChildren(current)
|
||||||
|
|
||||||
var oldPos = oldLength - 1
|
# maximal common prefix
|
||||||
var newPos = newLength - 1
|
var left = 0
|
||||||
while oldPos >= commonPrefix and newPos >= commonPrefix and
|
while left < minLength and equalsShallow(newNode[left], oldNode[left]):
|
||||||
equalsTree(newNode[newPos], oldNode[oldPos]):
|
updateElement(current, oldNode[left].dom, newNode[left], oldNode[left], ident + 1)
|
||||||
dec oldPos
|
inc left
|
||||||
dec newPos
|
|
||||||
|
|
||||||
var pos = min(oldPos, newPos) + 1
|
# maximal common suffix
|
||||||
for i in commonPrefix..pos-1:
|
var rightOld = oldLength - 1
|
||||||
updateElement(current, current.childNodes[i], newNode[i], oldNode[i])
|
var rightNew = newLength - 1
|
||||||
|
while rightOld >= left and rightNew >= left and equalsShallow(newNode[rightNew], oldNode[rightOld]):
|
||||||
|
updateElement(current, oldNode[rightOld].dom, newNode[rightNew], oldNode[rightOld], ident + 1)
|
||||||
|
dec rightOld
|
||||||
|
dec rightNew
|
||||||
|
|
||||||
var nextChildPos = oldPos + 1
|
var leftOld = left
|
||||||
while pos <= newPos:
|
var leftNew = left
|
||||||
if nextChildPos == oldLength:
|
|
||||||
current.appendChild(vnodeToDom(newNode[pos]))
|
|
||||||
|
var flag = false
|
||||||
|
#if rightOld >= leftOld and rightNew >= leftNew and equalsShallow(oldNode[leftOld], newNode[rightNew]):
|
||||||
|
print("current", ident)
|
||||||
|
print(printChildren(current), ident)
|
||||||
|
print("oldNode", ident)
|
||||||
|
print(printChildren(oldNode), ident)
|
||||||
|
print("newNode", ident)
|
||||||
|
print(printChildren(newNode), ident)
|
||||||
|
flag = true
|
||||||
|
|
||||||
|
# cross comparing
|
||||||
|
while rightOld >= leftOld and rightNew >= leftNew and equalsShallow(oldNode[leftOld], newNode[rightNew]):
|
||||||
|
print($oldNode[leftOld].id & " " & $newNode[rightNew].id, ident)
|
||||||
|
print("pos: " & $leftOld & " " & $rightNew, ident)
|
||||||
|
|
||||||
|
var nextNode: Node = nil
|
||||||
|
if rightNew + 1 < newLength:
|
||||||
|
nextNode = newNode[rightNew + 1].dom
|
||||||
|
print("update", ident)
|
||||||
|
updateElement(current, oldNode[leftOld].dom, newNode[rightNew], oldNode[leftOld], ident + 1)
|
||||||
|
print("update", ident)
|
||||||
|
if nextNode == nil:
|
||||||
|
current.appendChild(oldNode[leftOld].dom)
|
||||||
|
print("append", ident)
|
||||||
else:
|
else:
|
||||||
current.insertBefore(vnodeToDom(newNode[pos]), current.childNodes[nextChildPos])
|
print("insertBefore", ident)
|
||||||
# added new Node, so old state of VDOM have one more Node
|
current.insertBefore(oldNode[leftOld].dom, nextNode)
|
||||||
inc oldLength
|
print($oldNode[leftOld], ident)
|
||||||
inc pos
|
inc leftOld
|
||||||
inc nextChildPos
|
dec rightNew
|
||||||
|
|
||||||
for i in pos..oldPos:
|
while rightOld >= leftOld and rightNew >= leftNew and equalsShallow(oldNode[rightOld], newNode[leftNew]):
|
||||||
|
var nextNode: Node = oldNode[leftOld].dom
|
||||||
|
updateElement(current, oldNode[rightOld].dom, newNode[leftNew], oldNode[rightOld], ident + 1)
|
||||||
|
current.insertBefore(oldNode[rightOld].dom, nextNode)
|
||||||
|
inc leftNew
|
||||||
|
dec rightOld
|
||||||
|
|
||||||
|
if flag:
|
||||||
|
print("after", ident)
|
||||||
|
print(printChildren(current), ident)
|
||||||
|
|
||||||
|
var isKeyed = true
|
||||||
|
for i in leftNew..rightNew:
|
||||||
|
if newNode[i].key == -1:
|
||||||
|
isKeyed = false
|
||||||
|
break
|
||||||
|
|
||||||
|
for i in leftOld..rightOld:
|
||||||
|
if oldNode[i].key == -1:
|
||||||
|
isKeyed = false
|
||||||
|
if not isKeyed:
|
||||||
|
break
|
||||||
|
|
||||||
|
if rightNew - leftNew + 1 + rightOld - leftOld + 1 == 0:
|
||||||
|
isKeyed = false
|
||||||
|
|
||||||
|
|
||||||
|
if isKeyed:
|
||||||
|
if rightNew > leftNew:
|
||||||
|
# remove redundant old nodes
|
||||||
|
for i in leftOld..rightOld:
|
||||||
|
current.removeChild(oldNode[i].dom)
|
||||||
detach(oldNode[i])
|
detach(oldNode[i])
|
||||||
current.removeChild(current.childNodes[pos])
|
else:
|
||||||
|
# permute elements using LIS
|
||||||
|
var positionByKey = newJDict[VKey, int]()
|
||||||
|
var positions = newSeq[int]()
|
||||||
|
for i in leftOld..rightOld:
|
||||||
|
positionByKey[oldNode[i].key] = i
|
||||||
|
for i in leftNew..rightNew:
|
||||||
|
if positionByKey.contains(newNode[i].key):
|
||||||
|
positions.add positionByKey[newNode[i].key]
|
||||||
|
|
||||||
|
#if len(positions) > 0:
|
||||||
|
# kout cstring("new segment len = " & $(rightNew - leftNew + 1))
|
||||||
|
# kout cstring("old segment len = " & $(rightOld - leftOld + 1))
|
||||||
|
# var t = ""
|
||||||
|
# for i in 0..<len(positions):
|
||||||
|
# t.add($positions[i] & " ")
|
||||||
|
# kout cstring(t)
|
||||||
|
|
||||||
|
var lis = longestIncreasingSubsequence(positions)
|
||||||
|
var lisPos = 0
|
||||||
|
var isNotRedundant = newSeq[bool](rightOld - leftOld + 1)
|
||||||
|
for i in leftNew..rightNew:
|
||||||
|
if lisPos < len(lis):
|
||||||
|
var index = lis[lisPos]
|
||||||
|
if oldNode[index].key == newNode[i].key:
|
||||||
|
isNotRedundant[index - leftOld] = true
|
||||||
|
updateElement(current, oldNode[index].dom, newNode[i], oldNode[index], ident + 1)
|
||||||
|
inc lisPos
|
||||||
|
else:
|
||||||
|
if positionByKey.contains(newNode[i].key):
|
||||||
|
var oldPos = positionByKey[newNode[i].key]
|
||||||
|
isNotRedundant[oldPos - leftOld] = true
|
||||||
|
current.insertBefore(oldNode[oldPos].dom, oldNode[index].dom)
|
||||||
|
else:
|
||||||
|
current.insertBefore(vnodeToDom(newNode[i]), oldNode[index].dom)
|
||||||
|
else:
|
||||||
|
if positionByKey.contains(newNode[i].key):
|
||||||
|
var oldPos = positionByKey[newNode[i].key]
|
||||||
|
isNotRedundant[oldPos - leftOld] = true
|
||||||
|
current.appendChild(oldNode[oldPos].dom)
|
||||||
|
else:
|
||||||
|
current.appendChild(vnodeToDom(newNode[i]))
|
||||||
|
|
||||||
|
# remove redundant old nodes
|
||||||
|
for i in leftOld..rightOld:
|
||||||
|
if not isNotRedundant[i]:
|
||||||
|
current.removeChild(oldNode[i].dom)
|
||||||
|
else:
|
||||||
|
# simply diff
|
||||||
|
print($leftOld & " " & $rightOld & " " & $leftNew & " " & $rightNew, ident)
|
||||||
|
while rightOld >= leftOld and rightNew >= leftNew:
|
||||||
|
updateElement(current, oldNode[leftOld].dom, newNode[leftNew], oldNode[leftOld], ident + 1)
|
||||||
|
inc leftNew
|
||||||
|
inc leftOld
|
||||||
|
|
||||||
|
print("TEMP", ident)
|
||||||
|
print(printChildren(current), ident)
|
||||||
|
print($leftOld & " " & $rightOld & " " & $leftNew & " " & $rightNew, ident)
|
||||||
|
print("other part start", ident)
|
||||||
|
var isPushBack = (rightNew + 1 == newLength)
|
||||||
|
var nextNode: Node = nil
|
||||||
|
if not isPushBack:
|
||||||
|
print($(rightNew + 1), ident)
|
||||||
|
nextNode = newNode[rightNew + 1].dom
|
||||||
|
while leftNew <= rightNew:
|
||||||
|
var node = vnodeToDom(newNode[leftNew])
|
||||||
|
if isPushBack:
|
||||||
|
current.appendChild(node)
|
||||||
|
else:
|
||||||
|
current.insertBefore(node, nextNode)
|
||||||
|
inc leftNew
|
||||||
|
print("other part finish", ident)
|
||||||
|
|
||||||
|
for i in leftOld..rightOld:
|
||||||
|
current.removeChild(oldNode[i].dom)
|
||||||
|
detach(oldNode[i])
|
||||||
|
|
||||||
|
print("----------------", ident)
|
||||||
|
print("before", ident)
|
||||||
|
print(before, ident)
|
||||||
|
print("finish", ident)
|
||||||
|
print(printChildren(current), ident)
|
||||||
|
print("----------------", ident)
|
||||||
|
print("----------------", ident)
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
var drawTimeout: Timeout
|
var drawTimeout: Timeout
|
||||||
|
|
@ -256,6 +456,8 @@ proc redraw*() =
|
||||||
else:
|
else:
|
||||||
dodraw()
|
dodraw()
|
||||||
|
|
||||||
|
proc redrawForce*() = dodraw()
|
||||||
|
|
||||||
proc init(ev: Event) =
|
proc init(ev: Event) =
|
||||||
reqFrame(dodraw)
|
reqFrame(dodraw)
|
||||||
|
|
||||||
|
|
@ -263,6 +465,12 @@ proc setRenderer*(renderer: proc (): VNode) =
|
||||||
dorender = renderer
|
dorender = renderer
|
||||||
window.onload = init
|
window.onload = init
|
||||||
|
|
||||||
|
proc setRendererOnly*(renderer: proc (): VNode) =
|
||||||
|
dorender = renderer
|
||||||
|
|
||||||
|
proc setOnloadOnly*() =
|
||||||
|
window.onload = init
|
||||||
|
|
||||||
proc addEventHandler*(n: VNode; k: EventKind; action: EventHandler) =
|
proc addEventHandler*(n: VNode; k: EventKind; action: EventHandler) =
|
||||||
## Implements the foundation of Karax's event management.
|
## Implements the foundation of Karax's event management.
|
||||||
## Karax DSL transforms ``tag(onEvent = handler)`` to
|
## Karax DSL transforms ``tag(onEvent = handler)`` to
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from strutils import startsWith, toLowerAscii
|
||||||
|
|
||||||
const
|
const
|
||||||
StmtContext = ["kout", "inc", "echo", "dec", "!"]
|
StmtContext = ["kout", "inc", "echo", "dec", "!"]
|
||||||
SpecialAttrs = ["id", "class", "value", "key"]
|
SpecialAttrs = ["id", "class", "value", "key", "track"]
|
||||||
|
|
||||||
proc getName(n: NimNode): string =
|
proc getName(n: NimNode): string =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
|
||||||
|
|
@ -102,10 +102,12 @@ type
|
||||||
kind*: VNodeKind
|
kind*: VNodeKind
|
||||||
key*: VKey
|
key*: VKey
|
||||||
id*, class*, text*: cstring
|
id*, class*, text*: cstring
|
||||||
|
track*: int
|
||||||
kids: seq[VNode]
|
kids: seq[VNode]
|
||||||
# even index: key, odd index: value; done this way for memory efficiency:
|
# even index: key, odd index: value; done this way for memory efficiency:
|
||||||
attrs: seq[cstring]
|
attrs: seq[cstring]
|
||||||
events*: seq[(EventKind, EventHandler)]
|
events*: seq[(EventKind, EventHandler)]
|
||||||
|
when false:
|
||||||
hash*: Hash
|
hash*: Hash
|
||||||
validHash*: bool
|
validHash*: bool
|
||||||
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
|
||||||
|
|
@ -146,6 +148,10 @@ proc eq*(a, b: VNode): bool =
|
||||||
|
|
||||||
proc setAttr*(n: VNode; key: cstring; val: cstring = "") =
|
proc setAttr*(n: VNode; key: cstring; val: cstring = "") =
|
||||||
if n.attrs.isNil:
|
if n.attrs.isNil:
|
||||||
|
when true:
|
||||||
|
let x = @[key, val]
|
||||||
|
shallowCopy n.attrs, x
|
||||||
|
else:
|
||||||
n.attrs = @[key, val]
|
n.attrs = @[key, val]
|
||||||
else:
|
else:
|
||||||
for i in countup(0, n.attrs.len-2, 2):
|
for i in countup(0, n.attrs.len-2, 2):
|
||||||
|
|
@ -161,6 +167,7 @@ proc getAttr*(n: VNode; key: cstring): cstring =
|
||||||
|
|
||||||
proc len*(x: VNode): int = x.kids.len
|
proc len*(x: VNode): int = x.kids.len
|
||||||
proc `[]`*(x: VNode; idx: int): VNode = x.kids[idx]
|
proc `[]`*(x: VNode; idx: int): VNode = x.kids[idx]
|
||||||
|
proc `[]=`*(x: VNode; idx: int; y: VNode) = x.kids[idx] = y
|
||||||
proc add*(parent, kid: VNode) = parent.kids.add kid
|
proc add*(parent, kid: VNode) = parent.kids.add kid
|
||||||
proc newVNode*(kind: VNodeKind): VNode = VNode(kind: kind, key: -1)
|
proc newVNode*(kind: VNodeKind): VNode = VNode(kind: kind, key: -1)
|
||||||
|
|
||||||
|
|
@ -216,6 +223,7 @@ proc toString*(n: VNode; result: var string; indent: int) =
|
||||||
for i in 1..indent: result.add ' '
|
for i in 1..indent: result.add ' '
|
||||||
result.add "\L</" & $n.kind & ">"
|
result.add "\L</" & $n.kind & ">"
|
||||||
|
|
||||||
|
when false:
|
||||||
proc calcHash*(n: VNode) =
|
proc calcHash*(n: VNode) =
|
||||||
if n.validHash: return
|
if n.validHash: return
|
||||||
n.validHash = true
|
n.validHash = true
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Diff dom tests</title>
|
<title>Diff dom tests</title>
|
||||||
<link rel="stylesheet" href="style.css">
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body id="body">
|
<body id="body">
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ proc test1() =
|
||||||
proc check2() =
|
proc check2() =
|
||||||
let result = checkOrder(@[8, 0, 1, 2, 3, 4, 7, 5])
|
let result = checkOrder(@[8, 0, 1, 2, 3, 4, 7, 5])
|
||||||
if result:
|
if result:
|
||||||
results.add cstring"test1 - OK"
|
results.add cstring"test2 - OK"
|
||||||
else:
|
else:
|
||||||
results.add cstring"test2 - FAIL"
|
results.add cstring"test2 - FAIL"
|
||||||
|
|
||||||
|
|
@ -83,16 +83,16 @@ proc test4() =
|
||||||
timeout = setTimeout(check4, 20)
|
timeout = setTimeout(check4, 20)
|
||||||
|
|
||||||
proc check5() =
|
proc check5() =
|
||||||
let result = checkOrder(@[0, 1, 3, 5, 4, 5])
|
let result = checkOrder(@[0, 1, 3, 5, 4, 8])
|
||||||
if result:
|
if result:
|
||||||
results.add cstring"test5 - OK"
|
results.add cstring"test5 - OK"
|
||||||
else:
|
else:
|
||||||
results.add cstring"test5 - FAIL"
|
results.add cstring"test5 - FAIL"
|
||||||
|
|
||||||
# result: 0 1 3 5 4 5
|
# result: 0 1 3 5 4 8
|
||||||
proc test5() =
|
proc test5() =
|
||||||
results.add cstring"test5 started"
|
results.add cstring"test5 started"
|
||||||
entries = @[cstring("0"), cstring("1"), cstring("3"), cstring("5"), cstring("4"), cstring("5") ]
|
entries = @[cstring("0"), cstring("1"), cstring("3"), cstring("5"), cstring("4"), cstring("8") ]
|
||||||
redraw()
|
redraw()
|
||||||
timeout = setTimeout(check5, 20)
|
timeout = setTimeout(check5, 20)
|
||||||
|
|
||||||
|
|
@ -127,14 +127,14 @@ proc test7() =
|
||||||
|
|
||||||
proc createEntry(id: int): VNode =
|
proc createEntry(id: int): VNode =
|
||||||
result = buildHtml():
|
result = buildHtml():
|
||||||
button(id="" & $id):
|
button(id="" & $id, key = id):
|
||||||
text $id
|
text $id
|
||||||
|
|
||||||
proc createDom(): VNode =
|
proc createDom(): VNode =
|
||||||
result = buildHtml(tdiv()):
|
result = buildHtml(tdiv()):
|
||||||
ul(id="ul"):
|
ul(id="ul"):
|
||||||
for e in entries:
|
for e in entries:
|
||||||
createEntry(parseInt(e))
|
createEntry(jstrutils.parseInt(e))
|
||||||
for r in results:
|
for r in results:
|
||||||
tdiv:
|
tdiv:
|
||||||
text r
|
text r
|
||||||
|
|
|
||||||
16
uibench/index.html
Normal file
16
uibench/index.html
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link href="https://localvoid.github.io/uibench-base/0.1.0/styles.css" rel="stylesheet" />
|
||||||
|
<title>UI Benchmark: React</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="ROOT"></div>
|
||||||
|
|
||||||
|
<script src="https://localvoid.github.io/uibench-base/0.1.0/uibench.js"></script>
|
||||||
|
<script src="nimcache/nim_uibench.js" type="text/javascript"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
105
uibench/nim_uibench.nim
Normal file
105
uibench/nim_uibench.nim
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
import dom, vdom, karax, karaxdsl, jdict, jstrutils, kajax
|
||||||
|
|
||||||
|
type
|
||||||
|
HomeState {.importc.} = ref object
|
||||||
|
TableItemState {.importc.} = ref object
|
||||||
|
id: int
|
||||||
|
active: bool
|
||||||
|
props: seq[cstring]
|
||||||
|
TableState {.importc.} = ref object
|
||||||
|
items: seq[TableItemState]
|
||||||
|
AnimBoxState {.importc.} = ref object
|
||||||
|
id: int
|
||||||
|
time: int
|
||||||
|
AnimState {.importc.} = ref object
|
||||||
|
items: seq[AnimBoxState]
|
||||||
|
TreeNodeState {.importc.} = ref object
|
||||||
|
id: int
|
||||||
|
container: bool
|
||||||
|
children: seq[TreeNodeState]
|
||||||
|
TreeState {.importc.} = ref object
|
||||||
|
root: TreeNodeState
|
||||||
|
AppState {.importc.} = ref object
|
||||||
|
location: cstring
|
||||||
|
home: HomeState
|
||||||
|
table: TableState
|
||||||
|
anim: AnimState
|
||||||
|
tree: TreeState
|
||||||
|
|
||||||
|
var appState: AppState
|
||||||
|
|
||||||
|
proc createTableCell(id: cstring): VNode =
|
||||||
|
proc tableCellClick(ev: karax.Event; n: VNode) =
|
||||||
|
kout "Clicked" & id
|
||||||
|
result = buildHtml(td(class="TableCell", onclick=tableCellClick)):
|
||||||
|
text id
|
||||||
|
|
||||||
|
proc createTableRow(item: TableItemState): VNode =
|
||||||
|
let className = if item.active: cstring"TableRow active" else: cstring"TableRow"
|
||||||
|
result = buildHtml(tr(class=className, `data-id` = &item.id)):
|
||||||
|
createTableCell("#" & &item.id)
|
||||||
|
for i in 0..<len(item.props):
|
||||||
|
createTableCell(item.props[i])
|
||||||
|
|
||||||
|
proc tableCreateVNode(data: TableState): VNode =
|
||||||
|
result = buildHtml(table(class="Table")):
|
||||||
|
tbody:
|
||||||
|
for child in data.items:
|
||||||
|
createTableRow(child)
|
||||||
|
|
||||||
|
proc createAnimBox(item: AnimBoxState): VNode =
|
||||||
|
let time = item.time
|
||||||
|
let t10 = time mod 10
|
||||||
|
let color = float(t10) / 10
|
||||||
|
let divStyles = cstring"border-radius: " & &t10 &
|
||||||
|
"px; background: rgba(0,0,0," & cstring($color) & ")"
|
||||||
|
result = flatHtml(tdiv(class="AnimBox", `data-id` = &item.id, style=divStyles))
|
||||||
|
|
||||||
|
proc animCreateVNode(data: AnimState): VNode =
|
||||||
|
result = buildHtml(tdiv(class="Anim")):
|
||||||
|
for child in data.items:
|
||||||
|
createAnimBox(child)
|
||||||
|
|
||||||
|
proc createTreeNode(data: TreeNodeState): VNode =
|
||||||
|
result = buildHtml(ul(class="TreeNode")):
|
||||||
|
for n in data.children:
|
||||||
|
if n.container:
|
||||||
|
createTreeNode(n)
|
||||||
|
else:
|
||||||
|
li(class="TreeLeaf"):
|
||||||
|
text &n.id
|
||||||
|
|
||||||
|
proc treeCreateVNode(data: TreeState): VNode =
|
||||||
|
result = buildHtml(tdiv(class="Tree")):
|
||||||
|
createTreeNode(data.root)
|
||||||
|
|
||||||
|
proc update(): VNode =
|
||||||
|
assert appState != nil
|
||||||
|
let location = appState.location
|
||||||
|
var children: VNode = nil
|
||||||
|
if location == cstring"table":
|
||||||
|
children = tableCreateVNode(appState.table)
|
||||||
|
elif location == cstring"anim":
|
||||||
|
children = animCreateVNode(appState.anim)
|
||||||
|
elif location == cstring"tree":
|
||||||
|
children = treeCreateVNode(appState.tree)
|
||||||
|
result = buildHtml():
|
||||||
|
tdiv(class="Main"):
|
||||||
|
children
|
||||||
|
|
||||||
|
proc a(state: AppState) =
|
||||||
|
appState = state
|
||||||
|
redrawForce()
|
||||||
|
|
||||||
|
proc myToJson[T](x: T): cstring {.importcpp: "JSON.stringify(#, null, ' ')".}
|
||||||
|
|
||||||
|
proc b(samples: RootRef) =
|
||||||
|
document.body.innerHTML = cstring"<pre>" & myToJson(samples) & cstring"</pre>"
|
||||||
|
|
||||||
|
proc init*(a: cstring, b: cstring) {.importc: "uibench.init", nodecl.}
|
||||||
|
proc run*(a: proc(state: AppState), b: proc(samples: RootRef)) {.importc: "uibench.run", nodecl.}
|
||||||
|
|
||||||
|
init(cstring"Nim-karax", cstring"0.6.1")
|
||||||
|
|
||||||
|
setRendererOnly update
|
||||||
|
run(a, b)
|
||||||
1
uibench/nim_uibench.nims
Normal file
1
uibench/nim_uibench.nims
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
--path: "../src"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue