In diffing, support elements with descendants
This commit is contained in:
parent
0a5e27fdcf
commit
b021e19598
|
|
@ -187,13 +187,32 @@ namespace Microsoft.Blazor.RenderTree
|
||||||
var newElementName = newTree[newNodeIndex].ElementName;
|
var newElementName = newTree[newNodeIndex].ElementName;
|
||||||
if (string.Equals(oldElementName, newElementName, StringComparison.Ordinal))
|
if (string.Equals(oldElementName, newElementName, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
// Recurse into the element. This covers diffing the attributes as well as
|
var oldNodeAttributesEndIndexExcl = GetAttributesEndIndexExclusive(oldTree, oldNodeIndex);
|
||||||
// the descendants.
|
var newNodeAttributesEndIndexExcl = GetAttributesEndIndexExclusive(newTree, newNodeIndex);
|
||||||
AppendDiffEntriesForRange(
|
|
||||||
oldTree, oldNodeIndex + 1, oldTree[oldNodeIndex].ElementDescendantsEndIndex + 1,
|
|
||||||
newTree, newNodeIndex + 1, newTree[newNodeIndex].ElementDescendantsEndIndex + 1);
|
|
||||||
|
|
||||||
Append(RenderTreeDiffEntry.Continue());
|
// Diff the attributes
|
||||||
|
AppendDiffEntriesForRange(
|
||||||
|
oldTree, oldNodeIndex + 1, oldNodeAttributesEndIndexExcl,
|
||||||
|
newTree, newNodeIndex + 1, newNodeAttributesEndIndexExcl);
|
||||||
|
|
||||||
|
// Diff the children
|
||||||
|
var oldNodeChildrenEndIndexExcl = oldTree[oldNodeIndex].ElementDescendantsEndIndex + 1;
|
||||||
|
var newNodeChildrenEndIndexExcl = newTree[newNodeIndex].ElementDescendantsEndIndex + 1;
|
||||||
|
var hasChildrenToProcess =
|
||||||
|
oldNodeChildrenEndIndexExcl > oldNodeAttributesEndIndexExcl ||
|
||||||
|
newNodeChildrenEndIndexExcl > newNodeAttributesEndIndexExcl;
|
||||||
|
if (hasChildrenToProcess)
|
||||||
|
{
|
||||||
|
Append(RenderTreeDiffEntry.StepIn());
|
||||||
|
AppendDiffEntriesForRange(
|
||||||
|
oldTree, oldNodeAttributesEndIndexExcl, oldNodeChildrenEndIndexExcl,
|
||||||
|
newTree, newNodeAttributesEndIndexExcl, newNodeChildrenEndIndexExcl);
|
||||||
|
Append(RenderTreeDiffEntry.StepOut());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Append(RenderTreeDiffEntry.Continue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -256,6 +275,21 @@ namespace Microsoft.Blazor.RenderTree
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int GetAttributesEndIndexExclusive(RenderTreeNode[] tree, int rootIndex)
|
||||||
|
{
|
||||||
|
var descendantsEndIndex = tree[rootIndex].ElementDescendantsEndIndex;
|
||||||
|
var index = rootIndex + 1;
|
||||||
|
for (; index <= descendantsEndIndex; index++)
|
||||||
|
{
|
||||||
|
if (tree[index].NodeType != RenderTreeNodeType.Attribute)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
private void Append(RenderTreeDiffEntry entry)
|
private void Append(RenderTreeDiffEntry entry)
|
||||||
{
|
{
|
||||||
if (_entriesInUse == _entries.Length)
|
if (_entriesInUse == _entries.Length)
|
||||||
|
|
|
||||||
|
|
@ -45,5 +45,15 @@ namespace Microsoft.Blazor.RenderTree
|
||||||
Type = RenderTreeDiffEntryType.RemoveAttribute,
|
Type = RenderTreeDiffEntryType.RemoveAttribute,
|
||||||
RemovedAttributeName = name
|
RemovedAttributeName = name
|
||||||
};
|
};
|
||||||
|
|
||||||
|
internal static RenderTreeDiffEntry StepIn() => new RenderTreeDiffEntry
|
||||||
|
{
|
||||||
|
Type = RenderTreeDiffEntryType.StepIn
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static RenderTreeDiffEntry StepOut() => new RenderTreeDiffEntry
|
||||||
|
{
|
||||||
|
Type = RenderTreeDiffEntryType.StepOut
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,7 @@ namespace Microsoft.Blazor.RenderTree
|
||||||
SetAttribute = 4,
|
SetAttribute = 4,
|
||||||
RemoveAttribute = 5,
|
RemoveAttribute = 5,
|
||||||
UpdateText = 6,
|
UpdateText = 6,
|
||||||
|
StepIn = 7,
|
||||||
|
StepOut = 8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -512,6 +512,47 @@ namespace Microsoft.Blazor.Test
|
||||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DiffsElementsHierarchically()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
||||||
|
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
||||||
|
var diff = new RenderTreeDiff();
|
||||||
|
oldTree.OpenElement(10, "root");
|
||||||
|
oldTree.OpenElement(11, "child");
|
||||||
|
oldTree.OpenElement(12, "grandchild");
|
||||||
|
oldTree.AddText(13, "grandchild old text");
|
||||||
|
oldTree.CloseElement();
|
||||||
|
oldTree.CloseElement();
|
||||||
|
oldTree.CloseElement();
|
||||||
|
|
||||||
|
newTree.OpenElement(10, "root");
|
||||||
|
newTree.OpenElement(11, "child");
|
||||||
|
newTree.OpenElement(12, "grandchild");
|
||||||
|
newTree.AddText(13, "grandchild new text");
|
||||||
|
newTree.CloseElement();
|
||||||
|
newTree.CloseElement();
|
||||||
|
newTree.CloseElement();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(result,
|
||||||
|
entry => Assert.Equal(RenderTreeDiffEntryType.StepIn, entry.Type),
|
||||||
|
entry => Assert.Equal(RenderTreeDiffEntryType.StepIn, entry.Type),
|
||||||
|
entry => Assert.Equal(RenderTreeDiffEntryType.StepIn, entry.Type),
|
||||||
|
entry =>
|
||||||
|
{
|
||||||
|
Assert.Equal(RenderTreeDiffEntryType.UpdateText, entry.Type);
|
||||||
|
Assert.Equal(3, entry.NewTreeIndex);
|
||||||
|
},
|
||||||
|
entry => Assert.Equal(RenderTreeDiffEntryType.StepOut, entry.Type),
|
||||||
|
entry => Assert.Equal(RenderTreeDiffEntryType.StepOut, entry.Type),
|
||||||
|
entry => Assert.Equal(RenderTreeDiffEntryType.StepOut, entry.Type));
|
||||||
|
}
|
||||||
|
|
||||||
private class FakeRenderer : Renderer
|
private class FakeRenderer : Renderer
|
||||||
{
|
{
|
||||||
internal protected override void UpdateDisplay(int componentId, ArraySegment<RenderTreeNode> renderTree)
|
internal protected override void UpdateDisplay(int componentId, ArraySegment<RenderTreeNode> renderTree)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue