mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-22 20:13:50 +08:00
Merge
--HG-- branch : dev
This commit is contained in:
@@ -145,6 +145,35 @@ namespace Orchard.Tests.DisplayManagement {
|
|||||||
Assert.That(result.ToString(), Is.EqualTo("Hi there!"));
|
Assert.That(result.ToString(), Is.EqualTo("Hi there!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RenderPreCalculatedShape() {
|
||||||
|
var displayManager = _container.Resolve<IDisplayManager>();
|
||||||
|
|
||||||
|
var shape = new Shape {
|
||||||
|
Metadata = new ShapeMetadata {
|
||||||
|
Type = "Foo"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
shape.Metadata.OnDisplaying(
|
||||||
|
context => {
|
||||||
|
context.ChildContent = new HtmlString("Bar");
|
||||||
|
});
|
||||||
|
|
||||||
|
var descriptor = new ShapeDescriptor {
|
||||||
|
ShapeType = "Foo",
|
||||||
|
};
|
||||||
|
descriptor.Bindings["Foo"] = new ShapeBinding {
|
||||||
|
BindingName = "Foo",
|
||||||
|
Binding = ctx => new HtmlString("Hi there!"),
|
||||||
|
};
|
||||||
|
|
||||||
|
AddShapeDescriptor(descriptor);
|
||||||
|
|
||||||
|
var result = displayManager.Execute(CreateDisplayContext(shape));
|
||||||
|
Assert.That(result.ToString(), Is.EqualTo("Bar"));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void RenderFallbackShape() {
|
public void RenderFallbackShape() {
|
||||||
var displayManager = _container.Resolve<IDisplayManager>();
|
var displayManager = _container.Resolve<IDisplayManager>();
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
using Orchard.ContentManagement;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
using Orchard.DisplayManagement.Descriptors;
|
using Orchard.DisplayManagement.Descriptors;
|
||||||
|
|
||||||
namespace Orchard.Core.Contents {
|
namespace Orchard.Core.Contents {
|
||||||
@@ -12,16 +15,19 @@ namespace Orchard.Core.Contents {
|
|||||||
.OnDisplaying(displaying => {
|
.OnDisplaying(displaying => {
|
||||||
ContentItem contentItem = displaying.Shape.ContentItem;
|
ContentItem contentItem = displaying.Shape.ContentItem;
|
||||||
if (contentItem != null) {
|
if (contentItem != null) {
|
||||||
//Content-BlogPost
|
// Content__[ContentType] e.g. Content-BlogPost
|
||||||
displaying.ShapeMetadata.Alternates.Add("Content__" + contentItem.ContentType);
|
displaying.ShapeMetadata.Alternates.Add("Content__" + contentItem.ContentType);
|
||||||
//Content-42
|
|
||||||
displaying.ShapeMetadata.Alternates.Add("Content__" + contentItem.Id);
|
// Content_[DisplayType]__[ContentType] e.g. Content-BlogPost.Summary
|
||||||
//Content.Summary
|
|
||||||
displaying.ShapeMetadata.Alternates.Add("Content_" + displaying.ShapeMetadata.DisplayType);
|
|
||||||
//Content-Page.Summary
|
|
||||||
displaying.ShapeMetadata.Alternates.Add("Content_" + displaying.ShapeMetadata.DisplayType + "__" + contentItem.ContentType);
|
displaying.ShapeMetadata.Alternates.Add("Content_" + displaying.ShapeMetadata.DisplayType + "__" + contentItem.ContentType);
|
||||||
|
|
||||||
if (!displaying.ShapeMetadata.DisplayType.Contains("Admin"))
|
// Content__[Id] e.g. Content-42
|
||||||
|
displaying.ShapeMetadata.Alternates.Add("Content__" + contentItem.Id);
|
||||||
|
|
||||||
|
// Content_[DisplayType]__[Id] e.g. Content-42.Summary
|
||||||
|
displaying.ShapeMetadata.Alternates.Add("Content_" + displaying.ShapeMetadata.DisplayType + "__" + contentItem.Id);
|
||||||
|
|
||||||
|
if ( !displaying.ShapeMetadata.DisplayType.Contains("Admin") )
|
||||||
displaying.ShapeMetadata.Wrappers.Add("Content_ControlWrapper");
|
displaying.ShapeMetadata.Wrappers.Add("Content_ControlWrapper");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -7,6 +7,6 @@
|
|||||||
|
|
||||||
@using (Html.BeginFormAntiForgeryPost()) {
|
@using (Html.BeginFormAntiForgeryPost()) {
|
||||||
@Html.ValidationSummary()
|
@Html.ValidationSummary()
|
||||||
// Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type
|
// Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type
|
||||||
@Display(Model)
|
@Display(Model)
|
||||||
}
|
}
|
@@ -9,6 +9,7 @@ using System.Web.Mvc.Html;
|
|||||||
using Orchard.DisplayManagement;
|
using Orchard.DisplayManagement;
|
||||||
using Orchard.DisplayManagement.Descriptors;
|
using Orchard.DisplayManagement.Descriptors;
|
||||||
using Orchard.DisplayManagement.Descriptors.ResourceBindingStrategy;
|
using Orchard.DisplayManagement.Descriptors.ResourceBindingStrategy;
|
||||||
|
using Orchard.Environment;
|
||||||
using Orchard.Mvc;
|
using Orchard.Mvc;
|
||||||
using Orchard.Settings;
|
using Orchard.Settings;
|
||||||
using Orchard.UI;
|
using Orchard.UI;
|
||||||
@@ -20,23 +21,20 @@ using Orchard.Utility.Extensions;
|
|||||||
|
|
||||||
namespace Orchard.Core.Shapes {
|
namespace Orchard.Core.Shapes {
|
||||||
public class CoreShapes : IShapeTableProvider {
|
public class CoreShapes : IShapeTableProvider {
|
||||||
private readonly IWorkContextAccessor _workContextAccessor;
|
private readonly Work<WorkContext> _workContext;
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
private readonly Work<IResourceManager> _resourceManager;
|
||||||
|
private readonly Work<IHttpContextAccessor> _httpContextAccessor;
|
||||||
|
|
||||||
public CoreShapes(IWorkContextAccessor workContextAccessor, IHttpContextAccessor httpContextAccessor) {
|
public CoreShapes(
|
||||||
// needed to get CurrentSite.
|
Work<WorkContext> workContext,
|
||||||
// note that injecting ISiteService here causes a stack overflow in AutoFac!
|
Work<IResourceManager> resourceManager,
|
||||||
_workContextAccessor = workContextAccessor;
|
Work<IHttpContextAccessor> httpContextAccessor
|
||||||
|
) {
|
||||||
|
_workContext = workContext;
|
||||||
|
_resourceManager = resourceManager;
|
||||||
_httpContextAccessor = httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not injected the usual way because this component is a 'static' dependency and RM is per-request
|
|
||||||
private IResourceManager ResourceManager {
|
|
||||||
get {
|
|
||||||
return _workContextAccessor.GetContext(_httpContextAccessor.Current()).Resolve<IResourceManager>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Discover(ShapeTableBuilder builder) {
|
public void Discover(ShapeTableBuilder builder) {
|
||||||
// the root page shape named 'Layout' is wrapped with 'Document'
|
// the root page shape named 'Layout' is wrapped with 'Document'
|
||||||
// and has an automatic zone creating behavior
|
// and has an automatic zone creating behavior
|
||||||
@@ -54,6 +52,7 @@ namespace Orchard.Core.Shapes {
|
|||||||
layout.Content = created.New.Zone();
|
layout.Content = created.New.Zone();
|
||||||
layout.Content.ZoneName = "Content";
|
layout.Content.ZoneName = "Content";
|
||||||
layout.Content.Add(created.New.PlaceChildContent(Source: layout));
|
layout.Content.Add(created.New.PlaceChildContent(Source: layout));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 'Zone' shapes are built on the Zone base class
|
// 'Zone' shapes are built on the Zone base class
|
||||||
@@ -66,6 +65,8 @@ namespace Orchard.Core.Shapes {
|
|||||||
string zoneName = zone.ZoneName;
|
string zoneName = zone.ZoneName;
|
||||||
zone.Classes.Add("zone-" + zoneName.HtmlClassify());
|
zone.Classes.Add("zone-" + zoneName.HtmlClassify());
|
||||||
zone.Classes.Add("zone");
|
zone.Classes.Add("zone");
|
||||||
|
|
||||||
|
// Zone__[ZoneName] e.g. Zone-SideBar
|
||||||
zone.Metadata.Alternates.Add("Zone__" + zoneName);
|
zone.Metadata.Alternates.Add("Zone__" + zoneName);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -208,25 +209,25 @@ namespace Orchard.Core.Shapes {
|
|||||||
[Shape]
|
[Shape]
|
||||||
public void HeadScripts(dynamic Display, TextWriter Output) {
|
public void HeadScripts(dynamic Display, TextWriter Output) {
|
||||||
WriteResources(Display, Output, "script", ResourceLocation.Head, null);
|
WriteResources(Display, Output, "script", ResourceLocation.Head, null);
|
||||||
WriteLiteralScripts(Output, ResourceManager.GetRegisteredHeadScripts());
|
WriteLiteralScripts(Output, _resourceManager.Value.GetRegisteredHeadScripts());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Shape]
|
[Shape]
|
||||||
public void FootScripts(dynamic Display, TextWriter Output) {
|
public void FootScripts(dynamic Display, TextWriter Output) {
|
||||||
WriteResources(Display, Output, "script", null, ResourceLocation.Head);
|
WriteResources(Display, Output, "script", null, ResourceLocation.Head);
|
||||||
WriteLiteralScripts(Output, ResourceManager.GetRegisteredFootScripts());
|
WriteLiteralScripts(Output, _resourceManager.Value.GetRegisteredFootScripts());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Shape]
|
[Shape]
|
||||||
public void Metas(TextWriter Output) {
|
public void Metas(TextWriter Output) {
|
||||||
foreach (var meta in ResourceManager.GetRegisteredMetas()) {
|
foreach (var meta in _resourceManager.Value.GetRegisteredMetas() ) {
|
||||||
Output.WriteLine(meta.GetTag());
|
Output.WriteLine(meta.GetTag());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Shape]
|
[Shape]
|
||||||
public void HeadLinks(TextWriter Output) {
|
public void HeadLinks(TextWriter Output) {
|
||||||
foreach (var link in ResourceManager.GetRegisteredLinks()) {
|
foreach (var link in _resourceManager.Value.GetRegisteredLinks() ) {
|
||||||
Output.WriteLine(link.GetTag());
|
Output.WriteLine(link.GetTag());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,7 +258,7 @@ namespace Orchard.Core.Shapes {
|
|||||||
|
|
||||||
private void WriteResources(dynamic Display, TextWriter Output, string resourceType, ResourceLocation? includeLocation, ResourceLocation? excludeLocation) {
|
private void WriteResources(dynamic Display, TextWriter Output, string resourceType, ResourceLocation? includeLocation, ResourceLocation? excludeLocation) {
|
||||||
bool debugMode;
|
bool debugMode;
|
||||||
var site = _workContextAccessor.GetContext(_httpContextAccessor.Current()).CurrentSite;
|
var site = _workContext.Value.CurrentSite;
|
||||||
switch (site.ResourceDebugMode) {
|
switch (site.ResourceDebugMode) {
|
||||||
case ResourceDebugMode.Enabled:
|
case ResourceDebugMode.Enabled:
|
||||||
debugMode = true;
|
debugMode = true;
|
||||||
@@ -267,15 +268,15 @@ namespace Orchard.Core.Shapes {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Debug.Assert(site.ResourceDebugMode == ResourceDebugMode.FromAppSetting, "Unknown ResourceDebugMode value.");
|
Debug.Assert(site.ResourceDebugMode == ResourceDebugMode.FromAppSetting, "Unknown ResourceDebugMode value.");
|
||||||
debugMode = _httpContextAccessor.Current().IsDebuggingEnabled;
|
debugMode = _httpContextAccessor.Value.Current().IsDebuggingEnabled;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
var defaultSettings = new RequireSettings {
|
var defaultSettings = new RequireSettings {
|
||||||
DebugMode = debugMode,
|
DebugMode = debugMode,
|
||||||
Culture = CultureInfo.CurrentUICulture.Name,
|
Culture = CultureInfo.CurrentUICulture.Name,
|
||||||
};
|
};
|
||||||
var requiredResources = ResourceManager.BuildRequiredResources(resourceType);
|
var requiredResources = _resourceManager.Value.BuildRequiredResources(resourceType);
|
||||||
var appPath = _httpContextAccessor.Current().Request.ApplicationPath;
|
var appPath = _httpContextAccessor.Value.Current().Request.ApplicationPath;
|
||||||
foreach (var context in requiredResources.Where(r =>
|
foreach (var context in requiredResources.Where(r =>
|
||||||
(includeLocation.HasValue ? r.Settings.Location == includeLocation.Value : true) &&
|
(includeLocation.HasValue ? r.Settings.Location == includeLocation.Value : true) &&
|
||||||
(excludeLocation.HasValue ? r.Settings.Location != excludeLocation.Value : true))) {
|
(excludeLocation.HasValue ? r.Settings.Location != excludeLocation.Value : true))) {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
@{
|
@{
|
||||||
Html.AddTitleParts(T("Manage Blog").ToString());
|
Html.AddTitleParts(T("Manage Blog").ToString());
|
||||||
}
|
}
|
||||||
// Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type
|
@* Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type *@
|
||||||
@Display(Model)
|
@Display(Model)
|
||||||
|
@@ -11,3 +11,7 @@ Features:
|
|||||||
Category: Designer
|
Category: Designer
|
||||||
Description: Displays all currently displayed shapes and some information to customize them
|
Description: Displays all currently displayed shapes and some information to customize them
|
||||||
Dependencies: Orchard.jQuery
|
Dependencies: Orchard.jQuery
|
||||||
|
UrlAlternates:
|
||||||
|
Name: Url Alternates
|
||||||
|
Category: Designer
|
||||||
|
Description: Adds shape alternates for specific urls
|
||||||
|
@@ -83,6 +83,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Services\ObjectDumper.cs" />
|
<Compile Include="Services\ObjectDumper.cs" />
|
||||||
<Compile Include="Services\ShapeTracingFactory.cs" />
|
<Compile Include="Services\ShapeTracingFactory.cs" />
|
||||||
|
<Compile Include="Services\UrlAlternatesFactory.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Views\ShapeTracing.Wrapper.cshtml" />
|
<Content Include="Views\ShapeTracing.Wrapper.cshtml" />
|
||||||
|
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
|
using Orchard.DisplayManagement.Implementation;
|
||||||
|
using Orchard.Environment.Extensions;
|
||||||
|
using Orchard.Mvc;
|
||||||
|
|
||||||
|
namespace Orchard.DesignerTools.Services {
|
||||||
|
[OrchardFeature("UrlAlternates")]
|
||||||
|
public class UrlAlternatesFactory : ShapeDisplayEvents {
|
||||||
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
private readonly List<string> _urlAlternates;
|
||||||
|
|
||||||
|
public UrlAlternatesFactory(IHttpContextAccessor httpContextAccessor) {
|
||||||
|
_httpContextAccessor = httpContextAccessor;
|
||||||
|
|
||||||
|
var request = _httpContextAccessor.Current().Request;
|
||||||
|
|
||||||
|
// extract each segment of the url
|
||||||
|
var urlSegments = VirtualPathUtility.ToAppRelative(request.Path.ToLower())
|
||||||
|
.Split('/')
|
||||||
|
.Skip(1) // ignore the heading ~ segment
|
||||||
|
.Select(url => url.Replace("-", "__").Replace(".", "_")) // format the alternate
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if ( String.IsNullOrWhiteSpace(urlSegments[0]) ) {
|
||||||
|
urlSegments[0] = "homepage";
|
||||||
|
}
|
||||||
|
|
||||||
|
_urlAlternates = Enumerable.Range(1, urlSegments.Count()).Select(range => String.Join("__", urlSegments.Take(range))).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Displaying(ShapeDisplayingContext context) {
|
||||||
|
|
||||||
|
context.ShapeMetadata.OnDisplaying(displayedContext => {
|
||||||
|
// appends Url alternates to current ones
|
||||||
|
displayedContext.ShapeMetadata.Alternates = displayedContext.ShapeMetadata.Alternates.SelectMany(
|
||||||
|
alternate => new [] { alternate }.Union(_urlAlternates.Select(a => alternate + "__url__" + a))
|
||||||
|
).ToList();
|
||||||
|
|
||||||
|
// appends [ShapeType__url__[Url] alternates
|
||||||
|
displayedContext.ShapeMetadata.Alternates = _urlAlternates.Select(url => displayedContext.ShapeMetadata.Type + "__url__" + url)
|
||||||
|
.Union(displayedContext.ShapeMetadata.Alternates)
|
||||||
|
.ToList();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -25,8 +25,12 @@ namespace Orchard.Widgets {
|
|||||||
widget.Classes.Add("widget-" + contentItem.ContentType.HtmlClassify());
|
widget.Classes.Add("widget-" + contentItem.ContentType.HtmlClassify());
|
||||||
|
|
||||||
var zoneName = contentItem.As<WidgetPart>().Zone;
|
var zoneName = contentItem.As<WidgetPart>().Zone;
|
||||||
displaying.ShapeMetadata.Alternates.Add("Widget__" + contentItem.ContentType);
|
|
||||||
|
// Widget__[ZoneName] e.g. Widget-SideBar
|
||||||
displaying.ShapeMetadata.Alternates.Add("Widget__" + zoneName);
|
displaying.ShapeMetadata.Alternates.Add("Widget__" + zoneName);
|
||||||
|
|
||||||
|
// Widget__[ContentType] e.g. Widget-BlogArchive
|
||||||
|
displaying.ShapeMetadata.Alternates.Add("Widget__" + contentItem.ContentType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,6 @@ namespace Orchard.ContentManagement.Drivers {
|
|||||||
return contentFieldInfo;
|
return contentFieldInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected virtual DriverResult Display(ContentPart part, TField field, string displayType, dynamic shapeHelper) { return null; }
|
protected virtual DriverResult Display(ContentPart part, TField field, string displayType, dynamic shapeHelper) { return null; }
|
||||||
protected virtual DriverResult Editor(ContentPart part, TField field, dynamic shapeHelper) { return null; }
|
protected virtual DriverResult Editor(ContentPart part, TField field, dynamic shapeHelper) { return null; }
|
||||||
protected virtual DriverResult Editor(ContentPart part, TField field, IUpdateModel updater, dynamic shapeHelper) { return null; }
|
protected virtual DriverResult Editor(ContentPart part, TField field, IUpdateModel updater, dynamic shapeHelper) { return null; }
|
||||||
@@ -69,30 +68,77 @@ namespace Orchard.ContentManagement.Drivers {
|
|||||||
return new ContentShapeResult(shapeType, Prefix, ctx => AddAlternates(shapeBuilder(ctx), differentiator)).Differentiator(differentiator);
|
return new ContentShapeResult(shapeType, Prefix, ctx => AddAlternates(shapeBuilder(ctx), differentiator)).Differentiator(differentiator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private object AddAlternates(dynamic shape, string differentiator) {
|
private static object AddAlternates(dynamic shape, string differentiator) {
|
||||||
// automatically add shape alternates for shapes added by fields
|
// automatically add shape alternates for shapes added by fields
|
||||||
// [ShapeType__FieldName] for ShapeType-FieldName.cshtml templates
|
|
||||||
// [ShapeType__PartName] for ShapeType-PartName.cshtml templates
|
|
||||||
// [ShapeType__PartName__FieldName] for ShapeType-PartName-FieldName.cshtml templates
|
|
||||||
|
|
||||||
// for fields on dynamic parts the part name is the same as the content type name
|
// for fields on dynamic parts the part name is the same as the content type name
|
||||||
// ex. Fields/Common.Text-Something.FirstName
|
|
||||||
|
|
||||||
ShapeMetadata metadata = shape.Metadata;
|
ShapeMetadata metadata = shape.Metadata;
|
||||||
if (!string.IsNullOrEmpty(differentiator))
|
|
||||||
metadata.Alternates.Add(metadata.Type + "__" + differentiator);
|
|
||||||
|
|
||||||
ContentPart part = shape.ContentPart;
|
ContentPart part = shape.ContentPart;
|
||||||
if (part != null) {
|
var shapeType = metadata.Type;
|
||||||
metadata.Alternates.Add(metadata.Type + "__" + part.PartDefinition.Name);
|
var fieldName = differentiator ?? String.Empty;
|
||||||
if (!string.IsNullOrEmpty(differentiator))
|
var partName = part != null ? part.PartDefinition.Name : String.Empty;
|
||||||
metadata.Alternates.Add(metadata.Type + "__" + part.PartDefinition.Name + "__" + differentiator);
|
var contentType = part != null ? part.ContentItem.ContentType : String.Empty;
|
||||||
|
var displayType = metadata.DisplayType ?? String.Empty;
|
||||||
|
var dynamicType = string.Equals(partName, contentType, StringComparison.Ordinal);
|
||||||
|
|
||||||
|
// [ShapeType__FieldName] e.g. Fields/Common.Text-Teaser
|
||||||
|
if ( !string.IsNullOrEmpty(fieldName) )
|
||||||
|
metadata.Alternates.Add(shapeType + "__" + fieldName);
|
||||||
|
|
||||||
|
// [ShapeType__PartName] e.g. Fields/Common.Text-TeaserPart
|
||||||
|
if ( !string.IsNullOrEmpty(partName) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "__" + partName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]__[ContentType]__[PartName] e.g. Fields/Common.Text-Blog-TeaserPart
|
||||||
|
if ( !string.IsNullOrEmpty(partName) && !string.IsNullOrEmpty(contentType) && !dynamicType ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "__" + contentType + "__" + partName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]_[DisplayType]__[FieldName] e.g. Fields/Common.Text-Teaser.Summary
|
||||||
|
if ( !string.IsNullOrEmpty(displayType) && !string.IsNullOrEmpty(fieldName) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "_" + displayType + "__" + fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]__[PartName]__[FieldName] e.g. Fields/Common.Text-TeaserPart-Teaser
|
||||||
|
if ( !string.IsNullOrEmpty(partName) && !string.IsNullOrEmpty(fieldName) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "__" + partName + "__" + fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]__[ContentType]__[FieldName] e.g. Fields/Common.Text-Blog-Teaser
|
||||||
|
if ( !string.IsNullOrEmpty(contentType) && !string.IsNullOrEmpty(fieldName) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "__" + contentType + "__" + fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]__[ContentType]__[PartName]__[FieldName] e.g. Fields/Common.Text-Blog-TeaserPart-Teaser
|
||||||
|
if ( !string.IsNullOrEmpty(contentType) && !string.IsNullOrEmpty(partName) && !string.IsNullOrEmpty(fieldName) && !dynamicType ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "__" + contentType + "__" + partName );
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]_[DisplayType]__[PartName] e.g. Fields/Common.Text-TeaserPart.Summary
|
||||||
|
if ( !string.IsNullOrEmpty(displayType) && !string.IsNullOrEmpty(partName) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "_" + displayType + "__" + partName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]_[DisplayType]__[ContentType]__[PartName] e.g. Fields/Common.Text-Blog-TeaserPart.Summary
|
||||||
|
if ( !string.IsNullOrEmpty(displayType) && !string.IsNullOrEmpty(contentType) && !string.IsNullOrEmpty(partName) && !dynamicType ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "_" + displayType + "__" + contentType + "__" + partName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]_[DisplayType]__[PartName]__[FieldName] e.g. Fields/Common.Text-TeaserPart-Teaser.Summary
|
||||||
|
if ( !string.IsNullOrEmpty(displayType) && !string.IsNullOrEmpty(partName) && !string.IsNullOrEmpty(fieldName) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "_" + displayType + "__" + partName + "__" + fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]_[DisplayType]__[ContentType]__[PartName]__[FieldName] e.g. Fields/Common.Text-Blog-TeaserPart-Teaser.Summary
|
||||||
|
if ( !string.IsNullOrEmpty(displayType) && !string.IsNullOrEmpty(contentType) && !string.IsNullOrEmpty(partName) && !dynamicType && !string.IsNullOrEmpty(fieldName) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "_" + displayType + "__" + contentType + "__" + partName + "__" + fieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
private object CreateShape(BuildShapeContext context, string shapeType) {
|
private static object CreateShape(BuildShapeContext context, string shapeType) {
|
||||||
IShapeFactory shapeFactory = context.New;
|
IShapeFactory shapeFactory = context.New;
|
||||||
return shapeFactory.Create(shapeType);
|
return shapeFactory.Create(shapeType);
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using Orchard.ContentManagement.Handlers;
|
using Orchard.ContentManagement.Handlers;
|
||||||
using Orchard.ContentManagement.MetaData;
|
using Orchard.ContentManagement.MetaData;
|
||||||
using Orchard.DisplayManagement;
|
using Orchard.DisplayManagement;
|
||||||
|
using Orchard.DisplayManagement.Shapes;
|
||||||
|
|
||||||
namespace Orchard.ContentManagement.Drivers {
|
namespace Orchard.ContentManagement.Drivers {
|
||||||
public abstract class ContentPartDriver<TContent> : IContentPartDriver where TContent : ContentPart, new() {
|
public abstract class ContentPartDriver<TContent> : IContentPartDriver where TContent : ContentPart, new() {
|
||||||
@@ -47,10 +48,46 @@ namespace Orchard.ContentManagement.Drivers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ContentShapeResult ContentShapeImplementation(string shapeType, Func<BuildShapeContext, object> shapeBuilder) {
|
private ContentShapeResult ContentShapeImplementation(string shapeType, Func<BuildShapeContext, object> shapeBuilder) {
|
||||||
return new ContentShapeResult(shapeType, Prefix, shapeBuilder);
|
return new ContentShapeResult(shapeType, Prefix, ctx => AddAlternates(shapeBuilder(ctx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private object CreateShape(BuildShapeContext context, string shapeType) {
|
private static object AddAlternates(dynamic shape) {
|
||||||
|
ShapeMetadata metadata = shape.Metadata;
|
||||||
|
ContentPart part = shape.ContentPart;
|
||||||
|
var id = part != null ? part.ContentItem.Id.ToString() : String.Empty;
|
||||||
|
var shapeType = metadata.Type;
|
||||||
|
var contentType = part != null ? part.ContentItem.ContentType : String.Empty;
|
||||||
|
var displayType = metadata.DisplayType ?? String.Empty;
|
||||||
|
|
||||||
|
// [ShapeType]__[Id] e.g. Parts/Common.Metadata-42
|
||||||
|
if ( !string.IsNullOrEmpty(id) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "__" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]__[ContentType] e.g. Parts/Common.Metadata-BlogPost
|
||||||
|
if ( !string.IsNullOrEmpty(contentType) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "__" + contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]_[DisplayType] e.g. Parts/Common.Metadata.Summary
|
||||||
|
if ( !string.IsNullOrEmpty(displayType) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "_" + displayType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]_[DisplayType]__[ContentType] e.g. Parts/Common.Metadata-BlogPost.Summary
|
||||||
|
if ( !string.IsNullOrEmpty(displayType) && !string.IsNullOrEmpty(contentType) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "_" + displayType + "__" + contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ShapeType]_[DisplayType]__[Id] e.g. Parts/Common.Metadata-42.Summary
|
||||||
|
if ( !string.IsNullOrEmpty(displayType) && !string.IsNullOrEmpty(id) ) {
|
||||||
|
metadata.Alternates.Add(shapeType + "_" + displayType + "__" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object CreateShape(BuildShapeContext context, string shapeType) {
|
||||||
IShapeFactory shapeFactory = context.New;
|
IShapeFactory shapeFactory = context.New;
|
||||||
return shapeFactory.Create(shapeType);
|
return shapeFactory.Create(shapeType);
|
||||||
}
|
}
|
||||||
|
@@ -68,13 +68,22 @@ namespace Orchard.DisplayManagement.Implementation {
|
|||||||
shapeBinding.ShapeDescriptor.Displaying.Invoke(action => action(displayingContext), Logger);
|
shapeBinding.ShapeDescriptor.Displaying.Invoke(action => action(displayingContext), Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now find the actual binding to render, taking alternates into account
|
// invoking ShapeMetadata displaying events
|
||||||
ShapeBinding actualBinding;
|
shapeMetadata.Displaying.Invoke(action => action(displayingContext), Logger);
|
||||||
if (TryGetDescriptorBinding(shapeMetadata.Type, shapeMetadata.Alternates, shapeTable, out actualBinding)) {
|
|
||||||
shape.Metadata.ChildContent = Process(actualBinding, shape, context);
|
// use pre-fectched content if available (e.g. coming from specific cache implmentation)
|
||||||
|
if ( displayingContext.ChildContent != null ) {
|
||||||
|
shape.Metadata.ChildContent = displayingContext.ChildContent;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new OrchardException(T("Shape type {0} not found", shapeMetadata.Type));
|
// now find the actual binding to render, taking alternates into account
|
||||||
|
ShapeBinding actualBinding;
|
||||||
|
if ( TryGetDescriptorBinding(shapeMetadata.Type, shapeMetadata.Alternates, shapeTable, out actualBinding) ) {
|
||||||
|
shape.Metadata.ChildContent = Process(actualBinding, shape, context);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new OrchardException(T("Shape type {0} not found", shapeMetadata.Type));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var frameType in shape.Metadata.Wrappers) {
|
foreach (var frameType in shape.Metadata.Wrappers) {
|
||||||
@@ -108,6 +117,9 @@ namespace Orchard.DisplayManagement.Implementation {
|
|||||||
}, Logger);
|
}, Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// invoking ShapeMetadata displayed events
|
||||||
|
shapeMetadata.Displayed.Invoke(action => action(displayedContext), Logger);
|
||||||
|
|
||||||
return shape.Metadata.ChildContent;
|
return shape.Metadata.ChildContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@ namespace Orchard.DisplayManagement.Implementation {
|
|||||||
public class ShapeDisplayingContext {
|
public class ShapeDisplayingContext {
|
||||||
public dynamic Shape { get; set; }
|
public dynamic Shape { get; set; }
|
||||||
public ShapeMetadata ShapeMetadata { get; set; }
|
public ShapeMetadata ShapeMetadata { get; set; }
|
||||||
|
public IHtmlString ChildContent { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ShapeDisplayedContext {
|
public class ShapeDisplayedContext {
|
||||||
|
@@ -1,11 +1,16 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
|
using Orchard.DisplayManagement.Implementation;
|
||||||
|
|
||||||
namespace Orchard.DisplayManagement.Shapes {
|
namespace Orchard.DisplayManagement.Shapes {
|
||||||
public class ShapeMetadata {
|
public class ShapeMetadata {
|
||||||
public ShapeMetadata() {
|
public ShapeMetadata() {
|
||||||
Wrappers = new List<string>();
|
Wrappers = new List<string>();
|
||||||
Alternates = new List<string>();
|
Alternates = new List<string>();
|
||||||
|
Displaying = Enumerable.Empty<Action<ShapeDisplayingContext>>();
|
||||||
|
Displayed = Enumerable.Empty<Action<ShapeDisplayedContext>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Type { get; set; }
|
public string Type { get; set; }
|
||||||
@@ -17,5 +22,18 @@ namespace Orchard.DisplayManagement.Shapes {
|
|||||||
|
|
||||||
public bool WasExecuted { get; set; }
|
public bool WasExecuted { get; set; }
|
||||||
public IHtmlString ChildContent { get; set; }
|
public IHtmlString ChildContent { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<Action<ShapeDisplayingContext>> Displaying { get; private set; }
|
||||||
|
public IEnumerable<Action<ShapeDisplayedContext>> Displayed { get; private set; }
|
||||||
|
|
||||||
|
public void OnDisplaying(Action<ShapeDisplayingContext> action) {
|
||||||
|
var existing = Displaying ?? Enumerable.Empty<Action<ShapeDisplayingContext>>();
|
||||||
|
Displaying = existing.Concat(new[] { action });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDisplayed(Action<ShapeDisplayedContext> action) {
|
||||||
|
var existing = Displayed ?? Enumerable.Empty<Action<ShapeDisplayedContext>>();
|
||||||
|
Displayed = existing.Concat(new[] { action });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,5 +1,13 @@
|
|||||||
using System.Web;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Web;
|
||||||
using Autofac;
|
using Autofac;
|
||||||
|
using Autofac.Builder;
|
||||||
|
using Autofac.Core;
|
||||||
|
using Autofac.Features.Metadata;
|
||||||
|
using Module = Autofac.Module;
|
||||||
|
|
||||||
namespace Orchard.Environment {
|
namespace Orchard.Environment {
|
||||||
public class WorkContextModule : Module {
|
public class WorkContextModule : Module {
|
||||||
@@ -19,6 +27,96 @@ namespace Orchard.Environment {
|
|||||||
builder.Register(ctx => ctx.Resolve<WorkContextProperty<HttpContextBase>>().Value)
|
builder.Register(ctx => ctx.Resolve<WorkContextProperty<HttpContextBase>>().Value)
|
||||||
.As<HttpContextBase>()
|
.As<HttpContextBase>()
|
||||||
.InstancePerDependency();
|
.InstancePerDependency();
|
||||||
|
|
||||||
|
builder.RegisterGeneric(typeof(WorkValues<>))
|
||||||
|
.InstancePerMatchingLifetimeScope("work");
|
||||||
|
|
||||||
|
builder.RegisterSource(new WorkRegistrationSource());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Work<T> where T : class {
|
||||||
|
private readonly Func<Work<T>, T> _resolve;
|
||||||
|
|
||||||
|
public Work(Func<Work<T>, T> resolve) {
|
||||||
|
_resolve = resolve;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Value {
|
||||||
|
get { return _resolve(this); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class WorkValues<T> where T : class {
|
||||||
|
public WorkValues(IComponentContext componentContext) {
|
||||||
|
ComponentContext = componentContext;
|
||||||
|
Values = new Dictionary<Work<T>, T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IComponentContext ComponentContext { get; private set; }
|
||||||
|
public IDictionary<Work<T>, T> Values { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Support the <see cref="Meta{T}"/>
|
||||||
|
/// types automatically whenever type T is registered with the container.
|
||||||
|
/// Metadata values come from the component registration's metadata.
|
||||||
|
/// </summary>
|
||||||
|
class WorkRegistrationSource : IRegistrationSource {
|
||||||
|
static readonly MethodInfo CreateMetaRegistrationMethod = typeof(WorkRegistrationSource).GetMethod(
|
||||||
|
"CreateMetaRegistration", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
private static bool IsClosingTypeOf(Type type, Type openGenericType) {
|
||||||
|
return type.IsGenericType && type.GetGenericTypeDefinition() == openGenericType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor) {
|
||||||
|
var swt = service as IServiceWithType;
|
||||||
|
if (swt == null || !IsClosingTypeOf(swt.ServiceType, typeof(Work<>)))
|
||||||
|
return Enumerable.Empty<IComponentRegistration>();
|
||||||
|
|
||||||
|
var valueType = swt.ServiceType.GetGenericArguments()[0];
|
||||||
|
|
||||||
|
var valueService = swt.ChangeType(valueType);
|
||||||
|
|
||||||
|
var registrationCreator = CreateMetaRegistrationMethod.MakeGenericMethod(valueType);
|
||||||
|
|
||||||
|
return registrationAccessor(valueService)
|
||||||
|
.Select(v => registrationCreator.Invoke(null, new object[] { service, v }))
|
||||||
|
.Cast<IComponentRegistration>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAdapterForIndividualComponents {
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
static IComponentRegistration CreateMetaRegistration<T>(Service providedService, IComponentRegistration valueRegistration) where T : class {
|
||||||
|
var rb = RegistrationBuilder.ForDelegate(
|
||||||
|
(c, p) => {
|
||||||
|
var workContextAccessor = c.Resolve<IWorkContextAccessor>();
|
||||||
|
return new Work<T>(w => {
|
||||||
|
var workContext = workContextAccessor.GetContext();
|
||||||
|
if (workContext == null)
|
||||||
|
return default(T);
|
||||||
|
|
||||||
|
var workValues = workContext.Resolve<WorkValues<T>>();
|
||||||
|
|
||||||
|
T value;
|
||||||
|
if (!workValues.Values.TryGetValue(w, out value)) {
|
||||||
|
value = (T)workValues.ComponentContext.Resolve(valueRegistration, p);
|
||||||
|
workValues.Values[w] = value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int x = 5;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.As(providedService)
|
||||||
|
.Targeting(valueRegistration);
|
||||||
|
|
||||||
|
return rb.CreateRegistration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user