Merge branch 'master' of github.com:pragmagic/karax
This commit is contained in:
commit
05766db4b6
2 changed files with 124 additions and 109 deletions
175
karax/karax.nim
175
karax/karax.nim
|
|
@ -13,11 +13,11 @@ proc kout*[T](x: T) {.importc: "console.log", varargs, deprecated.}
|
||||||
|
|
||||||
type
|
type
|
||||||
PatchKind = enum
|
PatchKind = enum
|
||||||
pkReplace, pkRemove, pkAppend, pkInsertBefore, pkDetach
|
pkReplace, pkRemove, pkAppend, pkInsertBefore, pkDetach, pkSame
|
||||||
Patch = object
|
Patch = object
|
||||||
k: PatchKind
|
k: PatchKind
|
||||||
parent, current: Node
|
parent, current: Node
|
||||||
n: VNode
|
newNode, oldNode: VNode
|
||||||
PatchV = object
|
PatchV = object
|
||||||
parent, newChild: VNode
|
parent, newChild: VNode
|
||||||
pos: int
|
pos: int
|
||||||
|
|
@ -117,7 +117,7 @@ proc wrapEvent(d: Node; n: VNode; k: EventKind;
|
||||||
# --------------------- DOM diff -----------------------------------------
|
# --------------------- DOM diff -----------------------------------------
|
||||||
|
|
||||||
template detach(n: VNode) =
|
template detach(n: VNode) =
|
||||||
addPatch(kxi, pkDetach, nil, nil, n)
|
addPatch(kxi, pkDetach, nil, nil, nil, n)
|
||||||
|
|
||||||
template attach(n: VNode) =
|
template attach(n: VNode) =
|
||||||
n.dom = result
|
n.dom = result
|
||||||
|
|
@ -134,7 +134,9 @@ proc getVNodeById*(id: cstring; kxi: KaraxInstance = kxi): VNode =
|
||||||
if kxi.byId.contains(id):
|
if kxi.byId.contains(id):
|
||||||
result = kxi.byId[id]
|
result = kxi.byId[id]
|
||||||
|
|
||||||
proc vnodeToDom*(n: VNode; kxi: KaraxInstance = nil): Node =
|
proc toDom*(n: VNode; useAttachedNode: bool; kxi: KaraxInstance = nil): Node =
|
||||||
|
if useAttachedNode:
|
||||||
|
if n.dom != nil: return n.dom
|
||||||
if n.kind == VNodeKind.text:
|
if n.kind == VNodeKind.text:
|
||||||
result = document.createTextNode(n.text)
|
result = document.createTextNode(n.text)
|
||||||
attach n
|
attach n
|
||||||
|
|
@ -145,7 +147,7 @@ proc vnodeToDom*(n: VNode; kxi: KaraxInstance = nil): Node =
|
||||||
return result
|
return result
|
||||||
elif n.kind == VNodeKind.vthunk:
|
elif n.kind == VNodeKind.vthunk:
|
||||||
let x = callThunk(vcomponents[n.text], n)
|
let x = callThunk(vcomponents[n.text], n)
|
||||||
result = vnodeToDom(x, kxi)
|
result = toDom(x, useAttachedNode, kxi)
|
||||||
#n.key = result.key
|
#n.key = result.key
|
||||||
attach n
|
attach n
|
||||||
return result
|
return result
|
||||||
|
|
@ -163,14 +165,14 @@ proc vnodeToDom*(n: VNode; kxi: KaraxInstance = nil): Node =
|
||||||
x.expanded = x.renderImpl(x)
|
x.expanded = x.renderImpl(x)
|
||||||
# x.updatedImpl(x, nil)
|
# x.updatedImpl(x, nil)
|
||||||
assert x.expanded != nil
|
assert x.expanded != nil
|
||||||
result = vnodeToDom(x.expanded, kxi)
|
result = toDom(x.expanded, useAttachedNode, kxi)
|
||||||
attach n
|
attach n
|
||||||
return result
|
return result
|
||||||
else:
|
else:
|
||||||
result = document.createElement(toTag[n.kind])
|
result = document.createElement(toTag[n.kind])
|
||||||
attach n
|
attach n
|
||||||
for k in n:
|
for k in n:
|
||||||
appendChild(result, vnodeToDom(k, kxi))
|
appendChild(result, toDom(k, useAttachedNode, kxi))
|
||||||
# text is mapped to 'value':
|
# text is mapped to 'value':
|
||||||
if n.text != nil:
|
if n.text != nil:
|
||||||
result.value = n.text
|
result.value = n.text
|
||||||
|
|
@ -231,7 +233,7 @@ when defined(profileKarax):
|
||||||
for i in low(DifferEnum)..high(DifferEnum):
|
for i in low(DifferEnum)..high(DifferEnum):
|
||||||
echo i, " value: ", a[i]
|
echo i, " value: ", a[i]
|
||||||
|
|
||||||
proc eq(a, b: VNode): EqResult =
|
proc eq(a, b: VNode; recursive: bool): EqResult =
|
||||||
if a.kind != b.kind:
|
if a.kind != b.kind:
|
||||||
when defined(profileKarax): inc reasons[deKind]
|
when defined(profileKarax): inc reasons[deKind]
|
||||||
return different
|
return different
|
||||||
|
|
@ -250,7 +252,7 @@ proc eq(a, b: VNode): EqResult =
|
||||||
if a.text != b.text: return different
|
if a.text != b.text: return different
|
||||||
if a.len != b.len: return different
|
if a.len != b.len: return different
|
||||||
for i in 0..<a.len:
|
for i in 0..<a.len:
|
||||||
if eq(a[i], b[i]) == different: return different
|
if eq(a[i], b[i], recursive) == different: return different
|
||||||
elif a.kind == VNodeKind.dthunk:
|
elif a.kind == VNodeKind.dthunk:
|
||||||
return identical
|
return identical
|
||||||
elif a.kind == VNodeKind.verbatim:
|
elif a.kind == VNodeKind.verbatim:
|
||||||
|
|
@ -274,6 +276,14 @@ proc eq(a, b: VNode): EqResult =
|
||||||
if a.class != b.class or not eq(a.style, b.style) or not sameAttrs(a, b):
|
if a.class != b.class or not eq(a.style, b.style) or not sameAttrs(a, b):
|
||||||
when defined(profileKarax): inc reasons[deSimilar]
|
when defined(profileKarax): inc reasons[deSimilar]
|
||||||
return similar
|
return similar
|
||||||
|
|
||||||
|
if recursive:
|
||||||
|
if a.len != b.len:
|
||||||
|
return different
|
||||||
|
for i in 0..<a.len:
|
||||||
|
if eq(a[i], b[i], true) != identical:
|
||||||
|
return different
|
||||||
|
|
||||||
# Do not test event listeners here!
|
# Do not test event listeners here!
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
@ -298,6 +308,7 @@ proc updateAttributes(newNode, oldNode: VNode) =
|
||||||
|
|
||||||
proc mergeEvents(newNode, oldNode: VNode; kxi: KaraxInstance) =
|
proc mergeEvents(newNode, oldNode: VNode; kxi: KaraxInstance) =
|
||||||
let d = oldNode.dom
|
let d = oldNode.dom
|
||||||
|
if d != nil:
|
||||||
for i in 0..<oldNode.events.len:
|
for i in 0..<oldNode.events.len:
|
||||||
let k = oldNode.events[i][0]
|
let k = oldNode.events[i][0]
|
||||||
let name = case k
|
let name = case k
|
||||||
|
|
@ -321,16 +332,18 @@ when false:
|
||||||
printV(n[i], depth & " ")
|
printV(n[i], depth & " ")
|
||||||
|
|
||||||
proc addPatch(kxi: KaraxInstance; ka: PatchKind; parenta, currenta: Node;
|
proc addPatch(kxi: KaraxInstance; ka: PatchKind; parenta, currenta: Node;
|
||||||
na: VNode) =
|
na, oldNode: VNode) =
|
||||||
let L = kxi.patchLen
|
let L = kxi.patchLen
|
||||||
if L >= kxi.patches.len:
|
if L >= kxi.patches.len:
|
||||||
# allocate more space:
|
# allocate more space:
|
||||||
kxi.patches.add(Patch(k: ka, parent: parenta, current: currenta, n: na))
|
kxi.patches.add(Patch(k: ka, parent: parenta, current: currenta,
|
||||||
|
newNode: na, oldNode: oldNode))
|
||||||
else:
|
else:
|
||||||
kxi.patches[L].k = ka
|
kxi.patches[L].k = ka
|
||||||
kxi.patches[L].parent = parenta
|
kxi.patches[L].parent = parenta
|
||||||
kxi.patches[L].current = currenta
|
kxi.patches[L].current = currenta
|
||||||
kxi.patches[L].n = na
|
kxi.patches[L].newNode = na
|
||||||
|
kxi.patches[L].oldNode = oldNode
|
||||||
inc kxi.patchLen
|
inc kxi.patchLen
|
||||||
|
|
||||||
proc addPatchV(kxi: KaraxInstance; parent: VNode; pos: int; newChild: VNode) =
|
proc addPatchV(kxi: KaraxInstance; parent: VNode; pos: int; newChild: VNode) =
|
||||||
|
|
@ -344,26 +357,35 @@ proc addPatchV(kxi: KaraxInstance; parent: VNode; pos: int; newChild: VNode) =
|
||||||
kxi.patchesV[L].pos = pos
|
kxi.patchesV[L].pos = pos
|
||||||
inc kxi.patchLenV
|
inc kxi.patchLenV
|
||||||
|
|
||||||
|
proc moveDom(dest, src: VNode) =
|
||||||
|
dest.dom = src.dom
|
||||||
|
src.dom = nil
|
||||||
|
assert dest.len == src.len
|
||||||
|
for i in 0..<dest.len:
|
||||||
|
moveDom(dest[i], src[i])
|
||||||
|
|
||||||
proc applyPatch(kxi: KaraxInstance) =
|
proc applyPatch(kxi: KaraxInstance) =
|
||||||
for i in 0..<kxi.patchLen:
|
for i in 0..<kxi.patchLen:
|
||||||
let p = kxi.patches[i]
|
let p = kxi.patches[i]
|
||||||
case p.k
|
case p.k
|
||||||
of pkReplace:
|
of pkReplace:
|
||||||
let nn = vnodeToDom(p.n, kxi)
|
let nn = toDom(p.newNode, useAttachedNode = true, kxi)
|
||||||
if p.parent == nil:
|
if p.parent == nil:
|
||||||
replaceById(kxi.rootId, nn)
|
replaceById(kxi.rootId, nn)
|
||||||
else:
|
else:
|
||||||
p.parent.replaceChild(nn, p.current)
|
p.parent.replaceChild(nn, p.current)
|
||||||
|
of pkSame:
|
||||||
|
moveDom(p.newNode, p.oldNode)
|
||||||
of pkRemove:
|
of pkRemove:
|
||||||
p.parent.removeChild(p.current)
|
p.parent.removeChild(p.current)
|
||||||
of pkAppend:
|
of pkAppend:
|
||||||
let nn = vnodeToDom(p.n, kxi)
|
let nn = toDom(p.newNode, useAttachedNode = true, kxi)
|
||||||
p.parent.appendChild(nn)
|
p.parent.appendChild(nn)
|
||||||
of pkInsertBefore:
|
of pkInsertBefore:
|
||||||
let nn = vnodeToDom(p.n, kxi)
|
let nn = toDom(p.newNode, useAttachedNode = true, kxi)
|
||||||
p.parent.insertBefore(nn, p.current)
|
p.parent.insertBefore(nn, p.current)
|
||||||
of pkDetach:
|
of pkDetach:
|
||||||
let n = p.n
|
let n = p.oldNode
|
||||||
if n.id != nil: kxi.byId.del(n.id)
|
if n.id != nil: kxi.byId.del(n.id)
|
||||||
if n.kind == VNodeKind.component:
|
if n.kind == VNodeKind.component:
|
||||||
let x = VComponent(n)
|
let x = VComponent(n)
|
||||||
|
|
@ -377,16 +399,38 @@ proc applyPatch(kxi: KaraxInstance) =
|
||||||
assert p.newChild.dom != nil
|
assert p.newChild.dom != nil
|
||||||
kxi.patchLenV = 0
|
kxi.patchLenV = 0
|
||||||
|
|
||||||
proc diff(newNode, oldNode: VNode; parent, current: Node; kxi: KaraxInstance): EqResult =
|
# ASSUME: We patch both the virtual DOM and the real DOM and throw away
|
||||||
|
# the newly produced DOM. Thus on updates like 'newNode.dom = oldNode.dom'
|
||||||
|
# are required. The only exception is when the top level node is replaced.
|
||||||
|
# Then we have to take the new virtual DOM. In fact, we trigger a full DOM
|
||||||
|
# rebuild then. However, we don't have to consider old event handlers then
|
||||||
|
# so everything stays simple.
|
||||||
|
# We also do not produce "Patch sets" anymore, everything is done as simply
|
||||||
|
# as possible. Ok, let's assume that we seek to update event handler lists:
|
||||||
|
# The new node has captures to itself or to other new nodes, never to old
|
||||||
|
# nodes! --> We cannot ever use the old VDOM, we have to use the new virtual
|
||||||
|
# DOM. For identical nodes we need to take over the .dom field from the old
|
||||||
|
# node since we don't recompute them. This must be done recursively. In
|
||||||
|
# vnodeToDom we have to check whether the 'dom' field was already set. If so,
|
||||||
|
# There is nothing to do.
|
||||||
|
# "Similar" nodes can have the opposite effect; consider
|
||||||
|
#
|
||||||
|
# AAAABAAAA
|
||||||
|
# AAAACDAAAA
|
||||||
|
#
|
||||||
|
# In this example B did change to C and 'D' is new. However, replacing B by
|
||||||
|
# CD is fine.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
proc diff(newNode, oldNode: VNode; parent, current: Node; kxi: KaraxInstance) =
|
||||||
when defined(stats):
|
when defined(stats):
|
||||||
if kxi.recursion > 100:
|
if kxi.recursion > 100:
|
||||||
echo "newNode ", newNode.kind, " oldNode ", oldNode.kind, " eq ", eq(newNode, oldNode)
|
echo "newNode ", newNode.kind, " oldNode ", oldNode.kind, " eq ", eq(newNode, oldNode, false)
|
||||||
if oldNode.kind == VNodeKind.text:
|
if oldNode.kind == VNodeKind.text:
|
||||||
echo oldNode.text
|
echo oldNode.text
|
||||||
#return
|
|
||||||
#doAssert false, "overflow!"
|
|
||||||
inc kxi.recursion
|
inc kxi.recursion
|
||||||
result = eq(newNode, oldNode)
|
let result = eq(newNode, oldNode, false)
|
||||||
case result
|
case result
|
||||||
of componentsIdentical:
|
of componentsIdentical:
|
||||||
kxi.components.add ComponentPair(oldNode: VComponent(oldNode),
|
kxi.components.add ComponentPair(oldNode: VComponent(oldNode),
|
||||||
|
|
@ -402,92 +446,56 @@ proc diff(newNode, oldNode: VNode; parent, current: Node; kxi: KaraxInstance): E
|
||||||
oldNode.text = newNode.text
|
oldNode.text = newNode.text
|
||||||
oldNode.dom.nodeValue = newNode.text
|
oldNode.dom.nodeValue = newNode.text
|
||||||
|
|
||||||
if newNode.events.len != 0 or oldNode.events.len != 0:
|
#if newNode.events.len != 0 or oldNode.events.len != 0:
|
||||||
mergeEvents(newNode, oldNode, kxi)
|
# mergeEvents(newNode, oldNode, kxi)
|
||||||
when false:
|
|
||||||
if oldNode.kind == VNodeKind.input or oldNode.kind == VNodeKind.textarea:
|
|
||||||
if oldNode.text != newNode.text:
|
|
||||||
oldNode.text = newNode.text
|
|
||||||
oldNode.dom.value = newNode.text
|
|
||||||
|
|
||||||
let newLength = newNode.len
|
let newLength = newNode.len
|
||||||
let oldLength = oldNode.len
|
let oldLength = oldNode.len
|
||||||
if newLength == 0 and oldLength == 0: return result
|
if newLength == 0 and oldLength == 0: return
|
||||||
let minLength = min(newLength, oldLength)
|
let minLength = min(newLength, oldLength)
|
||||||
|
|
||||||
assert oldNode.kind == newNode.kind
|
assert oldNode.kind == newNode.kind
|
||||||
var commonPrefix = 0
|
var commonPrefix = 0
|
||||||
let isSpecial = oldNode.kind == VNodeKind.component or
|
|
||||||
oldNode.kind == VNodeKind.vthunk or
|
|
||||||
oldNode.kind == VNodeKind.dthunk
|
|
||||||
|
|
||||||
template eqAndUpdate(a: VNode; i: int; b: VNode; j: int; info, action: untyped) =
|
|
||||||
let oldLen = kxi.patchLen
|
|
||||||
let oldLenV = kxi.patchLenV
|
|
||||||
assert i < a.len
|
|
||||||
assert j < b.len
|
|
||||||
let r = if isSpecial:
|
|
||||||
diff(a[i], b[j], parent, current, kxi)
|
|
||||||
else:
|
|
||||||
diff(a[i], b[j], current, current.childNodes[j], kxi)
|
|
||||||
case r
|
|
||||||
of identical, componentsIdentical, similar:
|
|
||||||
a[i] = b[j]
|
|
||||||
action
|
|
||||||
of usenewNode:
|
|
||||||
kxi.addPatchV(b, j, a[i])
|
|
||||||
action
|
|
||||||
# unfortunately, we need to propagate the changes upwards:
|
|
||||||
result = useNewNode
|
|
||||||
of different:
|
|
||||||
# undo what 'diff' would have done:
|
|
||||||
kxi.patchLen = oldLen
|
|
||||||
kxi.patchLenV = oldLenV
|
|
||||||
if result != different: result = r
|
|
||||||
break
|
|
||||||
# compute common prefix:
|
# compute common prefix:
|
||||||
while commonPrefix < minLength:
|
while commonPrefix < minLength:
|
||||||
eqAndUpdate(newNode, commonPrefix, oldNode, commonPrefix, cstring"prefix"):
|
if eq(newNode[commonPrefix], oldNode[commonPrefix], true) == identical:
|
||||||
|
kxi.addPatch(pkSame, nil, nil, newNode[commonPrefix], oldNode[commonPrefix])
|
||||||
inc commonPrefix
|
inc commonPrefix
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
# compute common suffix:
|
# compute common suffix:
|
||||||
var oldPos = oldLength - 1
|
var oldPos = oldLength - 1
|
||||||
var newPos = newLength - 1
|
var newPos = newLength - 1
|
||||||
while oldPos >= commonPrefix and newPos >= commonPrefix:
|
while oldPos >= commonPrefix and newPos >= commonPrefix:
|
||||||
eqAndUpdate(newNode, newPos, oldNode, oldPos, cstring"suffix"):
|
if eq(newNode[newPos], oldNode[oldPos], true) == identical:
|
||||||
|
kxi.addPatch(pkSame, nil, nil, newNode[newPos], oldNode[oldPos])
|
||||||
dec oldPos
|
dec oldPos
|
||||||
dec newPos
|
dec newPos
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
let pos = min(oldPos, newPos) + 1
|
let pos = min(oldPos, newPos) + 1
|
||||||
# now the different children are in commonPrefix .. pos - 1:
|
# now the different children are in commonPrefix .. pos - 1:
|
||||||
for i in commonPrefix..pos-1:
|
for i in commonPrefix..pos-1:
|
||||||
let r = diff(newNode[i], oldNode[i], current, current.childNodes[i], kxi)
|
diff(newNode[i], oldNode[i], current, current.childNodes[i], kxi)
|
||||||
if r == usenewNode:
|
|
||||||
#oldNode[i] = newNode[i]
|
|
||||||
kxi.addPatchV(oldNode, i, newNode[i])
|
|
||||||
elif r != different:
|
|
||||||
newNode[i] = oldNode[i]
|
|
||||||
#else:
|
|
||||||
# result = usenewNode
|
|
||||||
|
|
||||||
if oldPos + 1 == oldLength:
|
if oldPos + 1 == oldLength:
|
||||||
for i in pos..newPos:
|
for i in pos..newPos:
|
||||||
kxi.addPatch(pkAppend, current, nil, newNode[i])
|
kxi.addPatch(pkAppend, current, nil, newNode[i], nil)
|
||||||
result = usenewNode
|
|
||||||
else:
|
else:
|
||||||
let before = current.childNodes[oldPos + 1]
|
let before = current.childNodes[oldPos + 1]
|
||||||
for i in pos..newPos:
|
for i in pos..newPos:
|
||||||
kxi.addPatch(pkInsertBefore, current, before, newNode[i])
|
kxi.addPatch(pkInsertBefore, current, before, newNode[i], nil)
|
||||||
result = usenewNode
|
|
||||||
# XXX call 'attach' here?
|
# XXX call 'attach' here?
|
||||||
for i in pos..oldPos:
|
for i in pos..oldPos:
|
||||||
detach(oldNode[i])
|
detach(oldNode[i])
|
||||||
#doAssert i < current.childNodes.len
|
#doAssert i < current.childNodes.len
|
||||||
kxi.addPatch(pkRemove, current, current.childNodes[i], nil)
|
kxi.addPatch(pkRemove, current, current.childNodes[i], nil, nil)
|
||||||
result = usenewNode
|
|
||||||
of different:
|
of different:
|
||||||
detach(oldNode)
|
detach(oldNode)
|
||||||
kxi.addPatch(pkReplace, parent, current, newNode)
|
kxi.addPatch(pkReplace, parent, current, newNode, nil)
|
||||||
of usenewNode: doAssert(false, "eq returned usenewNode")
|
of usenewNode: doAssert(false, "eq returned usenewNode")
|
||||||
when defined(stats):
|
when defined(stats):
|
||||||
dec kxi.recursion
|
dec kxi.recursion
|
||||||
|
|
@ -517,11 +525,12 @@ proc applyComponents(kxi: KaraxInstance) =
|
||||||
x.renderedVersion = x.version
|
x.renderedVersion = x.version
|
||||||
if oldExpanded == nil:
|
if oldExpanded == nil:
|
||||||
detach(x)
|
detach(x)
|
||||||
kxi.addPatch(pkReplace, parent, current, x.expanded)
|
kxi.addPatch(pkReplace, parent, current, x.expanded, nil)
|
||||||
when defined(karaxDebug):
|
when defined(karaxDebug):
|
||||||
echo "Component ", newNode.text, ": old expansion didn't exist"
|
echo "Component ", newNode.text, ": old expansion didn't exist"
|
||||||
else:
|
else:
|
||||||
let res = diff(x.expanded, oldExpanded, parent, current, kxi)
|
diff(x.expanded, oldExpanded, parent, current, kxi)
|
||||||
|
when false:
|
||||||
if res == usenewNode:
|
if res == usenewNode:
|
||||||
when defined(karaxDebug):
|
when defined(karaxDebug):
|
||||||
echo "Component ", newNode.text, ": re-render triggered a DOM change (case A)"
|
echo "Component ", newNode.text, ": re-render triggered a DOM change (case A)"
|
||||||
|
|
@ -549,7 +558,7 @@ when defined(stats):
|
||||||
proc runDel*(kxi: KaraxInstance; parent: VNode; position: int) =
|
proc runDel*(kxi: KaraxInstance; parent: VNode; position: int) =
|
||||||
detach(parent[position])
|
detach(parent[position])
|
||||||
let current = parent.dom
|
let current = parent.dom
|
||||||
kxi.addPatch(pkRemove, current, current.childNodes[position], nil)
|
kxi.addPatch(pkRemove, current, current.childNodes[position], nil, nil)
|
||||||
parent.delete(position)
|
parent.delete(position)
|
||||||
applyPatch(kxi)
|
applyPatch(kxi)
|
||||||
doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
||||||
|
|
@ -557,11 +566,11 @@ proc runDel*(kxi: KaraxInstance; parent: VNode; position: int) =
|
||||||
proc runIns*(kxi: KaraxInstance; parent, kid: VNode; position: int) =
|
proc runIns*(kxi: KaraxInstance; parent, kid: VNode; position: int) =
|
||||||
let current = parent.dom
|
let current = parent.dom
|
||||||
if position >= parent.len:
|
if position >= parent.len:
|
||||||
kxi.addPatch(pkAppend, current, nil, kid)
|
kxi.addPatch(pkAppend, current, nil, kid, nil)
|
||||||
parent.add(kid)
|
parent.add(kid)
|
||||||
else:
|
else:
|
||||||
let before = current.childNodes[position]
|
let before = current.childNodes[position]
|
||||||
kxi.addPatch(pkInsertBefore, current, before, kid)
|
kxi.addPatch(pkInsertBefore, current, before, kid, nil)
|
||||||
parent.insert(kid, position)
|
parent.insert(kid, position)
|
||||||
applyPatch(kxi)
|
applyPatch(kxi)
|
||||||
doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
||||||
|
|
@ -569,7 +578,7 @@ proc runIns*(kxi: KaraxInstance; parent, kid: VNode; position: int) =
|
||||||
proc runDiff*(kxi: KaraxInstance; oldNode, newNode: VNode) =
|
proc runDiff*(kxi: KaraxInstance; oldNode, newNode: VNode) =
|
||||||
let olddom = oldNode.dom
|
let olddom = oldNode.dom
|
||||||
doAssert olddom != nil
|
doAssert olddom != nil
|
||||||
discard diff(newNode, oldNode, nil, olddom, kxi)
|
diff(newNode, oldNode, nil, olddom, kxi)
|
||||||
# this is a bit nasty: Since we cannot patch the 'parent' of
|
# this is a bit nasty: Since we cannot patch the 'parent' of
|
||||||
# the current VNode (because we don't store it at all!), we
|
# the current VNode (because we don't store it at all!), we
|
||||||
# need to override the fields individually:
|
# need to override the fields individually:
|
||||||
|
|
@ -591,13 +600,12 @@ proc dodraw(kxi: KaraxInstance) =
|
||||||
newtree.id = kxi.rootId
|
newtree.id = kxi.rootId
|
||||||
kxi.toFocus = nil
|
kxi.toFocus = nil
|
||||||
if kxi.currentTree == nil:
|
if kxi.currentTree == nil:
|
||||||
let asdom = vnodeToDom(newtree, kxi)
|
let asdom = toDom(newtree, useAttachedNode = true, kxi)
|
||||||
replaceById(kxi.rootId, asdom)
|
replaceById(kxi.rootId, asdom)
|
||||||
else:
|
else:
|
||||||
doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
||||||
let olddom = document.getElementById(kxi.rootId)
|
let olddom = document.getElementById(kxi.rootId)
|
||||||
discard diff(newtree, kxi.currentTree, nil, olddom, kxi)
|
diff(newtree, kxi.currentTree, nil, olddom, kxi)
|
||||||
#kout cstring"patch len ", patches.len
|
|
||||||
when defined(profileKarax):
|
when defined(profileKarax):
|
||||||
echo "<<<<<<<<<<<<<<"
|
echo "<<<<<<<<<<<<<<"
|
||||||
echa reasons
|
echa reasons
|
||||||
|
|
@ -768,3 +776,6 @@ proc toChecked*(checked: bool): cstring =
|
||||||
|
|
||||||
proc toDisabled*(disabled: bool): cstring =
|
proc toDisabled*(disabled: bool): cstring =
|
||||||
(if disabled: cstring"disabled" else: cstring(nil))
|
(if disabled: cstring"disabled" else: cstring(nil))
|
||||||
|
|
||||||
|
proc vnodeToDom*(n: VNode; kxi: KaraxInstance = nil): Node =
|
||||||
|
result = toDom(n, useAttachedNode = false, kxi)
|
||||||
|
|
|
||||||
|
|
@ -22,15 +22,19 @@ proc shortRepr(n: VNode): string =
|
||||||
var err = 0
|
var err = 0
|
||||||
|
|
||||||
proc doDiff(a, b: VNode; expected: varargs[string]) =
|
proc doDiff(a, b: VNode; expected: varargs[string]) =
|
||||||
discard diff(b, a, nil, vnodeToDom(a, kxi), kxi)
|
diff(b, a, nil, vnodeToDom(a, kxi), kxi)
|
||||||
|
var j = 0
|
||||||
for i in 0..<kxi.patchLen:
|
for i in 0..<kxi.patchLen:
|
||||||
let p = $kxi.patches[i].k & " " & shortRepr(kxi.patches[i].n)
|
if kxi.patches[i].k != pkSame:
|
||||||
if i >= expected.len:
|
let n = if kxi.patches[i].k == pkDetach: kxi.patches[i].oldNode else: kxi.patches[i].newNode
|
||||||
|
let p = $kxi.patches[i].k & " " & shortRepr(n)
|
||||||
|
if j >= expected.len:
|
||||||
echo "patches differ; expected nothing but got: ", p
|
echo "patches differ; expected nothing but got: ", p
|
||||||
inc err
|
inc err
|
||||||
elif p != expected[i]:
|
elif p != expected[j]:
|
||||||
echo "patches differ; expected ", expected[i], " but got: ", p
|
echo "patches differ; expected ", expected[i], " but got: ", p
|
||||||
inc err
|
inc err
|
||||||
|
inc j
|
||||||
#hasDom(kxi.currentTree)
|
#hasDom(kxi.currentTree)
|
||||||
kxi.patchLen = 0
|
kxi.patchLen = 0
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue