React to WriteAttribute \ AddHtmlAttribute API changes
This commit is contained in:
parent
5a705d820d
commit
2028351bb8
|
|
@ -107,7 +107,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
// Can't use nameof because IHtmlHelper is (also) not accessible here.
|
||||
MarkAsHtmlEncodedMethodName = HtmlHelperPropertyName + ".Raw",
|
||||
AddHtmlAttributeValuesMethodName = "AddHtmlAttributeValues",
|
||||
BeginAddHtmlAttributeValuesMethodName = "BeginAddHtmlAttributeValues",
|
||||
EndAddHtmlAttributeValuesMethodName = "EndAddHtmlAttributeValues",
|
||||
AddHtmlAttributeValueMethodName = "AddHtmlAttributeValue",
|
||||
HtmlEncoderPropertyName = "HtmlEncoder",
|
||||
TagHelperContentGetContentMethodName = nameof(TagHelperContent.GetContent),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
public class AttributeValue
|
||||
{
|
||||
public AttributeValue(PositionTagged<string> prefix, PositionTagged<object> value, bool literal)
|
||||
{
|
||||
Prefix = prefix;
|
||||
Value = value;
|
||||
Literal = literal;
|
||||
}
|
||||
|
||||
public PositionTagged<string> Prefix { get; private set; }
|
||||
|
||||
public PositionTagged<object> Value { get; private set; }
|
||||
|
||||
public bool Literal { get; private set; }
|
||||
|
||||
public static AttributeValue FromTuple(Tuple<Tuple<string, int>, Tuple<object, int>, bool> value)
|
||||
{
|
||||
return new AttributeValue(value.Item1, value.Item2, value.Item3);
|
||||
}
|
||||
|
||||
public static AttributeValue FromTuple(Tuple<Tuple<string, int>, Tuple<string, int>, bool> value)
|
||||
{
|
||||
return new AttributeValue(value.Item1,
|
||||
new PositionTagged<object>(value.Item2.Item1, value.Item2.Item2),
|
||||
value.Item3);
|
||||
}
|
||||
|
||||
public static implicit operator AttributeValue(Tuple<Tuple<string, int>, Tuple<object, int>, bool> value)
|
||||
{
|
||||
return FromTuple(value);
|
||||
}
|
||||
|
||||
public static implicit operator AttributeValue(Tuple<Tuple<string, int>, Tuple<string, int>, bool> value)
|
||||
{
|
||||
return FromTuple(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
[DebuggerDisplay("({Position})\"{Value}\"")]
|
||||
public class PositionTagged<T>
|
||||
{
|
||||
public PositionTagged(T value, int offset)
|
||||
{
|
||||
Position = offset;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public int Position { get; private set; }
|
||||
|
||||
public T Value { get; private set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
|
||||
public static implicit operator T(PositionTagged<T> value)
|
||||
{
|
||||
return value.Value;
|
||||
}
|
||||
|
||||
public static implicit operator PositionTagged<T>(Tuple<T, int> value)
|
||||
{
|
||||
return new PositionTagged<T>(value.Item1, value.Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
|
@ -34,6 +35,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
private ITagHelperActivator _tagHelperActivator;
|
||||
private ITypeActivatorCache _typeActivatorCache;
|
||||
private bool _renderedBody;
|
||||
private AttributeInfo _attributeInfo;
|
||||
private TagHelperAttributeInfo _tagHelperAttributeInfo;
|
||||
private StringCollectionTextWriter _valueBuffer;
|
||||
|
||||
public RazorPage()
|
||||
{
|
||||
|
|
@ -571,31 +575,25 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
}
|
||||
|
||||
public virtual void WriteAttribute(
|
||||
public virtual void BeginWriteAttribute(
|
||||
string name,
|
||||
PositionTagged<string> prefix,
|
||||
PositionTagged<string> suffix,
|
||||
params AttributeValue[] values)
|
||||
string prefix,
|
||||
int prefixOffset,
|
||||
string suffix,
|
||||
int suffixOffset,
|
||||
int attributeValuesCount)
|
||||
{
|
||||
if (prefix == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(prefix));
|
||||
}
|
||||
|
||||
if (suffix == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(suffix));
|
||||
}
|
||||
|
||||
WriteAttributeTo(Output, name, prefix, suffix, values);
|
||||
BeginWriteAttributeTo(Output, name, prefix, prefixOffset, suffix, suffixOffset, attributeValuesCount);
|
||||
}
|
||||
|
||||
public virtual void WriteAttributeTo(
|
||||
public virtual void BeginWriteAttributeTo(
|
||||
TextWriter writer,
|
||||
string name,
|
||||
PositionTagged<string> prefix,
|
||||
PositionTagged<string> suffix,
|
||||
params AttributeValue[] values)
|
||||
string prefix,
|
||||
int prefixOffset,
|
||||
string suffix,
|
||||
int suffixOffset,
|
||||
int attributeValuesCount)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
|
|
@ -612,112 +610,170 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
throw new ArgumentNullException(nameof(suffix));
|
||||
}
|
||||
|
||||
if (values.Length == 0)
|
||||
_attributeInfo = new AttributeInfo(name, prefix, prefixOffset, suffix, suffixOffset, attributeValuesCount);
|
||||
|
||||
// Single valued attributes might be omitted in entirety if it the attribute value strictly evaluates to
|
||||
// null or false. Consequently defer the prefix generation until we encounter the attribute value.
|
||||
if (attributeValuesCount != 1)
|
||||
{
|
||||
// Explicitly empty attribute, so write the prefix
|
||||
WritePositionTaggedLiteral(writer, prefix);
|
||||
WritePositionTaggedLiteral(writer, prefix, prefixOffset);
|
||||
}
|
||||
else if (IsSingleBoolFalseOrNullValue(values))
|
||||
{
|
||||
// Value is either null or the bool 'false' with no prefix; don't render the attribute.
|
||||
return;
|
||||
}
|
||||
else if (UseAttributeNameAsValue(values))
|
||||
{
|
||||
var attributeValue = values[0];
|
||||
var positionTaggedAttributeValue = attributeValue.Value;
|
||||
|
||||
WritePositionTaggedLiteral(writer, prefix);
|
||||
|
||||
var sourceLength = suffix.Position - positionTaggedAttributeValue.Position;
|
||||
var nameAttributeValue = new AttributeValue(
|
||||
attributeValue.Prefix,
|
||||
new PositionTagged<object>(name, attributeValue.Value.Position),
|
||||
literal: attributeValue.Literal);
|
||||
|
||||
// The value is just the bool 'true', write the attribute name instead of the string 'True'.
|
||||
WriteAttributeValue(writer, nameAttributeValue, sourceLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This block handles two cases.
|
||||
// 1. Single value with prefix.
|
||||
// 2. Multiple values with or without prefix.
|
||||
WritePositionTaggedLiteral(writer, prefix);
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
var attributeValue = values[i];
|
||||
var positionTaggedAttributeValue = attributeValue.Value;
|
||||
|
||||
if (positionTaggedAttributeValue.Value == null)
|
||||
{
|
||||
// Nothing to write
|
||||
continue;
|
||||
}
|
||||
|
||||
var next = i == values.Length - 1 ?
|
||||
suffix : // End of the list, grab the suffix
|
||||
values[i + 1].Prefix; // Still in the list, grab the next prefix
|
||||
|
||||
// Calculate length of the source span by the position of the next value (or suffix)
|
||||
var sourceLength = next.Position - attributeValue.Value.Position;
|
||||
|
||||
WriteAttributeValue(writer, attributeValue, sourceLength);
|
||||
}
|
||||
}
|
||||
|
||||
WritePositionTaggedLiteral(writer, suffix);
|
||||
}
|
||||
|
||||
public void AddHtmlAttributeValues(
|
||||
string attributeName,
|
||||
TagHelperExecutionContext executionContext,
|
||||
params AttributeValue[] values)
|
||||
public void WriteAttributeValue(
|
||||
string prefix,
|
||||
int prefixOffset,
|
||||
object value,
|
||||
int valueOffset,
|
||||
int valueLength,
|
||||
bool isLiteral)
|
||||
{
|
||||
if (IsSingleBoolFalseOrNullValue(values))
|
||||
{
|
||||
// The first value was 'null' or 'false' indicating that we shouldn't render the attribute. The
|
||||
// attribute is treated as a TagHelper attribute so it's only available in
|
||||
// TagHelperContext.AllAttributes for TagHelper authors to see (if they want to see why the attribute
|
||||
// was removed from TagHelperOutput.Attributes).
|
||||
executionContext.AddTagHelperAttribute(
|
||||
attributeName,
|
||||
values[0].Value.Value?.ToString() ?? string.Empty);
|
||||
WriteAttributeValueTo(Output, prefix, prefixOffset, value, valueOffset, valueLength, isLiteral);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if (UseAttributeNameAsValue(values))
|
||||
public void WriteAttributeValueTo(
|
||||
TextWriter writer,
|
||||
string prefix,
|
||||
int prefixOffset,
|
||||
object value,
|
||||
int valueOffset,
|
||||
int valueLength,
|
||||
bool isLiteral)
|
||||
{
|
||||
if (_attributeInfo.AttributeValuesCount == 1)
|
||||
{
|
||||
executionContext.AddHtmlAttribute(attributeName, attributeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
var valueBuffer = new StringCollectionTextWriter(Output.Encoding);
|
||||
|
||||
foreach (var value in values)
|
||||
if (IsBoolFalseOrNullValue(prefix, value))
|
||||
{
|
||||
if (value.Value.Value == null)
|
||||
{
|
||||
// Skip null values
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(value.Prefix))
|
||||
{
|
||||
WriteLiteralTo(valueBuffer, value.Prefix);
|
||||
}
|
||||
|
||||
WriteUnprefixedAttributeValueTo(valueBuffer, value);
|
||||
// Value is either null or the bool 'false' with no prefix; don't render the attribute.
|
||||
_attributeInfo.Suppressed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
using (var stringWriter = new StringWriter())
|
||||
{
|
||||
valueBuffer.Content.WriteTo(stringWriter, HtmlEncoder);
|
||||
// We are not omitting the attribute. Write the prefix.
|
||||
WritePositionTaggedLiteral(writer, _attributeInfo.Prefix, _attributeInfo.PrefixOffset);
|
||||
|
||||
var htmlString = new HtmlString(stringWriter.ToString());
|
||||
executionContext.AddHtmlAttribute(attributeName, htmlString);
|
||||
if (IsBoolTrueWithEmptyPrefixValue(prefix, value))
|
||||
{
|
||||
// The value is just the bool 'true', write the attribute name instead of the string 'True'.
|
||||
value = _attributeInfo.Name;
|
||||
}
|
||||
}
|
||||
|
||||
// This block handles two cases.
|
||||
// 1. Single value with prefix.
|
||||
// 2. Multiple values with or without prefix.
|
||||
if (value != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(prefix))
|
||||
{
|
||||
WritePositionTaggedLiteral(writer, prefix, prefixOffset);
|
||||
}
|
||||
|
||||
BeginContext(valueOffset, valueLength, isLiteral);
|
||||
|
||||
WriteUnprefixedAttributeValueTo(writer, value, isLiteral);
|
||||
|
||||
EndContext();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void EndWriteAttribute()
|
||||
{
|
||||
EndWriteAttributeTo(Output);
|
||||
}
|
||||
|
||||
public virtual void EndWriteAttributeTo(TextWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(writer));
|
||||
}
|
||||
|
||||
if (!_attributeInfo.Suppressed)
|
||||
{
|
||||
WritePositionTaggedLiteral(writer, _attributeInfo.Suffix, _attributeInfo.SuffixOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public void BeginAddHtmlAttributeValues(
|
||||
TagHelperExecutionContext executionContext,
|
||||
string attributeName,
|
||||
int attributeValuesCount)
|
||||
{
|
||||
_tagHelperAttributeInfo = new TagHelperAttributeInfo(executionContext, attributeName, attributeValuesCount);
|
||||
_valueBuffer = null;
|
||||
}
|
||||
|
||||
public void AddHtmlAttributeValue(
|
||||
string prefix,
|
||||
int prefixOffset,
|
||||
object value,
|
||||
int valueOffset,
|
||||
int valueLength,
|
||||
bool isLiteral)
|
||||
{
|
||||
Debug.Assert(_tagHelperAttributeInfo.ExecutionContext != null);
|
||||
if (_tagHelperAttributeInfo.AttributeValuesCount == 1)
|
||||
{
|
||||
if (IsBoolFalseOrNullValue(prefix, value))
|
||||
{
|
||||
// The first value was 'null' or 'false' indicating that we shouldn't render the attribute. The
|
||||
// attribute is treated as a TagHelper attribute so it's only available in
|
||||
// TagHelperContext.AllAttributes for TagHelper authors to see (if they want to see why the
|
||||
// attribute was removed from TagHelperOutput.Attributes).
|
||||
_tagHelperAttributeInfo.ExecutionContext.AddTagHelperAttribute(
|
||||
_tagHelperAttributeInfo.Name,
|
||||
value?.ToString() ?? string.Empty);
|
||||
_tagHelperAttributeInfo.Suppressed = true;
|
||||
return;
|
||||
}
|
||||
else if (IsBoolTrueWithEmptyPrefixValue(prefix, value))
|
||||
{
|
||||
_tagHelperAttributeInfo.ExecutionContext.AddHtmlAttribute(
|
||||
_tagHelperAttributeInfo.Name,
|
||||
_tagHelperAttributeInfo.Name);
|
||||
_tagHelperAttributeInfo.Suppressed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
if (_valueBuffer == null)
|
||||
{
|
||||
_valueBuffer = new StringCollectionTextWriter(Output.Encoding);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(prefix))
|
||||
{
|
||||
WriteLiteralTo(_valueBuffer, prefix);
|
||||
}
|
||||
|
||||
WriteUnprefixedAttributeValueTo(_valueBuffer, value, isLiteral);
|
||||
}
|
||||
}
|
||||
|
||||
public void EndAddHtmlAttributeValues(TagHelperExecutionContext executionContext)
|
||||
{
|
||||
if (!_tagHelperAttributeInfo.Suppressed)
|
||||
{
|
||||
HtmlString htmlString;
|
||||
|
||||
if (_valueBuffer != null)
|
||||
{
|
||||
using (var stringWriter = new StringWriter())
|
||||
{
|
||||
_valueBuffer.Content.WriteTo(stringWriter, HtmlEncoder);
|
||||
htmlString = new HtmlString(stringWriter.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
htmlString = HtmlString.Empty;
|
||||
}
|
||||
|
||||
executionContext.AddHtmlAttribute(_tagHelperAttributeInfo.Name, htmlString);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string Href(string contentPath)
|
||||
|
|
@ -735,33 +791,18 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
return _urlHelper.Content(contentPath);
|
||||
}
|
||||
|
||||
private void WriteAttributeValue(TextWriter writer, AttributeValue attributeValue, int sourceLength)
|
||||
private void WriteUnprefixedAttributeValueTo(TextWriter writer, object value, bool isLiteral)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(attributeValue.Prefix))
|
||||
{
|
||||
WritePositionTaggedLiteral(writer, attributeValue.Prefix);
|
||||
}
|
||||
|
||||
BeginContext(attributeValue.Value.Position, sourceLength, isLiteral: attributeValue.Literal);
|
||||
|
||||
WriteUnprefixedAttributeValueTo(writer, attributeValue);
|
||||
|
||||
EndContext();
|
||||
}
|
||||
|
||||
private void WriteUnprefixedAttributeValueTo(TextWriter writer, AttributeValue attributeValue)
|
||||
{
|
||||
var positionTaggedAttributeValue = attributeValue.Value;
|
||||
var stringValue = positionTaggedAttributeValue.Value as string;
|
||||
var stringValue = value as string;
|
||||
|
||||
// The extra branching here is to ensure that we call the Write*To(string) overload where possible.
|
||||
if (attributeValue.Literal && stringValue != null)
|
||||
if (isLiteral && stringValue != null)
|
||||
{
|
||||
WriteLiteralTo(writer, stringValue);
|
||||
}
|
||||
else if (attributeValue.Literal)
|
||||
else if (isLiteral)
|
||||
{
|
||||
WriteLiteralTo(writer, positionTaggedAttributeValue.Value);
|
||||
WriteLiteralTo(writer, value);
|
||||
}
|
||||
else if (stringValue != null)
|
||||
{
|
||||
|
|
@ -769,7 +810,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
else
|
||||
{
|
||||
WriteTo(writer, positionTaggedAttributeValue.Value);
|
||||
WriteTo(writer, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -780,11 +821,6 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
EndContext();
|
||||
}
|
||||
|
||||
private void WritePositionTaggedLiteral(TextWriter writer, PositionTagged<string> value)
|
||||
{
|
||||
WritePositionTaggedLiteral(writer, value.Value, value.Position);
|
||||
}
|
||||
|
||||
protected virtual HelperResult RenderBody()
|
||||
{
|
||||
if (RenderBodyDelegateAsync == null)
|
||||
|
|
@ -1030,30 +1066,18 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
return HtmlString.Empty;
|
||||
}
|
||||
|
||||
private bool IsSingleBoolFalseOrNullValue(AttributeValue[] values)
|
||||
private bool IsBoolFalseOrNullValue(string prefix, object value)
|
||||
{
|
||||
if (values.Length == 1 && string.IsNullOrEmpty(values[0].Prefix) &&
|
||||
(values[0].Value.Value is bool || values[0].Value.Value == null))
|
||||
{
|
||||
var attributeValue = values[0];
|
||||
var positionTaggedAttributeValue = attributeValue.Value;
|
||||
|
||||
if (positionTaggedAttributeValue.Value == null || !(bool)positionTaggedAttributeValue.Value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return string.IsNullOrEmpty(prefix) &&
|
||||
(value == null ||
|
||||
(value is bool && !(bool)value));
|
||||
}
|
||||
|
||||
private bool UseAttributeNameAsValue(AttributeValue[] values)
|
||||
private bool IsBoolTrueWithEmptyPrefixValue(string prefix, object value)
|
||||
{
|
||||
// If the value is just the bool 'true', use the attribute name as the value.
|
||||
return values.Length == 1 &&
|
||||
string.IsNullOrEmpty(values[0].Prefix) &&
|
||||
values[0].Value.Value is bool &&
|
||||
(bool)values[0].Value.Value;
|
||||
return string.IsNullOrEmpty(prefix) &&
|
||||
(value is bool && (bool)value);
|
||||
}
|
||||
|
||||
private void EnsureMethodCanBeInvoked(string methodName)
|
||||
|
|
@ -1063,5 +1087,63 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
throw new InvalidOperationException(Resources.FormatRazorPage_MethodCannotBeCalled(methodName, Path));
|
||||
}
|
||||
}
|
||||
|
||||
private struct AttributeInfo
|
||||
{
|
||||
public AttributeInfo(
|
||||
string name,
|
||||
string prefix,
|
||||
int prefixOffset,
|
||||
string suffix,
|
||||
int suffixOffset,
|
||||
int attributeValuesCount)
|
||||
{
|
||||
Name = name;
|
||||
Prefix = prefix;
|
||||
PrefixOffset = prefixOffset;
|
||||
Suffix = suffix;
|
||||
SuffixOffset = suffixOffset;
|
||||
AttributeValuesCount = attributeValuesCount;
|
||||
|
||||
Suppressed = false;
|
||||
}
|
||||
|
||||
public int AttributeValuesCount { get; }
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public string Prefix { get; }
|
||||
|
||||
public int PrefixOffset { get; }
|
||||
|
||||
public string Suffix { get; }
|
||||
|
||||
public int SuffixOffset { get; }
|
||||
|
||||
public bool Suppressed { get; set; }
|
||||
}
|
||||
|
||||
private struct TagHelperAttributeInfo
|
||||
{
|
||||
public TagHelperAttributeInfo(
|
||||
TagHelperExecutionContext tagHelperExecutionContext,
|
||||
string name,
|
||||
int attributeValuesCount)
|
||||
{
|
||||
ExecutionContext = tagHelperExecutionContext;
|
||||
Name = name;
|
||||
AttributeValuesCount = attributeValuesCount;
|
||||
|
||||
Suppressed = false;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public TagHelperExecutionContext ExecutionContext { get; }
|
||||
|
||||
public int AttributeValuesCount { get; }
|
||||
|
||||
public bool Suppressed { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,8 +32,9 @@ namespace Asp
|
|||
BeginContext(0, 4, true);
|
||||
WriteLiteral("<div");
|
||||
EndContext();
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 4), Tuple.Create("\"", 17),
|
||||
Tuple.Create(Tuple.Create("", 12), Tuple.Create<System.Object, System.Int32>(logo, 12), false));
|
||||
BeginWriteAttribute("class", " class=\"", 4, "\"", 17, 1);
|
||||
WriteAttributeValue("", 12, logo, 12, 5, false);
|
||||
EndWriteAttribute();
|
||||
BeginContext(18, 24, true);
|
||||
WriteLiteral(">\r\n Hello world\r\n ");
|
||||
EndContext();
|
||||
|
|
|
|||
|
|
@ -664,15 +664,10 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var page = CreatePage(p =>
|
||||
{
|
||||
p.HtmlEncoder = new CommonTestEncoder();
|
||||
p.WriteAttribute("href",
|
||||
new PositionTagged<string>("prefix", 0),
|
||||
new PositionTagged<string>("suffix", 34),
|
||||
new AttributeValue(new PositionTagged<string>("prefix", 0),
|
||||
new PositionTagged<object>("attr1-value", 8),
|
||||
literal: true),
|
||||
new AttributeValue(new PositionTagged<string>("prefix2", 22),
|
||||
new PositionTagged<object>("attr2", 29),
|
||||
literal: false));
|
||||
p.BeginWriteAttribute("href", "prefix", 0, "suffix", 34, 2);
|
||||
p.WriteAttributeValue("prefix", 0, "attr1-value", 8, 14, true);
|
||||
p.WriteAttributeValue("prefix2", 22, "attr2", 29, 5, false);
|
||||
p.EndWriteAttribute();
|
||||
});
|
||||
var context = new Mock<IPageExecutionContext>(MockBehavior.Strict);
|
||||
var sequence = new MockSequence();
|
||||
|
|
@ -704,12 +699,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var page = CreatePage(p =>
|
||||
{
|
||||
p.HtmlEncoder = new CommonTestEncoder();
|
||||
p.WriteAttribute("href",
|
||||
new PositionTagged<string>("prefix", 0),
|
||||
new PositionTagged<string>("suffix", 10),
|
||||
new AttributeValue(new PositionTagged<string>(string.Empty, 6),
|
||||
new PositionTagged<object>("true", 6),
|
||||
literal: false));
|
||||
p.BeginWriteAttribute("href", "prefix", 0, "suffix", 10, 1);
|
||||
p.WriteAttributeValue("", 6, "true", 6, 4, false);
|
||||
p.EndWriteAttribute();
|
||||
});
|
||||
var context = new Mock<IPageExecutionContext>(MockBehavior.Strict);
|
||||
var sequence = new MockSequence();
|
||||
|
|
@ -734,9 +726,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
// Arrange
|
||||
var page = CreatePage(p =>
|
||||
{
|
||||
p.WriteAttribute("href",
|
||||
new PositionTagged<string>("prefix", 0),
|
||||
new PositionTagged<string>("tail", 7));
|
||||
p.BeginWriteAttribute("href", "prefix", 0, "tail", 7, 0);
|
||||
p.EndWriteAttribute();
|
||||
});
|
||||
var context = new Mock<IPageExecutionContext>(MockBehavior.Strict);
|
||||
var sequence = new MockSequence();
|
||||
|
|
@ -758,72 +749,51 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
get
|
||||
{
|
||||
// attributeValues, expectedValue
|
||||
return new TheoryData<AttributeValue[], string>
|
||||
return new TheoryData<Tuple<string, int, object, int, bool>[], string>
|
||||
{
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(string.Empty, 9),
|
||||
new PositionTagged<object>("Hello", 9),
|
||||
literal: true)
|
||||
new []
|
||||
{
|
||||
Tuple.Create(string.Empty, 9, (object)"Hello", 9, true),
|
||||
},
|
||||
"Hello"
|
||||
},
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(" ", 9),
|
||||
new PositionTagged<object>("Hello", 10),
|
||||
literal: true)
|
||||
new []
|
||||
{
|
||||
Tuple.Create(" ", 9, (object)"Hello", 10, true)
|
||||
},
|
||||
" Hello"
|
||||
},
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(" ", 9),
|
||||
new PositionTagged<object>(null, 10),
|
||||
literal: false)
|
||||
|
||||
new []
|
||||
{
|
||||
Tuple.Create(" ", 9, (object)null, 10, false)
|
||||
},
|
||||
string.Empty
|
||||
},
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(" ", 9),
|
||||
new PositionTagged<object>(false, 10),
|
||||
literal: false)
|
||||
new []
|
||||
{
|
||||
Tuple.Create(" ", 9, (object)false, 10, false)
|
||||
},
|
||||
" HtmlEncode[[False]]"
|
||||
},
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(" ", 9),
|
||||
new PositionTagged<object>(true, 11),
|
||||
literal: false),
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(" ", 15),
|
||||
new PositionTagged<object>("abcd", 17),
|
||||
literal: true),
|
||||
new []
|
||||
{
|
||||
Tuple.Create(" ", 9, (object)true, 11, false),
|
||||
Tuple.Create(" ", 9, (object)"abcd", 17, true)
|
||||
},
|
||||
" HtmlEncode[[True]] abcd"
|
||||
},
|
||||
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(string.Empty, 9),
|
||||
new PositionTagged<object>("prefix", 9),
|
||||
literal: true),
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(" ", 15),
|
||||
new PositionTagged<object>(null, 17),
|
||||
literal: false),
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(" ", 21),
|
||||
new PositionTagged<object>("suffix", 22),
|
||||
literal: false),
|
||||
new []
|
||||
{
|
||||
Tuple.Create(string.Empty, 9, (object)"prefix", 9, true),
|
||||
Tuple.Create(" ", 15, (object)null, 17, false),
|
||||
Tuple.Create(" ", 21, (object)"suffix", 22, false),
|
||||
},
|
||||
"prefix HtmlEncode[[suffix]]"
|
||||
},
|
||||
|
|
@ -834,7 +804,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
[Theory]
|
||||
[MemberData(nameof(AddHtmlAttributeValues_ValueData))]
|
||||
public void AddHtmlAttributeValues_AddsToHtmlAttributesAsExpected(
|
||||
AttributeValue[] attributeValues,
|
||||
Tuple<string, int, object, int, bool>[] attributeValues,
|
||||
string expectedValue)
|
||||
{
|
||||
// Arrange
|
||||
|
|
@ -850,7 +820,12 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
|
||||
// Act
|
||||
page.AddHtmlAttributeValues("someattr", executionContext, attributeValues);
|
||||
page.BeginAddHtmlAttributeValues(executionContext, "someattr", attributeValues.Length);
|
||||
foreach (var value in attributeValues)
|
||||
{
|
||||
page.AddHtmlAttributeValue(value.Item1, value.Item2, value.Item3, value.Item4, 0, value.Item5);
|
||||
}
|
||||
page.EndAddHtmlAttributeValues(executionContext);
|
||||
|
||||
// Assert
|
||||
var htmlAttribute = Assert.Single(executionContext.HTMLAttributes);
|
||||
|
|
@ -885,13 +860,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
|
||||
// Act
|
||||
page.AddHtmlAttributeValues(
|
||||
"someattr",
|
||||
executionContext,
|
||||
new AttributeValue(
|
||||
prefix: new PositionTagged<string>(string.Empty, 9),
|
||||
value: new PositionTagged<object>(attributeValue, 9),
|
||||
literal: false));
|
||||
page.BeginAddHtmlAttributeValues(executionContext, "someattr", 1);
|
||||
page.AddHtmlAttributeValue(string.Empty, 9, attributeValue, 9, valueLength: 0, isLiteral: false);
|
||||
page.EndAddHtmlAttributeValues(executionContext);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(executionContext.HTMLAttributes);
|
||||
|
|
@ -917,13 +888,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
|
||||
// Act
|
||||
page.AddHtmlAttributeValues(
|
||||
"someattr",
|
||||
executionContext,
|
||||
new AttributeValue(
|
||||
prefix: new PositionTagged<string>(string.Empty, 9),
|
||||
value: new PositionTagged<object>(true, 9),
|
||||
literal: false));
|
||||
page.BeginAddHtmlAttributeValues(executionContext, "someattr", 1);
|
||||
page.AddHtmlAttributeValue(string.Empty, 9, true, 9, valueLength: 0, isLiteral: false);
|
||||
page.EndAddHtmlAttributeValues(executionContext);
|
||||
|
||||
// Assert
|
||||
var htmlAttribute = Assert.Single(executionContext.HTMLAttributes);
|
||||
|
|
@ -936,68 +903,53 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
Assert.False(allAttribute.Minimized);
|
||||
}
|
||||
|
||||
public static TheoryData<AttributeValue[], string> WriteAttributeData
|
||||
public static TheoryData WriteAttributeData
|
||||
{
|
||||
get
|
||||
{
|
||||
// AttributeValues, ExpectedOutput
|
||||
return new TheoryData<AttributeValue[], string>
|
||||
return new TheoryData<Tuple<string, int, object, int, bool>[], string>
|
||||
{
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(string.Empty, 9),
|
||||
new PositionTagged<object>(true, 9),
|
||||
literal: false)
|
||||
new[]
|
||||
{
|
||||
Tuple.Create(string.Empty, 9, (object)true, 9, false),
|
||||
},
|
||||
"someattr=HtmlEncode[[someattr]]"
|
||||
},
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(string.Empty, 9),
|
||||
new PositionTagged<object>(false, 9),
|
||||
literal: false)
|
||||
new[]
|
||||
{
|
||||
Tuple.Create(string.Empty, 9, (object)false, 9, false),
|
||||
},
|
||||
string.Empty
|
||||
},
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(string.Empty, 9),
|
||||
new PositionTagged<object>(null, 9),
|
||||
literal: false)
|
||||
new[]
|
||||
{
|
||||
Tuple.Create(string.Empty, 9, (object)null, 9, false),
|
||||
},
|
||||
string.Empty
|
||||
},
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(" ", 9),
|
||||
new PositionTagged<object>(false, 11),
|
||||
literal: false)
|
||||
new[]
|
||||
{
|
||||
Tuple.Create(" ", 9, (object)false, 11, false),
|
||||
},
|
||||
"someattr= HtmlEncode[[False]]"
|
||||
},
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(" ", 9),
|
||||
new PositionTagged<object>(null, 11),
|
||||
literal: false)
|
||||
new[]
|
||||
{
|
||||
Tuple.Create(" ", 9, (object)null, 11, false),
|
||||
},
|
||||
"someattr="
|
||||
},
|
||||
{
|
||||
new AttributeValue[] {
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(" ", 9),
|
||||
new PositionTagged<object>(true, 11),
|
||||
literal: false),
|
||||
new AttributeValue(
|
||||
new PositionTagged<string>(" ", 15),
|
||||
new PositionTagged<object>("abcd", 17),
|
||||
literal: true),
|
||||
new[]
|
||||
{
|
||||
Tuple.Create(" ", 9, (object)true, 11, false),
|
||||
Tuple.Create(" ", 15, (object)"abcd", 17, true),
|
||||
},
|
||||
"someattr= HtmlEncode[[True]] abcd"
|
||||
},
|
||||
|
|
@ -1007,17 +959,31 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
[Theory]
|
||||
[MemberData(nameof(WriteAttributeData))]
|
||||
public void WriteAttributeTo_WritesAsExpected(AttributeValue[] attributeValues, string expectedOutput)
|
||||
public void WriteAttributeTo_WritesAsExpected(
|
||||
Tuple<string, int, object, int, bool>[] attributeValues,
|
||||
string expectedOutput)
|
||||
{
|
||||
// Arrange
|
||||
var page = CreatePage(p => { });
|
||||
page.HtmlEncoder = new CommonTestEncoder();
|
||||
var writer = new StringWriter();
|
||||
var prefix = new PositionTagged<string>("someattr=", 0);
|
||||
var suffix = new PositionTagged<string>(string.Empty, 0);
|
||||
var prefix = "someattr=";
|
||||
var suffix = string.Empty;
|
||||
|
||||
// Act
|
||||
page.WriteAttributeTo(writer, "someattr", prefix, suffix, attributeValues);
|
||||
page.BeginWriteAttributeTo(writer, "someattr", prefix, 0, suffix, 0, attributeValues.Length);
|
||||
foreach (var value in attributeValues)
|
||||
{
|
||||
page.WriteAttributeValueTo(
|
||||
writer,
|
||||
value.Item1,
|
||||
value.Item2,
|
||||
value.Item3,
|
||||
value.Item4,
|
||||
value.Item3?.ToString().Length ?? 0,
|
||||
value.Item5);
|
||||
}
|
||||
page.EndWriteAttributeTo(writer);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedOutput, writer.ToString());
|
||||
|
|
|
|||
Loading…
Reference in New Issue