Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Display Header" property to ListPartSettings #12525

Merged
merged 18 commits into from
Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

<h1 class="fs-5">@Model.ContentItem</h1>
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.Display.ContentDisplay;
using OrchardCore.ContentManagement.Metadata;
using OrchardCore.ContentManagement.Metadata.Models;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Views;
using OrchardCore.Lists.Models;
using OrchardCore.Lists.Services;
using OrchardCore.Lists.ViewModels;
using YesSql;

namespace OrchardCore.Lists.Drivers
{
public class ContainedPartDisplayDriver : ContentDisplayDriver
{
private readonly IContentManager _contentManager;
private readonly ISession _session;
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IContainerService _containerService;

public ContainedPartDisplayDriver(
IContentManager contentManager,
ISession session,
IContentDefinitionManager contentDefinitionManager,
IContainerService containerService
)
{
_session = session;
_contentManager = contentManager;
_contentDefinitionManager = contentDefinitionManager;
_containerService = containerService;
}

Expand All @@ -33,13 +37,15 @@ public override async Task<IDisplayResult> EditAsync(ContentItem model, IUpdateM
// the query string contains a ListPart.ContainerId value, or when an
// existing content item has ContainedPart value. In both cases the hidden field
// needs to be rendered in the edit form to maintain the relationship with the parent.
var containedPart = model.As<ContainedPart>();

if (model.As<ContainedPart>() != null)
if (containedPart != null)
{
return BuildViewModel(model.As<ContainedPart>().ListContentItemId, model.ContentType);
return BuildViewModel(containedPart.ListContentItemId, containedPart.ListContentType, model.ContentType);
}

var viewModel = new EditContainedPartViewModel();

if (await updater.TryUpdateModelAsync(viewModel, nameof(ListPart)) && viewModel.ContainerId != null && viewModel.ContentType == model.ContentType)
{
// We are creating a content item that needs to be added to a container
Expand All @@ -48,23 +54,12 @@ public override async Task<IDisplayResult> EditAsync(ContentItem model, IUpdateM
// The content type must be included to prevent any contained items,
// such as widgets, from also having a ContainedPart shape built for them.

return BuildViewModel(viewModel.ContainerId, model.ContentType, viewModel.EnableOrdering);
return BuildViewModel(viewModel.ContainerId, viewModel.ContainerContentType, model.ContentType, viewModel.EnableOrdering);
}

return null;
}

private IDisplayResult BuildViewModel(string containerId, string contentType, bool enableOrdering = false)
{
return Initialize<EditContainedPartViewModel>("ListPart_ContainerId", m =>
{
m.ContainerId = containerId;
m.EnableOrdering = enableOrdering;
m.ContentType = contentType;
})
.Location("Content");
}

public override async Task<IDisplayResult> UpdateAsync(ContentItem model, IUpdateModel updater)
{
var viewModel = new EditContainedPartViewModel();
Expand All @@ -73,7 +68,12 @@ public override async Task<IDisplayResult> UpdateAsync(ContentItem model, IUpdat
// in order for the ContainedPart to be included on the Content Item.
if (await updater.TryUpdateModelAsync(viewModel, nameof(ListPart)) && viewModel.ContainerId != null && viewModel.ContentType == model.ContentType)
{
model.Alter<ContainedPart>(x => x.ListContentItemId = viewModel.ContainerId);
model.Alter<ContainedPart>(x =>
{
x.ListContentItemId = viewModel.ContainerId;
x.ListContentType = viewModel.ContainerContentType;
});

// If creating get next order number so item is added to the end of the list
if (viewModel.EnableOrdering)
{
Expand All @@ -84,5 +84,78 @@ public override async Task<IDisplayResult> UpdateAsync(ContentItem model, IUpdat

return await EditAsync(model, updater);
}

private IDisplayResult BuildViewModel(string containerId, string containerContentType, string contentType, bool enableOrdering = false)
{
var results = new List<IDisplayResult>()
{
Initialize<EditContainedPartViewModel>("ListPart_ContainerId", m =>
{
m.ContainerId = containerId;
m.ContainerContentType = containerContentType;
m.EnableOrdering = enableOrdering;
m.ContentType = contentType;
})
.Location("Content")
};

if (!String.IsNullOrEmpty(containerContentType))
{
var definition = _contentDefinitionManager.GetTypeDefinition(containerContentType);

if (definition != null)
{
var listPart = definition.Parts.FirstOrDefault(x => x.PartDefinition.Name == nameof(ListPart));
var settings = listPart?.GetSettings<ListPartSettings>();

if (settings != null)
{
// Add list part navigation
results.Add(Initialize<ListPartNavigationViewModel>("ListPartNavigation", async model =>
{
model.ContainedContentTypeDefinitions = GetContainedContentTypes(settings).ToArray();
model.Container = await _contentManager.GetAsync(containerId);
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
model.EnableOrdering = settings.EnableOrdering;
model.ContainerContentTypeDefinition = definition;
}).Location("Content:1.5"));

if (settings.ShowHeader)
{
results.Add(GetListPartHeader(containerId, settings));
}
}
}
}

return Combine(results);
}

private IDisplayResult GetListPartHeader(string containerId, ListPartSettings listPartSettings)
{
return Initialize<ListPartHeaderViewModel>("ListPartHeader", async model =>
{
var container = await _contentManager.GetAsync(containerId, VersionOptions.Published);
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved

if (container == null)
{
return;
}

model.ContainerContentItem = container;

if (listPartSettings != null)
{
model.ContainedContentTypeDefinitions = GetContainedContentTypes(listPartSettings).ToArray();
model.EnableOrdering = listPartSettings.EnableOrdering;
}
}).Location("Content:1");
}

private IEnumerable<ContentTypeDefinition> GetContainedContentTypes(ListPartSettings settings)
{
var contentTypes = settings.ContainedContentTypes ?? Enumerable.Empty<string>();

return contentTypes.Select(contentType => _contentDefinitionManager.GetTypeDefinition(contentType));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ IUpdateModelAccessor updateModelAccessor
_updateModelAccessor = updateModelAccessor;
}

public override IDisplayResult Edit(ListPart part, BuildPartEditorContext context)
{
return Initialize<ListPartNavigationViewModel>("ListPartNavigation", model =>
{
var settings = context.TypePartDefinition.GetSettings<ListPartSettings>();
model.Container = part.ContentItem;
model.ContainedContentTypeDefinitions = GetContainedContentTypes(settings).ToArray();
model.EnableOrdering = settings.EnableOrdering;
model.ContainerContentTypeDefinition = context.TypePartDefinition.ContentTypeDefinition;
})
.Location("Content:1.5")
.RenderWhen(() => Task.FromResult(!context.IsNew));
}

public override IDisplayResult Display(ListPart listPart, BuildPartDisplayContext context)
{
return
Expand All @@ -47,7 +61,7 @@ public override IDisplayResult Display(ListPart listPart, BuildPartDisplayContex
pager,
containedItemOptions)).ToArray();

model.ContainedContentTypeDefinitions = GetContainedContentTypes(context);
model.ContainedContentTypeDefinitions = GetContainedContentTypes(settings);
model.Context = context;
model.Pager = await context.New.PagerSlim(pager);
})
Expand All @@ -71,18 +85,27 @@ public override IDisplayResult Display(ListPart listPart, BuildPartDisplayContex
pager,
containedItemOptions)).ToArray();

model.ContainedContentTypeDefinitions = GetContainedContentTypes(context);
model.ContainedContentTypeDefinitions = GetContainedContentTypes(settings);
model.Context = context;
model.EnableOrdering = settings.EnableOrdering;
model.Pager = await context.New.PagerSlim(pager);
})
.Location("DetailAdmin", "Content:10"),
Initialize<ListPartNavigationViewModel>("ListPartNavigation", model =>
{
var settings = context.TypePartDefinition.GetSettings<ListPartSettings>();
model.ContainedContentTypeDefinitions = GetContainedContentTypes(settings).ToArray();
model.Container = listPart.ContentItem;
model.EnableOrdering = settings.EnableOrdering;
model.ContainerContentTypeDefinition = context.TypePartDefinition.ContentTypeDefinition;
})
.Location("DetailAdmin", "Content:1.5"),
Initialize<ContentItemViewModel>("ListPartSummaryAdmin", model => model.ContentItem = listPart.ContentItem)
.Location("SummaryAdmin", "Actions:4")
);
}

