Add TagHelperRunner for TagHelper runtime.
- This involved adding the following core classes: TagHelper, TagHelperExecutionContext, TagHelperOutput, TagHelperContext. All of which aid in running TagHelpers. #154
This commit is contained in:
parent
dfe41eced8
commit
4378f9613e
|
|
@ -1,12 +1,22 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Contract used to filter matching HTML elements.
|
||||
/// </summary>
|
||||
public interface ITagHelper
|
||||
{
|
||||
// TODO: Will be implemented in https://github.com/aspnet/razor/issues/154
|
||||
/// <summary>
|
||||
/// Asynchronously executes the <see cref="ITagHelper"/> with the given <paramref name="context"/> and
|
||||
/// <paramref name="output"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains information associated with the current HTML tag.</param>
|
||||
/// <param name="output">A stateful HTML element used to generate an HTML tag.</param>
|
||||
/// <returns>A <see cref="Task"/> that on completion updates the <paramref name="output"/>.</returns>
|
||||
Task ProcessAsync(TagHelperContext context, TagHelperOutput output);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Class used to filter matching HTML elements.
|
||||
/// </summary>
|
||||
public abstract class TagHelper : ITagHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Synchronously executes the <see cref="TagHelper"/> with the given <paramref name="context"/> and
|
||||
/// <paramref name="output"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains information associated with the current HTML tag.</param>
|
||||
/// <param name="output">A stateful HTML element used to generate an HTML tag.</param>
|
||||
public virtual void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously executes the <see cref="TagHelper"/> with the given <paramref name="context"/> and
|
||||
/// <paramref name="output"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains information associated with the current HTML tag.</param>
|
||||
/// <param name="output">A stateful HTML element used to generate an HTML tag.</param>
|
||||
/// <returns>A <see cref="Task"/> that on completion updates the <paramref name="output"/>.</returns>
|
||||
/// <remarks>By default this calls into <see cref="Process"/>.</remarks>.
|
||||
#pragma warning disable 1998
|
||||
public virtual async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
Process(context, output);
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains information related to the execution of <see cref="ITagHelper"/>s.
|
||||
/// </summary>
|
||||
public class TagHelperContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="TagHelperContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="allAttributes">Every attribute associated with the current HTML element.</param>
|
||||
public TagHelperContext([NotNull] IDictionary<string, object> allAttributes)
|
||||
{
|
||||
AllAttributes = allAttributes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Every attribute associated with the current HTML element.
|
||||
/// </summary>
|
||||
public IDictionary<string, object> AllAttributes { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Class used to represent the output of an <see cref="ITagHelper"/>.
|
||||
/// </summary>
|
||||
public class TagHelperOutput
|
||||
{
|
||||
private string _content;
|
||||
private string _tagName;
|
||||
|
||||
// Internal for testing
|
||||
internal TagHelperOutput(string tagName)
|
||||
{
|
||||
TagName = tagName;
|
||||
Attributes = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
// Internal for testing
|
||||
internal TagHelperOutput(string tagName, [NotNull] IDictionary<string, string> attributes)
|
||||
: this(tagName, attributes, string.Empty)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new instance of <see cref="TagHelperOutput"/>.
|
||||
/// </summary>
|
||||
/// <param name="tagName">The HTML element's tag name.</param>
|
||||
/// <param name="attributes">The HTML attributes.</param>
|
||||
/// <param name="content">The HTML element's content.</param>
|
||||
public TagHelperOutput(string tagName,
|
||||
[NotNull] IDictionary<string, string> attributes,
|
||||
string content)
|
||||
{
|
||||
TagName = tagName;
|
||||
Content = content;
|
||||
Attributes = new Dictionary<string, string>(attributes, StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The HTML element's tag name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A whitespace value results in no start or end tag being rendered.
|
||||
/// </remarks>
|
||||
public string TagName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _tagName;
|
||||
}
|
||||
set
|
||||
{
|
||||
_tagName = value ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The HTML element's content.
|
||||
/// </summary>
|
||||
public string Content
|
||||
{
|
||||
get
|
||||
{
|
||||
return _content;
|
||||
}
|
||||
set
|
||||
{
|
||||
_content = value ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether or not the tag is self closing.
|
||||
/// </summary>
|
||||
public bool SelfClosing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The HTML element's attributes.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> Attributes { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Generates the <see cref="TagHelperOutput"/>'s start tag.
|
||||
/// </summary>
|
||||
/// <returns><c>string.Empty</c> if <see cref="TagName"/> is <c>string.Empty</c> or whitespace. Otherwise, the
|
||||
/// <see cref="string"/> representation of the <see cref="TagHelperOutput"/>'s start tag.</returns>
|
||||
public string GenerateStartTag()
|
||||
{
|
||||
// Only render a start tag if the tag name is not whitespace
|
||||
if (string.IsNullOrWhiteSpace(TagName))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append('<')
|
||||
.Append(TagName);
|
||||
|
||||
foreach (var attribute in Attributes)
|
||||
{
|
||||
var value = WebUtility.HtmlEncode(attribute.Value);
|
||||
sb.Append(' ')
|
||||
.Append(attribute.Key)
|
||||
.Append("=\"")
|
||||
.Append(value)
|
||||
.Append('"');
|
||||
}
|
||||
|
||||
if (SelfClosing)
|
||||
{
|
||||
sb.Append(" /");
|
||||
}
|
||||
|
||||
sb.Append('>');
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the <see cref="TagHelperOutput"/>'s body.
|
||||
/// </summary>
|
||||
/// <returns><c>string.Empty</c> if <see cref="SelfClosing"/> is <c>true</c>. <see cref="Output"/> otherwise.
|
||||
/// </returns>
|
||||
public string GenerateContent()
|
||||
{
|
||||
if (SelfClosing)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return Content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the <see cref="TagHelperOutput"/>'s end tag.
|
||||
/// </summary>
|
||||
/// <returns><c>string.Empty</c> if <see cref="TagName"/> is <c>string.Empty</c> or whitespace. Otherwise, the
|
||||
/// <see cref="string"/> representation of the <see cref="TagHelperOutput"/>'s end tag.</returns>
|
||||
public string GenerateEndTag()
|
||||
{
|
||||
if (SelfClosing || string.IsNullOrWhiteSpace(TagName))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return string.Format(CultureInfo.InvariantCulture, "</{0}>", TagName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// A class used to run <see cref="ITagHelper"/>s.
|
||||
/// </summary>
|
||||
public class TagHelperRunner
|
||||
{
|
||||
/// <summary>
|
||||
/// Calls the <see cref="ITagHelper.ProcessAsync"/> method on <see cref="ITagHelper"/>s.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains information associated with running <see cref="ITagHelper"/>s.</param>
|
||||
/// <returns>Resulting <see cref="TagHelperOutput"/> from processing all of the
|
||||
/// <paramref name="context"/>'s <see cref="ITagHelper"/>s.</returns>
|
||||
public async Task<TagHelperOutput> RunAsync([NotNull] TagHelpersExecutionContext context)
|
||||
{
|
||||
return await RunAsyncCore(context, string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls the <see cref="ITagHelper.ProcessAsync"/> method on <see cref="ITagHelper"/>s.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains information associated with running <see cref="ITagHelper"/>s.</param>
|
||||
/// <param name="bufferedBody">Contains the buffered content of the current HTML tag.</param>
|
||||
/// <returns>Resulting <see cref="TagHelperOutput"/> from processing all of the
|
||||
/// <paramref name="context"/>'s <see cref="ITagHelper"/>s.</returns>
|
||||
public async Task<TagHelperOutput> RunAsync([NotNull] TagHelpersExecutionContext context,
|
||||
[NotNull] TextWriter bufferedBody)
|
||||
{
|
||||
return await RunAsyncCore(context, bufferedBody.ToString());
|
||||
}
|
||||
|
||||
private async Task<TagHelperOutput> RunAsyncCore(TagHelpersExecutionContext executionContext, string outputContent)
|
||||
{
|
||||
var tagHelperContext = new TagHelperContext(executionContext.AllAttributes);
|
||||
var tagHelperOutput = new TagHelperOutput(executionContext.TagName,
|
||||
executionContext.HTMLAttributes,
|
||||
outputContent);
|
||||
|
||||
foreach (var tagHelper in executionContext.TagHelpers)
|
||||
{
|
||||
await tagHelper.ProcessAsync(tagHelperContext, tagHelperOutput);
|
||||
}
|
||||
|
||||
return tagHelperOutput;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Class used to store information about a <see cref="ITagHelper"/>'s execution lifetime.
|
||||
/// </summary>
|
||||
public class TagHelpersExecutionContext
|
||||
{
|
||||
private readonly List<ITagHelper> _tagHelpers;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new <see cref="TagHelpersExecutionContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="tagName">The HTML tag name in the Razor source.</param>
|
||||
public TagHelpersExecutionContext([NotNull] string tagName)
|
||||
{
|
||||
AllAttributes = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
HTMLAttributes = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
_tagHelpers = new List<ITagHelper>();
|
||||
TagName = tagName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTML attributes.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> HTMLAttributes { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="ITagHelper"/> bound attributes and HTML attributes.
|
||||
/// </summary>
|
||||
public IDictionary<string, object> AllAttributes { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="ITagHelper"/>s that should be run.
|
||||
/// </summary>
|
||||
public IEnumerable<ITagHelper> TagHelpers
|
||||
{
|
||||
get
|
||||
{
|
||||
return _tagHelpers;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The HTML tag name in the Razor source.
|
||||
/// </summary>
|
||||
public string TagName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ITagHelper">s' output.
|
||||
/// </summary>
|
||||
public TagHelperOutput Output { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the given <paramref name="tagHelper"/>.
|
||||
/// </summary>
|
||||
/// <param name="tagHelper">The tag helper to track.</param>
|
||||
public void Add([NotNull] ITagHelper tagHelper)
|
||||
{
|
||||
_tagHelpers.Add(tagHelper);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the HTML attribute in <see cref="AllAttributes"/> and <see cref="HTMLAttributes"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The HTML attribute name.</param>
|
||||
/// <param name="value">The HTML attribute value.</param>
|
||||
public void AddHtmlAttribute([NotNull] string name, string value)
|
||||
{
|
||||
HTMLAttributes.Add(name, value);
|
||||
AllAttributes.Add(name, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the <see cref="ITagHelper"/> bound attribute in <see cref="AllAttributes"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The bound attribute name.</param>
|
||||
/// <param name="value">The attribute value.</param>
|
||||
public void AddTagHelperAttribute([NotNull] string name, object value)
|
||||
{
|
||||
AllAttributes.Add(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue