Skip to content
This repository was archived by the owner on Dec 19, 2018. It is now read-only.

Commit

Permalink
Add TagHelperRunner for TagHelper runtime.
Browse files Browse the repository at this point in the history
- This involved adding the following core classes: TagHelper, TagHelperExecutionContext, TagHelperOutput, TagHelperContext.  All of which aid in running TagHelpers.

#154
  • Loading branch information
NTaylorMullen committed Oct 2, 2014
1 parent 2f878d0 commit b5be7e6
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 2 deletions.
35 changes: 35 additions & 0 deletions src/Microsoft.AspNet.Razor.Runtime/TagHelpers/ITagHelperRunner.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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>
/// Defines a contract that is used to run <see cref="TagHelper"/>s.
/// </summary>
public interface ITagHelperRunner
{
/// <summary>
/// Calls the <see cref="TagHelper.ProcessAsync(TagHelperOutput, TagHelperContext)"/> method on
/// <see cref="TagHelper"/>s.
/// </summary>
/// <param name="context">Contains information associated with running <see cref="TagHelper"/>s</param>
/// <returns>A the resulting <see cref="TagHelperOutput"/> from processing all of the
/// <paramref name="context"/>s <see cref="TagHelper"/>s.</returns>
Task<TagHelperOutput> RunAsync(TagHelpersExecutionContext context);

/// <summary>
/// Calls the <see cref="TagHelper.ProcessAsync(TagHelperOutput, TagHelperContext)"/> method on
/// <see cref="TagHelper"/>s with a <see cref="TagHelperOutput"/> whos <see cref="TagHelperOutput.Content"/>
/// is set to the given <paramref name="bufferBody"/> <see cref="string"/> value.
/// </summary>
/// <param name="context">Contains information associated with running <see cref="TagHelper"/>s</param>
/// <param name="bufferedBody">Contains the buffered content of the current HTML tag that is associated
/// with the current set of <see cref="TagHelper"/>s provided by the <paramref name="context"/>.</param>
/// <returns>A the resulting <see cref="TagHelperOutput"/> from processing all of the
/// <paramref name="context"/>s <see cref="TagHelper"/>s.</returns>
Task<TagHelperOutput> RunAsync(TagHelpersExecutionContext context, TextWriter bufferedBody);
}
}
30 changes: 28 additions & 2 deletions src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelper.cs
Original file line number Diff line number Diff line change
@@ -1,12 +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;
using System.Threading.Tasks;

namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
/// <summary>
/// Defines a class that is used to control rendering of HTML elements.
/// </summary>
public abstract class TagHelper
{
// TODO: Will be implemented in https://github.com/aspnet/razor/issues/154
/// <summary>
/// Synchronously executes the <see cref="TagHelper"/> with the given <paramref name="output"/> and
/// <paramref name="context"/>.
/// </summary>
/// <param name="output">The stateful HTML element used to represent a tag.</param>
/// <param name="context">Contains information associated with the current HTML tags execution.</param>
public virtual void Process(TagHelperOutput output, TagHelperContext context)
{
}

/// <summary>
/// Synchronously executes the <see cref="TagHelper"/> with the given <paramref name="output"/> and
/// <paramref name="context"/>.
/// </summary>
/// <param name="output">The stateful HTML element used to represent a tag</param>
/// <param name="context">Contains information associated with the current HTML tags execution.</param>
/// <returns>A task that represents when the method has completed.</returns>
/// <remarks>By default this calls into <see cref="Process(TagHelperOutput, TagHelperContext)"/>.</remarks>.
public virtual Task ProcessAsync(TagHelperOutput output, TagHelperContext context)
{
Process(output, context);

return Task.FromResult(result: true);
}
}
}
28 changes: 28 additions & 0 deletions src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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="TagHelper"/>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(Dictionary<string, object> allAttributes)
{
// We don't want to use the existing attribute list, must not affect other tag helpers.
AllAttributes = new Dictionary<string, object>(allAttributes);
}

/// <summary>
/// Every attribute associated with the current HTML element.
/// </summary>
public Dictionary<string, object> AllAttributes { get; private set; }
}
}
146 changes: 146 additions & 0 deletions src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperOutput.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// 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;
using System.IO;
using System.Net;
using System.Text;

namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
/// <summary>
/// Defines a class used to represent the output of a tag helper.
/// </summary>
public class TagHelperOutput
{
private string _content;
private string _tagName;

// Internal for testing
internal TagHelperOutput(string tagName)
: this(tagName, attributes: new Dictionary<string, string>())
{
}

/// <summary>
/// Instantiates a new instance of <see cref="TagHelperOutput"/>.
/// </summary>
/// <param name="tagName">The HTML elements tag name.</param>
/// <param name="attributes">The HTML attributes.</param>
public TagHelperOutput(string tagName, Dictionary<string, string> attributes)
{
TagName = tagName;
Content = string.Empty;
Attributes = new Dictionary<string, string>(attributes);
}

/// <summary>
/// The HTML elements tag name.
/// </summary>
public string TagName
{
get
{
return _tagName;
}
set
{
_tagName = value ?? string.Empty;
}
}

/// <summary>
/// The HTML elements 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 elements attributes.
/// </summary>
public Dictionary<string, string> Attributes { get; private set; }

/// <summary>
/// Generates the <see cref="TagHelperOutput"/>'s start tag.
/// </summary>
/// <returns>The string representation of the <see cref="TagHelperOutput"/>s start tag.</returns>
public string GenerateTagStart()
{
var sb = new StringBuilder();

// Only render a start tag if the tag name is not whitespace
if (!string.IsNullOrWhiteSpace(TagName))
{
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>The string representation of the <see cref="TagHelperOutput"/>s Inner HTML.</returns>
public string GenerateTagContent()
{
if (SelfClosing)
{
return string.Empty;
}

return Content;
}

/// <summary>
/// Generates the <see cref="TagHelperOutput"/>'s end tag.
/// </summary>
/// <returns>The string representation of the <see cref="TagHelperOutput"/>s end tag.</returns>
public string GenerateTagEnd()
{
if (SelfClosing && !string.IsNullOrWhiteSpace(TagName))
{
return string.Empty;
}

var sb = new StringBuilder();

sb.Append("</")
.Append(TagName)
.Append('>');

return sb.ToString();
}
}
}
42 changes: 42 additions & 0 deletions src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperRunner.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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="TagHelper"/>s during runtime.
/// </summary>
public class TagHelperRunner : ITagHelperRunner
{
/// <inheritdoc />
public async Task<TagHelperOutput> RunAsync(TagHelpersExecutionContext context)
{
return await RunAsyncCore(context, string.Empty);
}

/// <inheritdoc />
public async Task<TagHelperOutput> RunAsync(TagHelpersExecutionContext context, 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)
{
Content = outputContent
};

foreach (var tagHelper in executionContext.TagHelpers)
{
await tagHelper.ProcessAsync(tagHelperOutput, tagHelperContext);
}

return tagHelperOutput;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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>
/// Defines a class that is used to store information about a <see cref="TagHelper"/>s execution lifetime.
/// </summary>
public class TagHelpersExecutionContext
{
/// <summary>
/// Instantiates a new <see cref="TagHelpersExecutionContext"/>.
/// </summary>
/// <param name="tagName">The HTML tag name associated with the current <see cref="TagHelpersExecutionContext"/>.</param>
public TagHelpersExecutionContext(string tagName)
{
AllAttributes = new Dictionary<string, object>(StringComparer.Ordinal);
HTMLAttributes = new Dictionary<string, string>(StringComparer.Ordinal);
TagHelpers = new List<TagHelper>();
TagName = tagName;
}

/// <summary>
/// HTML attributes for the current execution context.
/// </summary>
public Dictionary<string, string> HTMLAttributes { get; private set; }

/// <summary>
/// <see cref="TagHelper"/> bound attributes and HTML attributes.
/// </summary>
public Dictionary<string, object> AllAttributes { get; private set; }

/// <summary>
/// <see cref="TagHelper"/>s that should be run for the current <see cref="TagHelpersExecutionContext"/>.
/// </summary>
public List<TagHelper> TagHelpers { get; private set; }

/// <summary>
/// The HTML tag name for the current <see cref="TagHelpersExecutionContext"/>.
/// </summary>
public string TagName { get; private set; }

/// <summary>
/// The <see cref="TagHelperOutput"/> of the current <see cref="TagHelpersExecutionContext"/>.
/// </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(TagHelper tagHelper)
{
TagHelpers.Add(tagHelper);
}

/// <summary>
/// Tracks the HTML attribute.
/// </summary>
/// <param name="name">The HTML attribute name.</param>
/// <param name="value">The HTML attribute value.</param>
public void AddHtmlAttribute(string name, string value)
{
HTMLAttributes.Add(name, value);
AllAttributes.Add(name, value);
}

/// <summary>
/// Tracks the HTML attribute so it can be used by a <see cref="TagHelperContext.AllAttributes"/>.
/// </summary>
/// <param name="name">The HTML attribute name.</param>
/// <param name="value">The attribute value.</param>
public void AddTagHelperAttribute(string name, object value)
{
AllAttributes.Add(name, value);
}
}
}

0 comments on commit b5be7e6

Please sign in to comment.