#20781: Fixing template alternates support

Work Item: 20781
This commit is contained in:
Sebastien Ros
2014-08-21 17:53:40 -07:00
parent cb98e31df1
commit 284891dbaa
7 changed files with 114 additions and 62 deletions

View File

@@ -10,7 +10,7 @@ Features:
Name: Templates
Description: Provides a Template type that represents a shape template, stored as a content item.
Category: Content
Dependencies: Contents, Orchard.Tokens
Dependencies: Contents, Orchard.Tokens, Orchard.Core
Orchard.Templates.Razor:
Name: Razor Templates
Description: Extends Templates with Razor templates.

View File

@@ -177,7 +177,7 @@
<Compile Include="Services\TemplateProcessorImpl.cs" />
<Compile Include="Services\RazorTemplateProcessor.cs" />
<Compile Include="Services\DefaultTemplateService.cs" />
<Compile Include="Services\TemplateShapeDisplayEvent.cs" />
<Compile Include="Services\TemplateShapeBindingResolver.cs" />
<Compile Include="Settings\ShapePartSettings.cs" />
<Compile Include="Settings\ShapePartSettingsEvents.cs" />
<Compile Include="ViewModels\ShapePartSettingsViewModel.cs" />

View File

@@ -0,0 +1,84 @@
using Orchard.Caching;
using Orchard.ContentManagement;
using Orchard.DisplayManagement.Implementation;
using Orchard.Templates.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
namespace Orchard.Templates.Services {
public class TemplateShapeBindingResolver : IShapeBindingResolver {
private ICacheManager _cacheManager;
private ISignals _signals;
private IContentManager _contentManager;
private ITemplateService _templateService;
public TemplateShapeBindingResolver(
ICacheManager cacheManager,
ISignals signals,
IContentManager contentManager,
ITemplateService templateService
) {
_cacheManager = cacheManager;
_signals = signals;
_contentManager = contentManager;
_templateService = templateService;
}
public bool TryGetDescriptorBinding(string shapeType, out ShapeBinding shapeBinding) {
var processors = BuildShapeProcessors();
Func<dynamic, IHtmlString> processor;
TemplateResult templateResult = null;
if (processors.TryGetValue(shapeType, out templateResult)) {
shapeBinding = new ShapeBinding {
BindingName = "Templates",
Binding = ctx => CoerceHtmlString(_templateService.Execute(
templateResult.Template,
templateResult.Name,
templateResult.Processor, ctx.Value))
};
return true;
}
shapeBinding = null;
return false;
}
private IDictionary<string, TemplateResult> BuildShapeProcessors() {
return _cacheManager.Get("Template.ShapeProcessors", ctx => {
ctx.Monitor(_signals.When(DefaultTemplateService.TemplatesSignal));
var allTemplates = _contentManager.Query<ShapePart>().List();
return allTemplates.Select(x => {
var name = x.Name;
var template = x.Template;
var processorName = x.ProcessorName;
return new TemplateResult {
Name = x.Name,
Template = x.Template,
Processor = x.ProcessorName
};
}).ToDictionary(x => x.Name, x => x);
});
}
private static IHtmlString CoerceHtmlString(object invoke) {
return invoke as IHtmlString ?? (invoke != null ? new HtmlString(invoke.ToString()) : null);
}
private class TemplateResult {
public string Name { get; set; }
public string Processor { get; set; }
public string Template { get; set; }
}
}
}

View File

@@ -1,59 +0,0 @@
using Orchard.Caching;
using Orchard.ContentManagement;
using Orchard.DisplayManagement.Implementation;
using Orchard.Templates.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Orchard.Templates.Services {
public class TemplateShapeDisplayEvent : IShapeDisplayEvents {
private ICacheManager _cacheManager;
private ISignals _signals;
private IContentManager _contentManager;
private ITemplateService _templateService;
public TemplateShapeDisplayEvent(
ICacheManager cacheManager,
ISignals signals,
IContentManager contentManager,
ITemplateService templateService
) {
_cacheManager = cacheManager;
_signals = signals;
_contentManager = contentManager;
_templateService = templateService;
}
public void Displaying(ShapeDisplayingContext context) {
var processors = BuildShapeProcessors();
Func<dynamic, IHtmlString> processor;
if (processors.TryGetValue(context.ShapeMetadata.Type, out processor)) {
context.ChildContent = processor(context.Shape);
}
}
public void Displayed(ShapeDisplayedContext context) {
}
public IDictionary<string, Func<dynamic, IHtmlString>> BuildShapeProcessors() {
return _cacheManager.Get("Template.ShapeProcessors", ctx => {
ctx.Monitor(_signals.When(DefaultTemplateService.TemplatesSignal));
var allTemplates = _contentManager.Query<ShapePart>().List();
return allTemplates.Select(x => new KeyValuePair<string, Func<dynamic, IHtmlString>>(
x.Name,
d => CoerceHtmlString(_templateService.Execute(x.Template, x.Name, x.ProcessorName, d))
)).ToDictionary(x => x.Key, x => x.Value);
});
}
private static IHtmlString CoerceHtmlString(object invoke) {
return invoke as IHtmlString ?? (invoke != null ? new HtmlString(invoke.ToString()) : null);
}
}
}

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Shapes;
namespace Orchard.DisplayManagement {
public interface IShapeBindingResolver : IDependency {
bool TryGetDescriptorBinding(string shapeType, out ShapeBinding shapeBinding);
}
}

View File

@@ -18,6 +18,7 @@ namespace Orchard.DisplayManagement.Implementation {
private readonly IWorkContextAccessor _workContextAccessor;
private readonly IEnumerable<IShapeDisplayEvents> _shapeDisplayEvents;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IEnumerable<IShapeBindingResolver> _shapeBindingResolvers;
// this need to be Shape instead of IShape - cast to interface throws error on clr types like HtmlString
private static readonly CallSite<Func<CallSite, object, Shape>> _convertAsShapeCallsite = CallSite<Func<CallSite, object, Shape>>.Create(
@@ -30,12 +31,15 @@ namespace Orchard.DisplayManagement.Implementation {
public DefaultDisplayManager(
IWorkContextAccessor workContextAccessor,
IEnumerable<IShapeDisplayEvents> shapeDisplayEvents,
IEnumerable<IShapeBindingResolver> shapeBindingResolvers,
IHttpContextAccessor httpContextAccessor,
Lazy<IShapeTableLocator> shapeTableLocator) {
_shapeTableLocator = shapeTableLocator;
_workContextAccessor = workContextAccessor;
_shapeDisplayEvents = shapeDisplayEvents;
_httpContextAccessor = httpContextAccessor;
_shapeBindingResolvers = shapeBindingResolvers;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
}
@@ -135,12 +139,19 @@ namespace Orchard.DisplayManagement.Implementation {
return shape.Metadata.ChildContent;
}
static bool TryGetDescriptorBinding(string shapeType, IEnumerable<string> shapeAlternates, ShapeTable shapeTable, out ShapeBinding shapeBinding) {
private bool TryGetDescriptorBinding(string shapeType, IEnumerable<string> shapeAlternates, ShapeTable shapeTable, out ShapeBinding shapeBinding) {
// shape alternates are optional, fully qualified binding names
// the earliest added alternates have the lowest priority
// the descriptor returned is based on the binding that is matched, so it may be an entirely
// different descriptor if the alternate has a different base name
foreach (var shapeAlternate in shapeAlternates.Reverse()) {
foreach (var shapeBindingResolver in _shapeBindingResolvers) {
if(shapeBindingResolver.TryGetDescriptorBinding(shapeAlternate, out shapeBinding)) {
return true;
}
}
if (shapeTable.Bindings.TryGetValue(shapeAlternate, out shapeBinding)) {
return true;
}
@@ -151,6 +162,12 @@ namespace Orchard.DisplayManagement.Implementation {
// so the shapetype itself may contain a longer alternate forms that falls back to a shorter one
var shapeTypeScan = shapeType;
for (; ; ) {
foreach (var shapeBindingResolver in _shapeBindingResolvers) {
if (shapeBindingResolver.TryGetDescriptorBinding(shapeTypeScan, out shapeBinding)) {
return true;
}
}
if (shapeTable.Bindings.TryGetValue(shapeTypeScan, out shapeBinding)) {
return true;
}

View File

@@ -211,6 +211,7 @@
<Compile Include="DisplayManagement\Implementation\IShapeDisplayEvents.cs" />
<Compile Include="DisplayManagement\Implementation\IShapeFactoryEvents.cs" />
<Compile Include="DisplayManagement\INamedEnumerable.cs" />
<Compile Include="DisplayManagement\IShapeBindingResolver.cs" />
<Compile Include="DisplayManagement\IShapeDisplay.cs" />
<Compile Include="DisplayManagement\ShapeDisplay.cs" />
<Compile Include="DisplayManagement\Shapes\Composite.cs" />