Add Multiple attribute same name understanding to TagHelperChunk.

- This also involved adding understanding to CSharpTagHelperCodeRenderer.
- When rebasing this commit was lost as part of: 7c604d2b11 .

#279
This commit is contained in:
N. Taylor Mullen 2015-04-30 14:57:23 -07:00
parent 6384977e96
commit e3fdb8886a
4 changed files with 19 additions and 17 deletions

View File

@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
public void RenderTagHelper(TagHelperChunk chunk) public void RenderTagHelper(TagHelperChunk chunk)
{ {
// Remove any duplicate TagHelperDescriptors that reference the same type name. Duplicates can occur when // Remove any duplicate TagHelperDescriptors that reference the same type name. Duplicates can occur when
// multiple TargetElement attributes are on a TagHelper type and matchs overlap for an HTML element. // multiple TargetElement attributes are on a TagHelper type and matches overlap for an HTML element.
// Having more than one descriptor with the same TagHelper type results in generated code that runs // Having more than one descriptor with the same TagHelper type results in generated code that runs
// the same TagHelper X many times (instead of once) over a single HTML element. // the same TagHelper X many times (instead of once) over a single HTML element.
var tagHelperDescriptors = chunk.Descriptors.Distinct(TypeNameTagHelperDescriptorComparer.Default); var tagHelperDescriptors = chunk.Descriptors.Distinct(TypeNameTagHelperDescriptorComparer.Default);
@ -190,20 +190,21 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
} }
} }
private void RenderBoundHTMLAttributes(IDictionary<string, Chunk> chunkAttributes, private void RenderBoundHTMLAttributes(IList<KeyValuePair<string, Chunk>> chunkAttributes,
string tagHelperVariableName, string tagHelperVariableName,
IEnumerable<TagHelperAttributeDescriptor> attributeDescriptors, IEnumerable<TagHelperAttributeDescriptor> attributeDescriptors,
Dictionary<string, string> htmlAttributeValues) Dictionary<string, string> htmlAttributeValues)
{ {
foreach (var attributeDescriptor in attributeDescriptors) foreach (var attributeDescriptor in attributeDescriptors)
{ {
Chunk attributeValueChunk; var matchingAttributes = chunkAttributes.Where(
attr => string.Equals(attr.Key, attributeDescriptor.Name, StringComparison.OrdinalIgnoreCase));
var providedAttribute = chunkAttributes.TryGetValue(attributeDescriptor.Name, if (matchingAttributes.Any())
out attributeValueChunk);
if (providedAttribute)
{ {
// First attribute wins, even if there's duplicates.
var attributeValueChunk = matchingAttributes.First().Value;
var attributeValueRecorded = htmlAttributeValues.ContainsKey(attributeDescriptor.Name); var attributeValueRecorded = htmlAttributeValues.ContainsKey(attributeDescriptor.Name);
// Bufferable attributes are attributes that can have Razor code inside of them. // Bufferable attributes are attributes that can have Razor code inside of them.

View File

@ -25,7 +25,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
public TagHelperChunk( public TagHelperChunk(
string tagName, string tagName,
bool selfClosing, bool selfClosing,
IDictionary<string, Chunk> attributes, IList<KeyValuePair<string, Chunk>> attributes,
IEnumerable<TagHelperDescriptor> descriptors) IEnumerable<TagHelperDescriptor> descriptors)
{ {
TagName = tagName; TagName = tagName;
@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
/// These attributes are <see cref="string"/> => <see cref="Chunk"/> so attribute values can consist /// These attributes are <see cref="string"/> => <see cref="Chunk"/> so attribute values can consist
/// of all sorts of Razor specific pieces. /// of all sorts of Razor specific pieces.
/// </remarks> /// </remarks>
public IDictionary<string, Chunk> Attributes { get; set; } public IList<KeyValuePair<string, Chunk>> Attributes { get; set; }
/// <summary> /// <summary>
/// The <see cref="TagHelperDescriptor"/>s that are associated with the tag helpers HTML element. /// The <see cref="TagHelperDescriptor"/>s that are associated with the tag helpers HTML element.

View File

@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Razor.Generator
RazorResources.TagHelpers_TagHelperCodeGeneartorMustBeAssociatedWithATagHelperBlock); RazorResources.TagHelpers_TagHelperCodeGeneartorMustBeAssociatedWithATagHelperBlock);
} }
var attributes = new Dictionary<string, Chunk>(StringComparer.OrdinalIgnoreCase); var attributes = new List<KeyValuePair<string, Chunk>>();
// We need to create a code generator to create chunks for each of the attributes. // We need to create a code generator to create chunks for each of the attributes.
var codeGenerator = context.Host.CreateCodeGenerator( var codeGenerator = context.Host.CreateCodeGenerator(
@ -63,12 +63,13 @@ namespace Microsoft.AspNet.Razor.Generator
var chunks = codeGenerator.Context.CodeTreeBuilder.CodeTree.Chunks; var chunks = codeGenerator.Context.CodeTreeBuilder.CodeTree.Chunks;
var first = chunks.FirstOrDefault(); var first = chunks.FirstOrDefault();
attributes[attribute.Key] = new ChunkBlock attributes.Add(new KeyValuePair<string, Chunk>(attribute.Key,
{ new ChunkBlock
Association = first?.Association, {
Children = chunks, Association = first?.Association,
Start = first == null ? SourceLocation.Zero : first.Start Children = chunks,
}; Start = first == null ? SourceLocation.Zero : first.Start
}));
// Reset the code tree builder so we can build a new one for the next attribute // Reset the code tree builder so we can build a new one for the next attribute
codeGenerator.Context.CodeTreeBuilder = new CodeTreeBuilder(); codeGenerator.Context.CodeTreeBuilder = new CodeTreeBuilder();

View File

@ -133,7 +133,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
return new TagHelperChunk( return new TagHelperChunk(
tagName, tagName,
selfClosing: false, selfClosing: false,
attributes: new Dictionary<string, Chunk>(), attributes: new List<KeyValuePair<string, Chunk>>(),
descriptors: tagHelperDescriptors) descriptors: tagHelperDescriptors)
{ {
Children = new List<Chunk>(), Children = new List<Chunk>(),