Reintroduce WriteAttribute methods on RazorView type

This commit is contained in:
Pranav K 2014-02-24 19:55:48 -08:00
parent f1183f57af
commit 9915b1c767
4 changed files with 180 additions and 1 deletions

View File

@ -3,6 +3,7 @@
@{
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Home Page";
string nullValue = null;
}
<div class="jumbotron">
@ -11,7 +12,8 @@
<p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more &raquo;</a></p>
</div>
<div class="row">
<h3>Hello @Model.Name!</h3>
<h3 title="@Model.Name" class="@nullValue">Hello @Model.Name!</h3>
<div class="col-md-4">
<h2>Getting started</h2>
<p>

View File

@ -0,0 +1,45 @@
using System;
using System.Diagnostics.CodeAnalysis;
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; }
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "We are using tuples here to avoid dependencies from Razor to WebPages")]
public static AttributeValue FromTuple(Tuple<Tuple<string, int>, Tuple<object, int>, bool> value)
{
return new AttributeValue(value.Item1, value.Item2, value.Item3);
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "We are using tuples here to avoid dependencies from Razor to WebPages")]
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);
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "We are using tuples here to avoid dependencies from Razor to WebPages")]
public static implicit operator AttributeValue(Tuple<Tuple<string, int>, Tuple<object, int>, bool> value)
{
return FromTuple(value);
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "We are using tuples here to avoid dependencies from Razor to WebPages")]
public static implicit operator AttributeValue(Tuple<Tuple<string, int>, Tuple<string, int>, bool> value)
{
return FromTuple(value);
}
}
}

View File

@ -0,0 +1,34 @@
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);
}
}
}

View File

@ -92,6 +92,104 @@ namespace Microsoft.AspNet.Mvc.Razor
}
}
public virtual void WriteAttribute(string name,
PositionTagged<string> prefix,
PositionTagged<string> suffix,
params AttributeValue[] values)
{
WriteAttributeTo(Output, name, prefix, suffix, values);
}
public virtual void WriteAttributeTo(TextWriter writer,
string name,
PositionTagged<string> prefix,
PositionTagged<string> suffix,
params AttributeValue[] values)
{
bool first = true;
bool wroteSomething = false;
if (values.Length == 0)
{
// Explicitly empty attribute, so write the prefix and suffix
WritePositionTaggedLiteral(writer, prefix);
WritePositionTaggedLiteral(writer, suffix);
}
else
{
for (int i = 0; i < values.Length; i++)
{
AttributeValue attrVal = values[i];
PositionTagged<object> val = attrVal.Value;
PositionTagged<string> 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
if (val.Value == null)
{
// Nothing to write
continue;
}
// The special cases here are that the value we're writing might already be a string, or that the
// value might be a bool. If the value is the bool 'true' we want to write the attribute name instead
// of the string 'true'. If the value is the bool 'false' we don't want to write anything.
//
// Otherwise the value is another object (perhaps an IHtmlString), and we'll ask it to format itself.
string stringValue;
bool? boolValue = val.Value as bool?;
if (boolValue == true)
{
stringValue = name;
}
else if (boolValue == false)
{
continue;
}
else
{
stringValue = val.Value as string;
}
if (first)
{
WritePositionTaggedLiteral(writer, prefix);
first = false;
}
else
{
WritePositionTaggedLiteral(writer, attrVal.Prefix);
}
// Calculate length of the source span by the position of the next value (or suffix)
int sourceLength = next.Position - attrVal.Value.Position;
if (attrVal.Literal)
{
WriteLiteralTo(writer, stringValue ?? val.Value);
}
else
{
WriteTo(writer, stringValue ?? val.Value); // Write value
}
wroteSomething = true;
}
if (wroteSomething)
{
WritePositionTaggedLiteral(writer, suffix);
}
}
}
private void WritePositionTaggedLiteral(TextWriter writer, string value, int position)
{
WriteLiteralTo(writer, value);
}
private void WritePositionTaggedLiteral(TextWriter writer, PositionTagged<string> value)
{
WritePositionTaggedLiteral(writer, value.Value, value.Position);
}
protected virtual HtmlString RenderBody()
{
if (BodyContent == null)