Skip to content

Commit

Permalink
Layers enhancements (#17111)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeAlhayek authored Dec 3, 2024
1 parent 69762e2 commit 80d8d24
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ private async Task<IEnumerable<ContentTypeDefinition>> GetContainedContentTypesA

if (settings?.ContainedContentTypes == null || settings.ContainedContentTypes.Length == 0)
{
return (await _contentDefinitionManager.ListTypeDefinitionsAsync()).Where(t => t.StereotypeEquals("Widget"));
return await _contentDefinitionManager.ListWidgetTypeDefinitionsAsync();
}

var definitions = new List<ContentTypeDefinition>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,10 @@ private async Task<IEnumerable<ContentTypeDefinition>> GetContainedContentTypesA

if (settings?.ContainedContentTypes == null || settings.ContainedContentTypes.Length == 0)
{
return (await _contentDefinitionManager.ListTypeDefinitionsAsync())
.Where(t => t.StereotypeEquals("Widget"));
return await _contentDefinitionManager.ListWidgetTypeDefinitionsAsync();
}

return (await _contentDefinitionManager.ListTypeDefinitionsAsync())
.Where(t => settings.ContainedContentTypes.Contains(t.Name) && t.StereotypeEquals("Widget"));
return (await _contentDefinitionManager.ListWidgetTypeDefinitionsAsync())
.Where(t => settings.ContainedContentTypes.Contains(t.Name));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public async Task<IActionResult> CreatePost(LayerEditViewModel model)

await _layerService.UpdateAsync(layers);

return RedirectToAction(nameof(Index));
return RedirectToAction(nameof(Edit), new { name = layer.Name, });
}

return View(model);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Localization;
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.Display.ContentDisplay;
Expand All @@ -10,53 +11,58 @@

namespace OrchardCore.Layers.Drivers;

public class LayerMetadataWelder : ContentDisplayDriver
public sealed class LayerMetadataWelder : ContentDisplayDriver
{
private readonly ILayerService _layerService;
protected readonly IStringLocalizer S;

public LayerMetadataWelder(ILayerService layerService, IStringLocalizer<LayerMetadataWelder> stringLocalizer)
internal readonly IStringLocalizer S;

public LayerMetadataWelder(
ILayerService layerService,
IStringLocalizer<LayerMetadataWelder> stringLocalizer)
{
_layerService = layerService;
S = stringLocalizer;
}

protected override void BuildPrefix(ContentItem model, string htmlFieldPrefix)
{
base.BuildPrefix(model, htmlFieldPrefix);
if (string.IsNullOrWhiteSpace(htmlFieldPrefix))
{
Prefix = "LayerMetadata";
}
}

public override async Task<IDisplayResult> EditAsync(ContentItem model, BuildEditorContext context)
{
var layerMetadata = model.As<LayerMetadata>();

if (layerMetadata == null)
if (!model.TryGet<LayerMetadata>(out var layerMetadata))
{
layerMetadata = new LayerMetadata();
await context.Updater.TryUpdateModelAsync(layerMetadata, Prefix, m => m.Zone, m => m.Position);

// Are we loading an editor that requires layer metadata?
if (!string.IsNullOrEmpty(layerMetadata.Zone))
{
model.Weld(layerMetadata);
}
else
// In the initial request, the 'Zone' and 'Position' are passed as route values.
// We attempt to populate the new 'LayerMetadata' and ensure the 'Zone' is correctly set.
await context.Updater.TryUpdateModelAsync(layerMetadata, string.Empty, m => m.Zone, m => m.Position);

if (string.IsNullOrEmpty(layerMetadata.Zone))
{
// At this point, the 'Zone' value was not provided in the route values, so the widget is not visible.
return null;
}

model.Weld(layerMetadata);
}

return Initialize<LayerMetadataEditViewModel>("LayerMetadata_Edit", async shape =>
return Initialize<LayerMetadataEditViewModel>("LayerMetadata_Edit", async m =>
{
shape.Title = model.DisplayText;
shape.LayerMetadata = layerMetadata;
shape.Layers = (await _layerService.GetLayersAsync()).Layers;
})
.Location("Content:before");
m.Title = model.DisplayText;
m.RenderTitle = layerMetadata.RenderTitle;
m.Position = layerMetadata.Position;
m.Zone = layerMetadata.Zone;
m.Layer = layerMetadata.Layer;
m.Layers = (await _layerService.GetLayersAsync()).Layers
.Select(x => new SelectListItem(x.Name, x.Name));
}).Location("Content:before");
}

