diff --git a/src/Orchard.Tests/DisplayManagement/Descriptors/ContainerTestBase.cs b/src/Orchard.Tests/DisplayManagement/Descriptors/ContainerTestBase.cs index d2bf35180..48103c1da 100644 --- a/src/Orchard.Tests/DisplayManagement/Descriptors/ContainerTestBase.cs +++ b/src/Orchard.Tests/DisplayManagement/Descriptors/ContainerTestBase.cs @@ -10,7 +10,6 @@ namespace Orchard.Tests.DisplayManagement.Descriptors { [SetUp] public virtual void Init() { var builder = new ContainerBuilder(); - builder.RegisterAutoMocking(); Register(builder); _container = builder.Build(); Resolve(_container); diff --git a/src/Orchard.Tests/DisplayManagement/Descriptors/ShapeAttributeBindingStrategyTests.cs b/src/Orchard.Tests/DisplayManagement/Descriptors/ShapeAttributeBindingStrategyTests.cs index 36685bf7e..f613981fc 100644 --- a/src/Orchard.Tests/DisplayManagement/Descriptors/ShapeAttributeBindingStrategyTests.cs +++ b/src/Orchard.Tests/DisplayManagement/Descriptors/ShapeAttributeBindingStrategyTests.cs @@ -9,6 +9,7 @@ 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] @@ -16,6 +17,7 @@ namespace Orchard.Tests.DisplayManagement.Descriptors { private FeatureDescriptor _testFeature; protected override void Register(Autofac.ContainerBuilder builder) { + builder.RegisterAutoMocking(); _testFeature = new FeatureDescriptor { Name = "Testing", Extension = new ExtensionDescriptor { Name = "Testing" } }; builder.RegisterType().As(); builder.RegisterInstance(new TestProvider()).WithMetadata("Feature", _testFeature); diff --git a/src/Orchard.Tests/DisplayManagement/Descriptors/ShapeTemplateBindingStrategyTests.cs b/src/Orchard.Tests/DisplayManagement/Descriptors/ShapeTemplateBindingStrategyTests.cs new file mode 100644 index 000000000..c18fd35b8 --- /dev/null +++ b/src/Orchard.Tests/DisplayManagement/Descriptors/ShapeTemplateBindingStrategyTests.cs @@ -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 _features; + private TestViewEngine _testViewEngine; + + + protected override void Register(Autofac.ContainerBuilder builder) { + _descriptor = new ShellDescriptor { }; + _testViewEngine = new TestViewEngine(); + + builder.Register(ctx => _descriptor); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterInstance(_testViewEngine).As(); + + var extensionManager = new Mock(); + builder.Register(ctx => extensionManager); + builder.Register(ctx => extensionManager.Object); + } + + public class TestViewEngine : Dictionary, IShapeTemplateViewEngine { + public IEnumerable 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(); + + container.Resolve>() + .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(); + var builder = new ShapeTableBuilder(); + strategy.Discover(builder); + var alterations = builder.Build(); + + Assert.That(alterations.Any(alt => alt.ShapeType == "AlphaShape")); + } + + } +} diff --git a/src/Orchard.Tests/DisplayManagement/DisplayHelperTests.cs b/src/Orchard.Tests/DisplayManagement/DisplayHelperTests.cs deleted file mode 100644 index 52569fb86..000000000 --- a/src/Orchard.Tests/DisplayManagement/DisplayHelperTests.cs +++ /dev/null @@ -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(); - var shapeFactory = new Mock(); - - 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>())); - //displayManager.Verify(dm => dm.Execute(It.IsAny(), viewContext, null)); - } - [Test] - public void DisplayingShapeWithArgumentsDynamically() { - var viewContext = new ViewContext(); - - var displayManager = new Mock(); - var shapeFactory = new Mock(); - - 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>())); - //displayManager.Verify(dm => dm.Execute(It.IsAny(), viewContext, null)); - } - - - - [Test] - public void UsingDisplayAsFunctionAndPassingInTheShape() { - var viewContext = new ViewContext(); - - var displayManager = new Mock(); - var shapeFactory = new Mock(); - - 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)); - } - } -} diff --git a/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs b/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs index 5b14c684f..d72148395 100644 --- a/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs +++ b/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs @@ -93,6 +93,11 @@ namespace Orchard.Tests.Environment { yield return ext; } + public IEnumerable AvailableFeatures() { + // note - doesn't order properly + return AvailableExtensions().SelectMany(ed => ed.Features); + } + public IEnumerable LoadFeatures(IEnumerable featureDescriptors) { foreach (var descriptor in featureDescriptors) { if (descriptor.Name == "Orchard.Framework") { diff --git a/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs b/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs index f967ea44d..1301f5604 100644 --- a/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs +++ b/src/Orchard.Tests/Environment/Extensions/ExtensionManagerTests.cs @@ -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(" - + diff --git a/src/Orchard.Web/Modules/Orchard.DevTools/Orchard.DevTools.csproj b/src/Orchard.Web/Modules/Orchard.DevTools/Orchard.DevTools.csproj index f74e91ce1..c86fb5eff 100644 --- a/src/Orchard.Web/Modules/Orchard.DevTools/Orchard.DevTools.csproj +++ b/src/Orchard.Web/Modules/Orchard.DevTools/Orchard.DevTools.csproj @@ -126,6 +126,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.DevTools/Shapes.cs b/src/Orchard.Web/Modules/Orchard.DevTools/Shapes.cs index fa319bfac..a7001b6b3 100644 --- a/src/Orchard.Web/Modules/Orchard.DevTools/Shapes.cs +++ b/src/Orchard.Web/Modules/Orchard.DevTools/Shapes.cs @@ -29,7 +29,10 @@ namespace Orchard.DevTools { tag.GenerateId("zone-" + Shape.Name); tag.AddCssClass("zone-" + Shape.Name); tag.AddCssClass("zone"); - tag.InnerHtml = Combine(DisplayAll(Display, Shape).ToArray()).ToString(); + + IEnumerable all = DisplayAll(Display, Shape); + tag.InnerHtml = Combine(all.ToArray()).ToString(); + return new HtmlString(tag.ToString()); } diff --git a/src/Orchard.Web/Modules/Orchard.DevTools/Views/Home/UsingShapes.cshtml b/src/Orchard.Web/Modules/Orchard.DevTools/Views/Home/UsingShapes.cshtml index d71563273..1bbc1b8fd 100644 --- a/src/Orchard.Web/Modules/Orchard.DevTools/Views/Home/UsingShapes.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DevTools/Views/Home/UsingShapes.cshtml @@ -1,14 +1,16 @@ 
-a @Display.Title(text:"This is everything") -b @Display(Model) +a @Display.Title(text:"This is everything") +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)
diff --git a/src/Orchard.Web/Modules/Orchard.DevTools/Views/Rounded.cshtml b/src/Orchard.Web/Modules/Orchard.DevTools/Views/Rounded.cshtml new file mode 100644 index 000000000..1074a92e5 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DevTools/Views/Rounded.cshtml @@ -0,0 +1,6 @@ +
+ @model dynamic +

above

+ @Display(Model.Contents) +

below

+
diff --git a/src/Orchard/DisplayManagement/Descriptors/ShapeAttributeStrategy/ShapeAttributeBindingStrategy.cs b/src/Orchard/DisplayManagement/Descriptors/ShapeAttributeStrategy/ShapeAttributeBindingStrategy.cs index 84686dcf9..7efeeef48 100644 --- a/src/Orchard/DisplayManagement/Descriptors/ShapeAttributeStrategy/ShapeAttributeBindingStrategy.cs +++ b/src/Orchard/DisplayManagement/Descriptors/ShapeAttributeStrategy/ShapeAttributeBindingStrategy.cs @@ -13,13 +13,14 @@ using Orchard.Environment; namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy { public class ShapeAttributeBindingStrategy : IShapeDescriptorBindingStrategy { private readonly IEnumerable _shapeAttributeOccurrences; - private readonly IOrchardHostContainer _orchardHostContainer; + private readonly IComponentContext _componentContext; public ShapeAttributeBindingStrategy( IEnumerable shapeAttributeOccurrences, - IOrchardHostContainer orchardHostContainer) { + IComponentContext componentContext) { _shapeAttributeOccurrences = shapeAttributeOccurrences; - _orchardHostContainer = orchardHostContainer; + // todo: using a component context won't work when this is singleton + _componentContext = componentContext; } public void Discover(ShapeTableBuilder builder) { @@ -37,8 +38,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy { ShapeAttributeOccurrence attributeOccurrence, ShapeDescriptor descriptor) { return context => { - var componentContext = _orchardHostContainer.Resolve(); - var serviceInstance = componentContext.Resolve(attributeOccurrence.Registration, Enumerable.Empty()); + var serviceInstance = _componentContext.Resolve(attributeOccurrence.Registration, Enumerable.Empty()); // oversimplification for the sake of evolving return PerformInvoke(context, attributeOccurrence.MethodInfo, serviceInstance); diff --git a/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/IShapeTemplateHarvester.cs b/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/IShapeTemplateHarvester.cs new file mode 100644 index 000000000..dde0f1b77 --- /dev/null +++ b/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/IShapeTemplateHarvester.cs @@ -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 { + /// + /// This service determines which paths to examine, and provides + /// the shape type based on the template file paths discovered + /// + public interface IShapeTemplateHarvester : IDependency { + IEnumerable SubPaths(); + IEnumerable HarvestShape(HarvestShapeInfo info); + } + + public class BasicShapeTemplateHarvester : IShapeTemplateHarvester { + private readonly IEnumerable _shapeTemplateViewEngines; + + public BasicShapeTemplateHarvester(IEnumerable shapeTemplateViewEngines) { + _shapeTemplateViewEngines = shapeTemplateViewEngines; + } + + public IEnumerable SubPaths() { + return new[] { "Views", "Views/Items", "Views/Parts", "Views/Fields" }; + } + + public IEnumerable 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 DetectTemplateFileNames(string virtualPath); + } + +} diff --git a/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs b/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs new file mode 100644 index 000000000..41f49eb94 --- /dev/null +++ b/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs @@ -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 _harvesters; + private readonly IEnumerable _shapeTemplateViewEngines; + + public ShapeTemplateBindingStrategy( + IEnumerable harvesters, + ShellDescriptor shellDescriptor, + IExtensionManager extensionManager, + IEnumerable shapeTemplateViewEngines) { + _harvesters = harvesters; + _shellDescriptor = shellDescriptor; + _extensionManager = extensionManager; + _shapeTemplateViewEngines = shapeTemplateViewEngines; + } + + private static IEnumerable Once(IEnumerable featureDescriptors) { + var once = new ConcurrentDictionary(); + 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); + } + + } +} diff --git a/src/Orchard/DisplayManagement/Implementation/DisplayContext.cs b/src/Orchard/DisplayManagement/Implementation/DisplayContext.cs index 398b3c0ae..f1afbb6c7 100644 --- a/src/Orchard/DisplayManagement/Implementation/DisplayContext.cs +++ b/src/Orchard/DisplayManagement/Implementation/DisplayContext.cs @@ -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; } } } diff --git a/src/Orchard/DisplayManagement/Implementation/DisplayHelper.cs b/src/Orchard/DisplayManagement/Implementation/DisplayHelper.cs index 78f3b9547..ffbdbea70 100644 --- a/src/Orchard/DisplayManagement/Implementation/DisplayHelper.cs +++ b/src/Orchard/DisplayManagement/Implementation/DisplayHelper.cs @@ -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); } diff --git a/src/Orchard/Environment/Extensions/ExtensionManager.cs b/src/Orchard/Environment/Extensions/ExtensionManager.cs index 99ec652a7..eac94aa90 100644 --- a/src/Orchard/Environment/Extensions/ExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/ExtensionManager.cs @@ -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 AvailableExtensions() { return _folders.SelectMany(folder => folder.AvailableExtensions()); } + + public IEnumerable 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 LoadedModules() { foreach (var descriptor in AvailableExtensions()) { diff --git a/src/Orchard/Environment/Extensions/IExtensionManager.cs b/src/Orchard/Environment/Extensions/IExtensionManager.cs index be0950a66..68377af42 100644 --- a/src/Orchard/Environment/Extensions/IExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/IExtensionManager.cs @@ -5,7 +5,9 @@ using Orchard.Environment.Extensions.Models; namespace Orchard.Environment.Extensions { public interface IExtensionManager { IEnumerable AvailableExtensions(); + IEnumerable AvailableFeatures(); IEnumerable LoadFeatures(IEnumerable featureDescriptors); + void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle); void UninstallExtension(string extensionType, string extensionName); } diff --git a/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs b/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs index cdbcf23e1..db5c8b1b2 100644 --- a/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs +++ b/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs @@ -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, diff --git a/src/Orchard/Environment/ShellBuilders/Models/ShellBlueprint.cs b/src/Orchard/Environment/ShellBuilders/Models/ShellBlueprint.cs index 027d9012e..2f49e08dd 100644 --- a/src/Orchard/Environment/ShellBuilders/Models/ShellBlueprint.cs +++ b/src/Orchard/Environment/ShellBuilders/Models/ShellBlueprint.cs @@ -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. /// public class ShellBlueprint { + public ShellSettings Settings { get; set; } + public ShellDescriptor Descriptor { get; set; } + public IEnumerable Dependencies { get; set; } public IEnumerable Controllers { get; set; } public IEnumerable Records { get; set; } diff --git a/src/Orchard/Environment/ShellBuilders/ShellContainerFactory.cs b/src/Orchard/Environment/ShellBuilders/ShellContainerFactory.cs index dccb4d324..24a108c9c 100644 --- a/src/Orchard/Environment/ShellBuilders/ShellContainerFactory.cs +++ b/src/Orchard/Environment/ShellBuilders/ShellContainerFactory.cs @@ -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>(); diff --git a/src/Orchard/Mvc/ViewEngines/Razor/RazorViewEngineProvider.cs b/src/Orchard/Mvc/ViewEngines/Razor/RazorViewEngineProvider.cs index f2ef6b61d..bd42ebf7c 100644 --- a/src/Orchard/Mvc/ViewEngines/Razor/RazorViewEngineProvider.cs +++ b/src/Orchard/Mvc/ViewEngines/Razor/RazorViewEngineProvider.cs @@ -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 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); + } + } + } } } diff --git a/src/Orchard/Mvc/ViewEngines/WebForms/WebFormViewEngineForAspNet4.cs b/src/Orchard/Mvc/ViewEngines/WebForms/WebFormViewEngineForAspNet4.cs index 1af79428f..2e39255e5 100644 --- a/src/Orchard/Mvc/ViewEngines/WebForms/WebFormViewEngineForAspNet4.cs +++ b/src/Orchard/Mvc/ViewEngines/WebForms/WebFormViewEngineForAspNet4.cs @@ -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 diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 8b48a8259..be2819bd4 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -380,6 +380,8 @@ + +