Adding an array of alternate shapes to shapemetadata

ShapeMetadata.Alternates may be accumulated at any time after the shape is created
Most recently added alternate has highest priority
Alternates may target longer shape variations by appending something context specific to the base name
The alternate may match a shape binding name that is part of a different descriptor

--HG--
branch : dev
extra : rebase_source : 864892c019dbf2a7bd1c33c71bb01be3068b5081
This commit is contained in:
Louis DeJardin
2010-10-05 17:45:22 -07:00
parent 16feca6be1
commit 48a615e597
5 changed files with 72 additions and 14 deletions

View File

@@ -20,7 +20,10 @@ namespace Orchard.Tests.DisplayManagement {
WorkContext _workContext;
protected override void Register(Autofac.ContainerBuilder builder) {
_defaultShapeTable = new ShapeTable { Descriptors = new Dictionary<string, ShapeDescriptor>() };
_defaultShapeTable = new ShapeTable {
Descriptors = new Dictionary<string, ShapeDescriptor>(),
Bindings = new Dictionary<string, ShapeBinding>()
};
_workContext = new TestWorkContext {
CurrentTheme = new Theme { ThemeName = "Hello" }
};
@@ -85,11 +88,10 @@ namespace Orchard.Tests.DisplayManagement {
public IContainerProvider ContainerProvider { get; set; }
public override T Resolve<T>() {
if (typeof(T) == typeof(ILifetimeScope))
{
return (T) ContainerProvider.RequestLifetime;
if (typeof(T) == typeof(ILifetimeScope)) {
return (T)ContainerProvider.RequestLifetime;
}
throw new NotImplementedException();
}
@@ -104,8 +106,10 @@ namespace Orchard.Tests.DisplayManagement {
}
void AddShapeDescriptor(ShapeDescriptor shapeDescriptor) {
_defaultShapeTable.Descriptors[shapeDescriptor.ShapeType] = shapeDescriptor;
foreach (var binding in shapeDescriptor.Bindings) {
_defaultShapeTable.Descriptors[binding.Key] = shapeDescriptor;
binding.Value.ShapeDescriptor = shapeDescriptor;
_defaultShapeTable.Bindings[binding.Key] = binding.Value;
}
}
@@ -163,7 +167,7 @@ namespace Orchard.Tests.DisplayManagement {
}
[Test]
public void RenderAlternateShape() {
public void RenderAlternateShapeExplicitly() {
var displayManager = _container.Resolve<IDisplayManager>();
var shape = new Shape {
@@ -188,5 +192,39 @@ namespace Orchard.Tests.DisplayManagement {
var result = displayManager.Execute(CreateDisplayContext(shape));
Assert.That(result.ToString(), Is.EqualTo("Hello again!"));
}
[Test]
public void RenderAlternateShapeByMostRecentlyAddedMatchingAlternate() {
var displayManager = _container.Resolve<IDisplayManager>();
var shape = new Shape {
Metadata = new ShapeMetadata {
Type = "Foo"
}
};
shape.Metadata.Alternates.Add("Foo__1");
shape.Metadata.Alternates.Add("Foo__2");
shape.Metadata.Alternates.Add("Foo__3");
var descriptor = new ShapeDescriptor {
ShapeType = "Foo",
};
descriptor.Bindings["Foo"] = new ShapeBinding {
BindingName = "Foo",
Binding = ctx => new HtmlString("Hi there!"),
};
descriptor.Bindings["Foo__1"] = new ShapeBinding {
BindingName = "Foo__1",
Binding = ctx => new HtmlString("Hello (1)!"),
};
descriptor.Bindings["Foo__2"] = new ShapeBinding {
BindingName = "Foo__2",
Binding = ctx => new HtmlString("Hello (2)!"),
};
AddShapeDescriptor(descriptor);
var result = displayManager.Execute(CreateDisplayContext(shape));
Assert.That(result.ToString(), Is.EqualTo("Hello (2)!"));
}
}
}

View File

@@ -41,12 +41,13 @@ namespace Orchard.DisplayManagement.Descriptors {
}));
return new ShapeTable {
Descriptors = descriptors.ToDictionary(sd => sd.ShapeType)
Descriptors = descriptors.ToDictionary(sd => sd.ShapeType),
Bindings = descriptors.SelectMany(sd => sd.Bindings).ToDictionary(kv => kv.Key, kv => kv.Value),
};
});
}
static bool IsModuleOrRequestedTheme(ShapeAlteration alteration, string themeName) {
if (alteration == null ||
alteration.Feature == null ||

View File

@@ -3,5 +3,6 @@
namespace Orchard.DisplayManagement.Descriptors {
public class ShapeTable {
public IDictionary<string, ShapeDescriptor> Descriptors { get; set; }
public IDictionary<string, ShapeBinding> Bindings { get; set; }
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Web;
@@ -50,7 +52,7 @@ namespace Orchard.DisplayManagement.Implementation {
ShapeDescriptor shapeDescriptor;
ShapeBinding shapeBinding;
if (TryGetDescriptor(shapeMetadata.Type, shapeTable, out shapeDescriptor, out shapeBinding)) {
if (TryGetDescriptorBinding(shapeMetadata.Type, shapeMetadata.Alternates, shapeTable, out shapeDescriptor, out shapeBinding)) {
shape.Metadata.ChildContent = Process(shapeDescriptor, shapeBinding, shape, context);
}
else {
@@ -60,7 +62,7 @@ namespace Orchard.DisplayManagement.Implementation {
foreach (var frameType in shape.Metadata.Wrappers) {
ShapeDescriptor frameDescriptor;
ShapeBinding frameBinding;
if (TryGetDescriptor(frameType, shapeTable, out frameDescriptor, out frameBinding)) {
if (TryGetDescriptorBinding(frameType, Enumerable.Empty<string>(), shapeTable, out frameDescriptor, out frameBinding)) {
shape.Metadata.ChildContent = Process(frameDescriptor, frameBinding, shape, context);
}
}
@@ -68,18 +70,32 @@ namespace Orchard.DisplayManagement.Implementation {
return shape.Metadata.ChildContent;
}
static bool TryGetDescriptor(string shapeType, ShapeTable shapeTable, out ShapeDescriptor shapeDescriptor, out ShapeBinding shapeBinding) {
static bool TryGetDescriptorBinding(string shapeType, IEnumerable<string> shapeAlternates, ShapeTable shapeTable, out ShapeDescriptor shapeDescriptor, 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()) {
if (shapeTable.Bindings.TryGetValue(shapeAlternate, out shapeBinding)) {
shapeDescriptor = shapeBinding.ShapeDescriptor;
return true;
}
}
// when no alternates match, the shapeType is used to find the longest matching binding
// the shapetype name can break itself into shorter fallbacks at double-underscore marks
// so the shapetype itself may contain a longer alternate forms that falls back to a shorter one
var shapeTypeScan = shapeType;
for (; ; ) {
if (shapeTable.Descriptors.TryGetValue(shapeTypeScan, out shapeDescriptor) &&
shapeDescriptor.Bindings.TryGetValue(shapeTypeScan, out shapeBinding)) {
if (shapeTable.Bindings.TryGetValue(shapeTypeScan, out shapeBinding)) {
shapeDescriptor = shapeBinding.ShapeDescriptor;
return true;
}
var delimiterIndex = shapeTypeScan.LastIndexOf("__");
if (delimiterIndex < 0) {
shapeBinding = null;
shapeDescriptor = null;
return false;
}

View File

@@ -6,11 +6,13 @@ namespace Orchard.DisplayManagement.Shapes {
public class ShapeMetadata {
public ShapeMetadata() {
Wrappers = new List<string>();
Alternates = new List<string>();
}
public string Type { get; set; }
public string Position { get; set; }
public IList<string> Wrappers { get; set; }
public IList<string> Alternates { get; set; }
public bool WasExecuted { get; set; }
public IHtmlString ChildContent { get; set; }