diff --git a/src/Orchard.Web/Core/Containers/Controllers/ItemController.cs b/src/Orchard.Web/Core/Containers/Controllers/ItemController.cs index 939379938..a61c28c4d 100644 --- a/src/Orchard.Web/Core/Containers/Controllers/ItemController.cs +++ b/src/Orchard.Web/Core/Containers/Controllers/ItemController.cs @@ -59,34 +59,8 @@ namespace Orchard.Core.Containers.Controllers { } var container = _contentManager.Get(hits.Single().Id); - IContentQuery query = _contentManager - .Query(VersionOptions.Published) - .Join().Where(cr => cr.Container.Id == container.Id); - - var descendingOrder = container.As().Record.OrderByDirection == (int) OrderByDirection.Descending; - query = query.OrderBy(container.As().Record.OrderByProperty, descendingOrder); - - _feedManager.Register(container.As().Title, "rss", new RouteValueDictionary { { "containerid", container.Id } }); - - Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters); - pager.PageSize = pagerParameters.PageSize != null && container.As().Record.Paginated - ? pager.PageSize - : container.As().Record.PageSize; - var pagerShape = Shape.Pager(pager).TotalItemCount(query.Count()); - - var startIndex = container.As().Record.Paginated ? pager.GetStartIndex() : 0; - var pageOfItems = query.Slice(startIndex, pager.PageSize).ToList(); - - var list = Shape.List(); - list.AddRange(pageOfItems.Select(item => _contentManager.BuildDisplay(item, "Summary"))); - list.Classes.Add("content-items"); - list.Classes.Add("list-items"); - + container.As().PagerParameters = pagerParameters; var model = _contentManager.BuildDisplay(container, "Detail"); - model.Content.Add(list, "7"); - if (container.As().Record.Paginated) { - model.Content.Add(pagerShape, "7.5"); - } return new ShapeResult(this, model); } diff --git a/src/Orchard.Web/Core/Containers/Drivers/ContainablePartDriver.cs b/src/Orchard.Web/Core/Containers/Drivers/ContainablePartDriver.cs index c068f61da..22f5eee38 100644 --- a/src/Orchard.Web/Core/Containers/Drivers/ContainablePartDriver.cs +++ b/src/Orchard.Web/Core/Containers/Drivers/ContainablePartDriver.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Web.Mvc; using Orchard.ContentManagement; -using Orchard.ContentManagement.Aspects; using Orchard.ContentManagement.Drivers; using Orchard.Core.Common.Models; using Orchard.Core.Containers.Models; @@ -44,6 +43,7 @@ namespace Orchard.Core.Containers.Drivers { commonPart.Record.Container = containerItem == null ? null : containerItem.Record; } } + part.Weight = model.Weight; } // note: string.isnullorempty not being recognized by linq-to-nhibernate hence the inline or @@ -59,6 +59,7 @@ namespace Orchard.Core.Containers.Drivers { .ToList(); model.AvailableContainers = new SelectList(listItems, "Value", "Text", model.ContainerId); + model.Weight = part.Weight; return shapeHelper.EditorTemplate(TemplateName: "Containable", Model: model, Prefix: "Containable"); }); diff --git a/src/Orchard.Web/Core/Containers/Drivers/ContainerPartDriver.cs b/src/Orchard.Web/Core/Containers/Drivers/ContainerPartDriver.cs index 309251dea..18191c499 100644 --- a/src/Orchard.Web/Core/Containers/Drivers/ContainerPartDriver.cs +++ b/src/Orchard.Web/Core/Containers/Drivers/ContainerPartDriver.cs @@ -7,29 +7,79 @@ using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.MetaData; using Orchard.Core.Common.Models; using Orchard.Core.Containers.Models; -using Orchard.Core.Containers.Settings; using Orchard.Core.Containers.ViewModels; -using Orchard.Data; using Orchard.Localization; using Orchard.UI.Notify; +using Orchard.DisplayManagement; +using Orchard.Core.Containers.Extensions; +using Orchard.Core.Routable.Models; +using System.Web.Routing; +using Orchard.Settings; +using Orchard.Core.Feeds; +using Orchard.UI.Navigation; namespace Orchard.Core.Containers.Drivers { public class ContainerPartDriver : ContentPartDriver { private readonly IContentDefinitionManager _contentDefinitionManager; + private readonly IOrchardServices _orchardServices; + private readonly IContentManager _contentManager; + private readonly dynamic _shapeFactory; + private readonly ISiteService _siteService; + private readonly IFeedManager _feedManager; - public ContainerPartDriver(IContentDefinitionManager contentDefinitionManager, IOrchardServices orchardServices) { + public ContainerPartDriver( + IContentDefinitionManager contentDefinitionManager, + IOrchardServices orchardServices, + IShapeFactory shapeFactory, + ISiteService siteService, + IFeedManager feedManager) { _contentDefinitionManager = contentDefinitionManager; - Services = orchardServices; + _orchardServices = orchardServices; + _contentManager = orchardServices.ContentManager; + _shapeFactory = shapeFactory; + _siteService = siteService; + _feedManager = feedManager; + T = NullLocalizer.Instance; } - public IOrchardServices Services { get; private set; } public Localizer T { get; set; } protected override DriverResult Display(ContainerPart part, string displayType, dynamic shapeHelper) { + if (!part.ItemsShown) + return null; + return Combined( ContentShape("Parts_Container_Contained", - () => shapeHelper.Parts_Container_Contained(ContentPart: part)), + () => { + var container = part.ContentItem; + + IContentQuery query = _contentManager + .Query(VersionOptions.Published) + .Join().Where(cr => cr.Container.Id == container.Id); + + var descendingOrder = part.OrderByDirection == (int)OrderByDirection.Descending; + query = query.OrderBy(part.OrderByProperty, descendingOrder); + + _feedManager.Register(container.As().Title, "rss", new RouteValueDictionary { { "containerid", container.Id } }); + + var pager = new Pager(_siteService.GetSiteSettings(), part.PagerParameters); + pager.PageSize = part.PagerParameters.PageSize != null && part.Paginated + ? pager.PageSize + : part.PageSize; + + // var pagerShape = _shapeFactory.Pager(pager).TotalItemCount(query.Count()); + + var startIndex = part.Paginated ? pager.GetStartIndex() : 0; + var pageOfItems = query.Slice(startIndex, pager.PageSize).ToList(); + + var list = _shapeFactory.List(); + list.AddRange(pageOfItems.Select(item => _contentManager.BuildDisplay(item, "Summary"))); + list.Classes.Add("content-items"); + list.Classes.Add("list-items"); + + return list; + }), ContentShape("Parts_Container_Contained_Summary", () => shapeHelper.Parts_Container_Contained_Summary(ContentPart: part)), ContentShape("Parts_Container_Contained_SummaryAdmin", @@ -39,9 +89,8 @@ namespace Orchard.Core.Containers.Drivers { protected override DriverResult Editor(ContainerPart part, dynamic shapeHelper) { // if there are no containable items then show a nice little warning - if (!_contentDefinitionManager.ListTypeDefinitions() - .Where(typeDefinition => typeDefinition.Parts.Any(partDefinition => partDefinition.PartDefinition.Name == "ContainablePart")).Any()) { - Services.Notifier.Warning(T("There are no content types in the system with a Containable part attached. Consider adding a Containable part to some content type, existing or new, in order to relate items to this (Container enabled) item.")); + if (!_contentDefinitionManager.ListTypeDefinitions().Any(typeDefinition => typeDefinition.Parts.Any(partDefinition => partDefinition.PartDefinition.Name == "ContainablePart"))) { + _orchardServices.Notifier.Warning(T("There are no content types in the system with a Containable part attached. Consider adding a Containable part to some content type, existing or new, in order to relate items to this (Container enabled) item.")); } return Editor(part, (IUpdateModel)null, shapeHelper); @@ -62,12 +111,12 @@ namespace Orchard.Core.Containers.Drivers { })) .ToList(); - model.AvailableContainables = new SelectList(listItems, "Value", "Text", model.Part.Record.ItemContentType); + model.AvailableContainables = new SelectList(listItems, "Value", "Text", model.Part.ItemContentType); if (updater != null) { updater.TryUpdateModel(model, "Container", null, null); } - + return shapeHelper.EditorTemplate(TemplateName: "Container", Model: model, Prefix: "Container"); }); } @@ -80,6 +129,11 @@ namespace Orchard.Core.Containers.Drivers { } } + var itemsShown = context.Attribute(part.PartDefinition.Name, "ItemsShown"); + if (itemsShown != null) { + part.Record.ItemsShown = Convert.ToBoolean(itemsShown); + } + var paginated = context.Attribute(part.PartDefinition.Name, "Paginated"); if (paginated != null) { part.Record.Paginated = Convert.ToBoolean(paginated); @@ -103,26 +157,11 @@ namespace Orchard.Core.Containers.Drivers { protected override void Exporting(ContainerPart part, ExportContentContext context) { context.Element(part.PartDefinition.Name).SetAttributeValue("ItemContentType", part.Record.ItemContentType); + context.Element(part.PartDefinition.Name).SetAttributeValue("ItemsShown", part.Record.ItemsShown); context.Element(part.PartDefinition.Name).SetAttributeValue("Paginated", part.Record.Paginated); context.Element(part.PartDefinition.Name).SetAttributeValue("PageSize", part.Record.PageSize); context.Element(part.PartDefinition.Name).SetAttributeValue("OrderByProperty", part.Record.OrderByProperty); context.Element(part.PartDefinition.Name).SetAttributeValue("OrderByDirection", part.Record.OrderByDirection); } } - - public class ContainerPartHandler : ContentHandler { - public ContainerPartHandler(IRepository repository) { - Filters.Add(StorageFilter.For(repository)); - OnInitializing((context, part) => { - part.Record.PageSize = part.Settings.GetModel().PageSizeDefault - ?? part.PartDefinition.Settings.GetModel().PageSizeDefault; - part.Record.Paginated = part.Settings.GetModel().PaginatedDefault - ?? part.PartDefinition.Settings.GetModel().PaginatedDefault; - - // hard-coded defaults for ordering - part.Record.OrderByProperty = part.Is() ? "CommonPart.CreatedUtc" : string.Empty; - part.Record.OrderByDirection = (int)OrderByDirection.Descending; - }); - } - } } diff --git a/src/Orchard.Web/Core/Containers/Extensions/ContentQueryExtensions.cs b/src/Orchard.Web/Core/Containers/Extensions/ContentQueryExtensions.cs index 5b782f1fa..24b296b3b 100644 --- a/src/Orchard.Web/Core/Containers/Extensions/ContentQueryExtensions.cs +++ b/src/Orchard.Web/Core/Containers/Extensions/ContentQueryExtensions.cs @@ -6,12 +6,16 @@ using Orchard.Core.Containers.Models; using Orchard.Core.Routable.Models; using Orchard.Core.Title.Models; -namespace Orchard.Core.Containers.Extensions -{ +namespace Orchard.Core.Containers.Extensions { public static class ContentQueryExtensions { public static IContentQuery OrderBy(this IContentQuery query, string partAndProperty, bool descendingOrder) where T : IContent { //todo: (heskew) order by custom part properties switch (partAndProperty) { + case "ContainablePart.Weight": + query = descendingOrder + ? query.OrderByDescending(record => record.Weight) + : query.OrderBy(record => record.Weight); + break; case "TitlePart.Title": query = descendingOrder ? query.OrderByDescending(record => record.Title) diff --git a/src/Orchard.Web/Core/Containers/Handlers/ContainablePartHandler.cs b/src/Orchard.Web/Core/Containers/Handlers/ContainablePartHandler.cs new file mode 100644 index 000000000..2b8e9a0e7 --- /dev/null +++ b/src/Orchard.Web/Core/Containers/Handlers/ContainablePartHandler.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Orchard.ContentManagement.Handlers; +using Orchard.Data; +using Orchard.Core.Containers.Models; + +namespace Orchard.Core.Containers.Handlers { + public class ContainablePartHandler : ContentHandler { + public ContainablePartHandler(IRepository repository) { + Filters.Add(StorageFilter.For(repository)); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Containers/Handlers/ContainerPartHandler.cs b/src/Orchard.Web/Core/Containers/Handlers/ContainerPartHandler.cs new file mode 100644 index 000000000..821e35381 --- /dev/null +++ b/src/Orchard.Web/Core/Containers/Handlers/ContainerPartHandler.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Orchard.ContentManagement.Handlers; +using Orchard.Core.Containers.Models; +using Orchard.Core.Containers.Settings; +using Orchard.Core.Common.Models; +using Orchard.Data; +using Orchard.Core.Containers.Extensions; +using Orchard.ContentManagement; + +namespace Orchard.Core.Containers.Handlers { + public class ContainerPartHandler : ContentHandler { + public ContainerPartHandler(IRepository repository) { + Filters.Add(StorageFilter.For(repository)); + OnInitializing((context, part) => { + part.Record.ItemsShown = true; + part.Record.PageSize = part.Settings.GetModel().PageSizeDefault + ?? part.PartDefinition.Settings.GetModel().PageSizeDefault; + part.Record.Paginated = part.Settings.GetModel().PaginatedDefault + ?? part.PartDefinition.Settings.GetModel().PaginatedDefault; + + // hard-coded defaults for ordering + part.Record.OrderByProperty = part.Is() ? "CommonPart.CreatedUtc" : string.Empty; + part.Record.OrderByDirection = (int)OrderByDirection.Descending; + }); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Containers/Migrations.cs b/src/Orchard.Web/Core/Containers/Migrations.cs index bab60d441..f90653b2e 100644 --- a/src/Orchard.Web/Core/Containers/Migrations.cs +++ b/src/Orchard.Web/Core/Containers/Migrations.cs @@ -11,7 +11,9 @@ namespace Orchard.Core.Containers { .Column("Paginated") .Column("PageSize") .Column("OrderByProperty") - .Column("OrderByDirection")); + .Column("OrderByDirection") + .Column("ItemContentType") + .Column("ItemsShown", column => column.WithDefault(true))); SchemaBuilder.CreateTable("ContainerWidgetPartRecord", table => table @@ -32,6 +34,11 @@ namespace Orchard.Core.Containers { .Column("CustomTwo") .Column("CustomThree")); + SchemaBuilder.CreateTable("ContainablePartRecord", + table => table + .ContentPartRecord() + .Column("Weight")); + ContentDefinitionManager.AlterTypeDefinition("ContainerWidget", cfg => cfg .WithPart("CommonPart") @@ -43,12 +50,24 @@ namespace Orchard.Core.Containers { ContentDefinitionManager.AlterPartDefinition("ContainablePart", builder => builder.Attachable()); ContentDefinitionManager.AlterPartDefinition("CustomPropertiesPart", builder => builder.Attachable()); - return 1; + return 3; } public int UpdateFrom1() { SchemaBuilder.AlterTable("ContainerPartRecord", table => table.AddColumn("ItemContentType")); return 2; } + + public int UpdateFrom2() { + SchemaBuilder.AlterTable("ContainerPartRecord", + table => table.AddColumn("ItemsShown", column => column.WithDefault(true))); + + SchemaBuilder.CreateTable("ContainablePartRecord", + table => table + .ContentPartRecord() + .Column("Weight")); + + return 3; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Core/Containers/Models/ContainablePart.cs b/src/Orchard.Web/Core/Containers/Models/ContainablePart.cs index dcafd72aa..7b83322ec 100644 --- a/src/Orchard.Web/Core/Containers/Models/ContainablePart.cs +++ b/src/Orchard.Web/Core/Containers/Models/ContainablePart.cs @@ -1,6 +1,15 @@ using Orchard.ContentManagement; +using Orchard.ContentManagement.Records; namespace Orchard.Core.Containers.Models { - public class ContainablePart : ContentPart { + public class ContainablePart : ContentPart { + public int Weight { + get { return Record.Weight; } + set { Record.Weight = value; } + } + } + + public class ContainablePartRecord : ContentPartRecord { + public virtual int Weight { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Core/Containers/Models/ContainerPart.cs b/src/Orchard.Web/Core/Containers/Models/ContainerPart.cs index 6ee085097..6e7550a73 100644 --- a/src/Orchard.Web/Core/Containers/Models/ContainerPart.cs +++ b/src/Orchard.Web/Core/Containers/Models/ContainerPart.cs @@ -1,12 +1,49 @@ using Orchard.ContentManagement; using Orchard.ContentManagement.Records; +using Orchard.UI.Navigation; namespace Orchard.Core.Containers.Models { public class ContainerPart : ContentPart { + public string ItemContentType { + get { return Record.ItemContentType; } + set { Record.ItemContentType = value; } + } + + public bool ItemsShown { + get { return Record.ItemsShown; } + set { Record.ItemsShown = value; } + } + + public bool Paginated { + get { return Record.Paginated; } + set { Record.Paginated = value; } + } + + public int PageSize { + get { return Record.PageSize; } + set { Record.PageSize = value; } + } + + public string OrderByProperty { + get { return Record.OrderByProperty; } + set { Record.OrderByProperty = value; } + } + + public int OrderByDirection { + get { return Record.OrderByDirection; } + set { Record.OrderByDirection = value; } + } + + public PagerParameters PagerParameters { get; set; } + + public ContainerPart() { + PagerParameters = new PagerParameters(); + } } public class ContainerPartRecord : ContentPartRecord { public virtual string ItemContentType { get; set; } + public virtual bool ItemsShown { get; set; } public virtual bool Paginated { get; set; } public virtual int PageSize { get; set; } public virtual string OrderByProperty { get; set; } diff --git a/src/Orchard.Web/Core/Containers/Placement.info b/src/Orchard.Web/Core/Containers/Placement.info index 9feba91ba..f25b8d22d 100644 --- a/src/Orchard.Web/Core/Containers/Placement.info +++ b/src/Orchard.Web/Core/Containers/Placement.info @@ -4,6 +4,9 @@ Parts_Container_Contained Parts_Container_Contained_Summary --> + + + diff --git a/src/Orchard.Web/Core/Containers/ViewModels/ContainableViewModel.cs b/src/Orchard.Web/Core/Containers/ViewModels/ContainableViewModel.cs index d3261f577..d34c3d4ff 100644 --- a/src/Orchard.Web/Core/Containers/ViewModels/ContainableViewModel.cs +++ b/src/Orchard.Web/Core/Containers/ViewModels/ContainableViewModel.cs @@ -4,5 +4,6 @@ namespace Orchard.Core.Containers.ViewModels { public class ContainableViewModel { public int ContainerId { get; set; } public SelectList AvailableContainers { get; set; } + public int Weight { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Core/Containers/Views/EditorTemplates/Containable.cshtml b/src/Orchard.Web/Core/Containers/Views/EditorTemplates/Containable.cshtml index 16a610a71..af19c6ae1 100644 --- a/src/Orchard.Web/Core/Containers/Views/EditorTemplates/Containable.cshtml +++ b/src/Orchard.Web/Core/Containers/Views/EditorTemplates/Containable.cshtml @@ -1,5 +1,11 @@ @model Orchard.Core.Containers.ViewModels.ContainableViewModel
- @Html.LabelFor(m => m.ContainerId, T("Add to")) - @Html.DropDownListFor(m => m.ContainerId, Model.AvailableContainers) + + @Html.LabelFor(m => m.ContainerId, T("Add to")) + @Html.DropDownListFor(m => m.ContainerId, Model.AvailableContainers) + + + @Html.LabelFor(m => m.Weight, T("Weight")) + @Html.TextBoxFor(m => m.Weight, new { @class = "text text-small" }) +
\ No newline at end of file diff --git a/src/Orchard.Web/Core/Containers/Views/EditorTemplates/Container.cshtml b/src/Orchard.Web/Core/Containers/Views/EditorTemplates/Container.cshtml index 3ffc307f8..c67105908 100644 --- a/src/Orchard.Web/Core/Containers/Views/EditorTemplates/Container.cshtml +++ b/src/Orchard.Web/Core/Containers/Views/EditorTemplates/Container.cshtml @@ -1,34 +1,41 @@ @model Orchard.Core.Containers.ViewModels.ContainerViewModel @using Orchard.Core.Containers.Models; +
+ + @Html.CheckBoxFor(m => m.Part.ItemsShown) + + +
- @Html.LabelFor(m => m.Part.Record.ItemContentType, T("Contains")) - @Html.DropDownListFor(m => m.Part.Record.ItemContentType, Model.AvailableContainables) + @Html.LabelFor(m => m.Part.ItemContentType, T("Contains")) + @Html.DropDownListFor(m => m.Part.ItemContentType, Model.AvailableContainables) @T("Only types with the Containable part can be contained in a list.")
- @Html.LabelFor(m => m.Part.Record.OrderByProperty, T("Order by")) - + @Html.SelectOption(Model.Part.OrderByProperty, "ContainablePart.Weight", T("Weight").Text) + @Html.SelectOption(Model.Part.OrderByProperty, "CommonPart.CreatedUtc", T("Date Created").Text) + @Html.SelectOption(Model.Part.OrderByProperty, "CommonPart.PublishedUtc", T("Date Published").Text) + @Html.SelectOption(Model.Part.OrderByProperty, "TitlePart.Title", T("Title").Text) + @Html.SelectOption(Model.Part.OrderByProperty, "RoutePart.Title", T("Routable Title").Text) + @Html.SelectOption(Model.Part.OrderByProperty, "RoutePart.Slug", T("Slug").Text) + @Html.SelectOption(Model.Part.OrderByProperty, "CustomPropertiesPart.CustomOne", T("Custom 1").Text) + @Html.SelectOption(Model.Part.OrderByProperty, "CustomPropertiesPart.CustomTwo", T("Custom 2").Text) + @Html.SelectOption(Model.Part.OrderByProperty, "CustomPropertiesPart.CustomThree", T("Custom 3").Text) - + @Html.SelectOption(Model.Part.OrderByDirection, (int)OrderByDirection.Ascending, T("Ascending").Text) + @Html.SelectOption(Model.Part.OrderByDirection, (int)OrderByDirection.Descending, T("Descending").Text)
- @Html.LabelFor(m => m.Part.Record.PageSize, T("Page size")) - @Html.TextBoxFor(m => m.Part.Record.PageSize, new { @class = "text text-small" }) + @Html.LabelFor(m => m.Part.PageSize, T("Page size")) + @Html.TextBoxFor(m => m.Part.PageSize, new { @class = "text text-small" }) - @Html.CheckBoxFor(m => m.Part.Record.Paginated) - + @Html.CheckBoxFor(m => m.Part.Paginated) +
\ 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 5b6b16cdf..1e88747ef 100644 --- a/src/Orchard.Web/Core/Orchard.Core.csproj +++ b/src/Orchard.Web/Core/Orchard.Core.csproj @@ -89,6 +89,8 @@ + +