Replacing BufferedEntryCollection with BufferedHtmlContent so any IHtmlContent can be added to a TagHelperContent.

- Introducing a new logic to calculate IsEmpty/IsWhitespace.
- Making Buffer private in DefaultTagHelperContent.
- Making SetContent non-abstract.
This commit is contained in:
sornaks 2015-07-29 16:16:49 -07:00
parent 4604c807c4
commit 168fcbb9c1
4 changed files with 152 additions and 123 deletions

View File

@ -2,8 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.AspNet.Html.Abstractions;
using Microsoft.Framework.Internal;
using Microsoft.Framework.WebEncoders;
@ -14,35 +15,60 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// </summary>
public class DefaultTagHelperContent : TagHelperContent
{
private readonly BufferEntryCollection _buffer;
private BufferedHtmlContent _buffer;
/// <summary>
/// Instantiates a new instance of <see cref="DefaultTagHelperContent"/>.
/// </summary>
public DefaultTagHelperContent()
{
_buffer = new BufferEntryCollection();
}
/// <inheritdoc />
public override bool IsModified
private BufferedHtmlContent Buffer
{
get
{
return _buffer.IsModified;
if (_buffer == null)
{
_buffer = new BufferedHtmlContent();
}
return _buffer;
}
}
/// <inheritdoc />
public override bool IsModified => _buffer != null;
/// <inheritdoc />
/// <remarks>Returns <c>true</c> for a cleared <see cref="TagHelperContent"/>.</remarks>
public override bool IsWhiteSpace
{
get
{
foreach (var value in _buffer)
if (_buffer == null)
{
if (!string.IsNullOrWhiteSpace(value))
return true;
}
using (var writer = new EmptyOrWhiteSpaceWriter())
{
foreach (var entry in _buffer.Entries)
{
return false;
if (entry == null)
{
continue;
}
var stringValue = entry as string;
if (stringValue != null)
{
if (!string.IsNullOrWhiteSpace(stringValue))
{
return false;
}
}
else
{
((IHtmlContent)entry).WriteTo(writer, HtmlEncoder.Default);
if (!writer.IsWhiteSpace)
{
return false;
}
}
}
}
@ -55,11 +81,36 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
get
{
foreach (var value in _buffer)
if (_buffer == null)
{
if (!string.IsNullOrEmpty(value))
return true;
}
using (var writer = new EmptyOrWhiteSpaceWriter())
{
foreach (var entry in _buffer.Entries)
{
return false;
if (entry == null)
{
continue;
}
var stringValue = entry as string;
if (stringValue != null)
{
if (!string.IsNullOrEmpty(stringValue))
{
return false;
}
}
else
{
((IHtmlContent)entry).WriteTo(writer, HtmlEncoder.Default);
if (!writer.IsEmpty)
{
return false;
}
}
}
}
@ -67,55 +118,38 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}
}
/// <inheritdoc />
public override TagHelperContent SetContent(string value)
{
Clear();
Append(value);
return this;
}
/// <inheritdoc />
public override TagHelperContent SetContent(TagHelperContent tagHelperContent)
{
Clear();
Append(tagHelperContent);
return this;
}
/// <inheritdoc />
public override TagHelperContent Append(string value)
{
_buffer.Add(value);
Buffer.Append(value);
return this;
}
/// <inheritdoc />
public override TagHelperContent AppendFormat([NotNull] string format, object arg0)
{
_buffer.Add(string.Format(format, arg0));
Buffer.Append(string.Format(format, arg0));
return this;
}
/// <inheritdoc />
public override TagHelperContent AppendFormat([NotNull] string format, object arg0, object arg1)
{
_buffer.Add(string.Format(format, arg0, arg1));
Buffer.Append(string.Format(format, arg0, arg1));
return this;
}
/// <inheritdoc />
public override TagHelperContent AppendFormat([NotNull] string format, object arg0, object arg1, object arg2)
{
_buffer.Add(string.Format(format, arg0, arg1, arg2));
Buffer.Append(string.Format(format, arg0, arg1, arg2));
return this;
}
/// <inheritdoc />
public override TagHelperContent AppendFormat([NotNull] string format, params object[] args)
{
_buffer.Add(string.Format(format, args));
Buffer.Append(string.Format(format, args));
return this;
}
@ -125,7 +159,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
[NotNull] string format,
object arg0)
{
_buffer.Add(string.Format(provider, format, arg0));
Buffer.Append(string.Format(provider, format, arg0));
return this;
}
@ -136,7 +170,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
object arg0,
object arg1)
{
_buffer.Add(string.Format(provider, format, arg0, arg1));
Buffer.Append(string.Format(provider, format, arg0, arg1));
return this;
}
@ -148,7 +182,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
object arg1,
object arg2)
{
_buffer.Add(string.Format(provider, format, arg0, arg1, arg2));
Buffer.Append(string.Format(provider, format, arg0, arg1, arg2));
return this;
}
@ -158,43 +192,43 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
[NotNull] string format,
params object[] args)
{
_buffer.Add(string.Format(provider, format, args));
Buffer.Append(string.Format(provider, format, args));
return this;
}
/// <inheritdoc />
public override TagHelperContent Append(TagHelperContent tagHelperContent)
public override TagHelperContent Append(IHtmlContent htmlContent)
{
if (tagHelperContent != null)
{
foreach (var value in tagHelperContent)
{
Append(value);
}
}
// If Append() was called with an empty TagHelperContent IsModified should
// still be true. If the content was not already modified, it means it is empty.
// So the Clear() method can be used to indirectly set the IsModified.
if (!IsModified)
{
Clear();
}
Buffer.Append(htmlContent);
return this;
}
/// <inheritdoc />
public override TagHelperContent Clear()
{
_buffer.Clear();
Buffer.Clear();
return this;
}
/// <inheritdoc />
public override string GetContent()
{
return string.Join(string.Empty, _buffer);
if (_buffer == null)
{
return string.Empty;
}
using (var writer = new StringWriter())
{
WriteTo(writer, HtmlEncoder.Default);
return writer.ToString();
}
}
/// <inheritdoc />
public override void WriteTo([NotNull] TextWriter writer, [NotNull] IHtmlEncoder encoder)
{
Buffer.WriteTo(writer, encoder);
}
/// <inheritdoc />
@ -203,20 +237,40 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return GetContent();
}
/// <inheritdoc />
public override IEnumerator<string> GetEnumerator()
// Overrides Write(string) to find if the content written is empty/whitespace.
private class EmptyOrWhiteSpaceWriter : TextWriter
{
// The enumerator is exposed so that SetContent(TagHelperContent) and Append(TagHelperContent)
// can use this to iterate through the values of the buffer.
return _buffer.GetEnumerator();
}
/// <inheritdoc />
public override void WriteTo(TextWriter writer, IHtmlEncoder encoder)
{
foreach (var entry in _buffer)
public override Encoding Encoding
{
writer.Write(entry);
get
{
throw new NotImplementedException();
}
}
public bool IsEmpty { get; private set; } = true;
public bool IsWhiteSpace { get; private set; } = true;
#if DNXCORE50
// This is an abstract method in DNXCore
public override void Write(char value)
{
throw new NotImplementedException();
}
#endif
public override void Write(string value)
{
if (IsEmpty && !string.IsNullOrEmpty(value))
{
IsEmpty = false;
}
if (IsWhiteSpace && !string.IsNullOrWhiteSpace(value))
{
IsWhiteSpace = false;
}
}
}
}

