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 ContainedStereotypes BagPartSettings to allow a user to include content-types by steryotype #11978

Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,19 @@ private static bool IsSecurable(IContentDefinitionManager contentDefinitionManag
private async Task<IEnumerable<ContentTypeDefinition>> GetContainedContentTypesAsync(IContentDefinitionManager contentDefinitionManager, ContentTypePartDefinition typePartDefinition)
{
var settings = typePartDefinition.GetSettings<BagPartSettings>();
var contentTypes = Enumerable.Empty<ContentTypeDefinition>();

var contentTypes = settings.ContainedContentTypes
.Select(contentType => _contentDefinitionManager.GetTypeDefinition(contentType))
.Where(contentType => contentType != null);
if (settings.ContainedStereotypes != null && settings.ContainedStereotypes.Length > 0)
{
contentTypes = _contentDefinitionManager.ListTypeDefinitions()
.Where(contentType => contentType.HasStereotype() && settings.ContainedStereotypes.Contains(contentType.GetStereotypeOrDefault(), StringComparer.OrdinalIgnoreCase));
}
else if (settings.ContainedContentTypes != null && settings.ContainedContentTypes.Length > 0)
{
contentTypes = settings.ContainedContentTypes
.Select(contentType => _contentDefinitionManager.GetTypeDefinition(contentType))
.Where(contentType => contentType != null);
}

var accessibleContentTypes = new List<ContentTypeDefinition>();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace OrchardCore.Flows.Models;

public enum BagPartSettingType
{
None,
ContentTypes,
Stereotypes
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ namespace OrchardCore.Flows.Models
public class BagPartSettings
{
public string[] ContainedContentTypes { get; set; } = Array.Empty<string>();

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

public string DisplayType { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Specialized;
using System.Threading.Tasks;
using Microsoft.Extensions.Localization;
Expand All @@ -8,6 +9,7 @@
using OrchardCore.DisplayManagement.Views;
using OrchardCore.Flows.Models;
using OrchardCore.Flows.ViewModels;
using OrchardCore.Mvc.ModelBinding;

namespace OrchardCore.Flows.Settings
{
Expand All @@ -28,11 +30,14 @@ public override IDisplayResult Edit(ContentTypePartDefinition contentTypePartDef
{
return Initialize<BagPartSettingsViewModel>("BagPartSettings_Edit", model =>
{
model.BagPartSettings = contentTypePartDefinition.GetSettings<BagPartSettings>();
var settings = contentTypePartDefinition.GetSettings<BagPartSettings>();

model.BagPartSettings = settings;
model.ContainedContentTypes = model.BagPartSettings.ContainedContentTypes;
model.DisplayType = model.BagPartSettings.DisplayType;
model.ContentTypes = new NameValueCollection();

model.Source = settings.ContainedStereotypes != null && settings.ContainedStereotypes.Length > 0 ? BagPartSettingType.Stereotypes : BagPartSettingType.ContentTypes;
model.Stereotypes = String.Join(',', settings.ContainedStereotypes ?? Array.Empty<string>());
foreach (var contentTypeDefinition in _contentDefinitionManager.ListTypeDefinitions())
{
model.ContentTypes.Add(contentTypeDefinition.Name, contentTypeDefinition.DisplayName);
Expand All @@ -44,22 +49,56 @@ public override async Task<IDisplayResult> UpdateAsync(ContentTypePartDefinition
{
var model = new BagPartSettingsViewModel();

await context.Updater.TryUpdateModelAsync(model, Prefix, m => m.ContainedContentTypes, m => m.DisplayType);
await context.Updater.TryUpdateModelAsync(model, Prefix, m => m.ContainedContentTypes, m => m.DisplayType, m => m.Source, m => m.Stereotypes);

if (model.ContainedContentTypes == null || model.ContainedContentTypes.Length == 0)
switch (model.Source)
{
context.Updater.ModelState.AddModelError(nameof(model.ContainedContentTypes), S["At least one content type must be selected."]);
case BagPartSettingType.ContentTypes:
SetContentTypes(context, model);
break;
case BagPartSettingType.Stereotypes:
SetStereoTypes(context, model);
break;
default:
context.Updater.ModelState.AddModelError(Prefix, nameof(model.Source), S["Content type source must be set with a valid value."]);
break;
}
else

return Edit(contentTypePartDefinition, context.Updater);
}

private void SetStereoTypes(UpdateTypePartEditorContext context, BagPartSettingsViewModel model)
{
if (String.IsNullOrEmpty(model.Stereotypes))
{
context.Builder.WithSettings(new BagPartSettings
{
ContainedContentTypes = model.ContainedContentTypes,
DisplayType = model.DisplayType
});
context.Updater.ModelState.AddModelError(Prefix, nameof(model.Stereotypes), S["Please provide a Stereotype."]);

return;
}

return Edit(contentTypePartDefinition, context.Updater);
context.Builder.WithSettings(new BagPartSettings
{
ContainedContentTypes = Array.Empty<string>(),
ContainedStereotypes = model.Stereotypes.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries),
DisplayType = model.DisplayType
});
}

private void SetContentTypes(UpdateTypePartEditorContext context, BagPartSettingsViewModel model)
{
if (model.ContainedContentTypes == null || model.ContainedContentTypes.Length == 0)
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
{
context.Updater.ModelState.AddModelError(Prefix, nameof(model.ContainedContentTypes), S["At least one content type must be selected."]);

return;
}

context.Builder.WithSettings(new BagPartSettings
{
ContainedContentTypes = model.ContainedContentTypes,
ContainedStereotypes = Array.Empty<string>(),
DisplayType = model.DisplayType
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ public class BagPartSettingsViewModel
public NameValueCollection ContentTypes { get; set; }
public string DisplayType { get; set; }
public string[] ContainedContentTypes { get; set; } = Array.Empty<string>();
public BagPartSettingType Source { get; set; }
public string Stereotypes { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,66 @@
@model OrchardCore.Flows.ViewModels.BagPartSettingsViewModel

@using OrchardCore.Flows.Settings
@using OrchardCore.Flows.Models
<div class="mb-3">
<label asp-for="Source">@T["Contained Content Types"]</label>
<div class="w-sm-50" id="@Html.IdFor(x => x.Source)">
<div class="form-check">
<input class="form-check-input" type="radio" asp-for="Source" id="SourceContentTypes" value="@(BagPartSettingType.ContentTypes)" checked="@(Model.Source == BagPartSettingType.ContentTypes))">
<label for="SourceContentTypes">
@T["Content Types"]
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" asp-for="Source" id="SourceStereotype" value="@(BagPartSettingType.Stereotypes)" checked="@(Model.Source == BagPartSettingType.Stereotypes)">
<label for="SourceStereotype">
@T["Stereotype"] <span class="hint">@T["All content types of these Stereotypes"]</span>
</label>
</div>
</div>
</div>

<div class="mb-3" id="ContentTypesContainer">
<label asp-for="ContainedContentTypes">@T["Contained Content Types"]</label>
<span class="hint">@T["The content types that this bag can contain, e.g. Slide for a Slide Show."]</span>
@await Component.InvokeAsync("SelectContentTypes", new { selectedContentTypes = Model.ContainedContentTypes, htmlName = Html.NameFor(m => m.ContainedContentTypes) })
</div>

<div class="mb-3" id="StereotypesContainer">
<div class="w-sm-50" id="@Html.IdFor(x => x.Source)">
<label asp-for="Stereotypes">@T["Stereotypes"]</label>
<input asp-for="Stereotypes" class="form-control medium" />
<span class="hint">@T["The Stereotypes of the content types that this bag can contain. You may define multiple Stereotypes using the comma (,) as a separator"]</span>
</div>
</div>
<div class="mb-3">
<div class="w-sm-50">
<label asp-for="DisplayType">@T["Display Type"]</label>
<input asp-for="DisplayType" placeholder="Summary" class="form-control medium" />
</div>
<span class="hint">@T["The display type to use when rendering the content items. Default is Summary."]</span>
</div>

<script at="Foot" asp-name="bagPartSettings">
document.addEventListener('DOMContentLoaded', function() {
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
var sources = document.getElementsByName('@Html.NameFor(x => x.Source)');
var contentTypesContainer = document.getElementById('ContentTypesContainer');
var stereotypeContainer = document.getElementById('StereotypesContainer');

for (var i = 0; i < sources.length; i++) {
var source = sources[i];
source.addEventListener('change', function(src) {
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
if (!src.target.checked) {
return;
}
if (src.target.value == '@(BagPartSettingType.Stereotypes)') {
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
contentTypesContainer.classList.add('d-none');
stereotypeContainer.classList.remove('d-none');
} else {
contentTypesContainer.classList.remove('d-none');
stereotypeContainer.classList.add('d-none');
}
});
source.dispatchEvent(new Event('change'));
}
});
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using OrchardCore.ContentManagement.Metadata.Settings;

namespace OrchardCore.ContentManagement.Metadata.Models;

public static class ContentTypeExtensions
{
public static bool HasStereotype(this ContentTypeDefinition contentTypeDefinition)
{
return !String.IsNullOrEmpty(contentTypeDefinition.GetStereotypeOrDefault());
}

public static string GetStereotypeOrDefault(this ContentTypeDefinition contentTypeDefinition)
{
return contentTypeDefinition.GetSettings().Stereotype;
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
}

public static bool IsListable(this ContentTypeDefinition contentTypeDefinition)
hishamco marked this conversation as resolved.
Show resolved Hide resolved
{
return contentTypeDefinition.GetSettings().Listable;
}

public static bool IsCreatable(this ContentTypeDefinition contentTypeDefinition)
{
return contentTypeDefinition.GetSettings().Creatable;
}

public static bool IsDraftable(this ContentTypeDefinition contentTypeDefinition)
{
return contentTypeDefinition.GetSettings().Draftable;
}

public static bool IsVersionable(this ContentTypeDefinition contentTypeDefinition)
{
return contentTypeDefinition.GetSettings().Versionable;
}

public static bool IsSecurable(this ContentTypeDefinition contentTypeDefinition)
{
return contentTypeDefinition.GetSettings().Securable;
}

public static bool HasDescription(this ContentTypeDefinition contentTypeDefinition)
{
return !String.IsNullOrEmpty(contentTypeDefinition.GetSettings().Description);
}

public static string GetDescription(this ContentTypeDefinition contentTypeDefinition)
{
return contentTypeDefinition.GetSettings().Description;
}

public static ContentTypeSettings GetSettings(this ContentTypeDefinition contentTypeDefinition)
{
return contentTypeDefinition.GetSettings<ContentTypeSettings>();
}
}