diff --git a/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpTagHelperCodeRenderer.cs b/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpTagHelperCodeRenderer.cs index 0ee81fc78c..a75a9d0d33 100644 --- a/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpTagHelperCodeRenderer.cs +++ b/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpTagHelperCodeRenderer.cs @@ -404,25 +404,15 @@ namespace Microsoft.AspNet.Razor.CodeGenerators private void RenderUnboundAttribute(string attributeName, Chunk attributeValueChunk) { - string textValue = null; - var isPlainTextValue = false; - - // A null attribute value means the HTML attribute is minimized. - if (attributeValueChunk != null) - { - isPlainTextValue = TryGetPlainTextValue(attributeValueChunk, out textValue); - - // HTML attributes are always strings. So if this value is not plain text i.e. if the value contains - // C# code, then we need to buffer it. - if (!isPlainTextValue) - { - BuildBufferedWritingScope(attributeValueChunk, htmlEncodeValues: true); - } - } - - // Execution contexts are a runtime feature, therefore no need to add anything to them. + // Render children to provide IntelliSense at design time. No need for the execution context logic, it's + // a runtime feature. if (_designTimeMode) { + if (attributeValueChunk != null) + { + _bodyVisitor.Accept(attributeValueChunk); + } + return; } @@ -438,27 +428,60 @@ namespace Microsoft.AspNet.Razor.CodeGenerators } else { - _writer - .WriteStartInstanceMethodInvocation( - ExecutionContextVariableName, - _tagHelperContext.ExecutionContextAddHtmlAttributeMethodName) - .WriteStringLiteral(attributeName) - .WriteParameterSeparator() - .WriteStartMethodInvocation(_tagHelperContext.MarkAsHtmlEncodedMethodName); + string textValue = null; + var isPlainTextValue = TryGetPlainTextValue(attributeValueChunk, out textValue); - // If it's a plain text value then we need to surround the value with quotes. if (isPlainTextValue) { - _writer.WriteStringLiteral(textValue); + // If it's a plain text value then we need to surround the value with quotes. + _writer + .WriteStartInstanceMethodInvocation( + ExecutionContextVariableName, + _tagHelperContext.ExecutionContextAddHtmlAttributeMethodName) + .WriteStringLiteral(attributeName) + .WriteParameterSeparator() + .WriteStartMethodInvocation(_tagHelperContext.MarkAsHtmlEncodedMethodName) + .WriteStringLiteral(textValue) + .WriteEndMethodInvocation(endLine: false) + .WriteEndMethodInvocation(); + } + else if (IsDynamicAttributeValue(attributeValueChunk)) + { + // Dynamic attribute value should be run through the conditional attribute removal system. It's + // unbound and contains C#. + + _writer + .WriteStartMethodInvocation(_tagHelperContext.AddHtmlAttributeValuesMethodName) + .WriteStringLiteral(attributeName) + .WriteParameterSeparator() + .Write(ExecutionContextVariableName); + + _bodyVisitor.Accept(attributeValueChunk); + + _writer.WriteEndMethodInvocation(); } else { - RenderBufferedAttributeValueAccessor(_writer); - } + // HTML attributes are always strings. This attribute contains C# but is not dynamic. This occurs + // when the attribute is a data-* attribute. - _writer - .WriteEndMethodInvocation(endLine: false) - .WriteEndMethodInvocation(); + // Attribute value is not plain text, must be buffered to determine its final value. + BuildBufferedWritingScope(attributeValueChunk, htmlEncodeValues: true); + + _writer + .WriteStartInstanceMethodInvocation( + ExecutionContextVariableName, + _tagHelperContext.ExecutionContextAddHtmlAttributeMethodName) + .WriteStringLiteral(attributeName) + .WriteParameterSeparator() + .WriteStartMethodInvocation(_tagHelperContext.MarkAsHtmlEncodedMethodName); + + RenderBufferedAttributeValueAccessor(_writer); + + _writer + .WriteEndMethodInvocation(endLine: false) + .WriteEndMethodInvocation(); + } } } @@ -616,6 +639,17 @@ namespace Microsoft.AspNet.Razor.CodeGenerators } } + private static bool IsDynamicAttributeValue(Chunk attributeValueChunk) + { + var parentChunk = attributeValueChunk as ParentChunk; + if (parentChunk != null) + { + return parentChunk.Children.Any(child => child is DynamicCodeAttributeChunk); + } + + return false; + } + private static bool TryGetPlainTextValue(Chunk chunk, out string plainText) { var parentChunk = chunk as ParentChunk; diff --git a/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedTagHelperContext.cs b/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedTagHelperContext.cs index d50d4901da..79380fddfb 100644 --- a/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedTagHelperContext.cs +++ b/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedTagHelperContext.cs @@ -13,6 +13,7 @@ namespace Microsoft.AspNet.Razor.CodeGenerators /// public GeneratedTagHelperContext() { + AddHtmlAttributeValuesMethodName = "AddHtmlAttributeValues"; CreateTagHelperMethodName = "CreateTagHelper"; RunnerRunAsyncMethodName = "RunAsync"; ScopeManagerBeginMethodName = "Begin"; @@ -34,6 +35,20 @@ namespace Microsoft.AspNet.Razor.CodeGenerators WriteTagHelperToAsyncMethodName = "WriteTagHelperToAsync"; } + /// + /// The name of the method used to add unbound, complex tag helper attributes to TagHelperExecutionContexts. + /// + /// + /// Method signature should be + /// + /// public void AddHtmlAttributeValues( + /// string attributeName, + /// TagHelperExecutionContext executionContext, + /// params Microsoft.AspNet.Mvc.Razor.AttributeValue[] values) + /// + /// + public string AddHtmlAttributeValuesMethodName { get; set; } + /// /// The name of the method used to create a tag helper. /// diff --git a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs index 5dc2bee774..94b4c234aa 100644 --- a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs +++ b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs @@ -324,7 +324,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal // We need to rebuild the chunk generators of the builder and its children (this is needed to // ensure we don't do special attribute chunk generation since this is a tag helper). - block = RebuildChunkGenerators(builder.Build()); + block = RebuildChunkGenerators(builder.Build(), result.IsBoundAttribute); // If there's only 1 child at this point its value could be a simple markup span (treated differently than // block level elements for attributes). @@ -376,10 +376,27 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal return blockBuilder.Build(); } - private static Block RebuildChunkGenerators(Block block) + private static Block RebuildChunkGenerators(Block block, bool isBound) { var builder = new BlockBuilder(block); + // Don't want to rebuild unbound dynamic attributes. They need to run through the conditional attribute + // removal system at runtime. A conditional attribute at the parse tree rewriting level is defined by + // having at least 1 child with a DynamicAttributeBlockChunkGenerator. + if (!isBound && + block.Children.Any( + child => child.IsBlock && + ((Block)child).ChunkGenerator is DynamicAttributeBlockChunkGenerator)) + { + // The parent chunk generator must be removed because it's normally responsible for conditionally + // generating the attribute prefix (class=") and suffix ("). The prefix and suffix concepts aren't + // applicable for the TagHelper use case since the attributes are put into a dictionary like object as + // name value pairs. + builder.ChunkGenerator = ParentChunkGenerator.Null; + + return builder.Build(); + } + var isDynamic = builder.ChunkGenerator is DynamicAttributeBlockChunkGenerator; // We don't want any attribute specific logic here, null out the block chunk generator. @@ -395,7 +412,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal if (child.IsBlock) { // The child is a block, recurse down into the block to rebuild its children - builder.Children[i] = RebuildChunkGenerators((Block)child); + builder.Children[i] = RebuildChunkGenerators((Block)child, isBound); } else { diff --git a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs index 472787e151..e456e5774d 100644 --- a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpTagHelperRenderingTest.cs @@ -63,6 +63,29 @@ namespace Microsoft.AspNet.Razor.Test.Generator } } + private static IEnumerable DynamicAttributeTagHelpers_Descriptors + { + get + { + return new[] + { + new TagHelperDescriptor( + tagName: "input", + typeName: "InputTagHelper", + assemblyName: "SomeAssembly", + attributes: new[] + { + new TagHelperAttributeDescriptor( + "bound", + "Bound", + typeof(string).FullName, + isIndexer: false, + designTimeDescriptor: null) + }), + }; + } + } + private static IEnumerable DuplicateTargetTagHelperDescriptors { get @@ -922,6 +945,261 @@ namespace Microsoft.AspNet.Razor.Test.Generator contentLength: 1), } }, + { + "DynamicAttributeTagHelpers", + "DynamicAttributeTagHelpers.DesignTime", + DynamicAttributeTagHelpers_Descriptors, + new List + { + BuildLineMapping( + documentAbsoluteIndex: 14, + documentLineIndex: 0, + generatedAbsoluteIndex: 497, + generatedLineIndex: 15, + characterOffsetIndex: 14, + contentLength: 17), + BuildLineMapping( + documentAbsoluteIndex: 59, + documentLineIndex: 2, + documentCharacterOffsetIndex: 24, + generatedAbsoluteIndex: 1002, + generatedLineIndex: 34, + generatedCharacterOffsetIndex: 6, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 96, + documentLineIndex: 4, + documentCharacterOffsetIndex: 17, + generatedAbsoluteIndex: 1160, + generatedLineIndex: 40, + generatedCharacterOffsetIndex: 0, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 109, + documentLineIndex: 4, + documentCharacterOffsetIndex: 30, + generatedAbsoluteIndex: 1258, + generatedLineIndex: 46, + generatedCharacterOffsetIndex: 6, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 121, + documentLineIndex: 4, + documentCharacterOffsetIndex: 42, + generatedAbsoluteIndex: 1349, + generatedLineIndex: 51, + generatedCharacterOffsetIndex: 0, + contentLength: 10), + BuildLineMapping( + documentAbsoluteIndex: 132, + documentLineIndex: 4, + documentCharacterOffsetIndex: 53, + generatedAbsoluteIndex: 1445, + generatedLineIndex: 57, + generatedCharacterOffsetIndex: 6, + contentLength: 5), + BuildLineMapping( + documentAbsoluteIndex: 137, + documentLineIndex: 4, + documentCharacterOffsetIndex: 58, + generatedAbsoluteIndex: 1529, + generatedLineIndex: 62, + generatedCharacterOffsetIndex: 0, + contentLength: 2), + BuildLineMapping( + documentAbsoluteIndex: 176, + documentLineIndex: 6, + documentCharacterOffsetIndex: 22, + generatedAbsoluteIndex: 1684, + generatedLineIndex: 69, + generatedCharacterOffsetIndex: 6, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 214, + documentLineIndex: 6, + documentCharacterOffsetIndex: 60, + generatedAbsoluteIndex: 1833, + generatedLineIndex: 75, + generatedCharacterOffsetIndex: 6, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 256, + documentLineIndex: 8, + documentCharacterOffsetIndex: 15, + generatedAbsoluteIndex: 1997, + generatedLineIndex: 81, + generatedCharacterOffsetIndex: 6, + contentLength: 13), + BuildLineMapping( + documentAbsoluteIndex: 271, + documentLineIndex: 8, + documentCharacterOffsetIndex: 30, + generatedAbsoluteIndex: 2089, + generatedLineIndex: 86, + generatedCharacterOffsetIndex: 0, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 284, + documentLineIndex: 8, + documentCharacterOffsetIndex: 43, + generatedAbsoluteIndex: 2187, + generatedLineIndex: 92, + generatedCharacterOffsetIndex: 6, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 296, + documentLineIndex: 8, + documentCharacterOffsetIndex: 55, + generatedAbsoluteIndex: 2278, + generatedLineIndex: 97, + generatedCharacterOffsetIndex: 0, + contentLength: 10), + BuildLineMapping( + documentAbsoluteIndex: 307, + documentLineIndex: 8, + documentCharacterOffsetIndex: 66, + generatedAbsoluteIndex: 2374, + generatedLineIndex: 103, + generatedCharacterOffsetIndex: 6, + contentLength: 5), + BuildLineMapping( + documentAbsoluteIndex: 312, + documentLineIndex: 8, + documentCharacterOffsetIndex: 71, + generatedAbsoluteIndex: 2458, + generatedLineIndex: 108, + generatedCharacterOffsetIndex: 0, + contentLength: 2), + BuildLineMapping( + documentAbsoluteIndex: 316, + documentLineIndex: 8, + documentCharacterOffsetIndex: 75, + generatedAbsoluteIndex: 2546, + generatedLineIndex: 114, + generatedCharacterOffsetIndex: 6, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 348, + documentLineIndex: 9, + documentCharacterOffsetIndex: 17, + generatedAbsoluteIndex: 2696, + generatedLineIndex: 120, + generatedCharacterOffsetIndex: 6, + contentLength: 13), + BuildLineMapping( + documentAbsoluteIndex: 363, + documentLineIndex: 9, + documentCharacterOffsetIndex: 32, + generatedAbsoluteIndex: 2789, + generatedLineIndex: 125, + generatedCharacterOffsetIndex: 0, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 376, + documentLineIndex: 9, + documentCharacterOffsetIndex: 45, + generatedAbsoluteIndex: 2888, + generatedLineIndex: 131, + generatedCharacterOffsetIndex: 6, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 388, + documentLineIndex: 9, + documentCharacterOffsetIndex: 57, + generatedAbsoluteIndex: 2980, + generatedLineIndex: 136, + generatedCharacterOffsetIndex: 0, + contentLength: 10), + BuildLineMapping( + documentAbsoluteIndex: 399, + documentLineIndex: 9, + documentCharacterOffsetIndex: 68, + generatedAbsoluteIndex: 3077, + generatedLineIndex: 142, + generatedCharacterOffsetIndex: 6, + contentLength: 5), + BuildLineMapping( + documentAbsoluteIndex: 404, + documentLineIndex: 9, + documentCharacterOffsetIndex: 73, + generatedAbsoluteIndex: 3162, + generatedLineIndex: 147, + generatedCharacterOffsetIndex: 0, + contentLength: 2), + BuildLineMapping( + documentAbsoluteIndex: 408, + documentLineIndex: 9, + documentCharacterOffsetIndex: 77, + generatedAbsoluteIndex: 3251, + generatedLineIndex: 153, + generatedCharacterOffsetIndex: 6, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 445, + documentLineIndex: 11, + documentCharacterOffsetIndex: 17, + generatedAbsoluteIndex: 3416, + generatedLineIndex: 159, + generatedCharacterOffsetIndex: 6, + contentLength: 13), + BuildLineMapping( + documentAbsoluteIndex: 460, + documentLineIndex: 11, + documentCharacterOffsetIndex: 32, + generatedAbsoluteIndex: 3515, + generatedLineIndex: 164, + generatedCharacterOffsetIndex: 6, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 492, + documentLineIndex: 11, + documentCharacterOffsetIndex: 64, + generatedAbsoluteIndex: 3613, + generatedLineIndex: 169, + generatedCharacterOffsetIndex: 6, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 529, + documentLineIndex: 13, + documentCharacterOffsetIndex: 17, + generatedAbsoluteIndex: 3772, + generatedLineIndex: 175, + generatedCharacterOffsetIndex: 0, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 542, + documentLineIndex: 13, + documentCharacterOffsetIndex: 30, + generatedAbsoluteIndex: 3871, + generatedLineIndex: 181, + generatedCharacterOffsetIndex: 6, + contentLength: 12), + BuildLineMapping( + documentAbsoluteIndex: 554, + documentLineIndex: 13, + documentCharacterOffsetIndex: 42, + generatedAbsoluteIndex: 3963, + generatedLineIndex: 186, + generatedCharacterOffsetIndex: 0, + contentLength: 10), + BuildLineMapping( + documentAbsoluteIndex: 565, + documentLineIndex: 13, + documentCharacterOffsetIndex: 53, + generatedAbsoluteIndex: 4060, + generatedLineIndex: 192, + generatedCharacterOffsetIndex: 6, + contentLength: 5), + BuildLineMapping( + documentAbsoluteIndex: 570, + documentLineIndex: 13, + documentCharacterOffsetIndex: 58, + generatedAbsoluteIndex: 4145, + generatedLineIndex: 197, + generatedCharacterOffsetIndex: 0, + contentLength: 2), + } + }, }; } } @@ -965,6 +1243,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator PrefixedAttributeTagHelperDescriptors.Reverse() }, { "DuplicateAttributeTagHelpers", null, DefaultPAndInputTagHelperDescriptors }, + { "DynamicAttributeTagHelpers", null, DynamicAttributeTagHelpers_Descriptors }, }; } } diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs index f75491aa81..95e2262733 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperBlockRewriterTest.cs @@ -32,17 +32,15 @@ namespace Microsoft.AspNet.Razor.TagHelpers { return new MarkupBlock( new MarkupBlock( + new DynamicAttributeBlockChunkGenerator( + new LocationTagged( + string.Empty, + new SourceLocation(10, 0, 10)), + new SourceLocation(10, 0, 10)), new StatementBlock( factory.CodeTransition(), factory.Code("do {" + extraCode).AsStatement()))); }; - var dateTimeNow = new MarkupBlock( - new MarkupBlock( - new ExpressionBlock( - factory.CodeTransition(), - factory.Code("DateTime.Now") - .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) - .Accepts(AcceptedCharacters.NonWhiteSpace)))); return new TheoryData { @@ -301,7 +299,20 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupTagHelperBlock("p", new List> { - new KeyValuePair("class", dateTimeNow) + new KeyValuePair( + "class", + new MarkupBlock( + new MarkupBlock( + new DynamicAttributeBlockChunkGenerator( + new LocationTagged( + string.Empty, + new SourceLocation(9, 0, 9)), + new SourceLocation(9, 0, 9)), + new ExpressionBlock( + factory.CodeTransition(), + factory.Code("DateTime.Now") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))))) })), new [] { @@ -803,12 +814,6 @@ namespace Microsoft.AspNet.Razor.TagHelpers var blockFactory = new BlockFactory(factory); var malformedErrorFormat = "Found a malformed '{0}' tag helper. Tag helpers must have a start and " + "end tag or be self closing."; - var dateTimeNow = new MarkupBlock( - new ExpressionBlock( - factory.CodeTransition(), - factory.Code("DateTime.Now") - .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) - .Accepts(AcceptedCharacters.NonWhiteSpace))); yield return new object[] { @@ -818,7 +823,20 @@ namespace Microsoft.AspNet.Razor.TagHelpers new List> { new KeyValuePair("class", factory.Markup("foo")), - new KeyValuePair("dynamic", new MarkupBlock(dateTimeNow)), + new KeyValuePair( + "dynamic", + new MarkupBlock( + new MarkupBlock( + new DynamicAttributeBlockChunkGenerator( + new LocationTagged( + string.Empty, + new SourceLocation(21, 0, 21)), + new SourceLocation(21, 0, 21)), + new ExpressionBlock( + factory.CodeTransition(), + factory.Code("DateTime.Now") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))))), new KeyValuePair("style", factory.Markup("color:red;")) }, new MarkupTagHelperBlock("strong")), @@ -991,25 +1009,45 @@ namespace Microsoft.AspNet.Razor.TagHelpers var factory = CreateDefaultSpanFactory(); var blockFactory = new BlockFactory(factory); var dateTimeNowString = "@DateTime.Now"; - var dateTimeNow = new MarkupBlock( - new ExpressionBlock( - factory.CodeTransition(), - factory.Code("DateTime.Now") - .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) - .Accepts(AcceptedCharacters.NonWhiteSpace))); + var dateTimeNow = new Func(index => + new MarkupBlock( + new MarkupBlock( + new DynamicAttributeBlockChunkGenerator( + new LocationTagged( + string.Empty, + new SourceLocation(index, 0, index)), + new SourceLocation(index, 0, index)), + new ExpressionBlock( + factory.CodeTransition(), + factory.Code("DateTime.Now") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))))); var doWhileString = "@do { var foo = bar; Foo foo++; } while (foo);"; - var doWhile = new MarkupBlock( - new StatementBlock( - factory.CodeTransition(), - factory.Code("do { var foo = bar;").AsStatement(), - new MarkupBlock( - new MarkupTagBlock( - factory.MarkupTransition("")), - factory.Markup("Foo").Accepts(AcceptedCharacters.None), - new MarkupTagBlock( - factory.MarkupTransition("")), - factory.CodeMarkup(" ").With(new StatementChunkGenerator()).Accepts(AcceptedCharacters.None)), - factory.Code("foo++; } while (foo);").AsStatement().Accepts(AcceptedCharacters.None))); + var doWhile = new Func(index => + new MarkupBlock( + new MarkupBlock( + new DynamicAttributeBlockChunkGenerator( + new LocationTagged( + string.Empty, + new SourceLocation(index, 0, index)), + new SourceLocation(index, 0, index)), + new StatementBlock( + factory.CodeTransition(), + factory.Code("do { var foo = bar;").AsStatement(), + new MarkupBlock( + new MarkupTagBlock( + factory.MarkupTransition("")), + factory.Markup("Foo").Accepts(AcceptedCharacters.None), + new MarkupTagBlock( + factory.MarkupTransition("")), + factory + .CodeMarkup(" ") + .With(new StatementChunkGenerator()) + .Accepts(AcceptedCharacters.None)), + factory + .Code("foo++; } while (foo);") + .AsStatement() + .Accepts(AcceptedCharacters.None))))); var currentFormattedString = "

"; yield return new object[] @@ -1019,8 +1057,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupTagHelperBlock("p", new List> { - new KeyValuePair("class", new MarkupBlock(dateTimeNow)), - new KeyValuePair("style", new MarkupBlock(dateTimeNow)) + new KeyValuePair("class", dateTimeNow(10)), + new KeyValuePair("style", dateTimeNow(32)) })) }; yield return new object[] @@ -1030,8 +1068,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupTagHelperBlock("p", new List> { - new KeyValuePair("class", new MarkupBlock(doWhile)), - new KeyValuePair("style", new MarkupBlock(doWhile)) + new KeyValuePair("class", doWhile(10)), + new KeyValuePair("style", doWhile(83)) })) }; @@ -1043,8 +1081,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupTagHelperBlock("p", new List> { - new KeyValuePair("class", new MarkupBlock(dateTimeNow)), - new KeyValuePair("style", new MarkupBlock(dateTimeNow)) + new KeyValuePair("class", dateTimeNow(10)), + new KeyValuePair("style", dateTimeNow(32)) }, factory.Markup("Hello World"))) }; @@ -1055,8 +1093,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupTagHelperBlock("p", new List> { - new KeyValuePair("class", new MarkupBlock(doWhile)), - new KeyValuePair("style", new MarkupBlock(doWhile)) + new KeyValuePair("class", doWhile(10)), + new KeyValuePair("style", doWhile(83)) }, factory.Markup("Hello World"))) }; @@ -1069,14 +1107,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupTagHelperBlock("p", new List> { - new KeyValuePair("class", new MarkupBlock(dateTimeNow)) + new KeyValuePair("class", dateTimeNow(10)) }, factory.Markup("Hello")), factory.Markup(" "), new MarkupTagHelperBlock("p", new List> { - new KeyValuePair("style", new MarkupBlock(dateTimeNow)) + new KeyValuePair("style", dateTimeNow(45)) }, factory.Markup("World"))) }; @@ -1087,14 +1125,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupTagHelperBlock("p", new List> { - new KeyValuePair("class", new MarkupBlock(doWhile)) + new KeyValuePair("class", doWhile(10)) }, factory.Markup("Hello")), factory.Markup(" "), new MarkupTagHelperBlock("p", new List> { - new KeyValuePair("style", new MarkupBlock(doWhile)) + new KeyValuePair("style", doWhile(96)) }, factory.Markup("World"))) }; @@ -1108,8 +1146,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers new MarkupTagHelperBlock("p", new List> { - new KeyValuePair("class", new MarkupBlock(dateTimeNow)), - new KeyValuePair("style", new MarkupBlock(dateTimeNow)) + new KeyValuePair("class", dateTimeNow(10)), + new KeyValuePair("style", dateTimeNow(32)) }, factory.Markup("Hello World "), new MarkupTagBlock( @@ -1977,12 +2015,19 @@ namespace Microsoft.AspNet.Razor.TagHelpers { var factory = CreateDefaultSpanFactory(); var blockFactory = new BlockFactory(factory); - var dateTimeNow = new MarkupBlock( - new ExpressionBlock( - factory.CodeTransition(), - factory.Code("DateTime.Now") - .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) - .Accepts(AcceptedCharacters.NonWhiteSpace))); + var dateTimeNow = new Func(index => + new MarkupBlock( + new MarkupBlock( + new DynamicAttributeBlockChunkGenerator( + new LocationTagged( + string.Empty, + new SourceLocation(index, 0, index)), + new SourceLocation(index, 0, index)), + new ExpressionBlock( + factory.CodeTransition(), + factory.Code("DateTime.Now") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))))); yield return new object[] { @@ -1992,7 +2037,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers new List> { new KeyValuePair("class", factory.Markup("foo")), - new KeyValuePair("dynamic", new MarkupBlock(dateTimeNow)), + new KeyValuePair("dynamic", dateTimeNow(21)), new KeyValuePair("style", factory.Markup("color:red;")) })) }; @@ -2004,7 +2049,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers new List> { new KeyValuePair("class", factory.Markup("foo")), - new KeyValuePair("dynamic", new MarkupBlock(dateTimeNow)), + new KeyValuePair("dynamic", dateTimeNow(21)), new KeyValuePair("style", factory.Markup("color:red;")) }, factory.Markup("Hello World"))) @@ -2017,7 +2062,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers new List> { new KeyValuePair("class", factory.Markup("foo")), - new KeyValuePair("dynamic", new MarkupBlock(dateTimeNow)), + new KeyValuePair("dynamic", dateTimeNow(21)), new KeyValuePair( "style", new MarkupBlock( @@ -2037,7 +2082,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers new List> { new KeyValuePair("class", factory.Markup("foo")), - new KeyValuePair("dynamic", new MarkupBlock(dateTimeNow)) + new KeyValuePair("dynamic", dateTimeNow(21)) }, factory.Markup("Hello")), factory.Markup(" "), @@ -2045,7 +2090,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers new List> { new KeyValuePair("style", factory.Markup("color:red;")), - new KeyValuePair("dynamic", new MarkupBlock(dateTimeNow)) + new KeyValuePair("dynamic", dateTimeNow(73)) }, factory.Markup("World"))) }; @@ -2057,7 +2102,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers new List> { new KeyValuePair("class", factory.Markup("foo")), - new KeyValuePair("dynamic", new MarkupBlock(dateTimeNow)), + new KeyValuePair("dynamic", dateTimeNow(21)), new KeyValuePair("style", factory.Markup("color:red;")) }, factory.Markup("Hello World "), @@ -2394,15 +2439,27 @@ namespace Microsoft.AspNet.Razor.TagHelpers var stringType = typeof(string).FullName; var intType = typeof(int).FullName; var expressionString = "@DateTime.Now + 1"; - var expression = new MarkupBlock( + var expression = new Func(index => new MarkupBlock( - new ExpressionBlock( - factory.CodeTransition(), - factory.Code("DateTime.Now") - .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) - .Accepts(AcceptedCharacters.NonWhiteSpace))), - factory.Markup(" +"), - factory.Markup(" 1")); + new MarkupBlock( + new DynamicAttributeBlockChunkGenerator( + new LocationTagged( + string.Empty, + new SourceLocation(index, 0, index)), + new SourceLocation(index, 0, index)), + new ExpressionBlock( + factory.CodeTransition(), + factory.Code("DateTime.Now") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))), + factory.Markup(" +") + .With(new LiteralAttributeChunkGenerator( + prefix: new LocationTagged(" ", index + 13, 0, index + 13), + value: new LocationTagged("+", index + 14, 0, index + 14))), + factory.Markup(" 1") + .With(new LiteralAttributeChunkGenerator( + prefix: new LocationTagged(" ", index + 15, 0, index + 15), + value: new LocationTagged("1", index + 16, 0, index + 16))))); // documentContent, expectedOutput, expectedErrors return new TheoryData @@ -2933,7 +2990,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers selfClosing: true, attributes: new List>() { - new KeyValuePair("class", expression), + new KeyValuePair("class", expression(14)), new KeyValuePair("bound-required-int", null), })), new[] @@ -2950,7 +3007,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers selfClosing: false, attributes: new List>() { - new KeyValuePair("class", expression), + new KeyValuePair("class", expression(10)), new KeyValuePair("bound-int", null), })), new[] @@ -2968,9 +3025,9 @@ namespace Microsoft.AspNet.Razor.TagHelpers attributes: new List>() { new KeyValuePair("bound-required-int", null), - new KeyValuePair("class", expression), + new KeyValuePair("class", expression(36)), new KeyValuePair("bound-required-string", null), - new KeyValuePair("class", expression), + new KeyValuePair("class", expression(86)), new KeyValuePair("unbound-required", null), })), new[] @@ -2995,9 +3052,9 @@ namespace Microsoft.AspNet.Razor.TagHelpers attributes: new List>() { new KeyValuePair("bound-int", null), - new KeyValuePair("class", expression), + new KeyValuePair("class", expression(23)), new KeyValuePair("bound-string", null), - new KeyValuePair("class", expression), + new KeyValuePair("class", expression(64)), new KeyValuePair("bound-string", null), })), new[] @@ -3029,10 +3086,85 @@ namespace Microsoft.AspNet.Razor.TagHelpers factory.MetaCode("}").Accepts(AcceptedCharacters.None)), factory.EmptyHtml()); }; + Action updateDynamicChunkGenerators = (block) => + { + var tagHelperBlock = block.Children.First() as MarkupTagHelperBlock; + + for (var i = 0; i < tagHelperBlock.Attributes.Count; i++) + { + var attribute = tagHelperBlock.Attributes[i]; + var holderBlock = attribute.Value as Block; + + if (holderBlock == null) + { + continue; + } + + var valueBlock = holderBlock.Children.FirstOrDefault() as Block; + if (valueBlock != null) + { + var chunkGenerator = valueBlock.ChunkGenerator as DynamicAttributeBlockChunkGenerator; + + if (chunkGenerator != null) + { + var blockBuilder = new BlockBuilder(holderBlock); + var expressionBlockBuilder = new BlockBuilder(valueBlock); + var newChunkGenerator = new DynamicAttributeBlockChunkGenerator( + new LocationTagged( + chunkGenerator.Prefix.Value, + new SourceLocation( + chunkGenerator.Prefix.Location.AbsoluteIndex + 2, + chunkGenerator.Prefix.Location.LineIndex, + chunkGenerator.Prefix.Location.CharacterIndex + 2)), + new SourceLocation( + chunkGenerator.ValueStart.AbsoluteIndex + 2, + chunkGenerator.ValueStart.LineIndex, + chunkGenerator.ValueStart.CharacterIndex + 2)); + + expressionBlockBuilder.ChunkGenerator = newChunkGenerator; + blockBuilder.Children[0] = expressionBlockBuilder.Build(); + + for (var j = 1; j < blockBuilder.Children.Count; j++) + { + var span = blockBuilder.Children[j] as Span; + if (span != null) + { + var literalChunkGenerator = + span.ChunkGenerator as LiteralAttributeChunkGenerator; + + var spanBuilder = new SpanBuilder(span); + spanBuilder.ChunkGenerator = new LiteralAttributeChunkGenerator( + prefix: new LocationTagged( + literalChunkGenerator.Prefix.Value, + new SourceLocation( + literalChunkGenerator.Prefix.Location.AbsoluteIndex + 2, + literalChunkGenerator.Prefix.Location.LineIndex, + literalChunkGenerator.Prefix.Location.CharacterIndex + 2)), + value: new LocationTagged( + literalChunkGenerator.Value.Value, + new SourceLocation( + literalChunkGenerator.Value.Location.AbsoluteIndex + 2, + literalChunkGenerator.Value.Location.LineIndex, + literalChunkGenerator.Value.Location.CharacterIndex + 2))); + + blockBuilder.Children[j] = spanBuilder.Build(); + } + } + + tagHelperBlock.Attributes[i] = new KeyValuePair( + attribute.Key, + blockBuilder.Build()); + } + } + } + }; foreach (var data in documentData) { data[0] = $"@{{{data[0]}}}"; + + updateDynamicChunkGenerators(data[1] as MarkupBlock); + data[1] = buildStatementBlock(() => data[1] as MarkupBlock); var errors = data[2] as RazorError[]; diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs index 2b23559c32..0be0ea587c 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs @@ -23,13 +23,19 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers { var factory = CreateDefaultSpanFactory(); var blockFactory = new BlockFactory(factory); - var dateTimeNow = new MarkupBlock( - new MarkupBlock( - new ExpressionBlock( - factory.CodeTransition(), - factory.Code("DateTime.Now") - .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) - .Accepts(AcceptedCharacters.NonWhiteSpace)))); + var dateTimeNow = new Func(index => + new MarkupBlock( + new MarkupBlock( + new DynamicAttributeBlockChunkGenerator( + new LocationTagged( + string.Empty, + new SourceLocation(index, 0, index)), + new SourceLocation(index, 0, index)), + new ExpressionBlock( + factory.CodeTransition(), + factory.Code("DateTime.Now") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))))); // documentContent, expectedOutput return new TheoryData @@ -73,7 +79,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers selfClosing: true, attributes: new List> { - new KeyValuePair("class", dateTimeNow) + new KeyValuePair("class", dateTimeNow(10)) })) }, { @@ -94,7 +100,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "p", attributes: new List> { - new KeyValuePair("class", dateTimeNow) + new KeyValuePair("class", dateTimeNow(10)) }, children: factory.Markup("words and spaces"))) }, @@ -135,7 +141,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers selfClosing: true, attributes: new List> { - new KeyValuePair("catchAll", dateTimeNow) + new KeyValuePair("catchAll", dateTimeNow(18)) })) }, { @@ -156,7 +162,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "strong", attributes: new List> { - new KeyValuePair("catchAll", dateTimeNow) + new KeyValuePair("catchAll", dateTimeNow(18)) }, children: factory.Markup("words and spaces"))) }, @@ -217,7 +223,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers selfClosing: true, attributes: new List> { - new KeyValuePair("notRequired", dateTimeNow), + new KeyValuePair("notRequired", dateTimeNow(16)), new KeyValuePair("class", factory.Markup("btn")) })) }, @@ -253,7 +259,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers selfClosing: true, attributes: new List> { - new KeyValuePair("style", dateTimeNow), + new KeyValuePair("style", dateTimeNow(12)), new KeyValuePair("class", factory.Markup("btn")) })) }, @@ -276,8 +282,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "div", attributes: new List> { - new KeyValuePair("style", dateTimeNow), - new KeyValuePair("class", dateTimeNow) + new KeyValuePair("style", dateTimeNow(12)), + new KeyValuePair("class", dateTimeNow(34)) }, children: factory.Markup("words and spaces"))) }, @@ -376,9 +382,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "div", attributes: new List> { - new KeyValuePair("style", dateTimeNow), - new KeyValuePair("class", dateTimeNow), - new KeyValuePair("catchAll", dateTimeNow) + new KeyValuePair("style", dateTimeNow(12)), + new KeyValuePair("class", dateTimeNow(34)), + new KeyValuePair("catchAll", dateTimeNow(59)) }, children: factory.Markup("words and spaces"))) }, diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.cs index bc2d154ba0..4194474902 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.cs @@ -239,15 +239,8 @@ if(true) { , StartTagHelperWritingScope, EndTagHelperWritingScope); __PTagHelper = CreateTagHelper(); __tagHelperExecutionContext.Add(__PTagHelper); - StartTagHelperWritingScope(); - WriteLiteral("Current Time: "); -#line 8 "ComplexTagHelpers.cshtml" -Write(DateTime.Now); - -#line default -#line hidden - __tagHelperStringValueBuffer = EndTagHelperWritingScope(); - __tagHelperExecutionContext.AddHtmlAttribute("time", Html.Raw(__tagHelperStringValueBuffer.ToString())); + AddHtmlAttributeValues("time", __tagHelperExecutionContext, Tuple.Create(Tuple.Create("", 148), Tuple.Create("Current", 148), true), Tuple.Create(Tuple.Create(" ", 155), Tuple.Create("Time:", 156), true), + Tuple.Create(Tuple.Create(" ", 161), Tuple.Create(DateTime.Now, 162), false)); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); Instrumentation.BeginContext(139, 531, false); await WriteTagHelperAsync(__tagHelperExecutionContext); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/DynamicAttributeTagHelpers.DesignTime.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/DynamicAttributeTagHelpers.DesignTime.cs new file mode 100644 index 0000000000..3f154a58d5 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/DynamicAttributeTagHelpers.DesignTime.cs @@ -0,0 +1,206 @@ +namespace TestOutput +{ + using Microsoft.AspNet.Razor.Runtime.TagHelpers; + using System; + using System.Threading.Tasks; + + public class DynamicAttributeTagHelpers + { + private static object @__o; + private void @__RazorDesignTimeHelpers__() + { + #pragma warning disable 219 + string __tagHelperDirectiveSyntaxHelper = null; + __tagHelperDirectiveSyntaxHelper = +#line 1 "DynamicAttributeTagHelpers.cshtml" + "something, nice" + +#line default +#line hidden + ; + #pragma warning restore 219 + } + #line hidden + private InputTagHelper __InputTagHelper = null; + #line hidden + public DynamicAttributeTagHelpers() + { + } + + #pragma warning disable 1998 + public override async Task ExecuteAsync() + { + __InputTagHelper = CreateTagHelper(); +#line 3 "DynamicAttributeTagHelpers.cshtml" +__o = DateTime.Now; + +#line default +#line hidden + __InputTagHelper = CreateTagHelper(); +#line 5 "DynamicAttributeTagHelpers.cshtml" +if (true) { + +#line default +#line hidden + +#line 5 "DynamicAttributeTagHelpers.cshtml" +__o = string.Empty; + +#line default +#line hidden +#line 5 "DynamicAttributeTagHelpers.cshtml" + } else { + +#line default +#line hidden + +#line 5 "DynamicAttributeTagHelpers.cshtml" +__o = false; + +#line default +#line hidden +#line 5 "DynamicAttributeTagHelpers.cshtml" + } + +#line default +#line hidden + + __InputTagHelper = CreateTagHelper(); +#line 7 "DynamicAttributeTagHelpers.cshtml" +__o = DateTime.Now; + +#line default +#line hidden + __InputTagHelper.Bound = string.Empty; +#line 7 "DynamicAttributeTagHelpers.cshtml" +__o = DateTime.Now; + +#line default +#line hidden + __InputTagHelper = CreateTagHelper(); +#line 9 "DynamicAttributeTagHelpers.cshtml" +__o = long.MinValue; + +#line default +#line hidden +#line 9 "DynamicAttributeTagHelpers.cshtml" +if (true) { + +#line default +#line hidden + +#line 9 "DynamicAttributeTagHelpers.cshtml" +__o = string.Empty; + +#line default +#line hidden +#line 9 "DynamicAttributeTagHelpers.cshtml" + } else { + +#line default +#line hidden + +#line 9 "DynamicAttributeTagHelpers.cshtml" +__o = false; + +#line default +#line hidden +#line 9 "DynamicAttributeTagHelpers.cshtml" + } + +#line default +#line hidden + +#line 9 "DynamicAttributeTagHelpers.cshtml" +__o = int.MaxValue; + +#line default +#line hidden + __InputTagHelper.Bound = string.Empty; +#line 10 "DynamicAttributeTagHelpers.cshtml" +__o = long.MinValue; + +#line default +#line hidden +#line 10 "DynamicAttributeTagHelpers.cshtml" +if (true) { + +#line default +#line hidden + +#line 10 "DynamicAttributeTagHelpers.cshtml" +__o = string.Empty; + +#line default +#line hidden +#line 10 "DynamicAttributeTagHelpers.cshtml" + } else { + +#line default +#line hidden + +#line 10 "DynamicAttributeTagHelpers.cshtml" +__o = false; + +#line default +#line hidden +#line 10 "DynamicAttributeTagHelpers.cshtml" + } + +#line default +#line hidden + +#line 10 "DynamicAttributeTagHelpers.cshtml" +__o = int.MaxValue; + +#line default +#line hidden + __InputTagHelper = CreateTagHelper(); +#line 12 "DynamicAttributeTagHelpers.cshtml" +__o = long.MinValue; + +#line default +#line hidden +#line 12 "DynamicAttributeTagHelpers.cshtml" +__o = DateTime.Now; + +#line default +#line hidden +#line 12 "DynamicAttributeTagHelpers.cshtml" +__o = int.MaxValue; + +#line default +#line hidden + __InputTagHelper = CreateTagHelper(); +#line 14 "DynamicAttributeTagHelpers.cshtml" +if (true) { + +#line default +#line hidden + +#line 14 "DynamicAttributeTagHelpers.cshtml" +__o = string.Empty; + +#line default +#line hidden +#line 14 "DynamicAttributeTagHelpers.cshtml" + } else { + +#line default +#line hidden + +#line 14 "DynamicAttributeTagHelpers.cshtml" +__o = false; + +#line default +#line hidden +#line 14 "DynamicAttributeTagHelpers.cshtml" + } + +#line default +#line hidden + + } + #pragma warning restore 1998 + } +} diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/DynamicAttributeTagHelpers.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/DynamicAttributeTagHelpers.cs new file mode 100644 index 0000000000..c2712ca754 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/DynamicAttributeTagHelpers.cs @@ -0,0 +1,281 @@ +#pragma checksum "DynamicAttributeTagHelpers.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "782463195265ee647cc2fc63fd5095a80090845b" +namespace TestOutput +{ + using Microsoft.AspNet.Razor.Runtime.TagHelpers; + using System; + using System.Threading.Tasks; + + public class DynamicAttributeTagHelpers + { + #line hidden + #pragma warning disable 0414 + private TagHelperContent __tagHelperStringValueBuffer = null; + #pragma warning restore 0414 + private TagHelperExecutionContext __tagHelperExecutionContext = null; + private TagHelperRunner __tagHelperRunner = null; + private TagHelperScopeManager __tagHelperScopeManager = new TagHelperScopeManager(); + private InputTagHelper __InputTagHelper = null; + #line hidden + public DynamicAttributeTagHelpers() + { + } + + #pragma warning disable 1998 + public override async Task ExecuteAsync() + { + __tagHelperRunner = __tagHelperRunner ?? new TagHelperRunner(); + Instrumentation.BeginContext(33, 2, true); + WriteLiteral("\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __InputTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__InputTagHelper); + AddHtmlAttributeValues("unbound", __tagHelperExecutionContext, Tuple.Create(Tuple.Create("", 51), Tuple.Create("prefix", 51), true), + Tuple.Create(Tuple.Create(" ", 57), Tuple.Create(DateTime.Now, 58), false)); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(35, 40, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(75, 4, true); + WriteLiteral("\r\n\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __InputTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__InputTagHelper); + AddHtmlAttributeValues("unbound", __tagHelperExecutionContext, + Tuple.Create(Tuple.Create("", 95), Tuple.Create(new Template((__razor_attribute_value_writer) => { +#line 5 "DynamicAttributeTagHelpers.cshtml" +if (true) { + +#line default +#line hidden + + Instrumentation.BeginContext(109, 12, false); +#line 5 "DynamicAttributeTagHelpers.cshtml" +WriteTo(__razor_attribute_value_writer, string.Empty); + +#line default +#line hidden + Instrumentation.EndContext(); +#line 5 "DynamicAttributeTagHelpers.cshtml" + } else { + +#line default +#line hidden + + Instrumentation.BeginContext(132, 5, false); +#line 5 "DynamicAttributeTagHelpers.cshtml" +WriteTo(__razor_attribute_value_writer, false); + +#line default +#line hidden + Instrumentation.EndContext(); +#line 5 "DynamicAttributeTagHelpers.cshtml" + } + +#line default +#line hidden + + } + ), 95), false), Tuple.Create(Tuple.Create(" ", 139), Tuple.Create("suffix", 140), true)); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(79, 71, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(150, 4, true); + WriteLiteral("\r\n\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __InputTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__InputTagHelper); + StartTagHelperWritingScope(); + WriteLiteral("prefix "); +#line 7 "DynamicAttributeTagHelpers.cshtml" +WriteLiteral(DateTime.Now); + +#line default +#line hidden + WriteLiteral(" suffix"); + __tagHelperStringValueBuffer = EndTagHelperWritingScope(); + __InputTagHelper.Bound = __tagHelperStringValueBuffer.ToString(); + __tagHelperExecutionContext.AddTagHelperAttribute("bound", __InputTagHelper.Bound); + AddHtmlAttributeValues("unbound", __tagHelperExecutionContext, Tuple.Create(Tuple.Create("", 206), Tuple.Create("prefix", 206), true), + Tuple.Create(Tuple.Create(" ", 212), Tuple.Create(DateTime.Now, 213), false), Tuple.Create(Tuple.Create(" ", 226), Tuple.Create("suffix", 227), true)); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(154, 83, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(237, 4, true); + WriteLiteral("\r\n\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __InputTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__InputTagHelper); + StartTagHelperWritingScope(); +#line 9 "DynamicAttributeTagHelpers.cshtml" +WriteLiteral(long.MinValue); + +#line default +#line hidden + WriteLiteral(" "); +#line 9 "DynamicAttributeTagHelpers.cshtml" +if (true) { + +#line default +#line hidden + +#line 9 "DynamicAttributeTagHelpers.cshtml" +WriteLiteral(string.Empty); + +#line default +#line hidden +#line 9 "DynamicAttributeTagHelpers.cshtml" + } else { + +#line default +#line hidden + +#line 9 "DynamicAttributeTagHelpers.cshtml" +WriteLiteral(false); + +#line default +#line hidden +#line 9 "DynamicAttributeTagHelpers.cshtml" + } + +#line default +#line hidden + + WriteLiteral(" "); +#line 9 "DynamicAttributeTagHelpers.cshtml" +WriteLiteral(int.MaxValue); + +#line default +#line hidden + __tagHelperStringValueBuffer = EndTagHelperWritingScope(); + __InputTagHelper.Bound = __tagHelperStringValueBuffer.ToString(); + __tagHelperExecutionContext.AddTagHelperAttribute("bound", __InputTagHelper.Bound); + AddHtmlAttributeValues("unbound", __tagHelperExecutionContext, + Tuple.Create(Tuple.Create("", 347), Tuple.Create(long.MinValue, 347), false), + Tuple.Create(Tuple.Create(" ", 361), Tuple.Create(new Template((__razor_attribute_value_writer) => { +#line 10 "DynamicAttributeTagHelpers.cshtml" +if (true) { + +#line default +#line hidden + + Instrumentation.BeginContext(376, 12, false); +#line 10 "DynamicAttributeTagHelpers.cshtml" +WriteTo(__razor_attribute_value_writer, string.Empty); + +#line default +#line hidden + Instrumentation.EndContext(); +#line 10 "DynamicAttributeTagHelpers.cshtml" + } else { + +#line default +#line hidden + + Instrumentation.BeginContext(399, 5, false); +#line 10 "DynamicAttributeTagHelpers.cshtml" +WriteTo(__razor_attribute_value_writer, false); + +#line default +#line hidden + Instrumentation.EndContext(); +#line 10 "DynamicAttributeTagHelpers.cshtml" + } + +#line default +#line hidden + + } + ), 362), false), + Tuple.Create(Tuple.Create(" ", 406), Tuple.Create(int.MaxValue, 407), false)); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(241, 183, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(424, 4, true); + WriteLiteral("\r\n\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __InputTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__InputTagHelper); + AddHtmlAttributeValues("unbound", __tagHelperExecutionContext, + Tuple.Create(Tuple.Create("", 444), Tuple.Create(long.MinValue, 444), false), + Tuple.Create(Tuple.Create(" ", 458), Tuple.Create(DateTime.Now, 459), false), Tuple.Create(Tuple.Create(" ", 472), Tuple.Create("static", 473), true), Tuple.Create(Tuple.Create(" ", 479), Tuple.Create("content", 483), true), + Tuple.Create(Tuple.Create(" ", 490), Tuple.Create(int.MaxValue, 491), false)); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(428, 80, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + Instrumentation.BeginContext(508, 4, true); + WriteLiteral("\r\n\r\n"); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { + } + , StartTagHelperWritingScope, EndTagHelperWritingScope); + __InputTagHelper = CreateTagHelper(); + __tagHelperExecutionContext.Add(__InputTagHelper); + AddHtmlAttributeValues("unbound", __tagHelperExecutionContext, + Tuple.Create(Tuple.Create("", 528), Tuple.Create(new Template((__razor_attribute_value_writer) => { +#line 14 "DynamicAttributeTagHelpers.cshtml" +if (true) { + +#line default +#line hidden + + Instrumentation.BeginContext(542, 12, false); +#line 14 "DynamicAttributeTagHelpers.cshtml" +WriteTo(__razor_attribute_value_writer, string.Empty); + +#line default +#line hidden + Instrumentation.EndContext(); +#line 14 "DynamicAttributeTagHelpers.cshtml" + } else { + +#line default +#line hidden + + Instrumentation.BeginContext(565, 5, false); +#line 14 "DynamicAttributeTagHelpers.cshtml" +WriteTo(__razor_attribute_value_writer, false); + +#line default +#line hidden + Instrumentation.EndContext(); +#line 14 "DynamicAttributeTagHelpers.cshtml" + } + +#line default +#line hidden + + } + ), 528), false)); + __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); + Instrumentation.BeginContext(512, 64, false); + await WriteTagHelperAsync(__tagHelperExecutionContext); + Instrumentation.EndContext(); + __tagHelperExecutionContext = __tagHelperScopeManager.End(); + } + #pragma warning restore 1998 + } +} diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TagHelpersInSection.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TagHelpersInSection.cs index e23dab4f1f..db2d98010a 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TagHelpersInSection.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TagHelpersInSection.cs @@ -83,15 +83,8 @@ WriteLiteral(DateTime.Now); __tagHelperStringValueBuffer = EndTagHelperWritingScope(); __MyTagHelper.BoundProperty = __tagHelperStringValueBuffer.ToString(); __tagHelperExecutionContext.AddTagHelperAttribute("boundproperty", __MyTagHelper.BoundProperty); - StartTagHelperWritingScope(); - WriteLiteral("Current Time: "); -#line 9 "TagHelpersInSection.cshtml" -Write(DateTime.Now); - -#line default -#line hidden - __tagHelperStringValueBuffer = EndTagHelperWritingScope(); - __tagHelperExecutionContext.AddHtmlAttribute("unboundproperty", Html.Raw(__tagHelperStringValueBuffer.ToString())); + AddHtmlAttributeValues("unboundproperty", __tagHelperExecutionContext, Tuple.Create(Tuple.Create("", 188), Tuple.Create("Current", 188), true), Tuple.Create(Tuple.Create(" ", 195), Tuple.Create("Time:", 196), true), + Tuple.Create(Tuple.Create(" ", 201), Tuple.Create(DateTime.Now, 202), false)); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); Instrumentation.BeginContext(114, 245, false); await WriteTagHelperToAsync(__razor_template_writer, __tagHelperExecutionContext); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/DynamicAttributeTagHelpers.cshtml b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/DynamicAttributeTagHelpers.cshtml new file mode 100644 index 0000000000..8cf97d3f5d --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Source/DynamicAttributeTagHelpers.cshtml @@ -0,0 +1,14 @@ +@addTagHelper "something, nice" + + + + + + + + + + + + \ No newline at end of file