code cleanups
This commit is contained in:
parent
f89da765fa
commit
74c07f0634
1 changed files with 45 additions and 211 deletions
256
src/karax.nim
256
src/karax.nim
|
|
@ -152,13 +152,12 @@ proc same(n: VNode, e: Node): bool =
|
||||||
proc replaceById(id: cstring; newTree: Node) =
|
proc replaceById(id: cstring; newTree: Node) =
|
||||||
let x = document.getElementById(id)
|
let x = document.getElementById(id)
|
||||||
x.parentNode.replaceChild(newTree, x)
|
x.parentNode.replaceChild(newTree, x)
|
||||||
#newTree.id = id
|
|
||||||
|
|
||||||
type
|
type
|
||||||
EqResult = enum
|
EqResult = enum
|
||||||
changed, different, similar, identical
|
changed, different, similar, identical
|
||||||
|
|
||||||
proc eq(a, b: VNode; deep: bool): EqResult =
|
proc eq(a, b: VNode): EqResult =
|
||||||
if a.kind != b.kind: return different
|
if a.kind != b.kind: return different
|
||||||
if a.id != b.id: return different
|
if a.id != b.id: return different
|
||||||
result = identical
|
result = identical
|
||||||
|
|
@ -169,60 +168,25 @@ proc eq(a, b: VNode; deep: bool): 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], deep) == different: return different
|
if eq(a[i], b[i]) == different: return different
|
||||||
elif b.kind == VNodeKind.component:
|
elif b.kind == VNodeKind.component:
|
||||||
# different component names mean different components:
|
# different component names mean different components:
|
||||||
if a.text != b.text: return different
|
if a.text != b.text: return different
|
||||||
let x = VComponent(b)
|
let x = VComponent(b)
|
||||||
assert x.changedImpl != nil
|
assert x.changedImpl != nil
|
||||||
return if x.changedImpl(x): changed else: identical
|
return if x.changedImpl(x): changed else: identical
|
||||||
elif deep:
|
|
||||||
if a.len != b.len: return different
|
|
||||||
for i in 0..<a.len:
|
|
||||||
let res = eq(a[i], b[i], deep)
|
|
||||||
if res <= different: return different
|
|
||||||
elif res == similar:
|
|
||||||
# but continue, maybe something makes it 'different'!
|
|
||||||
result = similar
|
|
||||||
if not sameAttrs(a, b): return different
|
if not sameAttrs(a, b): return different
|
||||||
if a.class != b.class: return different
|
if a.class != b.class: return different
|
||||||
if not eq(a.style, b.style): return similar
|
if not eq(a.style, b.style): return similar
|
||||||
# Do not test event listeners here!
|
# Do not test event listeners here!
|
||||||
return result
|
return result
|
||||||
|
|
||||||
when false:
|
proc updateStyles(newNode, oldNode: VNode) =
|
||||||
proc updateDirtyElements(parent, current: Node, newNode: VNode,
|
|
||||||
kxi: KaraxInstance) =
|
|
||||||
if newNode.key >= 0 and isDirty(newNode.key):
|
|
||||||
unmarkDirty(newNode.key)
|
|
||||||
let n = vnodeToDom(newNode, kxi)
|
|
||||||
if parent == nil:
|
|
||||||
replaceById(kxi.rootId, n)
|
|
||||||
else:
|
|
||||||
parent.replaceChild(n, current)
|
|
||||||
elif newNode.kind != VNodeKind.text and newNode.kind != VNodeKind.vthunk and
|
|
||||||
newNode.kind != VNodeKind.dthunk:
|
|
||||||
for i in 0..newNode.len-1:
|
|
||||||
updateDirtyElements(current, current[i], newNode[i], kxi)
|
|
||||||
# leave early if we know there cannot be anything left to do:
|
|
||||||
#if dirtyCount <= 0: return
|
|
||||||
|
|
||||||
proc updateStyles(newNode, oldNode: VNode; deep: bool) =
|
|
||||||
# we keep the oldNode, but take over the style from the new node:
|
# we keep the oldNode, but take over the style from the new node:
|
||||||
if oldNode.dom != nil:
|
if oldNode.dom != nil:
|
||||||
if newNode.style != nil: applyStyle(oldNode.dom, newNode.style)
|
if newNode.style != nil: applyStyle(oldNode.dom, newNode.style)
|
||||||
else: oldNode.dom.style = Style()
|
else: oldNode.dom.style = Style()
|
||||||
oldNode.style = newNode.style
|
oldNode.style = newNode.style
|
||||||
if deep:
|
|
||||||
doAssert newNode.len == oldNode.len
|
|
||||||
for i in 0 ..< newNode.len:
|
|
||||||
updateStyles(newNode[i], oldNode[i], deep)
|
|
||||||
|
|
||||||
proc updateDom(newNode, oldNode: VNode) =
|
|
||||||
newNode.dom = oldNode.dom
|
|
||||||
assert newNode.len == oldNode.len
|
|
||||||
for i in 0 ..< newNode.len:
|
|
||||||
updateDom(newNode[i], oldNode[i])
|
|
||||||
|
|
||||||
proc printV(n: VNode; depth: cstring = "") =
|
proc printV(n: VNode; depth: cstring = "") =
|
||||||
kout depth, cstring($n.kind), n.myid, cstring"key ", n.key
|
kout depth, cstring($n.kind), n.myid, cstring"key ", n.key
|
||||||
|
|
@ -264,55 +228,32 @@ proc apply(patches: seq[Patch]; kxi: KaraxInstance) =
|
||||||
|
|
||||||
proc diff(parent, current: Node; newNode, oldNode: VNode; patches: var seq[Patch];
|
proc diff(parent, current: Node; newNode, oldNode: VNode; patches: var seq[Patch];
|
||||||
kxi: KaraxInstance): EqResult =
|
kxi: KaraxInstance): EqResult =
|
||||||
result = eq(newNode, oldNode, deep=false)
|
result = eq(newNode, oldNode)
|
||||||
if result <= different:
|
case result
|
||||||
var n: Node
|
of identical:
|
||||||
if result == changed:
|
|
||||||
assert oldNode.kind == VNodeKind.component
|
|
||||||
let x = VComponent(oldNode)
|
|
||||||
let oldExpanded = x.expanded
|
|
||||||
x.expanded = x.renderImpl(x)
|
|
||||||
x.updatedImpl(x)
|
|
||||||
if oldExpanded == nil:
|
|
||||||
n = vnodeToDom(x.expanded, kxi)
|
|
||||||
else:
|
|
||||||
let res = diff(parent, current, x.expanded, oldExpanded, patches, kxi)
|
|
||||||
if res != different:
|
|
||||||
x.expanded = oldExpanded
|
|
||||||
n = oldExpanded.dom
|
|
||||||
doAssert n != nil, "old expanded.dom is nil"
|
|
||||||
else:
|
|
||||||
n = x.expanded.dom
|
|
||||||
doAssert n != nil, "expanded.dom is nil"
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
detach(oldNode)
|
|
||||||
n = vnodeToDom(newNode, kxi)
|
|
||||||
patches.addPatch(pkReplace, parent, current, n)
|
|
||||||
elif result == similar:
|
|
||||||
updateStyles(newNode, oldNode, false)
|
|
||||||
else:
|
|
||||||
newNode.dom = oldNode.dom
|
newNode.dom = oldNode.dom
|
||||||
let newLength = newNode.len
|
let newLength = newNode.len
|
||||||
var oldLength = oldNode.len
|
var oldLength = oldNode.len
|
||||||
let minLength = min(newLength, oldLength)
|
let minLength = min(newLength, oldLength)
|
||||||
|
if minLength == 0: return result
|
||||||
|
|
||||||
assert oldNode.kind == newNode.kind
|
assert oldNode.kind == newNode.kind
|
||||||
var commonPrefix = 0
|
var commonPrefix = 0
|
||||||
|
|
||||||
template eqAndUpdate(a: VNode; i: int; b: VNode; j: int; info, action: untyped) =
|
template eqAndUpdate(a: VNode; i: int; b: VNode; j: int; info, action: untyped) =
|
||||||
let oldLen = patches.len
|
let oldLen = patches.len
|
||||||
if oldNode.kind notin {VNodeKind.component, VNodeKind.vthunk, VNodeKind.dthunk}:
|
when false:
|
||||||
assert current != nil
|
if oldNode.kind notin {VNodeKind.component, VNodeKind.vthunk, VNodeKind.dthunk}:
|
||||||
assert current.childNodes[j] != nil, $info
|
assert current != nil
|
||||||
assert oldNode.len == current.len
|
assert current.childNodes[j] != nil, $info
|
||||||
|
assert oldNode.len == current.len
|
||||||
|
|
||||||
let r = if oldNode.kind in {VNodeKind.component, VNodeKind.vthunk, VNodeKind.dthunk}:
|
let r = if oldNode.kind in {VNodeKind.component, VNodeKind.vthunk, VNodeKind.dthunk}:
|
||||||
diff(parent, current, a[i], b[j], patches, kxi)
|
diff(parent, current, a[i], b[j], patches, kxi)
|
||||||
else:
|
else:
|
||||||
diff(current, current.childNodes[j], a[i], b[j], patches, kxi)
|
diff(current, current.childNodes[j], a[i], b[j], patches, kxi)
|
||||||
case r
|
case r
|
||||||
of identical, changed:
|
of identical, changed, similar:
|
||||||
a[i] = b[j]
|
a[i] = b[j]
|
||||||
action
|
action
|
||||||
of different:
|
of different:
|
||||||
|
|
@ -320,10 +261,10 @@ proc diff(parent, current: Node; newNode, oldNode: VNode; patches: var seq[Patch
|
||||||
setLen(patches, oldLen)
|
setLen(patches, oldLen)
|
||||||
if result != different: result = r
|
if result != different: result = r
|
||||||
break
|
break
|
||||||
of similar:
|
#of similar:
|
||||||
updateStyles(a[i], b[j], false)
|
# updateStyles(a[i], b[j])
|
||||||
a[i] = b[j]
|
# a[i] = b[j]
|
||||||
action
|
# action
|
||||||
|
|
||||||
while commonPrefix < minLength:
|
while commonPrefix < minLength:
|
||||||
eqAndUpdate(newNode, commonPrefix, oldNode, commonPrefix, cstring"prefix"):
|
eqAndUpdate(newNode, commonPrefix, oldNode, commonPrefix, cstring"prefix"):
|
||||||
|
|
@ -338,20 +279,18 @@ proc diff(parent, current: Node; newNode, oldNode: VNode; patches: var seq[Patch
|
||||||
|
|
||||||
var pos = min(oldPos, newPos) + 1
|
var pos = min(oldPos, newPos) + 1
|
||||||
for i in commonPrefix..pos-1:
|
for i in commonPrefix..pos-1:
|
||||||
let res = diff(current, current.childNodes[i],
|
if diff(current, current.childNodes[i],
|
||||||
newNode[i], oldNode[i], patches, kxi)
|
newNode[i], oldNode[i], patches, kxi) != different:
|
||||||
if res != different:
|
|
||||||
newNode[i] = oldNode[i]
|
newNode[i] = oldNode[i]
|
||||||
else:
|
else:
|
||||||
result = different
|
result = different
|
||||||
|
|
||||||
var nextChildPos = oldPos + 1
|
if oldPos + 1 == oldLength:
|
||||||
if nextChildPos == oldLength:
|
|
||||||
for i in pos..newPos:
|
for i in pos..newPos:
|
||||||
patches.addPatch(pkAppend, current, nil, vnodeToDom(newNode[i], kxi))
|
patches.addPatch(pkAppend, current, nil, vnodeToDom(newNode[i], kxi))
|
||||||
result = different
|
result = different
|
||||||
else:
|
else:
|
||||||
let before = current.childNodes[nextChildPos]
|
let before = current.childNodes[oldPos + 1]
|
||||||
for i in pos..newPos:
|
for i in pos..newPos:
|
||||||
patches.addPatch(pkInsertBefore, current, before,
|
patches.addPatch(pkInsertBefore, current, before,
|
||||||
vnodeToDom(newNode[i], kxi))
|
vnodeToDom(newNode[i], kxi))
|
||||||
|
|
@ -359,153 +298,48 @@ proc diff(parent, current: Node; newNode, oldNode: VNode; patches: var seq[Patch
|
||||||
# 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
|
||||||
patches.addPatch(pkRemove, current, current.childNodes[i], nil)
|
patches.addPatch(pkRemove, current, current.childNodes[i], nil)
|
||||||
result = different
|
result = different
|
||||||
|
|
||||||
|
of similar:
|
||||||
proc updateElement(parent, current: Node, newNode, oldNode: VNode;
|
updateStyles(newNode, oldNode)
|
||||||
kxi: KaraxInstance): EqResult =
|
of changed:
|
||||||
result = eq(newNode, oldNode, deep=false)
|
assert oldNode.kind == VNodeKind.component
|
||||||
if result <= different:
|
let x = VComponent(oldNode)
|
||||||
var n: Node
|
let oldExpanded = x.expanded
|
||||||
var state = 0
|
x.expanded = x.renderImpl(x)
|
||||||
if result == changed:
|
x.updatedImpl(x)
|
||||||
assert oldNode.kind == VNodeKind.component
|
if oldExpanded == nil:
|
||||||
let x = VComponent(oldNode)
|
|
||||||
let oldExpanded = x.expanded
|
|
||||||
x.expanded = x.renderImpl(x)
|
|
||||||
x.updatedImpl(x)
|
|
||||||
if oldExpanded == nil:
|
|
||||||
n = vnodeToDom(x.expanded, kxi)
|
|
||||||
state = 1
|
|
||||||
else:
|
|
||||||
let res = updateElement(parent, current, x.expanded, oldExpanded, kxi)
|
|
||||||
if res != different:
|
|
||||||
x.expanded = oldExpanded
|
|
||||||
n = oldExpanded.dom
|
|
||||||
doAssert n != nil, "old expanded.dom is nil"
|
|
||||||
#kout cstring"produced old DOM: ", cstring($res)
|
|
||||||
#printV(oldExpanded)
|
|
||||||
#printV(x.expanded)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
n = x.expanded.dom
|
|
||||||
doAssert n != nil, "expanded.dom is nil"
|
|
||||||
state = 2
|
|
||||||
#kout cstring"produced new DOM:"
|
|
||||||
#printV(oldExpanded)
|
|
||||||
#printV(x.expanded)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
detach(oldNode)
|
detach(oldNode)
|
||||||
n = vnodeToDom(newNode, kxi)
|
let n = vnodeToDom(x.expanded, kxi)
|
||||||
state = 3
|
patches.addPatch(pkReplace, parent, current, n)
|
||||||
if parent == nil:
|
|
||||||
replaceById(kxi.rootId, n)
|
|
||||||
else:
|
else:
|
||||||
#kout cstring"state ", state, parent, current
|
let res = diff(parent, current, x.expanded, oldExpanded, patches, kxi)
|
||||||
if n != current:
|
if res != different:
|
||||||
parent.replaceChild(n, current)
|
x.expanded = oldExpanded
|
||||||
elif result == similar:
|
assert oldExpanded.dom != nil, "old expanded.dom is nil"
|
||||||
updateStyles(newNode, oldNode, false)
|
|
||||||
else:
|
|
||||||
newNode.dom = oldNode.dom
|
|
||||||
if newNode.kind != VNodeKind.text:
|
|
||||||
let newLength = newNode.len
|
|
||||||
var oldLength = oldNode.len
|
|
||||||
let minLength = min(newLength, oldLength)
|
|
||||||
assert oldNode.kind == newNode.kind
|
|
||||||
when defined(simpleDiff):
|
|
||||||
for i in 0..min(newLength, oldLength)-1:
|
|
||||||
updateElement(current, current[i], newNode[i], oldNode[i], kxi)
|
|
||||||
if newLength > oldLength:
|
|
||||||
for i in oldLength..newLength-1:
|
|
||||||
current.appendChild(vnodeToDom(newNode[i]))
|
|
||||||
elif oldLength > newLength:
|
|
||||||
for i in countdown(oldLength-1, newLength):
|
|
||||||
detach(oldNode[i])
|
|
||||||
current.removeChild(current.lastChild)
|
|
||||||
else:
|
else:
|
||||||
var commonPrefix = 0
|
assert x.expanded.dom != nil, "expanded.dom is nil"
|
||||||
|
of different:
|
||||||
template eqAndUpdate(a: VNode; i: int; b: VNode; action: untyped) =
|
detach(oldNode)
|
||||||
let r = eq(a[i], b, true)
|
let n = vnodeToDom(newNode, kxi)
|
||||||
case r
|
patches.addPatch(pkReplace, parent, current, n)
|
||||||
of identical:
|
|
||||||
a[i] = b
|
|
||||||
#updateDom(a, b)
|
|
||||||
action
|
|
||||||
of different, changed:
|
|
||||||
if result != different: result = r
|
|
||||||
break
|
|
||||||
of similar:
|
|
||||||
#updateDom(a, b)
|
|
||||||
updateStyles(a[i], b, true)
|
|
||||||
a[i] = b
|
|
||||||
action
|
|
||||||
|
|
||||||
while commonPrefix < minLength:
|
|
||||||
eqAndUpdate(newNode, commonPrefix, oldNode[commonPrefix]):
|
|
||||||
inc commonPrefix
|
|
||||||
|
|
||||||
var oldPos = oldLength - 1
|
|
||||||
var newPos = newLength - 1
|
|
||||||
while oldPos >= commonPrefix and newPos >= commonPrefix:
|
|
||||||
eqAndUpdate(newNode, newPos, oldNode[oldPos]):
|
|
||||||
dec oldPos
|
|
||||||
dec newPos
|
|
||||||
|
|
||||||
var pos = min(oldPos, newPos) + 1
|
|
||||||
for i in commonPrefix..pos-1:
|
|
||||||
let res = updateElement(current, current.childNodes[i],
|
|
||||||
newNode[i], oldNode[i], kxi)
|
|
||||||
if res != different:
|
|
||||||
newNode[i] = oldNode[i]
|
|
||||||
else:
|
|
||||||
result = different
|
|
||||||
|
|
||||||
var nextChildPos = oldPos + 1
|
|
||||||
while pos <= newPos:
|
|
||||||
if nextChildPos == oldLength:
|
|
||||||
current.appendChild(vnodeToDom(newNode[pos], kxi))
|
|
||||||
else:
|
|
||||||
current.insertBefore(vnodeToDom(newNode[pos], kxi), current.childNodes[nextChildPos])
|
|
||||||
# added new Node, so old state of VDOM have one more Node
|
|
||||||
inc oldLength
|
|
||||||
inc pos
|
|
||||||
inc nextChildPos
|
|
||||||
result = different
|
|
||||||
|
|
||||||
for i in pos..oldPos:
|
|
||||||
detach(oldNode[i])
|
|
||||||
doAssert pos < current.childNodes.len
|
|
||||||
current.removeChild(current.childNodes[pos])
|
|
||||||
result = different
|
|
||||||
|
|
||||||
when false:
|
|
||||||
var drawTimeout: Timeout
|
|
||||||
|
|
||||||
proc dodraw(kxi: KaraxInstance) =
|
proc dodraw(kxi: KaraxInstance) =
|
||||||
if kxi.renderer.isNil: return
|
if kxi.renderer.isNil: return
|
||||||
let newtree = kxi.renderer()
|
let newtree = kxi.renderer()
|
||||||
newtree.id = kxi.rootId
|
newtree.id = kxi.rootId
|
||||||
kxi.toFocus = nil
|
kxi.toFocus = nil
|
||||||
#if kxi.currentTree != nil:
|
|
||||||
# kout cstring"same? ", same(kxi.currentTree, document.getElementById(kxi.rootId))
|
|
||||||
#kout cstring"dodraw -----------------------------"
|
|
||||||
if kxi.currentTree == nil:
|
if kxi.currentTree == nil:
|
||||||
kxi.currentTree = newtree
|
kxi.currentTree = newtree
|
||||||
let asdom = vnodeToDom(kxi.currentTree, kxi)
|
let asdom = vnodeToDom(kxi.currentTree, kxi)
|
||||||
replaceById(kxi.rootId, asdom)
|
replaceById(kxi.rootId, asdom)
|
||||||
else:
|
else:
|
||||||
let olddom = document.getElementById(kxi.rootId)
|
let olddom = document.getElementById(kxi.rootId)
|
||||||
when false:
|
var patches: seq[Patch] = @[]
|
||||||
discard updateElement(nil, olddom, newtree, kxi.currentTree, kxi)
|
discard diff(nil, olddom, newtree, kxi.currentTree, patches, kxi)
|
||||||
else:
|
patches.apply(kxi)
|
||||||
var patches: seq[Patch] = @[]
|
|
||||||
discard diff(nil, olddom, newtree, kxi.currentTree, patches, kxi)
|
|
||||||
patches.apply(kxi)
|
|
||||||
kxi.currentTree = newtree
|
kxi.currentTree = newtree
|
||||||
#doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
#doAssert same(kxi.currentTree, document.getElementById(kxi.rootId))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue