From a992c1e74edadc11bf3a9e887bfe1a154369d727 Mon Sep 17 00:00:00 2001 From: Carl Woodhouse Date: Thu, 7 Sep 2017 20:40:49 +0100 Subject: [PATCH] Made shape placement parsing strategy extendable with providers (#7837) --- .../DefaultShapeTableManagerTests.cs | 5 +- .../DefaultPlacementParseMatchProviders.cs | 57 +++++++++++++++++++ .../IPlacementParseMatchProvider.cs | 6 ++ .../ShapePlacementParsingStrategy.cs | 47 ++++++--------- src/Orchard/Orchard.Framework.csproj | 2 + 5 files changed, 85 insertions(+), 32 deletions(-) create mode 100644 src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/DefaultPlacementParseMatchProviders.cs create mode 100644 src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/IPlacementParseMatchProvider.cs diff --git a/src/Orchard.Tests/DisplayManagement/Descriptors/DefaultShapeTableManagerTests.cs b/src/Orchard.Tests/DisplayManagement/Descriptors/DefaultShapeTableManagerTests.cs index 5f2f210ba..70a847561 100644 --- a/src/Orchard.Tests/DisplayManagement/Descriptors/DefaultShapeTableManagerTests.cs +++ b/src/Orchard.Tests/DisplayManagement/Descriptors/DefaultShapeTableManagerTests.cs @@ -247,7 +247,10 @@ namespace Orchard.Tests.DisplayManagement.Descriptors { _container.Resolve().Discover = builder => builder.Describe("Hello").From(TestFeature()) - .Placement(ShapePlacementParsingStrategy.BuildPredicate(c => true, new KeyValuePair("Path", path)), new PlacementInfo { Location = "Match" }); + .Placement(ShapePlacementParsingStrategy.BuildPredicate(c => true, + new KeyValuePair("Path", path), + new[] { new PathPlacementParseMatchProvider() }), + new PlacementInfo { Location = "Match" }); var manager = _container.Resolve(); var hello = manager.GetShapeTable(null).Descriptors["Hello"]; diff --git a/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/DefaultPlacementParseMatchProviders.cs b/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/DefaultPlacementParseMatchProviders.cs new file mode 100644 index 000000000..e3b5257ba --- /dev/null +++ b/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/DefaultPlacementParseMatchProviders.cs @@ -0,0 +1,57 @@ +using System; +using System.Linq; +using System.Web; + +namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy { + public class ContentPartPlacementParseMatchProvider : IPlacementParseMatchProvider { + public string Key { get { return "ContentPart"; } } + + public bool Match(ShapePlacementContext context, string expression) { + return context.Content != null && context.Content.ContentItem.Parts.Any(part => part.PartDefinition.Name == expression); + } + } + + public class ContentTypePlacementParseMatchProvider : IPlacementParseMatchProvider { + public string Key { get { return "ContentType"; } } + + public bool Match(ShapePlacementContext context, string expression) { + if (expression.EndsWith("*")) { + var prefix = expression.Substring(0, expression.Length - 1); + return (context.ContentType ?? "").StartsWith(prefix) || (context.Stereotype ?? "").StartsWith(prefix); + } + + return context.ContentType == expression || context.Stereotype == expression; + } + } + + public class DisplayTypePlacementParseMatchProvider : IPlacementParseMatchProvider { + public string Key { get { return "DisplayType"; } } + + public bool Match(ShapePlacementContext context, string expression) { + if (expression.EndsWith("*")) { + var prefix = expression.Substring(0, expression.Length - 1); + return (context.DisplayType ?? "").StartsWith(prefix); + } + + return context.DisplayType == expression; + } + } + + public class PathPlacementParseMatchProvider : IPlacementParseMatchProvider { + public string Key { get { return "Path"; } } + + public bool Match(ShapePlacementContext context, string expression) { + var normalizedPath = VirtualPathUtility.IsAbsolute(expression) + ? VirtualPathUtility.ToAppRelative(expression) + : VirtualPathUtility.Combine("~/", expression); + + if (normalizedPath.EndsWith("*")) { + var prefix = normalizedPath.Substring(0, normalizedPath.Length - 1); + return VirtualPathUtility.ToAppRelative(string.IsNullOrEmpty(context.Path) ? "/" : context.Path).StartsWith(prefix, StringComparison.OrdinalIgnoreCase); + } + + normalizedPath = VirtualPathUtility.AppendTrailingSlash(normalizedPath); + return context.Path.Equals(normalizedPath, StringComparison.OrdinalIgnoreCase); + } + } +} diff --git a/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/IPlacementParseMatchProvider.cs b/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/IPlacementParseMatchProvider.cs new file mode 100644 index 000000000..e1e14c87a --- /dev/null +++ b/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/IPlacementParseMatchProvider.cs @@ -0,0 +1,6 @@ +namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy { + public interface IPlacementParseMatchProvider : IDependency { + string Key { get; } + bool Match(ShapePlacementContext context, string expression); + } +} diff --git a/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/ShapePlacementParsingStrategy.cs b/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/ShapePlacementParsingStrategy.cs index 5b27a8ad2..9aa489de4 100644 --- a/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/ShapePlacementParsingStrategy.cs +++ b/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/ShapePlacementParsingStrategy.cs @@ -2,7 +2,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; -using System.Web; using Orchard.Environment.Descriptor.Models; using Orchard.Environment.Extensions; using Orchard.Environment.Extensions.Models; @@ -15,14 +14,17 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy { private readonly IExtensionManager _extensionManager; private readonly ShellDescriptor _shellDescriptor; private readonly IPlacementFileParser _placementFileParser; + private readonly IEnumerable _placementParseMatchProviders; public ShapePlacementParsingStrategy( IExtensionManager extensionManager, ShellDescriptor shellDescriptor, - IPlacementFileParser placementFileParser) { + IPlacementFileParser placementFileParser, + IEnumerable placementParseMatchProviders) { _extensionManager = extensionManager; _shellDescriptor = shellDescriptor; _placementFileParser = placementFileParser; + _placementParseMatchProviders = placementParseMatchProviders; } public void Discover(ShapeTableBuilder builder) { @@ -125,37 +127,20 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy { } } - public static Func BuildPredicate(Func predicate, KeyValuePair term) { - var expression = term.Value; - switch (term.Key) { - case "ContentPart": - return ctx => ctx.Content != null - && ctx.Content.ContentItem.Parts.Any(part => part.PartDefinition.Name == expression) - && predicate(ctx); - case "ContentType": - if (expression.EndsWith("*")) { - var prefix = expression.Substring(0, expression.Length - 1); - return ctx => ((ctx.ContentType ?? "").StartsWith(prefix) || (ctx.Stereotype ?? "").StartsWith(prefix)) && predicate(ctx); - } - return ctx => ((ctx.ContentType == expression) || (ctx.Stereotype == expression)) && predicate(ctx); - case "DisplayType": - if (expression.EndsWith("*")) { - var prefix = expression.Substring(0, expression.Length - 1); - return ctx => (ctx.DisplayType ?? "").StartsWith(prefix) && predicate(ctx); - } - return ctx => (ctx.DisplayType == expression) && predicate(ctx); - case "Path": - var normalizedPath = VirtualPathUtility.IsAbsolute(expression) - ? VirtualPathUtility.ToAppRelative(expression) - : VirtualPathUtility.Combine("~/", expression); + private Func BuildPredicate(Func predicate, + KeyValuePair term) { + return BuildPredicate(predicate, term, _placementParseMatchProviders); + } - if (normalizedPath.EndsWith("*")) { - var prefix = normalizedPath.Substring(0, normalizedPath.Length - 1); - return ctx => VirtualPathUtility.ToAppRelative(String.IsNullOrEmpty(ctx.Path) ? "/" : ctx.Path).StartsWith(prefix, StringComparison.OrdinalIgnoreCase) && predicate(ctx); - } + public static Func BuildPredicate(Func predicate, + KeyValuePair term, IEnumerable placementMatchProviders) { - normalizedPath = VirtualPathUtility.AppendTrailingSlash(normalizedPath); - return ctx => (ctx.Path.Equals(normalizedPath, StringComparison.OrdinalIgnoreCase)) && predicate(ctx); + if (placementMatchProviders != null) { + var providersForTerm = placementMatchProviders.Where(x => x.Key.Equals(term.Key)); + if (providersForTerm.Any()) { + var expression = term.Value; + return ctx => providersForTerm.Any(x => x.Match(ctx, expression)) && predicate(ctx); + } } return predicate; } diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 7f33ef116..c10eb9820 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -176,6 +176,8 @@ + +