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);
    }
예제 #3
0
    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();
            }
        }
    }