From 66aea52542f7d0e15d2f56cc1c0e219ca105e738 Mon Sep 17 00:00:00 2001 From: NTaylorMullen Date: Thu, 25 Sep 2014 01:34:21 -0700 Subject: [PATCH] Add TagHelperScopeManager for runtime. - Also added an interface ITagHelperScopeManager so we can activate the type via DI. #155 --- .../Properties/Resources.Designer.cs | 16 +++++ .../Resources.resx | 3 + ...ontext.cs => TagHelperExecutionContext.cs} | 6 +- .../TagHelpers/TagHelperRunner.cs | 6 +- .../TagHelpers/TagHelperScopeManager.cs | 64 +++++++++++++++++++ 5 files changed, 89 insertions(+), 6 deletions(-) rename src/Microsoft.AspNet.Razor.Runtime/TagHelpers/{TagHelpersExecutionContext.cs => TagHelperExecutionContext.cs} (94%) create mode 100644 src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperScopeManager.cs diff --git a/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs index 5a0fccdfdb..e9d4cc8127 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs @@ -62,6 +62,22 @@ namespace Microsoft.AspNet.Razor.Runtime return GetString("TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull"); } + /// + /// Must call '{2}.{1}' before calling '{2}.{0}'. + /// + internal static string ScopeManager_EndCannotBeCalledWithoutACallToBegin + { + get { return GetString("ScopeManager_EndCannotBeCalledWithoutACallToBegin"); } + } + + /// + /// Must call '{2}.{1}' before calling '{2}.{0}'. + /// + internal static string FormatScopeManager_EndCannotBeCalledWithoutACallToBegin(object p0, object p1, object p2) + { + return string.Format(CultureInfo.CurrentCulture, GetString("ScopeManager_EndCannotBeCalledWithoutACallToBegin"), p0, p1, p2); + } + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNet.Razor.Runtime/Resources.resx b/src/Microsoft.AspNet.Razor.Runtime/Resources.resx index 8a7d783249..89259d17d4 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/Resources.resx +++ b/src/Microsoft.AspNet.Razor.Runtime/Resources.resx @@ -128,4 +128,7 @@ Tag helper directive assembly name cannot be null or empty. + + Must call '{2}.{1}' before calling '{2}.{0}'. + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelpersExecutionContext.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperExecutionContext.cs similarity index 94% rename from src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelpersExecutionContext.cs rename to src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperExecutionContext.cs index dd58d2c723..93087fab3b 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelpersExecutionContext.cs +++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperExecutionContext.cs @@ -9,15 +9,15 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// /// Class used to store information about a 's execution lifetime. /// - public class TagHelpersExecutionContext + public class TagHelperExecutionContext { private readonly List _tagHelpers; /// - /// Instantiates a new . + /// Instantiates a new . /// /// The HTML tag name in the Razor source. - public TagHelpersExecutionContext([NotNull] string tagName) + public TagHelperExecutionContext([NotNull] string tagName) { AllAttributes = new Dictionary(StringComparer.Ordinal); HTMLAttributes = new Dictionary(StringComparer.Ordinal); diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperRunner.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperRunner.cs index a6aa597529..fd8ba3c408 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperRunner.cs +++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperRunner.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// Contains information associated with running s. /// Resulting from processing all of the /// 's s. - public async Task RunAsync([NotNull] TagHelpersExecutionContext context) + public async Task RunAsync([NotNull] TagHelperExecutionContext context) { return await RunAsyncCore(context, string.Empty); } @@ -29,13 +29,13 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// Contains the buffered content of the current HTML tag. /// Resulting from processing all of the /// 's s. - public async Task RunAsync([NotNull] TagHelpersExecutionContext context, + public async Task RunAsync([NotNull] TagHelperExecutionContext context, [NotNull] TextWriter bufferedBody) { return await RunAsyncCore(context, bufferedBody.ToString()); } - private async Task RunAsyncCore(TagHelpersExecutionContext executionContext, string outputContent) + private async Task RunAsyncCore(TagHelperExecutionContext executionContext, string outputContent) { var tagHelperContext = new TagHelperContext(executionContext.AllAttributes); var tagHelperOutput = new TagHelperOutput(executionContext.TagName, diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperScopeManager.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperScopeManager.cs new file mode 100644 index 0000000000..7ce38b69ba --- /dev/null +++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperScopeManager.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.AspNet.Razor.Runtime.TagHelpers +{ + /// + /// Class that manages scopes. + /// + public class TagHelperScopeManager + { + private readonly Stack _executionScopes; + + /// + /// Instantiates a new . + /// + public TagHelperScopeManager() + { + _executionScopes = new Stack(); + } + + /// + /// Starts a scope. + /// + /// The HTML tag name that the scope is associated with. + /// A to use. + public TagHelperExecutionContext Begin(string tagName) + { + var executionContext = new TagHelperExecutionContext(tagName); + + _executionScopes.Push(executionContext); + + return executionContext; + } + + /// + /// Ends a scope. + /// + /// If the current scope is nested, the parent . + /// null otherwise. + public TagHelperExecutionContext End() + { + if (_executionScopes.Count == 0) + { + throw new InvalidOperationException( + Resources.FormatScopeManager_EndCannotBeCalledWithoutACallToBegin( + nameof(End), + nameof(Begin), + nameof(TagHelperScopeManager))); + } + + _executionScopes.Pop(); + + if (_executionScopes.Count != 0) + { + return _executionScopes.Peek(); + } + + return null; + } + } +} \ No newline at end of file