Add @tagHelperPrefix inheritance support.
- Updated some naming bits that were outdated (referring to ViewStart). - Added a TagHelperDirective merging mechanic to ensure user file descriptors and inherited descriptors come together correctly. #2110
This commit is contained in:
parent
f05520602f
commit
f49d52b5fc
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A subtype of <see cref="RazorParser"/> that <see cref="MvcRazorHost"/> uses to support inheritance of tag
|
/// A subtype of <see cref="RazorParser"/> that <see cref="MvcRazorHost"/> uses to support inheritance of tag
|
||||||
/// helpers from <c>_ViewStart</c> files.
|
/// helpers from <c>_GlobalImport</c> files.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MvcRazorParser : RazorParser
|
public class MvcRazorParser : RazorParser
|
||||||
{
|
{
|
||||||
|
|
@ -27,16 +27,19 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="parser">The <see cref="RazorParser"/> to copy properties from.</param>
|
/// <param name="parser">The <see cref="RazorParser"/> to copy properties from.</param>
|
||||||
/// <param name="inheritedCodeTrees">The <see cref="IReadOnlyList{CodeTree}"/>s that are inherited
|
/// <param name="inheritedCodeTrees">The <see cref="IReadOnlyList{CodeTree}"/>s that are inherited
|
||||||
/// from parsed pages from _ViewStart files.</param>
|
/// from parsed pages from _GlobalImport files.</param>
|
||||||
/// <param name="defaultInheritedChunks">The <see cref="IReadOnlyList{Chunk}"/> inherited by
|
/// <param name="defaultInheritedChunks">The <see cref="IReadOnlyList{Chunk}"/> inherited by
|
||||||
/// default by all Razor pages in the application.</param>
|
/// default by all Razor pages in the application.</param>
|
||||||
public MvcRazorParser([NotNull] RazorParser parser,
|
public MvcRazorParser(
|
||||||
[NotNull] IReadOnlyList<CodeTree> inheritedCodeTrees,
|
[NotNull] RazorParser parser,
|
||||||
[NotNull] IReadOnlyList<Chunk> defaultInheritedChunks)
|
[NotNull] IReadOnlyList<CodeTree> inheritedCodeTrees,
|
||||||
|
[NotNull] IReadOnlyList<Chunk> defaultInheritedChunks)
|
||||||
: base(parser)
|
: base(parser)
|
||||||
{
|
{
|
||||||
// Construct tag helper descriptors from @addTagHelper and @removeTagHelper chunks
|
// Construct tag helper descriptors from @addTagHelper, @removeTagHelper and @tagHelperPrefix chunks
|
||||||
_globalImportDirectiveDescriptors = GetTagHelperDirectiveDescriptors(inheritedCodeTrees, defaultInheritedChunks);
|
_globalImportDirectiveDescriptors = GetTagHelperDirectiveDescriptors(
|
||||||
|
inheritedCodeTrees,
|
||||||
|
defaultInheritedChunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -44,7 +47,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
[NotNull] Block documentRoot,
|
[NotNull] Block documentRoot,
|
||||||
[NotNull] ParserErrorSink errorSink)
|
[NotNull] ParserErrorSink errorSink)
|
||||||
{
|
{
|
||||||
var visitor = new GlobalImportAddRemoveTagHelperVisitor(
|
var visitor = new GlobalImportTagHelperDirectiveSpanVisitor(
|
||||||
TagHelperDescriptorResolver,
|
TagHelperDescriptorResolver,
|
||||||
_globalImportDirectiveDescriptors,
|
_globalImportDirectiveDescriptors,
|
||||||
errorSink);
|
errorSink);
|
||||||
|
|
@ -58,43 +61,63 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
var descriptors = new List<TagHelperDirectiveDescriptor>();
|
var descriptors = new List<TagHelperDirectiveDescriptor>();
|
||||||
|
|
||||||
// For tag helpers, the @removeTagHelper only applies tag helpers that were added prior to it.
|
// For tag helpers, the @removeTagHelper only applies tag helpers that were added prior to it.
|
||||||
// Consequently we must visit tag helpers outside-in - furthest _ViewStart first and nearest one last. This
|
// Consequently we must visit tag helpers outside-in - furthest _GlobalImport first and nearest one last.
|
||||||
// is different from the behavior of chunk merging where we visit the nearest one first and ignore chunks
|
// This is different from the behavior of chunk merging where we visit the nearest one first and ignore
|
||||||
// that were previously visited.
|
// chunks that were previously visited.
|
||||||
var chunksFromViewStarts = inheritedCodeTrees.Reverse()
|
var chunksFromGlobalImports = inheritedCodeTrees
|
||||||
.SelectMany(tree => tree.Chunks);
|
.Reverse()
|
||||||
var chunksInOrder = defaultInheritedChunks.Concat(chunksFromViewStarts);
|
.SelectMany(tree => tree.Chunks);
|
||||||
|
var chunksInOrder = defaultInheritedChunks.Concat(chunksFromGlobalImports);
|
||||||
foreach (var chunk in chunksInOrder)
|
foreach (var chunk in chunksInOrder)
|
||||||
{
|
{
|
||||||
var addHelperChunk = chunk as AddTagHelperChunk;
|
// All TagHelperDirectiveDescriptors created here have undefined source locations because the source
|
||||||
if (addHelperChunk != null)
|
// that created them is not in the same file.
|
||||||
|
var addTagHelperChunk = chunk as AddTagHelperChunk;
|
||||||
|
if (addTagHelperChunk != null)
|
||||||
{
|
{
|
||||||
var descriptor = new TagHelperDirectiveDescriptor(addHelperChunk.LookupText,
|
var descriptor = new TagHelperDirectiveDescriptor(
|
||||||
SourceLocation.Undefined,
|
addTagHelperChunk.LookupText,
|
||||||
TagHelperDirectiveType.AddTagHelper);
|
SourceLocation.Undefined,
|
||||||
|
TagHelperDirectiveType.AddTagHelper);
|
||||||
|
|
||||||
descriptors.Add(descriptor);
|
descriptors.Add(descriptor);
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
var removeTagHelperChunk = chunk as RemoveTagHelperChunk;
|
||||||
|
if (removeTagHelperChunk != null)
|
||||||
{
|
{
|
||||||
var removeHelperChunk = chunk as RemoveTagHelperChunk;
|
var descriptor = new TagHelperDirectiveDescriptor(
|
||||||
if (removeHelperChunk != null)
|
removeTagHelperChunk.LookupText,
|
||||||
{
|
SourceLocation.Undefined,
|
||||||
var descriptor = new TagHelperDirectiveDescriptor(removeHelperChunk.LookupText,
|
TagHelperDirectiveType.RemoveTagHelper);
|
||||||
SourceLocation.Undefined,
|
|
||||||
TagHelperDirectiveType.RemoveTagHelper);
|
descriptors.Add(descriptor);
|
||||||
descriptors.Add(descriptor);
|
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tagHelperPrefixDirectiveChunk = chunk as TagHelperPrefixDirectiveChunk;
|
||||||
|
if (tagHelperPrefixDirectiveChunk != null)
|
||||||
|
{
|
||||||
|
var descriptor = new TagHelperDirectiveDescriptor(
|
||||||
|
tagHelperPrefixDirectiveChunk.Prefix,
|
||||||
|
SourceLocation.Undefined,
|
||||||
|
TagHelperDirectiveType.TagHelperPrefix);
|
||||||
|
|
||||||
|
descriptors.Add(descriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return descriptors;
|
return descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class GlobalImportAddRemoveTagHelperVisitor : TagHelperDirectiveSpanVisitor
|
private class GlobalImportTagHelperDirectiveSpanVisitor : TagHelperDirectiveSpanVisitor
|
||||||
{
|
{
|
||||||
private readonly IEnumerable<TagHelperDirectiveDescriptor> _globalImportDirectiveDescriptors;
|
private readonly IEnumerable<TagHelperDirectiveDescriptor> _globalImportDirectiveDescriptors;
|
||||||
|
|
||||||
public GlobalImportAddRemoveTagHelperVisitor(
|
public GlobalImportTagHelperDirectiveSpanVisitor(
|
||||||
ITagHelperDescriptorResolver descriptorResolver,
|
ITagHelperDescriptorResolver descriptorResolver,
|
||||||
IEnumerable<TagHelperDirectiveDescriptor> globalImportDirectiveDescriptors,
|
IEnumerable<TagHelperDirectiveDescriptor> globalImportDirectiveDescriptors,
|
||||||
ParserErrorSink errorSink)
|
ParserErrorSink errorSink)
|
||||||
|
|
@ -107,9 +130,43 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
IEnumerable<TagHelperDirectiveDescriptor> descriptors,
|
IEnumerable<TagHelperDirectiveDescriptor> descriptors,
|
||||||
ParserErrorSink errorSink)
|
ParserErrorSink errorSink)
|
||||||
{
|
{
|
||||||
return base.GetTagHelperDescriptorResolutionContext(
|
var directivesToImport = MergeDirectiveDescriptors(descriptors, _globalImportDirectiveDescriptors);
|
||||||
_globalImportDirectiveDescriptors.Concat(descriptors),
|
|
||||||
errorSink);
|
return base.GetTagHelperDescriptorResolutionContext(directivesToImport, errorSink);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TagHelperDirectiveDescriptor> MergeDirectiveDescriptors(
|
||||||
|
IEnumerable<TagHelperDirectiveDescriptor> descriptors,
|
||||||
|
IEnumerable<TagHelperDirectiveDescriptor> inheritedDescriptors)
|
||||||
|
{
|
||||||
|
var mergedDescriptors = new List<TagHelperDirectiveDescriptor>();
|
||||||
|
TagHelperDirectiveDescriptor prefixDirectiveDescriptor = null;
|
||||||
|
|
||||||
|
foreach (var descriptor in inheritedDescriptors)
|
||||||
|
{
|
||||||
|
if (descriptor.DirectiveType == TagHelperDirectiveType.TagHelperPrefix)
|
||||||
|
{
|
||||||
|
// Always take the latest @tagHelperPrefix descriptor. Can only have 1 per page.
|
||||||
|
prefixDirectiveDescriptor = descriptor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mergedDescriptors.Add(descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to see if the provided descriptors contain a @tagHelperPrefix directive. If so, it
|
||||||
|
// takes precedence and overrides any provided by the inheritedDescriptors. If not we need to add the
|
||||||
|
// inherited @tagHelperPrefix directive back into the merged list.
|
||||||
|
if (prefixDirectiveDescriptor != null &&
|
||||||
|
!descriptors.Any(descriptor => descriptor.DirectiveType == TagHelperDirectiveType.TagHelperPrefix))
|
||||||
|
{
|
||||||
|
mergedDescriptors.Add(prefixDirectiveDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
mergedDescriptors.AddRange(descriptors);
|
||||||
|
|
||||||
|
return mergedDescriptors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue