Updating for part placement

Correcting several issues
Providing default placement info for body and tags
Fixing predicate logic

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-10-12 21:08:27 -07:00
parent f7748c3590
commit 945e41de1e
19 changed files with 155 additions and 97 deletions

View File

@@ -54,7 +54,6 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
VerifyShapeType("Views/Items", "Content.Edit", "Items_Content_Edit"); VerifyShapeType("Views/Items", "Content.Edit", "Items_Content_Edit");
} }
[Test] [Test]
public void ExplicitSpecializationMixedWithDisplayTypes() { public void ExplicitSpecializationMixedWithDisplayTypes() {
VerifyShapeType("Views/Items", "Content-MyType", "Items_Content__MyType"); VerifyShapeType("Views/Items", "Content-MyType", "Items_Content__MyType");
@@ -62,12 +61,18 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
VerifyShapeType("Views/Items", "Content-MyType.Edit", "Items_Content_Edit__MyType"); VerifyShapeType("Views/Items", "Content-MyType.Edit", "Items_Content_Edit__MyType");
} }
[Test] [Test]
public void ImplicitSpecializationMixedWithDisplayTypes() { public void ImplicitSpecializationMixedWithDisplayTypes() {
VerifyShapeType("Views/Items", "MyType", "Items_Content__MyType"); VerifyShapeType("Views/Items", "MyType", "Items_Content__MyType");
VerifyShapeType("Views/Items", "MyType.Summary", "Items_Content_Summary__MyType"); VerifyShapeType("Views/Items", "MyType.Summary", "Items_Content_Summary__MyType");
VerifyShapeType("Views/Items", "MyType.Edit", "Items_Content_Edit__MyType"); VerifyShapeType("Views/Items", "MyType.Edit", "Items_Content_Edit__MyType");
} }
[Test]
public void MultipleDotsAreNormalizedToUnderscore() {
VerifyShapeType("Views/Parts", "Common.Body", "Parts_Common_Body");
VerifyShapeType("Views/Parts", "Common.Body.Summary", "Parts_Common_Body_Summary");
VerifyShapeType("Views/Parts", "Localization.ContentTranslations.Summary", "Parts_Localization_ContentTranslations_Summary");
}
} }
} }

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web; using System.Web;
using JetBrains.Annotations; using JetBrains.Annotations;
@@ -36,33 +37,35 @@ namespace Orchard.Core.Common.Drivers {
protected override DriverResult Display(BodyPart part, string displayType, dynamic shapeHelper) { protected override DriverResult Display(BodyPart part, string displayType, dynamic shapeHelper) {
return Combined( return Combined(
ContentShape("Parts_Common_Body", displayType == "Detail" ? "Content" : null, () => { ContentShape("Parts_Common_Body",
var bodyText = _htmlFilters.Aggregate(part.Text, (text, filter) => filter.ProcessContent(text)); () => {
return shapeHelper.Parts_Common_Body(ContentPart: part, Html: new HtmlString(bodyText)); var bodyText = _htmlFilters.Aggregate(part.Text, (text, filter) => filter.ProcessContent(text));
}), return shapeHelper.Parts_Common_Body(ContentPart: part, Html: new HtmlString(bodyText));
ContentShape("Parts_Common_Body_Summary", displayType == "Summary" ? "Content" : null, () => { }),
var bodyText = _htmlFilters.Aggregate(part.Text, (text, filter) => filter.ProcessContent(text)); ContentShape("Parts_Common_Body_Summary",
return shapeHelper.Parts_Common_Body_Summary(ContentPart: part, Html: new HtmlString(bodyText)); () => {
}) var bodyText = _htmlFilters.Aggregate(part.Text, (text, filter) => filter.ProcessContent(text));
); return shapeHelper.Parts_Common_Body_Summary(ContentPart: part, Html: new HtmlString(bodyText));
})
);
}
private string IfThen(bool predicate, string value) {
return predicate ? value : null;
} }
protected override DriverResult Editor(BodyPart part, dynamic shapeHelper) { protected override DriverResult Editor(BodyPart part, dynamic shapeHelper) {
var model = BuildEditorViewModel(part); var model = BuildEditorViewModel(part);
var location = part.GetLocation("Editor"); return ContentShape("Parts_Common_Body_Editor",
return ContentPartTemplate(model, TemplateName, Prefix).Location(location); () => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix));
} }
protected override DriverResult Editor(BodyPart part, IUpdateModel updater, dynamic shapeHelper) { protected override DriverResult Editor(BodyPart part, IUpdateModel updater, dynamic shapeHelper) {
var model = BuildEditorViewModel(part); var model = BuildEditorViewModel(part);
updater.TryUpdateModel(model, Prefix, null, null); updater.TryUpdateModel(model, Prefix, null, null);
// only set the format if it has not yet been set to preserve the initial format type - might want to change this later to support changing body formats but...later return ContentShape("Parts_Common_Body_Editor",
if (string.IsNullOrWhiteSpace(model.Format)) () => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix));
model.Format = GetFlavor(part);
var location = part.GetLocation("Editor");
return ContentPartTemplate(model, TemplateName, Prefix).Location(location);
} }
private static BodyEditorViewModel BuildEditorViewModel(BodyPart part) { private static BodyEditorViewModel BuildEditorViewModel(BodyPart part) {

View File

@@ -0,0 +1,13 @@
<Placement>
<Place Parts_Common_Body_Editor="Primary:2"/>
<!-- show summary for all DisplayType by default -->
<Place Parts_Common_Body_Summary="Content:5"/>
<Match DisplayType="Detail">
<!-- hide summary, show full content, for Detail -->
<Place Parts_Common_Body_Summary="-"
Parts_Common_Body="Content:5" />
</Match>
</Placement>

View File

@@ -1,9 +1,9 @@
@model BodyDisplayViewModel @*doing excerpt generation on the way out for now so we don't stick ourselves with needing to regen excerpts for existing data
@using Orchard.Core.Common.ViewModels;
@*doing excerpt generation on the way out for now so we don't stick ourselves with needing to regen excerpts for existing data
also, doing this here, inline, until we have a pluggable processing model (both in and out) also, doing this here, inline, until we have a pluggable processing model (both in and out)
also, ...this is ugly *@ also, ...this is ugly *@
@{ @{
var body = new HtmlString(Html.Excerpt(Model.Html.ToString(), 200).ToString().Replace(Environment.NewLine, "</p>" + Environment.NewLine + "<p>")); Orchard.ContentManagement.ContentItem contentItem = Model.ContentPart.ContentItem;
string bodyHtml = Model.Html.ToString();
var body = new HtmlString(Html.Excerpt(bodyHtml, 200).ToString().Replace(Environment.NewLine, "</p>" + Environment.NewLine + "<p>"));
} }
<p>@body @Html.ItemDisplayLink(T("[more]").ToString(), Model.BodyPart.ContentItem)</p> <p>@body @Html.ItemDisplayLink(T("[more]").ToString(), contentItem)</p>

View File

@@ -8,7 +8,6 @@ namespace Orchard.Core.Contents {
public class Shapes : IShapeTableProvider { public class Shapes : IShapeTableProvider {
public void Discover(ShapeTableBuilder builder) { public void Discover(ShapeTableBuilder builder) {
builder.Describe("Items_Content") builder.Describe("Items_Content")
.OnCreating(creating => creating.Behaviors.Add(new ZoneHoldingBehavior(name => ContentZone(creating, name))))
.OnDisplaying(displaying => { .OnDisplaying(displaying => {
ContentItem contentItem = displaying.Shape.ContentItem; ContentItem contentItem = displaying.Shape.ContentItem;
if (contentItem != null) { if (contentItem != null) {
@@ -16,12 +15,14 @@ namespace Orchard.Core.Contents {
displaying.ShapeMetadata.Alternates.Add("Items_Content__" + contentItem.Id); displaying.ShapeMetadata.Alternates.Add("Items_Content__" + contentItem.Id);
} }
}); });
}
private static object ContentZone(ShapeCreatingContext creating, string name) { builder.Describe("Items_Content_Editor")
var zone = creating.New.ContentZone(); .OnDisplaying(displaying => {
zone.ZoneName = name; ContentItem contentItem = displaying.Shape.ContentItem;
return zone; if (contentItem != null) {
displaying.ShapeMetadata.Alternates.Add("Items_Content_Editor__" + contentItem.ContentType);
}
});
} }
} }
} }

View File

@@ -381,7 +381,7 @@
<Content Include="ContentsLocation\Views\Web.config" /> <Content Include="ContentsLocation\Views\Web.config" />
<Content Include="Messaging\Views\Web.config" /> <Content Include="Messaging\Views\Web.config" />
<Content Include="Contents\Views\Items\Content.cshtml" /> <Content Include="Contents\Views\Items\Content.cshtml" />
<Content Include="Contents\Views\Items\Content.Edit.cshtml" /> <Content Include="Contents\Views\Items\Content.Editor.cshtml" />
<Content Include="Contents\Views\Items\Content.Summary.cshtml" /> <Content Include="Contents\Views\Items\Content.Summary.cshtml" />
<Content Include="Contents\Views\Items\Content.SummaryAdmin.cshtml" /> <Content Include="Contents\Views\Items\Content.SummaryAdmin.cshtml" />
<Content Include="Shapes\Views\Document.cshtml" /> <Content Include="Shapes\Views\Document.cshtml" />
@@ -392,6 +392,7 @@
<Content Include="Shapes\Views\MenuItem.cshtml" /> <Content Include="Shapes\Views\MenuItem.cshtml" />
<Content Include="Shapes\Views\Web.config" /> <Content Include="Shapes\Views\Web.config" />
<Content Include="Dashboard\Views\Helper\Index.cshtml" /> <Content Include="Dashboard\Views\Helper\Index.cshtml" />
<None Include="Common\Placement.info" />
<None Include="Routable\Views\Parts\RoutableTitle.cshtml" /> <None Include="Routable\Views\Parts\RoutableTitle.cshtml" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

View File

@@ -31,7 +31,7 @@ namespace Orchard.Core.Shapes {
// and has an automatic zone creating behavior // and has an automatic zone creating behavior
builder.Describe("Layout") builder.Describe("Layout")
.Configure(descriptor => descriptor.Wrappers.Add("Document")) .Configure(descriptor => descriptor.Wrappers.Add("Document"))
.OnCreating(creating => creating.Behaviors.Add(new ZoneHoldingBehavior(name => CreateZone(creating)))) .OnCreating(creating => creating.Behaviors.Add(new ZoneHoldingBehavior(() => creating.New.Zone())))
.OnCreated(created => { .OnCreated(created => {
var layout = created.Shape; var layout = created.Shape;
layout.Head = created.New.DocumentZone(ZoneName: "Head"); layout.Head = created.New.DocumentZone(ZoneName: "Head");
@@ -81,9 +81,6 @@ namespace Orchard.Core.Shapes {
}); });
} }
static object CreateZone(ShapeCreatingContext context) {
return context.New.Zone();
}
static TagBuilder GetTagBuilder(string tagName, string id, IEnumerable<string> classes, IDictionary<string, string> attributes) { static TagBuilder GetTagBuilder(string tagName, string id, IEnumerable<string> classes, IDictionary<string, string> attributes) {
var tagBuilder = new TagBuilder(tagName); var tagBuilder = new TagBuilder(tagName);
@@ -271,8 +268,8 @@ namespace Orchard.Core.Shapes {
} }
[Shape] [Shape]
public void Partial(HtmlHelper Html, TextWriter Output, string TemplateName, object Model) { public void Partial(HtmlHelper Html, TextWriter Output, string TemplateName, object Model, string Prefix) {
RenderInternal(Html, Output, TemplateName, Model, null); RenderInternal(Html, Output, TemplateName, Model, Prefix);
} }
[Shape] [Shape]

View File

@@ -24,11 +24,8 @@ namespace Orchard.Tags.Drivers {
public virtual IUser CurrentUser { get; set; } public virtual IUser CurrentUser { get; set; }
protected override DriverResult Display(TagsPart part, string displayType, dynamic shapeHelper) { protected override DriverResult Display(TagsPart part, string displayType, dynamic shapeHelper) {
var showTags = shapeHelper.Parts_Tags_ShowTags(ContentPart: part, Tags: part.CurrentTags); return ContentShape("Parts_Tags_ShowTags",
if (!string.IsNullOrWhiteSpace(displayType)) () => shapeHelper.Parts_Tags_ShowTags(ContentPart: part, Tags: part.CurrentTags));
showTags.Metadata.Type = string.Format("{0}.{1}", showTags.Metadata.Type, displayType);
var location = part.GetLocation(displayType);
return ContentShape(showTags).Location(location);
} }
protected override DriverResult Editor(TagsPart part, dynamic shapeHelper) { protected override DriverResult Editor(TagsPart part, dynamic shapeHelper) {

View File

@@ -112,6 +112,9 @@
<Name>Orchard.Core</Name> <Name>Orchard.Core</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Include="Placement.info" />
</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" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -0,0 +1,3 @@
<Placement>
<Place Parts_Tags_ShowTags="Header:after.7"/>
</Placement>

View File

@@ -12,10 +12,5 @@
</Match> </Match>
--> -->
<Match ContentType="Page" DisplayType="Detail">
<Place
Parts_RoutableTitle="Content:5.b"
Parts_Common_Body="Header:after" />
</Match>
</Placement> </Placement>

View File

@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Web.Routing; using System.Web.Routing;
using ClaySharp;
using ClaySharp.Implementation;
using Microsoft.CSharp.RuntimeBinder; using Microsoft.CSharp.RuntimeBinder;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
using Orchard.DisplayManagement; using Orchard.DisplayManagement;
@@ -10,11 +12,13 @@ using Orchard.DisplayManagement.Descriptors;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Mvc; using Orchard.Mvc;
using Orchard.Themes; using Orchard.Themes;
using Orchard.UI.Zones;
namespace Orchard.ContentManagement { namespace Orchard.ContentManagement {
public class DefaultContentDisplay : IContentDisplay { public class DefaultContentDisplay : IContentDisplay {
private readonly Lazy<IEnumerable<IContentHandler>> _handlers; private readonly Lazy<IEnumerable<IContentHandler>> _handlers;
private readonly IShapeHelperFactory _shapeHelperFactory; private readonly IShapeHelperFactory _shapeHelperFactory;
private readonly IShapeFactory _shapeFactory;
private readonly IShapeTableManager _shapeTableManager; private readonly IShapeTableManager _shapeTableManager;
private readonly IWorkContextAccessor _workContextAccessor; private readonly IWorkContextAccessor _workContextAccessor;
private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHttpContextAccessor _httpContextAccessor;
@@ -24,6 +28,7 @@ namespace Orchard.ContentManagement {
public DefaultContentDisplay( public DefaultContentDisplay(
Lazy<IEnumerable<IContentHandler>> handlers, Lazy<IEnumerable<IContentHandler>> handlers,
IShapeHelperFactory shapeHelperFactory, IShapeHelperFactory shapeHelperFactory,
IShapeFactory shapeFactory,
IShapeTableManager shapeTableManager, IShapeTableManager shapeTableManager,
IWorkContextAccessor workContextAccessor, IWorkContextAccessor workContextAccessor,
IHttpContextAccessor httpContextAccessor, IHttpContextAccessor httpContextAccessor,
@@ -31,6 +36,7 @@ namespace Orchard.ContentManagement {
RequestContext requestContext) { RequestContext requestContext) {
_handlers = handlers; _handlers = handlers;
_shapeHelperFactory = shapeHelperFactory; _shapeHelperFactory = shapeHelperFactory;
_shapeFactory = shapeFactory;
_shapeTableManager = shapeTableManager; _shapeTableManager = shapeTableManager;
_workContextAccessor = workContextAccessor; _workContextAccessor = workContextAccessor;
_httpContextAccessor = httpContextAccessor; _httpContextAccessor = httpContextAccessor;
@@ -55,29 +61,30 @@ namespace Orchard.ContentManagement {
if (!contentTypeDefinition.Settings.TryGetValue("Stereotype", out stereotype)) if (!contentTypeDefinition.Settings.TryGetValue("Stereotype", out stereotype))
stereotype = "Content"; stereotype = "Content";
var shapeTypeName = "Items_" + stereotype; var actualShapeType = "Items_" + stereotype;
var shapeDisplayType = string.IsNullOrWhiteSpace(displayType) ? "Detail" : displayType; var actualDisplayType = string.IsNullOrWhiteSpace(displayType) ? "Detail" : displayType;
var shapeHelper = _shapeHelperFactory.CreateHelper();
var itemShape = _shapeHelperCalls.Invoke(shapeHelper, shapeTypeName);
dynamic itemShape = CreateItemShape(actualShapeType);
itemShape.ContentItem = content.ContentItem; itemShape.ContentItem = content.ContentItem;
itemShape.Metadata.DisplayType = shapeDisplayType; itemShape.Metadata.DisplayType = actualDisplayType;
var context = new BuildDisplayContext(itemShape, content, shapeDisplayType, _shapeHelperFactory); var context = new BuildDisplayContext(itemShape, content, actualDisplayType, _shapeHelperFactory);
BindPlacement(context, displayType); BindPlacement(context, actualDisplayType);
_handlers.Value.Invoke(handler => handler.BuildDisplay(context), Logger); _handlers.Value.Invoke(handler => handler.BuildDisplay(context), Logger);
return context.Shape; return context.Shape;
} }
public dynamic BuildEditor(IContent content) { public dynamic BuildEditor(IContent content) {
var shapeHelper = _shapeHelperFactory.CreateHelper(); var contentTypeDefinition = content.ContentItem.TypeDefinition;
var itemShape = shapeHelper.Items_Content_Edit(); string stereotype;
if (!contentTypeDefinition.Settings.TryGetValue("Stereotype", out stereotype))
stereotype = "Content";
IContent iContent = content; var actualShapeType = "Items_" + stereotype + "_Editor";
if (iContent != null)
itemShape.ContentItem = iContent.ContentItem; dynamic itemShape = CreateItemShape(actualShapeType);
itemShape.ContentItem = content.ContentItem;
var context = new BuildEditorContext(itemShape, content, _shapeHelperFactory); var context = new BuildEditorContext(itemShape, content, _shapeHelperFactory);
BindPlacement(context, null); BindPlacement(context, null);
@@ -87,12 +94,15 @@ namespace Orchard.ContentManagement {
} }
public dynamic UpdateEditor(IContent content, IUpdateModel updater) { public dynamic UpdateEditor(IContent content, IUpdateModel updater) {
var shapeHelper = _shapeHelperFactory.CreateHelper(); var contentTypeDefinition = content.ContentItem.TypeDefinition;
var itemShape = shapeHelper.Items_Content_Edit(); string stereotype;
if (!contentTypeDefinition.Settings.TryGetValue("Stereotype", out stereotype))
stereotype = "Content";
IContent iContent = content; var actualShapeType = "Items_" + stereotype + "_Editor";
if (iContent != null)
itemShape.ContentItem = iContent.ContentItem; dynamic itemShape = CreateItemShape(actualShapeType);
itemShape.ContentItem = content.ContentItem;
var context = new UpdateEditorContext(itemShape, content, updater, _shapeHelperFactory); var context = new UpdateEditorContext(itemShape, content, updater, _shapeHelperFactory);
BindPlacement(context, null); BindPlacement(context, null);
@@ -101,6 +111,11 @@ namespace Orchard.ContentManagement {
return context.Shape; return context.Shape;
} }
private dynamic CreateItemShape(string actualShapeType) {
var zoneHoldingBehavior = new ZoneHoldingBehavior(() => _shapeFactory.Create("ContentZone", Arguments.Empty()));
return _shapeFactory.Create(actualShapeType, Arguments.Empty(), new[] { zoneHoldingBehavior });
}
private void BindPlacement(BuildShapeContext context, string displayType) { private void BindPlacement(BuildShapeContext context, string displayType) {
context.FindPlacement = (partShapeType, defaultLocation) => { context.FindPlacement = (partShapeType, defaultLocation) => {
//var workContext = _workContextAccessor.GetContext(); //var workContext = _workContextAccessor.GetContext();
@@ -109,9 +124,9 @@ namespace Orchard.ContentManagement {
var shapeTable = _shapeTableManager.GetShapeTable(theme.ThemeName); var shapeTable = _shapeTableManager.GetShapeTable(theme.ThemeName);
ShapeDescriptor descriptor; ShapeDescriptor descriptor;
if (shapeTable.Descriptors.TryGetValue(partShapeType, out descriptor)) { if (shapeTable.Descriptors.TryGetValue(partShapeType, out descriptor)) {
var placementContext = new ShapePlacementContext { var placementContext = new ShapePlacementContext {
ContentType = context.ContentItem.ContentType, ContentType = context.ContentItem.ContentType,
DisplayType = displayType DisplayType = displayType
}; };
var location = descriptor.Placement(placementContext); var location = descriptor.Placement(placementContext);
return location ?? defaultLocation; return location ?? defaultLocation;

View File

@@ -24,7 +24,8 @@ namespace Orchard.DisplayManagement.Descriptors {
/// </summary> /// </summary>
public string BindingSource { public string BindingSource {
get { get {
return Bindings[ShapeType].BindingSource; ShapeBinding binding;
return Bindings.TryGetValue(ShapeType, out binding) ? binding.BindingSource : null;
} }
} }

View File

@@ -27,11 +27,11 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy {
public void Discover(ShapeTableBuilder builder) { public void Discover(ShapeTableBuilder builder) {
var availableFeatures = _extensionManager.AvailableFeatures(); var availableFeatures = _extensionManager.AvailableFeatures();
var activeFeatures = availableFeatures.Where(fd => FeatureIsTheme(fd) || FeatureIsEnabled(fd)); var activeFeatures = availableFeatures.Where(fd => FeatureIsTheme(fd) || FeatureIsEnabled(fd));
var activeExtensions = Once(activeFeatures); var activeExtensions = Once(activeFeatures);
foreach (var extensionDescriptor in activeExtensions) { foreach (var extensionDescriptor in activeExtensions) {
foreach (var featureDescriptor in extensionDescriptor.Features.Where(fd=>fd.Name == fd.Extension.Name)) { foreach (var featureDescriptor in extensionDescriptor.Features.Where(fd => fd.Name == fd.Extension.Name)) {
ProcessFeatureDescriptor(builder, featureDescriptor); ProcessFeatureDescriptor(builder, featureDescriptor);
} }
} }
@@ -46,7 +46,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy {
} }
private void ProcessPlacementFile(ShapeTableBuilder builder, FeatureDescriptor featureDescriptor, PlacementFile placementFile) { private void ProcessPlacementFile(ShapeTableBuilder builder, FeatureDescriptor featureDescriptor, PlacementFile placementFile) {
var feature = new Feature {Descriptor = featureDescriptor}; var feature = new Feature { Descriptor = featureDescriptor };
// invert the tree into a list of leaves and the stack // invert the tree into a list of leaves and the stack
var entries = DrillDownShapeLocations(placementFile.Nodes, Enumerable.Empty<PlacementMatch>()); var entries = DrillDownShapeLocations(placementFile.Nodes, Enumerable.Empty<PlacementMatch>());
@@ -55,7 +55,9 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy {
var matches = entry.Item2; var matches = entry.Item2;
Func<ShapePlacementContext, bool> predicate = ctx => true; Func<ShapePlacementContext, bool> predicate = ctx => true;
predicate = matches.SelectMany(match=>match.Terms).Aggregate(predicate, BuildPredicate); if (matches.Any()) {
predicate = matches.SelectMany(match => match.Terms).Aggregate(predicate, BuildPredicate);
}
builder.Describe(shapeLocation.ShapeType) builder.Describe(shapeLocation.ShapeType)
.From(feature) .From(feature)
@@ -65,31 +67,39 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy {
private Func<ShapePlacementContext, bool> BuildPredicate(Func<ShapePlacementContext, bool> predicate, KeyValuePair<string, string> term) { private Func<ShapePlacementContext, bool> BuildPredicate(Func<ShapePlacementContext, bool> predicate, KeyValuePair<string, string> term) {
var expression = term.Value; var expression = term.Value;
switch(term.Key) { switch (term.Key) {
case "ContentType": case "ContentType":
return ctx=>ctx.ContentType == expression ? true : predicate(ctx); if (expression.EndsWith("*")) {
var prefix = expression.Substring(0, expression.Length - 1);
return ctx => (ctx.ContentType ?? "").StartsWith(prefix) && predicate(ctx);
}
return ctx => (ctx.ContentType == expression) && predicate(ctx);
case "DisplayType": case "DisplayType":
return ctx=>ctx.DisplayType == expression ? true : predicate(ctx); if (expression.EndsWith("*")) {
var prefix = expression.Substring(0, expression.Length - 1);
return ctx => (ctx.DisplayType ?? "").StartsWith(prefix) && predicate(ctx);
}
return ctx => (ctx.DisplayType == expression) && predicate(ctx);
} }
return predicate; return predicate;
} }
private static IEnumerable<Tuple<PlacementShapeLocation, IEnumerable<PlacementMatch>>> DrillDownShapeLocations( private static IEnumerable<Tuple<PlacementShapeLocation, IEnumerable<PlacementMatch>>> DrillDownShapeLocations(
IEnumerable<PlacementNode> nodes, IEnumerable<PlacementNode> nodes,
IEnumerable<PlacementMatch> path) { IEnumerable<PlacementMatch> path) {
// return shape locations nodes in this place // return shape locations nodes in this place
foreach (var placementShapeLocation in nodes.OfType<PlacementShapeLocation>()) { foreach (var placementShapeLocation in nodes.OfType<PlacementShapeLocation>()) {
yield return new Tuple<PlacementShapeLocation, IEnumerable<PlacementMatch>>(placementShapeLocation, path); yield return new Tuple<PlacementShapeLocation, IEnumerable<PlacementMatch>>(placementShapeLocation, path);
} }
// recurse down into match nodes // recurse down into match nodes
foreach (var placementMatch in nodes.OfType<PlacementMatch>()) { foreach (var placementMatch in nodes.OfType<PlacementMatch>()) {
foreach (var findShapeLocation in DrillDownShapeLocations(placementMatch.Nodes, path.Concat(new[] {placementMatch}))) { foreach (var findShapeLocation in DrillDownShapeLocations(placementMatch.Nodes, path.Concat(new[] { placementMatch }))) {
yield return findShapeLocation; yield return findShapeLocation;
} }
} }
} }
private bool FeatureIsTheme(FeatureDescriptor fd) { private bool FeatureIsTheme(FeatureDescriptor fd) {
return fd.Extension.ExtensionType == "Theme"; return fd.Extension.ExtensionType == "Theme";
@@ -98,7 +108,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy {
private bool FeatureIsEnabled(FeatureDescriptor fd) { private bool FeatureIsEnabled(FeatureDescriptor fd) {
return _shellDescriptor.Features.Any(sf => sf.Name == fd.Name); return _shellDescriptor.Features.Any(sf => sf.Name == fd.Name);
} }
private static IEnumerable<ExtensionDescriptor> Once(IEnumerable<FeatureDescriptor> featureDescriptors) { private static IEnumerable<ExtensionDescriptor> Once(IEnumerable<FeatureDescriptor> featureDescriptors) {
var once = new ConcurrentDictionary<string, object>(); var once = new ConcurrentDictionary<string, object>();
return featureDescriptors.Select(fd => fd.Extension).Where(ed => once.TryAdd(ed.Name, null)).ToList(); return featureDescriptors.Select(fd => fd.Extension).Where(ed => once.TryAdd(ed.Name, null)).ToList();

View File

@@ -26,7 +26,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
} }
public IEnumerable<HarvestShapeHit> HarvestShape(HarvestShapeInfo info) { public IEnumerable<HarvestShapeHit> HarvestShape(HarvestShapeInfo info) {
var lastDot = info.FileName.IndexOf('.'); var lastDot = info.FileName.LastIndexOf('.');
if (lastDot <= 0) { if (lastDot <= 0) {
yield return new HarvestShapeHit { yield return new HarvestShapeHit {
ShapeType = Adjust(info.SubPath, info.FileName, null) ShapeType = Adjust(info.SubPath, info.FileName, null)

View File

@@ -1,4 +1,5 @@
using ClaySharp; using System.Collections.Generic;
using ClaySharp;
using ClaySharp.Implementation; using ClaySharp.Implementation;
namespace Orchard.DisplayManagement { namespace Orchard.DisplayManagement {
@@ -8,6 +9,7 @@ namespace Orchard.DisplayManagement {
/// </summary> /// </summary>
public interface IShapeFactory : IDependency { public interface IShapeFactory : IDependency {
IShape Create(string shapeType, INamedEnumerable<object> parameters); IShape Create(string shapeType, INamedEnumerable<object> parameters);
IShape Create(string shapeType, INamedEnumerable<object> parameters, IEnumerable<IClayBehavior> behaviors);
} }
public static class ShapeFactoryExtensions { public static class ShapeFactoryExtensions {
@@ -16,3 +18,4 @@ namespace Orchard.DisplayManagement {
} }
} }
} }

View File

@@ -16,8 +16,8 @@ namespace Orchard.DisplayManagement.Implementation {
private readonly Lazy<IShapeHelperFactory> _shapeHelperFactory; private readonly Lazy<IShapeHelperFactory> _shapeHelperFactory;
public DefaultShapeFactory( public DefaultShapeFactory(
IEnumerable<Lazy<IShapeFactoryEvents>> events, IEnumerable<Lazy<IShapeFactoryEvents>> events,
IShapeTableManager shapeTableManager, IShapeTableManager shapeTableManager,
Lazy<IShapeHelperFactory> shapeHelperFactory) { Lazy<IShapeHelperFactory> shapeHelperFactory) {
_events = events; _events = events;
_shapeTableManager = shapeTableManager; _shapeTableManager = shapeTableManager;
@@ -25,13 +25,17 @@ namespace Orchard.DisplayManagement.Implementation {
} }
public IShape Create(string shapeType, INamedEnumerable<object> parameters) { public IShape Create(string shapeType, INamedEnumerable<object> parameters) {
return Create(shapeType, parameters, Enumerable.Empty<IClayBehavior>());
}
public IShape Create(string shapeType, INamedEnumerable<object> parameters, IEnumerable<IClayBehavior> behaviors) {
var defaultShapeTable = _shapeTableManager.GetShapeTable(null); var defaultShapeTable = _shapeTableManager.GetShapeTable(null);
ShapeDescriptor shapeDescriptor; ShapeDescriptor shapeDescriptor;
defaultShapeTable.Descriptors.TryGetValue(shapeType, out shapeDescriptor); defaultShapeTable.Descriptors.TryGetValue(shapeType, out shapeDescriptor);
var creatingContext = new ShapeCreatingContext { var creatingContext = new ShapeCreatingContext {
New = _shapeHelperFactory.Value.CreateHelper(), New = _shapeHelperFactory.Value.CreateHelper(),
ShapeFactory=this, ShapeFactory = this,
ShapeType = shapeType, ShapeType = shapeType,
OnCreated = new List<Action<ShapeCreatedContext>>() OnCreated = new List<Action<ShapeCreatedContext>>()
}; };
@@ -64,8 +68,13 @@ namespace Orchard.DisplayManagement.Implementation {
new ClaySharp.Behaviors.NilResultBehavior() new ClaySharp.Behaviors.NilResultBehavior()
}; };
} }
if (behaviors != null && behaviors.Any()) {
// include behaviors passed in by caller, if any
creatingContext.Behaviors = creatingContext.Behaviors.Concat(behaviors).ToList();
}
// "creating" events may add behaviors and alter base type // "creating" events may add behaviors and alter base type)
foreach (var ev in _events) { foreach (var ev in _events) {
ev.Value.Creating(creatingContext); ev.Value.Creating(creatingContext);
} }
@@ -102,7 +111,7 @@ namespace Orchard.DisplayManagement.Implementation {
// other properties passed with call overlay any defaults, so are after the created events // other properties passed with call overlay any defaults, so are after the created events
// only one non-Type, non-named argument is allowed // only one non-Type, non-named argument is allowed
var initializer = positional.SingleOrDefault(); var initializer = positional.SingleOrDefault();
if (initializer != null) { if (initializer != null) {
@@ -117,6 +126,8 @@ namespace Orchard.DisplayManagement.Implementation {
return createdContext.Shape; return createdContext.Shape;
} }
} }

View File

@@ -20,9 +20,9 @@ namespace Orchard.UI.Zones {
/// ///
/// </summary> /// </summary>
public class ZoneHoldingBehavior : ClayBehavior { public class ZoneHoldingBehavior : ClayBehavior {
private readonly Func<string, dynamic> _zoneFactory; private readonly Func<dynamic> _zoneFactory;
public ZoneHoldingBehavior(Func<string, dynamic> zoneFactory) { public ZoneHoldingBehavior(Func<dynamic> zoneFactory) {
_zoneFactory = zoneFactory; _zoneFactory = zoneFactory;
} }
@@ -50,10 +50,10 @@ namespace Orchard.UI.Zones {
} }
public class ZonesBehavior : ClayBehavior { public class ZonesBehavior : ClayBehavior {
private readonly Func<string, dynamic> _zoneFactory; private readonly Func<dynamic> _zoneFactory;
private readonly object _parent; private readonly object _parent;
public ZonesBehavior(Func<string, dynamic> zoneFactory, object parent) { public ZonesBehavior(Func<dynamic> zoneFactory, object parent) {
_zoneFactory = zoneFactory; _zoneFactory = zoneFactory;
_parent = parent; _parent = parent;
} }
@@ -78,11 +78,11 @@ namespace Orchard.UI.Zones {
} }
public class ZoneOnDemandBehavior : ClayBehavior { public class ZoneOnDemandBehavior : ClayBehavior {
private readonly Func<string, dynamic> _zoneFactory; private readonly Func<dynamic> _zoneFactory;
private readonly object _parent; private readonly object _parent;
private readonly string _potentialZoneName; private readonly string _potentialZoneName;
public ZoneOnDemandBehavior(Func<string, dynamic> zoneFactory, object parent, string potentialZoneName) { public ZoneOnDemandBehavior(Func<dynamic> zoneFactory, object parent, string potentialZoneName) {
_zoneFactory = zoneFactory; _zoneFactory = zoneFactory;
_parent = parent; _parent = parent;
_potentialZoneName = potentialZoneName; _potentialZoneName = potentialZoneName;
@@ -93,7 +93,7 @@ namespace Orchard.UI.Zones {
if (name == "Add" && (argsCount == 1 || argsCount == 2)) { if (name == "Add" && (argsCount == 1 || argsCount == 2)) {
dynamic parent = _parent; dynamic parent = _parent;
dynamic zone = _zoneFactory(_potentialZoneName); dynamic zone = _zoneFactory();
zone.Parent = _parent; zone.Parent = _parent;
zone.ZoneName = _potentialZoneName; zone.ZoneName = _potentialZoneName;
parent[_potentialZoneName] = zone; parent[_potentialZoneName] = zone;