Reintroduce WriteAttribute methods on RazorView type
This commit is contained in:
parent
f1183f57af
commit
9915b1c767
|
|
@ -3,6 +3,7 @@
|
||||||
@{
|
@{
|
||||||
Layout = "/Views/Shared/_Layout.cshtml";
|
Layout = "/Views/Shared/_Layout.cshtml";
|
||||||
ViewBag.Title = "Home Page";
|
ViewBag.Title = "Home Page";
|
||||||
|
string nullValue = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="jumbotron">
|
<div class="jumbotron">
|
||||||
|
|
@ -11,7 +12,8 @@
|
||||||
<p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more »</a></p>
|
<p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more »</a></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h3>Hello @Model.Name!</h3>
|
<h3 title="@Model.Name" class="@nullValue">Hello @Model.Name!</h3>
|
||||||
|
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<h2>Getting started</h2>
|
<h2>Getting started</h2>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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()
|
protected virtual HtmlString RenderBody()
|
||||||
{
|
{
|
||||||
if (BodyContent == null)
|
if (BodyContent == null)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue