Fix ordering issue with nested logical element insertion
This commit is contained in:
parent
74b2b6b232
commit
a700fa945e
|
|
@ -66,22 +66,14 @@ export function insertLogicalChild(child: Node, parent: LogicalElement, childInd
|
|||
}
|
||||
|
||||
const newSiblings = getLogicalChildrenArray(parent);
|
||||
const newPhysicalParent = getClosestDomElement(parent);
|
||||
if (childIndex < newSiblings.length) {
|
||||
newPhysicalParent.insertBefore(child, newSiblings[childIndex] as any as Node);
|
||||
// Insert
|
||||
const nextSibling = newSiblings[childIndex] as any as Node;
|
||||
nextSibling.parentNode!.insertBefore(child, nextSibling);
|
||||
newSiblings.splice(childIndex, 0, childAsLogicalElement);
|
||||
} else {
|
||||
if (parent instanceof Comment) {
|
||||
const parentLogicalNextSibling = getLogicalNextSibling(parent);
|
||||
if (parentLogicalNextSibling) {
|
||||
newPhysicalParent.insertBefore(child, parentLogicalNextSibling as any as Node);
|
||||
} else {
|
||||
newPhysicalParent.appendChild(child);
|
||||
}
|
||||
} else {
|
||||
newPhysicalParent.appendChild(child);
|
||||
}
|
||||
|
||||
// Append
|
||||
appendDomNode(child, parent);
|
||||
newSiblings.push(childAsLogicalElement);
|
||||
}
|
||||
|
||||
|
|
@ -140,6 +132,27 @@ function getClosestDomElement(logicalElement: LogicalElement) {
|
|||
}
|
||||
}
|
||||
|
||||
function appendDomNode(child: Node, parent: LogicalElement) {
|
||||
// This function only puts 'child' into the DOM in the right place relative to 'parent'
|
||||
// It does not update the logical children array of anything
|
||||
if (parent instanceof Element) {
|
||||
parent.appendChild(child);
|
||||
} else if (parent instanceof Comment) {
|
||||
const parentLogicalNextSibling = getLogicalNextSibling(parent) as any as Node;
|
||||
if (parentLogicalNextSibling) {
|
||||
// Since the parent has a logical next-sibling, its appended child goes right before that
|
||||
parentLogicalNextSibling.parentNode!.insertBefore(child, parentLogicalNextSibling);
|
||||
} else {
|
||||
// Since the parent has no logical next-sibling, keep recursing upwards until we find
|
||||
// a logical ancestor that does have a next-sibling or is a physical element.
|
||||
appendDomNode(child, getLogicalParent(parent)!);
|
||||
}
|
||||
} else {
|
||||
// Should never happen
|
||||
throw new Error(`Cannot append node because the parent is not a valid logical element. Parent: ${parent}`);
|
||||
}
|
||||
}
|
||||
|
||||
function createSymbolOrFallback(fallback: string): symbol | string {
|
||||
return typeof Symbol === 'function' ? Symbol() : fallback;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,5 +292,12 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
|||
var svgCircleElement = appElement.FindElement(By.XPath("//*[local-name()='circle' and namespace-uri()='http://www.w3.org/2000/svg']"));
|
||||
Assert.NotNull(svgCircleElement);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LogicalElementInsertionWorksHierarchically()
|
||||
{
|
||||
var appElement = MountTestComponent<LogicalElementInsertionCases>();
|
||||
Assert.Equal("First Second Third", appElement.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<!--
|
||||
The lack of whitespace between the nested components, and the fact that PassThroughContentComponent
|
||||
renders its child content without any surrounding nodes, triggers a difficult scenario for the
|
||||
logical element insertion logic. It has to recurse upwards through the logical elements hierarchy
|
||||
to determine where to append nested component output nodes because there are no other nodes for
|
||||
the output to be inserted before.
|
||||
-->
|
||||
First
|
||||
<PassThroughContentComponent><PassThroughContentComponent>Second</PassThroughContentComponent></PassThroughContentComponent>
|
||||
Third
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
@using Microsoft.AspNetCore.Blazor
|
||||
@ChildContent
|
||||
@functions {
|
||||
// Note: The lack of any whitespace or other output besides @ChildContent is important for
|
||||
// what scenarios this component is used for in E2E tests.
|
||||
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
<option value="BasicTestApp.ExternalContentPackage">External content package</option>
|
||||
<option value="BasicTestApp.SvgComponent">SVG</option>
|
||||
<option value="BasicTestApp.SvgWithChildComponent">SVG with child component</option>
|
||||
<option value="BasicTestApp.LogicalElementInsertionCases">Logical element insertion cases</option>
|
||||
<!--<option value="BasicTestApp.RouterTest.Default">Router</option> Excluded because it requires additional setup to work correctly when loaded manually -->
|
||||
</select>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue