mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Merge
--HG-- branch : mvc3p1
This commit is contained in:
@@ -1,39 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Autofac;
|
||||
using NUnit.Framework;
|
||||
using Orchard.DisplayManagement;
|
||||
|
||||
namespace Orchard.Tests.DisplayManagement {
|
||||
[TestFixture]
|
||||
public class DefaultShapeTableFactoryTests {
|
||||
static IShapeTableFactory CreateShapeTableFactory(Action<ContainerBuilder> config) {
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterType<DefaultShapeTableFactory>().As<IShapeTableFactory>();
|
||||
config(builder);
|
||||
var container = builder.Build();
|
||||
return container.Resolve<IShapeTableFactory>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShapeTableRecognizesMethodNames() {
|
||||
var stf = CreateShapeTableFactory(cfg => cfg.RegisterType<Test>().As<IShapeDriver>());
|
||||
var shapeTable = stf.CreateShapeTable();
|
||||
Assert.That(shapeTable.Entries.Count(), Is.EqualTo(2));
|
||||
Assert.That(shapeTable.Entries.ContainsKey("Pager"));
|
||||
Assert.That(shapeTable.Entries.ContainsKey("Email"));
|
||||
}
|
||||
|
||||
public class Test : IShapeDriver {
|
||||
public void Pager() {
|
||||
}
|
||||
|
||||
public void Email(string text, string address) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
using Autofac;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Tests.Utility;
|
||||
|
||||
namespace Orchard.Tests.DisplayManagement.Descriptors {
|
||||
public class ContainerTestBase {
|
||||
|
||||
protected IContainer _container;
|
||||
|
||||
[SetUp]
|
||||
public virtual void Init() {
|
||||
var builder = new ContainerBuilder();
|
||||
Register(builder);
|
||||
_container = builder.Build();
|
||||
Resolve(_container);
|
||||
}
|
||||
|
||||
protected virtual void Register(ContainerBuilder builder) { }
|
||||
protected virtual void Resolve(IContainer container) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using Autofac;
|
||||
using NUnit.Framework;
|
||||
using Orchard.DisplayManagement.Descriptors;
|
||||
|
||||
namespace Orchard.Tests.DisplayManagement.Descriptors {
|
||||
[TestFixture]
|
||||
public class DefaultShapeTableFactoryTests : ContainerTestBase {
|
||||
private IShapeTableFactory _factory;
|
||||
|
||||
protected override void Register(ContainerBuilder builder) {
|
||||
builder.RegisterType<DefaultShapeTableFactory>().As<IShapeTableFactory>();
|
||||
}
|
||||
|
||||
protected override void Resolve(IContainer container) {
|
||||
_factory = container.Resolve<IShapeTableFactory>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FactoryIsResolved() {
|
||||
Assert.That(_factory, Is.Not.Null);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Orchard.Tests.DisplayManagement.Descriptors {
|
||||
[TestFixture]
|
||||
public class DefaultShapeTableManagerTests {
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.DisplayManagement;
|
||||
using Orchard.DisplayManagement.Descriptors;
|
||||
using Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Tests.Utility;
|
||||
|
||||
namespace Orchard.Tests.DisplayManagement.Descriptors {
|
||||
[TestFixture]
|
||||
public class ShapeAttributeBindingStrategyTests : ContainerTestBase {
|
||||
private FeatureDescriptor _testFeature;
|
||||
|
||||
protected override void Register(Autofac.ContainerBuilder builder) {
|
||||
builder.RegisterAutoMocking();
|
||||
_testFeature = new FeatureDescriptor { Name = "Testing", Extension = new ExtensionDescriptor { Name = "Testing" } };
|
||||
builder.RegisterType<ShapeAttributeBindingStrategy>().As<IShapeDescriptorBindingStrategy>();
|
||||
builder.RegisterInstance(new TestProvider()).WithMetadata("Feature", _testFeature);
|
||||
builder.RegisterModule(new ShapeAttributeBindingModule());
|
||||
}
|
||||
|
||||
protected override void Resolve(IContainer container) {
|
||||
// implementation resorts to orchard host to resolve "current scope" services
|
||||
container.Resolve<Mock<IOrchardHostContainer>>()
|
||||
.Setup(x => x.Resolve<IComponentContext>())
|
||||
.Returns(container);
|
||||
}
|
||||
|
||||
class TestProvider {
|
||||
[Shape]
|
||||
public string Simple() {
|
||||
return "Simple";
|
||||
}
|
||||
|
||||
[Shape("Renamed")]
|
||||
public string RenamedMethod() {
|
||||
return "Renamed";
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<ShapeDescriptorAlteration> GetInitializers() {
|
||||
var strategy = _container.Resolve<IShapeDescriptorBindingStrategy>();
|
||||
var builder = new ShapeTableBuilder();
|
||||
strategy.Discover(builder);
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShapeAttributeOccurrencesAreDetected() {
|
||||
var occurrences = _container.Resolve<IEnumerable<ShapeAttributeOccurrence>>();
|
||||
Assert.That(occurrences.Any(o => o.MethodInfo == typeof(TestProvider).GetMethod("Simple")));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InitializersHaveExpectedShapeTypeNames() {
|
||||
var strategy = _container.Resolve<IShapeDescriptorBindingStrategy>();
|
||||
var builder = new ShapeTableBuilder();
|
||||
strategy.Discover(builder);
|
||||
var initializers = builder.Build();
|
||||
Assert.That(initializers.Any(i => i.ShapeType == "Simple"));
|
||||
Assert.That(initializers.Any(i => i.ShapeType == "Renamed"));
|
||||
Assert.That(initializers.Any(i => i.ShapeType == "RenamedMethod"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FeatureMetadataIsDetected() {
|
||||
var strategy = _container.Resolve<IShapeDescriptorBindingStrategy>();
|
||||
var builder = new ShapeTableBuilder();
|
||||
strategy.Discover(builder);
|
||||
var initializers = builder.Build();
|
||||
Assert.That(initializers.All(i => i.Feature == _testFeature));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LifetimeScopeContainersHaveMetadata() {
|
||||
var strategy = _container.Resolve<IShapeDescriptorBindingStrategy>();
|
||||
var builder = new ShapeTableBuilder();
|
||||
strategy.Discover(builder);
|
||||
var initializers = builder.Build();
|
||||
Assert.That(initializers.Any(i => i.ShapeType == "Simple"));
|
||||
|
||||
var childContainer = _container.BeginLifetimeScope();
|
||||
|
||||
var strategy2 = childContainer.Resolve<IShapeDescriptorBindingStrategy>();
|
||||
var builder2 = new ShapeTableBuilder();
|
||||
strategy2.Discover(builder2);
|
||||
var initializers2 = builder2.Build();
|
||||
Assert.That(initializers2.Any(i => i.ShapeType == "Simple"));
|
||||
|
||||
Assert.That(strategy, Is.Not.SameAs(strategy2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BindingProvidedByStrategyInvokesMethod() {
|
||||
var initializers = GetInitializers();
|
||||
|
||||
var shapeDescriptor = initializers.Where(i => i.ShapeType == "Simple")
|
||||
.Aggregate(new ShapeDescriptor { ShapeType = "Simple" }, (d, i) => { i.Alter(d); return d; });
|
||||
|
||||
var displayContext = new DisplayContext();
|
||||
var result = shapeDescriptor.Binding(displayContext);
|
||||
var result2 = shapeDescriptor.Binding.Invoke(displayContext);
|
||||
Assert.That(result.ToString(), Is.StringContaining("Simple"));
|
||||
Assert.That(result2.ToString(), Is.StringContaining("Simple"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Autofac;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.DisplayManagement.Descriptors;
|
||||
using Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy;
|
||||
using Orchard.Environment.Descriptor.Models;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
|
||||
namespace Orchard.Tests.DisplayManagement.Descriptors {
|
||||
[TestFixture]
|
||||
public class ShapeTemplateBindingStrategyTests : ContainerTestBase {
|
||||
private ShellDescriptor _descriptor;
|
||||
private IList<FeatureDescriptor> _features;
|
||||
private TestViewEngine _testViewEngine;
|
||||
|
||||
|
||||
protected override void Register(Autofac.ContainerBuilder builder) {
|
||||
_descriptor = new ShellDescriptor { };
|
||||
_testViewEngine = new TestViewEngine();
|
||||
|
||||
builder.Register(ctx => _descriptor);
|
||||
builder.RegisterType<ShapeTemplateBindingStrategy>().As<IShapeDescriptorBindingStrategy>();
|
||||
builder.RegisterType<BasicShapeTemplateHarvester>().As<IShapeTemplateHarvester>();
|
||||
builder.RegisterInstance(_testViewEngine).As<IShapeTemplateViewEngine>();
|
||||
|
||||
var extensionManager = new Mock<IExtensionManager>();
|
||||
builder.Register(ctx => extensionManager);
|
||||
builder.Register(ctx => extensionManager.Object);
|
||||
}
|
||||
|
||||
public class TestViewEngine : Dictionary<string, object>, IShapeTemplateViewEngine {
|
||||
public IEnumerable<string> DetectTemplateFileNames(string virtualPath) {
|
||||
var virtualPathNorm = virtualPath.Replace("\\", "/");
|
||||
|
||||
foreach (var key in Keys) {
|
||||
var keyNorm = key.Replace("\\", "/");
|
||||
|
||||
if (keyNorm.StartsWith(virtualPathNorm, StringComparison.OrdinalIgnoreCase)) {
|
||||
var rest = keyNorm.Substring(virtualPathNorm.Length).TrimStart('/', '\\');
|
||||
if (rest.IndexOfAny(new[] { '/', '\\' }) != -1) {
|
||||
continue;
|
||||
}
|
||||
yield return Path.GetFileNameWithoutExtension(rest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Resolve(IContainer container) {
|
||||
_features = new List<FeatureDescriptor>();
|
||||
|
||||
container.Resolve<Mock<IExtensionManager>>()
|
||||
.Setup(em => em.AvailableFeatures())
|
||||
.Returns(_features);
|
||||
}
|
||||
|
||||
void AddFeature(string name, params string[] dependencies) {
|
||||
var featureDescriptor = new FeatureDescriptor {
|
||||
Name = name,
|
||||
Dependencies = dependencies,
|
||||
Extension = new ExtensionDescriptor {
|
||||
Name = name,
|
||||
Location = "~/Modules"
|
||||
}
|
||||
};
|
||||
featureDescriptor.Extension.Features = new[] { featureDescriptor };
|
||||
|
||||
_features.Add(featureDescriptor);
|
||||
}
|
||||
|
||||
void AddEnabledFeature(string name, params string[] dependencies) {
|
||||
AddFeature(name, dependencies);
|
||||
_descriptor.Features = _descriptor.Features.Concat(new[] { new ShellFeature { Name = name } });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TemplateResolutionWorks() {
|
||||
AddEnabledFeature("Alpha");
|
||||
|
||||
_testViewEngine.Add("~/Modules/Alpha/Views/AlphaShape.blah", null);
|
||||
var strategy = _container.Resolve<IShapeDescriptorBindingStrategy>();
|
||||
var builder = new ShapeTableBuilder();
|
||||
strategy.Discover(builder);
|
||||
var alterations = builder.Build();
|
||||
|
||||
Assert.That(alterations.Any(alt => alt.ShapeType == "AlphaShape"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web.Mvc;
|
||||
using ClaySharp;
|
||||
using ClaySharp.Implementation;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.DisplayManagement;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.DisplayManagement.Shapes;
|
||||
|
||||
namespace Orchard.Tests.DisplayManagement {
|
||||
[TestFixture]
|
||||
public class DisplayHelperTests {
|
||||
[Test]
|
||||
public void DisplayingShapeWithArgumentsStatically() {
|
||||
var viewContext = new ViewContext();
|
||||
|
||||
var displayManager = new Mock<IDisplayManager>();
|
||||
var shapeFactory = new Mock<IShapeFactory>();
|
||||
|
||||
var displayHelperFactory = new DisplayHelperFactory(displayManager.Object, shapeFactory.Object);
|
||||
var displayHelper = displayHelperFactory.CreateHelper(viewContext, null);
|
||||
|
||||
displayHelper.Invoke("Pager", ArgsUtility.Positional(1, 2, 3, 4));
|
||||
|
||||
shapeFactory.Verify(sf => sf.Create("Pager", It.IsAny<INamedEnumerable<object>>()));
|
||||
//displayManager.Verify(dm => dm.Execute(It.IsAny<Shape>(), viewContext, null));
|
||||
}
|
||||
[Test]
|
||||
public void DisplayingShapeWithArgumentsDynamically() {
|
||||
var viewContext = new ViewContext();
|
||||
|
||||
var displayManager = new Mock<IDisplayManager>();
|
||||
var shapeFactory = new Mock<IShapeFactory>();
|
||||
|
||||
var displayHelperFactory = new DisplayHelperFactory(displayManager.Object, shapeFactory.Object);
|
||||
var display = (dynamic)displayHelperFactory.CreateHelper(viewContext, null);
|
||||
|
||||
display.Pager(1, 2, 3, 4);
|
||||
|
||||
shapeFactory.Verify(sf => sf.Create("Pager", It.IsAny<INamedEnumerable<object>>()));
|
||||
//displayManager.Verify(dm => dm.Execute(It.IsAny<Shape>(), viewContext, null));
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void UsingDisplayAsFunctionAndPassingInTheShape() {
|
||||
var viewContext = new ViewContext();
|
||||
|
||||
var displayManager = new Mock<IDisplayManager>();
|
||||
var shapeFactory = new Mock<IShapeFactory>();
|
||||
|
||||
var displayHelperFactory = new DisplayHelperFactory(displayManager.Object, shapeFactory.Object);
|
||||
var display = (dynamic)displayHelperFactory.CreateHelper(viewContext, null);
|
||||
var outline = new Shape { ShapeMetadata = new ShapeMetadata { Type = "Outline" } };
|
||||
display(outline);
|
||||
|
||||
//displayManager.Verify(dm => dm.Execute(outline, viewContext, null));
|
||||
}
|
||||
}
|
||||
}
|
@@ -25,7 +25,7 @@ namespace Orchard.Tests.DisplayManagement {
|
||||
public void ShapeHasAttributesType() {
|
||||
var factory = _container.Resolve<IShapeFactory>();
|
||||
dynamic foo = factory.Create("Foo", ArgsUtility.Empty());
|
||||
ShapeMetadata metadata = foo.Attributes;
|
||||
ShapeMetadata metadata = foo.Metadata;
|
||||
Assert.That(metadata.Type, Is.EqualTo("Foo"));
|
||||
}
|
||||
|
||||
|
@@ -28,7 +28,7 @@ namespace Orchard.Tests.DisplayManagement {
|
||||
|
||||
var alpha = shape.Alpha();
|
||||
|
||||
Assert.That(alpha.Attributes.Type, Is.EqualTo("Alpha"));
|
||||
Assert.That(alpha.Metadata.Type, Is.EqualTo("Alpha"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -37,7 +37,7 @@ namespace Orchard.Tests.DisplayManagement {
|
||||
|
||||
var alpha = shape.Alpha(one: 1, two: "dos");
|
||||
|
||||
Assert.That(alpha.Attributes.Type, Is.EqualTo("Alpha"));
|
||||
Assert.That(alpha.Metadata.Type, Is.EqualTo("Alpha"));
|
||||
Assert.That(alpha.one, Is.EqualTo(1));
|
||||
Assert.That(alpha.two, Is.EqualTo("dos"));
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace Orchard.Tests.DisplayManagement {
|
||||
|
||||
var alpha = shape.Alpha(new { one = 1, two = "dos" });
|
||||
|
||||
Assert.That(alpha.Attributes.Type, Is.EqualTo("Alpha"));
|
||||
Assert.That(alpha.Metadata.Type, Is.EqualTo("Alpha"));
|
||||
Assert.That(alpha.one, Is.EqualTo(1));
|
||||
Assert.That(alpha.two, Is.EqualTo("dos"));
|
||||
}
|
||||
|
@@ -5,10 +5,15 @@ using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Autofac;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.DisplayManagement;
|
||||
using Orchard.DisplayManagement.Descriptors;
|
||||
using Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.DisplayManagement.Shapes;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Tests.Utility;
|
||||
|
||||
namespace Orchard.Tests.DisplayManagement {
|
||||
[TestFixture]
|
||||
@@ -18,20 +23,28 @@ namespace Orchard.Tests.DisplayManagement {
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterModule(new ShapeAttributeBindingModule());
|
||||
builder.RegisterType<ShapeAttributeBindingStrategy>().As<IShapeDescriptorBindingStrategy>();
|
||||
builder.RegisterType<DefaultDisplayManager>().As<IDisplayManager>();
|
||||
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
|
||||
builder.RegisterType<DisplayHelperFactory>().As<IDisplayHelperFactory>();
|
||||
builder.RegisterType<ShapeHelperFactory>().As<IShapeHelperFactory>();
|
||||
builder.RegisterType<DefaultShapeTableFactory>().As<IShapeTableFactory>();
|
||||
builder.RegisterType<SimpleShapes>().As<IShapeDriver>();
|
||||
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
|
||||
builder.RegisterType<SimpleShapes>();
|
||||
builder.RegisterAutoMocking(MockBehavior.Loose);
|
||||
_container = builder.Build();
|
||||
_container.Resolve<Mock<IOrchardHostContainer>>()
|
||||
.Setup(x => x.Resolve<IComponentContext>())
|
||||
.Returns(_container);
|
||||
}
|
||||
|
||||
public class SimpleShapes : IShapeDriver {
|
||||
public class SimpleShapes {
|
||||
[Shape]
|
||||
public IHtmlString Something() {
|
||||
return new HtmlString("<br/>");
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Pager() {
|
||||
return new HtmlString("<div>hello</div>");
|
||||
}
|
||||
|
@@ -93,6 +93,11 @@ namespace Orchard.Tests.Environment {
|
||||
yield return ext;
|
||||
}
|
||||
|
||||
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
|
||||
// note - doesn't order properly
|
||||
return AvailableExtensions().SelectMany(ed => ed.Features);
|
||||
}
|
||||
|
||||
public IEnumerable<Feature> LoadFeatures(IEnumerable<FeatureDescriptor> featureDescriptors) {
|
||||
foreach (var descriptor in featureDescriptors) {
|
||||
if (descriptor.Name == "Orchard.Framework") {
|
||||
|
@@ -411,5 +411,39 @@ orchardversion: 1
|
||||
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
||||
Assert.That(minimalisticModule.Features.Single().Name, Is.EqualTo("Minimalistic"));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void FeatureDescriptorsAreInDependencyOrder() {
|
||||
var extensionLoader = new StubLoaders();
|
||||
var extensionFolder = new StubFolders();
|
||||
|
||||
extensionFolder.Manifests.Add("Alpha", @"
|
||||
name: Alpha
|
||||
version: 1.0.3
|
||||
orchardversion: 1
|
||||
features:
|
||||
Alpha:
|
||||
Dependencies: Gamma
|
||||
");
|
||||
|
||||
extensionFolder.Manifests.Add("Beta", @"
|
||||
name: Beta
|
||||
version: 1.0.3
|
||||
orchardversion: 1
|
||||
");
|
||||
extensionFolder.Manifests.Add("Gamma", @"
|
||||
name: Gamma
|
||||
version: 1.0.3
|
||||
orchardversion: 1
|
||||
features:
|
||||
Gamma:
|
||||
Dependencies: Beta
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader });
|
||||
var features = extensionManager.AvailableFeatures();
|
||||
Assert.That(features.Aggregate("<", (a,b)=>a+b.Name+"<"), Is.EqualTo("<Beta<Gamma<Alpha<"));
|
||||
}
|
||||
}
|
||||
}
|
@@ -194,8 +194,11 @@
|
||||
<Compile Include="Data\StubLocator.cs" />
|
||||
<Compile Include="DisplayManagement\ArgsUtility.cs" />
|
||||
<Compile Include="DisplayManagement\DefaultDisplayManagerTests.cs" />
|
||||
<Compile Include="DisplayManagement\DefaultShapeTableFactoryTests.cs" />
|
||||
<Compile Include="DisplayManagement\DisplayHelperTests.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ContainerTestBase.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\DefaultShapeTableFactoryTests.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\DefaultShapeTableManagerTests.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeBindingStrategyTests.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapeTemplateBindingStrategyTests.cs" />
|
||||
<Compile Include="DisplayManagement\ShapeFactoryTests.cs" />
|
||||
<Compile Include="DisplayManagement\SubsystemTests.cs" />
|
||||
<Compile Include="DisplayManagement\ShapeHelperTests.cs" />
|
||||
|
@@ -127,6 +127,7 @@
|
||||
<ItemGroup>
|
||||
<None Include="Views\Home\FormShapes.cshtml" />
|
||||
<None Include="Views\Home\UsingShapes.cshtml" />
|
||||
<None Include="Views\Rounded.cshtml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||
|
@@ -6,28 +6,37 @@ using System.Web.Mvc;
|
||||
using Orchard.DisplayManagement;
|
||||
|
||||
namespace Orchard.DevTools {
|
||||
public class Shapes : IShapeDriver {
|
||||
public class Shapes : IDependency {
|
||||
[Shape]
|
||||
public IHtmlString Title(dynamic text) {
|
||||
return new HtmlString("<h2>" + text + "</h2>");
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Explosion(int? Height, int? Width) {
|
||||
|
||||
return new HtmlString(string.Format("<span>Boom {0}x{1}</span>", Height, Width));
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Page(dynamic Display, dynamic Shape) {
|
||||
return Display(Shape.Sidebar, Shape.Messages);
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Zone(dynamic Display, dynamic Shape) {
|
||||
var tag = new TagBuilder("div");
|
||||
tag.GenerateId("zone-" + Shape.Name);
|
||||
tag.AddCssClass("zone-" + Shape.Name);
|
||||
tag.AddCssClass("zone");
|
||||
tag.InnerHtml = Combine(DisplayAll(Display, Shape)).ToString();
|
||||
|
||||
IEnumerable<IHtmlString> all = DisplayAll(Display, Shape);
|
||||
tag.InnerHtml = Combine(all.ToArray()).ToString();
|
||||
|
||||
return new HtmlString(tag.ToString());
|
||||
}
|
||||
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Message(dynamic Display, object Content, string Severity) {
|
||||
return Display(new HtmlString("<p class=\"message\">"), Severity ?? "Neutral", ": ", Content, new HtmlString("</p>"));
|
||||
}
|
||||
|
@@ -1,21 +1,16 @@
|
||||
<div>
|
||||
|
||||
a @Display.Title(text:"This is everything")
|
||||
b @Display(Model)]
|
||||
|
||||
<style>#goodlink:after {content:'(url from css: ' attr(href) ')';} .bigredborderfromabadclassname {border:3px solid red;}</style>
|
||||
a @Display.Title(text:"This is everything")
|
||||
b @Display(Model)
|
||||
c [@Display(View.Page)]
|
||||
|
||||
c @Display(View.Page)
|
||||
d @Display.Message(Content:"Madness!!!")
|
||||
|
||||
c.a @Display.Link(Url: "http://orchardproject.net", Content: "Help, I'm in an anchor!!", Attributes: new {title = "foo"})
|
||||
c.b @Display.Link(
|
||||
Url: "http://orchardproject.net",
|
||||
Content: @Display.Image(Url: "http://orchardproject.net/content/images/heroShot.jpg", Attributes: new {@class = "bigredborderfromabadclassname"}),
|
||||
Attributes: new {id = "goodlink"})
|
||||
e @Display.Explosion(Width:40)
|
||||
|
||||
d @Display.Message(Content:"Madness!!!")
|
||||
f @Display.Message(Content: Display.Explosion(Height:10,Width:15))
|
||||
|
||||
e @Display.Explosion(Width:40)
|
||||
|
||||
f @Display.Message(Content: @Display.Explosion(Height:10,Width:15))
|
||||
g @Display.Rounded(Contents: Model)
|
||||
|
||||
</div>
|
||||
|
@@ -0,0 +1,6 @@
|
||||
<div class="rounded">
|
||||
@model dynamic
|
||||
<p>above</p>
|
||||
@Display(Model.Contents)
|
||||
<p>below</p>
|
||||
</div>
|
@@ -12,6 +12,7 @@ using Orchard.Data.Migration.Interpreters;
|
||||
using Orchard.Data.Providers;
|
||||
using Orchard.Data.Migration;
|
||||
using Orchard.DisplayManagement;
|
||||
using Orchard.DisplayManagement.Descriptors;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.DisplayManagement.Shapes;
|
||||
using Orchard.Environment.Extensions;
|
||||
@@ -65,7 +66,7 @@ namespace Orchard.Setup {
|
||||
builder.RegisterType<DisplayHelperFactory>().As<IDisplayHelperFactory>();
|
||||
builder.RegisterType<DefaultDisplayManager>().As<IDisplayManager>();
|
||||
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
|
||||
builder.RegisterType<DefaultShapeTableFactory>().As<IShapeTableFactory>();
|
||||
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableFactory>();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -29,11 +29,11 @@ namespace Orchard.ContentManagement.Drivers.Coordinators {
|
||||
var fieldTypeName = partFieldDefinition.FieldDefinition.Name;
|
||||
var fieldInfo = fieldInfos.FirstOrDefault(x => x.FieldTypeName == fieldTypeName);
|
||||
if (fieldInfo != null) {
|
||||
var storage = _fieldStorageProviderSelector
|
||||
.GetProvider(partFieldDefinition)
|
||||
.BindStorage(contentPart, partFieldDefinition);
|
||||
var field = fieldInfo.Factory(partFieldDefinition, storage);
|
||||
contentPart.Weld(field);
|
||||
var storage = _fieldStorageProviderSelector
|
||||
.GetProvider(partFieldDefinition)
|
||||
.BindStorage(contentPart, partFieldDefinition);
|
||||
var field = fieldInfo.Factory(partFieldDefinition, storage);
|
||||
contentPart.Weld(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Orchard.DisplayManagement.Descriptors {
|
||||
public class DefaultShapeTableFactory : IShapeTableFactory {
|
||||
public IDictionary<string, ShapeTable> CreateShapeTables() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Orchard.DisplayManagement.Descriptors {
|
||||
public class DefaultShapeTableManager : IShapeTableManager {
|
||||
private readonly IEnumerable<IShapeDescriptorBindingStrategy> _bindingStrategies;
|
||||
|
||||
public DefaultShapeTableManager(IEnumerable<IShapeDescriptorBindingStrategy> bindingStrategies) {
|
||||
_bindingStrategies = bindingStrategies;
|
||||
}
|
||||
|
||||
private ShapeTable _shapeTable;
|
||||
|
||||
public ShapeTable GetShapeTable(string themeName) {
|
||||
if (_shapeTable == null) {
|
||||
var builder = new ShapeTableBuilder();
|
||||
foreach (var bindingStrategy in _bindingStrategies) {
|
||||
bindingStrategy.Discover(builder);
|
||||
}
|
||||
// placeholder - alterations will need to be selective and in a particular order
|
||||
|
||||
_shapeTable = new ShapeTable {
|
||||
Descriptors = builder.Build()
|
||||
.GroupBy(alteration => alteration.ShapeType)
|
||||
.Select(group => group.Aggregate(
|
||||
new ShapeDescriptor { ShapeType = group.Key },
|
||||
(d, a) => {
|
||||
a.Alter(d);
|
||||
return d;
|
||||
}))
|
||||
.ToDictionary(sd => sd.ShapeType)
|
||||
};
|
||||
}
|
||||
return _shapeTable;
|
||||
}
|
||||
}
|
||||
}
|
112
src/Orchard/DisplayManagement/Descriptors/Interfaces.cs
Normal file
112
src/Orchard/DisplayManagement/Descriptors/Interfaces.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
|
||||
namespace Orchard.DisplayManagement.Descriptors {
|
||||
|
||||
public interface IShapeTableManager : IDependency {
|
||||
ShapeTable GetShapeTable(string themeName);
|
||||
}
|
||||
|
||||
public interface IShapeTableFactory : IDependency {
|
||||
IDictionary<string, ShapeTable> CreateShapeTables();
|
||||
}
|
||||
|
||||
public interface IShapeDescriptorBindingStrategy : IDependency {
|
||||
void Discover(ShapeTableBuilder builder);
|
||||
}
|
||||
|
||||
public class ShapeTable {
|
||||
public IDictionary<string, ShapeDescriptor> Descriptors { get; set; }
|
||||
}
|
||||
|
||||
public class ShapeDescriptor {
|
||||
public string ShapeType { get; set; }
|
||||
public ShapeBinding Binding { get; set; }
|
||||
}
|
||||
|
||||
public delegate object ShapeBinding(DisplayContext displayContext);
|
||||
|
||||
public class ShapeTableBuilder {
|
||||
readonly IList<ShapeDescriptorAlterationBuilderImpl> _descriptorBuilders = new List<ShapeDescriptorAlterationBuilderImpl>();
|
||||
|
||||
public ShapeDescriptorAlterationBuilder Describe {
|
||||
get {
|
||||
var db = new ShapeDescriptorAlterationBuilderImpl();
|
||||
_descriptorBuilders.Add(db);
|
||||
return db;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<ShapeDescriptorAlteration> Build() {
|
||||
return _descriptorBuilders.Select(b => b.Build());
|
||||
}
|
||||
|
||||
class ShapeDescriptorAlterationBuilderImpl : ShapeDescriptorAlterationBuilder {
|
||||
public ShapeDescriptorAlteration Build() {
|
||||
return new ShapeDescriptorAlteration(_shapeType, _feature, _configurations.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ShapeDescriptorAlteration {
|
||||
private readonly IList<Action<ShapeDescriptor>> _configurations;
|
||||
|
||||
public ShapeDescriptorAlteration(string shapeType, FeatureDescriptor feature, IList<Action<ShapeDescriptor>> configurations) {
|
||||
_configurations = configurations;
|
||||
ShapeType = shapeType;
|
||||
Feature = feature;
|
||||
}
|
||||
|
||||
public string ShapeType { get; private set; }
|
||||
public FeatureDescriptor Feature { get; private set; }
|
||||
public void Alter(ShapeDescriptor descriptor) {
|
||||
foreach (var configuration in _configurations) {
|
||||
configuration(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ShapeDescriptorAlterationBuilder {
|
||||
protected FeatureDescriptor _feature;
|
||||
protected string _shapeType;
|
||||
protected readonly IList<Action<ShapeDescriptor>> _configurations = new List<Action<ShapeDescriptor>>();
|
||||
|
||||
public ShapeDescriptorAlterationBuilder Named(string shapeType) {
|
||||
_shapeType = shapeType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ShapeDescriptorAlterationBuilder From(FeatureDescriptor feature) {
|
||||
_feature = feature;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ShapeDescriptorAlterationBuilder Configure(Action<ShapeDescriptor> action) {
|
||||
_configurations.Add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ShapeDescriptorAlterationBuilder BoundAs(Func<ShapeDescriptor, ShapeBinding> binder) {
|
||||
// schedule the configuration
|
||||
return Configure(descriptor => {
|
||||
|
||||
ShapeBinding target = null;
|
||||
|
||||
// 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);
|
||||
|
||||
// and execute the re
|
||||
return target(displayContext);
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
using Autofac.Core;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
|
||||
namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy {
|
||||
public class ShapeAttributeBindingModule : Module {
|
||||
readonly List<ShapeAttributeOccurrence> _occurrences = new List<ShapeAttributeOccurrence>();
|
||||
|
||||
protected override void Load(ContainerBuilder builder) {
|
||||
builder.RegisterInstance(_occurrences).As<IEnumerable<ShapeAttributeOccurrence>>();
|
||||
}
|
||||
|
||||
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) {
|
||||
|
||||
var occurrences = registration.Activator.LimitType.GetMethods()
|
||||
.SelectMany(mi => mi.GetCustomAttributes(typeof(ShapeAttribute), false).OfType<ShapeAttribute>()
|
||||
.Select(sa => new ShapeAttributeOccurrence(
|
||||
sa,
|
||||
mi,
|
||||
registration,
|
||||
() => GetFeatureDescriptor(registration))))
|
||||
.ToArray();
|
||||
|
||||
if (occurrences.Any())
|
||||
_occurrences.AddRange(occurrences);
|
||||
}
|
||||
|
||||
private static FeatureDescriptor GetFeatureDescriptor(IComponentRegistration registration) {
|
||||
object value; return registration.Metadata.TryGetValue("Feature", out value) ? value as FeatureDescriptor : null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Autofac;
|
||||
using Autofac.Core;
|
||||
using Microsoft.CSharp.RuntimeBinder;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.Environment;
|
||||
|
||||
namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy {
|
||||
public class ShapeAttributeBindingStrategy : IShapeDescriptorBindingStrategy {
|
||||
private readonly IEnumerable<ShapeAttributeOccurrence> _shapeAttributeOccurrences;
|
||||
private readonly IComponentContext _componentContext;
|
||||
|
||||
public ShapeAttributeBindingStrategy(
|
||||
IEnumerable<ShapeAttributeOccurrence> shapeAttributeOccurrences,
|
||||
IComponentContext componentContext) {
|
||||
_shapeAttributeOccurrences = shapeAttributeOccurrences;
|
||||
// todo: using a component context won't work when this is singleton
|
||||
_componentContext = componentContext;
|
||||
}
|
||||
|
||||
public void Discover(ShapeTableBuilder builder) {
|
||||
foreach (var iter in _shapeAttributeOccurrences) {
|
||||
var occurrence = iter;
|
||||
var shapeType = occurrence.ShapeAttribute.ShapeType ?? occurrence.MethodInfo.Name;
|
||||
builder.Describe
|
||||
.Named(shapeType)
|
||||
.From(occurrence.Feature)
|
||||
.BoundAs(descriptor => CreateDelegate(occurrence, descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
private ShapeBinding CreateDelegate(
|
||||
ShapeAttributeOccurrence attributeOccurrence,
|
||||
ShapeDescriptor descriptor) {
|
||||
return context => {
|
||||
var serviceInstance = _componentContext.Resolve(attributeOccurrence.Registration, Enumerable.Empty<Parameter>());
|
||||
|
||||
// oversimplification for the sake of evolving
|
||||
return PerformInvoke(context, attributeOccurrence.MethodInfo, serviceInstance);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private object PerformInvoke(DisplayContext displayContext, MethodInfo methodInfo, object serviceInstance) {
|
||||
var arguments = methodInfo.GetParameters()
|
||||
.Select(parameter => BindParameter(displayContext, parameter));
|
||||
|
||||
return methodInfo.Invoke(serviceInstance, arguments.ToArray());
|
||||
}
|
||||
|
||||
private object BindParameter(DisplayContext displayContext, ParameterInfo parameter) {
|
||||
if (parameter.Name == "Shape")
|
||||
return displayContext.Value;
|
||||
|
||||
if (parameter.Name == "Display")
|
||||
return displayContext.Display;
|
||||
|
||||
var result = ((dynamic)(displayContext.Value))[parameter.Name];
|
||||
var converter = _converters.GetOrAdd(parameter.ParameterType, CompileConverter);
|
||||
return converter.Invoke((object)result);
|
||||
}
|
||||
|
||||
static readonly ConcurrentDictionary<Type, Func<object, object>> _converters =
|
||||
new ConcurrentDictionary<Type, Func<object, object>>();
|
||||
|
||||
static Func<object, object> CompileConverter(Type targetType) {
|
||||
var valueParameter = Expression.Parameter(typeof(object), "value");
|
||||
|
||||
return Expression.Lambda<Func<object, object>>(
|
||||
Expression.Convert(
|
||||
Expression.Dynamic(
|
||||
Microsoft.CSharp.RuntimeBinder.Binder.Convert(CSharpBinderFlags.ConvertExplicit, targetType, null),
|
||||
targetType,
|
||||
valueParameter),
|
||||
typeof(object)),
|
||||
valueParameter).Compile();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Autofac.Core;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
|
||||
namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy {
|
||||
public class ShapeAttributeOccurrence {
|
||||
private readonly Func<FeatureDescriptor> _feature;
|
||||
|
||||
public ShapeAttributeOccurrence(ShapeAttribute shapeAttribute, MethodInfo methodInfo, IComponentRegistration registration, Func<FeatureDescriptor> feature) {
|
||||
ShapeAttribute = shapeAttribute;
|
||||
MethodInfo = methodInfo;
|
||||
Registration = registration;
|
||||
_feature = feature;
|
||||
}
|
||||
|
||||
public ShapeAttribute ShapeAttribute { get; private set; }
|
||||
public MethodInfo MethodInfo { get; private set; }
|
||||
public IComponentRegistration Registration { get; private set; }
|
||||
public FeatureDescriptor Feature { get { return _feature(); } }
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Events;
|
||||
|
||||
namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
|
||||
/// <summary>
|
||||
/// This service determines which paths to examine, and provides
|
||||
/// the shape type based on the template file paths discovered
|
||||
/// </summary>
|
||||
public interface IShapeTemplateHarvester : IDependency {
|
||||
IEnumerable<string> SubPaths();
|
||||
IEnumerable<HarvestShapeHit> HarvestShape(HarvestShapeInfo info);
|
||||
}
|
||||
|
||||
public class BasicShapeTemplateHarvester : IShapeTemplateHarvester {
|
||||
private readonly IEnumerable<IShapeTemplateViewEngine> _shapeTemplateViewEngines;
|
||||
|
||||
public BasicShapeTemplateHarvester(IEnumerable<IShapeTemplateViewEngine> shapeTemplateViewEngines) {
|
||||
_shapeTemplateViewEngines = shapeTemplateViewEngines;
|
||||
}
|
||||
|
||||
public IEnumerable<string> SubPaths() {
|
||||
return new[] { "Views", "Views/Items", "Views/Parts", "Views/Fields" };
|
||||
}
|
||||
|
||||
public IEnumerable<HarvestShapeHit> HarvestShape(HarvestShapeInfo info) {
|
||||
var lastDot = info.FileName.IndexOf('.');
|
||||
if (lastDot <= 0) {
|
||||
yield return new HarvestShapeHit {
|
||||
ShapeType = Adjust(info.FileName)
|
||||
};
|
||||
}
|
||||
else {
|
||||
yield return new HarvestShapeHit {
|
||||
ShapeType = Adjust(info.FileName.Substring(0, lastDot)),
|
||||
DisplayType = info.FileName.Substring(lastDot + 1)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static string Adjust(string fileName) {
|
||||
// canonical shape type names must not have - or . to be compatible
|
||||
// with display and shape api calls
|
||||
return fileName.Replace('-', '_').Replace('.', '_');
|
||||
}
|
||||
}
|
||||
|
||||
public class HarvestShapeInfo {
|
||||
public string SubPath { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public string TemplateVirtualPath { get; set; }
|
||||
}
|
||||
|
||||
public class HarvestShapeHit {
|
||||
public string ShapeType { get; set; }
|
||||
public string DisplayType { get; set; }
|
||||
}
|
||||
|
||||
public interface IShapeTemplateViewEngine : IDependency {
|
||||
IEnumerable<string> DetectTemplateFileNames(string virtualPath);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Mvc.Html;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.Environment.Descriptor.Models;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
|
||||
namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
|
||||
public class ShapeTemplateBindingStrategy : IShapeDescriptorBindingStrategy {
|
||||
private readonly ShellDescriptor _shellDescriptor;
|
||||
private readonly IExtensionManager _extensionManager;
|
||||
private readonly IEnumerable<IShapeTemplateHarvester> _harvesters;
|
||||
private readonly IEnumerable<IShapeTemplateViewEngine> _shapeTemplateViewEngines;
|
||||
|
||||
public ShapeTemplateBindingStrategy(
|
||||
IEnumerable<IShapeTemplateHarvester> harvesters,
|
||||
ShellDescriptor shellDescriptor,
|
||||
IExtensionManager extensionManager,
|
||||
IEnumerable<IShapeTemplateViewEngine> shapeTemplateViewEngines) {
|
||||
_harvesters = harvesters;
|
||||
_shellDescriptor = shellDescriptor;
|
||||
_extensionManager = extensionManager;
|
||||
_shapeTemplateViewEngines = shapeTemplateViewEngines;
|
||||
}
|
||||
|
||||
private static IEnumerable<ExtensionDescriptor> Once(IEnumerable<FeatureDescriptor> featureDescriptors) {
|
||||
var once = new ConcurrentDictionary<string, object>();
|
||||
return featureDescriptors.Select(fd => fd.Extension).Where(ed => once.TryAdd(ed.Name, null)).ToList();
|
||||
}
|
||||
|
||||
public void Discover(ShapeTableBuilder builder) {
|
||||
var harvesterInfos = _harvesters.Select(harvester => new { harvester, subPaths = harvester.SubPaths() });
|
||||
|
||||
var availableFeatures = _extensionManager.AvailableFeatures();
|
||||
var activeFeatures = availableFeatures.Where(fd => _shellDescriptor.Features.Any(sf => sf.Name == fd.Name));
|
||||
var activeExtensions = Once(activeFeatures);
|
||||
|
||||
var hits = activeExtensions.SelectMany(extensionDescriptor => {
|
||||
var pathContexts = harvesterInfos.SelectMany(harvesterInfo => harvesterInfo.subPaths.Select(subPath => {
|
||||
var basePath = Path.Combine(extensionDescriptor.Location, extensionDescriptor.Name);
|
||||
var virtualPath = Path.Combine(basePath, subPath);
|
||||
return new { harvesterInfo.harvester, basePath, subPath, virtualPath };
|
||||
}));
|
||||
|
||||
var fileContexts = pathContexts.SelectMany(pathContext => _shapeTemplateViewEngines.SelectMany(ve => {
|
||||
var fileNames = ve.DetectTemplateFileNames(pathContext.virtualPath);
|
||||
return fileNames.Select(fileName => new { fileName, fileVirtualPath = Path.Combine(pathContext.virtualPath, fileName), pathContext });
|
||||
}));
|
||||
|
||||
var shapeContexts = fileContexts.SelectMany(fileContext => {
|
||||
var harvestShapeInfo = new HarvestShapeInfo {
|
||||
SubPath = fileContext.pathContext.subPath,
|
||||
FileName = fileContext.fileName,
|
||||
TemplateVirtualPath = fileContext.fileVirtualPath
|
||||
};
|
||||
var harvestShapeHits = fileContext.pathContext.harvester.HarvestShape(harvestShapeInfo);
|
||||
return harvestShapeHits.Select(harvestShapeHit => new { harvestShapeInfo, harvestShapeHit, fileContext });
|
||||
});
|
||||
|
||||
return shapeContexts.Select(shapeContext => new { extensionDescriptor, shapeContext });
|
||||
});
|
||||
|
||||
|
||||
foreach (var iter in hits) {
|
||||
// templates are always associated with the namesake feature of module or theme
|
||||
var hit = iter;
|
||||
var featureDescriptors = iter.extensionDescriptor.Features.Where(fd => fd.Name == hit.extensionDescriptor.Name);
|
||||
foreach (var featureDescriptor in featureDescriptors) {
|
||||
builder.Describe
|
||||
.From(featureDescriptor)
|
||||
.Named(iter.shapeContext.harvestShapeHit.ShapeType)
|
||||
.BoundAs(shapeDescriptor => displayContext => Render(shapeDescriptor, displayContext, hit.shapeContext.harvestShapeInfo, hit.shapeContext.harvestShapeHit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object Render(ShapeDescriptor shapeDescriptor, DisplayContext displayContext, HarvestShapeInfo harvestShapeInfo, HarvestShapeHit harvestShapeHit) {
|
||||
var htmlHelper = new HtmlHelper(displayContext.ViewContext, displayContext.ViewDataContainer);
|
||||
//return htmlHelper.Partial(harvestShapeInfo.TemplateVirtualPath, displayContext.Value);
|
||||
return htmlHelper.Partial(harvestShapeInfo.TemplateVirtualPath.Replace("\\", "/") + ".cshtml", displayContext.Value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -5,6 +5,6 @@
|
||||
/// Note: Anything on this interface is a reserved word for the purpose of shape properties
|
||||
/// </summary>
|
||||
public interface IShape {
|
||||
IShapeMetadata ShapeMetadata { get; set; }
|
||||
IShapeMetadata Metadata { get; set; }
|
||||
}
|
||||
}
|
@@ -3,5 +3,5 @@
|
||||
/// Base interface for module components which define new shape types and
|
||||
/// optionally provide default implementation method
|
||||
/// </summary>
|
||||
public interface IShapeDriver : IDependency{}
|
||||
public interface IShapeProvider : IDependency{}
|
||||
}
|
@@ -4,11 +4,13 @@ using System.Linq.Expressions;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Web;
|
||||
using Microsoft.CSharp.RuntimeBinder;
|
||||
using Orchard.DisplayManagement.Descriptors;
|
||||
using Orchard.DisplayManagement.Shapes;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.DisplayManagement.Implementation {
|
||||
public class DefaultDisplayManager : IDisplayManager {
|
||||
private readonly IShapeTableManager _shapeTableManager;
|
||||
private readonly IShapeTableFactory _shapeTableFactory;
|
||||
|
||||
// this need to be Shape instead of IShape - cast to interface throws error on clr types like HtmlString
|
||||
@@ -19,8 +21,8 @@ namespace Orchard.DisplayManagement.Implementation {
|
||||
typeof(Shape),
|
||||
null/*typeof(DefaultDisplayManager)*/)));
|
||||
|
||||
public DefaultDisplayManager(IShapeTableFactory shapeTableFactory) {
|
||||
_shapeTableFactory = shapeTableFactory;
|
||||
public DefaultDisplayManager(IShapeTableManager shapeTableManager) {
|
||||
_shapeTableManager = shapeTableManager;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
@@ -28,23 +30,24 @@ namespace Orchard.DisplayManagement.Implementation {
|
||||
|
||||
|
||||
public IHtmlString Execute(DisplayContext context) {
|
||||
|
||||
var shape = _convertAsShapeCallsite.Target(_convertAsShapeCallsite, context.Value);
|
||||
|
||||
// non-shape arguements are returned as a no-op
|
||||
if (shape == null)
|
||||
return CoerceHtmlString(context.Value);
|
||||
|
||||
var shapeMetadata = shape.ShapeMetadata;
|
||||
var shapeMetadata = shape.Metadata;
|
||||
// can't really cope with a shape that has no type information
|
||||
if (shapeMetadata == null || string.IsNullOrEmpty(shapeMetadata.Type))
|
||||
return CoerceHtmlString(context.Value);
|
||||
|
||||
var shapeTable = _shapeTableFactory.CreateShapeTable();
|
||||
var shapeTable = _shapeTableManager.GetShapeTable(null);
|
||||
//preproc loop / event (alter shape, swapping type)
|
||||
|
||||
ShapeTable.Entry entry;
|
||||
if (shapeTable.Entries.TryGetValue(shapeMetadata.Type, out entry)) {
|
||||
return Process(entry, shape, context);
|
||||
ShapeDescriptor shapeDescriptor;
|
||||
if (shapeTable.Descriptors.TryGetValue(shapeMetadata.Type, out shapeDescriptor)) {
|
||||
return Process(shapeDescriptor, shape, context);
|
||||
}
|
||||
//postproc / content html alteration/wrapping/etc
|
||||
throw new OrchardException(T("Shape type {0} not found", shapeMetadata.Type));
|
||||
@@ -61,8 +64,8 @@ namespace Orchard.DisplayManagement.Implementation {
|
||||
return new HtmlString(HttpUtility.HtmlEncode(value));
|
||||
}
|
||||
|
||||
private IHtmlString Process(ShapeTable.Entry entry, IShape shape, DisplayContext context) {
|
||||
return CoerceHtmlString(entry.Target(context));
|
||||
private IHtmlString Process(ShapeDescriptor shapeDescriptor, IShape shape, DisplayContext context) {
|
||||
return CoerceHtmlString(shapeDescriptor.Binding(context));
|
||||
}
|
||||
|
||||
class ForgivingConvertBinder : ConvertBinder {
|
||||
|
@@ -41,7 +41,7 @@ namespace Orchard.DisplayManagement.Implementation {
|
||||
// consideration - types without default constructors could consume positional arguments?
|
||||
var shape = ClayActivator.CreateInstance(baseType, behaviors);
|
||||
|
||||
shape.ShapeMetadata = new ShapeMetadata { Type = shapeType };
|
||||
shape.Metadata = new ShapeMetadata { Type = shapeType };
|
||||
|
||||
// only one non-Type, non-named argument is allowed
|
||||
var initializer = positional.SingleOrDefault();
|
||||
|
@@ -1,9 +1,11 @@
|
||||
using System.Web.Mvc;
|
||||
using System;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Orchard.DisplayManagement.Implementation {
|
||||
public class DisplayContext {
|
||||
public DisplayHelper Display { get; set; }
|
||||
public ViewContext ViewContext { get; set; }
|
||||
public IViewDataContainer ViewDataContainer { get; set; }
|
||||
public object Value { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -67,7 +67,7 @@ namespace Orchard.DisplayManagement.Implementation {
|
||||
}
|
||||
|
||||
public object ShapeExecute(object shape) {
|
||||
var context = new DisplayContext { Display = this, Value = shape, ViewContext = ViewContext };
|
||||
var context = new DisplayContext { Display = this, Value = shape, ViewContext = ViewContext, ViewDataContainer = ViewDataContainer };
|
||||
return _displayManager.Execute(context);
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,8 @@ namespace Orchard.DisplayManagement.Implementation {
|
||||
public override object InvokeMember(Func<object> proceed, object target, string name, INamedEnumerable<object> args) {
|
||||
return ((DisplayHelper)target).Invoke(name, args);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
10
src/Orchard/DisplayManagement/ShapeAttribute.cs
Normal file
10
src/Orchard/DisplayManagement/ShapeAttribute.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Orchard.DisplayManagement {
|
||||
public class ShapeAttribute : Attribute {
|
||||
public ShapeAttribute() { }
|
||||
public ShapeAttribute(string shapeType) { this.ShapeType = shapeType; }
|
||||
|
||||
public string ShapeType { get; private set; }
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
namespace Orchard.DisplayManagement.Shapes {
|
||||
public class Shape : IShape {
|
||||
public virtual IShapeMetadata ShapeMetadata { get; set; }
|
||||
public virtual IShapeMetadata Metadata { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Orchard.DisplayManagement {
|
||||
public interface IShapeTableFactory : IDependency {
|
||||
ShapeTable CreateShapeTable();
|
||||
}
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Web;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
|
||||
namespace Orchard.DisplayManagement {
|
||||
public class ShapeTable {
|
||||
public IDictionary<string, Entry> Entries { get; set; }
|
||||
|
||||
public class Entry {
|
||||
public string ShapeType { get; set; }
|
||||
public Func<DisplayContext, object> Target { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,6 +10,8 @@ using Orchard.Environment.Extensions.Loaders;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Utility;
|
||||
using Orchard.Utility.Extensions;
|
||||
|
||||
namespace Orchard.Environment.Extensions {
|
||||
public class ExtensionManager : IExtensionManager {
|
||||
@@ -31,6 +33,15 @@ namespace Orchard.Environment.Extensions {
|
||||
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
||||
return _folders.SelectMany(folder => folder.AvailableExtensions());
|
||||
}
|
||||
|
||||
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
|
||||
var featureDescriptors = AvailableExtensions().SelectMany(ext => ext.Features);
|
||||
var featureDescriptorsOrdered = featureDescriptors.OrderByDependencies((item, dep) =>
|
||||
item.Dependencies != null &&
|
||||
item.Dependencies.Any(x => StringComparer.OrdinalIgnoreCase.Equals(x, dep.Name)));
|
||||
return featureDescriptorsOrdered.ToReadOnlyCollection();
|
||||
}
|
||||
|
||||
|
||||
private IEnumerable<ExtensionEntry> LoadedModules() {
|
||||
foreach (var descriptor in AvailableExtensions()) {
|
||||
|
@@ -5,7 +5,9 @@ using Orchard.Environment.Extensions.Models;
|
||||
namespace Orchard.Environment.Extensions {
|
||||
public interface IExtensionManager {
|
||||
IEnumerable<ExtensionDescriptor> AvailableExtensions();
|
||||
IEnumerable<FeatureDescriptor> AvailableFeatures();
|
||||
IEnumerable<Feature> LoadFeatures(IEnumerable<FeatureDescriptor> featureDescriptors);
|
||||
|
||||
void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle);
|
||||
void UninstallExtension(string extensionType, string extensionName);
|
||||
}
|
||||
|
@@ -47,6 +47,8 @@ namespace Orchard.Environment.ShellBuilders {
|
||||
var records = BuildBlueprint(features, IsRecord, (t, f) => BuildRecord(t, f, settings));
|
||||
|
||||
return new ShellBlueprint {
|
||||
Settings = settings,
|
||||
Descriptor = descriptor,
|
||||
Dependencies = dependencies.Concat(modules).ToArray(),
|
||||
Controllers = controllers,
|
||||
Records = records,
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Environment.Descriptor.Models;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
|
||||
@@ -11,6 +12,9 @@ namespace Orchard.Environment.ShellBuilders.Models {
|
||||
/// and is passed into the IShellContainerFactory.
|
||||
/// </summary>
|
||||
public class ShellBlueprint {
|
||||
public ShellSettings Settings { get; set; }
|
||||
public ShellDescriptor Descriptor { get; set; }
|
||||
|
||||
public IEnumerable<DependencyBlueprint> Dependencies { get; set; }
|
||||
public IEnumerable<ControllerBlueprint> Controllers { get; set; }
|
||||
public IEnumerable<RecordBlueprint> Records { get; set; }
|
||||
|
@@ -52,6 +52,7 @@ namespace Orchard.Environment.ShellBuilders {
|
||||
|
||||
builder.Register(ctx => dynamicProxyContext);
|
||||
builder.Register(ctx => settings);
|
||||
builder.Register(ctx => blueprint.Descriptor);
|
||||
builder.Register(ctx => blueprint);
|
||||
|
||||
var moduleIndex = intermediateScope.Resolve<IIndex<Type, IModule>>();
|
||||
|
@@ -1,11 +1,19 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Mvc.ViewEngines.WebForms;
|
||||
|
||||
namespace Orchard.Mvc.ViewEngines.Razor {
|
||||
public class RazorViewEngineProvider : IViewEngineProvider {
|
||||
public RazorViewEngineProvider() {
|
||||
public class RazorViewEngineProvider : IViewEngineProvider, IShapeTemplateViewEngine {
|
||||
private readonly IVirtualPathProvider _virtualPathProvider;
|
||||
|
||||
public RazorViewEngineProvider(IVirtualPathProvider virtualPathProvider) {
|
||||
_virtualPathProvider = virtualPathProvider;
|
||||
Logger = NullLogger.Instance;
|
||||
RazorCompilationEventsShim.EnsureInitialized();
|
||||
}
|
||||
@@ -82,5 +90,14 @@ namespace Orchard.Mvc.ViewEngines.Razor {
|
||||
|
||||
return viewEngine;
|
||||
}
|
||||
|
||||
public IEnumerable<string> DetectTemplateFileNames(string virtualPath) {
|
||||
var fileNames = _virtualPathProvider.ListFiles(virtualPath).Select(Path.GetFileName);
|
||||
foreach (var fileName in fileNames) {
|
||||
if (fileName.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase)) {
|
||||
yield return fileName.Substring(0, fileName.Length - ".cshtml".Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System.Web;
|
||||
using System;
|
||||
using System.Web;
|
||||
using System.Web.Compilation;
|
||||
using System.Web.Mvc;
|
||||
|
||||
@@ -6,8 +7,12 @@ namespace Orchard.Mvc.ViewEngines.WebForms {
|
||||
public class WebFormViewEngineForAspNet4 : WebFormViewEngine {
|
||||
protected override bool FileExists(ControllerContext controllerContext, string virtualPath) {
|
||||
try {
|
||||
|
||||
return BuildManager.GetObjectFactory(virtualPath, false) != null;
|
||||
if (virtualPath.EndsWith(".aspx", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
virtualPath.EndsWith(".ascx", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
virtualPath.EndsWith(".master", StringComparison.InvariantCultureIgnoreCase)) {
|
||||
return BuildManager.GetObjectFactory(virtualPath, false) != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (HttpException exception) {
|
||||
// Reproducing base class behavior, however these this code path should
|
||||
|
@@ -377,6 +377,13 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ContentManagement\DataMigrations\FrameworkDataMigration.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\DefaultShapeTableFactory.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeStrategy\ShapeAttributeBindingModule.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeStrategy\ShapeAttributeOccurrence.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapeTemplateStrategy\IShapeTemplateHarvester.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapeTemplateStrategy\ShapeTemplateBindingStrategy.cs" />
|
||||
<Compile Include="DisplayManagement\ShapeAttribute.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeStrategy\ShapeAttributeBindingStrategy.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\DefaultDisplayManager.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\DefaultShapeFactory.cs" />
|
||||
<Compile Include="DisplayManagement\IShapeHelperFactory.cs" />
|
||||
@@ -385,17 +392,16 @@
|
||||
<Compile Include="DisplayManagement\IShapeMetadata.cs" />
|
||||
<Compile Include="DisplayManagement\Shapes\Shape.cs" />
|
||||
<Compile Include="DisplayManagement\Shapes\ShapeMetadata.cs" />
|
||||
<Compile Include="DisplayManagement\Speculation\DefaultShapeTableFactory.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\DefaultShapeTableManager.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\DisplayContext.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\DisplayHelper.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\DisplayHelperFactory.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\IDisplayManager.cs" />
|
||||
<Compile Include="DisplayManagement\IShapeFactory.cs" />
|
||||
<Compile Include="DisplayManagement\IShapeDriver.cs" />
|
||||
<Compile Include="DisplayManagement\Speculation\IShapeTableFactory.cs" />
|
||||
<Compile Include="DisplayManagement\IShapeProvider.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\Interfaces.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\ShapeHelper.cs" />
|
||||
<Compile Include="DisplayManagement\Implementation\ShapeHelperFactory.cs" />
|
||||
<Compile Include="DisplayManagement\Speculation\ShapeTable.cs" />
|
||||
<Compile Include="Environment\IContextualizable.cs" />
|
||||
<Compile Include="Environment\IHostLocalRestart.cs" />
|
||||
<Compile Include="Environment\IShellContainerRegistrations.cs" />
|
||||
|
Reference in New Issue
Block a user