DOM diff problem: first success

This commit is contained in:
Roman Vishnevskii 2017-04-06 17:46:01 +07:00
commit 477bb60b14

161
karax.nim
View file

@ -109,13 +109,32 @@ proc equals(a, b: VNode): bool =
a.class = b.class a.class = b.class
return true return true
proc equalsTree(a, b : VNode): bool =
# kout cstring("equalsTree: (" & $a.kind & " = " & a.id & ") -> (" &
# $b.kind & " = " & b.id & ")")
# assert a != nil and b != nil
# kout cstring("equalsTree")
if not equals(a, b):
return false
else:
if len(a) != len(b):
return false
for i in 0..len(a)-1:
if not equalsTree(a[i], b[i]):
return false
return true
proc updateElement(parent, current: Node, newNode, oldNode: VNode) = proc updateElement(parent, current: Node, newNode, oldNode: VNode) =
#kout cstring("updateElement: (" & current.nodeName & " = " & current.id & ")")
if not equals(newNode, oldNode): if not equals(newNode, oldNode):
let n = vnodeToDom(newNode) let n = vnodeToDom(newNode)
if parent == nil: if parent == nil:
replaceById("ROOT", n) replaceById("ROOT", n)
else: else:
parent.replaceChild(n, current) parent.replaceChild(n, current)
kout cstring("ReplaceChild")
#kout cstring("ReplaceChild: (" & current.nodeName & " = " & newNode.id & ") -> (" &
# n.nodeName & " = " & oldNode.id & ")")
elif newNode.kind != VNodeKind.text: elif newNode.kind != VNodeKind.text:
let newLength = newNode.len let newLength = newNode.len
let oldLength = oldNode.len let oldLength = oldNode.len
@ -128,32 +147,150 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode) =
assert false assert false
var commonPrefix = 0 var commonPrefix = 0
while commonPrefix < minLength and newNode[commonPrefix] == oldNode[commonPrefix]: while commonPrefix < minLength and equalsTree(newNode[commonPrefix], oldNode[commonPrefix]):
inc commonPrefix inc commonPrefix
var oldPos = oldLength - 1 var oldPos = oldLength - 1
var newPos = newLength - 1 var newPos = newLength - 1
while oldPos >= 0 and newPos >= 0 and newNode[newPos] == oldNode[oldPos]: while oldPos >= commonPrefix and newPos >= commonPrefix and equalsTree(newNode[newPos], oldNode[oldPos]):
dec oldPos dec oldPos
dec newPos dec newPos
var pos = commonPrefix if commonPrefix + newLength - newPos > 1000:
while pos <= newPos and pos <= oldPos: kout cstring($(commonPrefix + newLength - newPos))
updateElement(current, current.childNodes[pos],
newNode[pos],
oldNode[pos])
inc pos
var pos = min(oldPos, newPos) + 1
# kout cstring("commonPrefix = " & $commonPrefix)
# kout cstring("oldPos = " & $oldPos)
# kout cstring("newPos = " & $newPos)
# kout cstring("newLength = " & $newLength)
# kout cstring("oldLength = " & $oldLength)
# kout cstring("-----------")
# for i in items(newNode):
# kout cstring(i.id)
# kout cstring("-----")
# for i in items(oldNode):
# kout cstring(i.id)
for i in commonPrefix..pos-1:
updateElement(current, current.childNodes[i],
newNode[i],
oldNode[i])
#kout cstring(newNode[i].id & " " & oldNode[i].id)
#kout cstring("----------")
var nextChildPos = oldPos + 1
while pos <= newPos: while pos <= newPos:
if newPos == newLength - 1: if nextChildPos == oldLength:
current.appendChild(vnodeToDom(newNode[pos])) current.appendChild(vnodeToDom(newNode[pos]))
kout cstring"appendChild"
#kout cstring("pos = " & $pos)
#kout cstring("newLength = " & $newLength)
else: else:
current.insertBefore(vnodeToDom(newNode[pos]), current.childNodes[pos + 1]) kout cstring"insertBefore"
current.insertBefore(vnodeToDom(newNode[pos]), current.childNodes[nextChildPos])
inc pos inc pos
inc nextChildPos
while pos <= oldPos: for i in 0..oldPos-pos:
kout cstring"removeChild"
current.removeChild(current.childNodes[pos]) current.removeChild(current.childNodes[pos])
inc pos
# var itNew = newPos + 1
# var itOld = oldPos + 1
# while itNew < newLength and itOld < oldLength:
# updateElement(current, current.childNodes[itNew],
# newNode[itNew],
# oldNode[itOld])
# kout cstring("commonPrefix = " & $commonPrefix)
# kout cstring("oldPos = " & $oldPos)
# kout cstring("newPos = " & $newPos)
# kout cstring("newLength = " & $newLength)
# kout cstring("oldLength = " & $oldLength)
# for i in 0..min(newLength, oldLength)-1:
# updateElement(current, current.childNodes[i],
# newNode[i],
# oldNode[i])
# if newLength > oldLength:
# for i in oldLength..newLength-1:
# kout cstring"appendChild"
# current.appendChild(vnodeToDom(newNode[i]))
# elif oldLength > newLength:
# for i in countdown(oldLength-1, newLength):
# kout cstring"removeChild"
# current.removeChild(current.lastChild)
proc updateElement1(parent, current: Node, newNode, oldNode: VNode) =
if not equals(newNode, oldNode):
let n = vnodeToDom(newNode)
if parent == nil:
replaceById("ROOT", n)
else:
parent.replaceChild(n, current)
kout cstring"ReplaceChild"
elif newNode.kind != VNodeKind.text:
let newLength = newNode.len
let oldLength = oldNode.len
let minLength = min(newLength, oldLength)
assert oldNode.kind == newNode.kind
when false:
if current.nodeName != toTag[oldNode.kind]:
kout current.nodeName
kout toTag[oldNode.kind]
assert false
# var commonPrefix = 0
# while commonPrefix < minLength and equals(newNode[commonPrefix], oldNode[commonPrefix]):
# inc commonPrefix
# var oldPos = oldLength - 1
# var newPos = newLength - 1
# while oldPos >= commonPrefix and newPos >= commonPrefix and equals(newNode[newPos], oldNode[oldPos]):
# dec oldPos
# dec newPos
# var pos = min(oldPos, newPos) + 1
# var nextChildPos = oldPos + 1
# while pos <= newPos:
# if nextChildPos == oldLength:
# current.appendChild(vnodeToDom(newNode[pos]))
# kout cstring"appendChild"
# else:
# kout cstring"insertBefore"
# current.insertBefore(vnodeToDom(newNode[pos]), current.childNodes[nextChildPos])
# inc pos
# inc nextChildPos
# for i in 0..oldPos-pos:
# kout cstring"removeChild"
# current.removeChild(current.childNodes[pos])
# # kout cstring("commonPrefix = " & $commonPrefix)
# # kout cstring("oldPos = " & $oldPos)
# # kout cstring("newPos = " & $newPos)
# # kout cstring("newLength = " & $newLength)
# # kout cstring("oldLength = " & $oldLength)
# for i in 0..newLength-1:
# updateElement(current, current.childNodes[i],
# newNode[i],
# oldNode[i])
for i in 0..min(newLength, oldLength)-1:
updateElement(current, current.childNodes[i],
newNode[i],
oldNode[i])
if newLength > oldLength:
for i in oldLength..newLength-1:
kout cstring"appendChild"
current.appendChild(vnodeToDom(newNode[i]))
elif oldLength > newLength:
for i in countdown(oldLength-1, newLength):
kout cstring"removeChild"
current.removeChild(current.lastChild)
proc dodraw() = proc dodraw() =
let newtree = dorender() let newtree = dorender()