mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-12-03 03:58:13 +08:00
Merge
--HG-- branch : dev
This commit is contained in:
@@ -17,7 +17,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" }
|
||||
};
|
||||
@@ -26,10 +29,22 @@ namespace Orchard.Tests.DisplayManagement {
|
||||
builder.RegisterType<DefaultDisplayManager>().As<IDisplayManager>();
|
||||
builder.RegisterType<TestShapeTableManager>().As<IShapeTableManager>();
|
||||
builder.RegisterType<TestWorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<TestDisplayEvents>().As<IShapeDisplayEvents>()
|
||||
.As<TestDisplayEvents>()
|
||||
.InstancePerLifetimeScope();
|
||||
|
||||
builder.Register(ctx => _defaultShapeTable);
|
||||
builder.Register(ctx => _workContext);
|
||||
}
|
||||
|
||||
class TestDisplayEvents : IShapeDisplayEvents {
|
||||
public Action<ShapeDisplayingContext> Displaying = ctx => { };
|
||||
public Action<ShapeDisplayedContext> Displayed = ctx => { };
|
||||
|
||||
void IShapeDisplayEvents.Displaying(ShapeDisplayingContext context) { Displaying(context); }
|
||||
void IShapeDisplayEvents.Displayed(ShapeDisplayedContext context) { Displayed(context); }
|
||||
}
|
||||
|
||||
public class Theme : ITheme {
|
||||
public string ThemeName { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
@@ -83,11 +98,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();
|
||||
}
|
||||
|
||||
@@ -102,8 +116,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +177,7 @@ namespace Orchard.Tests.DisplayManagement {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderAlternateShape() {
|
||||
public void RenderAlternateShapeExplicitly() {
|
||||
var displayManager = _container.Resolve<IDisplayManager>();
|
||||
|
||||
var shape = new Shape {
|
||||
@@ -186,5 +202,125 @@ 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",
|
||||
};
|
||||
AddBinding(descriptor, "Foo", ctx => new HtmlString("Hi there!"));
|
||||
AddBinding(descriptor, "Foo__1", ctx => new HtmlString("Hello (1)!"));
|
||||
AddBinding(descriptor, "Foo__2", ctx => new HtmlString("Hello (2)!"));
|
||||
AddShapeDescriptor(descriptor);
|
||||
|
||||
var result = displayManager.Execute(CreateDisplayContext(shape));
|
||||
Assert.That(result.ToString(), Is.EqualTo("Hello (2)!"));
|
||||
}
|
||||
|
||||
private static void AddBinding(ShapeDescriptor descriptor, string bindingName, Func<DisplayContext, IHtmlString> binding) {
|
||||
descriptor.Bindings[bindingName] = new ShapeBinding {
|
||||
BindingName = bindingName,
|
||||
Binding = binding,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void IShapeDisplayEventsIsCalled() {
|
||||
var displayManager = _container.Resolve<IDisplayManager>();
|
||||
|
||||
var shape = new Shape {
|
||||
Metadata = new ShapeMetadata {
|
||||
Type = "Foo"
|
||||
}
|
||||
};
|
||||
|
||||
var descriptor = new ShapeDescriptor {
|
||||
ShapeType = "Foo",
|
||||
};
|
||||
AddBinding(descriptor, "Foo", ctx => new HtmlString("yarg"));
|
||||
AddShapeDescriptor(descriptor);
|
||||
|
||||
var displayingEventCount = 0;
|
||||
var displayedEventCount = 0;
|
||||
_container.Resolve<TestDisplayEvents>().Displaying = ctx => { ++displayingEventCount; };
|
||||
_container.Resolve<TestDisplayEvents>().Displayed = ctx => { ++displayedEventCount; ctx.ChildContent = new HtmlString("[" + ctx.ChildContent.ToHtmlString() + "]"); };
|
||||
|
||||
var result = displayManager.Execute(CreateDisplayContext(shape));
|
||||
|
||||
Assert.That(displayingEventCount, Is.EqualTo(1));
|
||||
Assert.That(displayedEventCount, Is.EqualTo(1));
|
||||
Assert.That(result.ToString(), Is.EqualTo("[yarg]"));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void ShapeDescriptorDisplayingAndDisplayedAreCalled() {
|
||||
var displayManager = _container.Resolve<IDisplayManager>();
|
||||
|
||||
var shape = new Shape {
|
||||
Metadata = new ShapeMetadata {
|
||||
Type = "Foo"
|
||||
}
|
||||
};
|
||||
|
||||
var descriptor = new ShapeDescriptor {
|
||||
ShapeType = "Foo",
|
||||
};
|
||||
AddBinding(descriptor, "Foo", ctx => new HtmlString("yarg"));
|
||||
AddShapeDescriptor(descriptor);
|
||||
|
||||
var displayingEventCount = 0;
|
||||
var displayedEventCount = 0;
|
||||
descriptor.Displaying = new Action<ShapeDisplayingContext>[] { ctx => { ++displayingEventCount; } };
|
||||
descriptor.Displayed = new Action<ShapeDisplayedContext>[] { ctx => { ++displayedEventCount; ctx.ChildContent = new HtmlString("[" + ctx.ChildContent.ToHtmlString() + "]"); } };
|
||||
|
||||
var result = displayManager.Execute(CreateDisplayContext(shape));
|
||||
|
||||
Assert.That(displayingEventCount, Is.EqualTo(1));
|
||||
Assert.That(displayedEventCount, Is.EqualTo(1));
|
||||
Assert.That(result.ToString(), Is.EqualTo("[yarg]"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DisplayingEventFiresEarlyEnoughToAddAlternateShapeBindingNames() {
|
||||
var displayManager = _container.Resolve<IDisplayManager>();
|
||||
|
||||
var shapeFoo = new Shape {
|
||||
Metadata = new ShapeMetadata {
|
||||
Type = "Foo"
|
||||
}
|
||||
};
|
||||
var descriptorFoo = new ShapeDescriptor {
|
||||
ShapeType = "Foo",
|
||||
};
|
||||
AddBinding(descriptorFoo, "Foo", ctx => new HtmlString("alpha"));
|
||||
AddShapeDescriptor(descriptorFoo);
|
||||
|
||||
var descriptorBar = new ShapeDescriptor {
|
||||
ShapeType = "Bar",
|
||||
};
|
||||
AddBinding(descriptorBar, "Bar", ctx => new HtmlString("beta"));
|
||||
AddShapeDescriptor(descriptorBar);
|
||||
|
||||
|
||||
var resultNormally = displayManager.Execute(CreateDisplayContext(shapeFoo));
|
||||
descriptorFoo.Displaying = new Action<ShapeDisplayingContext>[] { ctx => ctx.ShapeMetadata.Alternates.Add("Bar") };
|
||||
var resultWithOverride = displayManager.Execute(CreateDisplayContext(shapeFoo));
|
||||
|
||||
Assert.That(resultNormally.ToString(), Is.EqualTo("alpha"));
|
||||
Assert.That(resultWithOverride.ToString(), Is.EqualTo("beta"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using Autofac;
|
||||
using NUnit.Framework;
|
||||
using Orchard.DisplayManagement.Descriptors;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
|
||||
namespace Orchard.Tests.DisplayManagement.Descriptors {
|
||||
@@ -12,7 +13,9 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
|
||||
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
|
||||
|
||||
builder.RegisterType<TestShapeProvider>().As<IShapeTableProvider>()
|
||||
.WithMetadata("Feature", TestFeature());
|
||||
.WithMetadata("Feature", TestFeature())
|
||||
.As<TestShapeProvider>()
|
||||
.InstancePerLifetimeScope();
|
||||
}
|
||||
|
||||
static Feature TestFeature() {
|
||||
@@ -29,8 +32,12 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
|
||||
}
|
||||
|
||||
public class TestShapeProvider : IShapeTableProvider {
|
||||
public void Discover(ShapeTableBuilder builder) {
|
||||
|
||||
public Action<ShapeTableBuilder> Discover = x => { };
|
||||
|
||||
void IShapeTableProvider.Discover(ShapeTableBuilder builder) {
|
||||
builder.Describe("Hello");
|
||||
Discover(builder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,5 +55,29 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
|
||||
Assert.That(shapeTable1.Descriptors["Hello"], Is.Not.Null);
|
||||
Assert.That(shapeTable2.Descriptors["Hello"], Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CallbackAlterationsContributeToDescriptor() {
|
||||
Action<ShapeCreatingContext> cb1 = x => { };
|
||||
Action<ShapeCreatedContext> cb2 = x => { };
|
||||
Action<ShapeDisplayingContext> cb3 = x => { };
|
||||
Action<ShapeDisplayedContext> cb4 = x => { };
|
||||
|
||||
_container.Resolve<TestShapeProvider>().Discover =
|
||||
builder => builder.Describe("Foo")
|
||||
.OnCreating(cb1)
|
||||
.OnCreated(cb2)
|
||||
.OnDisplaying(cb3)
|
||||
.OnDisplayed(cb4);
|
||||
|
||||
var manager = _container.Resolve<IShapeTableManager>();
|
||||
|
||||
var foo = manager.GetShapeTable(null).Descriptors["Foo"];
|
||||
|
||||
Assert.That(foo.Creating.Single(), Is.SameAs(cb1));
|
||||
Assert.That(foo.Created.Single(), Is.SameAs(cb2));
|
||||
Assert.That(foo.Displaying.Single(), Is.SameAs(cb3));
|
||||
Assert.That(foo.Displayed.Single(), Is.SameAs(cb4));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,21 @@ namespace Orchard.Core.Shapes {
|
||||
|
||||
// 'Zone' shapes are built on the Zone base class
|
||||
builder.Describe("Zone")
|
||||
.OnCreating(creating => creating.BaseType = typeof(Zone));
|
||||
.OnCreating(creating => creating.BaseType = typeof (Zone));
|
||||
//.OnDisplaying(displaying => {
|
||||
// var name = displaying.Shape.ZoneName.ToLower();
|
||||
// var zone = displaying.Shape;
|
||||
// zone.Classes.Add("zone-" + name);
|
||||
// zone.Classes.Add("zone");
|
||||
// });
|
||||
|
||||
//builder.Describe("menu")
|
||||
// .OnDisplaying(displaying => {
|
||||
// var name = displaying.Shape.MenuName.ToLower();
|
||||
// var menu = displaying.Shape;
|
||||
// menu.Classes.Add("menu-" + name);
|
||||
// menu.Classes.Add("menu");
|
||||
// });
|
||||
|
||||
// 'List' shapes start with several empty collections
|
||||
builder.Describe("List")
|
||||
@@ -61,14 +75,12 @@ namespace Orchard.Core.Shapes {
|
||||
|
||||
private object CreateZone(ShapeCreatingContext context, string zoneName) {
|
||||
var name = zoneName.ToLower();
|
||||
|
||||
var zone = context.New.Zone();
|
||||
zone.Id = "zone-" + name;
|
||||
zone.Classes.Add("zone");
|
||||
return zone;
|
||||
}
|
||||
|
||||
|
||||
static TagBuilder GetTagBuilder(string tagName, string id, IEnumerable<string> classes, IDictionary<string, string> attributes) {
|
||||
var tagBuilder = new TagBuilder(tagName);
|
||||
tagBuilder.MergeAttributes(attributes, false);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
@model Orchard.Setup.ViewModels.SetupViewModel
|
||||
|
||||
@Html.Partial("~/Themes/Classic/Theme.txt2")
|
||||
|
||||
<h1>@Html.TitleForPage(T("Get Started").ToString())</h1>
|
||||
|
||||
@using (Html.BeginFormAntiForgeryPost()) {
|
||||
|
||||
@@ -139,10 +139,14 @@
|
||||
<Content Include="Themes\TheThemeMachine\Styles\site.css" />
|
||||
<Content Include="Themes\TheThemeMachine\Theme.png" />
|
||||
<Content Include="Themes\TheThemeMachine\Theme.txt" />
|
||||
<None Include="Themes\TheThemeMachine\Views\TempFeatured.cshtml">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="Themes\TheThemeMachine\Views\Document.cshtml" />
|
||||
<Content Include="Web.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<None Include="Themes\TheThemeMachine\Views\MenuItem.cshtml_" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Orchard\Orchard.Framework.csproj">
|
||||
@@ -314,7 +318,7 @@
|
||||
<Content Include="Themes\Web.config" />
|
||||
<Content Include="Themes\TheThemeMachine\Views\Items\Content.Blog.cshtml" />
|
||||
<None Include="Themes\TheThemeMachine\Views\Layout.cshtml" />
|
||||
<None Include="Themes\TheThemeMachine\Views\Menu.cshtml">
|
||||
<None Include="Themes\TheThemeMachine\Views\Menu.cshtml_">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
if (Model.Sidebar != null) {
|
||||
Html.AddPageClassNames(new[]{"icanhassidebar"});
|
||||
}
|
||||
|
||||
WorkContext.Layout.Featured.Add(New.TempFeatured(Hello:"bob"));
|
||||
WorkContext.Layout.Featured.Add("just some text in featured");
|
||||
}
|
||||
@Model.TitleFromMenu
|
||||
<div id="layout-wrapper">
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<!-- Model is Model.Menu from the layout (Page.Menu) -->
|
||||
@{
|
||||
Layout.TitleFromMenu = "hi there!";
|
||||
}
|
||||
|
||||
<nav>
|
||||
@{
|
||||
// these should move somewhere else
|
||||
Model.Id = "menu-" + Model.MenuName.ToLower();
|
||||
Model.Classes.Add(Model.Id);
|
||||
Model.Classes.Add("menu");
|
||||
var tag = Html.Resolve<Orchard.DisplayManagement.Shapes.ITagBuilderFactory>().Create(Model, "ul");
|
||||
}
|
||||
@tag.StartElement
|
||||
@DisplayChildren(Model)
|
||||
@tag.EndElement <!-- /@Model.Id -->
|
||||
</nav>
|
||||
10
src/Orchard.Web/Themes/TheThemeMachine/Views/Menu.cshtml_
Normal file
10
src/Orchard.Web/Themes/TheThemeMachine/Views/Menu.cshtml_
Normal file
@@ -0,0 +1,10 @@
|
||||
@{
|
||||
// Model is Model.Menu from the layout (Layout.Menu)
|
||||
var tag = Tag(Model, "ul");
|
||||
}
|
||||
<nav>
|
||||
@tag.StartElement
|
||||
@* see MenuItem shape template *@
|
||||
@DisplayChildren(Model)
|
||||
@tag.EndElement
|
||||
</nav>
|
||||
@@ -0,0 +1,17 @@
|
||||
@{
|
||||
// odd formatting in this file is to cause more attractive results in the output.
|
||||
var items = (IEnumerable<dynamic>)Enumerable.Cast<dynamic>(Model);
|
||||
}
|
||||
@{
|
||||
if (HasText(Model.Text)) {
|
||||
@DisplayChildren(Model)
|
||||
} else {
|
||||
<li><a href="@Model.Href">@Model.Text</a>
|
||||
@if (items.Any()) {
|
||||
<ul>
|
||||
@DisplayChildren(Model)
|
||||
</ul>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<h1>I am temp featured!! Hello, @Model.Hello</h1>
|
||||
@@ -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 ||
|
||||
|
||||
@@ -73,6 +73,20 @@ namespace Orchard.DisplayManagement.Descriptors {
|
||||
descriptor.Created = existing.Concat(new[] { action });
|
||||
});
|
||||
}
|
||||
|
||||
public ShapeAlterationBuilder OnDisplaying(Action<ShapeDisplayingContext> action) {
|
||||
return Configure(descriptor => {
|
||||
var existing = descriptor.Displaying ?? Enumerable.Empty<Action<ShapeDisplayingContext>>();
|
||||
descriptor.Displaying = existing.Concat(new[] { action });
|
||||
});
|
||||
}
|
||||
|
||||
public ShapeAlterationBuilder OnDisplayed(Action<ShapeDisplayedContext> action) {
|
||||
return Configure(descriptor => {
|
||||
var existing = descriptor.Displayed ?? Enumerable.Empty<Action<ShapeDisplayedContext>>();
|
||||
descriptor.Displayed = existing.Concat(new[] { action });
|
||||
});
|
||||
}
|
||||
|
||||
public ShapeAlteration Build() {
|
||||
return new ShapeAlteration(_shapeType, _feature, _configurations.ToArray());
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace Orchard.DisplayManagement.Descriptors {
|
||||
public ShapeDescriptor() {
|
||||
Creating = Enumerable.Empty<Action<ShapeCreatingContext>>();
|
||||
Created = Enumerable.Empty<Action<ShapeCreatedContext>>();
|
||||
Displaying = Enumerable.Empty<Action<ShapeDisplayingContext>>();
|
||||
Displayed = Enumerable.Empty<Action<ShapeDisplayedContext>>();
|
||||
Wrappers = new List<string>();
|
||||
Bindings = new Dictionary<string, ShapeBinding>();
|
||||
}
|
||||
@@ -36,6 +38,9 @@ namespace Orchard.DisplayManagement.Descriptors {
|
||||
public IEnumerable<Action<ShapeCreatingContext>> Creating { get; set; }
|
||||
public IEnumerable<Action<ShapeCreatedContext>> Created { get; set; }
|
||||
|
||||
public IEnumerable<Action<ShapeDisplayingContext>> Displaying { get; set; }
|
||||
public IEnumerable<Action<ShapeDisplayedContext>> Displayed { get; set; }
|
||||
|
||||
public IList<string> Wrappers { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace Orchard.DisplayManagement {
|
||||
/// <summary>
|
||||
/// Base interface for module components which define new shape types and
|
||||
/// optionally provide default implementation method
|
||||
/// </summary>
|
||||
public interface IShapeProvider : IDependency{}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -7,11 +9,13 @@ using Microsoft.CSharp.RuntimeBinder;
|
||||
using Orchard.DisplayManagement.Descriptors;
|
||||
using Orchard.DisplayManagement.Shapes;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.DisplayManagement.Implementation {
|
||||
public class DefaultDisplayManager : IDisplayManager {
|
||||
private readonly IShapeTableManager _shapeTableManager;
|
||||
private readonly IWorkContextAccessor _workContextAccessor;
|
||||
private readonly IEnumerable<IShapeDisplayEvents> _shapeDisplayEvents;
|
||||
|
||||
// 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(
|
||||
@@ -23,13 +27,17 @@ namespace Orchard.DisplayManagement.Implementation {
|
||||
|
||||
public DefaultDisplayManager(
|
||||
IShapeTableManager shapeTableManager,
|
||||
IWorkContextAccessor workContextAccessor) {
|
||||
IWorkContextAccessor workContextAccessor,
|
||||
IEnumerable<IShapeDisplayEvents> shapeDisplayEvents) {
|
||||
_shapeTableManager = shapeTableManager;
|
||||
_workContextAccessor = workContextAccessor;
|
||||
_shapeDisplayEvents = shapeDisplayEvents;
|
||||
T = NullLocalizer.Instance;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public IHtmlString Execute(DisplayContext context) {
|
||||
|
||||
@@ -46,34 +54,80 @@ namespace Orchard.DisplayManagement.Implementation {
|
||||
|
||||
var workContext = _workContextAccessor.GetContext(context.ViewContext);
|
||||
var shapeTable = _shapeTableManager.GetShapeTable(workContext.CurrentTheme.ThemeName);
|
||||
// preproc loop / event (alter shape, swapping type)
|
||||
|
||||
ShapeDescriptor shapeDescriptor;
|
||||
var displayingContext = new ShapeDisplayingContext {
|
||||
Shape = shape,
|
||||
ShapeMetadata = shapeMetadata
|
||||
};
|
||||
_shapeDisplayEvents.Invoke(sde => sde.Displaying(displayingContext), Logger);
|
||||
|
||||
// find base shape association using only the fundamental shape type.
|
||||
// alternates that may already be registered do not affect the "displaying" event calls
|
||||
ShapeBinding shapeBinding;
|
||||
if (TryGetDescriptor(shapeMetadata.Type, shapeTable, out shapeDescriptor, out shapeBinding)) {
|
||||
shape.Metadata.ChildContent = Process(shapeDescriptor, shapeBinding, shape, context);
|
||||
if (TryGetDescriptorBinding(shapeMetadata.Type, Enumerable.Empty<string>(), shapeTable, out shapeBinding)) {
|
||||
shapeBinding.ShapeDescriptor.Displaying.Invoke(action => action(displayingContext), Logger);
|
||||
}
|
||||
|
||||
// now find the actual binding to render, taking alternates into account
|
||||
ShapeBinding actualBinding;
|
||||
if (TryGetDescriptorBinding(shapeMetadata.Type, shapeMetadata.Alternates, shapeTable, out actualBinding)) {
|
||||
shape.Metadata.ChildContent = Process(actualBinding, shape, context);
|
||||
}
|
||||
else {
|
||||
throw new OrchardException(T("Shape type {0} not found", shapeMetadata.Type));
|
||||
}
|
||||
|
||||
foreach (var frameType in shape.Metadata.Wrappers) {
|
||||
ShapeDescriptor frameDescriptor;
|
||||
ShapeBinding frameBinding;
|
||||
if (TryGetDescriptor(frameType, shapeTable, out frameDescriptor, out frameBinding)) {
|
||||
shape.Metadata.ChildContent = Process(frameDescriptor, frameBinding, shape, context);
|
||||
if (TryGetDescriptorBinding(frameType, Enumerable.Empty<string>(), shapeTable, out frameBinding)) {
|
||||
shape.Metadata.ChildContent = Process(frameBinding, shape, context);
|
||||
}
|
||||
}
|
||||
|
||||
var displayedContext = new ShapeDisplayedContext {
|
||||
Shape = shape,
|
||||
ShapeMetadata = shape.Metadata,
|
||||
ChildContent = shape.Metadata.ChildContent,
|
||||
};
|
||||
|
||||
_shapeDisplayEvents.Invoke(sde => {
|
||||
var prior = displayedContext.ChildContent = displayedContext.ShapeMetadata.ChildContent;
|
||||
sde.Displayed(displayedContext);
|
||||
// update the child content if the context variable has been reassigned
|
||||
if (prior != displayedContext.ChildContent)
|
||||
displayedContext.ShapeMetadata.ChildContent = displayedContext.ChildContent;
|
||||
}, Logger);
|
||||
|
||||
if (shapeBinding != null) {
|
||||
shapeBinding.ShapeDescriptor.Displayed.Invoke(action => {
|
||||
var prior = displayedContext.ChildContent = displayedContext.ShapeMetadata.ChildContent;
|
||||
action(displayedContext);
|
||||
// update the child content if the context variable has been reassigned
|
||||
if (prior != displayedContext.ChildContent)
|
||||
displayedContext.ShapeMetadata.ChildContent = displayedContext.ChildContent;
|
||||
}, Logger);
|
||||
}
|
||||
|
||||
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 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)) {
|
||||
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)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -98,9 +152,9 @@ namespace Orchard.DisplayManagement.Implementation {
|
||||
return new HtmlString(HttpUtility.HtmlEncode(value));
|
||||
}
|
||||
|
||||
static IHtmlString Process(ShapeDescriptor shapeDescriptor, ShapeBinding shapeBinding, IShape shape, DisplayContext context) {
|
||||
static IHtmlString Process(ShapeBinding shapeBinding, IShape shape, DisplayContext context) {
|
||||
|
||||
if (shapeDescriptor == null || shapeBinding == null || shapeBinding.Binding == null) {
|
||||
if (shapeBinding == null || shapeBinding.Binding == null) {
|
||||
// todo: create result from all child shapes
|
||||
return shape.Metadata.ChildContent ?? new HtmlString("");
|
||||
}
|
||||
@@ -132,4 +186,4 @@ namespace Orchard.DisplayManagement.Implementation {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
using Orchard.DisplayManagement.Shapes;
|
||||
|
||||
namespace Orchard.DisplayManagement.Implementation {
|
||||
public interface IShapeDisplayEvents : IDependency {
|
||||
void Displaying(ShapeDisplayingContext context);
|
||||
void Displayed(ShapeDisplayedContext context);
|
||||
}
|
||||
|
||||
public class ShapeDisplayingContext {
|
||||
public dynamic Shape { get; set; }
|
||||
public ShapeMetadata ShapeMetadata { get; set; }
|
||||
}
|
||||
|
||||
public class ShapeDisplayedContext {
|
||||
public dynamic Shape { get; set; }
|
||||
public ShapeMetadata ShapeMetadata { get; set; }
|
||||
public IHtmlString ChildContent { get; set; }
|
||||
}
|
||||
|
||||
public abstract class ShapeDisplayEvents : IShapeDisplayEvents {
|
||||
public virtual void Displaying(ShapeDisplayingContext context) { }
|
||||
public virtual void Displayed(ShapeDisplayedContext context) { }
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
|
||||
@@ -165,6 +165,7 @@
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapeAlterationBuilder.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapeTable.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapeTableBuilder.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\IShapeDisplayEvents.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\IShapeFactoryEvents.cs" />
|
||||
<Compile Include="DisplayManagement\Shapes\ITagBuilderFactory.cs" />
|
||||
<Compile Include="Environment\Extensions\Loaders\RawThemeExtensionLoader.cs" />
|
||||
@@ -433,7 +434,6 @@
|
||||
<Compile Include="DisplayManagement\Implementation\DisplayHelperFactory.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\IDisplayManager.cs" />
|
||||
<Compile Include="DisplayManagement\IShapeFactory.cs" />
|
||||
<Compile Include="DisplayManagement\IShapeProvider.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\Interfaces.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\ShapeHelper.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\ShapeHelperFactory.cs" />
|
||||
|
||||
Reference in New Issue
Block a user