-
Notifications
You must be signed in to change notification settings - Fork 222
Add support for minimized attributes in TagHelpers. #372
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ public GeneratedTagHelperContext() | |
ScopeManagerEndMethodName = "End"; | ||
ExecutionContextAddMethodName = "Add"; | ||
ExecutionContextAddTagHelperAttributeMethodName = "AddTagHelperAttribute"; | ||
ExecutionContextAddMinimizedHtmlAttributeMethodName = "AddMinimizedHtmlAttribute"; | ||
ExecutionContextAddHtmlAttributeMethodName = "AddHtmlAttribute"; | ||
ExecutionContextOutputPropertyName = "Output"; | ||
MarkAsHtmlEncodedMethodName = "Html.Raw"; | ||
|
@@ -57,6 +58,11 @@ public GeneratedTagHelperContext() | |
/// </summary> | ||
public string ExecutionContextAddTagHelperAttributeMethodName { get; set; } | ||
|
||
/// <summary> | ||
/// The name of the <see cref="ExecutionContextTypeName"/> method used to add minimized HTML attributes. | ||
/// </summary> | ||
public string ExecutionContextAddMinimizedHtmlAttributeMethodName { get; set; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So there's going to be an MVC reaction PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Si. |
||
|
||
/// <summary> | ||
/// The name of the <see cref="ExecutionContextTypeName"/> method used to add HTML attributes. | ||
/// </summary> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -473,12 +473,25 @@ private void BeforeAttribute() | |
|
||
if (!At(HtmlSymbolType.Equals)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since parser gets confused by whitespace, how will There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
{ | ||
// Saw a space or newline after the name, so just skip this attribute and continue around the loop | ||
Accept(whitespace); | ||
Accept(name); | ||
// Minimized attribute | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most of the comment at this spot in previous iterations was useful. It described what the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In particular, remind the reader what has already been accepted i.e. what the first |
||
|
||
// Output anything prior to the attribute, in most cases this will be the tag name: | ||
// |<input| checked />. If in-between other attributes this will noop or output malformed attribute | ||
// content (if the previous attribute was malformed). | ||
Output(SpanKind.Markup); | ||
|
||
using (Context.StartBlock(BlockType.Markup)) | ||
{ | ||
Accept(whitespace); | ||
Accept(name); | ||
Output(SpanKind.Markup); | ||
} | ||
|
||
return; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a comment right below here reminding user that we're in the mainline scenario at this point i.e. recovery and minimized attribute cases were handled above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanx |
||
// Not a minimized attribute, parse as if it were well-formed (if attribute turns out to be malformed we | ||
// will go into recovery). | ||
Output(SpanKind.Markup); | ||
|
||
// Start a new markup block for the attribute | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// 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; | ||
|
@@ -71,11 +71,12 @@ private static IList<KeyValuePair<string, SyntaxTreeNode>> GetTagAttributes( | |
// Only want to track the attribute if we succeeded in parsing its corresponding Block/Span. | ||
if (succeeded) | ||
{ | ||
// Check if it's a bound attribute that is not of type string and happens to be null or whitespace. | ||
// Check if it's a bound attribute that is minimized or not of type string and null or whitespace. | ||
string attributeValueType; | ||
if (attributeValueTypes.TryGetValue(attribute.Key, out attributeValueType) && | ||
(attribute.Value == null || | ||
!IsStringAttribute(attributeValueType) && | ||
IsNullOrWhitespaceAttributeValue(attribute.Value)) | ||
IsNullOrWhitespaceAttributeValue(attribute.Value))) | ||
{ | ||
var errorLocation = GetAttributeNameStartLocation(child); | ||
|
||
|
@@ -167,7 +168,7 @@ private static bool TryParseSpan( | |
{ | ||
Debug.Assert( | ||
name != null, | ||
"Name should never be null here. The parser should guaruntee an attribute has a name."); | ||
"Name should never be null here. The parser should guarantee an attribute has a name."); | ||
|
||
// We've captured all leading whitespace and the attribute name. | ||
// We're now at: " asp-for|='...'" or " asp-for|=..." | ||
|
@@ -239,7 +240,9 @@ private static bool TryParseSpan( | |
return false; | ||
} | ||
|
||
attribute = CreateMarkupAttribute(name, builder, attributeValueTypes); | ||
// If we're not after an equal then we should treat the value as if it were a minimized attribute. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we don't run into an |
||
var attributeValueBuilder = afterEquals ? builder : null; | ||
attribute = CreateMarkupAttribute(name, attributeValueBuilder, attributeValueTypes); | ||
|
||
return true; | ||
} | ||
|
@@ -432,17 +435,24 @@ private static KeyValuePair<string, SyntaxTreeNode> CreateMarkupAttribute( | |
IReadOnlyDictionary<string, string> attributeValueTypes) | ||
{ | ||
string attributeTypeName; | ||
Span value = null; | ||
|
||
// If the attribute was requested by the tag helper and doesn't happen to be a string then we need to treat | ||
// its value as code. Any non-string value can be any C# value so we need to ensure the SyntaxTreeNode | ||
// reflects that. | ||
if (attributeValueTypes.TryGetValue(name, out attributeTypeName) && | ||
!IsStringAttribute(attributeTypeName)) | ||
// Builder will be null in the case of minimized attributes | ||
if (builder != null) | ||
{ | ||
builder.Kind = SpanKind.Code; | ||
// If the attribute was requested by the tag helper and doesn't happen to be a string then we need to treat | ||
// its value as code. Any non-string value can be any C# value so we need to ensure the SyntaxTreeNode | ||
// reflects that. | ||
if (attributeValueTypes.TryGetValue(name, out attributeTypeName) && | ||
!IsStringAttribute(attributeTypeName)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: why is this line wrapped? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Long line otherwise. |
||
{ | ||
builder.Kind = SpanKind.Code; | ||
} | ||
|
||
value = builder.Build(); | ||
} | ||
|
||
return new KeyValuePair<string, SyntaxTreeNode>(name, builder.Build()); | ||
return new KeyValuePair<string, SyntaxTreeNode>(name, value); | ||
} | ||
|
||
private static bool IsNullOrWhitespaceAttributeValue(SyntaxTreeNode attributeValue) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,6 @@ | |
|
||
using System; | ||
using System.Collections.Generic; | ||
using Microsoft.Internal.Web.Utils; | ||
|
||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers | ||
{ | ||
|
@@ -26,16 +25,13 @@ public bool Equals(IReadOnlyTagHelperAttribute attributeX, IReadOnlyTagHelperAtt | |
// Normal comparer (TagHelperAttribute.Equals()) doesn't care about the Name case, in tests we do. | ||
return attributeX != null && | ||
string.Equals(attributeX.Name, attributeY.Name, StringComparison.Ordinal) && | ||
Equals(attributeX.Value, attributeY.Value); | ||
attributeX.Minimized == attributeY.Minimized && | ||
(attributeX.Minimized || Equals(attributeX.Value, attributeY.Value)); | ||
} | ||
|
||
public int GetHashCode(IReadOnlyTagHelperAttribute attribute) | ||
{ | ||
return HashCodeCombiner | ||
.Start() | ||
.Add(attribute.Name, StringComparer.Ordinal) | ||
.Add(attribute.Value) | ||
.CombinedHash; | ||
return attribute.GetHashCode(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 though I don't see how this relates to the rest of this PR. should at least be separately mentioned in the PR and commit descriptions. |
||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't repeat the same comment with slightly different words.