Add DOM rendering capability for attributes
This commit is contained in:
parent
0db6f5cc5d
commit
f7cb54121b
|
|
@ -58,6 +58,8 @@ function insertNode(intoDomElement: Element, tree: System_Array, node: UITreeNod
|
||||||
case NodeType.text:
|
case NodeType.text:
|
||||||
insertText(intoDomElement, node);
|
insertText(intoDomElement, node);
|
||||||
break;
|
break;
|
||||||
|
case NodeType.attribute:
|
||||||
|
throw new Error('Attribute nodes should only be present as leading children of element nodes.');
|
||||||
default:
|
default:
|
||||||
const unknownType: never = nodeType; // Compile-time verification that the switch was exhaustive
|
const unknownType: never = nodeType; // Compile-time verification that the switch was exhaustive
|
||||||
throw new Error(`Unknown node type: ${ unknownType }`);
|
throw new Error(`Unknown node type: ${ unknownType }`);
|
||||||
|
|
@ -69,9 +71,26 @@ function insertElement(intoDomElement: Element, tree: System_Array, elementNode:
|
||||||
const newDomElement = document.createElement(tagName);
|
const newDomElement = document.createElement(tagName);
|
||||||
intoDomElement.appendChild(newDomElement);
|
intoDomElement.appendChild(newDomElement);
|
||||||
|
|
||||||
// Recursively insert children
|
// Apply attributes
|
||||||
const descendantsEndIndex = uiTreeNode.descendantsEndIndex(elementNode);
|
const descendantsEndIndex = uiTreeNode.descendantsEndIndex(elementNode);
|
||||||
insertNodeRange(newDomElement, tree, elementNodeIndex + 1, descendantsEndIndex);
|
for (let descendantIndex = elementNodeIndex + 1; descendantIndex <= descendantsEndIndex; descendantIndex++) {
|
||||||
|
const descendantNode = getTreeNodePtr(tree, descendantIndex);
|
||||||
|
if (uiTreeNode.nodeType(descendantNode) === NodeType.attribute) {
|
||||||
|
applyAttribute(newDomElement, descendantNode);
|
||||||
|
} else {
|
||||||
|
// As soon as we see a non-attribute child, all the subsequent child nodes are
|
||||||
|
// not attributes, so bail out and insert the remnants recursively
|
||||||
|
insertNodeRange(newDomElement, tree, descendantIndex, descendantsEndIndex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyAttribute(toDomElement: Element, attributeNode: UITreeNodePointer) {
|
||||||
|
toDomElement.setAttribute(
|
||||||
|
uiTreeNode.attributeName(attributeNode),
|
||||||
|
uiTreeNode.attributeValue(attributeNode)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertText(intoDomElement: Element, textNode: UITreeNodePointer) {
|
function insertText(intoDomElement: Element, textNode: UITreeNodePointer) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { System_String, System_Array, Pointer } from '../Platform/Platform';
|
import { System_String, System_Array, Pointer } from '../Platform/Platform';
|
||||||
import { platform } from '../Environment';
|
import { platform } from '../Environment';
|
||||||
const uiTreeNodeStructLength = 16;
|
const uiTreeNodeStructLength = 24;
|
||||||
|
|
||||||
// To minimise GC pressure, instead of instantiating a JS object to represent each tree node,
|
// 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
|
// we work in terms of pointers to the structs on the .NET heap, and use static functions that
|
||||||
|
|
@ -16,12 +16,15 @@ export const uiTreeNode = {
|
||||||
elementName: (node: UITreeNodePointer) => _readStringProperty(node, 4),
|
elementName: (node: UITreeNodePointer) => _readStringProperty(node, 4),
|
||||||
descendantsEndIndex: (node: UITreeNodePointer) => _readInt32Property(node, 8) as NodeType,
|
descendantsEndIndex: (node: UITreeNodePointer) => _readInt32Property(node, 8) as NodeType,
|
||||||
textContent: (node: UITreeNodePointer) => _readStringProperty(node, 12),
|
textContent: (node: UITreeNodePointer) => _readStringProperty(node, 12),
|
||||||
|
attributeName: (node: UITreeNodePointer) => _readStringProperty(node, 16),
|
||||||
|
attributeValue: (node: UITreeNodePointer) => _readStringProperty(node, 20),
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum NodeType {
|
export enum NodeType {
|
||||||
// The values must be kept in sync with the .NET equivalent in UITreeNodeType.cs
|
// The values must be kept in sync with the .NET equivalent in UITreeNodeType.cs
|
||||||
element = 1,
|
element = 1,
|
||||||
text = 2
|
text = 2,
|
||||||
|
attribute = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
function _readInt32Property(baseAddress: Pointer, offsetBytes: number) {
|
function _readInt32Property(baseAddress: Pointer, offsetBytes: number) {
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,19 @@ namespace Microsoft.Blazor.E2ETest.Tests
|
||||||
Assert.Equal("Hello from TextOnlyComponent", appElement.Text);
|
Assert.Equal("Hello from TextOnlyComponent", appElement.Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CanRenderComponentWithAttributes()
|
||||||
|
{
|
||||||
|
Navigate("/", noReload: true);
|
||||||
|
MountTestComponent("BasicTestApp.RedTextComponent");
|
||||||
|
|
||||||
|
var appElement = Browser.FindElement(By.TagName("app"));
|
||||||
|
var styledElement = appElement.FindElement(By.TagName("h1"));
|
||||||
|
Assert.Equal("Hello, world!", styledElement.Text);
|
||||||
|
Assert.Equal("color: red;", styledElement.GetAttribute("style"));
|
||||||
|
Assert.Equal("somevalue", styledElement.GetAttribute("customattribute"));
|
||||||
|
}
|
||||||
|
|
||||||
private void MountTestComponent(string componentTypeName)
|
private void MountTestComponent(string componentTypeName)
|
||||||
{
|
{
|
||||||
WaitUntilDotNetRunningInBrowser();
|
WaitUntilDotNetRunningInBrowser();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// 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 Microsoft.Blazor.Components;
|
||||||
|
using Microsoft.Blazor.UITree;
|
||||||
|
|
||||||
|
namespace BasicTestApp
|
||||||
|
{
|
||||||
|
public class RedTextComponent : IComponent
|
||||||
|
{
|
||||||
|
public void BuildUITree(UITreeBuilder builder)
|
||||||
|
{
|
||||||
|
builder.OpenElement("h1");
|
||||||
|
builder.AddAttribute("style", "color: red;");
|
||||||
|
builder.AddAttribute("customattribute", "somevalue");
|
||||||
|
builder.AddText("Hello, world!");
|
||||||
|
builder.CloseElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue