diff --git a/src/Orchard.Tests/DisplayManagement/Descriptors/DefaultShapeTableManagerTests.cs b/src/Orchard.Tests/DisplayManagement/Descriptors/DefaultShapeTableManagerTests.cs index 77a350f02..2b2d9a0ce 100644 --- a/src/Orchard.Tests/DisplayManagement/Descriptors/DefaultShapeTableManagerTests.cs +++ b/src/Orchard.Tests/DisplayManagement/Descriptors/DefaultShapeTableManagerTests.cs @@ -153,7 +153,68 @@ namespace Orchard.Tests.DisplayManagement.Descriptors { Assert.That(foo.Displaying.Single(), Is.SameAs(cb3)); Assert.That(foo.Displayed.Single(), Is.SameAs(cb4)); } + [Test] + public void DefaultPlacementIsReturnedByDefault() { + var manager = _container.Resolve(); + var hello = manager.GetShapeTable(null).Descriptors["Hello"]; + hello.DefaultPlacement = "Header:5"; + var result = hello.Placement(null); + Assert.That(result, Is.EqualTo("Header:5")); + } + + [Test] + public void DescribedPlacementIsReturnedIfNotNull() { + + _container.Resolve().Discover = + builder => builder.Describe("Hello") + .Placement(ctx => ctx.DisplayType == "Detail" ? "Main" : null) + .Placement(ctx => ctx.DisplayType == "Summary" ? "" : null); + + var manager = _container.Resolve(); + var hello = manager.GetShapeTable(null).Descriptors["Hello"]; + var result1 = hello.Placement(new ShapePlacementContext { DisplayType = "Detail" }); + var result2 = hello.Placement(new ShapePlacementContext { DisplayType = "Summary" }); + var result3 = hello.Placement(new ShapePlacementContext { DisplayType = "Tile" }); + hello.DefaultPlacement = "Header:5"; + var result4 = hello.Placement(new ShapePlacementContext { DisplayType = "Detail" }); + var result5 = hello.Placement(new ShapePlacementContext { DisplayType = "Summary" }); + var result6 = hello.Placement(new ShapePlacementContext { DisplayType = "Tile" }); + + Assert.That(result1, Is.EqualTo("Main")); + Assert.That(result2, Is.EqualTo("")); + Assert.That(result3, Is.Null); + Assert.That(result4, Is.EqualTo("Main")); + Assert.That(result5, Is.EqualTo("")); + Assert.That(result6, Is.EqualTo("Header:5")); + } + + [Test] + public void TwoArgumentVariationDoesSameThing() { + + _container.Resolve().Discover = + builder => builder.Describe("Hello") + .Placement(ctx => ctx.DisplayType == "Detail", "Main") + .Placement(ctx => ctx.DisplayType == "Summary", ""); + + var manager = _container.Resolve(); + var hello = manager.GetShapeTable(null).Descriptors["Hello"]; + var result1 = hello.Placement(new ShapePlacementContext { DisplayType = "Detail" }); + var result2 = hello.Placement(new ShapePlacementContext { DisplayType = "Summary" }); + var result3 = hello.Placement(new ShapePlacementContext { DisplayType = "Tile" }); + hello.DefaultPlacement = "Header:5"; + var result4 = hello.Placement(new ShapePlacementContext { DisplayType = "Detail" }); + var result5 = hello.Placement(new ShapePlacementContext { DisplayType = "Summary" }); + var result6 = hello.Placement(new ShapePlacementContext { DisplayType = "Tile" }); + + Assert.That(result1, Is.EqualTo("Main")); + Assert.That(result2, Is.EqualTo("")); + Assert.That(result3, Is.Null); + Assert.That(result4, Is.EqualTo("Main")); + Assert.That(result5, Is.EqualTo("")); + Assert.That(result6, Is.EqualTo("Header:5")); + } + [Test] public void OnlyShapesFromTheGivenThemeAreProvided() { _container.Resolve(); @@ -182,5 +243,7 @@ namespace Orchard.Tests.DisplayManagement.Descriptors { Assert.IsTrue(table.Bindings.ContainsKey("OverriddenShape")); Assert.AreEqual("DerivedTheme", table.Descriptors["OverriddenShape"].BindingSource); } + + } } \ No newline at end of file diff --git a/src/Orchard.Tests/DisplayManagement/Descriptors/InMemoryWebSiteFolder.cs b/src/Orchard.Tests/DisplayManagement/Descriptors/InMemoryWebSiteFolder.cs new file mode 100644 index 000000000..315ea32f5 --- /dev/null +++ b/src/Orchard.Tests/DisplayManagement/Descriptors/InMemoryWebSiteFolder.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Orchard.Caching; +using Orchard.FileSystems.WebSite; + +namespace Orchard.Tests.DisplayManagement.Descriptors { + public class InMemoryWebSiteFolder : IWebSiteFolder { + public InMemoryWebSiteFolder() { + Contents = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + public IDictionary Contents { get; set; } + + public IEnumerable ListDirectories(string virtualPath) { + throw new NotImplementedException(); + } + + public IEnumerable ListFiles(string virtualPath, bool recursive) { + throw new NotImplementedException(); + } + + public bool FileExists(string virtualPath) { + throw new NotImplementedException(); + } + + public string ReadFile(string virtualPath) { + string result; + return Contents.TryGetValue(virtualPath, out result) ? result : null; + } + + public string ReadFile(string virtualPath, bool actualContent) { + throw new NotImplementedException(); + } + + public void CopyFileTo(string virtualPath, Stream destination) { + throw new NotImplementedException(); + } + + public void CopyFileTo(string virtualPath, Stream destination, bool actualContent) { + throw new NotImplementedException(); + } + + public IVolatileToken WhenPathChanges(string virtualPath) { + return new Token { IsCurrent = true }; + } + + public class Token : IVolatileToken { + public bool IsCurrent { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Tests/DisplayManagement/Descriptors/PlacementFileParserTests.cs b/src/Orchard.Tests/DisplayManagement/Descriptors/PlacementFileParserTests.cs new file mode 100644 index 000000000..899617170 --- /dev/null +++ b/src/Orchard.Tests/DisplayManagement/Descriptors/PlacementFileParserTests.cs @@ -0,0 +1,92 @@ +using System.Linq; +using System.Text; +using Autofac; +using NUnit.Framework; +using Orchard.Caching; +using Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy; +using Orchard.FileSystems.WebSite; +using Orchard.Tests.Stubs; + +namespace Orchard.Tests.DisplayManagement.Descriptors { + [TestFixture] + public class PlacementFileParserTests : ContainerTestBase { + private IPlacementFileParser _parser; + private InMemoryWebSiteFolder _folder; + + protected override void Register(Autofac.ContainerBuilder builder) { + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As() + .As().InstancePerLifetimeScope(); + } + + + protected override void Resolve(IContainer container) { + _parser = container.Resolve(); + _folder = container.Resolve(); + } + + [Test] + public void ParsingMissingFileIsNull() { + var result = _parser.Parse("~/hello.xml"); + Assert.That(result, Is.Null); + } + + [Test] + public void ParsingEmptyFileAsNothing() { + _folder.Contents["~/hello.xml"] = ""; + var result = _parser.Parse("~/hello.xml"); + Assert.That(result, Is.Not.Null); + Assert.That(result.Nodes, Is.Not.Null); + Assert.That(result.Nodes.Count(), Is.EqualTo(0)); + } + + [Test] + public void ItemsComeBackAsPlacementNodes() { + _folder.Contents["~/hello.xml"] = @" + + + + +"; + var result = _parser.Parse("~/hello.xml"); + Assert.That(result, Is.Not.Null); + Assert.That(result.Nodes, Is.Not.Null); + Assert.That(result.Nodes.Count(), Is.EqualTo(2)); + } + + + [Test] + public void NestedItemsComeBackAsNestedNodes() { + _folder.Contents["~/hello.xml"] = @" + + + + + + +"; + var result = _parser.Parse("~/hello.xml"); + Assert.That(result, Is.Not.Null); + Assert.That(result.Nodes, Is.Not.Null); + Assert.That(result.Nodes.Count(), Is.EqualTo(2)); + Assert.That(result.Nodes.First().Nodes.Count(), Is.EqualTo(1)); + Assert.That(result.Nodes.Last().Nodes.Count(), Is.EqualTo(0)); + } + + [Test] + public void EachPlaceAttributeIsShapeLocation() { + _folder.Contents["~/hello.xml"] = @" + +"; + var result = _parser.Parse("~/hello.xml"); + Assert.That(result, Is.Not.Null); + Assert.That(result.Nodes, Is.Not.Null); + Assert.That(result.Nodes.Count(), Is.EqualTo(2)); + var foo = result.Nodes.OfType().Single(x=>x.ShapeType == "Foo"); + var bar = result.Nodes.OfType().Single(x=>x.ShapeType == "Bar"); + Assert.That(foo.Location, Is.EqualTo("Header")); + Assert.That(bar.Location, Is.EqualTo("Content:after")); + } + } +} diff --git a/src/Orchard.Tests/Orchard.Framework.Tests.csproj b/src/Orchard.Tests/Orchard.Framework.Tests.csproj index ae856e317..c8c32269e 100644 --- a/src/Orchard.Tests/Orchard.Framework.Tests.csproj +++ b/src/Orchard.Tests/Orchard.Framework.Tests.csproj @@ -216,6 +216,8 @@ + + diff --git a/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs b/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs index 694d6b59b..a9020d471 100644 --- a/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs +++ b/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs @@ -34,19 +34,17 @@ namespace Orchard.Core.Common.Drivers { } protected override DriverResult Display(BodyPart part, string displayType, dynamic shapeHelper) { - var bodyText = _htmlFilters.Aggregate(part.Text, (text, filter) => filter.ProcessContent(text)); - var body = shapeHelper.Parts_Common_Body(ContentPart: part, Html: new HtmlString(bodyText)); - if (!string.IsNullOrWhiteSpace(displayType)) - body.Metadata.Type = string.Format("{0}.{1}", body.Metadata.Type, displayType); - var location = part.GetLocation(displayType); - //return Combined( - // Services.Authorizer.Authorize(Permissions.ChangeOwner) ? ContentPartTemplate(model, "Parts/Common.Body.ManageWrapperPre").LongestMatch(displayType, "SummaryAdmin").Location(location) : null, - // Services.Authorizer.Authorize(Permissions.ChangeOwner) ? ContentPartTemplate(model, "Parts/Common.Body.Manage").LongestMatch(displayType, "SummaryAdmin").Location(location) : null, - // ContentPartTemplate(model, TemplateName, Prefix).LongestMatch(displayType, "Summary", "SummaryAdmin").Location(location), - // Services.Authorizer.Authorize(Permissions.ChangeOwner) ? ContentPartTemplate(model, "Parts/Common.Body.ManageWrapperPost").LongestMatch(displayType, "SummaryAdmin").Location(location) : null); - - return ContentShape(body).Location(location); + return Combined( + ContentShape("Parts_Common_Body", displayType == "Detail" ? "Content" : null, () => { + 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)); + return shapeHelper.Parts_Common_Body_Summary(ContentPart: part, Html: new HtmlString(bodyText)); + }) + ); } protected override DriverResult Editor(BodyPart part, dynamic shapeHelper) { diff --git a/src/Orchard.Web/Core/Contents/Shapes.cs b/src/Orchard.Web/Core/Contents/Shapes.cs index e116dc6a7..fddd989a0 100644 --- a/src/Orchard.Web/Core/Contents/Shapes.cs +++ b/src/Orchard.Web/Core/Contents/Shapes.cs @@ -1,15 +1,27 @@ -using Orchard.DisplayManagement.Implementation; +using System; +using Orchard.ContentManagement; +using Orchard.DisplayManagement.Descriptors; +using Orchard.DisplayManagement.Implementation; using Orchard.UI.Zones; namespace Orchard.Core.Contents { - public class Shapes : IShapeFactoryEvents { - - public void Creating(ShapeCreatingContext creating) { - if (creating.ShapeType.StartsWith("Items_Content")) - creating.Behaviors.Add(new ZoneHoldingBehavior(name => creating.New.ContentZone())); + public class Shapes : IShapeTableProvider { + public void Discover(ShapeTableBuilder builder) { + builder.Describe("Items_Content") + .OnCreating(creating => creating.Behaviors.Add(new ZoneHoldingBehavior(name => ContentZone(creating, name)))) + .OnDisplaying(displaying => { + ContentItem contentItem = displaying.Shape.ContentItem; + if (contentItem != null) { + displaying.ShapeMetadata.Alternates.Add("Items_Content__" + contentItem.ContentType); + displaying.ShapeMetadata.Alternates.Add("Items_Content__" + contentItem.Id); + } + }); } - public void Created(ShapeCreatedContext created) { + private static object ContentZone(ShapeCreatingContext creating, string name) { + var zone = creating.New.ContentZone(); + zone.ZoneName = name; + return zone; } } } diff --git a/src/Orchard.Web/Core/Contents/Views/Items/Content.cshtml b/src/Orchard.Web/Core/Contents/Views/Items/Content.cshtml index 9147b7ecb..46e4e50b9 100644 --- a/src/Orchard.Web/Core/Contents/Views/Items/Content.cshtml +++ b/src/Orchard.Web/Core/Contents/Views/Items/Content.cshtml @@ -3,6 +3,6 @@ @Display(Model.Header)
-@Display(Model.Primary) +@Display(Model.Content)
\ No newline at end of file diff --git a/src/Orchard.Web/Core/Orchard.Core.csproj b/src/Orchard.Web/Core/Orchard.Core.csproj index 31141c616..2beb761d3 100644 --- a/src/Orchard.Web/Core/Orchard.Core.csproj +++ b/src/Orchard.Web/Core/Orchard.Core.csproj @@ -392,7 +392,7 @@ - + diff --git a/src/Orchard.Web/Core/Routable/Drivers/RoutePartDriver.cs b/src/Orchard.Web/Core/Routable/Drivers/RoutePartDriver.cs index 9bdd6b0d7..5a0b308cc 100644 --- a/src/Orchard.Web/Core/Routable/Drivers/RoutePartDriver.cs +++ b/src/Orchard.Web/Core/Routable/Drivers/RoutePartDriver.cs @@ -45,11 +45,7 @@ namespace Orchard.Core.Routable.Drivers { } protected override DriverResult Display(RoutePart part, string displayType, dynamic shapeHelper) { - var routePart = shapeHelper.Parts_Routable_RoutePart(ContentPart: part, Title: part.Title); - if (!string.IsNullOrWhiteSpace(displayType)) - routePart.Metadata.Type = string.Format("{0}.{1}", routePart.Metadata.Type, displayType); - var location = part.GetLocation(displayType, "Header", "5"); - return ContentShape(routePart).Location(location); + return ContentShape("Parts_RoutableTitle", "Header:5", () => shapeHelper.Parts_RoutableTitle(ContentPart: part, Title: part.Title)); } protected override DriverResult Editor(RoutePart part, dynamic shapeHelper) { @@ -80,7 +76,7 @@ namespace Orchard.Core.Routable.Drivers { } protected override DriverResult Editor(RoutePart part, IUpdateModel updater, dynamic shapeHelper) { - + var model = new RoutableEditorViewModel(); updater.TryUpdateModel(model, Prefix, null, null); part.Title = model.Title; diff --git a/src/Orchard.Web/Core/Routable/Views/Parts/Routable.RoutePart.cshtml b/src/Orchard.Web/Core/Routable/Views/Parts/RoutableTitle.cshtml similarity index 100% rename from src/Orchard.Web/Core/Routable/Views/Parts/Routable.RoutePart.cshtml rename to src/Orchard.Web/Core/Routable/Views/Parts/RoutableTitle.cshtml diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs index f8d9b297f..d48162bbb 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs +++ b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs @@ -215,6 +215,7 @@ namespace Orchard.Setup.Services { contentDefinitionManager.AlterPartDefinition("BodyPart", cfg => cfg .WithSetting("BodyPartSettings.FlavorDefault", BodyPartSettings.FlavorDefaultDefault)); + // add a layer for the homepage var layer = contentManager.Create("Layer"); layer.As().Name = "TheHomepage"; diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Orchard.Widgets.csproj b/src/Orchard.Web/Modules/Orchard.Widgets/Orchard.Widgets.csproj index f71910ccf..299f79a33 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Orchard.Widgets.csproj +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Orchard.Widgets.csproj @@ -115,6 +115,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Views/Items_Widget.cshtml b/src/Orchard.Web/Modules/Orchard.Widgets/Views/Items_Widget.cshtml new file mode 100644 index 000000000..0fa937dbb --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Views/Items_Widget.cshtml @@ -0,0 +1,4 @@ +TheWidget +@Display(Model.Content) +@Display(Model.Primary) +@Display(Model.Body) diff --git a/src/Orchard.Web/Orchard.Web.csproj b/src/Orchard.Web/Orchard.Web.csproj index e6f0ebc94..c95d3ddae 100644 --- a/src/Orchard.Web/Orchard.Web.csproj +++ b/src/Orchard.Web/Orchard.Web.csproj @@ -125,6 +125,7 @@ + diff --git a/src/Orchard.Web/Themes/Classic/Placement.info b/src/Orchard.Web/Themes/Classic/Placement.info new file mode 100644 index 000000000..af3251204 --- /dev/null +++ b/src/Orchard.Web/Themes/Classic/Placement.info @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/src/Orchard.Web/Themes/TheThemeMachine/Styles/site.css b/src/Orchard.Web/Themes/TheThemeMachine/Styles/site.css index 78f8231c7..d2499253e 100644 --- a/src/Orchard.Web/Themes/TheThemeMachine/Styles/site.css +++ b/src/Orchard.Web/Themes/TheThemeMachine/Styles/site.css @@ -141,6 +141,21 @@ p { margin-top:12px; } +/*Two Sidebars on */ +.has-sidebars #content { + background-color:#e8e8e8; + width: 600px; +} + +.has-sidebars .sidebar { + background-color:#f6f6f6; + width: 180px; +} + +.has-sidebars .primary, .has-sidebars .secondary, .has-sidebars #content { + float:left; +} + /* Navigation */ diff --git a/src/Orchard.Web/Themes/TheThemeMachine/Views/Layout.cshtml b/src/Orchard.Web/Themes/TheThemeMachine/Views/Layout.cshtml index 4fdba2241..57783dcc7 100644 --- a/src/Orchard.Web/Themes/TheThemeMachine/Views/Layout.cshtml +++ b/src/Orchard.Web/Themes/TheThemeMachine/Views/Layout.cshtml @@ -85,7 +85,6 @@ - } @* Create a zone and only show it on the home page. *@ diff --git a/src/Orchard.Web/Themes/Web.config b/src/Orchard.Web/Themes/Web.config index f2f307586..ae3d47d77 100644 --- a/src/Orchard.Web/Themes/Web.config +++ b/src/Orchard.Web/Themes/Web.config @@ -5,6 +5,8 @@ + +