diff --git a/src/Orchard.Web/Modules/Orchard.DevTools/Controllers/InventoryController.cs b/src/Orchard.Web/Modules/Orchard.DevTools/Controllers/InventoryController.cs new file mode 100644 index 000000000..863096119 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DevTools/Controllers/InventoryController.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using Orchard.DisplayManagement.Descriptors; +using Orchard.Themes; +using Orchard.UI.Admin; + +namespace Orchard.DevTools.Controllers { + [Themed, Admin] + public class InventoryController : Controller { + private readonly IShapeTableManager _shapeTableManager; + + public InventoryController(IShapeTableManager shapeTableManager) { + _shapeTableManager = shapeTableManager; + } + + public ActionResult ShapeTable(string themeName) { + return View("ShapeTable", _shapeTableManager.GetShapeTable(themeName)); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DevTools/Orchard.DevTools.csproj b/src/Orchard.Web/Modules/Orchard.DevTools/Orchard.DevTools.csproj index 232cd1f6c..1cb76f27a 100644 --- a/src/Orchard.Web/Modules/Orchard.DevTools/Orchard.DevTools.csproj +++ b/src/Orchard.Web/Modules/Orchard.DevTools/Orchard.DevTools.csproj @@ -77,6 +77,7 @@ + @@ -127,6 +128,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.DevTools/Views/Inventory/ShapeTable.cshtml b/src/Orchard.Web/Modules/Orchard.DevTools/Views/Inventory/ShapeTable.cshtml new file mode 100644 index 000000000..9a39f3d15 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DevTools/Views/Inventory/ShapeTable.cshtml @@ -0,0 +1,12 @@ + +
+ @model Orchard.DisplayManagement.Descriptors.ShapeTable; +
    + @foreach(var descriptor in Model.Descriptors) { +
  • + @descriptor.Key +

    @descriptor.Value.BindingSource

    +
  • + } +
+
diff --git a/src/Orchard.Web/Orchard.Web.csproj b/src/Orchard.Web/Orchard.Web.csproj index 13a8b771b..f4ed1d69e 100644 --- a/src/Orchard.Web/Orchard.Web.csproj +++ b/src/Orchard.Web/Orchard.Web.csproj @@ -310,6 +310,7 @@ + diff --git a/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs b/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs index 74b3b74cb..c3dc68272 100644 --- a/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs +++ b/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs @@ -18,7 +18,8 @@ namespace Orchard.DisplayManagement.Descriptors { bindingStrategy.Discover(builder); } // placeholder - alterations will need to be selective and in a particular order - + + // GroupBy has been determined to preserve the order of items in original series _shapeTable = new ShapeTable { Descriptors = builder.Build() .GroupBy(alteration => alteration.ShapeType) diff --git a/src/Orchard/DisplayManagement/Descriptors/Interfaces.cs b/src/Orchard/DisplayManagement/Descriptors/Interfaces.cs index fec859525..7dc5a8898 100644 --- a/src/Orchard/DisplayManagement/Descriptors/Interfaces.cs +++ b/src/Orchard/DisplayManagement/Descriptors/Interfaces.cs @@ -25,6 +25,13 @@ namespace Orchard.DisplayManagement.Descriptors { public class ShapeDescriptor { public string ShapeType { get; set; } + + /// + /// The BindingSource is informational text about the source of the Binding delegate. Not used except for + /// troubleshooting. + /// + public string BindingSource { get; set; } + public Func Binding { get; set; } } @@ -89,12 +96,14 @@ namespace Orchard.DisplayManagement.Descriptors { return this; } - public ShapeDescriptorAlterationBuilder BoundAs(Func> binder) { + public ShapeDescriptorAlterationBuilder BoundAs(string bindingSource, Func> binder) { // schedule the configuration return Configure(descriptor => { Func target = null; + descriptor.BindingSource = bindingSource; + // announce the binding, which may be reconfigured before it's used descriptor.Binding = displayContext => { diff --git a/src/Orchard/DisplayManagement/Descriptors/ShapeAttributeStrategy/ShapeAttributeBindingStrategy.cs b/src/Orchard/DisplayManagement/Descriptors/ShapeAttributeStrategy/ShapeAttributeBindingStrategy.cs index f46109101..f50300d13 100644 --- a/src/Orchard/DisplayManagement/Descriptors/ShapeAttributeStrategy/ShapeAttributeBindingStrategy.cs +++ b/src/Orchard/DisplayManagement/Descriptors/ShapeAttributeStrategy/ShapeAttributeBindingStrategy.cs @@ -36,7 +36,9 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy { builder.Describe .Named(shapeType) .From(occurrence.Feature) - .BoundAs(descriptor => CreateDelegate(occurrence, descriptor)); + .BoundAs( + occurrence.MethodInfo.DeclaringType.FullName + "::" + occurrence.MethodInfo.Name, + descriptor => CreateDelegate(occurrence, descriptor)); } } @@ -45,7 +47,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy { ShapeDescriptor descriptor) { return context => { 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/ShapeTemplateBindingStrategy.cs b/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs index 900b0ecf8..241272700 100644 --- a/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs +++ b/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs @@ -38,7 +38,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy { 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 activeFeatures = availableFeatures.Where(fd => FeatureIsTheme(fd) || FeatureIsEnabled(fd)); var activeExtensions = Once(activeFeatures); var hits = activeExtensions.SelectMany(extensionDescriptor => { @@ -50,7 +50,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy { 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 }); + return fileNames.Select(fileName => new { fileName = Path.GetFileNameWithoutExtension(fileName), fileVirtualPath = Path.Combine(pathContext.virtualPath, fileName).Replace('\\','/'), pathContext }); })); var shapeContexts = fileContexts.SelectMany(fileContext => { @@ -75,15 +75,24 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy { builder.Describe .From(featureDescriptor) .Named(iter.shapeContext.harvestShapeHit.ShapeType) - .BoundAs(shapeDescriptor => displayContext => Render(shapeDescriptor, displayContext, hit.shapeContext.harvestShapeInfo, hit.shapeContext.harvestShapeHit)); + .BoundAs( + hit.shapeContext.harvestShapeInfo.TemplateVirtualPath, + shapeDescriptor => displayContext => Render(shapeDescriptor, displayContext, hit.shapeContext.harvestShapeInfo, hit.shapeContext.harvestShapeHit)); } } } + private bool FeatureIsTheme(FeatureDescriptor fd) { + return fd.Extension.ExtensionType == "Theme"; + } + + private bool FeatureIsEnabled(FeatureDescriptor fd) { + return _shellDescriptor.Features.Any(sf => sf.Name == fd.Name); + } + private IHtmlString 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); + return htmlHelper.Partial(harvestShapeInfo.TemplateVirtualPath, displayContext.Value); } } diff --git a/src/Orchard/DisplayManagement/Implementation/DefaultDisplayManager.cs b/src/Orchard/DisplayManagement/Implementation/DefaultDisplayManager.cs index 52adbaab7..987efda19 100644 --- a/src/Orchard/DisplayManagement/Implementation/DefaultDisplayManager.cs +++ b/src/Orchard/DisplayManagement/Implementation/DefaultDisplayManager.cs @@ -11,7 +11,6 @@ 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 private static readonly CallSite> _convertAsShapeCallsite = CallSite>.Create( diff --git a/src/Orchard/Environment/Extensions/ExtensionManager.cs b/src/Orchard/Environment/Extensions/ExtensionManager.cs index eac94aa90..d15f5158a 100644 --- a/src/Orchard/Environment/Extensions/ExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/ExtensionManager.cs @@ -36,12 +36,26 @@ namespace Orchard.Environment.Extensions { 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))); + var featureDescriptorsOrdered = featureDescriptors.OrderByDependencies(HasDependency); return featureDescriptorsOrdered.ToReadOnlyCollection(); } + /// + /// Returns true if the item has an explicit or implicit dependency on the subject + /// + /// + /// + /// + static bool HasDependency(FeatureDescriptor item, FeatureDescriptor subject) { + // Themes implicitly depend on modules to ensure build and override ordering + if (item.Extension.ExtensionType == "Theme" && subject.Extension.ExtensionType == "Module") + return true; + + // Return based on explicit dependencies + return item.Dependencies != null && + item.Dependencies.Any(x => StringComparer.OrdinalIgnoreCase.Equals(x, subject.Name)); + } + private IEnumerable LoadedModules() { foreach (var descriptor in AvailableExtensions()) { diff --git a/src/Orchard/Mvc/ViewEngines/Razor/RazorViewEngineProvider.cs b/src/Orchard/Mvc/ViewEngines/Razor/RazorViewEngineProvider.cs index bd42ebf7c..7bbe0d567 100644 --- a/src/Orchard/Mvc/ViewEngines/Razor/RazorViewEngineProvider.cs +++ b/src/Orchard/Mvc/ViewEngines/Razor/RazorViewEngineProvider.cs @@ -95,7 +95,7 @@ namespace Orchard.Mvc.ViewEngines.Razor { 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); + yield return fileName; } } }