From 9d30f43b67ca25a12efb83dfb856ec3bf3b77e0d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 29 Sep 2015 18:03:22 -0700 Subject: [PATCH] Refactor WriteAttribute \ AddHtmlAttribute Fixes #177 --- .../CodeGenerators/CSharpCodeWriter.cs | 4 +- .../CSharpTagHelperCodeRenderer.cs | 41 +++++- .../CodeGenerators/GeneratedClassContext.cs | 98 ++++++++------ .../GeneratedTagHelperContext.cs | 44 +++++- .../Visitors/CSharpCodeVisitor.cs | 125 +++++++++++------- .../CodeGenerator/Output/ComplexTagHelpers.cs | 7 +- .../Output/ConditionalAttributes.cs | 45 ++++--- .../Output/DynamicAttributeTagHelpers.cs | 50 ++++--- .../CodeGenerator/Output/InlineBlocks.cs | 7 +- .../Output/TagHelpersInSection.cs | 7 +- .../TransitionsInTagHelperAttributes.cs | 18 ++- 11 files changed, 298 insertions(+), 148 deletions(-) diff --git a/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpCodeWriter.cs b/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpCodeWriter.cs index 51c3882bb..89c0cf7ce 100644 --- a/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpCodeWriter.cs +++ b/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpCodeWriter.cs @@ -106,11 +106,9 @@ public CSharpCodeWriter WriteStartNewObject(string typeName) public CSharpCodeWriter WriteLocationTaggedString(LocationTagged value) { - WriteStartMethodInvocation("Tuple.Create"); WriteStringLiteral(value.Value); WriteParameterSeparator(); - Write(value.Location.AbsoluteIndex.ToString(CultureInfo.CurrentCulture)); - WriteEndMethodInvocation(false); + Write(value.Location.AbsoluteIndex.ToString(CultureInfo.InvariantCulture)); return this; } diff --git a/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpTagHelperCodeRenderer.cs b/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpTagHelperCodeRenderer.cs index f521b40ab..ed22119df 100644 --- a/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpTagHelperCodeRenderer.cs +++ b/src/Microsoft.AspNet.Razor/CodeGenerators/CSharpTagHelperCodeRenderer.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.Linq; using Microsoft.AspNet.Razor.Chunks; @@ -26,6 +27,7 @@ public class CSharpTagHelperCodeRenderer private readonly CodeGeneratorContext _context; private readonly IChunkVisitor _bodyVisitor; private readonly IChunkVisitor _literalBodyVisitor; + private readonly TagHelperAttributeCodeVisitor _attributeCodeVisitor; private readonly GeneratedTagHelperContext _tagHelperContext; private readonly bool _designTimeMode; @@ -63,6 +65,7 @@ public CSharpTagHelperCodeRenderer( _designTimeMode = context.Host.DesignTimeMode; _literalBodyVisitor = new CSharpLiteralCodeVisitor(this, writer, context); + _attributeCodeVisitor = new TagHelperAttributeCodeVisitor(writer, context); AttributeValueCodeRenderer = new TagHelperAttributeValueCodeRenderer(); } @@ -467,15 +470,32 @@ private void RenderUnboundAttribute(string attributeName, Chunk attributeValueCh // 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 currentTargetWriter = _context.TargetWriterName; + var currentWriteAttributeMethodName = _context.Host.GeneratedClassContext.WriteAttributeValueMethodName; + _context.TargetWriterName = null; + + Debug.Assert(attributeValueChunk is ParentChunk); + var children = ((ParentChunk)attributeValueChunk).Children; + var attributeCount = children.Count(c => c is DynamicCodeAttributeChunk || c is LiteralCodeAttributeChunk); + _writer - .WriteStartMethodInvocation(_tagHelperContext.AddHtmlAttributeValuesMethodName) + .WriteStartMethodInvocation(_tagHelperContext.BeginAddHtmlAttributeValuesMethodName) + .Write(ExecutionContextVariableName) + .WriteParameterSeparator() .WriteStringLiteral(attributeName) .WriteParameterSeparator() - .Write(ExecutionContextVariableName); + .Write(attributeCount.ToString(CultureInfo.InvariantCulture)) + .WriteEndMethodInvocation(); - _bodyVisitor.Accept(attributeValueChunk); + _attributeCodeVisitor.Accept(attributeValueChunk); + + _writer.WriteMethodInvocation( + _tagHelperContext.EndAddHtmlAttributeValuesMethodName, + ExecutionContextVariableName); - _writer.WriteEndMethodInvocation(); + _context.TargetWriterName = currentTargetWriter; } else { @@ -722,5 +742,18 @@ protected override string WriteToMethodName } } } + + private class TagHelperAttributeCodeVisitor : CSharpCodeVisitor + { + public TagHelperAttributeCodeVisitor( + CSharpCodeWriter writer, + CodeGeneratorContext context) + : base(writer, context) + { + } + + protected override string WriteAttributeValueMethodName => + Context.Host.GeneratedClassContext.GeneratedTagHelperContext.AddHtmlAttributeValueMethodName; + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedClassContext.cs b/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedClassContext.cs index 934406161..e98c28870 100644 --- a/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedClassContext.cs +++ b/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedClassContext.cs @@ -11,19 +11,25 @@ public struct GeneratedClassContext public static readonly string DefaultWriteMethodName = "Write"; public static readonly string DefaultWriteLiteralMethodName = "WriteLiteral"; public static readonly string DefaultExecuteMethodName = "ExecuteAsync"; - public static readonly string DefaultWriteAttributeMethodName = "WriteAttribute"; - public static readonly string DefaultWriteAttributeToMethodName = "WriteAttributeTo"; + public static readonly string DefaultBeginWriteAttributeMethodName = "BeginWriteAttribute"; + public static readonly string DefaultBeginWriteAttributeToMethodName = "BeginWriteAttributeTo"; + public static readonly string DefaultEndWriteAttributeMethodName = "EndWriteAttribute"; + public static readonly string DefaultEndWriteAttributeToMethodName = "EndWriteAttributeTo"; + public static readonly string DefaultWriteAttributeValueMethodName = "WriteAttributeValue"; + public static readonly string DefaultWriteAttributeValueToMethodName = "WriteAttributeValueTo"; public static readonly GeneratedClassContext Default = - new GeneratedClassContext(DefaultExecuteMethodName, - DefaultWriteMethodName, - DefaultWriteLiteralMethodName, - new GeneratedTagHelperContext()); - - public GeneratedClassContext(string executeMethodName, - string writeMethodName, - string writeLiteralMethodName, - GeneratedTagHelperContext generatedTagHelperContext) + new GeneratedClassContext( + DefaultExecuteMethodName, + DefaultWriteMethodName, + DefaultWriteLiteralMethodName, + new GeneratedTagHelperContext()); + + public GeneratedClassContext( + string executeMethodName, + string writeMethodName, + string writeLiteralMethodName, + GeneratedTagHelperContext generatedTagHelperContext) : this() { if (generatedTagHelperContext == null) @@ -61,17 +67,22 @@ public GeneratedClassContext(string executeMethodName, TemplateTypeName = null; DefineSectionMethodName = null; - WriteAttributeMethodName = DefaultWriteAttributeMethodName; - WriteAttributeToMethodName = DefaultWriteAttributeToMethodName; + BeginWriteAttributeMethodName = DefaultBeginWriteAttributeMethodName; + BeginWriteAttributeToMethodName = DefaultBeginWriteAttributeToMethodName; + EndWriteAttributeMethodName = DefaultEndWriteAttributeMethodName; + EndWriteAttributeToMethodName = DefaultEndWriteAttributeToMethodName; + WriteAttributeValueMethodName = DefaultWriteAttributeValueMethodName; + WriteAttributeValueToMethodName = DefaultWriteAttributeValueToMethodName; } - public GeneratedClassContext(string executeMethodName, - string writeMethodName, - string writeLiteralMethodName, - string writeToMethodName, - string writeLiteralToMethodName, - string templateTypeName, - GeneratedTagHelperContext generatedTagHelperContext) + public GeneratedClassContext( + string executeMethodName, + string writeMethodName, + string writeLiteralMethodName, + string writeToMethodName, + string writeLiteralToMethodName, + string templateTypeName, + GeneratedTagHelperContext generatedTagHelperContext) : this(executeMethodName, writeMethodName, writeLiteralMethodName, @@ -82,14 +93,15 @@ public GeneratedClassContext(string executeMethodName, TemplateTypeName = templateTypeName; } - public GeneratedClassContext(string executeMethodName, - string writeMethodName, - string writeLiteralMethodName, - string writeToMethodName, - string writeLiteralToMethodName, - string templateTypeName, - string defineSectionMethodName, - GeneratedTagHelperContext generatedTagHelperContext) + public GeneratedClassContext( + string executeMethodName, + string writeMethodName, + string writeLiteralMethodName, + string writeToMethodName, + string writeLiteralToMethodName, + string templateTypeName, + string defineSectionMethodName, + GeneratedTagHelperContext generatedTagHelperContext) : this(executeMethodName, writeMethodName, writeLiteralMethodName, @@ -101,16 +113,17 @@ public GeneratedClassContext(string executeMethodName, DefineSectionMethodName = defineSectionMethodName; } - public GeneratedClassContext(string executeMethodName, - string writeMethodName, - string writeLiteralMethodName, - string writeToMethodName, - string writeLiteralToMethodName, - string templateTypeName, - string defineSectionMethodName, - string beginContextMethodName, - string endContextMethodName, - GeneratedTagHelperContext generatedTagHelperContext) + public GeneratedClassContext( + string executeMethodName, + string writeMethodName, + string writeLiteralMethodName, + string writeToMethodName, + string writeLiteralToMethodName, + string templateTypeName, + string defineSectionMethodName, + string beginContextMethodName, + string endContextMethodName, + GeneratedTagHelperContext generatedTagHelperContext) : this(executeMethodName, writeMethodName, writeLiteralMethodName, @@ -137,8 +150,13 @@ public GeneratedClassContext(string executeMethodName, public string EndContextMethodName { get; set; } public string DefineSectionMethodName { get; set; } public string TemplateTypeName { get; set; } - public string WriteAttributeMethodName { get; set; } - public string WriteAttributeToMethodName { get; set; } + + public string BeginWriteAttributeMethodName { get; set; } + public string BeginWriteAttributeToMethodName { get; set; } + public string EndWriteAttributeMethodName { get; set; } + public string EndWriteAttributeToMethodName { get; set; } + public string WriteAttributeValueMethodName { get; set; } + public string WriteAttributeValueToMethodName { get; set; } public bool AllowSections { diff --git a/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedTagHelperContext.cs b/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedTagHelperContext.cs index 2cf560678..138f9a74f 100644 --- a/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedTagHelperContext.cs +++ b/src/Microsoft.AspNet.Razor/CodeGenerators/GeneratedTagHelperContext.cs @@ -13,7 +13,9 @@ public class GeneratedTagHelperContext /// public GeneratedTagHelperContext() { - AddHtmlAttributeValuesMethodName = "AddHtmlAttributeValues"; + BeginAddHtmlAttributeValuesMethodName = "BeginAddHtmlAttributeValues"; + EndAddHtmlAttributeValuesMethodName = "EndAddHtmlAttributeValues"; + AddHtmlAttributeValueMethodName = "AddHtmlAttributeValue"; CreateTagHelperMethodName = "CreateTagHelper"; RunnerRunAsyncMethodName = "RunAsync"; ScopeManagerBeginMethodName = "Begin"; @@ -38,18 +40,48 @@ public GeneratedTagHelperContext() } /// - /// The name of the method used to add unbound, complex tag helper attributes to TagHelperExecutionContexts. + /// The name of the method used to begin the addition of unbound, complex tag helper attributes to + /// TagHelperExecutionContexts. /// /// /// Method signature should be /// - /// public void AddHtmlAttributeValues( - /// string attributeName, + /// public void BeginAddHtmlAttributeValues( /// TagHelperExecutionContext executionContext, - /// params Microsoft.AspNet.Mvc.Razor.AttributeValue[] values) + /// string attributeName) + /// + /// + public string BeginAddHtmlAttributeValuesMethodName { get; set; } + + /// + /// Method name used to end addition of unbound, complex tag helper attributes to TagHelperExecutionContexts. + /// + /// + /// Method signature should be + /// + /// public void EndAddHtmlAttributeValues( + /// TagHelperExecutionContext executionContext) + /// + /// + public string EndAddHtmlAttributeValuesMethodName { get; set; } + + /// + /// Method name used to add individual components of an unbound, complex tag helper attribute to + /// TagHelperExecutionContexts. + /// + /// + /// Method signature: + /// + /// public void AddHtmlAttributeValues( + /// string prefix, + /// int prefixOffset, + /// string value, + /// int valueOffset, + /// int valueLength, + /// bool isLiteral) /// /// - public string AddHtmlAttributeValuesMethodName { get; set; } + public string AddHtmlAttributeValueMethodName { get; set; } /// /// The name of the method used to create a tag helper. diff --git a/src/Microsoft.AspNet.Razor/CodeGenerators/Visitors/CSharpCodeVisitor.cs b/src/Microsoft.AspNet.Razor/CodeGenerators/Visitors/CSharpCodeVisitor.cs index 0c84e6bb9..7596be589 100644 --- a/src/Microsoft.AspNet.Razor/CodeGenerators/Visitors/CSharpCodeVisitor.cs +++ b/src/Microsoft.AspNet.Razor/CodeGenerators/Visitors/CSharpCodeVisitor.cs @@ -80,6 +80,13 @@ protected virtual string WriteToMethodName } } + /// + /// Gets the method name used to generate WriteAttribute invocations in the rendered page. + /// + /// Defaults to + protected virtual string WriteAttributeValueMethodName => + Context.Host.GeneratedClassContext.WriteAttributeValueMethodName; + protected override void Visit(TagHelperChunk chunk) { TagHelperRenderer.RenderTagHelper(chunk); @@ -174,50 +181,60 @@ protected override void Visit(DynamicCodeAttributeChunk chunk) var currentRenderingMode = Context.ExpressionRenderingMode; var currentTargetWriterName = Context.TargetWriterName; - Context.TargetWriterName = ValueWriterName; + if (!string.IsNullOrEmpty(currentTargetWriterName)) + { + Writer.WriteStartMethodInvocation(Context.Host.GeneratedClassContext.WriteAttributeValueToMethodName) + .Write(currentTargetWriterName) + .WriteParameterSeparator(); + } + else + { + Writer.WriteStartMethodInvocation(WriteAttributeValueMethodName); + } - Writer.WriteParameterSeparator() - .WriteLine(); + Context.TargetWriterName = ValueWriterName; var code = chunk.Children.FirstOrDefault(); if (code is ExpressionChunk || code is ExpressionBlockChunk) { - Writer.WriteStartMethodInvocation("Tuple.Create") - .WriteLocationTaggedString(chunk.Prefix) - .WriteParameterSeparator() - .WriteStartMethodInvocation("Tuple.Create", new string[] { "System.Object", "System.Int32" }); + Writer + .WriteLocationTaggedString(chunk.Prefix) + .WriteParameterSeparator(); Context.ExpressionRenderingMode = ExpressionRenderingMode.InjectCode; Accept(code); - Writer.WriteParameterSeparator() - .Write(chunk.Start.AbsoluteIndex.ToString(CultureInfo.CurrentCulture)) - .WriteEndMethodInvocation(endLine: false) - .WriteParameterSeparator() - .WriteBooleanLiteral(value: false) - .WriteEndMethodInvocation(endLine: false); + Writer + .WriteParameterSeparator() + .Write(chunk.Start.AbsoluteIndex.ToString(CultureInfo.InvariantCulture)) + .WriteParameterSeparator() + .Write(chunk.Association.Length.ToString(CultureInfo.InvariantCulture)) + .WriteParameterSeparator() + .WriteBooleanLiteral(value: false) + .WriteEndMethodInvocation(); } else { - Writer.WriteStartMethodInvocation("Tuple.Create") - .WriteLocationTaggedString(chunk.Prefix) - .WriteParameterSeparator() - .WriteStartMethodInvocation("Tuple.Create", new string[] { "System.Object", "System.Int32" }) - .WriteStartNewObject(Context.Host.GeneratedClassContext.TemplateTypeName); + Writer + .WriteLocationTaggedString(chunk.Prefix) + .WriteParameterSeparator() + .WriteStartNewObject(Context.Host.GeneratedClassContext.TemplateTypeName); using (Writer.BuildLambda(endLine: false, parameterNames: ValueWriterName)) { Accept(chunk.Children); } - Writer.WriteEndMethodInvocation(false) - .WriteParameterSeparator() - .Write(chunk.Start.AbsoluteIndex.ToString(CultureInfo.CurrentCulture)) - .WriteEndMethodInvocation(endLine: false) - .WriteParameterSeparator() - .WriteBooleanLiteral(false) - .WriteEndMethodInvocation(false); + Writer + .WriteEndMethodInvocation(false) + .WriteParameterSeparator() + .Write(chunk.Start.AbsoluteIndex.ToString(CultureInfo.InvariantCulture)) + .WriteParameterSeparator() + .Write(chunk.Association.Length.ToString(CultureInfo.InvariantCulture)) + .WriteParameterSeparator() + .WriteBooleanLiteral(false) + .WriteEndMethodInvocation(); } Context.TargetWriterName = currentTargetWriterName; @@ -239,15 +256,23 @@ protected override void Visit(LiteralCodeAttributeChunk chunk) return; } - Writer.WriteParameterSeparator() - .WriteStartMethodInvocation("Tuple.Create") - .WriteLocationTaggedString(chunk.Prefix) - .WriteParameterSeparator(); + if (!string.IsNullOrEmpty(Context.TargetWriterName)) + { + Writer.WriteStartMethodInvocation(Context.Host.GeneratedClassContext.WriteAttributeValueToMethodName) + .Write(Context.TargetWriterName) + .WriteParameterSeparator(); + } + else + { + Writer.WriteStartMethodInvocation(WriteAttributeValueMethodName); + } + + Writer + .WriteLocationTaggedString(chunk.Prefix) + .WriteParameterSeparator(); if (visitChildren) { - Writer.WriteStartMethodInvocation("Tuple.Create", new string[] { "System.Object", "System.Int32" }); - var currentRenderingMode = Context.ExpressionRenderingMode; Context.ExpressionRenderingMode = ExpressionRenderingMode.InjectCode; @@ -255,19 +280,24 @@ protected override void Visit(LiteralCodeAttributeChunk chunk) Context.ExpressionRenderingMode = currentRenderingMode; - Writer.WriteParameterSeparator() - .Write(chunk.ValueLocation.AbsoluteIndex.ToString(CultureInfo.CurrentCulture)) - .WriteEndMethodInvocation(false) - .WriteParameterSeparator() - .WriteBooleanLiteral(false) - .WriteEndMethodInvocation(false); + Writer + .WriteParameterSeparator() + .Write(chunk.ValueLocation.AbsoluteIndex.ToString(CultureInfo.InvariantCulture)) + .WriteParameterSeparator() + .Write(chunk.Association.Length.ToString(CultureInfo.InvariantCulture)) + .WriteParameterSeparator() + .WriteBooleanLiteral(false) + .WriteEndMethodInvocation(); } else { - Writer.WriteLocationTaggedString(chunk.Value) - .WriteParameterSeparator() - .WriteBooleanLiteral(true) - .WriteEndMethodInvocation(false); + Writer + .WriteLocationTaggedString(chunk.Value) + .WriteParameterSeparator() + .Write(chunk.Association.Length.ToString(CultureInfo.InvariantCulture)) + .WriteParameterSeparator() + .WriteBooleanLiteral(true) + .WriteEndMethodInvocation(); } } @@ -283,24 +313,29 @@ protected override void Visit(CodeAttributeChunk chunk) if (!string.IsNullOrEmpty(Context.TargetWriterName)) { - Writer.WriteStartMethodInvocation(Context.Host.GeneratedClassContext.WriteAttributeToMethodName) + Writer.WriteStartMethodInvocation(Context.Host.GeneratedClassContext.BeginWriteAttributeToMethodName) .Write(Context.TargetWriterName) .WriteParameterSeparator(); } else { - Writer.WriteStartMethodInvocation(Context.Host.GeneratedClassContext.WriteAttributeMethodName); + Writer.WriteStartMethodInvocation(Context.Host.GeneratedClassContext.BeginWriteAttributeMethodName); } + var attributeCount = chunk.Children.Count(c => c is LiteralCodeAttributeChunk || c is DynamicCodeAttributeChunk); + Writer.WriteStringLiteral(chunk.Attribute) .WriteParameterSeparator() .WriteLocationTaggedString(chunk.Prefix) .WriteParameterSeparator() - .WriteLocationTaggedString(chunk.Suffix); + .WriteLocationTaggedString(chunk.Suffix) + .WriteParameterSeparator() + .Write(attributeCount.ToString(CultureInfo.InvariantCulture)) + .WriteEndMethodInvocation(); Accept(chunk.Children); - Writer.WriteEndMethodInvocation(); + Writer.WriteMethodInvocation(Context.Host.GeneratedClassContext.EndWriteAttributeMethodName); } protected override void Visit(SectionChunk chunk) 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 94cc61db5..c37a5fb3b 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ComplexTagHelpers.cs @@ -239,8 +239,11 @@ public override async Task ExecuteAsync() , StartTagHelperWritingScope, EndTagHelperWritingScope); __PTagHelper = CreateTagHelper(); __tagHelperExecutionContext.Add(__PTagHelper); - 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)); + BeginAddHtmlAttributeValues(__tagHelperExecutionContext, "time", 3); + AddHtmlAttributeValue("", 148, "Current", 148, 7, true); + AddHtmlAttributeValue(" ", 155, "Time:", 156, 6, true); + AddHtmlAttributeValue(" ", 161, DateTime.Now, 162, 14, false); + EndAddHtmlAttributeValues(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); Instrumentation.BeginContext(139, 529, false); await WriteTagHelperAsync(__tagHelperExecutionContext); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ConditionalAttributes.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ConditionalAttributes.cs index b6de066b6..6dcc7c85d 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ConditionalAttributes.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/ConditionalAttributes.cs @@ -25,33 +25,41 @@ public override async Task ExecuteAsync() Instrumentation.BeginContext(46, 28, true); WriteLiteral(" \r\n (cls, 82), false)); + BeginWriteAttribute("class", " class=\"", 74, "\"", 86, 1); + WriteAttributeValue("", 82, cls, 82, 4, false); + EndWriteAttribute(); Instrumentation.BeginContext(87, 11, true); WriteLiteral(" />\r\n (cls, 110), false)); + BeginWriteAttribute("class", " class=\"", 98, "\"", 114, 2); + WriteAttributeValue("", 106, "foo", 106, 3, true); + WriteAttributeValue(" ", 109, cls, 110, 5, false); + EndWriteAttribute(); Instrumentation.BeginContext(115, 11, true); WriteLiteral(" />\r\n (cls, 134), false), Tuple.Create(Tuple.Create(" ", 138), Tuple.Create("foo", 139), true)); + BeginWriteAttribute("class", " class=\"", 126, "\"", 142, 2); + WriteAttributeValue("", 134, cls, 134, 4, false); + WriteAttributeValue(" ", 138, "foo", 139, 4, true); + EndWriteAttribute(); Instrumentation.BeginContext(143, 31, true); WriteLiteral(" />\r\n (ch, 184), false)); + BeginWriteAttribute("checked", " checked=\"", 174, "\"", 187, 1); + WriteAttributeValue("", 184, ch, 184, 3, false); + EndWriteAttribute(); Instrumentation.BeginContext(188, 31, true); WriteLiteral(" />\r\n (ch, 233), false)); + BeginWriteAttribute("checked", " checked=\"", 219, "\"", 236, 2); + WriteAttributeValue("", 229, "foo", 229, 3, true); + WriteAttributeValue(" ", 232, ch, 233, 4, false); + EndWriteAttribute(); Instrumentation.BeginContext(237, 11, true); WriteLiteral(" />\r\n (new Template((__razor_attribute_value_writer) => { + BeginWriteAttribute("class", " class=\"", 248, "\"", 281, 1); + WriteAttributeValue("", 256, new Template((__razor_attribute_value_writer) => { #line 10 "ConditionalAttributes.cshtml" if(cls != null) { @@ -72,17 +80,20 @@ public override async Task ExecuteAsync() #line hidden } - ), 256), false)); + ), 256, 25, false); + EndWriteAttribute(); Instrumentation.BeginContext(282, 40, true); WriteLiteral(" />\r\n \r\n (Url.Content("~/Scripts/jquery-1.6.2.min.js"), 328), false)); + BeginWriteAttribute("src", " src=\"", 322, "\"", 373, 1); + WriteAttributeValue("", 328, Url.Content("~/Scripts/jquery-1.6.2.min.js"), 328, 45, false); + EndWriteAttribute(); Instrumentation.BeginContext(374, 46, true); WriteLiteral(" type=\"text/javascript\">\r\n (Url.Content("~/Scripts/modernizr-2.0.6-development-only.js"), 426), false)); + BeginWriteAttribute("src", " src=\"", 420, "\"", 487, 1); + WriteAttributeValue("", 426, Url.Content("~/Scripts/modernizr-2.0.6-development-only.js"), 426, 61, false); + EndWriteAttribute(); Instrumentation.BeginContext(488, 152, true); WriteLiteral(" type=\"text/javascript\">\r\n \r\n"); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/DynamicAttributeTagHelpers.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/DynamicAttributeTagHelpers.cs index 69ca2c691..c2a63d935 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/DynamicAttributeTagHelpers.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/DynamicAttributeTagHelpers.cs @@ -32,8 +32,10 @@ public override async Task ExecuteAsync() , 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)); + BeginAddHtmlAttributeValues(__tagHelperExecutionContext, "unbound", 2); + AddHtmlAttributeValue("", 51, "prefix", 51, 6, true); + AddHtmlAttributeValue(" ", 57, DateTime.Now, 58, 14, false); + EndAddHtmlAttributeValues(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); Instrumentation.BeginContext(35, 40, false); await WriteTagHelperAsync(__tagHelperExecutionContext); @@ -47,8 +49,8 @@ public override async Task ExecuteAsync() , StartTagHelperWritingScope, EndTagHelperWritingScope); __InputTagHelper = CreateTagHelper(); __tagHelperExecutionContext.Add(__InputTagHelper); - AddHtmlAttributeValues("unbound", __tagHelperExecutionContext, - Tuple.Create(Tuple.Create("", 95), Tuple.Create(new Template((__razor_attribute_value_writer) => { + BeginAddHtmlAttributeValues(__tagHelperExecutionContext, "unbound", 2); + AddHtmlAttributeValue("", 95, new Template((__razor_attribute_value_writer) => { #line 5 "DynamicAttributeTagHelpers.cshtml" if (true) { @@ -82,7 +84,9 @@ public override async Task ExecuteAsync() #line hidden } - ), 95), false), Tuple.Create(Tuple.Create(" ", 139), Tuple.Create("suffix", 140), true)); + ), 95, 44, false); + AddHtmlAttributeValue(" ", 139, "suffix", 140, 7, true); + EndAddHtmlAttributeValues(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); Instrumentation.BeginContext(79, 71, false); await WriteTagHelperAsync(__tagHelperExecutionContext); @@ -107,8 +111,11 @@ public override async Task ExecuteAsync() __tagHelperStringValueBuffer = EndTagHelperWritingScope(); __InputTagHelper.Bound = __tagHelperStringValueBuffer.GetContent(HtmlEncoder); __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)); + BeginAddHtmlAttributeValues(__tagHelperExecutionContext, "unbound", 3); + AddHtmlAttributeValue("", 206, "prefix", 206, 6, true); + AddHtmlAttributeValue(" ", 212, DateTime.Now, 213, 14, false); + AddHtmlAttributeValue(" ", 226, "suffix", 227, 7, true); + EndAddHtmlAttributeValues(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); Instrumentation.BeginContext(154, 83, false); await WriteTagHelperAsync(__tagHelperExecutionContext); @@ -166,9 +173,9 @@ public override async Task ExecuteAsync() __tagHelperStringValueBuffer = EndTagHelperWritingScope(); __InputTagHelper.Bound = __tagHelperStringValueBuffer.GetContent(HtmlEncoder); __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) => { + BeginAddHtmlAttributeValues(__tagHelperExecutionContext, "unbound", 3); + AddHtmlAttributeValue("", 347, long.MinValue, 347, 14, false); + AddHtmlAttributeValue(" ", 361, new Template((__razor_attribute_value_writer) => { #line 10 "DynamicAttributeTagHelpers.cshtml" if (true) { @@ -202,8 +209,9 @@ public override async Task ExecuteAsync() #line hidden } - ), 362), false), - Tuple.Create(Tuple.Create(" ", 406), Tuple.Create(int.MaxValue, 407), false)); + ), 362, 45, false); + AddHtmlAttributeValue(" ", 406, int.MaxValue, 407, 14, false); + EndAddHtmlAttributeValues(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); Instrumentation.BeginContext(241, 183, false); await WriteTagHelperAsync(__tagHelperExecutionContext); @@ -217,10 +225,13 @@ public override async Task ExecuteAsync() , 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)); + BeginAddHtmlAttributeValues(__tagHelperExecutionContext, "unbound", 5); + AddHtmlAttributeValue("", 444, long.MinValue, 444, 14, false); + AddHtmlAttributeValue(" ", 458, DateTime.Now, 459, 14, false); + AddHtmlAttributeValue(" ", 472, "static", 473, 7, true); + AddHtmlAttributeValue(" ", 479, "content", 483, 11, true); + AddHtmlAttributeValue(" ", 490, int.MaxValue, 491, 14, false); + EndAddHtmlAttributeValues(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); Instrumentation.BeginContext(428, 80, false); await WriteTagHelperAsync(__tagHelperExecutionContext); @@ -234,8 +245,8 @@ public override async Task ExecuteAsync() , StartTagHelperWritingScope, EndTagHelperWritingScope); __InputTagHelper = CreateTagHelper(); __tagHelperExecutionContext.Add(__InputTagHelper); - AddHtmlAttributeValues("unbound", __tagHelperExecutionContext, - Tuple.Create(Tuple.Create("", 528), Tuple.Create(new Template((__razor_attribute_value_writer) => { + BeginAddHtmlAttributeValues(__tagHelperExecutionContext, "unbound", 1); + AddHtmlAttributeValue("", 528, new Template((__razor_attribute_value_writer) => { #line 14 "DynamicAttributeTagHelpers.cshtml" if (true) { @@ -269,7 +280,8 @@ public override async Task ExecuteAsync() #line hidden } - ), 528), false)); + ), 528, 44, false); + EndAddHtmlAttributeValues(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); Instrumentation.BeginContext(512, 64, false); await WriteTagHelperAsync(__tagHelperExecutionContext); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/InlineBlocks.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/InlineBlocks.cs index babca7b88..3cdef84f8 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/InlineBlocks.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/InlineBlocks.cs @@ -20,8 +20,8 @@ public override async Task ExecuteAsync() Instrumentation.BeginContext(13, 23, true); WriteLiteral("(string link) {\r\n (new Template((__razor_attribute_value_writer) => { + BeginWriteAttribute("href", " href=\"", 36, "\"", 94, 1); + WriteAttributeValue("", 43, new Template((__razor_attribute_value_writer) => { #line 2 "InlineBlocks.cshtml" if(link != null) { @@ -57,7 +57,8 @@ public override async Task ExecuteAsync() #line hidden } - ), 43), false)); + ), 43, 50, false); + EndWriteAttribute(); Instrumentation.BeginContext(95, 6, true); WriteLiteral(" />\r\n}"); Instrumentation.EndContext(); 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 3fde959c8..5d34d9a45 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TagHelpersInSection.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TagHelpersInSection.cs @@ -83,8 +83,11 @@ public override async Task ExecuteAsync() __tagHelperStringValueBuffer = EndTagHelperWritingScope(); __MyTagHelper.BoundProperty = __tagHelperStringValueBuffer.GetContent(HtmlEncoder); __tagHelperExecutionContext.AddTagHelperAttribute("boundproperty", __MyTagHelper.BoundProperty); - 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)); + BeginAddHtmlAttributeValues(__tagHelperExecutionContext, "unboundproperty", 3); + AddHtmlAttributeValue("", 188, "Current", 188, 7, true); + AddHtmlAttributeValue(" ", 195, "Time:", 196, 6, true); + AddHtmlAttributeValue(" ", 201, DateTime.Now, 202, 14, false); + EndAddHtmlAttributeValues(__tagHelperExecutionContext); __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/Output/TransitionsInTagHelperAttributes.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TransitionsInTagHelperAttributes.cs index 61a473837..e7230ae8b 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TransitionsInTagHelperAttributes.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/TransitionsInTagHelperAttributes.cs @@ -43,10 +43,11 @@ public override async Task ExecuteAsync() , StartTagHelperWritingScope, EndTagHelperWritingScope); __PTagHelper = CreateTagHelper(); __tagHelperExecutionContext.Add(__PTagHelper); - AddHtmlAttributeValues("class", __tagHelperExecutionContext, - Tuple.Create(Tuple.Create("", 109), Tuple.Create(new Template((__razor_attribute_value_writer) => { + BeginAddHtmlAttributeValues(__tagHelperExecutionContext, "class", 1); + AddHtmlAttributeValue("", 109, new Template((__razor_attribute_value_writer) => { } - ), 109), false)); + ), 109, 6, false); + EndAddHtmlAttributeValues(__tagHelperExecutionContext); #line 7 "TransitionsInTagHelperAttributes.cshtml" __PTagHelper.Age = 1337; @@ -66,8 +67,9 @@ public override async Task ExecuteAsync() , StartTagHelperWritingScope, EndTagHelperWritingScope); __PTagHelper = CreateTagHelper(); __tagHelperExecutionContext.Add(__PTagHelper); - AddHtmlAttributeValues("class", __tagHelperExecutionContext, - Tuple.Create(Tuple.Create("", 155), Tuple.Create(@class, 155), false)); + BeginAddHtmlAttributeValues(__tagHelperExecutionContext, "class", 1); + AddHtmlAttributeValue("", 155, @class, 155, 9, false); + EndAddHtmlAttributeValues(__tagHelperExecutionContext); #line 8 "TransitionsInTagHelperAttributes.cshtml" __PTagHelper.Age = 42; @@ -147,8 +149,10 @@ public override async Task ExecuteAsync() , StartTagHelperWritingScope, EndTagHelperWritingScope); __PTagHelper = CreateTagHelper(); __tagHelperExecutionContext.Add(__PTagHelper); - AddHtmlAttributeValues("class", __tagHelperExecutionContext, Tuple.Create(Tuple.Create("", 298), Tuple.Create("custom-", 298), true), - Tuple.Create(Tuple.Create("", 305), Tuple.Create(@class, 305), false)); + BeginAddHtmlAttributeValues(__tagHelperExecutionContext, "class", 2); + AddHtmlAttributeValue("", 298, "custom-", 298, 7, true); + AddHtmlAttributeValue("", 305, @class, 305, 9, false); + EndAddHtmlAttributeValues(__tagHelperExecutionContext); #line 12 "TransitionsInTagHelperAttributes.cshtml" __PTagHelper.Age = 4 * @(@int + 2);