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

Commit b7a38c3

Browse files
author
N. Taylor Mullen
committed
Add extensions for TagHelperOutput to copy and merge from TagBuilder.
- Added tests to validate functionality of all TagHelperOutputExtension methods. #1319
1 parent 4208c8f commit b7a38c3

File tree

2 files changed

+401
-0
lines changed

2 files changed

+401
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using Microsoft.AspNet.Mvc.Rendering;
8+
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
9+
10+
namespace Microsoft.AspNet.Mvc.TagHelpers
11+
{
12+
/// <summary>
13+
/// Utility related extensions for <see cref="TagHelperOutput"/>.
14+
/// </summary>
15+
public static class TagHelperOutputExtensions
16+
{
17+
/// <summary>
18+
/// Copies a user-provided attribute from <paramref name="context"/>'s
19+
/// <see cref="TagHelperContext.AllAttributes"/> to <paramref name="tagHelperOutput"/>'s
20+
/// <see cref="TagHelperOutput.Attributes"/>.
21+
/// </summary>
22+
/// <param name="tagHelperOutput">The <see cref="TagHelperOutput"/> this method extends.</param>
23+
/// <param name="attributeName">The name of the bound attribute.</param>
24+
/// <param name="context">The <see cref="TagHelperContext"/>.</param>
25+
/// <remarks>Only copies the attribute if <paramref name="tagHelperOutput"/>'s
26+
/// <see cref="TagHelperOutput.Attributes"/> does not contain an attribute with the given
27+
/// <paramref name="attributeName"/></remarks>
28+
public static void CopyHtmlAttribute(this TagHelperOutput tagHelperOutput,
29+
string attributeName,
30+
TagHelperContext context)
31+
{
32+
// We look for the original attribute so we can restore the exact attribute name the user typed.
33+
var entry = context.AllAttributes.First(attribute =>
34+
attribute.Key.Equals(attributeName, StringComparison.OrdinalIgnoreCase));
35+
36+
if (!tagHelperOutput.Attributes.ContainsKey(entry.Key))
37+
{
38+
tagHelperOutput.Attributes.Add(entry.Key, entry.Value.ToString());
39+
}
40+
}
41+
42+
/// <summary>
43+
/// Returns all attributes from <paramref name="tagHelperOutput"/>'s
44+
/// <see cref="TagHelperOutput.Attributes"/> that have the given <paramref name="prefix"/>.
45+
/// </summary>
46+
/// <param name="tagHelperOutput">The <see cref="TagHelperOutput"/> this method extends.</param>
47+
/// <param name="prefix">A prefix to look for.</param>
48+
/// <returns><see cref="KeyValuePair{string, string}"/>s with <see cref="KeyValuePair{string, string}.Key"/>
49+
/// starting with the given <paramref name="prefix"/>.</returns>
50+
public static IEnumerable<KeyValuePair<string, string>> FindPrefixedAttributes(
51+
this TagHelperOutput tagHelperOutput, string prefix)
52+
{
53+
// TODO: We will not need this method once https://github.com/aspnet/Razor/issues/89 is completed.
54+
55+
// We're only interested in HTML attributes that have the desired prefix.
56+
var prefixedAttributes = tagHelperOutput.Attributes
57+
.Where(attribute => attribute.Key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
58+
.ToArray();
59+
60+
return prefixedAttributes;
61+
}
62+
63+
/// <summary>
64+
/// Merges the given <paramref name="tagBuilder"/> into the <paramref name="tagHelperOutput"/>.
65+
/// </summary>
66+
/// <param name="tagHelperOutput">The <see cref="TagHelperOutput"/> this method extends.</param>
67+
/// <param name="tagBuilder">The <see cref="TagBuilder"/> to merge.</param>
68+
/// <remarks><paramref name="tagHelperOutput"/>'s <see cref="TagHelperOutput.Content"/> has the given
69+
/// <paramref name="tagBuilder"/>s <see cref="TagBuilder.InnerHtml"/> appended to it. This is to ensure
70+
/// multiple <see cref="ITagHelper"/>s running on the same HTML tag don't overwrite each other; therefore,
71+
/// this method may not be appropriate for all <see cref="ITagHelper"/> scenarios.</remarks>
72+
public static void Merge(this TagHelperOutput tagHelperOutput, TagBuilder tagBuilder)
73+
{
74+
tagHelperOutput.TagName = tagBuilder.TagName;
75+
tagHelperOutput.Content += tagBuilder.InnerHtml;
76+
77+
MergeAttributes(tagHelperOutput, tagBuilder);
78+
}
79+
80+
/// <summary>
81+
/// Merges the given <see cref="tagBuilder"/>'s <see cref="TagBuilder.Attributes"/> into the
82+
/// <paramref name="tagHelperOutput"/>.
83+
/// </summary>
84+
/// <param name="tagHelperOutput">The <see cref="TagHelperOutput"/> this method extends.</param>
85+
/// <param name="tagBuilder">The <see cref="TagBuilder"/> to merge attributes from.</param>
86+
/// <remarks>Existing <see cref="TagHelperOutput.Attributes"/> on the given <paramref name="tagHelperOutput"/>
87+
/// are not overriden; "class" attributes are merged with spaces.</remarks>
88+
public static void MergeAttributes(this TagHelperOutput tagHelperOutput, TagBuilder tagBuilder)
89+
{
90+
foreach (var attribute in tagBuilder.Attributes)
91+
{
92+
if (!tagHelperOutput.Attributes.ContainsKey(attribute.Key))
93+
{
94+
tagHelperOutput.Attributes.Add(attribute.Key, attribute.Value);
95+
}
96+
else if (attribute.Key.Equals("class", StringComparison.Ordinal))
97+
{
98+
tagHelperOutput.Attributes["class"] += " " + attribute.Value;
99+
}
100+
}
101+
}
102+
103+
/// <summary>
104+
/// Removes the given <paramref name="attributes"/> from <paramref name="tagHelperOutput"/>'s
105+
/// <see cref="TagHelperOutput.Attributes"/>.
106+
/// </summary>
107+
/// <param name="tagHelperOutput">The <see cref="TagHelperOutput"/> this method extends.</param>
108+
/// <param name="attributes">Attributes to remove.</param>
109+
public static void RemoveRange(
110+
this TagHelperOutput tagHelperOutput, IEnumerable<KeyValuePair<string, string>> attributes)
111+
{
112+
foreach (var attribute in attributes)
113+
{
114+
tagHelperOutput.Attributes.Remove(attribute);
115+
}
116+
}
117+
}
118+
}

0 commit comments

Comments
 (0)