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.
|
// 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.
|
// 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
|
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contract used to filter matching HTML elements.
|
||||||
|
/// </summary>
|
||||||
public interface ITagHelper
|
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