Add `TagHelperOutput.GetChildContentAsync()` overloads including an `HtmlEncoder`
- #643 part 1 - change is viral and requires an update to `RazorPage.StartTagHelperWritingScope()` - memoize `GetChildContentAsync()` per-encoder - update generation tests to match and to test new behaviour - note `HtmlEncoder`s used elsewhere e.g. in other `RazorPage` instances are unaffected Add `NullHtmlEncoder` Nits: - generally clean up affected doc comments and make them more consistent - remove unused `using`s in files I had open
This commit is contained in:
parent
e68c55ab41
commit
37850b5d85
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
using Microsoft.AspNet.Razor.TagHelpers;
|
||||||
|
|
||||||
|
|
@ -15,9 +16,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
{
|
{
|
||||||
private readonly List<ITagHelper> _tagHelpers;
|
private readonly List<ITagHelper> _tagHelpers;
|
||||||
private readonly Func<Task> _executeChildContentAsync;
|
private readonly Func<Task> _executeChildContentAsync;
|
||||||
private readonly Action _startTagHelperWritingScope;
|
private readonly Action<HtmlEncoder> _startTagHelperWritingScope;
|
||||||
private readonly Func<TagHelperContent> _endTagHelperWritingScope;
|
private readonly Func<TagHelperContent> _endTagHelperWritingScope;
|
||||||
private TagHelperContent _childContent;
|
private TagHelperContent _childContent;
|
||||||
|
private Dictionary<HtmlEncoder, TagHelperContent> _perEncoderChildContent;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Internal for testing purposes only.
|
/// Internal for testing purposes only.
|
||||||
|
|
@ -28,7 +30,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
items: new Dictionary<object, object>(),
|
items: new Dictionary<object, object>(),
|
||||||
uniqueId: string.Empty,
|
uniqueId: string.Empty,
|
||||||
executeChildContentAsync: async () => await Task.FromResult(result: true),
|
executeChildContentAsync: async () => await Task.FromResult(result: true),
|
||||||
startTagHelperWritingScope: () => { },
|
startTagHelperWritingScope: _ => { },
|
||||||
endTagHelperWritingScope: () => new DefaultTagHelperContent())
|
endTagHelperWritingScope: () => new DefaultTagHelperContent())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -42,7 +44,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
/// <see cref="ITagHelper"/>s</param>
|
/// <see cref="ITagHelper"/>s</param>
|
||||||
/// <param name="uniqueId">An identifier unique to the HTML element this context is for.</param>
|
/// <param name="uniqueId">An identifier unique to the HTML element this context is for.</param>
|
||||||
/// <param name="executeChildContentAsync">A delegate used to execute the child content asynchronously.</param>
|
/// <param name="executeChildContentAsync">A delegate used to execute the child content asynchronously.</param>
|
||||||
/// <param name="startTagHelperWritingScope">A delegate used to start a writing scope in a Razor page.</param>
|
/// <param name="startTagHelperWritingScope">
|
||||||
|
/// A delegate used to start a writing scope in a Razor page and optionally override the page's
|
||||||
|
/// <see cref="HtmlEncoder"/> within that scope.
|
||||||
|
/// </param>
|
||||||
/// <param name="endTagHelperWritingScope">A delegate used to end a writing scope in a Razor page.</param>
|
/// <param name="endTagHelperWritingScope">A delegate used to end a writing scope in a Razor page.</param>
|
||||||
public TagHelperExecutionContext(
|
public TagHelperExecutionContext(
|
||||||
string tagName,
|
string tagName,
|
||||||
|
|
@ -50,7 +55,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
IDictionary<object, object> items,
|
IDictionary<object, object> items,
|
||||||
string uniqueId,
|
string uniqueId,
|
||||||
Func<Task> executeChildContentAsync,
|
Func<Task> executeChildContentAsync,
|
||||||
Action startTagHelperWritingScope,
|
Action<HtmlEncoder> startTagHelperWritingScope,
|
||||||
Func<TagHelperContent> endTagHelperWritingScope)
|
Func<TagHelperContent> endTagHelperWritingScope)
|
||||||
{
|
{
|
||||||
if (tagName == null)
|
if (tagName == null)
|
||||||
|
|
@ -224,23 +229,57 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Execute and retrieve the rendered child content asynchronously.
|
/// Executes children asynchronously with the given <paramref name="encoder"/> in scope and returns their
|
||||||
|
/// rendered content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="useCachedResult">
|
||||||
|
/// If <c>true</c>, multiple calls with the same <see cref="HtmlEncoder"/> will not cause children to
|
||||||
|
/// re-execute; returns cached content.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="encoder">
|
||||||
|
/// The <see cref="HtmlEncoder"/> to use when the page handles
|
||||||
|
/// non-<see cref="Microsoft.AspNet.Html.IHtmlContent"/> C# expressions. If <c>null</c>, executes children with
|
||||||
|
/// the page's current <see cref="HtmlEncoder"/>.
|
||||||
|
/// </param>
|
||||||
/// <returns>A <see cref="Task"/> that on completion returns the rendered child content.</returns>
|
/// <returns>A <see cref="Task"/> that on completion returns the rendered child content.</returns>
|
||||||
/// <remarks>
|
public async Task<TagHelperContent> GetChildContentAsync(bool useCachedResult, HtmlEncoder encoder)
|
||||||
/// Child content is only executed once. Successive calls to this method or successive executions of the
|
|
||||||
/// returned <see cref="Task{TagHelperContent}"/> return a cached result.
|
|
||||||
/// </remarks>
|
|
||||||
public async Task<TagHelperContent> GetChildContentAsync(bool useCachedResult)
|
|
||||||
{
|
{
|
||||||
if (!useCachedResult || _childContent == null)
|
// Get cached content for this encoder.
|
||||||
|
TagHelperContent childContent;
|
||||||
|
if (encoder == null)
|
||||||
{
|
{
|
||||||
_startTagHelperWritingScope();
|
childContent = _childContent;
|
||||||
await _executeChildContentAsync();
|
}
|
||||||
_childContent = _endTagHelperWritingScope();
|
else
|
||||||
|
{
|
||||||
|
if (_perEncoderChildContent == null)
|
||||||
|
{
|
||||||
|
childContent = null;
|
||||||
|
_perEncoderChildContent = new Dictionary<HtmlEncoder, TagHelperContent>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_perEncoderChildContent.TryGetValue(encoder, out childContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DefaultTagHelperContent().SetContent(_childContent);
|
if (!useCachedResult || childContent == null)
|
||||||
|
{
|
||||||
|
_startTagHelperWritingScope(encoder);
|
||||||
|
await _executeChildContentAsync();
|
||||||
|
childContent = _endTagHelperWritingScope();
|
||||||
|
|
||||||
|
if (encoder == null)
|
||||||
|
{
|
||||||
|
_childContent = childContent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_perEncoderChildContent[encoder] = childContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DefaultTagHelperContent().SetContent(childContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
using Microsoft.AspNet.Razor.TagHelpers;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
using Microsoft.AspNet.Razor.TagHelpers;
|
||||||
using Microsoft.Extensions.Internal;
|
using Microsoft.Extensions.Internal;
|
||||||
|
|
@ -31,7 +32,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
/// <param name="tagMode">HTML syntax of the element in the Razor source.</param>
|
/// <param name="tagMode">HTML syntax of the element in the Razor source.</param>
|
||||||
/// <param name="uniqueId">An identifier unique to the HTML element this scope is for.</param>
|
/// <param name="uniqueId">An identifier unique to the HTML element this scope is for.</param>
|
||||||
/// <param name="executeChildContentAsync">A delegate used to execute the child content asynchronously.</param>
|
/// <param name="executeChildContentAsync">A delegate used to execute the child content asynchronously.</param>
|
||||||
/// <param name="startTagHelperWritingScope">A delegate used to start a writing scope in a Razor page.</param>
|
/// <param name="startTagHelperWritingScope">
|
||||||
|
/// A delegate used to start a writing scope in a Razor page and optionally override the page's
|
||||||
|
/// <see cref="HtmlEncoder"/> within that scope.
|
||||||
|
/// </param>
|
||||||
/// <param name="endTagHelperWritingScope">A delegate used to end a writing scope in a Razor page.</param>
|
/// <param name="endTagHelperWritingScope">A delegate used to end a writing scope in a Razor page.</param>
|
||||||
/// <returns>A <see cref="TagHelperExecutionContext"/> to use.</returns>
|
/// <returns>A <see cref="TagHelperExecutionContext"/> to use.</returns>
|
||||||
public TagHelperExecutionContext Begin(
|
public TagHelperExecutionContext Begin(
|
||||||
|
|
@ -39,7 +43,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
TagMode tagMode,
|
TagMode tagMode,
|
||||||
string uniqueId,
|
string uniqueId,
|
||||||
Func<Task> executeChildContentAsync,
|
Func<Task> executeChildContentAsync,
|
||||||
Action startTagHelperWritingScope,
|
Action<HtmlEncoder> startTagHelperWritingScope,
|
||||||
Func<TagHelperContent> endTagHelperWritingScope)
|
Func<TagHelperContent> endTagHelperWritingScope)
|
||||||
{
|
{
|
||||||
if (tagName == null)
|
if (tagName == null)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
// Copyright (c) .NET Foundation. 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.IO;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="HtmlEncoder"/> that does not encode. Should not be used when writing directly to a response
|
||||||
|
/// expected to contain valid HTML.
|
||||||
|
/// </summary>
|
||||||
|
public class NullHtmlEncoder : HtmlEncoder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a <see cref="NullHtmlEncoder"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
protected NullHtmlEncoder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="HtmlEncoder"/> instance that does not encode. Should not be used when writing directly to a
|
||||||
|
/// response expected to contain valid HTML.
|
||||||
|
/// </summary>
|
||||||
|
public static new NullHtmlEncoder Default { get; } = new NullHtmlEncoder();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override int MaxOutputCharactersPerInputCharacter
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string Encode(string value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Encode(TextWriter output, char[] value, int startIndex, int characterCount)
|
||||||
|
{
|
||||||
|
if (output == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(output));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (characterCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.Write(value, startIndex, characterCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Encode(TextWriter output, string value, int startIndex, int characterCount)
|
||||||
|
{
|
||||||
|
if (output == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(output));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (characterCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.Write(value.Substring(startIndex, characterCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override unsafe int FindFirstCharacterToEncode(char* text, int textLength)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override unsafe bool TryEncodeUnicodeScalar(
|
||||||
|
int unicodeScalar,
|
||||||
|
char* buffer,
|
||||||
|
int bufferLength,
|
||||||
|
out int numberOfCharactersWritten)
|
||||||
|
{
|
||||||
|
if (buffer == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
numberOfCharactersWritten = 0;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool WillEncode(int unicodeScalar)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TagHelperOutput : IHtmlContent
|
public class TagHelperOutput : IHtmlContent
|
||||||
{
|
{
|
||||||
private readonly Func<bool, Task<TagHelperContent>> _getChildContentAsync;
|
private readonly Func<bool, HtmlEncoder, Task<TagHelperContent>> _getChildContentAsync;
|
||||||
private TagHelperContent _preElement;
|
private TagHelperContent _preElement;
|
||||||
private TagHelperContent _preContent;
|
private TagHelperContent _preContent;
|
||||||
private TagHelperContent _content;
|
private TagHelperContent _content;
|
||||||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
: this(
|
: this(
|
||||||
tagName,
|
tagName,
|
||||||
new TagHelperAttributeList(),
|
new TagHelperAttributeList(),
|
||||||
(cachedResult) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()))
|
(useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,12 +36,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tagName">The HTML element's tag name.</param>
|
/// <param name="tagName">The HTML element's tag name.</param>
|
||||||
/// <param name="attributes">The HTML attributes.</param>
|
/// <param name="attributes">The HTML attributes.</param>
|
||||||
/// <param name="getChildContentAsync">A delegate used to execute and retrieve the rendered child content
|
/// <param name="getChildContentAsync">
|
||||||
/// asynchronously.</param>
|
/// A delegate used to execute children asynchronously with the given <see cref="HtmlEncoder"/> in scope and
|
||||||
|
/// return their rendered content.
|
||||||
|
/// </param>
|
||||||
public TagHelperOutput(
|
public TagHelperOutput(
|
||||||
string tagName,
|
string tagName,
|
||||||
TagHelperAttributeList attributes,
|
TagHelperAttributeList attributes,
|
||||||
Func<bool, Task<TagHelperContent>> getChildContentAsync)
|
Func<bool, HtmlEncoder, Task<TagHelperContent>> getChildContentAsync)
|
||||||
{
|
{
|
||||||
if (attributes == null)
|
if (attributes == null)
|
||||||
{
|
{
|
||||||
|
|
@ -206,24 +208,65 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A delegate used to execute children asynchronously.
|
/// Executes children asynchronously and returns their rendered content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
||||||
/// <remarks>This method is memoized.</remarks>
|
/// <remarks>
|
||||||
|
/// This method is memoized. Multiple calls will not cause children to re-execute with the page's original
|
||||||
|
/// <see cref="HtmlEncoder"/>.
|
||||||
|
/// </remarks>
|
||||||
public Task<TagHelperContent> GetChildContentAsync()
|
public Task<TagHelperContent> GetChildContentAsync()
|
||||||
{
|
{
|
||||||
return GetChildContentAsync(useCachedResult: true);
|
return GetChildContentAsync(useCachedResult: true, encoder: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A delegate used to execute children asynchronously.
|
/// Executes children asynchronously and returns their rendered content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="useCachedResult">If <c>true</c> multiple calls to this method will not cause re-execution
|
/// <param name="useCachedResult">
|
||||||
/// of child content; cached content will be returned.</param>
|
/// If <c>true</c>, multiple calls will not cause children to re-execute with the page's original
|
||||||
|
/// <see cref="HtmlEncoder"/>; returns cached content.
|
||||||
|
/// </param>
|
||||||
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
||||||
public Task<TagHelperContent> GetChildContentAsync(bool useCachedResult)
|
public Task<TagHelperContent> GetChildContentAsync(bool useCachedResult)
|
||||||
{
|
{
|
||||||
return _getChildContentAsync(useCachedResult);
|
return GetChildContentAsync(useCachedResult, encoder: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes children asynchronously with the given <paramref name="encoder"/> in scope and returns their
|
||||||
|
/// rendered content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="encoder">
|
||||||
|
/// The <see cref="HtmlEncoder"/> to use when the page handles non-<see cref="IHtmlContent"/> C# expressions.
|
||||||
|
/// If <c>null</c>, executes children with the page's current <see cref="HtmlEncoder"/>.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method is memoized. Multiple calls with the same <see cref="HtmlEncoder"/> instance will not cause
|
||||||
|
/// children to re-execute with that encoder in scope.
|
||||||
|
/// </remarks>
|
||||||
|
public Task<TagHelperContent> GetChildContentAsync(HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
return GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes children asynchronously with the given <paramref name="encoder"/> in scope and returns their
|
||||||
|
/// rendered content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="useCachedResult">
|
||||||
|
/// If <c>true</c>, multiple calls with the same <see cref="HtmlEncoder"/> will not cause children to
|
||||||
|
/// re-execute; returns cached content.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="encoder">
|
||||||
|
/// The <see cref="HtmlEncoder"/> to use when the page handles non-<see cref="IHtmlContent"/> C# expressions.
|
||||||
|
/// If <c>null</c>, executes children with the page's current <see cref="HtmlEncoder"/>.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
||||||
|
public Task<TagHelperContent> GetChildContentAsync(bool useCachedResult, HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
return _getChildContentAsync(useCachedResult, encoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@
|
||||||
"description": "Runtime components for rendering Razor pages.",
|
"description": "Runtime components for rendering Razor pages.",
|
||||||
"version": "4.0.0-*",
|
"version": "4.0.0-*",
|
||||||
"compilationOptions": {
|
"compilationOptions": {
|
||||||
"warningsAsErrors": true,
|
"allowUnsafe": true,
|
||||||
"keyFile": "../../tools/Key.snk"
|
"keyFile": "../../tools/Key.snk",
|
||||||
|
"warningsAsErrors": true
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNet.Razor.Chunks;
|
using Microsoft.AspNet.Razor.Chunks;
|
||||||
using Microsoft.AspNet.Razor.CodeGenerators.Visitors;
|
using Microsoft.AspNet.Razor.CodeGenerators.Visitors;
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
|
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
|
||||||
|
using Microsoft.AspNet.Razor.TagHelpers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
{
|
{
|
||||||
|
|
@ -659,7 +659,7 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
// Scopes are a runtime feature.
|
// Scopes are a runtime feature.
|
||||||
if (!_designTimeMode)
|
if (!_designTimeMode)
|
||||||
{
|
{
|
||||||
_writer.WriteMethodInvocation(_tagHelperContext.StartTagHelperWritingScopeMethodName);
|
_writer.WriteMethodInvocation(_tagHelperContext.StartTagHelperWritingScopeMethodName, "null");
|
||||||
}
|
}
|
||||||
|
|
||||||
var visitor = htmlEncodeValues ? _bodyVisitor : _literalBodyVisitor;
|
var visitor = htmlEncodeValues ? _bodyVisitor : _literalBodyVisitor;
|
||||||
|
|
@ -668,8 +668,9 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
// Scopes are a runtime feature.
|
// Scopes are a runtime feature.
|
||||||
if (!_designTimeMode)
|
if (!_designTimeMode)
|
||||||
{
|
{
|
||||||
_writer.WriteStartAssignment(StringValueBufferVariableName)
|
_writer
|
||||||
.WriteMethodInvocation(_tagHelperContext.EndTagHelperWritingScopeMethodName);
|
.WriteStartAssignment(StringValueBufferVariableName)
|
||||||
|
.WriteMethodInvocation(_tagHelperContext.EndTagHelperWritingScopeMethodName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
@ -708,7 +709,7 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
StringValueBufferVariableName,
|
StringValueBufferVariableName,
|
||||||
_tagHelperContext.TagHelperContentGetContentMethodName,
|
_tagHelperContext.TagHelperContentGetContentMethodName,
|
||||||
endLine: false,
|
endLine: false,
|
||||||
parameters: new string[] { _tagHelperContext.HtmlEncoderPropertyName });
|
parameters: _tagHelperContext.HtmlEncoderPropertyName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. 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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
using Microsoft.AspNet.Razor.TagHelpers;
|
||||||
using Microsoft.Extensions.WebEncoders.Testing;
|
using Microsoft.Extensions.WebEncoders.Testing;
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
items: expectedItems,
|
items: expectedItems,
|
||||||
uniqueId: string.Empty,
|
uniqueId: string.Empty,
|
||||||
executeChildContentAsync: async () => await Task.FromResult(result: true),
|
executeChildContentAsync: async () => await Task.FromResult(result: true),
|
||||||
startTagHelperWritingScope: () => { },
|
startTagHelperWritingScope: _ => { },
|
||||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -51,13 +51,47 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
Assert.Same(expectedItems, executionContext.Items);
|
Assert.Same(expectedItems, executionContext.Items);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
public static TheoryData<HtmlEncoder> HtmlEncoderData
|
||||||
public async Task GetChildContentAsync_CachesValue()
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new TheoryData<HtmlEncoder>
|
||||||
|
{
|
||||||
|
null,
|
||||||
|
HtmlEncoder.Default,
|
||||||
|
NullHtmlEncoder.Default,
|
||||||
|
new HtmlTestEncoder(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TheoryData<HtmlEncoder> HtmlEncoderDataLessNull
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var data = new TheoryData<HtmlEncoder>();
|
||||||
|
foreach (var row in HtmlEncoderData)
|
||||||
|
{
|
||||||
|
var encoder = (HtmlEncoder)(row[0]);
|
||||||
|
if (encoder != null)
|
||||||
|
{
|
||||||
|
data.Add(encoder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(HtmlEncoderData))]
|
||||||
|
public async Task GetChildContentAsync_ReturnsExpectedContent(HtmlEncoder encoder)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var defaultTagHelperContent = new DefaultTagHelperContent();
|
var tagHelperContent = new DefaultTagHelperContent();
|
||||||
var content = string.Empty;
|
var executionCount = 0;
|
||||||
var expectedContent = string.Empty;
|
var content = "Hello from child content";
|
||||||
|
var expectedContent = $"HtmlEncode[[{content}]]";
|
||||||
var executionContext = new TagHelperExecutionContext(
|
var executionContext = new TagHelperExecutionContext(
|
||||||
"p",
|
"p",
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
|
@ -65,30 +99,46 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
uniqueId: string.Empty,
|
uniqueId: string.Empty,
|
||||||
executeChildContentAsync: () =>
|
executeChildContentAsync: () =>
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(expectedContent))
|
executionCount++;
|
||||||
{
|
tagHelperContent.SetContent(content);
|
||||||
content = "Hello from child content: " + Guid.NewGuid().ToString();
|
|
||||||
expectedContent = $"HtmlEncode[[{content}]]";
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultTagHelperContent.SetContent(content);
|
|
||||||
|
|
||||||
return Task.FromResult(result: true);
|
return Task.FromResult(result: true);
|
||||||
},
|
},
|
||||||
startTagHelperWritingScope: () => { },
|
startTagHelperWritingScope: _ => { },
|
||||||
endTagHelperWritingScope: () => defaultTagHelperContent);
|
endTagHelperWritingScope: () => tagHelperContent);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var content1 = await executionContext.GetChildContentAsync(useCachedResult: true);
|
var actualContent = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||||
var content2 = await executionContext.GetChildContentAsync(useCachedResult: true);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedContent, content1.GetContent(new HtmlTestEncoder()));
|
Assert.Equal(expectedContent, actualContent.GetContent(new HtmlTestEncoder()));
|
||||||
Assert.Equal(expectedContent, content2.GetContent(new HtmlTestEncoder()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Theory]
|
||||||
public async Task GetChildContentAsync_CanExecuteChildrenMoreThanOnce()
|
[MemberData(nameof(HtmlEncoderData))]
|
||||||
|
public async Task GetChildContentAsync_StartsWritingScopeWithGivenEncoder(HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
HtmlEncoder passedEncoder = null;
|
||||||
|
var executionContext = new TagHelperExecutionContext(
|
||||||
|
"p",
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
items: new Dictionary<object, object>(),
|
||||||
|
uniqueId: string.Empty,
|
||||||
|
executeChildContentAsync: () => Task.FromResult(result: true),
|
||||||
|
startTagHelperWritingScope: encoderArgument => passedEncoder = encoderArgument,
|
||||||
|
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(encoder, passedEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(HtmlEncoderData))]
|
||||||
|
public async Task GetChildContentAsync_CachesValue(HtmlEncoder encoder)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var executionCount = 0;
|
var executionCount = 0;
|
||||||
|
|
@ -100,15 +150,98 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
executeChildContentAsync: () =>
|
executeChildContentAsync: () =>
|
||||||
{
|
{
|
||||||
executionCount++;
|
executionCount++;
|
||||||
|
|
||||||
return Task.FromResult(result: true);
|
return Task.FromResult(result: true);
|
||||||
},
|
},
|
||||||
startTagHelperWritingScope: () => { },
|
startTagHelperWritingScope: _ => { },
|
||||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await executionContext.GetChildContentAsync(useCachedResult: false);
|
var content1 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||||
await executionContext.GetChildContentAsync(useCachedResult: false);
|
var content2 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1, executionCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(HtmlEncoderDataLessNull))]
|
||||||
|
public async Task GetChildContentAsync_CachesValuePerEncoder(HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var executionCount = 0;
|
||||||
|
var executionContext = new TagHelperExecutionContext(
|
||||||
|
"p",
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
items: new Dictionary<object, object>(),
|
||||||
|
uniqueId: string.Empty,
|
||||||
|
executeChildContentAsync: () =>
|
||||||
|
{
|
||||||
|
executionCount++;
|
||||||
|
return Task.FromResult(result: true);
|
||||||
|
},
|
||||||
|
startTagHelperWritingScope: _ => { },
|
||||||
|
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var content1 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: null);
|
||||||
|
var content2 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(2, executionCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(HtmlEncoderData))]
|
||||||
|
public async Task GetChildContentAsync_CachesValuePerEncoderInstance(HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var executionCount = 0;
|
||||||
|
var executionContext = new TagHelperExecutionContext(
|
||||||
|
"p",
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
items: new Dictionary<object, object>(),
|
||||||
|
uniqueId: string.Empty,
|
||||||
|
executeChildContentAsync: () =>
|
||||||
|
{
|
||||||
|
executionCount++;
|
||||||
|
return Task.FromResult(result: true);
|
||||||
|
},
|
||||||
|
startTagHelperWritingScope: _ => { },
|
||||||
|
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||||
|
|
||||||
|
// HtmlEncoderData includes another HtmlTestEncoder instance but method compares HtmlEncoder instances.
|
||||||
|
var firstEncoder = new HtmlTestEncoder();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var content1 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: firstEncoder);
|
||||||
|
var content2 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(2, executionCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(HtmlEncoderData))]
|
||||||
|
public async Task GetChildContentAsync_CanExecuteChildrenMoreThanOnce(HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var executionCount = 0;
|
||||||
|
var executionContext = new TagHelperExecutionContext(
|
||||||
|
"p",
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
items: new Dictionary<object, object>(),
|
||||||
|
uniqueId: string.Empty,
|
||||||
|
executeChildContentAsync: () =>
|
||||||
|
{
|
||||||
|
executionCount++;
|
||||||
|
return Task.FromResult(result: true);
|
||||||
|
},
|
||||||
|
startTagHelperWritingScope: _ => { },
|
||||||
|
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await executionContext.GetChildContentAsync(useCachedResult: false, encoder: encoder);
|
||||||
|
await executionContext.GetChildContentAsync(useCachedResult: false, encoder: encoder);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(2, executionCount);
|
Assert.Equal(2, executionCount);
|
||||||
|
|
@ -120,27 +253,21 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
public async Task GetChildContentAsync_ReturnsNewObjectEveryTimeItIsCalled(bool useCachedResult)
|
public async Task GetChildContentAsync_ReturnsNewObjectEveryTimeItIsCalled(bool useCachedResult)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var defaultTagHelperContent = new DefaultTagHelperContent();
|
|
||||||
var executionContext = new TagHelperExecutionContext(
|
var executionContext = new TagHelperExecutionContext(
|
||||||
"p",
|
"p",
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
items: new Dictionary<object, object>(),
|
items: new Dictionary<object, object>(),
|
||||||
uniqueId: string.Empty,
|
uniqueId: string.Empty,
|
||||||
executeChildContentAsync: () => { return Task.FromResult(result: true); },
|
executeChildContentAsync: () => Task.FromResult(result: true),
|
||||||
startTagHelperWritingScope: () => { },
|
startTagHelperWritingScope: _ => { },
|
||||||
endTagHelperWritingScope: () => defaultTagHelperContent);
|
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var content1 = await executionContext.GetChildContentAsync(useCachedResult);
|
var content1 = await executionContext.GetChildContentAsync(useCachedResult, encoder: null);
|
||||||
content1.Append("Hello");
|
var content2 = await executionContext.GetChildContentAsync(useCachedResult, encoder: null);
|
||||||
var content2 = await executionContext.GetChildContentAsync(useCachedResult);
|
|
||||||
content2.Append("World!");
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotSame(content1, content2);
|
Assert.NotSame(content1, content2);
|
||||||
|
|
||||||
var content3 = await executionContext.GetChildContentAsync(useCachedResult);
|
|
||||||
Assert.Empty(content3.GetContent(new HtmlTestEncoder()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TheoryData<string, string> DictionaryCaseTestingData
|
public static TheoryData<string, string> DictionaryCaseTestingData
|
||||||
|
|
@ -314,7 +441,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
Assert.Equal(2, tagHelpers.Length);
|
Assert.Equal(2, tagHelpers.Length);
|
||||||
Assert.Same(tagHelper1, tagHelpers[0]);
|
Assert.Same(tagHelper1, tagHelpers[0]);
|
||||||
Assert.Same(tagHelper2, tagHelpers[1]);
|
Assert.Same(tagHelper2, tagHelpers[1]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PTagHelper : TagHelper
|
private class PTagHelper : TagHelper
|
||||||
|
|
|
||||||
|
|
@ -1,698 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. 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.IO;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
|
||||||
using Microsoft.Extensions.WebEncoders.Testing;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.Test.Runtime.TagHelpers
|
|
||||||
{
|
|
||||||
public class TagHelperOutputTest
|
|
||||||
{
|
|
||||||
public static TheoryData<TagHelperOutput, string> WriteTagHelper_InputData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
// parameters: TagHelperOutput, expectedOutput
|
|
||||||
return new TheoryData<TagHelperOutput, string>
|
|
||||||
{
|
|
||||||
{
|
|
||||||
// parameters: TagName, Attributes, SelfClosing, PreContent, Content, PostContent
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "div",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<div>Hello World!</div>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: string.Empty,
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"Hello World!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: " ",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"Hello World!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p test=\"HtmlEncode[[testVal]]\">Hello World!</p>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList()
|
|
||||||
{
|
|
||||||
{ "test", "testVal" },
|
|
||||||
{ "something", " spaced " }
|
|
||||||
},
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\">Hello World!</p>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList()
|
|
||||||
{
|
|
||||||
["test"] = new TagHelperAttribute
|
|
||||||
{
|
|
||||||
Name = "test",
|
|
||||||
Minimized = true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p test>Hello World!</p>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList()
|
|
||||||
{
|
|
||||||
["test"] = new TagHelperAttribute
|
|
||||||
{
|
|
||||||
Name = "test",
|
|
||||||
Minimized = true
|
|
||||||
},
|
|
||||||
["test2"] = new TagHelperAttribute
|
|
||||||
{
|
|
||||||
Name = "test2",
|
|
||||||
Minimized = true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p test test2>Hello World!</p>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList()
|
|
||||||
{
|
|
||||||
["first"] = "unminimized",
|
|
||||||
["test"] = new TagHelperAttribute
|
|
||||||
{
|
|
||||||
Name = "test",
|
|
||||||
Minimized = true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p first=\"HtmlEncode[[unminimized]]\" test>Hello World!</p>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList()
|
|
||||||
{
|
|
||||||
["test"] = new TagHelperAttribute
|
|
||||||
{
|
|
||||||
Name = "test",
|
|
||||||
Minimized = true
|
|
||||||
},
|
|
||||||
["last"] = "unminimized",
|
|
||||||
},
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p test last=\"HtmlEncode[[unminimized]]\">Hello World!</p>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p test=\"HtmlEncode[[testVal]]\" />"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList()
|
|
||||||
{
|
|
||||||
{ "test", "testVal" },
|
|
||||||
{ "something", " spaced " }
|
|
||||||
},
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\" />"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p test=\"HtmlEncode[[testVal]]\">"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList()
|
|
||||||
{
|
|
||||||
{ "test", "testVal" },
|
|
||||||
{ "something", " spaced " }
|
|
||||||
},
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\">"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: "Hello World!",
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p>Hello World!</p>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: "Hello World!",
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"<p>Hello World!</p>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: "Hello World!",
|
|
||||||
postElement: null),
|
|
||||||
"<p>Hello World!</p>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: null),
|
|
||||||
"<p>HelloTestWorld!</p>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: null,
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: null),
|
|
||||||
"<p />"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "p",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: null,
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: null),
|
|
||||||
"<p>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: null),
|
|
||||||
"<custom>HelloTestWorld!</custom>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "random",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: null,
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: null),
|
|
||||||
"<random />"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "random",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: null,
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: null),
|
|
||||||
"<random>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"Before<custom></custom>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: string.Empty,
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"Before"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: string.Empty,
|
|
||||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"Before"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"Before<custom test=\"HtmlEncode[[testVal]]\" />"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"Before<custom />"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: string.Empty,
|
|
||||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"Before"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"Before<custom test=\"HtmlEncode[[testVal]]\">"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: null),
|
|
||||||
"Before<custom>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: "After"),
|
|
||||||
"<custom></custom>After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: string.Empty,
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: "After"),
|
|
||||||
"After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: string.Empty,
|
|
||||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: "After"),
|
|
||||||
"After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: "After"),
|
|
||||||
"<custom test=\"HtmlEncode[[testVal]]\" />After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: "After"),
|
|
||||||
"<custom />After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: string.Empty,
|
|
||||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: "After"),
|
|
||||||
"After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: "After"),
|
|
||||||
"<custom test=\"HtmlEncode[[testVal]]\">After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: null,
|
|
||||||
preContent: null,
|
|
||||||
content: null,
|
|
||||||
postContent: null,
|
|
||||||
postElement: "After"),
|
|
||||||
"<custom>After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: "After"),
|
|
||||||
"Before<custom>HelloTestWorld!</custom>After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: "After"),
|
|
||||||
"Before<custom test=\"HtmlEncode[[testVal]]\">HelloTestWorld!</custom>After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: "After"),
|
|
||||||
"Before<custom />After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: string.Empty,
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.SelfClosing,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: "After"),
|
|
||||||
"BeforeHelloTestWorld!After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: "custom",
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: "After"),
|
|
||||||
"Before<custom>After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: string.Empty,
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagOnly,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: "After"),
|
|
||||||
"BeforeHelloTestWorld!After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: string.Empty,
|
|
||||||
attributes: new TagHelperAttributeList(),
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: "After"),
|
|
||||||
"BeforeHelloTestWorld!After"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GetTagHelperOutput(
|
|
||||||
tagName: string.Empty,
|
|
||||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
|
||||||
tagMode: TagMode.StartTagAndEndTag,
|
|
||||||
preElement: "Before",
|
|
||||||
preContent: "Hello",
|
|
||||||
content: "Test",
|
|
||||||
postContent: "World!",
|
|
||||||
postElement: "After"),
|
|
||||||
"BeforeHelloTestWorld!After"
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[MemberData(nameof(WriteTagHelper_InputData))]
|
|
||||||
public void TagHelperOutput_WritesFormattedTagHelper(TagHelperOutput output, string expected)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var writer = new StringWriter();
|
|
||||||
var tagHelperExecutionContext = new TagHelperExecutionContext(
|
|
||||||
tagName: output.TagName,
|
|
||||||
tagMode: output.TagMode,
|
|
||||||
items: new Dictionary<object, object>(),
|
|
||||||
uniqueId: string.Empty,
|
|
||||||
executeChildContentAsync: () => Task.FromResult(result: true),
|
|
||||||
startTagHelperWritingScope: () => { },
|
|
||||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
|
||||||
tagHelperExecutionContext.Output = output;
|
|
||||||
var testEncoder = new HtmlTestEncoder();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
output.WriteTo(writer, testEncoder);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(expected, writer.ToString(), StringComparer.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TagHelperOutput GetTagHelperOutput(
|
|
||||||
string tagName,
|
|
||||||
TagHelperAttributeList attributes,
|
|
||||||
TagMode tagMode,
|
|
||||||
string preElement,
|
|
||||||
string preContent,
|
|
||||||
string content,
|
|
||||||
string postContent,
|
|
||||||
string postElement)
|
|
||||||
{
|
|
||||||
var output = new TagHelperOutput(
|
|
||||||
tagName,
|
|
||||||
attributes,
|
|
||||||
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()))
|
|
||||||
{
|
|
||||||
TagMode = tagMode
|
|
||||||
};
|
|
||||||
|
|
||||||
if (preElement != null)
|
|
||||||
{
|
|
||||||
output.PreElement.AppendHtml(preElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preContent != null)
|
|
||||||
{
|
|
||||||
output.PreContent.AppendHtml(preContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content != null)
|
|
||||||
{
|
|
||||||
output.Content.AppendHtml(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (postContent != null)
|
|
||||||
{
|
|
||||||
output.PostContent.AppendHtml(postContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (postElement != null)
|
|
||||||
{
|
|
||||||
output.PostElement.AppendHtml(postElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -167,7 +167,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
Assert.Equal(tagMode, executionContext.TagMode);
|
Assert.Equal(tagMode, executionContext.TagMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void End_ReturnsParentExecutionContext()
|
public void End_ReturnsParentExecutionContext()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -228,7 +228,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
tagMode,
|
tagMode,
|
||||||
uniqueId: string.Empty,
|
uniqueId: string.Empty,
|
||||||
executeChildContentAsync: async () => await Task.FromResult(result: true),
|
executeChildContentAsync: async () => await Task.FromResult(result: true),
|
||||||
startTagHelperWritingScope: () => { },
|
startTagHelperWritingScope: _ => { },
|
||||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
// Copyright (c) .NET Foundation. 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 Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
|
{
|
||||||
|
public class NullHtmlEncoderTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void MaxOutputCharactersPerInputCharacter_Returns1()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var encoder = NullHtmlEncoder.Default;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = encoder.MaxOutputCharactersPerInputCharacter;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("")]
|
||||||
|
[InlineData("abcd")]
|
||||||
|
[InlineData("<<''\"\">>")]
|
||||||
|
public void Encode_String_DoesNotEncode(string value)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var encoder = NullHtmlEncoder.Default;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = encoder.Encode(value);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(value, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("")]
|
||||||
|
[InlineData("abcd")]
|
||||||
|
[InlineData("<<''\"\">>")]
|
||||||
|
public void Encode_StringToTextWriter_DoesNotEncode(string value)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var encoder = NullHtmlEncoder.Default;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string result;
|
||||||
|
using (var writer = new StringWriter())
|
||||||
|
{
|
||||||
|
encoder.Encode(writer, value);
|
||||||
|
result = writer.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(value, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("", 0, 0, "")]
|
||||||
|
[InlineData("abcd", 0, 0, "")]
|
||||||
|
[InlineData("<<''\"\">>", 0, 0, "")]
|
||||||
|
[InlineData("abcd", 0, 1, "a")]
|
||||||
|
[InlineData("<<''\"\">>", 0, 1, "<")]
|
||||||
|
[InlineData("abcd", 0, 4, "abcd")]
|
||||||
|
[InlineData("<<''\"\">>", 0, 8, "<<''\"\">>")]
|
||||||
|
[InlineData("abcd", 2, 0, "")]
|
||||||
|
[InlineData("<<''\"\">>", 2, 0, "")]
|
||||||
|
[InlineData("abcd", 2, 2, "cd")]
|
||||||
|
[InlineData("<<''\"\">>", 2, 2, "''")]
|
||||||
|
[InlineData("abcd", 3, 0, "")]
|
||||||
|
[InlineData("<<''\"\">>", 7, 0, "")]
|
||||||
|
[InlineData("abcd", 3, 1, "d")]
|
||||||
|
[InlineData("<<''\"\">>", 7, 1, ">")]
|
||||||
|
public void Encode_StringToTextWriter_DoesNotEncodeSubstring(
|
||||||
|
string value,
|
||||||
|
int startIndex,
|
||||||
|
int characterCount,
|
||||||
|
string expectedResult)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var encoder = NullHtmlEncoder.Default;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string result;
|
||||||
|
using (var writer = new StringWriter())
|
||||||
|
{
|
||||||
|
encoder.Encode(writer, value, startIndex, characterCount);
|
||||||
|
result = writer.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("", 0, 0, "")]
|
||||||
|
[InlineData("abcd", 0, 0, "")]
|
||||||
|
[InlineData("<<''\"\">>", 0, 0, "")]
|
||||||
|
[InlineData("abcd", 0, 1, "a")]
|
||||||
|
[InlineData("<<''\"\">>", 0, 1, "<")]
|
||||||
|
[InlineData("abcd", 0, 4, "abcd")]
|
||||||
|
[InlineData("<<''\"\">>", 0, 8, "<<''\"\">>")]
|
||||||
|
[InlineData("abcd", 2, 0, "")]
|
||||||
|
[InlineData("<<''\"\">>", 2, 0, "")]
|
||||||
|
[InlineData("abcd", 2, 2, "cd")]
|
||||||
|
[InlineData("<<''\"\">>", 2, 2, "''")]
|
||||||
|
[InlineData("abcd", 3, 0, "")]
|
||||||
|
[InlineData("<<''\"\">>", 7, 0, "")]
|
||||||
|
[InlineData("abcd", 3, 1, "d")]
|
||||||
|
[InlineData("<<''\"\">>", 7, 1, ">")]
|
||||||
|
public void Encode_CharsToTextWriter_DoesNotEncodeSubstring(
|
||||||
|
string value,
|
||||||
|
int startIndex,
|
||||||
|
int characterCount,
|
||||||
|
string expectedResult)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var encoder = NullHtmlEncoder.Default;
|
||||||
|
var chars = value.ToCharArray();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string result;
|
||||||
|
using (var writer = new StringWriter())
|
||||||
|
{
|
||||||
|
encoder.Encode(writer, chars, startIndex, characterCount);
|
||||||
|
result = writer.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(int.MaxValue)]
|
||||||
|
[InlineData(int.MinValue)]
|
||||||
|
[InlineData(0)]
|
||||||
|
[InlineData((int)'\n')]
|
||||||
|
[InlineData((int)'\r')]
|
||||||
|
[InlineData((int)'<')]
|
||||||
|
[InlineData((int)'>')]
|
||||||
|
[InlineData((int)'\'')]
|
||||||
|
[InlineData((int)'"')]
|
||||||
|
public void WillEncode_ReturnsFalse(int unicodeScalar)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var encoder = NullHtmlEncoder.Default;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = encoder.WillEncode(unicodeScalar);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. 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.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||||
using Microsoft.Extensions.WebEncoders.Testing;
|
using Microsoft.Extensions.WebEncoders.Testing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -9,27 +14,148 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
{
|
{
|
||||||
public class TagHelperOutputTest
|
public class TagHelperOutputTest
|
||||||
{
|
{
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(true)]
|
public async Task GetChildContentAsync_CallsGetChildContentAsync()
|
||||||
[InlineData(false)]
|
|
||||||
public async Task GetChildContentAsync_PassesUseCachedResultAsExpected(bool expectedUseCachedResultValue)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
bool? useCachedResultValue = null;
|
bool? passedUseCacheResult = null;
|
||||||
|
HtmlEncoder passedEncoder = null;
|
||||||
|
var content = new DefaultTagHelperContent();
|
||||||
var output = new TagHelperOutput(
|
var output = new TagHelperOutput(
|
||||||
tagName: "p",
|
tagName: "tag",
|
||||||
attributes: new TagHelperAttributeList(),
|
attributes: new TagHelperAttributeList(),
|
||||||
getChildContentAsync: useCachedResult =>
|
getChildContentAsync: (useCachedResult, encoder) =>
|
||||||
{
|
{
|
||||||
useCachedResultValue = useCachedResult;
|
passedUseCacheResult = useCachedResult;
|
||||||
return Task.FromResult<TagHelperContent>(new DefaultTagHelperContent());
|
passedEncoder = encoder;
|
||||||
|
return Task.FromResult<TagHelperContent>(content);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await output.GetChildContentAsync(expectedUseCachedResultValue);
|
var result = await output.GetChildContentAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedUseCachedResultValue, useCachedResultValue);
|
Assert.True(passedUseCacheResult.HasValue);
|
||||||
|
Assert.True(passedUseCacheResult.Value);
|
||||||
|
Assert.Null(passedEncoder);
|
||||||
|
Assert.Same(content, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TheoryData<HtmlEncoder> HtmlEncoderData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new TheoryData<HtmlEncoder>
|
||||||
|
{
|
||||||
|
null,
|
||||||
|
HtmlEncoder.Default,
|
||||||
|
NullHtmlEncoder.Default,
|
||||||
|
new HtmlTestEncoder(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(HtmlEncoderData))]
|
||||||
|
public async Task GetChildContentAsync_CallsGetChildContentAsync(HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
bool? passedUseCacheResult = null;
|
||||||
|
HtmlEncoder passedEncoder = null;
|
||||||
|
var content = new DefaultTagHelperContent();
|
||||||
|
var output = new TagHelperOutput(
|
||||||
|
tagName: "tag",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
getChildContentAsync: (useCachedResult, encoderArgument) =>
|
||||||
|
{
|
||||||
|
passedUseCacheResult = useCachedResult;
|
||||||
|
passedEncoder = encoderArgument;
|
||||||
|
return Task.FromResult<TagHelperContent>(content);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await output.GetChildContentAsync(encoder);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(passedUseCacheResult.HasValue);
|
||||||
|
Assert.True(passedUseCacheResult.Value);
|
||||||
|
Assert.Same(encoder, passedEncoder);
|
||||||
|
Assert.Same(content, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(false)]
|
||||||
|
[InlineData(true)]
|
||||||
|
public async Task GetChildContentAsync_CallsGetChildContentAsync(bool useCachedResult)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
bool? passedUseCacheResult = null;
|
||||||
|
HtmlEncoder passedEncoder = null;
|
||||||
|
var content = new DefaultTagHelperContent();
|
||||||
|
var output = new TagHelperOutput(
|
||||||
|
tagName: "tag",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
getChildContentAsync: (useCachedResultArgument, encoder) =>
|
||||||
|
{
|
||||||
|
passedUseCacheResult = useCachedResultArgument;
|
||||||
|
passedEncoder = encoder;
|
||||||
|
return Task.FromResult<TagHelperContent>(content);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await output.GetChildContentAsync(useCachedResult);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(passedUseCacheResult.HasValue);
|
||||||
|
Assert.Equal(useCachedResult, passedUseCacheResult.Value);
|
||||||
|
Assert.Null(passedEncoder);
|
||||||
|
Assert.Same(content, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TheoryData<bool, HtmlEncoder> UseCachedResultAndHtmlEncoderData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var data = new TheoryData<bool, HtmlEncoder>();
|
||||||
|
foreach (var useCachedResult in new[] { false, true })
|
||||||
|
{
|
||||||
|
foreach (var encoderEntry in HtmlEncoderData)
|
||||||
|
{
|
||||||
|
var encoder = (HtmlEncoder)(encoderEntry[0]);
|
||||||
|
data.Add(useCachedResult, encoder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(UseCachedResultAndHtmlEncoderData))]
|
||||||
|
public async Task GetChildContentAsync_CallsGetChildContentAsync(bool useCachedResult, HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
bool? passedUseCacheResult = null;
|
||||||
|
HtmlEncoder passedEncoder = null;
|
||||||
|
var content = new DefaultTagHelperContent();
|
||||||
|
var output = new TagHelperOutput(
|
||||||
|
tagName: "tag",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
getChildContentAsync: (useCachedResultArgument, encoderArgument) =>
|
||||||
|
{
|
||||||
|
passedUseCacheResult = useCachedResultArgument;
|
||||||
|
passedEncoder = encoderArgument;
|
||||||
|
return Task.FromResult<TagHelperContent>(content);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await output.GetChildContentAsync(useCachedResult, encoder);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(passedUseCacheResult.HasValue);
|
||||||
|
Assert.Equal(useCachedResult, passedUseCacheResult.Value);
|
||||||
|
Assert.Same(encoder, passedEncoder);
|
||||||
|
Assert.Same(content, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -175,13 +301,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
public void SuppressOutput_PreventsTagOutput()
|
public void SuppressOutput_PreventsTagOutput()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var tagHelperOutput = new TagHelperOutput("p",
|
var tagHelperOutput = new TagHelperOutput(
|
||||||
|
"p",
|
||||||
new TagHelperAttributeList
|
new TagHelperAttributeList
|
||||||
{
|
{
|
||||||
{ "class", "btn" },
|
{ "class", "btn" },
|
||||||
{ "something", " spaced " }
|
{ "something", " spaced " }
|
||||||
},
|
},
|
||||||
(cachedResult) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
|
(cachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
|
||||||
tagHelperOutput.PreContent.Append("Pre Content");
|
tagHelperOutput.PreContent.Append("Pre Content");
|
||||||
tagHelperOutput.Content.Append("Content");
|
tagHelperOutput.Content.Append("Content");
|
||||||
tagHelperOutput.PostContent.Append("Post Content");
|
tagHelperOutput.PostContent.Append("Post Content");
|
||||||
|
|
@ -209,12 +336,13 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
public void Attributes_IgnoresCase(string originalName, string updateName)
|
public void Attributes_IgnoresCase(string originalName, string updateName)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var tagHelperOutput = new TagHelperOutput("p",
|
var tagHelperOutput = new TagHelperOutput(
|
||||||
|
"p",
|
||||||
new TagHelperAttributeList
|
new TagHelperAttributeList
|
||||||
{
|
{
|
||||||
{ originalName, "btn" },
|
{ originalName, "btn" },
|
||||||
},
|
},
|
||||||
(cachedResult) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
|
(cachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
tagHelperOutput.Attributes[updateName] = "super button";
|
tagHelperOutput.Attributes[updateName] = "super button";
|
||||||
|
|
@ -226,5 +354,687 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
attribute,
|
attribute,
|
||||||
CaseSensitiveTagHelperAttributeComparer.Default);
|
CaseSensitiveTagHelperAttributeComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TheoryData<TagHelperOutput, string> WriteTagHelper_InputData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// parameters: TagHelperOutput, expectedOutput
|
||||||
|
return new TheoryData<TagHelperOutput, string>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// parameters: TagName, Attributes, SelfClosing, PreContent, Content, PostContent
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "div",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<div>Hello World!</div>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: string.Empty,
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"Hello World!"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: " ",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"Hello World!"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p test=\"HtmlEncode[[testVal]]\">Hello World!</p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList()
|
||||||
|
{
|
||||||
|
{ "test", "testVal" },
|
||||||
|
{ "something", " spaced " }
|
||||||
|
},
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\">Hello World!</p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList()
|
||||||
|
{
|
||||||
|
["test"] = new TagHelperAttribute
|
||||||
|
{
|
||||||
|
Name = "test",
|
||||||
|
Minimized = true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p test>Hello World!</p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList()
|
||||||
|
{
|
||||||
|
["test"] = new TagHelperAttribute
|
||||||
|
{
|
||||||
|
Name = "test",
|
||||||
|
Minimized = true
|
||||||
|
},
|
||||||
|
["test2"] = new TagHelperAttribute
|
||||||
|
{
|
||||||
|
Name = "test2",
|
||||||
|
Minimized = true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p test test2>Hello World!</p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList()
|
||||||
|
{
|
||||||
|
["first"] = "unminimized",
|
||||||
|
["test"] = new TagHelperAttribute
|
||||||
|
{
|
||||||
|
Name = "test",
|
||||||
|
Minimized = true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p first=\"HtmlEncode[[unminimized]]\" test>Hello World!</p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList()
|
||||||
|
{
|
||||||
|
["test"] = new TagHelperAttribute
|
||||||
|
{
|
||||||
|
Name = "test",
|
||||||
|
Minimized = true
|
||||||
|
},
|
||||||
|
["last"] = "unminimized",
|
||||||
|
},
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p test last=\"HtmlEncode[[unminimized]]\">Hello World!</p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p test=\"HtmlEncode[[testVal]]\" />"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList()
|
||||||
|
{
|
||||||
|
{ "test", "testVal" },
|
||||||
|
{ "something", " spaced " }
|
||||||
|
},
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\" />"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p test=\"HtmlEncode[[testVal]]\">"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList()
|
||||||
|
{
|
||||||
|
{ "test", "testVal" },
|
||||||
|
{ "something", " spaced " }
|
||||||
|
},
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\">"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: "Hello World!",
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p>Hello World!</p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: "Hello World!",
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"<p>Hello World!</p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: "Hello World!",
|
||||||
|
postElement: null),
|
||||||
|
"<p>Hello World!</p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: null),
|
||||||
|
"<p>HelloTestWorld!</p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: null,
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: null),
|
||||||
|
"<p />"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "p",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: null,
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: null),
|
||||||
|
"<p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: null),
|
||||||
|
"<custom>HelloTestWorld!</custom>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "random",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: null,
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: null),
|
||||||
|
"<random />"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "random",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: null,
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: null),
|
||||||
|
"<random>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"Before<custom></custom>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: string.Empty,
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"Before"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: string.Empty,
|
||||||
|
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"Before"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"Before<custom test=\"HtmlEncode[[testVal]]\" />"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"Before<custom />"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: string.Empty,
|
||||||
|
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"Before"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"Before<custom test=\"HtmlEncode[[testVal]]\">"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: null),
|
||||||
|
"Before<custom>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: "After"),
|
||||||
|
"<custom></custom>After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: string.Empty,
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: "After"),
|
||||||
|
"After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: string.Empty,
|
||||||
|
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: "After"),
|
||||||
|
"After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: "After"),
|
||||||
|
"<custom test=\"HtmlEncode[[testVal]]\" />After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: "After"),
|
||||||
|
"<custom />After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: string.Empty,
|
||||||
|
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: "After"),
|
||||||
|
"After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: "After"),
|
||||||
|
"<custom test=\"HtmlEncode[[testVal]]\">After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: null,
|
||||||
|
preContent: null,
|
||||||
|
content: null,
|
||||||
|
postContent: null,
|
||||||
|
postElement: "After"),
|
||||||
|
"<custom>After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: "After"),
|
||||||
|
"Before<custom>HelloTestWorld!</custom>After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: "After"),
|
||||||
|
"Before<custom test=\"HtmlEncode[[testVal]]\">HelloTestWorld!</custom>After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: "After"),
|
||||||
|
"Before<custom />After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: string.Empty,
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.SelfClosing,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: "After"),
|
||||||
|
"BeforeHelloTestWorld!After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: "custom",
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: "After"),
|
||||||
|
"Before<custom>After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: string.Empty,
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagOnly,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: "After"),
|
||||||
|
"BeforeHelloTestWorld!After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: string.Empty,
|
||||||
|
attributes: new TagHelperAttributeList(),
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: "After"),
|
||||||
|
"BeforeHelloTestWorld!After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GetTagHelperOutput(
|
||||||
|
tagName: string.Empty,
|
||||||
|
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||||
|
tagMode: TagMode.StartTagAndEndTag,
|
||||||
|
preElement: "Before",
|
||||||
|
preContent: "Hello",
|
||||||
|
content: "Test",
|
||||||
|
postContent: "World!",
|
||||||
|
postElement: "After"),
|
||||||
|
"BeforeHelloTestWorld!After"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(WriteTagHelper_InputData))]
|
||||||
|
public void WriteTo_WritesFormattedTagHelper(TagHelperOutput output, string expected)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var writer = new StringWriter();
|
||||||
|
var tagHelperExecutionContext = new TagHelperExecutionContext(
|
||||||
|
tagName: output.TagName,
|
||||||
|
tagMode: output.TagMode,
|
||||||
|
items: new Dictionary<object, object>(),
|
||||||
|
uniqueId: string.Empty,
|
||||||
|
executeChildContentAsync: () => Task.FromResult(result: true),
|
||||||
|
startTagHelperWritingScope: _ => { },
|
||||||
|
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||||
|
tagHelperExecutionContext.Output = output;
|
||||||
|
var testEncoder = new HtmlTestEncoder();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
output.WriteTo(writer, testEncoder);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, writer.ToString(), StringComparer.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TagHelperOutput GetTagHelperOutput(
|
||||||
|
string tagName,
|
||||||
|
TagHelperAttributeList attributes,
|
||||||
|
TagMode tagMode,
|
||||||
|
string preElement,
|
||||||
|
string preContent,
|
||||||
|
string content,
|
||||||
|
string postContent,
|
||||||
|
string postElement)
|
||||||
|
{
|
||||||
|
var output = new TagHelperOutput(
|
||||||
|
tagName,
|
||||||
|
attributes,
|
||||||
|
getChildContentAsync: (useCachedContent, encoder) => Task.FromResult<TagHelperContent>(
|
||||||
|
new DefaultTagHelperContent()))
|
||||||
|
{
|
||||||
|
TagMode = tagMode
|
||||||
|
};
|
||||||
|
|
||||||
|
if (preElement != null)
|
||||||
|
{
|
||||||
|
output.PreElement.AppendHtml(preElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preContent != null)
|
||||||
|
{
|
||||||
|
output.PreContent.AppendHtml(preContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content != null)
|
||||||
|
{
|
||||||
|
output.Content.AppendHtml(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (postContent != null)
|
||||||
|
{
|
||||||
|
output.PostContent.AppendHtml(postContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (postElement != null)
|
||||||
|
{
|
||||||
|
output.PostElement.AppendHtml(postElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -16,5 +16,8 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<DnxInvisibleFolder Include=".testPublish\" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -51,7 +51,7 @@ namespace TestOutput
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
WriteLiteral("2000 + ");
|
WriteLiteral("2000 + ");
|
||||||
#line 6 "BasicTagHelpers.cshtml"
|
#line 6 "BasicTagHelpers.cshtml"
|
||||||
Write(ViewBag.DefaultInterval);
|
Write(ViewBag.DefaultInterval);
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ namespace TestOutput
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
WriteLiteral("2000 + ");
|
WriteLiteral("2000 + ");
|
||||||
#line 6 "BasicTagHelpers.cshtml"
|
#line 6 "BasicTagHelpers.cshtml"
|
||||||
Write(ViewBag.DefaultInterval);
|
Write(ViewBag.DefaultInterval);
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ namespace TestOutput
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
#line 16 "ComplexTagHelpers.cshtml"
|
#line 16 "ComplexTagHelpers.cshtml"
|
||||||
WriteLiteral(checkbox);
|
WriteLiteral(checkbox);
|
||||||
|
|
||||||
|
|
@ -163,7 +163,7 @@ namespace TestOutput
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
#line 17 "ComplexTagHelpers.cshtml"
|
#line 17 "ComplexTagHelpers.cshtml"
|
||||||
WriteLiteral(true ? "checkbox" : "anything");
|
WriteLiteral(true ? "checkbox" : "anything");
|
||||||
|
|
||||||
|
|
@ -188,7 +188,7 @@ namespace TestOutput
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
#line 18 "ComplexTagHelpers.cshtml"
|
#line 18 "ComplexTagHelpers.cshtml"
|
||||||
if(true) {
|
if(true) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ WriteTo(__razor_attribute_value_writer, string.Empty);
|
||||||
, StartTagHelperWritingScope, EndTagHelperWritingScope);
|
, StartTagHelperWritingScope, EndTagHelperWritingScope);
|
||||||
__TestNamespace_InputTagHelper = CreateTagHelper<global::TestNamespace.InputTagHelper>();
|
__TestNamespace_InputTagHelper = CreateTagHelper<global::TestNamespace.InputTagHelper>();
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
WriteLiteral("prefix ");
|
WriteLiteral("prefix ");
|
||||||
#line 7 "DynamicAttributeTagHelpers.cshtml"
|
#line 7 "DynamicAttributeTagHelpers.cshtml"
|
||||||
WriteLiteral(DateTime.Now);
|
WriteLiteral(DateTime.Now);
|
||||||
|
|
@ -136,7 +136,7 @@ AddHtmlAttributeValue(" ", 210, DateTime.Now, 211, 14, false);
|
||||||
, StartTagHelperWritingScope, EndTagHelperWritingScope);
|
, StartTagHelperWritingScope, EndTagHelperWritingScope);
|
||||||
__TestNamespace_InputTagHelper = CreateTagHelper<global::TestNamespace.InputTagHelper>();
|
__TestNamespace_InputTagHelper = CreateTagHelper<global::TestNamespace.InputTagHelper>();
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
#line 9 "DynamicAttributeTagHelpers.cshtml"
|
#line 9 "DynamicAttributeTagHelpers.cshtml"
|
||||||
WriteLiteral(long.MinValue);
|
WriteLiteral(long.MinValue);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ namespace TestOutput
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
#line 6 "EscapedTagHelpers.cshtml"
|
#line 6 "EscapedTagHelpers.cshtml"
|
||||||
WriteLiteral(DateTime.Now);
|
WriteLiteral(DateTime.Now);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ namespace TestOutput
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
WriteLiteral("2000 + ");
|
WriteLiteral("2000 + ");
|
||||||
#line 8 "NestedScriptTagTagHelpers.cshtml"
|
#line 8 "NestedScriptTagTagHelpers.cshtml"
|
||||||
Write(ViewBag.DefaultInterval);
|
Write(ViewBag.DefaultInterval);
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ __TestNamespace_InputTagHelper2.IntDictionaryProperty["salt"] = 37;
|
||||||
__TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"] = "another string";
|
__TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"] = "another string";
|
||||||
__tagHelperExecutionContext.AddTagHelperAttribute("string-prefix-paprika", __TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"]);
|
__tagHelperExecutionContext.AddTagHelperAttribute("string-prefix-paprika", __TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"]);
|
||||||
__TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"] = __TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"];
|
__TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"] = __TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"];
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
WriteLiteral("literate ");
|
WriteLiteral("literate ");
|
||||||
#line 21 "PrefixedAttributeTagHelpers.cshtml"
|
#line 21 "PrefixedAttributeTagHelpers.cshtml"
|
||||||
WriteLiteral(literate);
|
WriteLiteral(literate);
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ __TestNamespace_InputTagHelper1.IntDictionaryProperty["salt"] = 37;
|
||||||
__TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"] = "another string";
|
__TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"] = "another string";
|
||||||
__tagHelperExecutionContext.AddTagHelperAttribute("string-prefix-paprika", __TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"]);
|
__tagHelperExecutionContext.AddTagHelperAttribute("string-prefix-paprika", __TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"]);
|
||||||
__TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"] = __TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"];
|
__TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"] = __TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"];
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
WriteLiteral("literate ");
|
WriteLiteral("literate ");
|
||||||
#line 21 "PrefixedAttributeTagHelpers.cshtml"
|
#line 21 "PrefixedAttributeTagHelpers.cshtml"
|
||||||
WriteLiteral(literate);
|
WriteLiteral(literate);
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ namespace TestOutput
|
||||||
, StartTagHelperWritingScope, EndTagHelperWritingScope);
|
, StartTagHelperWritingScope, EndTagHelperWritingScope);
|
||||||
__TestNamespace_MyTagHelper = CreateTagHelper<global::TestNamespace.MyTagHelper>();
|
__TestNamespace_MyTagHelper = CreateTagHelper<global::TestNamespace.MyTagHelper>();
|
||||||
__tagHelperExecutionContext.Add(__TestNamespace_MyTagHelper);
|
__tagHelperExecutionContext.Add(__TestNamespace_MyTagHelper);
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
WriteLiteral("Current Time: ");
|
WriteLiteral("Current Time: ");
|
||||||
#line 9 "TagHelpersInSection.cshtml"
|
#line 9 "TagHelpersInSection.cshtml"
|
||||||
WriteLiteral(DateTime.Now);
|
WriteLiteral(DateTime.Now);
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ __TestNamespace_PTagHelper.Age = 1337;
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
__tagHelperExecutionContext.AddTagHelperAttribute("age", __TestNamespace_PTagHelper.Age);
|
__tagHelperExecutionContext.AddTagHelperAttribute("age", __TestNamespace_PTagHelper.Age);
|
||||||
StartTagHelperWritingScope();
|
StartTagHelperWritingScope(null);
|
||||||
#line 7 "TagHelpersWithWeirdlySpacedAttributes.cshtml"
|
#line 7 "TagHelpersWithWeirdlySpacedAttributes.cshtml"
|
||||||
Write(true);
|
Write(true);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue