diff --git a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs index 4032206bb1..5dc2bee774 100644 --- a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs +++ b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs @@ -254,7 +254,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal // If we're not after an equal then we should treat the value as if it were a minimized attribute. var attributeValueBuilder = afterEquals ? builder : null; result.AttributeValueNode = - CreateMarkupAttribute(name, attributeValueBuilder, result.IsBoundNonStringAttribute); + CreateMarkupAttribute(attributeValueBuilder, result.IsBoundNonStringAttribute); return result; } @@ -337,17 +337,45 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal var spanBuilder = new SpanBuilder(child); result.AttributeValueNode = - CreateMarkupAttribute(name, spanBuilder, result.IsBoundNonStringAttribute); + CreateMarkupAttribute(spanBuilder, result.IsBoundNonStringAttribute); return result; } } - result.AttributeValueNode = block; + result.AttributeValueNode = ConvertToMarkupAttributeBlock(block, result.IsBoundNonStringAttribute); return result; } + private static Block ConvertToMarkupAttributeBlock(Block block, bool isBoundNonStringAttribute) + { + var blockBuilder = new BlockBuilder + { + ChunkGenerator = block.ChunkGenerator, + Type = block.Type + }; + + foreach (var child in block.Children) + { + SyntaxTreeNode markupAttributeChild; + + if (child.IsBlock) + { + markupAttributeChild = ConvertToMarkupAttributeBlock((Block)child, isBoundNonStringAttribute); + } + else + { + var spanBuilder = new SpanBuilder((Span)child); + markupAttributeChild = CreateMarkupAttribute(spanBuilder, isBoundNonStringAttribute); + } + + blockBuilder.Children.Add(markupAttributeChild); + } + + return blockBuilder.Build(); + } + private static Block RebuildChunkGenerators(Block block) { var builder = new BlockBuilder(block); @@ -440,10 +468,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal return nodeStart + firstNonWhitespaceSymbol.Start; } - private static SyntaxTreeNode CreateMarkupAttribute( - string name, - SpanBuilder builder, - bool isBoundNonStringAttribute) + private static SyntaxTreeNode CreateMarkupAttribute(SpanBuilder builder, bool isBoundNonStringAttribute) { Span value = null; diff --git a/test/Microsoft.AspNet.Razor.Test/Framework/TestSpanBuilder.cs b/test/Microsoft.AspNet.Razor.Test/Framework/TestSpanBuilder.cs index 258bbd2a7d..9f607c7db7 100644 --- a/test/Microsoft.AspNet.Razor.Test/Framework/TestSpanBuilder.cs +++ b/test/Microsoft.AspNet.Razor.Test/Framework/TestSpanBuilder.cs @@ -385,6 +385,12 @@ namespace Microsoft.AspNet.Razor.Test.Framework return Builder.Build(); } + public SpanConstructor As(SpanKind spanKind) + { + Builder.Kind = spanKind; + return this; + } + public SpanConstructor With(ISpanChunkGenerator generator) { Builder.ChunkGenerator = generator; diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs index 0d44d5de5e..f45124d1c5 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs @@ -603,6 +603,58 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupBlock(factory.Markup("Time:"), dateTimeNow)) })) }, + { + "", + new MarkupBlock( + new MarkupTagHelperBlock("person", + selfClosing: true, + attributes: new List> + { + new KeyValuePair( + "age", + new MarkupBlock( + factory.CodeMarkup("1"), + factory.CodeMarkup(" +"), + new MarkupBlock( + factory.CodeMarkup(" "), + new ExpressionBlock( + factory.CodeTransition().As(SpanKind.Code), + factory + .Code("value") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))), + factory.CodeMarkup(" +"), + factory.CodeMarkup(" 2"))), + new KeyValuePair( + "birthday", + new MarkupBlock( + factory.CodeMarkup("(bool)"), + new MarkupBlock( + new ExpressionBlock( + factory.CodeTransition().As(SpanKind.Code), + factory + .Code("Bag[\"val\"]") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))), + factory.CodeMarkup(" ?"), + new MarkupBlock( + factory.CodeMarkup(" @").Accepts(AcceptedCharacters.None), + factory.CodeMarkup("@") + .With(SpanChunkGenerator.Null) + .Accepts(AcceptedCharacters.None)), + factory.CodeMarkup("DateTime"), + factory.CodeMarkup(" :"), + new MarkupBlock( + factory.CodeMarkup(" "), + new ExpressionBlock( + factory.CodeTransition().As(SpanKind.Code), + factory + .Code("DateTime.Now") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))) + )) + })) + }, { "", new MarkupBlock( @@ -675,17 +727,21 @@ namespace Microsoft.AspNet.Razor.TagHelpers "age", new MarkupBlock( new MarkupBlock( - factory.Markup("@").Accepts(AcceptedCharacters.None), - factory.Markup("@") + factory.CodeMarkup("@").Accepts(AcceptedCharacters.None), + factory.CodeMarkup("@") .With(SpanChunkGenerator.Null) .Accepts(AcceptedCharacters.None)), new MarkupBlock( - factory.EmptyHtml(), + factory.EmptyHtml().As(SpanKind.Code), new ExpressionBlock( - factory.CodeTransition(), - factory.MetaCode("(").Accepts(AcceptedCharacters.None), + factory.CodeTransition().As(SpanKind.Code), + factory.MetaCode("(") + .Accepts(AcceptedCharacters.None) + .As(SpanKind.Code), factory.Code("11+1").AsExpression(), - factory.MetaCode(")").Accepts(AcceptedCharacters.None))))), + factory.MetaCode(")") + .Accepts(AcceptedCharacters.None) + .As(SpanKind.Code))))), new KeyValuePair( "birthday", factory.CodeMarkup("DateTime.Now")), @@ -1653,13 +1709,13 @@ namespace Microsoft.AspNet.Razor.TagHelpers "bound", new MarkupBlock( new MarkupBlock( - factory.Markup(" "), + factory.CodeMarkup(" "), new ExpressionBlock( - factory.CodeTransition(), + factory.CodeTransition().As(SpanKind.Code), factory.Code("true") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace))), - factory.Markup(" "))) + factory.CodeMarkup(" "))) } })), new RazorError[0] @@ -1677,13 +1733,17 @@ namespace Microsoft.AspNet.Razor.TagHelpers "bound", new MarkupBlock( new MarkupBlock( - factory.Markup(" "), + factory.CodeMarkup(" "), new ExpressionBlock( - factory.CodeTransition(), - factory.MetaCode("(").Accepts(AcceptedCharacters.None), + factory.CodeTransition().As(SpanKind.Code), + factory.MetaCode("(") + .Accepts(AcceptedCharacters.None) + .As(SpanKind.Code), factory.Code("true").AsExpression(), - factory.MetaCode(")").Accepts(AcceptedCharacters.None))), - factory.Markup(" "))) + factory.MetaCode(")") + .Accepts(AcceptedCharacters.None) + .As(SpanKind.Code))), + factory.CodeMarkup(" "))) } })), new RazorError[0] diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs index 0b1172a37d..bf5b6cce8f 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs @@ -1131,7 +1131,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupBlock( new ExpressionBlock( - factory.CodeTransition(), + factory.CodeTransition().As(SpanKind.Code), factory.Code("DateTime.Now") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace))))) @@ -1153,7 +1153,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupBlock( new ExpressionBlock( - factory.CodeTransition(), + factory.CodeTransition().As(SpanKind.Code), factory.Code("DateTime.Now") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace))))) @@ -1174,12 +1174,12 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "bound", new MarkupBlock( new MarkupBlock( - factory.Markup("@").Accepts(AcceptedCharacters.None), - factory.Markup("@").With(SpanChunkGenerator.Null).Accepts(AcceptedCharacters.None)), + factory.CodeMarkup("@").Accepts(AcceptedCharacters.None), + factory.CodeMarkup("@").With(SpanChunkGenerator.Null).Accepts(AcceptedCharacters.None)), new MarkupBlock( - factory.EmptyHtml(), + factory.EmptyHtml().As(SpanKind.Code), new ExpressionBlock( - factory.CodeTransition(), + factory.CodeTransition().As(SpanKind.Code), factory.Code("DateTime.Now") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace)))))