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;
|
||||
if (string.Equals(oldElementName, newElementName, StringComparison.Ordinal))
|
||||
{
|
||||
// Recurse into the element. This covers diffing the attributes as well as
|
||||
// the descendants.
|
||||
AppendDiffEntriesForRange(
|
||||
oldTree, oldNodeIndex + 1, oldTree[oldNodeIndex].ElementDescendantsEndIndex + 1,
|
||||
newTree, newNodeIndex + 1, newTree[newNodeIndex].ElementDescendantsEndIndex + 1);
|
||||
var oldNodeAttributesEndIndexExcl = GetAttributesEndIndexExclusive(oldTree, oldNodeIndex);
|
||||
var newNodeAttributesEndIndexExcl = GetAttributesEndIndexExclusive(newTree, newNodeIndex);
|
||||
|
||||
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
|
||||
{
|
||||
|
|
@ -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)
|
||||
{
|
||||
if (_entriesInUse == _entries.Length)
|
||||
|
|
|
|||
|
|
@ -45,5 +45,15 @@ namespace Microsoft.Blazor.RenderTree
|
|||
Type = RenderTreeDiffEntryType.RemoveAttribute,
|
||||
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,
|
||||
RemoveAttribute = 5,
|
||||
UpdateText = 6,
|
||||
StepIn = 7,
|
||||
StepOut = 8,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -512,6 +512,47 @@ namespace Microsoft.Blazor.Test
|
|||
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
|
||||
{
|
||||
internal protected override void UpdateDisplay(int componentId, ArraySegment<RenderTreeNode> renderTree)
|
||||
|
|
|
|||
Loading…
Reference in New Issue