View File

@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNet.Html.Abstractions;
using Microsoft.Framework.WebEncoders;
@ -13,7 +11,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// <summary>
/// Abstract class used to buffer content returned by <see cref="ITagHelper"/>s.
/// </summary>
public abstract class TagHelperContent : IEnumerable<string>, IHtmlContent
public abstract class TagHelperContent : IHtmlContent
{
/// <summary>
/// Gets a value indicating whether the content was modifed.
@ -35,14 +33,24 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// </summary>
/// <param name="value">The <see cref="string"/> that replaces the content.</param>
/// <returns>A reference to this instance after the set operation has completed.</returns>
public abstract TagHelperContent SetContent(string value);
public TagHelperContent SetContent(string value)
{
Clear();
Append(value);
return this;
}
/// <summary>
/// Sets the content.
/// </summary>
/// <param name="tagHelperContent">The <see cref="TagHelperContent"/> that replaces the content.</param>
/// <param name="htmlContent">The <see cref="IHtmlContent"/> that replaces the content.</param>
/// <returns>A reference to this instance after the set operation has completed.</returns>
public abstract TagHelperContent SetContent(TagHelperContent tagHelperContent);
public TagHelperContent SetContent(IHtmlContent htmlContent)
{
Clear();
Append(htmlContent);
return this;
}
/// <summary>
/// Appends <paramref name="value"/> to the existing content.
@ -168,11 +176,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
public abstract TagHelperContent AppendFormat(IFormatProvider provider, string format, params object[] args);
/// <summary>
/// Appends <paramref name="tagHelperContent"/> to the existing content.
/// Appends <paramref name="htmlContent"/> to the existing content.
/// </summary>
/// <param name="tagHelperContent">The <see cref="TagHelperContent"/> to be appended.</param>
/// <param name="htmlContent">The <see cref="IHtmlContent"/> to be appended.</param>
/// <returns>A reference to this instance after the append operation has completed.</returns>
public abstract TagHelperContent Append(TagHelperContent tagHelperContent);
public abstract TagHelperContent Append(IHtmlContent htmlContent);
/// <summary>
/// Clears the content.
@ -186,15 +194,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// <returns>A <see cref="string"/> containing the content.</returns>
public abstract string GetContent();
/// <inheritdoc />
public abstract IEnumerator<string> GetEnumerator();
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <inheritdoc />
public abstract void WriteTo(TextWriter writer, IHtmlEncoder encoder);
}

