Add DOM rendering capability for attributes

This commit is contained in:
Steve Sanderson 2018-01-05 17:50:03 +00:00
parent 0db6f5cc5d
commit f7cb54121b
4 changed files with 59 additions and 4 deletions

View File

@ -58,6 +58,8 @@ function insertNode(intoDomElement: Element, tree: System_Array, node: UITreeNod
case NodeType.text:
insertText(intoDomElement, node);
break;
case NodeType.attribute:
throw new Error('Attribute nodes should only be present as leading children of element nodes.');
default:
const unknownType: never = nodeType; // Compile-time verification that the switch was exhaustive
throw new Error(`Unknown node type: ${ unknownType }`);
@ -69,9 +71,26 @@ function insertElement(intoDomElement: Element, tree: System_Array, elementNode:
const newDomElement = document.createElement(tagName);
intoDomElement.appendChild(newDomElement);
// Recursively insert children
// Apply attributes
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) {

View File

@ -1,6 +1,6 @@
import { System_String, System_Array, Pointer } from '../Platform/Platform';
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,
// 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),
descendantsEndIndex: (node: UITreeNodePointer) => _readInt32Property(node, 8) as NodeType,
textContent: (node: UITreeNodePointer) => _readStringProperty(node, 12),
attributeName: (node: UITreeNodePointer) => _readStringProperty(node, 16),
attributeValue: (node: UITreeNodePointer) => _readStringProperty(node, 20),
};
export enum NodeType {
// The values must be kept in sync with the .NET equivalent in UITreeNodeType.cs
element = 1,
text = 2
text = 2,
attribute = 3,
}
function _readInt32Property(baseAddress: Pointer, offsetBytes: number) {

View File

@ -36,6 +36,19 @@ namespace Microsoft.Blazor.E2ETest.Tests
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)
{
WaitUntilDotNetRunningInBrowser();

View File

@ -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();
}
}
}