mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Updates to display management
Breaking out the shape binding strategies Implements a ShapeAttribute based shape discovery Implements a template file name based discovery Adjusts webforms engine for fully-qualified view names to limit itself to known extensions --HG-- branch : mvc3p1
This commit is contained in:
@@ -10,7 +10,6 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
|
|||||||
[SetUp]
|
[SetUp]
|
||||||
public virtual void Init() {
|
public virtual void Init() {
|
||||||
var builder = new ContainerBuilder();
|
var builder = new ContainerBuilder();
|
||||||
builder.RegisterAutoMocking();
|
|
||||||
Register(builder);
|
Register(builder);
|
||||||
_container = builder.Build();
|
_container = builder.Build();
|
||||||
Resolve(_container);
|
Resolve(_container);
|
||||||
|
@@ -9,6 +9,7 @@ using Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy;
|
|||||||
using Orchard.DisplayManagement.Implementation;
|
using Orchard.DisplayManagement.Implementation;
|
||||||
using Orchard.Environment;
|
using Orchard.Environment;
|
||||||
using Orchard.Environment.Extensions.Models;
|
using Orchard.Environment.Extensions.Models;
|
||||||
|
using Orchard.Tests.Utility;
|
||||||
|
|
||||||
namespace Orchard.Tests.DisplayManagement.Descriptors {
|
namespace Orchard.Tests.DisplayManagement.Descriptors {
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
@@ -16,6 +17,7 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
|
|||||||
private FeatureDescriptor _testFeature;
|
private FeatureDescriptor _testFeature;
|
||||||
|
|
||||||
protected override void Register(Autofac.ContainerBuilder builder) {
|
protected override void Register(Autofac.ContainerBuilder builder) {
|
||||||
|
builder.RegisterAutoMocking();
|
||||||
_testFeature = new FeatureDescriptor { Name = "Testing", Extension = new ExtensionDescriptor { Name = "Testing" } };
|
_testFeature = new FeatureDescriptor { Name = "Testing", Extension = new ExtensionDescriptor { Name = "Testing" } };
|
||||||
builder.RegisterType<ShapeAttributeBindingStrategy>().As<IShapeDescriptorBindingStrategy>();
|
builder.RegisterType<ShapeAttributeBindingStrategy>().As<IShapeDescriptorBindingStrategy>();
|
||||||
builder.RegisterInstance(new TestProvider()).WithMetadata("Feature", _testFeature);
|
builder.RegisterInstance(new TestProvider()).WithMetadata("Feature", _testFeature);
|
||||||
|
@@ -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 { Metadata = new ShapeMetadata { Type = "Outline" } };
|
|
||||||
display(outline);
|
|
||||||
|
|
||||||
//displayManager.Verify(dm => dm.Execute(outline, viewContext, null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -93,6 +93,11 @@ namespace Orchard.Tests.Environment {
|
|||||||
yield return ext;
|
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) {
|
public IEnumerable<Feature> LoadFeatures(IEnumerable<FeatureDescriptor> featureDescriptors) {
|
||||||
foreach (var descriptor in featureDescriptors) {
|
foreach (var descriptor in featureDescriptors) {
|
||||||
if (descriptor.Name == "Orchard.Framework") {
|
if (descriptor.Name == "Orchard.Framework") {
|
||||||
|
@@ -411,5 +411,39 @@ orchardversion: 1
|
|||||||
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
||||||
Assert.That(minimalisticModule.Features.Single().Name, Is.EqualTo("Minimalistic"));
|
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<"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -198,7 +198,7 @@
|
|||||||
<Compile Include="DisplayManagement\Descriptors\DefaultShapeTableFactoryTests.cs" />
|
<Compile Include="DisplayManagement\Descriptors\DefaultShapeTableFactoryTests.cs" />
|
||||||
<Compile Include="DisplayManagement\Descriptors\DefaultShapeTableManagerTests.cs" />
|
<Compile Include="DisplayManagement\Descriptors\DefaultShapeTableManagerTests.cs" />
|
||||||
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeBindingStrategyTests.cs" />
|
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeBindingStrategyTests.cs" />
|
||||||
<Compile Include="DisplayManagement\DisplayHelperTests.cs" />
|
<Compile Include="DisplayManagement\Descriptors\ShapeTemplateBindingStrategyTests.cs" />
|
||||||
<Compile Include="DisplayManagement\ShapeFactoryTests.cs" />
|
<Compile Include="DisplayManagement\ShapeFactoryTests.cs" />
|
||||||
<Compile Include="DisplayManagement\SubsystemTests.cs" />
|
<Compile Include="DisplayManagement\SubsystemTests.cs" />
|
||||||
<Compile Include="DisplayManagement\ShapeHelperTests.cs" />
|
<Compile Include="DisplayManagement\ShapeHelperTests.cs" />
|
||||||
|
@@ -126,6 +126,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Views\Home\UsingShapes.cshtml" />
|
<None Include="Views\Home\UsingShapes.cshtml" />
|
||||||
|
<None Include="Views\Rounded.cshtml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||||
|
@@ -29,7 +29,10 @@ namespace Orchard.DevTools {
|
|||||||
tag.GenerateId("zone-" + Shape.Name);
|
tag.GenerateId("zone-" + Shape.Name);
|
||||||
tag.AddCssClass("zone-" + Shape.Name);
|
tag.AddCssClass("zone-" + Shape.Name);
|
||||||
tag.AddCssClass("zone");
|
tag.AddCssClass("zone");
|
||||||
tag.InnerHtml = Combine(DisplayAll(Display, Shape).ToArray()).ToString();
|
|
||||||
|
IEnumerable<IHtmlString> all = DisplayAll(Display, Shape);
|
||||||
|
tag.InnerHtml = Combine(all.ToArray()).ToString();
|
||||||
|
|
||||||
return new HtmlString(tag.ToString());
|
return new HtmlString(tag.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,14 +1,16 @@
|
|||||||
<div>
|
<div>
|
||||||
|
|
||||||
a @Display.Title(text:"This is everything")
|
a @Display.Title(text:"This is everything")
|
||||||
b @Display(Model)
|
b @Display(Model)]
|
||||||
|
|
||||||
c @Display(View.Page)
|
c [@Display(View.Page)]
|
||||||
|
|
||||||
d @Display.Message(Content:"Madness!!!")
|
d @Display.Message(Content:"Madness!!!")
|
||||||
|
|
||||||
e @Display.Explosion(Width:40)
|
e @Display.Explosion(Width:40)
|
||||||
|
|
||||||
f @Display.Message(Content: @Display.Explosion(Height:10,Width:15))
|
f @Display.Message(Content: Display.Explosion(Height:10,Width:15))
|
||||||
|
|
||||||
|
g @Display.Rounded(Contents: Model)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@@ -0,0 +1,6 @@
|
|||||||
|
<div class="rounded">
|
||||||
|
@model dynamic
|
||||||
|
<p>above</p>
|
||||||
|
@Display(Model.Contents)
|
||||||
|
<p>below</p>
|
||||||
|
</div>
|
@@ -13,13 +13,14 @@ using Orchard.Environment;
|
|||||||
namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy {
|
namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy {
|
||||||
public class ShapeAttributeBindingStrategy : IShapeDescriptorBindingStrategy {
|
public class ShapeAttributeBindingStrategy : IShapeDescriptorBindingStrategy {
|
||||||
private readonly IEnumerable<ShapeAttributeOccurrence> _shapeAttributeOccurrences;
|
private readonly IEnumerable<ShapeAttributeOccurrence> _shapeAttributeOccurrences;
|
||||||
private readonly IOrchardHostContainer _orchardHostContainer;
|
private readonly IComponentContext _componentContext;
|
||||||
|
|
||||||
public ShapeAttributeBindingStrategy(
|
public ShapeAttributeBindingStrategy(
|
||||||
IEnumerable<ShapeAttributeOccurrence> shapeAttributeOccurrences,
|
IEnumerable<ShapeAttributeOccurrence> shapeAttributeOccurrences,
|
||||||
IOrchardHostContainer orchardHostContainer) {
|
IComponentContext componentContext) {
|
||||||
_shapeAttributeOccurrences = shapeAttributeOccurrences;
|
_shapeAttributeOccurrences = shapeAttributeOccurrences;
|
||||||
_orchardHostContainer = orchardHostContainer;
|
// todo: using a component context won't work when this is singleton
|
||||||
|
_componentContext = componentContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Discover(ShapeTableBuilder builder) {
|
public void Discover(ShapeTableBuilder builder) {
|
||||||
@@ -37,8 +38,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy {
|
|||||||
ShapeAttributeOccurrence attributeOccurrence,
|
ShapeAttributeOccurrence attributeOccurrence,
|
||||||
ShapeDescriptor descriptor) {
|
ShapeDescriptor descriptor) {
|
||||||
return context => {
|
return context => {
|
||||||
var componentContext = _orchardHostContainer.Resolve<IComponentContext>();
|
var serviceInstance = _componentContext.Resolve(attributeOccurrence.Registration, Enumerable.Empty<Parameter>());
|
||||||
var serviceInstance = componentContext.Resolve(attributeOccurrence.Registration, Enumerable.Empty<Parameter>());
|
|
||||||
|
|
||||||
// oversimplification for the sake of evolving
|
// oversimplification for the sake of evolving
|
||||||
return PerformInvoke(context, attributeOccurrence.MethodInfo, serviceInstance);
|
return PerformInvoke(context, attributeOccurrence.MethodInfo, serviceInstance);
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -1,9 +1,11 @@
|
|||||||
using System.Web.Mvc;
|
using System;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
|
||||||
namespace Orchard.DisplayManagement.Implementation {
|
namespace Orchard.DisplayManagement.Implementation {
|
||||||
public class DisplayContext {
|
public class DisplayContext {
|
||||||
public DisplayHelper Display { get; set; }
|
public DisplayHelper Display { get; set; }
|
||||||
public ViewContext ViewContext { get; set; }
|
public ViewContext ViewContext { get; set; }
|
||||||
|
public IViewDataContainer ViewDataContainer { get; set; }
|
||||||
public object Value { get; set; }
|
public object Value { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -67,7 +67,7 @@ namespace Orchard.DisplayManagement.Implementation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public object ShapeExecute(object shape) {
|
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);
|
return _displayManager.Execute(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,6 +10,8 @@ using Orchard.Environment.Extensions.Loaders;
|
|||||||
using Orchard.Environment.Extensions.Models;
|
using Orchard.Environment.Extensions.Models;
|
||||||
using Orchard.Localization;
|
using Orchard.Localization;
|
||||||
using Orchard.Logging;
|
using Orchard.Logging;
|
||||||
|
using Orchard.Utility;
|
||||||
|
using Orchard.Utility.Extensions;
|
||||||
|
|
||||||
namespace Orchard.Environment.Extensions {
|
namespace Orchard.Environment.Extensions {
|
||||||
public class ExtensionManager : IExtensionManager {
|
public class ExtensionManager : IExtensionManager {
|
||||||
@@ -31,6 +33,15 @@ namespace Orchard.Environment.Extensions {
|
|||||||
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
||||||
return _folders.SelectMany(folder => folder.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() {
|
private IEnumerable<ExtensionEntry> LoadedModules() {
|
||||||
foreach (var descriptor in AvailableExtensions()) {
|
foreach (var descriptor in AvailableExtensions()) {
|
||||||
|
@@ -5,7 +5,9 @@ using Orchard.Environment.Extensions.Models;
|
|||||||
namespace Orchard.Environment.Extensions {
|
namespace Orchard.Environment.Extensions {
|
||||||
public interface IExtensionManager {
|
public interface IExtensionManager {
|
||||||
IEnumerable<ExtensionDescriptor> AvailableExtensions();
|
IEnumerable<ExtensionDescriptor> AvailableExtensions();
|
||||||
|
IEnumerable<FeatureDescriptor> AvailableFeatures();
|
||||||
IEnumerable<Feature> LoadFeatures(IEnumerable<FeatureDescriptor> featureDescriptors);
|
IEnumerable<Feature> LoadFeatures(IEnumerable<FeatureDescriptor> featureDescriptors);
|
||||||
|
|
||||||
void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle);
|
void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle);
|
||||||
void UninstallExtension(string extensionType, string extensionName);
|
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));
|
var records = BuildBlueprint(features, IsRecord, (t, f) => BuildRecord(t, f, settings));
|
||||||
|
|
||||||
return new ShellBlueprint {
|
return new ShellBlueprint {
|
||||||
|
Settings = settings,
|
||||||
|
Descriptor = descriptor,
|
||||||
Dependencies = dependencies.Concat(modules).ToArray(),
|
Dependencies = dependencies.Concat(modules).ToArray(),
|
||||||
Controllers = controllers,
|
Controllers = controllers,
|
||||||
Records = records,
|
Records = records,
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Orchard.Environment.Configuration;
|
||||||
using Orchard.Environment.Descriptor.Models;
|
using Orchard.Environment.Descriptor.Models;
|
||||||
using Orchard.Environment.Extensions.Models;
|
using Orchard.Environment.Extensions.Models;
|
||||||
|
|
||||||
@@ -11,6 +12,9 @@ namespace Orchard.Environment.ShellBuilders.Models {
|
|||||||
/// and is passed into the IShellContainerFactory.
|
/// and is passed into the IShellContainerFactory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ShellBlueprint {
|
public class ShellBlueprint {
|
||||||
|
public ShellSettings Settings { get; set; }
|
||||||
|
public ShellDescriptor Descriptor { get; set; }
|
||||||
|
|
||||||
public IEnumerable<DependencyBlueprint> Dependencies { get; set; }
|
public IEnumerable<DependencyBlueprint> Dependencies { get; set; }
|
||||||
public IEnumerable<ControllerBlueprint> Controllers { get; set; }
|
public IEnumerable<ControllerBlueprint> Controllers { get; set; }
|
||||||
public IEnumerable<RecordBlueprint> Records { get; set; }
|
public IEnumerable<RecordBlueprint> Records { get; set; }
|
||||||
|
@@ -52,6 +52,7 @@ namespace Orchard.Environment.ShellBuilders {
|
|||||||
|
|
||||||
builder.Register(ctx => dynamicProxyContext);
|
builder.Register(ctx => dynamicProxyContext);
|
||||||
builder.Register(ctx => settings);
|
builder.Register(ctx => settings);
|
||||||
|
builder.Register(ctx => blueprint.Descriptor);
|
||||||
builder.Register(ctx => blueprint);
|
builder.Register(ctx => blueprint);
|
||||||
|
|
||||||
var moduleIndex = intermediateScope.Resolve<IIndex<Type, IModule>>();
|
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 System.Web.Mvc;
|
||||||
|
using Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy;
|
||||||
|
using Orchard.FileSystems.VirtualPath;
|
||||||
using Orchard.Logging;
|
using Orchard.Logging;
|
||||||
using Orchard.Mvc.ViewEngines.WebForms;
|
using Orchard.Mvc.ViewEngines.WebForms;
|
||||||
|
|
||||||
namespace Orchard.Mvc.ViewEngines.Razor {
|
namespace Orchard.Mvc.ViewEngines.Razor {
|
||||||
public class RazorViewEngineProvider : IViewEngineProvider {
|
public class RazorViewEngineProvider : IViewEngineProvider, IShapeTemplateViewEngine {
|
||||||
public RazorViewEngineProvider() {
|
private readonly IVirtualPathProvider _virtualPathProvider;
|
||||||
|
|
||||||
|
public RazorViewEngineProvider(IVirtualPathProvider virtualPathProvider) {
|
||||||
|
_virtualPathProvider = virtualPathProvider;
|
||||||
Logger = NullLogger.Instance;
|
Logger = NullLogger.Instance;
|
||||||
RazorCompilationEventsShim.EnsureInitialized();
|
RazorCompilationEventsShim.EnsureInitialized();
|
||||||
}
|
}
|
||||||
@@ -82,5 +90,14 @@ namespace Orchard.Mvc.ViewEngines.Razor {
|
|||||||
|
|
||||||
return viewEngine;
|
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.Compilation;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
|
|
||||||
@@ -6,8 +7,12 @@ namespace Orchard.Mvc.ViewEngines.WebForms {
|
|||||||
public class WebFormViewEngineForAspNet4 : WebFormViewEngine {
|
public class WebFormViewEngineForAspNet4 : WebFormViewEngine {
|
||||||
protected override bool FileExists(ControllerContext controllerContext, string virtualPath) {
|
protected override bool FileExists(ControllerContext controllerContext, string virtualPath) {
|
||||||
try {
|
try {
|
||||||
|
if (virtualPath.EndsWith(".aspx", StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
return BuildManager.GetObjectFactory(virtualPath, false) != null;
|
virtualPath.EndsWith(".ascx", StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
virtualPath.EndsWith(".master", StringComparison.InvariantCultureIgnoreCase)) {
|
||||||
|
return BuildManager.GetObjectFactory(virtualPath, false) != null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
catch (HttpException exception) {
|
catch (HttpException exception) {
|
||||||
// Reproducing base class behavior, however these this code path should
|
// Reproducing base class behavior, however these this code path should
|
||||||
|
@@ -380,6 +380,8 @@
|
|||||||
<Compile Include="DisplayManagement\Descriptors\DefaultShapeTableFactory.cs" />
|
<Compile Include="DisplayManagement\Descriptors\DefaultShapeTableFactory.cs" />
|
||||||
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeStrategy\ShapeAttributeBindingModule.cs" />
|
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeStrategy\ShapeAttributeBindingModule.cs" />
|
||||||
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeStrategy\ShapeAttributeOccurrence.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\ShapeAttribute.cs" />
|
||||||
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeStrategy\ShapeAttributeBindingStrategy.cs" />
|
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeStrategy\ShapeAttributeBindingStrategy.cs" />
|
||||||
<Compile Include="DisplayManagement\Implementation\DefaultDisplayManager.cs" />
|
<Compile Include="DisplayManagement\Implementation\DefaultDisplayManager.cs" />
|
||||||
|
Reference in New Issue
Block a user