Add concept of "attributes" to UITree. So far the values are only allowed to be strings, but this will have to change later.
This commit is contained in:
parent
f0a78d13bf
commit
0db6f5cc5d
|
|
@ -15,6 +15,7 @@ namespace Microsoft.Blazor.UITree
|
||||||
private UITreeNode[] _entries = new UITreeNode[100];
|
private UITreeNode[] _entries = new UITreeNode[100];
|
||||||
private int _entriesInUse = 0;
|
private int _entriesInUse = 0;
|
||||||
private Stack<int> _openElementIndices = new Stack<int>();
|
private Stack<int> _openElementIndices = new Stack<int>();
|
||||||
|
private UITreeNodeType? _lastNonAttributeNodeType;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Appends a node representing an element, i.e., a container for other nodes.
|
/// Appends a node representing an element, i.e., a container for other nodes.
|
||||||
|
|
@ -46,6 +47,24 @@ namespace Microsoft.Blazor.UITree
|
||||||
public void AddText(string textContent)
|
public void AddText(string textContent)
|
||||||
=> Append(UITreeNode.Text(textContent));
|
=> Append(UITreeNode.Text(textContent));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends a node representing an attribute. The attribute is associated
|
||||||
|
/// with the most recently added element.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the attribute.</param>
|
||||||
|
/// <param name="value">The value of the attribute.</param>
|
||||||
|
public void AddAttribute(string name, string value)
|
||||||
|
{
|
||||||
|
if (_lastNonAttributeNodeType == UITreeNodeType.Element)
|
||||||
|
{
|
||||||
|
Append(UITreeNode.Attribute(name, value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Attributes may only be added immediately after nodes of type {UITreeNodeType.Element}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears the builder.
|
/// Clears the builder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -61,6 +80,7 @@ namespace Microsoft.Blazor.UITree
|
||||||
|
|
||||||
_entriesInUse = 0;
|
_entriesInUse = 0;
|
||||||
_openElementIndices.Clear();
|
_openElementIndices.Clear();
|
||||||
|
_lastNonAttributeNodeType = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -79,6 +99,12 @@ namespace Microsoft.Blazor.UITree
|
||||||
}
|
}
|
||||||
|
|
||||||
_entries[_entriesInUse++] = node;
|
_entries[_entriesInUse++] = node;
|
||||||
|
|
||||||
|
var nodeType = node.NodeType;
|
||||||
|
if (nodeType != UITreeNodeType.Attribute)
|
||||||
|
{
|
||||||
|
_lastNonAttributeNodeType = node.NodeType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@
|
||||||
|
|
||||||
namespace Microsoft.Blazor.UITree
|
namespace Microsoft.Blazor.UITree
|
||||||
{
|
{
|
||||||
|
// TODO: Consider coalescing properties of compatible types that don't need to be
|
||||||
|
// used simultaneously. For example, 'ElementName' and 'AttributeName' could be replaced
|
||||||
|
// by a single 'Name' property.
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an entry in a tree of user interface (UI) items.
|
/// Represents an entry in a tree of user interface (UI) items.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -32,6 +36,18 @@ namespace Microsoft.Blazor.UITree
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string TextContent { get; private set; }
|
public string TextContent { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If the <see cref="NodeType"/> property equals <see cref="UITreeNodeType.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="UITreeNodeType.Attribute"/>,
|
||||||
|
/// gets the attribute value. Otherwise, the value is <see langword="null"/>.
|
||||||
|
/// </summary>
|
||||||
|
public string AttributeValue { get; private set; }
|
||||||
|
|
||||||
internal static UITreeNode Element(string elementName) => new UITreeNode
|
internal static UITreeNode Element(string elementName) => new UITreeNode
|
||||||
{
|
{
|
||||||
NodeType = UITreeNodeType.Element,
|
NodeType = UITreeNodeType.Element,
|
||||||
|
|
@ -44,6 +60,13 @@ namespace Microsoft.Blazor.UITree
|
||||||
TextContent = textContent,
|
TextContent = textContent,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
internal static UITreeNode Attribute(string name, string value) => new UITreeNode
|
||||||
|
{
|
||||||
|
NodeType = UITreeNodeType.Attribute,
|
||||||
|
AttributeName = name,
|
||||||
|
AttributeValue = value
|
||||||
|
};
|
||||||
|
|
||||||
internal void CloseElement(int descendantsEndIndex)
|
internal void CloseElement(int descendantsEndIndex)
|
||||||
{
|
{
|
||||||
ElementDescendantsEndIndex = descendantsEndIndex;
|
ElementDescendantsEndIndex = descendantsEndIndex;
|
||||||
|
|
|
||||||
|
|
@ -17,5 +17,10 @@ namespace Microsoft.Blazor.UITree
|
||||||
/// Represents text content.
|
/// Represents text content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Text = 2,
|
Text = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a key-value pair associated with another <see cref="UITreeNode"/>.
|
||||||
|
/// </summary>
|
||||||
|
Attribute = 3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using Microsoft.Blazor.UITree;
|
using Microsoft.Blazor.UITree;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -130,6 +131,60 @@ namespace Microsoft.Blazor.Test
|
||||||
node => AssertText(node, "standalone text 2"));
|
node => AssertText(node, "standalone text 2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CanAddAttributes()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var builder = new UITreeBuilder();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
builder.OpenElement("myelement"); // 0: <myelement
|
||||||
|
builder.AddAttribute("attribute1", "value 1"); // 1: attribute1="value 1"
|
||||||
|
builder.AddAttribute("attribute2", "value 2"); // 2: attribute2="value 2">
|
||||||
|
builder.OpenElement("child"); // 3: <child
|
||||||
|
builder.AddAttribute("attribute1", "child value"); // 4: attribute1="child value">
|
||||||
|
builder.AddText("some text"); // 5: some text
|
||||||
|
builder.CloseElement(); // </child>
|
||||||
|
builder.CloseElement(); // </myelement>
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(builder.GetNodes(),
|
||||||
|
node => AssertElement(node, "myelement", 5),
|
||||||
|
node => AssertAttribute(node, "attribute1", "value 1"),
|
||||||
|
node => AssertAttribute(node, "attribute2", "value 2"),
|
||||||
|
node => AssertElement(node, "child", 5),
|
||||||
|
node => AssertAttribute(node, "attribute1", "child value"),
|
||||||
|
node => AssertText(node, "some text"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CannotAddAttributesAtRoot()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var builder = new UITreeBuilder();
|
||||||
|
|
||||||
|
// Act/Assert
|
||||||
|
Assert.Throws<InvalidOperationException>(() =>
|
||||||
|
{
|
||||||
|
builder.AddAttribute("name", "value");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CannotAddAttributesToText()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var builder = new UITreeBuilder();
|
||||||
|
|
||||||
|
// Act/Assert
|
||||||
|
Assert.Throws<InvalidOperationException>(() =>
|
||||||
|
{
|
||||||
|
builder.OpenElement("some element");
|
||||||
|
builder.AddText("hello");
|
||||||
|
builder.AddAttribute("name", "value");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CanClear()
|
public void CanClear()
|
||||||
{
|
{
|
||||||
|
|
@ -160,5 +215,12 @@ namespace Microsoft.Blazor.Test
|
||||||
Assert.Equal(elementName, node.ElementName);
|
Assert.Equal(elementName, node.ElementName);
|
||||||
Assert.Equal(descendantsEndIndex, node.ElementDescendantsEndIndex);
|
Assert.Equal(descendantsEndIndex, node.ElementDescendantsEndIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AssertAttribute(UITreeNode node, string attributeName, string attributeValue)
|
||||||
|
{
|
||||||
|
Assert.Equal(UITreeNodeType.Attribute, node.NodeType);
|
||||||
|
Assert.Equal(attributeName, node.AttributeName);
|
||||||
|
Assert.Equal(attributeValue, node.AttributeValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue