public void WriteTagHelperHtmlAttribute_Runtime_DynamicAttribute_RendersCorrectly() { // Arrange var extension = new DefaultTagHelperTargetExtension(); var context = TestCodeRenderingContext.CreateRuntime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperHtmlAttributeIntermediateNode() { AttributeName = "name", AttributeStructure = AttributeStructure.DoubleQuotes, Children = { new HtmlAttributeValueIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.Html, Content = "Blah-" } } }, new CSharpCodeAttributeValueIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.CSharp, Content = "\"Foo\"", } }, } } }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperHtmlAttribute(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"BeginAddHtmlAttributeValues(__tagHelperExecutionContext, ""name"", 2, global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes); Render Children Render Children EndAddHtmlAttributeValues(__tagHelperExecutionContext); ", csharp, ignoreLineEndingDifferences: true); }
public void WriteTagHelperHtmlAttribute_DesignTime_WritesNothing() { // Arrange var extension = new DefaultTagHelperTargetExtension(); var context = TestCodeRenderingContext.CreateDesignTime(); var tagHelperNode = new TagHelperIntermediateNode(); var node = new DefaultTagHelperHtmlAttributeIntermediateNode() { AttributeName = "name", AttributeStructure = AttributeStructure.DoubleQuotes, Children = { new HtmlAttributeValueIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.Html, Content = "Blah-" } } }, new CSharpCodeAttributeValueIntermediateNode() { Children ={ new IntermediateToken { Kind = TokenKind.CSharp, Content = "\"Foo\"", } }, } } }; tagHelperNode.Children.Add(node); Push(context, tagHelperNode); // Act extension.WriteTagHelperHtmlAttribute(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"Render Children Render Children ", csharp, ignoreLineEndingDifferences: true); }
public PreallocatedTagHelperHtmlAttributeValueIntermediateNode(DefaultTagHelperHtmlAttributeIntermediateNode htmlAttributeNode) { if (htmlAttributeNode == null) { throw new ArgumentNullException(nameof(htmlAttributeNode)); } Source = htmlAttributeNode.Source; for (var i = 0; i < htmlAttributeNode.Children.Count; i++) { Children.Add(htmlAttributeNode.Children[i]); } for (var i = 0; i < htmlAttributeNode.Diagnostics.Count; i++) { Diagnostics.Add(htmlAttributeNode.Diagnostics[i]); } }
public void WriteTagHelperHtmlAttribute(CodeRenderingContext context, DefaultTagHelperHtmlAttributeIntermediateNode node) { if (context.Parent as TagHelperIntermediateNode == null) { var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode)); throw new InvalidOperationException(message); } if (context.Options.DesignTime) { context.RenderChildren(node); } else { var attributeValueStyleParameter = $"{HtmlAttributeValueStyleTypeName}.{node.AttributeStructure}"; var isConditionalAttributeValue = node.Children.Any( child => child is CSharpExpressionAttributeValueIntermediateNode || child is CSharpCodeAttributeValueIntermediateNode); // All simple text and minimized attributes will be pre-allocated. if (isConditionalAttributeValue) { // Dynamic attribute value should be run through the conditional attribute removal system. It's // unbound and contains C#. // TagHelper attribute rendering is buffered by default. We do not want to write to the current // writer. var valuePieceCount = node.Children.Count( child => child is HtmlAttributeValueIntermediateNode || child is CSharpExpressionAttributeValueIntermediateNode || child is CSharpCodeAttributeValueIntermediateNode || child is ExtensionIntermediateNode); context.CodeWriter .WriteStartMethodInvocation(BeginAddHtmlAttributeValuesMethodName) .Write(ExecutionContextVariableName) .WriteParameterSeparator() .WriteStringLiteral(node.AttributeName) .WriteParameterSeparator() .Write(valuePieceCount.ToString(CultureInfo.InvariantCulture)) .WriteParameterSeparator() .Write(attributeValueStyleParameter) .WriteEndMethodInvocation(); context.RenderChildren(node, new TagHelperHtmlAttributeRuntimeNodeWriter()); context.CodeWriter .WriteMethodInvocation( EndAddHtmlAttributeValuesMethodName, ExecutionContextVariableName); } else { // This is a data-* attribute which includes C#. Do not perform the conditional attribute removal or // other special cases used when IsDynamicAttributeValue(). But the attribute must still be buffered to // determine its final value. // Attribute value is not plain text, must be buffered to determine its final value. context.CodeWriter.WriteMethodInvocation(BeginWriteTagHelperAttributeMethodName); // We're building a writing scope around the provided chunks which captures everything written from the // page. Therefore, we do not want to write to any other buffer since we're using the pages buffer to // ensure we capture all content that's written, directly or indirectly. context.RenderChildren(node, new RuntimeNodeWriter()); context.CodeWriter .WriteStartAssignment(StringValueBufferVariableName) .WriteMethodInvocation(EndWriteTagHelperAttributeMethodName) .WriteStartInstanceMethodInvocation( ExecutionContextVariableName, ExecutionContextAddHtmlAttributeMethodName) .WriteStringLiteral(node.AttributeName) .WriteParameterSeparator() .WriteStartMethodInvocation(MarkAsHtmlEncodedMethodName) .Write(StringValueBufferVariableName) .WriteEndMethodInvocation(endLine: false) .WriteParameterSeparator() .Write(attributeValueStyleParameter) .WriteEndMethodInvocation(); } } }