Making the ShapeDescriptor.Bindings multiply occuring information

The same descriptor has all variants registered in the bindings collection
The descriptor is registered in the table under each of those names

--HG--
branch : theming
This commit is contained in:
Louis DeJardin 2010-09-13 22:28:26 -07:00
parent 6bfde2891c
commit bab30e826d
4 changed files with 243 additions and 29 deletions

View File

@ -2,11 +2,183 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using Autofac;
using NUnit.Framework;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.DisplayManagement.Shapes;
using Orchard.Themes;
namespace Orchard.Tests.DisplayManagement {
[TestFixture]
public class DefaultDisplayManagerTests {
[TestFixture]
public class DefaultDisplayManagerTests : ContainerTestBase {
ShapeTable _defaultShapeTable;
WorkContext _workContext;
protected override void Register(Autofac.ContainerBuilder builder) {
_defaultShapeTable = new ShapeTable { Descriptors = new Dictionary<string, ShapeDescriptor>() };
_workContext = new TestWorkContext {
CurrentTheme = new Theme { ThemeName = "Hello" }
};
builder.RegisterType<DefaultDisplayManager>().As<IDisplayManager>();
builder.RegisterType<TestShapeTableManager>().As<IShapeTableManager>();
builder.RegisterType<TestWorkContextAccessor>().As<IWorkContextAccessor>();
builder.Register(ctx => _defaultShapeTable);
builder.Register(ctx => _workContext);
}
public class Theme : ITheme {
public string ThemeName { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public string Version { get; set; }
public string Author { get; set; }
public string HomePage { get; set; }
public string Tags { get; set; }
}
public class TestShapeTableManager : IShapeTableManager {
private readonly ShapeTable _defaultShapeTable;
public TestShapeTableManager(ShapeTable defaultShapeTable) {
_defaultShapeTable = defaultShapeTable;
}
public ShapeTable GetShapeTable(string themeName) {
return _defaultShapeTable;
}
}
public class TestWorkContextAccessor : IWorkContextAccessor {
private readonly WorkContext _workContext;
public TestWorkContextAccessor(WorkContext workContext) {
_workContext = workContext;
}
public WorkContext GetContext(HttpContextBase httpContext) {
return _workContext;
}
public IWorkContextScope CreateWorkContextScope(HttpContextBase httpContext) {
throw new NotImplementedException();
}
public WorkContext GetContext() {
return _workContext;
}
public IWorkContextScope CreateWorkContextScope() {
throw new NotImplementedException();
}
}
public class TestWorkContext : WorkContext {
readonly IDictionary<string, object> _state = new Dictionary<string, object>();
public override T Resolve<T>() {
throw new NotImplementedException();
}
public override T GetState<T>(string name) {
object value;
return _state.TryGetValue(name, out value) ? (T)value : default(T);
}
public override void SetState<T>(string name, T value) {
_state[name] = value;
}
}
void AddShapeDescriptor(ShapeDescriptor shapeDescriptor) {
foreach (var binding in shapeDescriptor.Bindings) {
_defaultShapeTable.Descriptors[binding.Key] = shapeDescriptor;
}
}
static DisplayContext CreateDisplayContext(Shape shape) {
return new DisplayContext {
Value = shape,
ViewContext = new ViewContext()
};
}
[Test]
public void RenderSimpleShape() {
var displayManager = _container.Resolve<IDisplayManager>();
var shape = new Shape {
Metadata = new ShapeMetadata {
Type = "Foo"
}
};
var descriptor = new ShapeDescriptor {
ShapeType = "Foo",
};
descriptor.Bindings["Foo"] = new ShapeBinding {
BindingName = "Foo",
Binding = ctx => new HtmlString("Hi there!"),
};
AddShapeDescriptor(descriptor);
var result = displayManager.Execute(CreateDisplayContext(shape));
Assert.That(result.ToString(), Is.EqualTo("Hi there!"));
}
[Test]
public void RenderFallbackShape() {
var displayManager = _container.Resolve<IDisplayManager>();
var shape = new Shape {
Metadata = new ShapeMetadata {
Type = "Foo__2"
}
};
var descriptor = new ShapeDescriptor {
ShapeType = "Foo",
};
descriptor.Bindings["Foo"] = new ShapeBinding {
BindingName = "Foo",
Binding = ctx => new HtmlString("Hi there!"),
};
AddShapeDescriptor(descriptor);
var result = displayManager.Execute(CreateDisplayContext(shape));
Assert.That(result.ToString(), Is.EqualTo("Hi there!"));
}
[Test]
public void RenderAlternateShape() {
var displayManager = _container.Resolve<IDisplayManager>();
var shape = new Shape {
Metadata = new ShapeMetadata {
Type = "Foo__2"
}
};
var descriptor = new ShapeDescriptor {
ShapeType = "Foo",
};
descriptor.Bindings["Foo"] = new ShapeBinding {
BindingName = "Foo",
Binding = ctx => new HtmlString("Hi there!"),
};
descriptor.Bindings["Foo__2"] = new ShapeBinding {
BindingName = "Foo__2",
Binding = ctx => new HtmlString("Hello again!"),
};
AddShapeDescriptor(descriptor);
var result = displayManager.Execute(CreateDisplayContext(shape));
Assert.That(result.ToString(), Is.EqualTo("Hello again!"));
}
}
}

View File

@ -32,18 +32,21 @@ namespace Orchard.DisplayManagement.Descriptors {
Func<DisplayContext, IHtmlString> target = null;
descriptor.BindingSource = bindingSource;
var binding = new ShapeBinding {
BindingName = _shapeType,
BindingSource = bindingSource,
Binding = displayContext => {
// announce the binding, which may be reconfigured before it's used
descriptor.Binding = displayContext => {
// when used, first realize the actual target once
if (target == null)
target = binder(descriptor);
// when used, first realize the actual target once
if (target == null)
target = binder(descriptor);
// and execute the re
return target(displayContext);
// and execute the re
return target(displayContext);
}
};
descriptor.Bindings[_shapeType] = binding;
});
}
@ -61,9 +64,8 @@ namespace Orchard.DisplayManagement.Descriptors {
});
}
public ShapeAlteration Build() {
return new ShapeAlteration(_shapeType, _feature, _configurations.ToArray());
}
public ShapeAlteration Build() {
return new ShapeAlteration(_shapeType, _feature, _configurations.ToArray());
}
}
}

