Rename RenderTreeNode -> RenderTreeFrame (and correspondingly, "node" ->
"frame" everywhere)
This commit is contained in:
parent
4526c8c1f0
commit
f1332919bc
|
|
@ -1,6 +1,6 @@
|
|||
import { System_Array, MethodHandle } from '../Platform/Platform';
|
||||
import { getRenderTreeEditPtr, renderTreeEdit, RenderTreeEditPointer, EditType } from './RenderTreeEdit';
|
||||
import { getTreeNodePtr, renderTreeNode, NodeType, RenderTreeNodePointer } from './RenderTreeNode';
|
||||
import { getTreeFramePtr, renderTreeFrame, FrameType, RenderTreeFramePointer } from './RenderTreeFrame';
|
||||
import { platform } from '../Environment';
|
||||
let raiseEventMethod: MethodHandle;
|
||||
let renderComponentMethod: MethodHandle;
|
||||
|
|
@ -15,7 +15,7 @@ export class BrowserRenderer {
|
|||
this.childComponentLocations[componentId] = element;
|
||||
}
|
||||
|
||||
public updateComponent(componentId: number, edits: System_Array<RenderTreeEditPointer>, editsLength: number, referenceTree: System_Array<RenderTreeNodePointer>) {
|
||||
public updateComponent(componentId: number, edits: System_Array<RenderTreeEditPointer>, editsLength: number, referenceTree: System_Array<RenderTreeFramePointer>) {
|
||||
const element = this.childComponentLocations[componentId];
|
||||
if (!element) {
|
||||
throw new Error(`No element is currently associated with component ${componentId}`);
|
||||
|
|
@ -28,31 +28,31 @@ export class BrowserRenderer {
|
|||
delete this.childComponentLocations[componentId];
|
||||
}
|
||||
|
||||
applyEdits(componentId: number, parent: Element, childIndex: number, edits: System_Array<RenderTreeEditPointer>, editsLength: number, referenceTree: System_Array<RenderTreeNodePointer>) {
|
||||
applyEdits(componentId: number, parent: Element, childIndex: number, edits: System_Array<RenderTreeEditPointer>, editsLength: number, referenceTree: System_Array<RenderTreeFramePointer>) {
|
||||
let currentDepth = 0;
|
||||
let childIndexAtCurrentDepth = childIndex;
|
||||
for (let editIndex = 0; editIndex < editsLength; editIndex++) {
|
||||
const edit = getRenderTreeEditPtr(edits, editIndex);
|
||||
const editType = renderTreeEdit.type(edit);
|
||||
switch (editType) {
|
||||
case EditType.prependNode: {
|
||||
const nodeIndex = renderTreeEdit.newTreeIndex(edit);
|
||||
const node = getTreeNodePtr(referenceTree, nodeIndex);
|
||||
case EditType.prependFrame: {
|
||||
const frameIndex = renderTreeEdit.newTreeIndex(edit);
|
||||
const frame = getTreeFramePtr(referenceTree, frameIndex);
|
||||
const siblingIndex = renderTreeEdit.siblingIndex(edit);
|
||||
this.insertNode(componentId, parent, childIndexAtCurrentDepth + siblingIndex, referenceTree, node, nodeIndex);
|
||||
this.insertFrame(componentId, parent, childIndexAtCurrentDepth + siblingIndex, referenceTree, frame, frameIndex);
|
||||
break;
|
||||
}
|
||||
case EditType.removeNode: {
|
||||
case EditType.removeFrame: {
|
||||
const siblingIndex = renderTreeEdit.siblingIndex(edit);
|
||||
removeNodeFromDOM(parent, childIndexAtCurrentDepth + siblingIndex);
|
||||
break;
|
||||
}
|
||||
case EditType.setAttribute: {
|
||||
const nodeIndex = renderTreeEdit.newTreeIndex(edit);
|
||||
const node = getTreeNodePtr(referenceTree, nodeIndex);
|
||||
const frameIndex = renderTreeEdit.newTreeIndex(edit);
|
||||
const frame = getTreeFramePtr(referenceTree, frameIndex);
|
||||
const siblingIndex = renderTreeEdit.siblingIndex(edit);
|
||||
const element = parent.childNodes[childIndexAtCurrentDepth + siblingIndex] as HTMLElement;
|
||||
this.applyAttribute(componentId, element, node, nodeIndex);
|
||||
this.applyAttribute(componentId, element, frame, frameIndex);
|
||||
break;
|
||||
}
|
||||
case EditType.removeAttribute: {
|
||||
|
|
@ -61,11 +61,11 @@ export class BrowserRenderer {
|
|||
break;
|
||||
}
|
||||
case EditType.updateText: {
|
||||
const nodeIndex = renderTreeEdit.newTreeIndex(edit);
|
||||
const node = getTreeNodePtr(referenceTree, nodeIndex);
|
||||
const frameIndex = renderTreeEdit.newTreeIndex(edit);
|
||||
const frame = getTreeFramePtr(referenceTree, frameIndex);
|
||||
const siblingIndex = renderTreeEdit.siblingIndex(edit);
|
||||
const domTextNode = parent.childNodes[childIndexAtCurrentDepth + siblingIndex] as Text;
|
||||
domTextNode.textContent = renderTreeNode.textContent(node);
|
||||
domTextNode.textContent = renderTreeFrame.textContent(frame);
|
||||
break;
|
||||
}
|
||||
case EditType.stepIn: {
|
||||
|
|
@ -89,79 +89,79 @@ export class BrowserRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
insertNode(componentId: number, parent: Element, childIndex: number, nodes: System_Array<RenderTreeNodePointer>, node: RenderTreeNodePointer, nodeIndex: number) {
|
||||
const nodeType = renderTreeNode.nodeType(node);
|
||||
switch (nodeType) {
|
||||
case NodeType.element:
|
||||
this.insertElement(componentId, parent, childIndex, nodes, node, nodeIndex);
|
||||
insertFrame(componentId: number, parent: Element, childIndex: number, frames: System_Array<RenderTreeFramePointer>, frame: RenderTreeFramePointer, frameIndex: number) {
|
||||
const frameType = renderTreeFrame.frameType(frame);
|
||||
switch (frameType) {
|
||||
case FrameType.element:
|
||||
this.insertElement(componentId, parent, childIndex, frames, frame, frameIndex);
|
||||
break;
|
||||
case NodeType.text:
|
||||
this.insertText(parent, childIndex, node);
|
||||
case FrameType.text:
|
||||
this.insertText(parent, childIndex, frame);
|
||||
break;
|
||||
case NodeType.attribute:
|
||||
throw new Error('Attribute nodes should only be present as leading children of element nodes.');
|
||||
case NodeType.component:
|
||||
this.insertComponent(parent, childIndex, node);
|
||||
case FrameType.attribute:
|
||||
throw new Error('Attribute frames should only be present as leading children of element frames.');
|
||||
case FrameType.component:
|
||||
this.insertComponent(parent, childIndex, frame);
|
||||
break;
|
||||
default:
|
||||
const unknownType: never = nodeType; // Compile-time verification that the switch was exhaustive
|
||||
throw new Error(`Unknown node type: ${unknownType}`);
|
||||
const unknownType: never = frameType; // Compile-time verification that the switch was exhaustive
|
||||
throw new Error(`Unknown frame type: ${unknownType}`);
|
||||
}
|
||||
}
|
||||
|
||||
insertElement(componentId: number, parent: Element, childIndex: number, nodes: System_Array<RenderTreeNodePointer>, node: RenderTreeNodePointer, nodeIndex: number) {
|
||||
const tagName = renderTreeNode.elementName(node)!;
|
||||
insertElement(componentId: number, parent: Element, childIndex: number, frames: System_Array<RenderTreeFramePointer>, frame: RenderTreeFramePointer, frameIndex: number) {
|
||||
const tagName = renderTreeFrame.elementName(frame)!;
|
||||
const newDomElement = document.createElement(tagName);
|
||||
insertNodeIntoDOM(newDomElement, parent, childIndex);
|
||||
|
||||
// Apply attributes
|
||||
const descendantsEndIndex = renderTreeNode.descendantsEndIndex(node);
|
||||
for (let descendantIndex = nodeIndex + 1; descendantIndex <= descendantsEndIndex; descendantIndex++) {
|
||||
const descendantNode = getTreeNodePtr(nodes, descendantIndex);
|
||||
if (renderTreeNode.nodeType(descendantNode) === NodeType.attribute) {
|
||||
this.applyAttribute(componentId, newDomElement, descendantNode, descendantIndex);
|
||||
const descendantsEndIndex = renderTreeFrame.descendantsEndIndex(frame);
|
||||
for (let descendantIndex = frameIndex + 1; descendantIndex <= descendantsEndIndex; descendantIndex++) {
|
||||
const descendantFrame = getTreeFramePtr(frames, descendantIndex);
|
||||
if (renderTreeFrame.frameType(descendantFrame) === FrameType.attribute) {
|
||||
this.applyAttribute(componentId, newDomElement, descendantFrame, descendantIndex);
|
||||
} else {
|
||||
// As soon as we see a non-attribute child, all the subsequent child nodes are
|
||||
// As soon as we see a non-attribute child, all the subsequent child frames are
|
||||
// not attributes, so bail out and insert the remnants recursively
|
||||
this.insertNodeRange(componentId, newDomElement, 0, nodes, descendantIndex, descendantsEndIndex);
|
||||
this.insertFrameRange(componentId, newDomElement, 0, frames, descendantIndex, descendantsEndIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
insertComponent(parent: Element, childIndex: number, node: RenderTreeNodePointer) {
|
||||
// Currently, to support O(1) lookups from render tree nodes to DOM nodes, we rely on
|
||||
insertComponent(parent: Element, childIndex: number, frame: RenderTreeFramePointer) {
|
||||
// Currently, to support O(1) lookups from render tree frames to DOM nodes, we rely on
|
||||
// each child component existing as a single top-level element in the DOM. To guarantee
|
||||
// that, we wrap child components in these 'blazor-component' wrappers.
|
||||
// To improve on this in the future:
|
||||
// - If we can statically detect that a given component always produces a single top-level
|
||||
// element anyway, then don't wrap it in a further nonstandard element
|
||||
// - If we really want to support child components producing multiple top-level nodes and
|
||||
// - If we really want to support child components producing multiple top-level frames and
|
||||
// not being wrapped in a container at all, then every time a component is refreshed in
|
||||
// the DOM, we could update an array on the parent element that specifies how many DOM
|
||||
// nodes correspond to each of its render tree nodes. Then when that parent wants to
|
||||
// locate the first DOM node for a render tree node, it can sum all the node counts for
|
||||
// all the preceding render trees nodes. It's O(N), but where N is the number of siblings
|
||||
// nodes correspond to each of its render tree frames. Then when that parent wants to
|
||||
// locate the first DOM node for a render tree frame, it can sum all the frame counts for
|
||||
// all the preceding render trees frames. It's O(N), but where N is the number of siblings
|
||||
// (counting child components as a single item), so N will rarely if ever be large.
|
||||
// We could even keep track of whether all the child components happen to have exactly 1
|
||||
// top level node, and in that case, there's no need to sum as we can do direct lookups.
|
||||
// top level frames, and in that case, there's no need to sum as we can do direct lookups.
|
||||
const containerElement = document.createElement('blazor-component');
|
||||
insertNodeIntoDOM(containerElement, parent, childIndex);
|
||||
|
||||
// All we have to do is associate the child component ID with its location. We don't actually
|
||||
// do any rendering here, because the diff for the child will appear later in the render batch.
|
||||
const childComponentId = renderTreeNode.componentId(node);
|
||||
const childComponentId = renderTreeFrame.componentId(frame);
|
||||
this.attachComponentToElement(childComponentId, containerElement);
|
||||
}
|
||||
|
||||
insertText(parent: Element, childIndex: number, textNode: RenderTreeNodePointer) {
|
||||
const textContent = renderTreeNode.textContent(textNode)!;
|
||||
insertText(parent: Element, childIndex: number, textFrame: RenderTreeFramePointer) {
|
||||
const textContent = renderTreeFrame.textContent(textFrame)!;
|
||||
const newDomTextNode = document.createTextNode(textContent);
|
||||
insertNodeIntoDOM(newDomTextNode, parent, childIndex);
|
||||
}
|
||||
|
||||
applyAttribute(componentId: number, toDomElement: Element, attributeNode: RenderTreeNodePointer, attributeNodeIndex: number) {
|
||||
const attributeName = renderTreeNode.attributeName(attributeNode)!;
|
||||
applyAttribute(componentId: number, toDomElement: Element, attributeFrame: RenderTreeFramePointer, attributeFrameIndex: number) {
|
||||
const attributeName = renderTreeFrame.attributeName(attributeFrame)!;
|
||||
const browserRendererId = this.browserRendererId;
|
||||
|
||||
// TODO: Instead of applying separate event listeners to each DOM element, use event delegation
|
||||
|
|
@ -169,7 +169,7 @@ export class BrowserRenderer {
|
|||
switch (attributeName) {
|
||||
case 'onclick': {
|
||||
toDomElement.removeEventListener('click', toDomElement['_blazorClickListener']);
|
||||
const listener = () => raiseEvent(browserRendererId, componentId, attributeNodeIndex, 'mouse', { Type: 'click' });
|
||||
const listener = () => raiseEvent(browserRendererId, componentId, attributeFrameIndex, 'mouse', { Type: 'click' });
|
||||
toDomElement['_blazorClickListener'] = listener;
|
||||
toDomElement.addEventListener('click', listener);
|
||||
break;
|
||||
|
|
@ -181,7 +181,7 @@ export class BrowserRenderer {
|
|||
// just to establish that we can pass parameters when raising events.
|
||||
// We use C#-style PascalCase on the eventInfo to simplify deserialization, but this could
|
||||
// change if we introduced a richer JSON library on the .NET side.
|
||||
raiseEvent(browserRendererId, componentId, attributeNodeIndex, 'keyboard', { Type: evt.type, Key: (evt as any).key });
|
||||
raiseEvent(browserRendererId, componentId, attributeFrameIndex, 'keyboard', { Type: evt.type, Key: (evt as any).key });
|
||||
};
|
||||
toDomElement['_blazorKeypressListener'] = listener;
|
||||
toDomElement.addEventListener('keypress', listener);
|
||||
|
|
@ -191,20 +191,20 @@ export class BrowserRenderer {
|
|||
// Treat as a regular string-valued attribute
|
||||
toDomElement.setAttribute(
|
||||
attributeName,
|
||||
renderTreeNode.attributeValue(attributeNode)!
|
||||
renderTreeFrame.attributeValue(attributeFrame)!
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
insertNodeRange(componentId: number, parent: Element, childIndex: number, nodes: System_Array<RenderTreeNodePointer>, startIndex: number, endIndex: number) {
|
||||
insertFrameRange(componentId: number, parent: Element, childIndex: number, frames: System_Array<RenderTreeFramePointer>, startIndex: number, endIndex: number) {
|
||||
for (let index = startIndex; index <= endIndex; index++) {
|
||||
const node = getTreeNodePtr(nodes, index);
|
||||
this.insertNode(componentId, parent, childIndex, nodes, node, index);
|
||||
const frame = getTreeFramePtr(frames, index);
|
||||
this.insertFrame(componentId, parent, childIndex, frames, frame, index);
|
||||
childIndex++;
|
||||
|
||||
// Skip over any descendants, since they are already dealt with recursively
|
||||
const descendantsEndIndex = renderTreeNode.descendantsEndIndex(node);
|
||||
const descendantsEndIndex = renderTreeFrame.descendantsEndIndex(frame);
|
||||
if (descendantsEndIndex > 0) {
|
||||
index = descendantsEndIndex;
|
||||
}
|
||||
|
|
@ -229,7 +229,7 @@ function removeAttributeFromDOM(parent: Element, childIndex: number, attributeNa
|
|||
element.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
function raiseEvent(browserRendererId: number, componentId: number, renderTreeNodeIndex: number, eventInfoType: EventInfoType, eventInfo: any) {
|
||||
function raiseEvent(browserRendererId: number, componentId: number, renderTreeFrameIndex: number, eventInfoType: EventInfoType, eventInfo: any) {
|
||||
if (!raiseEventMethod) {
|
||||
raiseEventMethod = platform.findMethod(
|
||||
'Microsoft.AspNetCore.Blazor.Browser', 'Microsoft.AspNetCore.Blazor.Browser.Rendering', 'BrowserRendererEventDispatcher', 'DispatchEvent'
|
||||
|
|
@ -239,7 +239,7 @@ function raiseEvent(browserRendererId: number, componentId: number, renderTreeNo
|
|||
const eventDescriptor = {
|
||||
BrowserRendererId: browserRendererId,
|
||||
ComponentId: componentId,
|
||||
RenderTreeNodeIndex: renderTreeNodeIndex,
|
||||
RenderTreeFrameIndex: renderTreeFrameIndex,
|
||||
EventArgsType: eventInfoType
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Pointer, System_Array } from '../Platform/Platform';
|
||||
import { platform } from '../Environment';
|
||||
import { RenderTreeNodePointer } from './RenderTreeNode';
|
||||
import { RenderTreeFramePointer } from './RenderTreeFrame';
|
||||
import { RenderTreeEditPointer } from './RenderTreeEdit';
|
||||
|
||||
// Keep in sync with the structs in .NET code
|
||||
|
|
@ -20,7 +20,7 @@ export const renderTreeDiffStructLength = 4 + 2 * arrayRangeStructLength;
|
|||
export const renderTreeDiff = {
|
||||
componentId: (obj: RenderTreeDiffPointer) => platform.readInt32Field(obj, 0),
|
||||
edits: (obj: RenderTreeDiffPointer) => platform.readStructField<ArrayRangePointer<RenderTreeEditPointer>>(obj, 4),
|
||||
currentState: (obj: RenderTreeDiffPointer) => platform.readStructField<ArrayRangePointer<RenderTreeNodePointer>>(obj, 4 + arrayRangeStructLength),
|
||||
currentState: (obj: RenderTreeDiffPointer) => platform.readStructField<ArrayRangePointer<RenderTreeFramePointer>>(obj, 4 + arrayRangeStructLength),
|
||||
};
|
||||
|
||||
// Nominal types to ensure only valid pointers are passed to the functions above.
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ export const renderTreeEdit = {
|
|||
};
|
||||
|
||||
export enum EditType {
|
||||
prependNode = 1,
|
||||
removeNode = 2,
|
||||
prependFrame = 1,
|
||||
removeFrame = 2,
|
||||
setAttribute = 3,
|
||||
removeAttribute = 4,
|
||||
updateText = 5,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
import { System_String, System_Array, Pointer } from '../Platform/Platform';
|
||||
import { platform } from '../Environment';
|
||||
const renderTreeFrameStructLength = 40;
|
||||
|
||||
// To minimise GC pressure, instead of instantiating a JS object to represent each tree frame,
|
||||
// we work in terms of pointers to the structs on the .NET heap, and use static functions that
|
||||
// know how to read property values from those structs.
|
||||
|
||||
export function getTreeFramePtr(renderTreeEntries: System_Array<RenderTreeFramePointer>, index: number) {
|
||||
return platform.getArrayEntryPtr(renderTreeEntries, index, renderTreeFrameStructLength);
|
||||
}
|
||||
|
||||
export const renderTreeFrame = {
|
||||
// The properties and memory layout must be kept in sync with the .NET equivalent in RenderTreeFrame.cs
|
||||
frameType: (frame: RenderTreeFramePointer) => platform.readInt32Field(frame, 4) as FrameType,
|
||||
elementName: (frame: RenderTreeFramePointer) => platform.readStringField(frame, 8),
|
||||
descendantsEndIndex: (frame: RenderTreeFramePointer) => platform.readInt32Field(frame, 12) as FrameType,
|
||||
textContent: (frame: RenderTreeFramePointer) => platform.readStringField(frame, 16),
|
||||
attributeName: (frame: RenderTreeFramePointer) => platform.readStringField(frame, 20),
|
||||
attributeValue: (frame: RenderTreeFramePointer) => platform.readStringField(frame, 24),
|
||||
componentId: (frame: RenderTreeFramePointer) => platform.readInt32Field(frame, 32),
|
||||
};
|
||||
|
||||
export enum FrameType {
|
||||
// The values must be kept in sync with the .NET equivalent in RenderTreeFrameType.cs
|
||||
element = 1,
|
||||
text = 2,
|
||||
attribute = 3,
|
||||
component = 4,
|
||||
}
|
||||
|
||||
// Nominal type to ensure only valid pointers are passed to the renderTreeFrame functions.
|
||||
// At runtime the values are just numbers.
|
||||
export interface RenderTreeFramePointer extends Pointer { RenderTreeFramePointer__DO_NOT_IMPLEMENT: any }
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
import { System_String, System_Array, Pointer } from '../Platform/Platform';
|
||||
import { platform } from '../Environment';
|
||||
const renderTreeNodeStructLength = 40;
|
||||
|
||||
// To minimise GC pressure, instead of instantiating a JS object to represent each tree node,
|
||||
// we work in terms of pointers to the structs on the .NET heap, and use static functions that
|
||||
// know how to read property values from those structs.
|
||||
|
||||
export function getTreeNodePtr(renderTreeEntries: System_Array<RenderTreeNodePointer>, index: number) {
|
||||
return platform.getArrayEntryPtr(renderTreeEntries, index, renderTreeNodeStructLength);
|
||||
}
|
||||
|
||||
export const renderTreeNode = {
|
||||
// The properties and memory layout must be kept in sync with the .NET equivalent in RenderTreeNode.cs
|
||||
nodeType: (node: RenderTreeNodePointer) => platform.readInt32Field(node, 4) as NodeType,
|
||||
elementName: (node: RenderTreeNodePointer) => platform.readStringField(node, 8),
|
||||
descendantsEndIndex: (node: RenderTreeNodePointer) => platform.readInt32Field(node, 12) as NodeType,
|
||||
textContent: (node: RenderTreeNodePointer) => platform.readStringField(node, 16),
|
||||
attributeName: (node: RenderTreeNodePointer) => platform.readStringField(node, 20),
|
||||
attributeValue: (node: RenderTreeNodePointer) => platform.readStringField(node, 24),
|
||||
componentId: (node: RenderTreeNodePointer) => platform.readInt32Field(node, 32),
|
||||
};
|
||||
|
||||
export enum NodeType {
|
||||
// The values must be kept in sync with the .NET equivalent in RenderTreeNodeType.cs
|
||||
element = 1,
|
||||
text = 2,
|
||||
attribute = 3,
|
||||
component = 4,
|
||||
}
|
||||
|
||||
// Nominal type to ensure only valid pointers are passed to the renderTreeNode functions.
|
||||
// At runtime the values are just numbers.
|
||||
export interface RenderTreeNodePointer extends Pointer { RenderTreeNodePointer__DO_NOT_IMPLEMENT: any }
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
import { System_Object, System_String, System_Array, MethodHandle, Pointer } from '../Platform/Platform';
|
||||
import { platform } from '../Environment';
|
||||
import { getTreeNodePtr, renderTreeNode, NodeType, RenderTreeNodePointer } from './RenderTreeNode';
|
||||
import { RenderTreeEditPointer } from './RenderTreeEdit';
|
||||
import { renderBatch as renderBatchStruct, arrayRange, renderTreeDiffStructLength, renderTreeDiff, RenderBatchPointer, RenderTreeDiffPointer } from './RenderBatch';
|
||||
import { BrowserRenderer } from './BrowserRenderer';
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Rendering
|
|||
var browserRenderer = BrowserRendererRegistry.Find(eventDescriptor.BrowserRendererId);
|
||||
browserRenderer.DispatchBrowserEvent(
|
||||
eventDescriptor.ComponentId,
|
||||
eventDescriptor.RenderTreeNodeIndex,
|
||||
eventDescriptor.RenderTreeFrameIndex,
|
||||
eventArgs);
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Rendering
|
|||
{
|
||||
public int BrowserRendererId { get; set; }
|
||||
public int ComponentId { get; set; }
|
||||
public int RenderTreeNodeIndex { get; set; }
|
||||
public int RenderTreeFrameIndex { get; set; }
|
||||
public string EventArgsType { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Core.RazorCompilation.Engine
|
|||
// To support syntax like <elem @completeAttributePair /> (which in turn supports syntax
|
||||
// like <elem @OnSomeEvent(Handler) />), check whether we are currently in the middle of
|
||||
// writing an element. If so, treat this C# expression as something that should evaluate
|
||||
// as a RenderTreeNode of type Attribute.
|
||||
// as a RenderTreeFrame of type Attribute.
|
||||
if (_unconsumedHtml != null)
|
||||
{
|
||||
var token = (IntermediateToken)node.Children.Single();
|
||||
|
|
@ -197,7 +197,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Core.RazorCompilation.Engine
|
|||
var codeWriter = context.CodeWriter;
|
||||
|
||||
// TODO: As an optimization, identify static subtrees (i.e., HTML elements in the Razor source
|
||||
// that contain no C#) and represent them as a new RenderTreeNodeType called StaticElement or
|
||||
// that contain no C#) and represent them as a new RenderTreeFrameType called StaticElement or
|
||||
// similar. This means you can have arbitrarily deep static subtrees without paying any per-
|
||||
// node cost during rendering or diffing.
|
||||
HtmlToken nextToken;
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ namespace Microsoft.AspNetCore.Blazor.Components
|
|||
/// Handles click events by invoking <paramref name="handler"/>.
|
||||
/// </summary>
|
||||
/// <param name="handler">The handler to be invoked when the event occurs.</param>
|
||||
/// <returns>A <see cref="RenderTreeNode"/> that represents the event handler.</returns>
|
||||
protected RenderTreeNode onclick(Action handler)
|
||||
/// <returns>A <see cref="RenderTreeFrame"/> that represents the event handler.</returns>
|
||||
protected RenderTreeFrame onclick(Action handler)
|
||||
// Note that the 'sequence' value is updated later when inserted into the tree
|
||||
=> RenderTreeNode.Attribute(0, "onclick", _ => handler());
|
||||
=> RenderTreeFrame.Attribute(0, "onclick", _ => handler());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Blazor.Components
|
|||
/// <summary>
|
||||
/// Builds a <see cref="RenderTree"/> representing the current state of the component.
|
||||
/// </summary>
|
||||
/// <param name="builder">A <see cref="RenderTreeBuilder"/> to which the rendered nodes should be appended.</param>
|
||||
/// <param name="builder">A <see cref="RenderTreeBuilder"/> to which the rendered frames should be appended.</param>
|
||||
void BuildRenderTree(RenderTreeBuilder builder);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ using System.Collections.Generic;
|
|||
namespace Microsoft.AspNetCore.Blazor.RenderTree
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods for building a collection of <see cref="RenderTreeNode"/> entries.
|
||||
/// Provides methods for building a collection of <see cref="RenderTreeFrame"/> entries.
|
||||
/// </summary>
|
||||
public class RenderTreeBuilder
|
||||
{
|
||||
private readonly Renderer _renderer;
|
||||
private readonly ArrayBuilder<RenderTreeNode> _entries = new ArrayBuilder<RenderTreeNode>(10);
|
||||
private readonly ArrayBuilder<RenderTreeFrame> _entries = new ArrayBuilder<RenderTreeFrame>(10);
|
||||
private readonly Stack<int> _openElementIndices = new Stack<int>();
|
||||
private RenderTreeNodeType? _lastNonAttributeNodeType;
|
||||
private RenderTreeFrameType? _lastNonAttributeFrameType;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an instance of <see cref="RenderTreeBuilder"/>.
|
||||
|
|
@ -28,21 +28,21 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends a node representing an element, i.e., a container for other nodes.
|
||||
/// Appends a frame representing an element, i.e., a container for other frames.
|
||||
/// In order for the <see cref="RenderTreeBuilder"/> state to be valid, you must
|
||||
/// also call <see cref="CloseElement"/> immediately after appending the
|
||||
/// new element's child nodes.
|
||||
/// new element's child frames.
|
||||
/// </summary>
|
||||
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
|
||||
/// <param name="elementName">A value representing the type of the element.</param>
|
||||
public void OpenElement(int sequence, string elementName)
|
||||
{
|
||||
_openElementIndices.Push(_entries.Count);
|
||||
Append(RenderTreeNode.Element(sequence, elementName));
|
||||
Append(RenderTreeFrame.Element(sequence, elementName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks a previously appended element node as closed. Calls to this method
|
||||
/// Marks a previously appended element frame as closed. Calls to this method
|
||||
/// must be balanced with calls to <see cref="OpenElement(string)"/>.
|
||||
/// </summary>
|
||||
public void CloseElement()
|
||||
|
|
@ -52,23 +52,23 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends a node representing text content.
|
||||
/// Appends a frame representing text content.
|
||||
/// </summary>
|
||||
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
|
||||
/// <param name="textContent">Content for the new text node.</param>
|
||||
/// <param name="textContent">Content for the new text frame.</param>
|
||||
public void AddText(int sequence, string textContent)
|
||||
=> Append(RenderTreeNode.Text(sequence, textContent));
|
||||
=> Append(RenderTreeFrame.Text(sequence, textContent));
|
||||
|
||||
/// <summary>
|
||||
/// Appends a node representing text content.
|
||||
/// Appends a frame representing text content.
|
||||
/// </summary>
|
||||
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
|
||||
/// <param name="textContent">Content for the new text node.</param>
|
||||
/// <param name="textContent">Content for the new text frame.</param>
|
||||
public void AddText(int sequence, object textContent)
|
||||
=> AddText(sequence, textContent?.ToString());
|
||||
|
||||
/// <summary>
|
||||
/// Appends a node representing a string-valued attribute.
|
||||
/// Appends a frame representing a string-valued attribute.
|
||||
/// The attribute is associated with the most recently added element.
|
||||
/// </summary>
|
||||
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
|
||||
|
|
@ -77,11 +77,11 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
public void AddAttribute(int sequence, string name, string value)
|
||||
{
|
||||
AssertCanAddAttribute();
|
||||
Append(RenderTreeNode.Attribute(sequence, name, value));
|
||||
Append(RenderTreeFrame.Attribute(sequence, name, value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends a node representing an <see cref="UIEventArgs"/>-valued attribute.
|
||||
/// Appends a frame representing an <see cref="UIEventArgs"/>-valued attribute.
|
||||
/// The attribute is associated with the most recently added element.
|
||||
/// </summary>
|
||||
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
|
||||
|
|
@ -90,11 +90,11 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
public void AddAttribute(int sequence, string name, UIEventHandler value)
|
||||
{
|
||||
AssertCanAddAttribute();
|
||||
Append(RenderTreeNode.Attribute(sequence, name, value));
|
||||
Append(RenderTreeFrame.Attribute(sequence, name, value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends a node representing a string-valued attribute.
|
||||
/// Appends a frame representing a string-valued attribute.
|
||||
/// The attribute is associated with the most recently added element.
|
||||
/// </summary>
|
||||
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
|
||||
|
|
@ -102,14 +102,14 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
/// <param name="value">The value of the attribute.</param>
|
||||
public void AddAttribute(int sequence, string name, object value)
|
||||
{
|
||||
if (_lastNonAttributeNodeType == RenderTreeNodeType.Element)
|
||||
if (_lastNonAttributeFrameType == RenderTreeFrameType.Element)
|
||||
{
|
||||
// Element attribute values can only be strings or UIEventHandler
|
||||
Append(RenderTreeNode.Attribute(sequence, name, value.ToString()));
|
||||
Append(RenderTreeFrame.Attribute(sequence, name, value.ToString()));
|
||||
}
|
||||
else if (_lastNonAttributeNodeType == RenderTreeNodeType.Component)
|
||||
else if (_lastNonAttributeFrameType == RenderTreeFrameType.Component)
|
||||
{
|
||||
Append(RenderTreeNode.Attribute(sequence, name, value));
|
||||
Append(RenderTreeFrame.Attribute(sequence, name, value));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -119,26 +119,26 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends a node representing an attribute.
|
||||
/// Appends a frame representing an attribute.
|
||||
/// The attribute is associated with the most recently added element.
|
||||
/// </summary>
|
||||
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
|
||||
/// <param name="name">The name of the attribute.</param>
|
||||
/// <param name="value">The value of the attribute.</param>
|
||||
public void AddAttribute(int sequence, RenderTreeNode node)
|
||||
public void AddAttribute(int sequence, RenderTreeFrame frame)
|
||||
{
|
||||
if (node.NodeType != RenderTreeNodeType.Attribute)
|
||||
if (frame.FrameType != RenderTreeFrameType.Attribute)
|
||||
{
|
||||
throw new ArgumentException($"The {nameof(node.NodeType)} must be {RenderTreeNodeType.Attribute}.");
|
||||
throw new ArgumentException($"The {nameof(frame.FrameType)} must be {RenderTreeFrameType.Attribute}.");
|
||||
}
|
||||
|
||||
AssertCanAddAttribute();
|
||||
node.SetSequence(sequence);
|
||||
Append(node);
|
||||
frame.SetSequence(sequence);
|
||||
Append(frame);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends a node representing a child component.
|
||||
/// Appends a frame representing a child component.
|
||||
/// </summary>
|
||||
/// <typeparam name="TComponent">The type of the child component.</typeparam>
|
||||
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
|
||||
|
|
@ -146,21 +146,21 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
{
|
||||
// Currently, child components can't have further grandchildren of their own, so it would
|
||||
// technically be possible to skip their CloseElement calls and not track them in _openElementIndices.
|
||||
// However at some point we might want to have the grandchildren nodes available at runtime
|
||||
// However at some point we might want to have the grandchildren frames available at runtime
|
||||
// (rather than being parsed as attributes at compile time) so that we could have APIs for
|
||||
// components to query the complete hierarchy of transcluded nodes instead of forcing the
|
||||
// components to query the complete hierarchy of transcluded frames instead of forcing the
|
||||
// transcluded subtree to be in a particular shape such as representing key/value pairs.
|
||||
// So it's more flexible if we track open/close nodes for components explicitly.
|
||||
// So it's more flexible if we track open/close frames for components explicitly.
|
||||
_openElementIndices.Push(_entries.Count);
|
||||
Append(RenderTreeNode.ChildComponent<TComponent>(sequence));
|
||||
Append(RenderTreeFrame.ChildComponent<TComponent>(sequence));
|
||||
}
|
||||
|
||||
private void AssertCanAddAttribute()
|
||||
{
|
||||
if (_lastNonAttributeNodeType != RenderTreeNodeType.Element
|
||||
&& _lastNonAttributeNodeType != RenderTreeNodeType.Component)
|
||||
if (_lastNonAttributeFrameType != RenderTreeFrameType.Element
|
||||
&& _lastNonAttributeFrameType != RenderTreeFrameType.Component)
|
||||
{
|
||||
throw new InvalidOperationException($"Attributes may only be added immediately after nodes of type {RenderTreeNodeType.Element} or {RenderTreeNodeType.Component}");
|
||||
throw new InvalidOperationException($"Attributes may only be added immediately after frames of type {RenderTreeFrameType.Element} or {RenderTreeFrameType.Component}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,24 +171,24 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
{
|
||||
_entries.Clear();
|
||||
_openElementIndices.Clear();
|
||||
_lastNonAttributeNodeType = null;
|
||||
_lastNonAttributeFrameType = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="RenderTreeNode"/> values that have been appended.
|
||||
/// Returns the <see cref="RenderTreeFrame"/> values that have been appended.
|
||||
/// </summary>
|
||||
/// <returns>An array range of <see cref="RenderTreeNode"/> values.</returns>
|
||||
public ArrayRange<RenderTreeNode> GetNodes() =>
|
||||
/// <returns>An array range of <see cref="RenderTreeFrame"/> values.</returns>
|
||||
public ArrayRange<RenderTreeFrame> GetFrames() =>
|
||||
_entries.ToRange();
|
||||
|
||||
private void Append(in RenderTreeNode node)
|
||||
private void Append(in RenderTreeFrame frame)
|
||||
{
|
||||
_entries.Append(node);
|
||||
_entries.Append(frame);
|
||||
|
||||
var nodeType = node.NodeType;
|
||||
if (nodeType != RenderTreeNodeType.Attribute)
|
||||
var frameType = frame.FrameType;
|
||||
if (frameType != RenderTreeFrameType.Attribute)
|
||||
{
|
||||
_lastNonAttributeNodeType = node.NodeType;
|
||||
_lastNonAttributeFrameType = frame.FrameType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,12 +25,12 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
/// Gets the latest render tree. That is, the result of applying the <see cref="Edits"/>
|
||||
/// to the previous state.
|
||||
/// </summary>
|
||||
public ArrayRange<RenderTreeNode> CurrentState { get; }
|
||||
public ArrayRange<RenderTreeFrame> CurrentState { get; }
|
||||
|
||||
internal RenderTreeDiff(
|
||||
int componentId,
|
||||
ArrayRange<RenderTreeEdit> entries,
|
||||
ArrayRange<RenderTreeNode> referenceTree)
|
||||
ArrayRange<RenderTreeFrame> referenceTree)
|
||||
{
|
||||
ComponentId = componentId;
|
||||
Edits = entries;
|
||||
|
|
|
|||
|
|
@ -20,15 +20,15 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
|
||||
/// <summary>
|
||||
/// As well as computing the diff between the two trees, this method also has the side-effect
|
||||
/// of instantiating child components on newly-inserted Component nodes, and copying the existing
|
||||
/// component instances onto retained Component nodes. It's particularly convenient to do that
|
||||
/// of instantiating child components on newly-inserted Component frames, and copying the existing
|
||||
/// component instances onto retained Component frames. It's particularly convenient to do that
|
||||
/// here because we have the right information and are already walking the trees to do the diff.
|
||||
/// </summary>
|
||||
public void ApplyNewRenderTreeVersion(
|
||||
RenderBatchBuilder batchBuilder,
|
||||
int componentId,
|
||||
ArrayRange<RenderTreeNode> oldTree,
|
||||
ArrayRange<RenderTreeNode> newTree)
|
||||
ArrayRange<RenderTreeFrame> oldTree,
|
||||
ArrayRange<RenderTreeFrame> newTree)
|
||||
{
|
||||
_entries.Clear();
|
||||
var siblingIndex = 0;
|
||||
|
|
@ -42,8 +42,8 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
|
||||
private void AppendDiffEntriesForRange(
|
||||
RenderBatchBuilder batchBuilder,
|
||||
RenderTreeNode[] oldTree, int oldStartIndex, int oldEndIndexExcl,
|
||||
RenderTreeNode[] newTree, int newStartIndex, int newEndIndexExcl,
|
||||
RenderTreeFrame[] oldTree, int oldStartIndex, int oldEndIndexExcl,
|
||||
RenderTreeFrame[] newTree, int newStartIndex, int newEndIndexExcl,
|
||||
ref int siblingIndex)
|
||||
{
|
||||
var hasMoreOld = oldEndIndexExcl > oldStartIndex;
|
||||
|
|
@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
|
||||
if (oldSeq == newSeq)
|
||||
{
|
||||
AppendDiffEntriesForNodesWithSameSequence(batchBuilder, oldTree, oldStartIndex, newTree, newStartIndex, ref siblingIndex);
|
||||
AppendDiffEntriesForFramesWithSameSequence(batchBuilder, oldTree, oldStartIndex, newTree, newStartIndex, ref siblingIndex);
|
||||
oldStartIndex = NextSiblingIndex(oldTree[oldStartIndex], oldStartIndex);
|
||||
newStartIndex = NextSiblingIndex(newTree[newStartIndex], newStartIndex);
|
||||
hasMoreOld = oldEndIndexExcl > oldStartIndex;
|
||||
|
|
@ -132,22 +132,22 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
|
||||
if (treatAsInsert)
|
||||
{
|
||||
ref var newNode = ref newTree[newStartIndex];
|
||||
var newNodeType = newNode.NodeType;
|
||||
if (newNodeType == RenderTreeNodeType.Attribute)
|
||||
ref var newFrame = ref newTree[newStartIndex];
|
||||
var newFrameType = newFrame.FrameType;
|
||||
if (newFrameType == RenderTreeFrameType.Attribute)
|
||||
{
|
||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, newStartIndex));
|
||||
newStartIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newNodeType == RenderTreeNodeType.Element || newNodeType == RenderTreeNodeType.Component)
|
||||
if (newFrameType == RenderTreeFrameType.Element || newFrameType == RenderTreeFrameType.Component)
|
||||
{
|
||||
InstantiateChildComponents(batchBuilder, newTree, newStartIndex);
|
||||
}
|
||||
|
||||
Append(RenderTreeEdit.PrependNode(siblingIndex, newStartIndex));
|
||||
newStartIndex = NextSiblingIndex(newNode, newStartIndex);
|
||||
Append(RenderTreeEdit.PrependFrame(siblingIndex, newStartIndex));
|
||||
newStartIndex = NextSiblingIndex(newFrame, newStartIndex);
|
||||
siblingIndex++;
|
||||
}
|
||||
|
||||
|
|
@ -156,22 +156,22 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
}
|
||||
else
|
||||
{
|
||||
ref var oldNode = ref oldTree[oldStartIndex];
|
||||
var oldNodeType = oldNode.NodeType;
|
||||
if (oldNodeType == RenderTreeNodeType.Attribute)
|
||||
ref var oldFrame = ref oldTree[oldStartIndex];
|
||||
var oldFrameType = oldFrame.FrameType;
|
||||
if (oldFrameType == RenderTreeFrameType.Attribute)
|
||||
{
|
||||
Append(RenderTreeEdit.RemoveAttribute(siblingIndex, oldNode.AttributeName));
|
||||
Append(RenderTreeEdit.RemoveAttribute(siblingIndex, oldFrame.AttributeName));
|
||||
oldStartIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (oldNodeType == RenderTreeNodeType.Element || oldNodeType == RenderTreeNodeType.Component)
|
||||
if (oldFrameType == RenderTreeFrameType.Element || oldFrameType == RenderTreeFrameType.Component)
|
||||
{
|
||||
DisposeChildComponents(batchBuilder, oldTree, oldStartIndex);
|
||||
}
|
||||
|
||||
Append(RenderTreeEdit.RemoveNode(siblingIndex));
|
||||
oldStartIndex = NextSiblingIndex(oldNode, oldStartIndex);
|
||||
Append(RenderTreeEdit.RemoveFrame(siblingIndex));
|
||||
oldStartIndex = NextSiblingIndex(oldFrame, oldStartIndex);
|
||||
}
|
||||
hasMoreOld = oldEndIndexExcl > oldStartIndex;
|
||||
prevOldSeq = oldSeq;
|
||||
|
|
@ -182,28 +182,28 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
|
||||
private void UpdateRetainedChildComponent(
|
||||
RenderBatchBuilder batchBuilder,
|
||||
RenderTreeNode[] oldTree, int oldComponentIndex,
|
||||
RenderTreeNode[] newTree, int newComponentIndex)
|
||||
RenderTreeFrame[] oldTree, int oldComponentIndex,
|
||||
RenderTreeFrame[] newTree, int newComponentIndex)
|
||||
{
|
||||
// The algorithm here is the same as in AppendDiffEntriesForRange, except that
|
||||
// here we don't optimise for loops - we assume that both sequences are forward-only.
|
||||
// That's because this is true for all currently supported scenarios, and it means
|
||||
// fewer steps here.
|
||||
|
||||
ref var oldComponentNode = ref oldTree[oldComponentIndex];
|
||||
ref var newComponentNode = ref newTree[newComponentIndex];
|
||||
var componentId = oldComponentNode.ComponentId;
|
||||
var componentInstance = oldComponentNode.Component;
|
||||
ref var oldComponentFrame = ref oldTree[oldComponentIndex];
|
||||
ref var newComponentFrame = ref newTree[newComponentIndex];
|
||||
var componentId = oldComponentFrame.ComponentId;
|
||||
var componentInstance = oldComponentFrame.Component;
|
||||
var hasSetAnyProperty = false;
|
||||
|
||||
// Preserve the actual componentInstance
|
||||
newComponentNode.SetChildComponentInstance(componentId, componentInstance);
|
||||
newComponentFrame.SetChildComponentInstance(componentId, componentInstance);
|
||||
|
||||
// Now locate any added/changed/removed properties
|
||||
var oldStartIndex = oldComponentIndex + 1;
|
||||
var newStartIndex = newComponentIndex + 1;
|
||||
var oldEndIndexIncl = oldComponentNode.ElementDescendantsEndIndex;
|
||||
var newEndIndexIncl = newComponentNode.ElementDescendantsEndIndex;
|
||||
var oldEndIndexIncl = oldComponentFrame.ElementDescendantsEndIndex;
|
||||
var newEndIndexIncl = newComponentFrame.ElementDescendantsEndIndex;
|
||||
var hasMoreOld = oldEndIndexIncl >= oldStartIndex;
|
||||
var hasMoreNew = newEndIndexIncl >= newStartIndex;
|
||||
while (hasMoreOld || hasMoreNew)
|
||||
|
|
@ -213,15 +213,15 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
|
||||
if (oldSeq == newSeq)
|
||||
{
|
||||
ref var oldNode = ref oldTree[oldStartIndex];
|
||||
ref var newNode = ref newTree[newStartIndex];
|
||||
var oldName = oldNode.AttributeName;
|
||||
var newName = newNode.AttributeName;
|
||||
var newPropertyValue = newNode.AttributeValue;
|
||||
ref var oldFrame = ref oldTree[oldStartIndex];
|
||||
ref var newFrame = ref newTree[newStartIndex];
|
||||
var oldName = oldFrame.AttributeName;
|
||||
var newName = newFrame.AttributeName;
|
||||
var newPropertyValue = newFrame.AttributeValue;
|
||||
if (string.Equals(oldName, newName, StringComparison.Ordinal))
|
||||
{
|
||||
// Using Equals to account for string comparisons, nulls, etc.
|
||||
var oldPropertyValue = oldNode.AttributeValue;
|
||||
var oldPropertyValue = oldFrame.AttributeValue;
|
||||
if (!Equals(oldPropertyValue, newPropertyValue))
|
||||
{
|
||||
SetChildComponentProperty(componentInstance, newName, newPropertyValue);
|
||||
|
|
@ -252,16 +252,16 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
|
||||
if (treatAsInsert)
|
||||
{
|
||||
ref var newNode = ref newTree[newStartIndex];
|
||||
SetChildComponentProperty(componentInstance, newNode.AttributeName, newNode.AttributeValue);
|
||||
ref var newFrame = ref newTree[newStartIndex];
|
||||
SetChildComponentProperty(componentInstance, newFrame.AttributeName, newFrame.AttributeValue);
|
||||
hasSetAnyProperty = true;
|
||||
newStartIndex++;
|
||||
hasMoreNew = newEndIndexIncl >= newStartIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
ref var oldNode = ref oldTree[oldStartIndex];
|
||||
RemoveChildComponentProperty(componentInstance, oldNode.AttributeName);
|
||||
ref var oldFrame = ref oldTree[oldStartIndex];
|
||||
RemoveChildComponentProperty(componentInstance, oldFrame.AttributeName);
|
||||
hasSetAnyProperty = true;
|
||||
oldStartIndex++;
|
||||
hasMoreOld = oldEndIndexIncl >= oldStartIndex;
|
||||
|
|
@ -271,7 +271,7 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
|
||||
if (hasSetAnyProperty)
|
||||
{
|
||||
TriggerChildComponentRender(batchBuilder, newComponentNode);
|
||||
TriggerChildComponentRender(batchBuilder, newComponentFrame);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -312,67 +312,67 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
return property;
|
||||
}
|
||||
|
||||
private static int NextSiblingIndex(in RenderTreeNode node, int nodeIndex)
|
||||
private static int NextSiblingIndex(in RenderTreeFrame frame, int frameIndex)
|
||||
{
|
||||
var descendantsEndIndex = node.ElementDescendantsEndIndex;
|
||||
return (descendantsEndIndex == 0 ? nodeIndex : descendantsEndIndex) + 1;
|
||||
var descendantsEndIndex = frame.ElementDescendantsEndIndex;
|
||||
return (descendantsEndIndex == 0 ? frameIndex : descendantsEndIndex) + 1;
|
||||
}
|
||||
|
||||
private void AppendDiffEntriesForNodesWithSameSequence(
|
||||
private void AppendDiffEntriesForFramesWithSameSequence(
|
||||
RenderBatchBuilder batchBuilder,
|
||||
RenderTreeNode[] oldTree, int oldNodeIndex,
|
||||
RenderTreeNode[] newTree, int newNodeIndex,
|
||||
RenderTreeFrame[] oldTree, int oldFrameIndex,
|
||||
RenderTreeFrame[] newTree, int newFrameIndex,
|
||||
ref int siblingIndex)
|
||||
{
|
||||
ref var oldNode = ref oldTree[oldNodeIndex];
|
||||
ref var newNode = ref newTree[newNodeIndex];
|
||||
ref var oldFrame = ref oldTree[oldFrameIndex];
|
||||
ref var newFrame = ref newTree[newFrameIndex];
|
||||
|
||||
// We can assume that the old and new nodes are of the same type, because they correspond
|
||||
// We can assume that the old and new frames are of the same type, because they correspond
|
||||
// to the same sequence number (and if not, the behaviour is undefined).
|
||||
switch (newTree[newNodeIndex].NodeType)
|
||||
switch (newTree[newFrameIndex].FrameType)
|
||||
{
|
||||
case RenderTreeNodeType.Text:
|
||||
case RenderTreeFrameType.Text:
|
||||
{
|
||||
var oldText = oldNode.TextContent;
|
||||
var newText = newNode.TextContent;
|
||||
var oldText = oldFrame.TextContent;
|
||||
var newText = newFrame.TextContent;
|
||||
if (!string.Equals(oldText, newText, StringComparison.Ordinal))
|
||||
{
|
||||
Append(RenderTreeEdit.UpdateText(siblingIndex, newNodeIndex));
|
||||
Append(RenderTreeEdit.UpdateText(siblingIndex, newFrameIndex));
|
||||
}
|
||||
siblingIndex++;
|
||||
break;
|
||||
}
|
||||
|
||||
case RenderTreeNodeType.Element:
|
||||
case RenderTreeFrameType.Element:
|
||||
{
|
||||
var oldElementName = oldNode.ElementName;
|
||||
var newElementName = newNode.ElementName;
|
||||
var oldElementName = oldFrame.ElementName;
|
||||
var newElementName = newFrame.ElementName;
|
||||
if (string.Equals(oldElementName, newElementName, StringComparison.Ordinal))
|
||||
{
|
||||
var oldNodeAttributesEndIndexExcl = GetAttributesEndIndexExclusive(oldTree, oldNodeIndex);
|
||||
var newNodeAttributesEndIndexExcl = GetAttributesEndIndexExclusive(newTree, newNodeIndex);
|
||||
var oldFrameAttributesEndIndexExcl = GetAttributesEndIndexExclusive(oldTree, oldFrameIndex);
|
||||
var newFrameAttributesEndIndexExcl = GetAttributesEndIndexExclusive(newTree, newFrameIndex);
|
||||
|
||||
// Diff the attributes
|
||||
AppendDiffEntriesForRange(
|
||||
batchBuilder,
|
||||
oldTree, oldNodeIndex + 1, oldNodeAttributesEndIndexExcl,
|
||||
newTree, newNodeIndex + 1, newNodeAttributesEndIndexExcl,
|
||||
oldTree, oldFrameIndex + 1, oldFrameAttributesEndIndexExcl,
|
||||
newTree, newFrameIndex + 1, newFrameAttributesEndIndexExcl,
|
||||
ref siblingIndex);
|
||||
|
||||
// Diff the children
|
||||
var oldNodeChildrenEndIndexExcl = oldNode.ElementDescendantsEndIndex + 1;
|
||||
var newNodeChildrenEndIndexExcl = newNode.ElementDescendantsEndIndex + 1;
|
||||
var oldFrameChildrenEndIndexExcl = oldFrame.ElementDescendantsEndIndex + 1;
|
||||
var newFrameChildrenEndIndexExcl = newFrame.ElementDescendantsEndIndex + 1;
|
||||
var hasChildrenToProcess =
|
||||
oldNodeChildrenEndIndexExcl > oldNodeAttributesEndIndexExcl ||
|
||||
newNodeChildrenEndIndexExcl > newNodeAttributesEndIndexExcl;
|
||||
oldFrameChildrenEndIndexExcl > oldFrameAttributesEndIndexExcl ||
|
||||
newFrameChildrenEndIndexExcl > newFrameAttributesEndIndexExcl;
|
||||
if (hasChildrenToProcess)
|
||||
{
|
||||
Append(RenderTreeEdit.StepIn(siblingIndex));
|
||||
var childSiblingIndex = 0;
|
||||
AppendDiffEntriesForRange(
|
||||
batchBuilder,
|
||||
oldTree, oldNodeAttributesEndIndexExcl, oldNodeChildrenEndIndexExcl,
|
||||
newTree, newNodeAttributesEndIndexExcl, newNodeChildrenEndIndexExcl,
|
||||
oldTree, oldFrameAttributesEndIndexExcl, oldFrameChildrenEndIndexExcl,
|
||||
newTree, newFrameAttributesEndIndexExcl, newFrameChildrenEndIndexExcl,
|
||||
ref childSiblingIndex);
|
||||
Append(RenderTreeEdit.StepOut());
|
||||
siblingIndex++;
|
||||
|
|
@ -385,51 +385,51 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
else
|
||||
{
|
||||
// Elements with different names are treated as completely unrelated
|
||||
InstantiateChildComponents(batchBuilder, newTree, newNodeIndex);
|
||||
DisposeChildComponents(batchBuilder, oldTree, oldNodeIndex);
|
||||
Append(RenderTreeEdit.PrependNode(siblingIndex, newNodeIndex));
|
||||
InstantiateChildComponents(batchBuilder, newTree, newFrameIndex);
|
||||
DisposeChildComponents(batchBuilder, oldTree, oldFrameIndex);
|
||||
Append(RenderTreeEdit.PrependFrame(siblingIndex, newFrameIndex));
|
||||
siblingIndex++;
|
||||
Append(RenderTreeEdit.RemoveNode(siblingIndex));
|
||||
Append(RenderTreeEdit.RemoveFrame(siblingIndex));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RenderTreeNodeType.Component:
|
||||
case RenderTreeFrameType.Component:
|
||||
{
|
||||
var oldComponentType = oldNode.ComponentType;
|
||||
var newComponentType = newNode.ComponentType;
|
||||
var oldComponentType = oldFrame.ComponentType;
|
||||
var newComponentType = newFrame.ComponentType;
|
||||
if (oldComponentType == newComponentType)
|
||||
{
|
||||
UpdateRetainedChildComponent(
|
||||
batchBuilder,
|
||||
oldTree, oldNodeIndex,
|
||||
newTree, newNodeIndex);
|
||||
oldTree, oldFrameIndex,
|
||||
newTree, newFrameIndex);
|
||||
|
||||
siblingIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Child components of different types are treated as completely unrelated
|
||||
InstantiateChildComponents(batchBuilder, newTree, newNodeIndex);
|
||||
DisposeChildComponents(batchBuilder, oldTree, oldNodeIndex);
|
||||
Append(RenderTreeEdit.PrependNode(siblingIndex, newNodeIndex));
|
||||
InstantiateChildComponents(batchBuilder, newTree, newFrameIndex);
|
||||
DisposeChildComponents(batchBuilder, oldTree, oldFrameIndex);
|
||||
Append(RenderTreeEdit.PrependFrame(siblingIndex, newFrameIndex));
|
||||
siblingIndex++;
|
||||
Append(RenderTreeEdit.RemoveNode(siblingIndex));
|
||||
Append(RenderTreeEdit.RemoveFrame(siblingIndex));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RenderTreeNodeType.Attribute:
|
||||
case RenderTreeFrameType.Attribute:
|
||||
{
|
||||
var oldName = oldNode.AttributeName;
|
||||
var newName = newNode.AttributeName;
|
||||
var oldName = oldFrame.AttributeName;
|
||||
var newName = newFrame.AttributeName;
|
||||
if (string.Equals(oldName, newName, StringComparison.Ordinal))
|
||||
{
|
||||
// Using Equals to account for string comparisons, nulls, etc.
|
||||
var valueChanged = !Equals(oldNode.AttributeValue, newNode.AttributeValue);
|
||||
var valueChanged = !Equals(oldFrame.AttributeValue, newFrame.AttributeValue);
|
||||
if (valueChanged)
|
||||
{
|
||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, newNodeIndex));
|
||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, newFrameIndex));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -437,24 +437,24 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
// Since this code path is never reachable for Razor components (because you
|
||||
// can't have two different attribute names from the same source sequence), we
|
||||
// could consider removing the 'name equality' check entirely for perf
|
||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, newNodeIndex));
|
||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, newFrameIndex));
|
||||
Append(RenderTreeEdit.RemoveAttribute(siblingIndex, oldName));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"Encountered unsupported node type during diffing: {newTree[newNodeIndex].NodeType}");
|
||||
throw new NotImplementedException($"Encountered unsupported frame type during diffing: {newTree[newFrameIndex].FrameType}");
|
||||
}
|
||||
}
|
||||
|
||||
private int GetAttributesEndIndexExclusive(RenderTreeNode[] tree, int rootIndex)
|
||||
private int GetAttributesEndIndexExclusive(RenderTreeFrame[] tree, int rootIndex)
|
||||
{
|
||||
var descendantsEndIndex = tree[rootIndex].ElementDescendantsEndIndex;
|
||||
var index = rootIndex + 1;
|
||||
for (; index <= descendantsEndIndex; index++)
|
||||
{
|
||||
if (tree[index].NodeType != RenderTreeNodeType.Attribute)
|
||||
if (tree[index].FrameType != RenderTreeFrameType.Attribute)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -467,7 +467,7 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
{
|
||||
if (entry.Type == RenderTreeEditType.StepOut)
|
||||
{
|
||||
// If the preceding node is a StepIn, then the StepOut cancels it out
|
||||
// If the preceding frame is a StepIn, then the StepOut cancels it out
|
||||
var previousIndex = _entries.Count - 1;
|
||||
if (previousIndex >= 0 && _entries.Buffer[previousIndex].Type == RenderTreeEditType.StepIn)
|
||||
{
|
||||
|
|
@ -479,41 +479,41 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
_entries.Append(entry);
|
||||
}
|
||||
|
||||
private void InstantiateChildComponents(RenderBatchBuilder batchBuilder, RenderTreeNode[] nodes, int elementOrComponentIndex)
|
||||
private void InstantiateChildComponents(RenderBatchBuilder batchBuilder, RenderTreeFrame[] frames, int elementOrComponentIndex)
|
||||
{
|
||||
var endIndex = nodes[elementOrComponentIndex].ElementDescendantsEndIndex;
|
||||
var endIndex = frames[elementOrComponentIndex].ElementDescendantsEndIndex;
|
||||
for (var i = elementOrComponentIndex; i <= endIndex; i++)
|
||||
{
|
||||
ref var node = ref nodes[i];
|
||||
if (node.NodeType == RenderTreeNodeType.Component)
|
||||
ref var frame = ref frames[i];
|
||||
if (frame.FrameType == RenderTreeFrameType.Component)
|
||||
{
|
||||
if (node.Component != null)
|
||||
if (frame.Component != null)
|
||||
{
|
||||
throw new InvalidOperationException($"Child component already exists during {nameof(InstantiateChildComponents)}");
|
||||
}
|
||||
|
||||
_renderer.InstantiateChildComponent(nodes, i);
|
||||
var childComponentInstance = node.Component;
|
||||
_renderer.InstantiateChildComponent(frames, i);
|
||||
var childComponentInstance = frame.Component;
|
||||
|
||||
// All descendants of a component are its properties
|
||||
var componentDescendantsEndIndex = node.ElementDescendantsEndIndex;
|
||||
for (var attributeNodeIndex = i + 1; attributeNodeIndex <= componentDescendantsEndIndex; attributeNodeIndex++)
|
||||
var componentDescendantsEndIndex = frame.ElementDescendantsEndIndex;
|
||||
for (var attributeFrameIndex = i + 1; attributeFrameIndex <= componentDescendantsEndIndex; attributeFrameIndex++)
|
||||
{
|
||||
ref var attributeNode = ref nodes[attributeNodeIndex];
|
||||
ref var attributeFrame = ref frames[attributeFrameIndex];
|
||||
SetChildComponentProperty(
|
||||
childComponentInstance,
|
||||
attributeNode.AttributeName,
|
||||
attributeNode.AttributeValue);
|
||||
attributeFrame.AttributeName,
|
||||
attributeFrame.AttributeValue);
|
||||
}
|
||||
|
||||
TriggerChildComponentRender(batchBuilder, node);
|
||||
TriggerChildComponentRender(batchBuilder, frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerChildComponentRender(RenderBatchBuilder batchBuilder, in RenderTreeNode node)
|
||||
private void TriggerChildComponentRender(RenderBatchBuilder batchBuilder, in RenderTreeFrame frame)
|
||||
{
|
||||
if (node.Component is IHandlePropertiesChanged notifyableComponent)
|
||||
if (frame.Component is IHandlePropertiesChanged notifyableComponent)
|
||||
{
|
||||
// TODO: Ensure any exceptions thrown here are handled equivalently to
|
||||
// unhandled exceptions during rendering.
|
||||
|
|
@ -525,18 +525,18 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
// can control whether any given set of property changes cause re-rendering.
|
||||
// Not doing so yet because it's unclear that the usage patterns would be
|
||||
// good to use.
|
||||
_renderer.RenderInExistingBatch(batchBuilder, node.ComponentId);
|
||||
_renderer.RenderInExistingBatch(batchBuilder, frame.ComponentId);
|
||||
}
|
||||
|
||||
private void DisposeChildComponents(RenderBatchBuilder batchBuilder, RenderTreeNode[] nodes, int elementOrComponentIndex)
|
||||
private void DisposeChildComponents(RenderBatchBuilder batchBuilder, RenderTreeFrame[] frames, int elementOrComponentIndex)
|
||||
{
|
||||
var endIndex = nodes[elementOrComponentIndex].ElementDescendantsEndIndex;
|
||||
var endIndex = frames[elementOrComponentIndex].ElementDescendantsEndIndex;
|
||||
for (var i = elementOrComponentIndex; i <= endIndex; i++)
|
||||
{
|
||||
ref var node = ref nodes[i];
|
||||
if (node.NodeType == RenderTreeNodeType.Component)
|
||||
ref var frame = ref frames[i];
|
||||
if (frame.FrameType == RenderTreeFrameType.Component)
|
||||
{
|
||||
_renderer.DisposeInExistingBatch(batchBuilder, node.ComponentId);
|
||||
_renderer.DisposeInExistingBatch(batchBuilder, frame.ComponentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
public RenderTreeEditType Type { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the sibling node that the edit relates to.
|
||||
/// Gets the index of the sibling frame that the edit relates to.
|
||||
/// </summary>
|
||||
public int SiblingIndex { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of related data in an associated render tree. For example, if the
|
||||
/// <see cref="Type"/> value is <see cref="RenderTreeEditType.PrependNode"/>, gets the
|
||||
/// index of the new node data in an associated render tree.
|
||||
/// <see cref="Type"/> value is <see cref="RenderTreeEditType.PrependFrame"/>, gets the
|
||||
/// index of the new frame data in an associated render tree.
|
||||
/// </summary>
|
||||
public int NewTreeIndex { get; private set; }
|
||||
|
||||
|
|
@ -31,15 +31,15 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
/// </summary>
|
||||
public string RemovedAttributeName { get; private set; }
|
||||
|
||||
internal static RenderTreeEdit RemoveNode(int siblingIndex) => new RenderTreeEdit
|
||||
internal static RenderTreeEdit RemoveFrame(int siblingIndex) => new RenderTreeEdit
|
||||
{
|
||||
Type = RenderTreeEditType.RemoveNode,
|
||||
Type = RenderTreeEditType.RemoveFrame,
|
||||
SiblingIndex = siblingIndex
|
||||
};
|
||||
|
||||
internal static RenderTreeEdit PrependNode(int siblingIndex, int newTreeIndex) => new RenderTreeEdit
|
||||
internal static RenderTreeEdit PrependFrame(int siblingIndex, int newTreeIndex) => new RenderTreeEdit
|
||||
{
|
||||
Type = RenderTreeEditType.PrependNode,
|
||||
Type = RenderTreeEditType.PrependFrame,
|
||||
SiblingIndex = siblingIndex,
|
||||
NewTreeIndex = newTreeIndex
|
||||
};
|
||||
|
|
@ -51,11 +51,11 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
NewTreeIndex = newTreeIndex
|
||||
};
|
||||
|
||||
internal static RenderTreeEdit SetAttribute(int siblingIndex, int newNodeIndex) => new RenderTreeEdit
|
||||
internal static RenderTreeEdit SetAttribute(int siblingIndex, int newFrameIndex) => new RenderTreeEdit
|
||||
{
|
||||
Type = RenderTreeEditType.SetAttribute,
|
||||
SiblingIndex = siblingIndex,
|
||||
NewTreeIndex = newNodeIndex
|
||||
NewTreeIndex = newFrameIndex
|
||||
};
|
||||
|
||||
internal static RenderTreeEdit RemoveAttribute(int siblingIndex, string name) => new RenderTreeEdit
|
||||
|
|
|
|||
|
|
@ -9,40 +9,40 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
public enum RenderTreeEditType: int
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a new node should be inserted before the specified tree node.
|
||||
/// Indicates that a new frame should be inserted before the specified tree frame.
|
||||
/// </summary>
|
||||
PrependNode = 1,
|
||||
PrependFrame = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the specified tree node should be removed.
|
||||
/// Indicates that the specified tree frame should be removed.
|
||||
/// </summary>
|
||||
RemoveNode = 2,
|
||||
RemoveFrame = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an attribute value should be applied to the specified node.
|
||||
/// Indicates that an attribute value should be applied to the specified frame.
|
||||
/// This may be a change to an existing attribute, or the addition of a new attribute.
|
||||
/// </summary>
|
||||
SetAttribute = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a named attribute should be removed from the specified node.
|
||||
/// Indicates that a named attribute should be removed from the specified frame.
|
||||
/// </summary>
|
||||
RemoveAttribute = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the text content of the specified node (which must be a text node)
|
||||
/// Indicates that the text content of the specified frame (which must be a text frame)
|
||||
/// should be updated.
|
||||
/// </summary>
|
||||
UpdateText = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the edit position should move inside the specified node.
|
||||
/// Indicates that the edit position should move inside the specified frame.
|
||||
/// </summary>
|
||||
StepIn = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that there are no further edit operations on the current node, and the
|
||||
/// edit position should move back to the parent node.
|
||||
/// Indicates that there are no further edit operations on the current frame, and the
|
||||
/// edit position should move back to the parent frame.
|
||||
/// </summary>
|
||||
StepOut = 7,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,111 +13,111 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
/// <summary>
|
||||
/// Represents an entry in a tree of user interface (UI) items.
|
||||
/// </summary>
|
||||
public struct RenderTreeNode
|
||||
public struct RenderTreeFrame
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the sequence number of the node. Sequence numbers indicate the relative source
|
||||
/// positions of the instructions that inserted the nodes. Sequence numbers are only
|
||||
/// Gets the sequence number of the frame. Sequence numbers indicate the relative source
|
||||
/// positions of the instructions that inserted the frames. Sequence numbers are only
|
||||
/// comparable within the same sequence (typically, the same source method).
|
||||
/// </summary>
|
||||
public int Sequence { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Describes the type of this node.
|
||||
/// Describes the type of this frame.
|
||||
/// </summary>
|
||||
public RenderTreeNodeType NodeType { get; private set; }
|
||||
public RenderTreeFrameType FrameType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="NodeType"/> property equals <see cref="RenderTreeNodeType.Element"/>,
|
||||
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Element"/>,
|
||||
/// gets a name representing the type of the element. Otherwise, the value is <see langword="null"/>.
|
||||
/// </summary>
|
||||
public string ElementName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="NodeType"/> property equals <see cref="RenderTreeNodeType.Element"/>,
|
||||
/// gets the index of the final descendant node in the tree. The value is
|
||||
/// zero if the node is of a different type, or if it has not yet been closed.
|
||||
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Element"/>,
|
||||
/// gets the index of the final descendant frame in the tree. The value is
|
||||
/// zero if the frame is of a different type, or if it has not yet been closed.
|
||||
/// </summary>
|
||||
public int ElementDescendantsEndIndex { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="NodeType"/> property equals <see cref="RenderTreeNodeType.Text"/>,
|
||||
/// gets the content of the text node. Otherwise, the value is <see langword="null"/>.
|
||||
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Text"/>,
|
||||
/// gets the content of the text frame. Otherwise, the value is <see langword="null"/>.
|
||||
/// </summary>
|
||||
public string TextContent { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="NodeType"/> property equals <see cref="RenderTreeNodeType.Attribute"/>,
|
||||
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Attribute"/>,
|
||||
/// gets the attribute name. Otherwise, the value is <see langword="null"/>.
|
||||
/// </summary>
|
||||
public string AttributeName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="NodeType"/> property equals <see cref="RenderTreeNodeType.Attribute"/>,
|
||||
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Attribute"/>,
|
||||
/// gets the attribute value. Otherwise, the value is <see langword="null"/>.
|
||||
/// </summary>
|
||||
public object AttributeValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="NodeType"/> property equals <see cref="RenderTreeNodeType.Component"/>,
|
||||
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Component"/>,
|
||||
/// gets the type of the child component.
|
||||
/// </summary>
|
||||
public Type ComponentType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="NodeType"/> property equals <see cref="RenderTreeNodeType.Component"/>,
|
||||
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Component"/>,
|
||||
/// gets the child component instance identifier.
|
||||
/// </summary>
|
||||
public int ComponentId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="NodeType"/> property equals <see cref="RenderTreeNodeType.Component"/>,
|
||||
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Component"/>,
|
||||
/// gets the child component instance. Otherwise, the value is <see langword="null"/>.
|
||||
/// </summary>
|
||||
public IComponent Component { get; private set; }
|
||||
|
||||
internal static RenderTreeNode Element(int sequence, string elementName) => new RenderTreeNode
|
||||
internal static RenderTreeFrame Element(int sequence, string elementName) => new RenderTreeFrame
|
||||
{
|
||||
Sequence = sequence,
|
||||
NodeType = RenderTreeNodeType.Element,
|
||||
FrameType = RenderTreeFrameType.Element,
|
||||
ElementName = elementName,
|
||||
};
|
||||
|
||||
internal static RenderTreeNode Text(int sequence, string textContent) => new RenderTreeNode
|
||||
internal static RenderTreeFrame Text(int sequence, string textContent) => new RenderTreeFrame
|
||||
{
|
||||
Sequence = sequence,
|
||||
NodeType = RenderTreeNodeType.Text,
|
||||
FrameType = RenderTreeFrameType.Text,
|
||||
TextContent = textContent ?? string.Empty,
|
||||
};
|
||||
|
||||
internal static RenderTreeNode Attribute(int sequence, string name, string value) => new RenderTreeNode
|
||||
internal static RenderTreeFrame Attribute(int sequence, string name, string value) => new RenderTreeFrame
|
||||
{
|
||||
Sequence = sequence,
|
||||
NodeType = RenderTreeNodeType.Attribute,
|
||||
FrameType = RenderTreeFrameType.Attribute,
|
||||
AttributeName = name,
|
||||
AttributeValue = value
|
||||
};
|
||||
|
||||
internal static RenderTreeNode Attribute(int sequence, string name, UIEventHandler value) => new RenderTreeNode
|
||||
internal static RenderTreeFrame Attribute(int sequence, string name, UIEventHandler value) => new RenderTreeFrame
|
||||
{
|
||||
Sequence = sequence,
|
||||
NodeType = RenderTreeNodeType.Attribute,
|
||||
FrameType = RenderTreeFrameType.Attribute,
|
||||
AttributeName = name,
|
||||
AttributeValue = value
|
||||
};
|
||||
|
||||
internal static RenderTreeNode Attribute(int sequence, string name, object value) => new RenderTreeNode
|
||||
internal static RenderTreeFrame Attribute(int sequence, string name, object value) => new RenderTreeFrame
|
||||
{
|
||||
Sequence = sequence,
|
||||
NodeType = RenderTreeNodeType.Attribute,
|
||||
FrameType = RenderTreeFrameType.Attribute,
|
||||
AttributeName = name,
|
||||
AttributeValue = value
|
||||
};
|
||||
|
||||
internal static RenderTreeNode ChildComponent<T>(int sequence) where T: IComponent => new RenderTreeNode
|
||||
internal static RenderTreeFrame ChildComponent<T>(int sequence) where T: IComponent => new RenderTreeFrame
|
||||
{
|
||||
Sequence = sequence,
|
||||
NodeType = RenderTreeNodeType.Component,
|
||||
FrameType = RenderTreeFrameType.Component,
|
||||
ComponentType = typeof(T)
|
||||
};
|
||||
|
||||
|
|
@ -134,8 +134,8 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
|
||||
internal void SetSequence(int sequence)
|
||||
{
|
||||
// This is only used when appending attribute nodes, because helpers such as @onclick
|
||||
// need to construct the attribute node in a context where they don't know the sequence
|
||||
// This is only used when appending attribute frames, because helpers such as @onclick
|
||||
// need to construct the attribute frame in a context where they don't know the sequence
|
||||
// number, so we assign it later
|
||||
Sequence = sequence;
|
||||
}
|
||||
|
|
@ -4,12 +4,12 @@
|
|||
namespace Microsoft.AspNetCore.Blazor.RenderTree
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the type of a <see cref="RenderTreeNode"/>.
|
||||
/// Describes the type of a <see cref="RenderTreeFrame"/>.
|
||||
/// </summary>
|
||||
public enum RenderTreeNodeType: int
|
||||
public enum RenderTreeFrameType: int
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a container for other nodes.
|
||||
/// Represents a container for other frames.
|
||||
/// </summary>
|
||||
Element = 1,
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
Text = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Represents a key-value pair associated with another <see cref="RenderTreeNode"/>.
|
||||
/// Represents a key-value pair associated with another <see cref="RenderTreeFrame"/>.
|
||||
/// </summary>
|
||||
Attribute = 3,
|
||||
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
namespace Microsoft.AspNetCore.Blazor.RenderTree
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles an event raised for a <see cref="RenderTreeNode"/>.
|
||||
/// Handles an event raised for a <see cref="RenderTreeFrame"/>.
|
||||
/// </summary>
|
||||
public delegate void UIEventHandler(UIEventArgs eventArgs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,14 +51,14 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
|
|||
_diffComputer.ApplyNewRenderTreeVersion(
|
||||
batchBuilder,
|
||||
_componentId,
|
||||
_renderTreeBuilderPrevious.GetNodes(),
|
||||
_renderTreeBuilderCurrent.GetNodes());
|
||||
_renderTreeBuilderPrevious.GetFrames(),
|
||||
_renderTreeBuilderCurrent.GetFrames());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the handler corresponding to an event.
|
||||
/// </summary>
|
||||
/// <param name="renderTreeIndex">The index of the current render tree node that holds the event handler to be invoked.</param>
|
||||
/// <param name="renderTreeIndex">The index of the current render tree frame that holds the event handler to be invoked.</param>
|
||||
/// <param name="eventArgs">Arguments to be passed to the event handler.</param>
|
||||
public void DispatchEvent(int renderTreeIndex, UIEventArgs eventArgs)
|
||||
{
|
||||
|
|
@ -67,11 +67,11 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
|
|||
throw new ArgumentNullException(nameof(eventArgs));
|
||||
}
|
||||
|
||||
var nodes = _renderTreeBuilderCurrent.GetNodes();
|
||||
var eventHandler = nodes.Array[renderTreeIndex].AttributeValue as UIEventHandler;
|
||||
var frames = _renderTreeBuilderCurrent.GetFrames();
|
||||
var eventHandler = frames.Array[renderTreeIndex].AttributeValue as UIEventHandler;
|
||||
if (eventHandler == null)
|
||||
{
|
||||
throw new ArgumentException($"The render tree node at index {renderTreeIndex} does not specify a {nameof(UIEventHandler)}.");
|
||||
throw new ArgumentException($"The render tree frame at index {renderTreeIndex} does not specify a {nameof(UIEventHandler)}.");
|
||||
}
|
||||
|
||||
eventHandler.Invoke(eventArgs);
|
||||
|
|
|
|||
|
|
@ -111,22 +111,22 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
|
|||
protected void DispatchEvent(int componentId, int renderTreeIndex, UIEventArgs eventArgs)
|
||||
=> GetRequiredComponentState(componentId).DispatchEvent(renderTreeIndex, eventArgs);
|
||||
|
||||
internal void InstantiateChildComponent(RenderTreeNode[] nodes, int componentNodeIndex)
|
||||
internal void InstantiateChildComponent(RenderTreeFrame[] frames, int componentFrameIndex)
|
||||
{
|
||||
ref var node = ref nodes[componentNodeIndex];
|
||||
if (node.NodeType != RenderTreeNodeType.Component)
|
||||
ref var frame = ref frames[componentFrameIndex];
|
||||
if (frame.FrameType != RenderTreeFrameType.Component)
|
||||
{
|
||||
throw new ArgumentException($"The node's {nameof(RenderTreeNode.NodeType)} property must equal {RenderTreeNodeType.Component}", nameof(node));
|
||||
throw new ArgumentException($"The frame's {nameof(RenderTreeFrame.FrameType)} property must equal {RenderTreeFrameType.Component}", nameof(frame));
|
||||
}
|
||||
|
||||
if (node.Component != null)
|
||||
if (frame.Component != null)
|
||||
{
|
||||
throw new ArgumentException($"The node already has a non-null component instance", nameof(node));
|
||||
throw new ArgumentException($"The frame already has a non-null component instance", nameof(frame));
|
||||
}
|
||||
|
||||
var newComponent = (IComponent)Activator.CreateInstance(node.ComponentType);
|
||||
var newComponent = (IComponent)Activator.CreateInstance(frame.ComponentType);
|
||||
var newComponentId = AssignComponentId(newComponent);
|
||||
node.SetChildComponentInstance(newComponentId, newComponent);
|
||||
frame.SetChildComponentInstance(newComponentId, newComponent);
|
||||
}
|
||||
|
||||
private ComponentState GetRequiredComponentState(int componentId)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Blazor.Build\Microsoft.AspNetCore.Blazor.Build.csproj" />
|
||||
|
||||
<!-- Shared sources -->
|
||||
<Compile Include="..\shared\AssertNode.cs" />
|
||||
<Compile Include="..\shared\AssertFrame.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
component.BuildRenderTree(treeBuilder);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(treeBuilder.GetNodes(),
|
||||
node => AssertNode.Text(node, "Some plain text", 0));
|
||||
Assert.Collection(treeBuilder.GetFrames(),
|
||||
frame => AssertFrame.Text(frame, "Some plain text", 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -112,17 +112,17 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
");
|
||||
|
||||
// Assert
|
||||
var nodes = GetRenderTree(component);
|
||||
Assert.Collection(nodes,
|
||||
node => AssertNode.Whitespace(node, 0),
|
||||
node => AssertNode.Text(node, "Hello", 1),
|
||||
node => AssertNode.Whitespace(node, 2),
|
||||
node => AssertNode.Whitespace(node, 3), // @((object)null)
|
||||
node => AssertNode.Whitespace(node, 4),
|
||||
node => AssertNode.Text(node, "123", 5),
|
||||
node => AssertNode.Whitespace(node, 6),
|
||||
node => AssertNode.Text(node, new object().ToString(), 7),
|
||||
node => AssertNode.Whitespace(node, 8));
|
||||
var frames = GetRenderTree(component);
|
||||
Assert.Collection(frames,
|
||||
frame => AssertFrame.Whitespace(frame, 0),
|
||||
frame => AssertFrame.Text(frame, "Hello", 1),
|
||||
frame => AssertFrame.Whitespace(frame, 2),
|
||||
frame => AssertFrame.Whitespace(frame, 3), // @((object)null)
|
||||
frame => AssertFrame.Whitespace(frame, 4),
|
||||
frame => AssertFrame.Text(frame, "123", 5),
|
||||
frame => AssertFrame.Whitespace(frame, 6),
|
||||
frame => AssertFrame.Text(frame, new object().ToString(), 7),
|
||||
frame => AssertFrame.Whitespace(frame, 8));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -139,14 +139,14 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
");
|
||||
|
||||
// Assert
|
||||
var nodes = GetRenderTree(component);
|
||||
Assert.Collection(nodes,
|
||||
node => AssertNode.Whitespace(node, 0),
|
||||
node => AssertNode.Text(node, "First", 1),
|
||||
node => AssertNode.Text(node, "Second", 1),
|
||||
node => AssertNode.Text(node, "Third", 1),
|
||||
node => AssertNode.Whitespace(node, 2),
|
||||
node => AssertNode.Whitespace(node, 3));
|
||||
var frames = GetRenderTree(component);
|
||||
Assert.Collection(frames,
|
||||
frame => AssertFrame.Whitespace(frame, 0),
|
||||
frame => AssertFrame.Text(frame, "First", 1),
|
||||
frame => AssertFrame.Text(frame, "Second", 1),
|
||||
frame => AssertFrame.Text(frame, "Third", 1),
|
||||
frame => AssertFrame.Whitespace(frame, 2),
|
||||
frame => AssertFrame.Whitespace(frame, 3));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -157,8 +157,8 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(GetRenderTree(component),
|
||||
node => AssertNode.Element(node, "myelem", 1, 0),
|
||||
node => AssertNode.Text(node, "Hello", 1));
|
||||
frame => AssertFrame.Element(frame, "myelem", 1, 0),
|
||||
frame => AssertFrame.Text(frame, "Hello", 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -169,8 +169,8 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(GetRenderTree(component),
|
||||
node => AssertNode.Text(node, "Some text so elem isn't at position 0 ", 0),
|
||||
node => AssertNode.Element(node, "myelem", 1, 1));
|
||||
frame => AssertFrame.Text(frame, "Some text so elem isn't at position 0 ", 0),
|
||||
frame => AssertFrame.Element(frame, "myelem", 1, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -181,8 +181,8 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(GetRenderTree(component),
|
||||
node => AssertNode.Text(node, "Some text so elem isn't at position 0 ", 0),
|
||||
node => AssertNode.Element(node, "img", 1, 1));
|
||||
frame => AssertFrame.Text(frame, "Some text so elem isn't at position 0 ", 0),
|
||||
frame => AssertFrame.Element(frame, "img", 1, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -193,9 +193,9 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(GetRenderTree(component),
|
||||
node => AssertNode.Element(node, "elem", 2, 0),
|
||||
node => AssertNode.Attribute(node, "attrib-one", "Value 1", 1),
|
||||
node => AssertNode.Attribute(node, "a2", "v2", 2));
|
||||
frame => AssertFrame.Element(frame, "elem", 2, 0),
|
||||
frame => AssertFrame.Attribute(frame, "attrib-one", "Value 1", 1),
|
||||
frame => AssertFrame.Attribute(frame, "a2", "v2", 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -208,8 +208,8 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(GetRenderTree(component),
|
||||
node => AssertNode.Element(node, "elem", 1, 0),
|
||||
node => AssertNode.Attribute(node, "attr", "My string", 1));
|
||||
frame => AssertFrame.Element(frame, "elem", 1, 0),
|
||||
frame => AssertFrame.Attribute(frame, "attr", "My string", 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -222,8 +222,8 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(GetRenderTree(component),
|
||||
node => AssertNode.Element(node, "elem", 1, 0),
|
||||
node => AssertNode.Attribute(node, "attr", "123", 1));
|
||||
frame => AssertFrame.Element(frame, "elem", 1, 0),
|
||||
frame => AssertFrame.Attribute(frame, "attr", "123", 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -236,8 +236,8 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(GetRenderTree(component),
|
||||
node => AssertNode.Element(node, "elem", 1, 0),
|
||||
node => AssertNode.Attribute(node, "attr", "Hello, WORLD with number 246!", 1));
|
||||
frame => AssertFrame.Element(frame, "elem", 1, 0),
|
||||
frame => AssertFrame.Attribute(frame, "attr", "Hello, WORLD with number 246!", 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -259,17 +259,17 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
// Assert
|
||||
Assert.False((bool)handlerWasCalledProperty.GetValue(component));
|
||||
Assert.Collection(GetRenderTree(component),
|
||||
node => AssertNode.Element(node, "elem", 1, 0),
|
||||
node =>
|
||||
frame => AssertFrame.Element(frame, "elem", 1, 0),
|
||||
frame =>
|
||||
{
|
||||
Assert.Equal(RenderTreeNodeType.Attribute, node.NodeType);
|
||||
Assert.Equal(1, node.Sequence);
|
||||
Assert.NotNull(node.AttributeValue);
|
||||
Assert.Equal(RenderTreeFrameType.Attribute, frame.FrameType);
|
||||
Assert.Equal(1, frame.Sequence);
|
||||
Assert.NotNull(frame.AttributeValue);
|
||||
|
||||
((UIEventHandler)node.AttributeValue)(null);
|
||||
((UIEventHandler)frame.AttributeValue)(null);
|
||||
Assert.True((bool)handlerWasCalledProperty.GetValue(component));
|
||||
},
|
||||
node => AssertNode.Whitespace(node, 2));
|
||||
frame => AssertFrame.Whitespace(frame, 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -282,22 +282,22 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
public bool DidInvokeCode { get; set; } = false;
|
||||
}");
|
||||
var didInvokeCodeProperty = component.GetType().GetProperty("DidInvokeCode");
|
||||
var nodes = GetRenderTree(component);
|
||||
var frames = GetRenderTree(component);
|
||||
|
||||
// Assert
|
||||
Assert.False((bool)didInvokeCodeProperty.GetValue(component));
|
||||
Assert.Collection(nodes,
|
||||
node => AssertNode.Element(node, "elem", 1, 0),
|
||||
node =>
|
||||
Assert.Collection(frames,
|
||||
frame => AssertFrame.Element(frame, "elem", 1, 0),
|
||||
frame =>
|
||||
{
|
||||
Assert.Equal(RenderTreeNodeType.Attribute, node.NodeType);
|
||||
Assert.NotNull(node.AttributeValue);
|
||||
Assert.Equal(1, node.Sequence);
|
||||
Assert.Equal(RenderTreeFrameType.Attribute, frame.FrameType);
|
||||
Assert.NotNull(frame.AttributeValue);
|
||||
Assert.Equal(1, frame.Sequence);
|
||||
|
||||
((UIEventHandler)node.AttributeValue)(null);
|
||||
((UIEventHandler)frame.AttributeValue)(null);
|
||||
Assert.True((bool)didInvokeCodeProperty.GetValue(component));
|
||||
},
|
||||
node => AssertNode.Whitespace(node, 2));
|
||||
frame => AssertFrame.Whitespace(frame, 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -313,13 +313,13 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
component.BuildRenderTree(treeBuilder);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(treeBuilder.GetNodes(),
|
||||
node => AssertNode.Whitespace(node, 0),
|
||||
node => AssertNode.Text(node, typeof(List<string>).FullName, 1));
|
||||
Assert.Collection(treeBuilder.GetFrames(),
|
||||
frame => AssertFrame.Whitespace(frame, 0),
|
||||
frame => AssertFrame.Text(frame, typeof(List<string>).FullName, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SupportsAttributeNodesEvaluatedInline()
|
||||
public void SupportsAttributeFramesEvaluatedInline()
|
||||
{
|
||||
// Arrange/Act
|
||||
var component = CompileToComponent(
|
||||
|
|
@ -336,17 +336,17 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
// Assert
|
||||
Assert.False((bool)didInvokeCodeProperty.GetValue(component));
|
||||
Assert.Collection(GetRenderTree(component),
|
||||
node => AssertNode.Element(node, "elem", 1, 0),
|
||||
node =>
|
||||
frame => AssertFrame.Element(frame, "elem", 1, 0),
|
||||
frame =>
|
||||
{
|
||||
Assert.Equal(RenderTreeNodeType.Attribute, node.NodeType);
|
||||
Assert.NotNull(node.AttributeValue);
|
||||
Assert.Equal(1, node.Sequence);
|
||||
Assert.Equal(RenderTreeFrameType.Attribute, frame.FrameType);
|
||||
Assert.NotNull(frame.AttributeValue);
|
||||
Assert.Equal(1, frame.Sequence);
|
||||
|
||||
((UIEventHandler)node.AttributeValue)(null);
|
||||
((UIEventHandler)frame.AttributeValue)(null);
|
||||
Assert.True((bool)didInvokeCodeProperty.GetValue(component));
|
||||
},
|
||||
node => AssertNode.Whitespace(node, 2));
|
||||
frame => AssertFrame.Whitespace(frame, 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -361,15 +361,15 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
component.BuildRenderTree(treeBuilder);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(treeBuilder.GetNodes(),
|
||||
node => AssertNode.Component<TestComponent>(node, 0));
|
||||
Assert.Collection(treeBuilder.GetFrames(),
|
||||
frame => AssertFrame.Component<TestComponent>(frame, 0));
|
||||
}
|
||||
|
||||
private static ArrayRange<RenderTreeNode> GetRenderTree(IComponent component)
|
||||
private static ArrayRange<RenderTreeFrame> GetRenderTree(IComponent component)
|
||||
{
|
||||
var treeBuilder = new RenderTreeBuilder(new TestRenderer());
|
||||
component.BuildRenderTree(treeBuilder);
|
||||
return treeBuilder.GetNodes();
|
||||
return treeBuilder.GetFrames();
|
||||
}
|
||||
|
||||
private static IComponent CompileToComponent(string cshtmlSource)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Blazor\Microsoft.AspNetCore.Blazor.csproj" />
|
||||
|
||||
<!-- Shared sources -->
|
||||
<Compile Include="..\shared\AssertNode.cs" />
|
||||
<Compile Include="..\shared\AssertFrame.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
var builder = new RenderTreeBuilder(new TestRenderer());
|
||||
|
||||
// Assert
|
||||
var nodes = builder.GetNodes();
|
||||
Assert.NotNull(nodes.Array);
|
||||
Assert.Empty(nodes);
|
||||
var frames = builder.GetFrames();
|
||||
Assert.NotNull(frames.Array);
|
||||
Assert.Empty(frames);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -47,11 +47,11 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
builder.AddText(0, "Second item");
|
||||
|
||||
// Assert
|
||||
var nodes = builder.GetNodes();
|
||||
Assert.Collection(nodes,
|
||||
node => AssertNode.Text(node, "First item"),
|
||||
node => AssertNode.Text(node, string.Empty),
|
||||
node => AssertNode.Text(node, "Second item"));
|
||||
var frames = builder.GetFrames();
|
||||
Assert.Collection(frames,
|
||||
frame => AssertFrame.Text(frame, "First item"),
|
||||
frame => AssertFrame.Text(frame, string.Empty),
|
||||
frame => AssertFrame.Text(frame, "Second item"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -66,10 +66,10 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
builder.AddText(0, nullObject);
|
||||
|
||||
// Assert
|
||||
var nodes = builder.GetNodes();
|
||||
Assert.Collection(nodes,
|
||||
node => AssertNode.Text(node, "1234"),
|
||||
node => AssertNode.Text(node, string.Empty));
|
||||
var frames = builder.GetFrames();
|
||||
Assert.Collection(frames,
|
||||
frame => AssertFrame.Text(frame, "1234"),
|
||||
frame => AssertFrame.Text(frame, string.Empty));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -82,8 +82,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
builder.OpenElement(0, "my element");
|
||||
|
||||
// Assert
|
||||
var node = builder.GetNodes().Single();
|
||||
AssertNode.Element(node, "my element", 0);
|
||||
var frame = builder.GetFrames().Single();
|
||||
AssertFrame.Element(frame, "my element", 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -93,14 +93,14 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
var builder = new RenderTreeBuilder(new TestRenderer());
|
||||
|
||||
// Act
|
||||
builder.AddText(0, "some node so that the element isn't at position zero");
|
||||
builder.AddText(0, "some frame so that the element isn't at position zero");
|
||||
builder.OpenElement(0, "my element");
|
||||
builder.CloseElement();
|
||||
|
||||
// Assert
|
||||
var nodes = builder.GetNodes();
|
||||
Assert.Equal(2, nodes.Count);
|
||||
AssertNode.Element(nodes.Array[1], "my element", 1);
|
||||
var frames = builder.GetFrames();
|
||||
Assert.Equal(2, frames.Count);
|
||||
AssertFrame.Element(frames.Array[1], "my element", 1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -117,9 +117,9 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
builder.AddText(0, "unrelated item");
|
||||
|
||||
// Assert
|
||||
var nodes = builder.GetNodes();
|
||||
Assert.Equal(4, nodes.Count);
|
||||
AssertNode.Element(nodes.Array[0], "my element", 2);
|
||||
var frames = builder.GetFrames();
|
||||
Assert.Equal(4, frames.Count);
|
||||
AssertFrame.Element(frames.Array[0], "my element", 2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -147,19 +147,19 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
builder.AddText(0, "standalone text 2"); // 11: standalone text 2
|
||||
|
||||
// Assert
|
||||
Assert.Collection(builder.GetNodes(),
|
||||
node => AssertNode.Text(node, "standalone text 1"),
|
||||
node => AssertNode.Element(node, "root", 10),
|
||||
node => AssertNode.Text(node, "root text 1"),
|
||||
node => AssertNode.Text(node, "root text 2"),
|
||||
node => AssertNode.Element(node, "child", 8),
|
||||
node => AssertNode.Text(node, "child text"),
|
||||
node => AssertNode.Element(node, "grandchild", 8),
|
||||
node => AssertNode.Text(node, "grandchild text 1"),
|
||||
node => AssertNode.Text(node, "grandchild text 2"),
|
||||
node => AssertNode.Text(node, "root text 3"),
|
||||
node => AssertNode.Element(node, "child 2", 10),
|
||||
node => AssertNode.Text(node, "standalone text 2"));
|
||||
Assert.Collection(builder.GetFrames(),
|
||||
frame => AssertFrame.Text(frame, "standalone text 1"),
|
||||
frame => AssertFrame.Element(frame, "root", 10),
|
||||
frame => AssertFrame.Text(frame, "root text 1"),
|
||||
frame => AssertFrame.Text(frame, "root text 2"),
|
||||
frame => AssertFrame.Element(frame, "child", 8),
|
||||
frame => AssertFrame.Text(frame, "child text"),
|
||||
frame => AssertFrame.Element(frame, "grandchild", 8),
|
||||
frame => AssertFrame.Text(frame, "grandchild text 1"),
|
||||
frame => AssertFrame.Text(frame, "grandchild text 2"),
|
||||
frame => AssertFrame.Text(frame, "root text 3"),
|
||||
frame => AssertFrame.Element(frame, "child 2", 10),
|
||||
frame => AssertFrame.Text(frame, "standalone text 2"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -180,13 +180,13 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
builder.CloseElement(); // </myelement>
|
||||
|
||||
// Assert
|
||||
Assert.Collection(builder.GetNodes(),
|
||||
node => AssertNode.Element(node, "myelement", 5),
|
||||
node => AssertNode.Attribute(node, "attribute1", "value 1"),
|
||||
node => AssertNode.Attribute(node, "attribute2", "123"),
|
||||
node => AssertNode.Element(node, "child", 5),
|
||||
node => AssertNode.Attribute(node, "childevent", eventHandler),
|
||||
node => AssertNode.Text(node, "some text"));
|
||||
Assert.Collection(builder.GetFrames(),
|
||||
frame => AssertFrame.Element(frame, "myelement", 5),
|
||||
frame => AssertFrame.Attribute(frame, "attribute1", "value 1"),
|
||||
frame => AssertFrame.Attribute(frame, "attribute2", "123"),
|
||||
frame => AssertFrame.Element(frame, "child", 5),
|
||||
frame => AssertFrame.Attribute(frame, "childevent", eventHandler),
|
||||
frame => AssertFrame.Text(frame, "some text"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -263,13 +263,13 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
builder.CloseElement(); // </parent>
|
||||
|
||||
// Assert
|
||||
Assert.Collection(builder.GetNodes(),
|
||||
node => AssertNode.Element(node, "parent", 5),
|
||||
node => AssertNode.Component<TestComponent>(node),
|
||||
node => AssertNode.Attribute(node, "child1attribute1", "A"),
|
||||
node => AssertNode.Attribute(node, "child1attribute2", "B"),
|
||||
node => AssertNode.Component<TestComponent>(node),
|
||||
node => AssertNode.Attribute(node, "child2attribute", "C"));
|
||||
Assert.Collection(builder.GetFrames(),
|
||||
frame => AssertFrame.Element(frame, "parent", 5),
|
||||
frame => AssertFrame.Component<TestComponent>(frame),
|
||||
frame => AssertFrame.Attribute(frame, "child1attribute1", "A"),
|
||||
frame => AssertFrame.Attribute(frame, "child1attribute2", "B"),
|
||||
frame => AssertFrame.Component<TestComponent>(frame),
|
||||
frame => AssertFrame.Attribute(frame, "child2attribute", "C"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -286,7 +286,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
builder.Clear();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(builder.GetNodes());
|
||||
Assert.Empty(builder.GetFrames());
|
||||
}
|
||||
|
||||
private class TestComponent : IComponent
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RecognizesEquivalentNodesAsSameCases))]
|
||||
public void RecognizesEquivalentNodesAsSame(Action<RenderTreeBuilder> appendAction)
|
||||
[MemberData(nameof(RecognizesEquivalentFramesAsSameCases))]
|
||||
public void RecognizesEquivalentFramesAsSame(Action<RenderTreeBuilder> appendAction)
|
||||
{
|
||||
// Arrange
|
||||
appendAction(oldTree);
|
||||
|
|
@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
Assert.Empty(result.Edits);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> RecognizesEquivalentNodesAsSameCases()
|
||||
public static IEnumerable<object[]> RecognizesEquivalentFramesAsSameCases()
|
||||
=> new Action<RenderTreeBuilder>[]
|
||||
{
|
||||
builder => builder.AddText(0, "Hello"),
|
||||
|
|
@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
Assert.Collection(result.Edits,
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 1);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 1);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
});
|
||||
}
|
||||
|
|
@ -93,7 +93,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(result.Edits,
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveNode, 1));
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -112,8 +112,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(result.Edits,
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveNode, 1),
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveNode, 1));
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1),
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -134,12 +134,12 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
Assert.Collection(result.Edits,
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 1);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 1);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
},
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 2);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 2);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
});
|
||||
}
|
||||
|
|
@ -160,8 +160,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(result.Edits,
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveNode, 2),
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveNode, 2));
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 2),
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -182,12 +182,12 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
Assert.Collection(result.Edits,
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 2);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 2);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
},
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 3);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 3);
|
||||
Assert.Equal(3, entry.NewTreeIndex);
|
||||
});
|
||||
}
|
||||
|
|
@ -210,12 +210,12 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
Assert.Collection(result.Edits,
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 1);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 1);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
},
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 2);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 2);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
});
|
||||
}
|
||||
|
|
@ -236,8 +236,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(result.Edits,
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveNode, 1),
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveNode, 1));
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1),
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -252,8 +252,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(result.Edits,
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveNode, 0),
|
||||
entry => AssertEdit(entry, RenderTreeEditType.PrependNode, 0));
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 0),
|
||||
entry => AssertEdit(entry, RenderTreeEditType.PrependFrame, 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -302,10 +302,10 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
Assert.Collection(result.Edits,
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 0);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 0);
|
||||
Assert.Equal(0, entry.NewTreeIndex);
|
||||
},
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveNode, 1));
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -330,18 +330,18 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
Assert.Collection(updatedComponent1.Edits,
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 0);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 0);
|
||||
Assert.Equal(0, entry.NewTreeIndex);
|
||||
Assert.IsType<FakeComponent2>(updatedComponent1.CurrentState.Array[0].Component);
|
||||
},
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveNode, 1));
|
||||
entry => AssertEdit(entry, RenderTreeEditType.RemoveFrame, 1));
|
||||
|
||||
// Assert: Second updated component is the new FakeComponent2
|
||||
var updatedComponent2 = renderBatch.UpdatedComponents.Array[1];
|
||||
Assert.Collection(updatedComponent2.Edits,
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 0);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 0);
|
||||
Assert.Equal(0, entry.NewTreeIndex);
|
||||
});
|
||||
}
|
||||
|
|
@ -577,7 +577,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void InstantiatesChildComponentsForInsertedNodes()
|
||||
public void InstantiatesChildComponentsForInsertedFrames()
|
||||
{
|
||||
// Arrange
|
||||
oldTree.AddText(10, "text1"); // 0: text1
|
||||
|
|
@ -603,37 +603,37 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
entry => AssertEdit(entry, RenderTreeEditType.StepIn, 1),
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 0);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 0);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
|
||||
var newTreeNode = newTree.GetNodes().Array[entry.NewTreeIndex];
|
||||
Assert.Equal(0, newTreeNode.ComponentId);
|
||||
Assert.IsType<FakeComponent>(newTreeNode.Component);
|
||||
var newTreeFrame = newTree.GetFrames().Array[entry.NewTreeIndex];
|
||||
Assert.Equal(0, newTreeFrame.ComponentId);
|
||||
Assert.IsType<FakeComponent>(newTreeFrame.Component);
|
||||
},
|
||||
entry =>
|
||||
{
|
||||
AssertEdit(entry, RenderTreeEditType.PrependNode, 1);
|
||||
AssertEdit(entry, RenderTreeEditType.PrependFrame, 1);
|
||||
Assert.Equal(3, entry.NewTreeIndex);
|
||||
|
||||
var newTreeNode = newTree.GetNodes().Array[entry.NewTreeIndex];
|
||||
Assert.Equal(1, newTreeNode.ComponentId);
|
||||
Assert.IsType<FakeComponent2>(newTreeNode.Component);
|
||||
var newTreeFrame = newTree.GetFrames().Array[entry.NewTreeIndex];
|
||||
Assert.Equal(1, newTreeFrame.ComponentId);
|
||||
Assert.IsType<FakeComponent2>(newTreeFrame.Component);
|
||||
},
|
||||
entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0));
|
||||
|
||||
// Second in batch is the first child component
|
||||
var secondComponentDiff = renderBatch.UpdatedComponents.Array[1];
|
||||
Assert.Equal(0, secondComponentDiff.ComponentId);
|
||||
Assert.Empty(secondComponentDiff.Edits); // Because FakeComponent produces no nodes
|
||||
Assert.Empty(secondComponentDiff.CurrentState); // Because FakeComponent produces no nodes
|
||||
Assert.Empty(secondComponentDiff.Edits); // Because FakeComponent produces no frames
|
||||
Assert.Empty(secondComponentDiff.CurrentState); // Because FakeComponent produces no frames
|
||||
|
||||
// Third in batch is the second child component
|
||||
var thirdComponentDiff = renderBatch.UpdatedComponents.Array[2];
|
||||
Assert.Equal(1, thirdComponentDiff.ComponentId);
|
||||
Assert.Collection(thirdComponentDiff.Edits,
|
||||
entry => AssertEdit(entry, RenderTreeEditType.PrependNode, 0));
|
||||
entry => AssertEdit(entry, RenderTreeEditType.PrependFrame, 0));
|
||||
Assert.Collection(thirdComponentDiff.CurrentState,
|
||||
node => AssertNode.Text(node, $"Hello from {nameof(FakeComponent2)}"));
|
||||
frame => AssertFrame.Text(frame, $"Hello from {nameof(FakeComponent2)}"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -649,13 +649,13 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Act
|
||||
var renderBatch = GetRenderedBatch();
|
||||
var componentInstance = newTree.GetNodes().First().Component as FakeComponent;
|
||||
var componentInstance = newTree.GetFrames().First().Component as FakeComponent;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, renderBatch.UpdatedComponents.Count);
|
||||
|
||||
var rootComponentDiff = renderBatch.UpdatedComponents.Array[0];
|
||||
AssertEdit(rootComponentDiff.Edits.Single(), RenderTreeEditType.PrependNode, 0);
|
||||
AssertEdit(rootComponentDiff.Edits.Single(), RenderTreeEditType.PrependFrame, 0);
|
||||
Assert.NotNull(componentInstance);
|
||||
Assert.Equal(123, componentInstance.IntProperty);
|
||||
Assert.Equal("some string", componentInstance.StringProperty);
|
||||
|
|
@ -674,7 +674,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
// Act/Assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
diff.ApplyNewRenderTreeVersion(new RenderBatchBuilder(), 0, oldTree.GetNodes(), newTree.GetNodes());
|
||||
diff.ApplyNewRenderTreeVersion(new RenderBatchBuilder(), 0, oldTree.GetFrames(), newTree.GetFrames());
|
||||
});
|
||||
Assert.Equal($"Component of type '{typeof(FakeComponent).FullName}' does not have a property matching the name 'SomeUnknownProperty'.", ex.Message);
|
||||
}
|
||||
|
|
@ -691,14 +691,14 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
// Act/Assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
diff.ApplyNewRenderTreeVersion(new RenderBatchBuilder(), 0, oldTree.GetNodes(), newTree.GetNodes());
|
||||
diff.ApplyNewRenderTreeVersion(new RenderBatchBuilder(), 0, oldTree.GetFrames(), newTree.GetFrames());
|
||||
});
|
||||
Assert.StartsWith($"Unable to set property '{nameof(FakeComponent.ReadonlyProperty)}' on " +
|
||||
$"component of type '{typeof(FakeComponent).FullName}'.", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RetainsChildComponentsForExistingNodes()
|
||||
public void RetainsChildComponentsForExistingFrames()
|
||||
{
|
||||
// Arrange
|
||||
oldTree.AddText(10, "text1"); // 0: text1
|
||||
|
|
@ -716,21 +716,21 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
newTree.CloseElement(); // </FakeComponent2>
|
||||
newTree.CloseElement(); // </container
|
||||
|
||||
diff.ApplyNewRenderTreeVersion(new RenderBatchBuilder(), 0, new RenderTreeBuilder(renderer).GetNodes(), oldTree.GetNodes());
|
||||
var originalFakeComponentInstance = oldTree.GetNodes().Array[2].Component;
|
||||
var originalFakeComponent2Instance = oldTree.GetNodes().Array[3].Component;
|
||||
diff.ApplyNewRenderTreeVersion(new RenderBatchBuilder(), 0, new RenderTreeBuilder(renderer).GetFrames(), oldTree.GetFrames());
|
||||
var originalFakeComponentInstance = oldTree.GetFrames().Array[2].Component;
|
||||
var originalFakeComponent2Instance = oldTree.GetFrames().Array[3].Component;
|
||||
|
||||
// Act
|
||||
var result = GetSingleUpdatedComponent();
|
||||
var newNode1 = newTree.GetNodes().Array[2];
|
||||
var newNode2 = newTree.GetNodes().Array[3];
|
||||
var newFrame1 = newTree.GetFrames().Array[2];
|
||||
var newFrame2 = newTree.GetFrames().Array[3];
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result.Edits);
|
||||
Assert.Equal(0, newNode1.ComponentId);
|
||||
Assert.Equal(1, newNode2.ComponentId);
|
||||
Assert.Same(originalFakeComponentInstance, newNode1.Component);
|
||||
Assert.Same(originalFakeComponent2Instance, newNode2.Component);
|
||||
Assert.Equal(0, newFrame1.ComponentId);
|
||||
Assert.Equal(1, newFrame2.ComponentId);
|
||||
Assert.Same(originalFakeComponentInstance, newFrame1.Component);
|
||||
Assert.Same(originalFakeComponent2Instance, newFrame2.Component);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -747,13 +747,13 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
newTree.AddAttribute(14, nameof(FakeComponent.ObjectProperty), objectWillNotChange);
|
||||
newTree.CloseElement();
|
||||
|
||||
diff.ApplyNewRenderTreeVersion(new RenderBatchBuilder(), 0, new RenderTreeBuilder(renderer).GetNodes(), oldTree.GetNodes());
|
||||
var originalComponentInstance = (FakeComponent)oldTree.GetNodes().Array[0].Component;
|
||||
diff.ApplyNewRenderTreeVersion(new RenderBatchBuilder(), 0, new RenderTreeBuilder(renderer).GetFrames(), oldTree.GetFrames());
|
||||
var originalComponentInstance = (FakeComponent)oldTree.GetFrames().Array[0].Component;
|
||||
originalComponentInstance.ObjectProperty = null; // So we can see it doesn't get reassigned
|
||||
|
||||
// Act
|
||||
var renderBatch = GetRenderedBatch();
|
||||
var newComponentInstance = (FakeComponent)oldTree.GetNodes().Array[0].Component;
|
||||
var newComponentInstance = (FakeComponent)oldTree.GetFrames().Array[0].Component;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, renderBatch.UpdatedComponents.Count);
|
||||
|
|
@ -775,7 +775,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(diffForChildComponent.CurrentState,
|
||||
node => AssertNode.Text(node, "Notifications: 1", 0));
|
||||
frame => AssertFrame.Text(frame, "Notifications: 1", 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -797,11 +797,11 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
// Act/Assert 0: Initial render
|
||||
var batch0 = GetRenderedBatch(new RenderTreeBuilder(renderer), oldTree);
|
||||
var diffForChildComponent0 = batch0.UpdatedComponents.Array[1];
|
||||
var childComponentNode = batch0.UpdatedComponents.Array[0].CurrentState.Array[0];
|
||||
var childComponentInstance = (HandlePropertiesChangedComponent)childComponentNode.Component;
|
||||
var childComponentFrame = batch0.UpdatedComponents.Array[0].CurrentState.Array[0];
|
||||
var childComponentInstance = (HandlePropertiesChangedComponent)childComponentFrame.Component;
|
||||
Assert.Equal(1, childComponentInstance.NotificationsCount);
|
||||
Assert.Collection(diffForChildComponent0.CurrentState,
|
||||
node => AssertNode.Text(node, "Notifications: 1", 0));
|
||||
frame => AssertFrame.Text(frame, "Notifications: 1", 0));
|
||||
|
||||
// Act/Assert 1: If properties didn't change, we don't notify
|
||||
GetRenderedBatch(oldTree, newTree1);
|
||||
|
|
@ -812,7 +812,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
var diffForChildComponent2 = batch2.UpdatedComponents.Array[1];
|
||||
Assert.Equal(2, childComponentInstance.NotificationsCount);
|
||||
Assert.Collection(diffForChildComponent2.CurrentState,
|
||||
node => AssertNode.Text(node, "Notifications: 2", 0));
|
||||
frame => AssertFrame.Text(frame, "Notifications: 2", 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -828,10 +828,10 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
newTree.OpenComponentElement<DisposableComponent>(30); // <DisposableComponent>
|
||||
newTree.CloseElement(); // </DisposableComponent>
|
||||
|
||||
diff.ApplyNewRenderTreeVersion(new RenderBatchBuilder(), 0, new RenderTreeBuilder(renderer).GetNodes(), oldTree.GetNodes());
|
||||
var disposableComponent1 = (DisposableComponent)oldTree.GetNodes().Array[0].Component;
|
||||
var nonDisposableComponent = (NonDisposableComponent)oldTree.GetNodes().Array[1].Component;
|
||||
var disposableComponent2 = (DisposableComponent)oldTree.GetNodes().Array[2].Component;
|
||||
diff.ApplyNewRenderTreeVersion(new RenderBatchBuilder(), 0, new RenderTreeBuilder(renderer).GetFrames(), oldTree.GetFrames());
|
||||
var disposableComponent1 = (DisposableComponent)oldTree.GetFrames().Array[0].Component;
|
||||
var nonDisposableComponent = (NonDisposableComponent)oldTree.GetFrames().Array[1].Component;
|
||||
var disposableComponent2 = (DisposableComponent)oldTree.GetFrames().Array[2].Component;
|
||||
|
||||
// Act
|
||||
var renderedBatch = GetRenderedBatch();
|
||||
|
|
@ -859,7 +859,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
private RenderBatch GetRenderedBatch(RenderTreeBuilder from, RenderTreeBuilder to)
|
||||
{
|
||||
var batchBuilder = new RenderBatchBuilder();
|
||||
diff.ApplyNewRenderTreeVersion(batchBuilder, 0, from.GetNodes(), to.GetNodes());
|
||||
diff.ApplyNewRenderTreeVersion(batchBuilder, 0, from.GetFrames(), to.GetFrames());
|
||||
return batchBuilder.ToBatch();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(renderer.Batches.Single().RenderTreesByComponentId[componentId],
|
||||
node => AssertNode.Element(node, "my element", 1),
|
||||
node => AssertNode.Text(node, "some text"));
|
||||
frame => AssertFrame.Element(frame, "my element", 1),
|
||||
frame => AssertFrame.Text(frame, "some text"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -52,16 +52,16 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
// Act/Assert
|
||||
var componentId = renderer.AssignComponentId(component);
|
||||
renderer.RenderNewBatch(componentId);
|
||||
var componentNode = renderer.Batches.Single().RenderTreesByComponentId[componentId]
|
||||
.Single(node => node.NodeType == RenderTreeNodeType.Component);
|
||||
var nestedComponentId = componentNode.ComponentId;
|
||||
var componentFrame = renderer.Batches.Single().RenderTreesByComponentId[componentId]
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component);
|
||||
var nestedComponentId = componentFrame.ComponentId;
|
||||
|
||||
// The nested component exists
|
||||
Assert.IsType<MessageComponent>(componentNode.Component);
|
||||
Assert.IsType<MessageComponent>(componentFrame.Component);
|
||||
|
||||
// The nested component was rendered as part of the batch
|
||||
Assert.Collection(renderer.Batches.Single().RenderTreesByComponentId[nestedComponentId],
|
||||
node => AssertNode.Text(node, "Nested component output"));
|
||||
frame => AssertFrame.Text(frame, "Nested component output"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -75,13 +75,13 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
// Act/Assert: first render
|
||||
renderer.RenderNewBatch(componentId);
|
||||
Assert.Collection(renderer.Batches.Single().RenderTreesByComponentId[componentId],
|
||||
node => AssertNode.Text(node, "Initial message"));
|
||||
frame => AssertFrame.Text(frame, "Initial message"));
|
||||
|
||||
// Act/Assert: second render
|
||||
component.Message = "Modified message";
|
||||
renderer.RenderNewBatch(componentId);
|
||||
Assert.Collection(renderer.Batches[1].RenderTreesByComponentId[componentId],
|
||||
node => AssertNode.Text(node, "Modified message"));
|
||||
frame => AssertFrame.Text(frame, "Modified message"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -96,22 +96,22 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
});
|
||||
var parentComponentId = renderer.AssignComponentId(parentComponent);
|
||||
renderer.RenderNewBatch(parentComponentId);
|
||||
var nestedComponentNode = renderer.Batches.Single().RenderTreesByComponentId[parentComponentId]
|
||||
.Single(node => node.NodeType == RenderTreeNodeType.Component);
|
||||
var nestedComponent = (MessageComponent)nestedComponentNode.Component;
|
||||
var nestedComponentId = nestedComponentNode.ComponentId;
|
||||
var nestedComponentFrame = renderer.Batches.Single().RenderTreesByComponentId[parentComponentId]
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component);
|
||||
var nestedComponent = (MessageComponent)nestedComponentFrame.Component;
|
||||
var nestedComponentId = nestedComponentFrame.ComponentId;
|
||||
|
||||
// Act/Assert: inital render
|
||||
nestedComponent.Message = "Render 1";
|
||||
renderer.RenderNewBatch(nestedComponentId);
|
||||
Assert.Collection(renderer.Batches[1].RenderTreesByComponentId[nestedComponentId],
|
||||
node => AssertNode.Text(node, "Render 1"));
|
||||
frame => AssertFrame.Text(frame, "Render 1"));
|
||||
|
||||
// Act/Assert: re-render
|
||||
nestedComponent.Message = "Render 2";
|
||||
renderer.RenderNewBatch(nestedComponentId);
|
||||
Assert.Collection(renderer.Batches[2].RenderTreesByComponentId[nestedComponentId],
|
||||
node => AssertNode.Text(node, "Render 2"));
|
||||
frame => AssertFrame.Text(frame, "Render 2"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -128,16 +128,16 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
var componentId = renderer.AssignComponentId(component);
|
||||
renderer.RenderNewBatch(componentId);
|
||||
|
||||
var (eventHandlerNodeIndex, _) = FirstWithIndex(
|
||||
var (eventHandlerFrameIndex, _) = FirstWithIndex(
|
||||
renderer.Batches.Single().RenderTreesByComponentId[componentId],
|
||||
node => node.AttributeValue != null);
|
||||
frame => frame.AttributeValue != null);
|
||||
|
||||
// Assert: Event not yet fired
|
||||
Assert.Null(receivedArgs);
|
||||
|
||||
// Act/Assert: Event can be fired
|
||||
var eventArgs = new UIEventArgs();
|
||||
renderer.DispatchEvent(componentId, eventHandlerNodeIndex, eventArgs);
|
||||
renderer.DispatchEvent(componentId, eventHandlerFrameIndex, eventArgs);
|
||||
Assert.Same(eventArgs, receivedArgs);
|
||||
}
|
||||
|
||||
|
|
@ -157,24 +157,24 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
renderer.RenderNewBatch(parentComponentId);
|
||||
|
||||
// Arrange: Render nested component
|
||||
var nestedComponentNode = renderer.Batches.Single().RenderTreesByComponentId[parentComponentId]
|
||||
.Single(node => node.NodeType == RenderTreeNodeType.Component);
|
||||
var nestedComponent = (EventComponent)nestedComponentNode.Component;
|
||||
var nestedComponentFrame = renderer.Batches.Single().RenderTreesByComponentId[parentComponentId]
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component);
|
||||
var nestedComponent = (EventComponent)nestedComponentFrame.Component;
|
||||
nestedComponent.Handler = args => { receivedArgs = args; };
|
||||
var nestedComponentId = nestedComponentNode.ComponentId;
|
||||
var nestedComponentId = nestedComponentFrame.ComponentId;
|
||||
renderer.RenderNewBatch(nestedComponentId);
|
||||
|
||||
// Find nested component's event handler ndoe
|
||||
var (eventHandlerNodeIndex, _) = FirstWithIndex(
|
||||
var (eventHandlerFrameIndex, _) = FirstWithIndex(
|
||||
renderer.Batches[1].RenderTreesByComponentId[nestedComponentId],
|
||||
node => node.AttributeValue != null);
|
||||
frame => frame.AttributeValue != null);
|
||||
|
||||
// Assert: Event not yet fired
|
||||
Assert.Null(receivedArgs);
|
||||
|
||||
// Act/Assert: Event can be fired
|
||||
var eventArgs = new UIEventArgs();
|
||||
renderer.DispatchEvent(nestedComponentId, eventHandlerNodeIndex, eventArgs);
|
||||
renderer.DispatchEvent(nestedComponentId, eventHandlerFrameIndex, eventArgs);
|
||||
Assert.Same(eventArgs, receivedArgs);
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +314,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
renderer.RenderNewBatch(rootComponentId);
|
||||
|
||||
var nestedComponentInstance = (MessageComponent)renderer.Batches.Single().RenderTreesByComponentId[rootComponentId]
|
||||
.Single(node => node.NodeType == RenderTreeNodeType.Component)
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component)
|
||||
.Component;
|
||||
|
||||
// Act: Second render
|
||||
|
|
@ -323,8 +323,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
// Assert
|
||||
Assert.Collection(renderer.Batches[1].RenderTreesByComponentId[rootComponentId],
|
||||
node => AssertNode.Text(node, "Modified message"),
|
||||
node => Assert.Same(nestedComponentInstance, node.Component));
|
||||
frame => AssertFrame.Text(frame, "Modified message"),
|
||||
frame => Assert.Same(nestedComponentInstance, frame.Component));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -347,7 +347,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
renderer.RenderNewBatch(rootComponentId);
|
||||
|
||||
var originalComponentInstance = (FakeComponent)renderer.Batches.Single().RenderTreesByComponentId[rootComponentId]
|
||||
.Single(node => node.NodeType == RenderTreeNodeType.Component)
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component)
|
||||
.Component;
|
||||
|
||||
// Assert 1: properties were assigned
|
||||
|
|
@ -360,7 +360,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
renderer.RenderNewBatch(rootComponentId);
|
||||
|
||||
var updatedComponentInstance = (FakeComponent)renderer.Batches[1].RenderTreesByComponentId[rootComponentId]
|
||||
.Single(node => node.NodeType == RenderTreeNodeType.Component)
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component)
|
||||
.Component;
|
||||
|
||||
// Assert
|
||||
|
|
@ -387,19 +387,19 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
renderer.RenderNewBatch(rootComponentId);
|
||||
|
||||
var childComponentId = renderer.Batches.Single().RenderTreesByComponentId[rootComponentId]
|
||||
.Single(node => node.NodeType == RenderTreeNodeType.Component)
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component)
|
||||
.ComponentId;
|
||||
|
||||
// Act: Second render
|
||||
firstRender = false;
|
||||
renderer.RenderNewBatch(rootComponentId);
|
||||
|
||||
var updatedComponentNode = renderer.Batches[1].RenderTreesByComponentId[rootComponentId]
|
||||
.Single(node => node.NodeType == RenderTreeNodeType.Component);
|
||||
var updatedComponentFrame = renderer.Batches[1].RenderTreesByComponentId[rootComponentId]
|
||||
.Single(frame => frame.FrameType == RenderTreeFrameType.Component);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(renderer.Batches[1].RenderTreesByComponentId[updatedComponentNode.ComponentId],
|
||||
node => AssertNode.Text(node, "second"));
|
||||
Assert.Collection(renderer.Batches[1].RenderTreesByComponentId[updatedComponentFrame.ComponentId],
|
||||
frame => AssertFrame.Text(frame, "second"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -428,8 +428,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
// Act/Assert 1: First render, capturing child component IDs
|
||||
renderer.RenderNewBatch(rootComponentId);
|
||||
var childComponentIds = renderer.Batches.Single().RenderTreesByComponentId[rootComponentId]
|
||||
.Where(node => node.NodeType == RenderTreeNodeType.Component)
|
||||
.Select(node => node.ComponentId)
|
||||
.Where(frame => frame.FrameType == RenderTreeFrameType.Component)
|
||||
.Select(frame => frame.ComponentId)
|
||||
.ToList();
|
||||
Assert.Equal(childComponentIds, new[] { 1, 2, 3 });
|
||||
|
||||
|
|
@ -486,8 +486,8 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
|
||||
private class CapturedBatch
|
||||
{
|
||||
public IDictionary<int, RenderTreeNode[]> RenderTreesByComponentId { get; }
|
||||
= new Dictionary<int, RenderTreeNode[]>();
|
||||
public IDictionary<int, RenderTreeFrame[]> RenderTreesByComponentId { get; }
|
||||
= new Dictionary<int, RenderTreeFrame[]>();
|
||||
|
||||
public IList<int> DisposedComponentIDs { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Blazor.Components;
|
||||
using Microsoft.AspNetCore.Blazor.RenderTree;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Blazor.Test.Shared
|
||||
{
|
||||
internal static class AssertFrame
|
||||
{
|
||||
public static void Sequence(RenderTreeFrame frame, int? sequence = null)
|
||||
{
|
||||
if (sequence.HasValue)
|
||||
{
|
||||
Assert.Equal(sequence.Value, frame.Sequence);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Text(RenderTreeFrame frame, string textContent, int? sequence = null)
|
||||
{
|
||||
Assert.Equal(RenderTreeFrameType.Text, frame.FrameType);
|
||||
Assert.Equal(textContent, frame.TextContent);
|
||||
Assert.Equal(0, frame.ElementDescendantsEndIndex);
|
||||
AssertFrame.Sequence(frame, sequence);
|
||||
}
|
||||
|
||||
public static void Element(RenderTreeFrame frame, string elementName, int descendantsEndIndex, int? sequence = null)
|
||||
{
|
||||
Assert.Equal(RenderTreeFrameType.Element, frame.FrameType);
|
||||
Assert.Equal(elementName, frame.ElementName);
|
||||
Assert.Equal(descendantsEndIndex, frame.ElementDescendantsEndIndex);
|
||||
AssertFrame.Sequence(frame, sequence);
|
||||
}
|
||||
|
||||
public static void Attribute(RenderTreeFrame frame, string attributeName, int? sequence = null)
|
||||
{
|
||||
Assert.Equal(RenderTreeFrameType.Attribute, frame.FrameType);
|
||||
Assert.Equal(attributeName, frame.AttributeName);
|
||||
AssertFrame.Sequence(frame, sequence);
|
||||
}
|
||||
|
||||
public static void Attribute(RenderTreeFrame frame, string attributeName, string attributeValue, int? sequence = null)
|
||||
{
|
||||
AssertFrame.Attribute(frame, attributeName, sequence);
|
||||
Assert.Equal(attributeValue, frame.AttributeValue);
|
||||
}
|
||||
|
||||
public static void Attribute(RenderTreeFrame frame, string attributeName, UIEventHandler attributeEventHandlerValue, int? sequence = null)
|
||||
{
|
||||
AssertFrame.Attribute(frame, attributeName, sequence);
|
||||
Assert.Equal(attributeEventHandlerValue, frame.AttributeValue);
|
||||
}
|
||||
|
||||
public static void Component<T>(RenderTreeFrame frame, int? sequence = null) where T : IComponent
|
||||
{
|
||||
Assert.Equal(RenderTreeFrameType.Component, frame.FrameType);
|
||||
Assert.Equal(typeof(T), frame.ComponentType);
|
||||
AssertFrame.Sequence(frame, sequence);
|
||||
}
|
||||
|
||||
public static void Whitespace(RenderTreeFrame frame, int? sequence = null)
|
||||
{
|
||||
Assert.Equal(RenderTreeFrameType.Text, frame.FrameType);
|
||||
AssertFrame.Sequence(frame, sequence);
|
||||
Assert.True(string.IsNullOrWhiteSpace(frame.TextContent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Blazor.Components;
|
||||
using Microsoft.AspNetCore.Blazor.RenderTree;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Blazor.Test.Shared
|
||||
{
|
||||
internal static class AssertNode
|
||||
{
|
||||
public static void Sequence(RenderTreeNode node, int? sequence = null)
|
||||
{
|
||||
if (sequence.HasValue)
|
||||
{
|
||||
Assert.Equal(sequence.Value, node.Sequence);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Text(RenderTreeNode node, string textContent, int? sequence = null)
|
||||
{
|
||||
Assert.Equal(RenderTreeNodeType.Text, node.NodeType);
|
||||
Assert.Equal(textContent, node.TextContent);
|
||||
Assert.Equal(0, node.ElementDescendantsEndIndex);
|
||||
AssertNode.Sequence(node, sequence);
|
||||
}
|
||||
|
||||
public static void Element(RenderTreeNode node, string elementName, int descendantsEndIndex, int? sequence = null)
|
||||
{
|
||||
Assert.Equal(RenderTreeNodeType.Element, node.NodeType);
|
||||
Assert.Equal(elementName, node.ElementName);
|
||||
Assert.Equal(descendantsEndIndex, node.ElementDescendantsEndIndex);
|
||||
AssertNode.Sequence(node, sequence);
|
||||
}
|
||||
|
||||
public static void Attribute(RenderTreeNode node, string attributeName, int? sequence = null)
|
||||
{
|
||||
Assert.Equal(RenderTreeNodeType.Attribute, node.NodeType);
|
||||
Assert.Equal(attributeName, node.AttributeName);
|
||||
AssertNode.Sequence(node, sequence);
|
||||
}
|
||||
|
||||
public static void Attribute(RenderTreeNode node, string attributeName, string attributeValue, int? sequence = null)
|
||||
{
|
||||
AssertNode.Attribute(node, attributeName, sequence);
|
||||
Assert.Equal(attributeValue, node.AttributeValue);
|
||||
}
|
||||
|
||||
public static void Attribute(RenderTreeNode node, string attributeName, UIEventHandler attributeEventHandlerValue, int? sequence = null)
|
||||
{
|
||||
AssertNode.Attribute(node, attributeName, sequence);
|
||||
Assert.Equal(attributeEventHandlerValue, node.AttributeValue);
|
||||
}
|
||||
|
||||
public static void Component<T>(RenderTreeNode node, int? sequence = null) where T : IComponent
|
||||
{
|
||||
Assert.Equal(RenderTreeNodeType.Component, node.NodeType);
|
||||
Assert.Equal(typeof(T), node.ComponentType);
|
||||
AssertNode.Sequence(node, sequence);
|
||||
}
|
||||
|
||||
public static void Whitespace(RenderTreeNode node, int? sequence = null)
|
||||
{
|
||||
Assert.Equal(RenderTreeNodeType.Text, node.NodeType);
|
||||
AssertNode.Sequence(node, sequence);
|
||||
Assert.True(string.IsNullOrWhiteSpace(node.TextContent));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue