Skip to content

Commit

Permalink
Add IShapePlacementProvider and ShapeTablePlacementProvider (#6780)
Browse files Browse the repository at this point in the history
  • Loading branch information
TFleury committed Aug 24, 2020
1 parent 3ba0002 commit 7bc7ff0
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.Layout;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Theming;
using OrchardCore.Modules;

namespace OrchardCore.ContentTypes.Editors
Expand All @@ -20,7 +19,6 @@ public class DefaultContentDefinitionDisplayManager : BaseDisplayManager, IConte
private readonly IShapeTableManager _shapeTableManager;
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IShapeFactory _shapeFactory;
private readonly IThemeManager _themeManager;
private readonly ILayoutAccessor _layoutAccessor;
private readonly ILogger _logger;

Expand All @@ -29,16 +27,15 @@ public DefaultContentDefinitionDisplayManager(
IShapeTableManager shapeTableManager,
IContentDefinitionManager contentDefinitionManager,
IShapeFactory shapeFactory,
IThemeManager themeManager,
IEnumerable<IShapePlacementProvider> placementProviders,
ILogger<DefaultContentDefinitionDisplayManager> logger,
ILayoutAccessor layoutAccessor
) : base(shapeTableManager, shapeFactory, themeManager)
) : base(shapeFactory, placementProviders)
{
_handlers = handlers;
_shapeTableManager = shapeTableManager;
_contentDefinitionManager = contentDefinitionManager;
_shapeFactory = shapeFactory;
_themeManager = themeManager;
_layoutAccessor = layoutAccessor;
_logger = logger;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
Expand All @@ -8,7 +9,6 @@
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.Layout;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Theming;
using OrchardCore.Workflows.Activities;
using OrchardCore.Workflows.Helpers;
using OrchardCore.Workflows.Options;
Expand All @@ -18,10 +18,16 @@ namespace OrchardCore.Workflows.Services
public class ActivityDisplayManager : IActivityDisplayManager
{
private readonly DisplayManager<IActivity> _displayManager;
public ActivityDisplayManager(IOptions<WorkflowOptions> workflowOptions, IServiceProvider serviceProvider, IShapeTableManager shapeTableManager, IShapeFactory shapeFactory, IThemeManager themeManager, ILogger<DisplayManager<IActivity>> displayManagerLogger, ILayoutAccessor layoutAccessor)
public ActivityDisplayManager(
IOptions<WorkflowOptions> workflowOptions,
IServiceProvider serviceProvider,
IShapeFactory shapeFactory,
IEnumerable<IShapePlacementProvider> placementProviders,
ILogger<DisplayManager<IActivity>> displayManagerLogger,
ILayoutAccessor layoutAccessor)
{
var drivers = workflowOptions.Value.ActivityDisplayDriverTypes.Select(x => serviceProvider.CreateInstance<IDisplayDriver<IActivity>>(x));
_displayManager = new DisplayManager<IActivity>(drivers, shapeTableManager, shapeFactory, themeManager, displayManagerLogger, layoutAccessor);
_displayManager = new DisplayManager<IActivity>(drivers, shapeFactory, placementProviders, displayManagerLogger, layoutAccessor);
}

public Task<IShape> BuildDisplayAsync(IActivity model, IUpdateModel updater, string displayType = "", string groupId = "")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
using OrchardCore.DisplayManagement.Layout;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Shapes;
using OrchardCore.DisplayManagement.Theming;
using OrchardCore.Modules;

namespace OrchardCore.ContentManagement.Display
Expand All @@ -31,7 +30,6 @@ public class ContentItemDisplayManager : BaseDisplayManager, IContentItemDisplay
private readonly IShapeTableManager _shapeTableManager;
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IShapeFactory _shapeFactory;
private readonly IThemeManager _themeManager;
private readonly ILayoutAccessor _layoutAccessor;
private readonly ILogger _logger;

Expand All @@ -41,17 +39,16 @@ public ContentItemDisplayManager(
IShapeTableManager shapeTableManager,
IContentDefinitionManager contentDefinitionManager,
IShapeFactory shapeFactory,
IThemeManager themeManager,
IEnumerable<IShapePlacementProvider> placementProviders,
ILogger<ContentItemDisplayManager> logger,
ILayoutAccessor layoutAccessor
) : base(shapeTableManager, shapeFactory, themeManager)
) : base(shapeFactory, placementProviders)
{
_handlers = handlers;
_contentHandlers = contentHandlers;
_shapeTableManager = shapeTableManager;
_contentDefinitionManager = contentDefinitionManager;
_shapeFactory = shapeFactory;
_themeManager = themeManager;
_layoutAccessor = layoutAccessor;
_logger = logger;
}
Expand Down
89 changes: 61 additions & 28 deletions src/OrchardCore/OrchardCore.DisplayManagement/BaseDisplayManager.cs
Original file line number Diff line number Diff line change
@@ -1,45 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using OrchardCore.DisplayManagement.Descriptors;
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.Theming;
using OrchardCore.DisplayManagement.Shapes;
using OrchardCore.DisplayManagement.Zones;

namespace OrchardCore.DisplayManagement
{
public abstract class BaseDisplayManager
{
private readonly IShapeTableManager _shapeTableManager;
private readonly IShapeFactory _shapeFactory;
private readonly IThemeManager _themeManager;
private readonly IEnumerable<IShapePlacementProvider> _placementProviders;

public BaseDisplayManager(
IShapeTableManager shapeTableManager,
IShapeFactory shapeFactory,
IThemeManager themeManager
IEnumerable<IShapePlacementProvider> placementProviders
)
{
_shapeTableManager = shapeTableManager;
_shapeFactory = shapeFactory;
_themeManager = themeManager;
_placementProviders = placementProviders;
}

protected async Task BindPlacementAsync(IBuildShapeContext context)
{
var theme = await _themeManager.GetThemeAsync();
var resolvers = new List<IPlacementInfoResolver>();

// If there is no active theme, do nothing
if (theme == null)
foreach (var provider in _placementProviders)
{
return;
}
var resolver = await provider.BuildPlacementInfoResolverAsync(context);

var shapeTable = _shapeTableManager.GetShapeTable(theme.Id);
if (resolver != null)
{
resolvers.Add(resolver);
}
}

context.FindPlacement = (shapeType, differentiator, displayType, displayContext) => FindPlacementImpl(shapeTable, shapeType, differentiator, displayType, context);
context.FindPlacement = (shapeType, differentiator, displayType, displayContext) => FindPlacementImpl(resolvers, shapeType, differentiator, displayType, context);
}

private static PlacementInfo FindPlacementImpl(ShapeTable shapeTable, string shapeType, string differentiator, string displayType, IBuildShapeContext context)
private static PlacementInfo FindPlacementImpl(IList<IPlacementInfoResolver> placementResolvers, string shapeType, string differentiator, string displayType, IBuildShapeContext context)
{
var delimiterIndex = shapeType.IndexOf("__", StringComparison.Ordinal);

Expand All @@ -48,24 +49,56 @@ private static PlacementInfo FindPlacementImpl(ShapeTable shapeTable, string sha
shapeType = shapeType.Substring(0, delimiterIndex);
}

if (shapeTable.Descriptors.TryGetValue(shapeType, out var descriptor))
{
var placementContext = new ShapePlacementContext(
shapeType,
displayType,
differentiator,
context.Shape
);
var placementContext = new ShapePlacementContext(
shapeType,
displayType,
differentiator,
context.Shape
);

var placement = descriptor.Placement(placementContext);
if (placement != null)
return placementResolvers.Aggregate<IPlacementInfoResolver, PlacementInfo>(null, (prev, resolver) =>
CombinePlacements(prev, resolver.ResolvePlacement(placementContext))
);
}

private static PlacementInfo CombinePlacements(PlacementInfo first, PlacementInfo second)
{
if (first == null)
{
return second;
}
else if (second != null)
{
CombineAlternates(first.Alternates, second.Alternates);
CombineAlternates(first.Wrappers, second.Wrappers);
if (!String.IsNullOrEmpty(second.ShapeType))
{
placement.Source = placementContext.Source;
return placement;
first.ShapeType = second.ShapeType;
}
if (!String.IsNullOrEmpty(second.Location))
{
first.Location = second.Location;
}
if (!String.IsNullOrEmpty(second.DefaultPosition))
{
first.DefaultPosition = second.DefaultPosition;
}
first.Source += "," + second.Source;
}
return first;
}

return null;
private static AlternatesCollection CombineAlternates(AlternatesCollection first, AlternatesCollection second)
{
if (first == null)
{
return second;
}
else if (second != null)
{
first.AddRange(second);
}
return first;
}

protected ValueTask<IShape> CreateContentShapeAsync(string actualShapeType)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using OrchardCore.DisplayManagement.Handlers;

namespace OrchardCore.DisplayManagement.Descriptors
{
Expand Down Expand Up @@ -33,4 +35,30 @@ public static IServiceCollection AddShapeAttributes<T>(this IServiceCollection s
return services;
}
}

/// <summary>
/// Represents a marker interface for classes that provide Shape placement informations
/// </summary>
public interface IShapePlacementProvider
{
/// <summary>
/// Builds a contextualized <see cref="IPlacementInfoResolver"/>
/// </summary>
/// <param name="context">The <see cref="IBuildShapeContext"/> for which we need a placement resolver</param>
/// <returns>An instance of <see cref="IPlacementInfoResolver"/> for the current context or <see cref="null"/> if this provider is not concerned.</returns>
Task<IPlacementInfoResolver> BuildPlacementInfoResolverAsync(IBuildShapeContext context);
}

/// <summary>
/// Represents a class capable of resolving <see cref="PlacementInfo"/> of Shapes
/// </summary>
public interface IPlacementInfoResolver
{
/// <summary>
/// Resolves <see cref="PlacementInfo"/> for the provided <see cref="ShapePlacementContext"/>
/// </summary>
/// <param name="placementContext">The <see cref="ShapePlacementContext"/></param>
/// <returns>An <see cref="PlacementInfo"/> or <see cref="null"/> if not concerned.</returns>
PlacementInfo ResolvePlacement(ShapePlacementContext placementContext);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Threading.Tasks;
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.Theming;

namespace OrchardCore.DisplayManagement.Descriptors
{
public class ShapeTablePlacementProvider : IShapePlacementProvider
{
private readonly IShapeTableManager _shapeTableManager;
private readonly IThemeManager _themeManager;

public ShapeTablePlacementProvider(
IShapeTableManager shapeTableManager,
IThemeManager themeManager
)
{
_shapeTableManager = shapeTableManager;
_themeManager = themeManager;
}

public async Task<IPlacementInfoResolver> BuildPlacementInfoResolverAsync(IBuildShapeContext context)
{
var theme = await _themeManager.GetThemeAsync();

// If there is no active theme, do nothing
if (theme == null)
{
return null;
}

var shapeTable = _shapeTableManager.GetShapeTable(theme.Id);

return new ShapeTablePlacementResolver(shapeTable);
}

private class ShapeTablePlacementResolver : IPlacementInfoResolver
{
private readonly ShapeTable _shapeTable;

internal ShapeTablePlacementResolver(ShapeTable shapeTable)
{
_shapeTable = shapeTable;
}

public PlacementInfo ResolvePlacement(ShapePlacementContext placementContext)
{
if (_shapeTable.Descriptors.TryGetValue(placementContext.ShapeType, out var descriptor))
{
var placement = descriptor.Placement(placementContext);
if (placement != null)
{
placement.Source = placementContext.Source;
return placement;
}
}

return null;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.Layout;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Theming;
using OrchardCore.Modules;

namespace OrchardCore.DisplayManagement
Expand All @@ -19,12 +18,11 @@ public class DisplayManager<TModel> : BaseDisplayManager, IDisplayManager<TModel

public DisplayManager(
IEnumerable<IDisplayDriver<TModel>> drivers,
IShapeTableManager shapeTableManager,
IShapeFactory shapeFactory,
IThemeManager themeManager,
IEnumerable<IShapePlacementProvider> placementProviders,
ILogger<DisplayManager<TModel>> logger,
ILayoutAccessor layoutAccessor
) : base(shapeTableManager, shapeFactory, themeManager)
) : base(shapeFactory, placementProviders)
{
_shapeFactory = shapeFactory;
_layoutAccessor = layoutAccessor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
using OrchardCore.DisplayManagement.Descriptors;
using OrchardCore.DisplayManagement.Descriptors;

namespace OrchardCore.DisplayManagement.Handlers
{
/// <summary>
/// A function that provides a <see cref="PlacementInfo"/> instance for a shape.
/// </summary>
/// <param name="shape">The shape to render.</param>
/// <param name="shapeType">The shape type to render.</param>
/// <param name="differentiator">
/// A discriminator that differentiates this specific shape to the others of the same type.
/// For instance multiple field shape smight be displayed in different locations even though
/// they are of the same type.
/// </param>
/// <param name="displayType">The display type the content item owning the shape is rendered with.</param>
/// <param name="context">The <see cref="IBuildShapeContext"/> in which the shape is placed.</param>
/// <returns>The <see cref="PlacementInfo"/> to use or <see cref="null"/> if this function is not concerned.</returns>
public delegate PlacementInfo FindPlacementDelegate(string shapeType, string differentiator, string displayType, IBuildShapeContext context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public static OrchardCoreBuilder AddTheming(this OrchardCoreBuilder builder)
services.AddScoped<IPlacementNodeFilterProvider, PathPlacementNodeFilterProvider>();
services.AddScoped<IShapePlacementProvider, ShapeTablePlacementProvider>();
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<ShapeTemplateOptions>, ShapeTemplateOptionsSetup>());
services.TryAddSingleton<IShapeTemplateFileProviderAccessor, ShapeTemplateFileProviderAccessor>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ private async Task ApplyImplementationAsync(BuildShapeContext context, string di
_defaultLocation = context.DefaultZone;
}

// Look into specific implementations of placements (like placement.json files)
// Look into specific implementations of placements (like placement.json files and IShapePlacementProviders)
var placement = context.FindPlacement(_shapeType, _differentiator, displayType, context);

// Look for mapped display type locations
Expand Down

0 comments on commit 7bc7ff0

Please sign in to comment.