View File

@ -10,21 +10,38 @@ namespace Orchard.DisplayManagement.Descriptors {
Creating = Enumerable.Empty<Action<ShapeCreatingContext>>();
Created = Enumerable.Empty<Action<ShapeCreatedContext>>();
Wrappers = new List<string>();
Bindings = new Dictionary<string, ShapeBinding>();
}
public string ShapeType { get; set; }
/// <summary>
/// The BindingSource is informational text about the source of the Binding delegate. Not used except for
/// troubleshooting.
/// </summary>
public string BindingSource { get; set; }
public string BindingSource {
get {
return Bindings[ShapeType].BindingSource;
}
}
public Func<DisplayContext, IHtmlString> Binding { get; set; }
public Func<DisplayContext, IHtmlString> Binding {
get {
return Bindings[ShapeType].Binding;
}
}
public IEnumerable<Action<ShapeCreatingContext>> Creating {get;set;}
public IEnumerable<Action<ShapeCreatedContext>> Created {get;set;}
public IDictionary<string, ShapeBinding> Bindings { get; set; }
public IEnumerable<Action<ShapeCreatingContext>> Creating { get; set; }
public IEnumerable<Action<ShapeCreatedContext>> Created { get; set; }
public IList<string> Wrappers { get; set; }
}
public class ShapeBinding {
public string BindingName { get; set; }
public string BindingSource { get; set; }
public Func<DisplayContext, IHtmlString> Binding { get; set; }
}
}

View File

@ -49,9 +49,11 @@ namespace Orchard.DisplayManagement.Implementation {
var shapeTable = _shapeTableManager.GetShapeTable(workContext.CurrentTheme.ThemeName);
//preproc loop / event (alter shape, swapping type)
ShapeDescriptor shapeDescriptor;
if (shapeTable.Descriptors.TryGetValue(shapeMetadata.Type, out shapeDescriptor)) {
shape.Metadata.ChildContent = Process(shapeDescriptor, shape, context);
ShapeBinding shapeBinding;
if (TryGetDescriptor(shapeMetadata.Type, shapeTable, out shapeDescriptor, out shapeBinding)) {
shape.Metadata.ChildContent = Process(shapeDescriptor, shapeBinding, shape, context);
}
else {
throw new OrchardException(T("Shape type {0} not found", shapeMetadata.Type));
@ -59,15 +61,35 @@ namespace Orchard.DisplayManagement.Implementation {
foreach (var frameType in shape.Metadata.Wrappers) {
ShapeDescriptor frameDescriptor;
if (shapeTable.Descriptors.TryGetValue(frameType, out frameDescriptor)) {
shape.Metadata.ChildContent = Process(frameDescriptor, shape, context);
ShapeBinding frameBinding;
if (TryGetDescriptor(frameType, shapeTable, out frameDescriptor, out frameBinding)) {
shape.Metadata.ChildContent = Process(frameDescriptor, frameBinding, shape, context);
}
}
return shape.Metadata.ChildContent;
}
private IHtmlString CoerceHtmlString(object value) {
static bool TryGetDescriptor(string shapeType, ShapeTable shapeTable, out ShapeDescriptor shapeDescriptor, out ShapeBinding shapeBinding) {
var shapeTypeScan = shapeType;
for (; ; ) {
if (shapeTable.Descriptors.TryGetValue(shapeTypeScan, out shapeDescriptor) &&
shapeDescriptor.Bindings.TryGetValue(shapeTypeScan, out shapeBinding)) {
return true;
}
var delimiterIndex = shapeTypeScan.LastIndexOf("__");
if (delimiterIndex < 0) {
shapeBinding = null;
return false;
}
shapeTypeScan = shapeTypeScan.Substring(0, delimiterIndex);
}
}
static IHtmlString CoerceHtmlString(object value) {
if (value == null)
return null;
@ -78,12 +100,13 @@ namespace Orchard.DisplayManagement.Implementation {
return new HtmlString(HttpUtility.HtmlEncode(value));
}
private IHtmlString Process(ShapeDescriptor shapeDescriptor, IShape shape, DisplayContext context) {
if (shapeDescriptor == null || shapeDescriptor.Binding == null) {
static IHtmlString Process(ShapeDescriptor shapeDescriptor, ShapeBinding shapeBinding, IShape shape, DisplayContext context) {
if (shapeDescriptor == null || shapeBinding == null || shapeBinding.Binding == null) {
//todo: create result from all child shapes
return shape.Metadata.ChildContent ?? new HtmlString("");
}
return CoerceHtmlString(shapeDescriptor.Binding(context));
return CoerceHtmlString(shapeBinding.Binding(context));
}
class ForgivingConvertBinder : ConvertBinder {