View File

@ -8,7 +8,7 @@
"dependencies": {
"Microsoft.AspNet.Html.Abstractions": "1.0.0-*",
"Microsoft.AspNet.Razor": "4.0.0-*",
"Microsoft.Framework.BufferEntryCollection.Sources": {
"Microsoft.Framework.BufferedHtmlContent.Sources": {
"type": "build",
"version": "1.0.0-*"
},

View File

@ -301,7 +301,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Assert
Assert.Equal(expected, copiedTagHelperContent.GetContent());
Assert.Equal(new[] { text1, text2 }, copiedTagHelperContent.ToArray());
}
[Fact]
@ -526,23 +525,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Equal(expected, actual, StringComparer.Ordinal);
}
[Fact]
public void GetEnumerator_EnumeratesThroughBuffer()
{
// Arrange
var tagHelperContent = new DefaultTagHelperContent();
var expected = new string[] { "Hello", "World" };
tagHelperContent.SetContent(expected[0]);
tagHelperContent.Append(expected[1]);
var i = 0;
// Act & Assert
foreach (var val in tagHelperContent)
{
Assert.Equal(expected[i++], val);
}
}
[Fact]
public void Fluent_SetContent_Append_WritesExpectedContent()
{
@ -562,17 +544,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
// Arrange
var tagHelperContent = new DefaultTagHelperContent();
var expected = new[] { "First ", "Second Third" };
var expected = "First Second Third";
var i = 0;
// Act
tagHelperContent.SetContent("First ").AppendFormat("{0} Third", "Second");
// Assert
foreach (var value in tagHelperContent)
{
Assert.Equal(expected[i++], value);
}
Assert.Equal(expected, tagHelperContent.GetContent());
}
[Fact]
@ -580,7 +559,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
// Arrange
var tagHelperContent = new DefaultTagHelperContent();
var expected = new[] { "First ", "Second Third ", "Fourth" };
var expected = "First Second Third Fourth";
var i = 0;
// Act
@ -590,10 +569,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
.Append("Fourth");
// Assert
foreach (var value in tagHelperContent)
{
Assert.Equal(expected[i++], value);
}
Assert.Equal(expected, tagHelperContent.GetContent());
}
[Fact]