private async Task<PagerSlim> GetPagerSlimAsync(BuildPartDisplayContext context)
private static async Task<PagerSlim> GetPagerSlimAsync(BuildPartDisplayContext context)
{
var settings = context.TypePartDefinition.GetSettings<ListPartSettings>();
var pagerParameters = new PagerSlimParameters();
Expand All @@ -93,10 +116,10 @@ private async Task<PagerSlim> GetPagerSlimAsync(BuildPartDisplayContext context)
return pager;
}

private IEnumerable<ContentTypeDefinition> GetContainedContentTypes(BuildPartDisplayContext context)
private IEnumerable<ContentTypeDefinition> GetContainedContentTypes(ListPartSettings settings)
{
var settings = context.TypePartDefinition.GetSettings<ListPartSettings>();
var contentTypes = settings.ContainedContentTypes ?? Enumerable.Empty<string>();

return contentTypes.Select(contentType => _contentDefinitionManager.GetTypeDefinition(contentType));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using OrchardCore.ContentManagement.Display.ContentDisplay;
using OrchardCore.ContentManagement.Display.Models;
using OrchardCore.ContentManagement.Metadata;
using OrchardCore.ContentManagement.Metadata.Models;
using OrchardCore.DisplayManagement.Views;
using OrchardCore.Lists.Models;
using OrchardCore.Lists.ViewModels;

namespace OrchardCore.Lists.Drivers;

public class ListPartHeaderDisplayDriver : ContentPartDisplayDriver<ListPart>
{
private readonly IContentDefinitionManager _contentDefinitionManager;

public ListPartHeaderDisplayDriver(IContentDefinitionManager contentDefinitionManager)
{
_contentDefinitionManager = contentDefinitionManager;
}

public override IDisplayResult Display(ListPart part, BuildPartDisplayContext context)
{
var settings = context.TypePartDefinition.GetSettings<ListPartSettings>();

return Initialize<ListPartHeaderViewModel>("ListPartHeader", model =>
{
model.ContainerContentItem = part.ContentItem;
model.ContainedContentTypeDefinitions = GetContainedContentTypes(settings).ToArray();
model.EnableOrdering = settings.EnableOrdering;
}).Location("DetailAdmin", "Content:1")
.RenderWhen(() => Task.FromResult(settings.ShowHeader));
}

public override IDisplayResult Edit(ListPart part, BuildPartEditorContext context)
{
var settings = context.TypePartDefinition.GetSettings<ListPartSettings>();

return Initialize<ListPartHeaderViewModel>("ListPartHeader", model =>
{
model.ContainerContentItem = part.ContentItem;
model.ContainedContentTypeDefinitions = GetContainedContentTypes(settings).ToArray();
model.EnableOrdering = settings.EnableOrdering;
}).Location("Content:1")
.RenderWhen(() => Task.FromResult(!context.IsNew && settings.ShowHeader));
}

private IEnumerable<ContentTypeDefinition> GetContainedContentTypes(ListPartSettings settings)
{
var contentTypes = settings.ContainedContentTypes ?? Enumerable.Empty<string>();

return contentTypes.Select(contentType => _contentDefinitionManager.GetTypeDefinition(contentType));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public class ContainedPart : ContentPart
/// </summary>
public string ListContentItemId { get; set; }

/// <summary>
/// The content type of the list owning this content item.
/// </summary>
public string ListContentType { get; set; }
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// The order of this content item in the list.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ public class ListPartSettings
public int PageSize { get; set; } = 10;
public string[] ContainedContentTypes { get; set; }
public bool EnableOrdering { get; set; }
public bool ShowHeader { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public override IDisplayResult Edit(ContentTypePartDefinition contentTypePartDef
model.PageSize = model.ListPartSettings.PageSize;
model.EnableOrdering = model.ListPartSettings.EnableOrdering;
model.ContainedContentTypes = model.ListPartSettings.ContainedContentTypes;
model.ShowHeader = model.ListPartSettings.ShowHeader;
model.ContentTypes = new NameValueCollection();

foreach (var contentTypeDefinition in _contentDefinitionManager.ListTypeDefinitions())
Expand All @@ -51,7 +52,7 @@ public override async Task<IDisplayResult> UpdateAsync(ContentTypePartDefinition

var model = new ListPartSettingsViewModel();

await context.Updater.TryUpdateModelAsync(model, Prefix, m => m.ContainedContentTypes, m => m.PageSize, m => m.EnableOrdering);
await context.Updater.TryUpdateModelAsync(model, Prefix, m => m.ContainedContentTypes, m => m.PageSize, m => m.EnableOrdering, m => m.ShowHeader);

if (model.ContainedContentTypes == null || model.ContainedContentTypes.Length == 0)
{
Expand All @@ -63,7 +64,8 @@ public override async Task<IDisplayResult> UpdateAsync(ContentTypePartDefinition
{
PageSize = model.PageSize,
EnableOrdering = model.EnableOrdering,
ContainedContentTypes = model.ContainedContentTypes
ContainedContentTypes = model.ContainedContentTypes,
ShowHeader = model.ShowHeader,
});

// Update order of existing content if enable ordering has been turned on
Expand Down
1 change: 1 addition & 0 deletions src/OrchardCore.Modules/OrchardCore.Lists/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public override void ConfigureServices(IServiceCollection services)
// List Part
services.AddContentPart<ListPart>()
.UseDisplayDriver<ListPartDisplayDriver>()
.UseDisplayDriver<ListPartHeaderDisplayDriver>()
.AddHandler<ListPartHandler>();

services.AddScoped<IContentTypePartDefinitionDisplayDriver, ListPartSettingsDisplayDriver>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace OrchardCore.Lists.ViewModels
public class EditContainedPartViewModel
{
public string ContainerId { get; set; }
public string ContainerContentType { get; set; }
public string ContentType { get; set; }
public bool EnableOrdering { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.Metadata.Models;

namespace OrchardCore.Lists.ViewModels;

public class ListPartHeaderViewModel
{
public ContentItem ContainerContentItem { get; set; }

public ContentTypeDefinition[] ContainedContentTypeDefinitions { get; set; } = Array.Empty<ContentTypeDefinition>();

public bool EnableOrdering { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.Metadata.Models;

namespace OrchardCore.Lists.ViewModels;

public class ListPartNavigationViewModel
{
public ContentItem Container { get; set; }

public ContentTypeDefinition ContainerContentTypeDefinition { get; set; }

public bool EnableOrdering { get; set; }

public ContentTypeDefinition[] ContainedContentTypeDefinitions { get; set; } = Array.Empty<ContentTypeDefinition>();
}
Loading