protected override void BuildPrefix(ContentItem model, string htmlFieldPrefix)
{
base.BuildPrefix(model, htmlFieldPrefix);
if (string.IsNullOrWhiteSpace(htmlFieldPrefix))
{
Prefix = nameof(LayerMetadata);
}
}

public override async Task<IDisplayResult> UpdateAsync(ContentItem model, UpdateEditorContext context)
Expand All @@ -65,26 +71,38 @@ public override async Task<IDisplayResult> UpdateAsync(ContentItem model, Update

await context.Updater.TryUpdateModelAsync(viewModel, Prefix);

if (viewModel.LayerMetadata == null)
if (string.IsNullOrEmpty(viewModel.Title))
{
return null;
context.Updater.ModelState.AddModelError(Prefix, nameof(viewModel.Title), S["The Title field is required"]);
}

if (string.IsNullOrEmpty(viewModel.LayerMetadata.Zone))
if (string.IsNullOrEmpty(viewModel.Zone))
{
context.Updater.ModelState.AddModelError(Prefix, "LayerMetadata.Zone", S["Zone is missing"]);
context.Updater.ModelState.AddModelError(Prefix, nameof(viewModel.Zone), S["The Zone field is required"]);
}

if (string.IsNullOrEmpty(viewModel.LayerMetadata.Layer))
if (string.IsNullOrEmpty(viewModel.Layer))
{
context.Updater.ModelState.AddModelError(Prefix, "LayerMetadata.Layer", S["Layer is missing"]);
context.Updater.ModelState.AddModelError(Prefix, nameof(viewModel.Layer), S["The Layer field is required"]);
}

if (context.Updater.ModelState.IsValid)
else
{
model.Apply(viewModel.LayerMetadata);
var document = await _layerService.GetLayersAsync();

if (!document.Layers.Any(x => x.Name == viewModel.Layer))
{
context.Updater.ModelState.AddModelError(Prefix, nameof(viewModel.Layer), S["Invalid Layer value provided"]);
}
}

model.Apply(new LayerMetadata
{
RenderTitle = viewModel.RenderTitle,
Zone = viewModel.Zone,
Position = viewModel.Position,
Layer = viewModel.Layer,
});

model.DisplayText = viewModel.Title;

return await EditAsync(model, context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ namespace OrchardCore.Layers.Models;
public class LayerMetadata : ContentPart
{
public bool RenderTitle { get; set; }

public double Position { get; set; }

public string Zone { get; set; }

public string Layer { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
using OrchardCore.Layers.Models;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace OrchardCore.Layers.ViewModels;

public class LayerMetadataEditViewModel
{
public string Title { get; set; }
public LayerMetadata LayerMetadata { get; set; }
public List<Layer> Layers { get; set; }

public bool RenderTitle { get; set; }

public double Position { get; set; }

public string Zone { get; set; }

public string Layer { get; set; }

[BindNever]
public IEnumerable<SelectListItem> Layers { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
@using OrchardCore.ContentManagement.Metadata.Settings
@using OrchardCore.Layers.Drivers
@using OrchardCore.ContentManagement.Metadata.Models
@using OrchardCore.ContentManagement.Metadata
@model OrchardCore.Layers.ViewModels.LayersIndexViewModel

@inject IContentManager ContentManager
@inject OrchardCore.ContentManagement.Metadata.IContentDefinitionManager ContentDefinitionManager
@inject IContentDefinitionManager ContentDefinitionManager
@inject OrchardCore.ContentManagement.Display.IContentItemDisplayManager ContentItemDisplayManager

<script asp-name="jquery-ui" at="Foot"></script>
Expand Down Expand Up @@ -66,11 +67,9 @@

@if (Model.Layers.Count > 0)
{
var widgetContentTypes = (await ContentDefinitionManager.ListTypeDefinitionsAsync())
.Where(t => t.StereotypeEquals("Widget"))
.ToList();
var widgetContentTypes = await ContentDefinitionManager.ListWidgetTypeDefinitionsAsync();

if (widgetContentTypes.Count > 0)
if (widgetContentTypes.Any())
{
var htmlId = Guid.NewGuid().ToString("n");

Expand All @@ -84,8 +83,8 @@
var contentItem = await ContentManager.NewAsync(type.Name);
var createRoute = (await ContentManager.PopulateAspectAsync<ContentItemMetadata>(contentItem)).CreateRouteValues;
createRoute["returnUrl"] = Context.Request.PathBase + Context.Request.Path;
createRoute["LayerMetadata.Zone"] = zone;
createRoute["LayerMetadata.Position"] = maxPosition + 1;
createRoute["Zone"] = zone;
createRoute["Position"] = maxPosition + 1;
<li>
<a class="dropdown-item add-list-widget"
data-widget-type="@type.Name"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,23 @@
<div class="@Orchard.GetWrapperClasses()">
<div class="@Orchard.GetEndClasses(true)">
<div class="form-check">
<input type="checkbox" class="form-check-input" asp-for="LayerMetadata.RenderTitle" checked="@Model.LayerMetadata.RenderTitle">
<label class="form-check-label" asp-for="LayerMetadata.RenderTitle">@T["Render title"]</label>
<input type="checkbox" class="form-check-input" asp-for="RenderTitle">
<label class="form-check-label" asp-for="RenderTitle">@T["Render title"]</label>
<span class="hint dashed">@T["If checked, the title will be rendered with the widget."]</span>
</div>
</div>
</div>

<div class="@Orchard.GetWrapperClasses()" asp-validation-class-for="LayerMetadata.Layer">
<label asp-for="LayerMetadata.Layer" class="@Orchard.GetLabelClasses()">@T["The layer the widget should be associated with."]</label>
<div class="@Orchard.GetWrapperClasses()" asp-validation-class-for="Layer">
<label asp-for="Layer" class="@Orchard.GetLabelClasses()">@T["The layer"]</label>
<div class="@Orchard.GetEndClasses()">
<select asp-for="LayerMetadata.Layer" class="form-select">
@foreach (var layer in Model.Layers)
{
<option value="@layer.Name" selected="@(Model.LayerMetadata.Layer == layer.Name)">@layer.Name</option>
}
<select asp-for="Layer" asp-items="Model.Layers" class="form-select">
<option value="">@T["Select a layer"]</option>
</select>
<span asp-validation-for="LayerMetadata.Layer" class="text-danger"></span>
<span asp-validation-for="Layer" class="text-danger"></span>
<span class="hint">@T["The layer controls the visibility of this widget."]</span>
</div>
</div>

<input asp-for="LayerMetadata.Zone" type="hidden" />
<input asp-for="LayerMetadata.Position" type="hidden" />
<input asp-for="Zone" type="hidden" />
<input asp-for="Position" type="hidden" />
Original file line number Diff line number Diff line change
Expand Up @@ -1100,7 +1100,7 @@
{
"ContentItemId": "[js: uuid()]",
"ContentType": "RawHtml",
"Displaytext": "Footer",
"DisplayText": "Footer",
"Latest": true,
"Published": true,
"Owner": "[js: parameters('AdminUserId')]",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,11 @@ await manager.AlterPartDefinitionAsync(partDefinition.Name, partBuilder =>
});
}
}

public static async Task<IEnumerable<ContentTypeDefinition>> ListWidgetTypeDefinitionsAsync(this IContentDefinitionManager manager)
{
var types = await manager.ListTypeDefinitionsAsync();

return types.Where(x => x.StereotypeEquals("Widget"));
}
}

0 comments on commit 80d8d24

Please sign in to comment.