diff --git a/.gitignore b/.gitignore index 6aaa7e81..7389491d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ node_modules/ *.user .pnpm-debug.log .editorconfig +*.orig diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/ConditionDisplayDriver.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/ConditionDisplayDriver.cs new file mode 100644 index 00000000..2143a528 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/ConditionDisplayDriver.cs @@ -0,0 +1,31 @@ +using Lombiq.HelpfulExtensions.Extensions.Widgets.ViewModels; +using Lombiq.HelpfulLibraries.OrchardCore.Contents; +using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.DisplayManagement.Views; +using OrchardCore.Rules; +using System.Collections.Generic; + +namespace Lombiq.HelpfulExtensions.Extensions.Widgets.Drivers; + +public abstract class ConditionDisplayDriver : DisplayDriver + where TCondition : Condition +{ + public override IDisplayResult Display(TCondition model) => + Combine( + InitializeDisplayType(CommonContentDisplayTypes.Summary, model), + InitializeDisplayType(CommonContentDisplayTypes.Thumbnail, model)); + + public override IDisplayResult Edit(TCondition model) => + Combine( + InitializeDisplayType(CommonContentDisplayTypes.Detail, model, "Title"), + GetEditor(model)); + + protected abstract ConditionViewModel GetConditionViewModel(TCondition condition); + protected abstract IDisplayResult GetEditor(TCondition model); + + private ShapeResult InitializeDisplayType(string displayType, TCondition model, string shapeTypeSuffix = null) => + Initialize( + string.Join('_', new[] { "Condition", "Fields", displayType, shapeTypeSuffix }.WhereNot(string.IsNullOrEmpty)), + target => GetConditionViewModel(model).CopyTo(target)) + .Location(displayType, CommonLocationNames.Content); +} diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionDisplayDriver.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionDisplayDriver.cs new file mode 100644 index 00000000..54df6e64 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionDisplayDriver.cs @@ -0,0 +1,90 @@ +using Lombiq.HelpfulExtensions.Extensions.Widgets.Models; +using Lombiq.HelpfulExtensions.Extensions.Widgets.ViewModels; +using Microsoft.AspNetCore.Html; +using Microsoft.AspNetCore.Mvc.Localization; +using Microsoft.Extensions.Localization; +using Newtonsoft.Json; +using OrchardCore.DisplayManagement.ModelBinding; +using OrchardCore.DisplayManagement.Views; +using System.Linq; +using System.Threading.Tasks; + +namespace Lombiq.HelpfulExtensions.Extensions.Widgets.Drivers; + +public class MvcConditionDisplayDriver : ConditionDisplayDriver +{ + private readonly IHtmlLocalizer H; + private readonly IStringLocalizer T; + public MvcConditionDisplayDriver( + IHtmlLocalizer htmlLocalizer, + IStringLocalizer stringLocalizer) + { + H = htmlLocalizer; + T = stringLocalizer; + } + + protected override IDisplayResult GetEditor(MvcCondition model) => + Initialize("MvcCondition_Fields_Edit", viewModel => + { + viewModel.Area = model.Area; + viewModel.Controller = model.Controller; + viewModel.Action = model.Action; + + foreach (var (key, value) in model.OtherRouteValues) + { + viewModel.OtherRouteNames.Add(key); + viewModel.OtherRouteValues.Add(value); + } + }).PlaceInContent(); + + public override async Task UpdateAsync(MvcCondition model, IUpdateModel updater) + { + var viewModel = new MvcConditionViewModel(); + if (await updater.TryUpdateModelAsync(viewModel, Prefix)) + { + if (viewModel.OtherRouteNames.Count != viewModel.OtherRouteValues.Count) + { + updater.ModelState.AddModelError( + nameof(viewModel.OtherRouteNames), + T["The count of other route value names didn't match the count of other route values."]); + } + + model.Area = viewModel.Area; + model.Controller = viewModel.Controller; + model.Action = viewModel.Action; + + model.OtherRouteValues.Clear(); + for (var i = 0; i < viewModel.OtherRouteNames.Count; i++) + { + model.OtherRouteValues[viewModel.OtherRouteNames[i]] = viewModel.OtherRouteValues[i]; + } + } + + return Edit(model); + } + + protected override ConditionViewModel GetConditionViewModel(MvcCondition condition) + { + IHtmlContentBuilder summaryHint = new HtmlContentBuilder(); + + static IHtmlContentBuilder AppendIfNotEmpty(IHtmlContentBuilder summaryHint, string value, IHtmlContent label) => + string.IsNullOrEmpty(value) ? summaryHint : summaryHint.AppendHtml(label).AppendHtml(" "); + + summaryHint = AppendIfNotEmpty(summaryHint, condition.Area, H["Area: \"{0}\"", condition.Area]); + summaryHint = AppendIfNotEmpty(summaryHint, condition.Controller, H["Controller: \"{0}\"", condition.Controller]); + summaryHint = AppendIfNotEmpty(summaryHint, condition.Action, H["Action: \"{0}\"", condition.Action]); + + if (condition.OtherRouteValues.Any()) + { + summaryHint = summaryHint.AppendHtml( + H["Other route values: {0}", JsonConvert.SerializeObject(condition.OtherRouteValues)]); + } + + return new ConditionViewModel + { + Title = H["MVC condition"], + Description = H["An MVC condition evaluates the currently route values such as controller and action name."], + SummaryHint = summaryHint, + }; + } +} diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionEvaluatorDriver.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionEvaluatorDriver.cs new file mode 100644 index 00000000..1eff2d27 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Drivers/MvcConditionEvaluatorDriver.cs @@ -0,0 +1,34 @@ +using Lombiq.HelpfulExtensions.Extensions.Widgets.Models; +using Microsoft.AspNetCore.Http; +using OrchardCore.ContentManagement.Display.ContentDisplay; +using OrchardCore.Rules; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace Lombiq.HelpfulExtensions.Extensions.Widgets.Drivers; + +public class MvcConditionEvaluatorDriver : ContentDisplayDriver, IConditionEvaluator +{ + private readonly IHttpContextAccessor _hca; + + public MvcConditionEvaluatorDriver(IHttpContextAccessor hca) => + _hca = hca; + + public ValueTask EvaluateAsync(Condition condition) => new(Evaluate((MvcCondition)condition)); + + private bool Evaluate(MvcCondition condition) => + MatchRouteValue("area", condition.Area) && + MatchRouteValue("controller", condition.Controller) && + MatchRouteValue("action", condition.Action) && + (!condition.OtherRouteValues.Any() || condition.OtherRouteValues.All(pair => MatchRouteValue(pair.Key, pair.Value))); + + private bool MatchRouteValue(string name, string value) + { + // Ignore this match operation if the target value is not set. + if (string.IsNullOrWhiteSpace(value)) return true; + + return _hca.HttpContext?.Request.RouteValues.TryGetValue(name, out var routeValue) == true && + value.EqualsOrdinalIgnoreCase(routeValue?.ToString()); + } +} diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Liquid/MenuWidgetLiquidFilter.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Liquid/MenuWidgetLiquidFilter.cs new file mode 100644 index 00000000..2cc0ac4a --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Liquid/MenuWidgetLiquidFilter.cs @@ -0,0 +1,133 @@ +using Fluid; +using Fluid.Values; +using Lombiq.HelpfulExtensions.Extensions.Widgets.ViewModels; +using Lombiq.HelpfulLibraries.OrchardCore.Liquid; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.Extensions.Localization; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OrchardCore.Liquid; +using OrchardCore.Navigation; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +namespace Lombiq.HelpfulExtensions.Extensions.Widgets.Liquid; + +public class MenuWidgetLiquidFilter : ILiquidFilter +{ + private readonly ILiquidContentDisplayService _liquidContentDisplayService; + private readonly Lazy _urlHelperLazy; + private readonly IStringLocalizer T; + + public MenuWidgetLiquidFilter( + IActionContextAccessor actionContextAccessor, + ILiquidContentDisplayService liquidContentDisplayService, + IStringLocalizer stringLocalizer, + IUrlHelperFactory urlHelperFactory) + { + _liquidContentDisplayService = liquidContentDisplayService; + + _urlHelperLazy = new Lazy(() => + urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext!)); + + T = stringLocalizer; + } + + public ValueTask ProcessAsync(FluidValue input, FilterArguments arguments, LiquidTemplateContext context) + { + bool noWrapper, localNav; + string classes; + noWrapper = arguments[nameof(noWrapper)].ToBooleanValue(); + localNav = arguments[nameof(localNav)].ToBooleanValue(); + classes = arguments[nameof(classes)].ToStringValue(); + + var converter = new LocalizedStringJsonConverter(T); + var serializer = new JsonSerializer(); + serializer.Converters.Add(converter); + var serializerSettings = new JsonSerializerSettings(); + serializerSettings.Converters.Add(converter); + + var menuItems = input?.Type switch + { + FluidValues.String => JsonConvert.DeserializeObject>( + input!.ToStringValue(), + serializerSettings), + FluidValues.Object => input!.ToObjectValue() switch + { + IEnumerable enumerable => enumerable.AsList(), + MenuItem single => new[] { single }, + JArray jArray => jArray.ToObject>(serializer), + JObject jObject => new[] { jObject.ToObject(serializer) }, + _ => null, + }, + _ => null, + }; + + UpdateMenuItems(menuItems, localNav); + + return _liquidContentDisplayService.DisplayNewAsync( + WidgetTypes.MenuWidget, + model => + { + model.NoWrapper = noWrapper; + model.MenuItems = menuItems ?? Array.Empty(); + model.HtmlClasses = classes; + }); + } + + private void UpdateMenuItems(IEnumerable menuItems, bool localNav) + { + if (menuItems == null) return; + + foreach (var item in menuItems) + { + if (!string.IsNullOrEmpty(item.Url)) + { + var finalUrl = _urlHelperLazy.Value.Content(item.Url); + item.Url = finalUrl; + item.Href = finalUrl; + } + + item.LocalNav = localNav || item.LocalNav; + + UpdateMenuItems(item.Items, localNav); + } + } + + public class LocalizedStringJsonConverter : JsonConverter + { + private readonly IStringLocalizer T; + + public LocalizedStringJsonConverter(IStringLocalizer stringLocalizer) => + T = stringLocalizer; + + public override void WriteJson(JsonWriter writer, LocalizedString value, JsonSerializer serializer) => + writer.WriteValue(value?.Value); + + [SuppressMessage("Style", "IDE0010:Add missing cases", Justification = "We don't want to handle other token types.")] + public override LocalizedString ReadJson( + JsonReader reader, + Type objectType, + LocalizedString existingValue, + bool hasExistingValue, + JsonSerializer serializer) + { + switch (reader.TokenType) + { + case JsonToken.String: + return JToken.ReadFrom(reader).ToObject() is { } text ? T[text] : null; + case JsonToken.StartObject: + var data = new Dictionary( + JToken.ReadFrom(reader).ToObject>(), + StringComparer.OrdinalIgnoreCase); + return new LocalizedString(data[nameof(LocalizedString.Name)], data[nameof(LocalizedString.Value)]); + default: + throw new InvalidOperationException("Unable to parse JSON!"); + } + } + } +} diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Migrations.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Migrations.cs index b7794824..9425ebee 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Widgets/Migrations.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Migrations.cs @@ -1,4 +1,6 @@ +using Lombiq.HelpfulExtensions.Extensions.Widgets.Models; using Lombiq.HelpfulLibraries.OrchardCore.Contents; +using OrchardCore.ContentFields.Settings; using OrchardCore.ContentManagement.Metadata; using OrchardCore.ContentManagement.Metadata.Settings; using OrchardCore.Data.Migration; @@ -55,7 +57,25 @@ public int Create() ) ); - return 4; + var contentItemWidgetPartName = _contentDefinitionManager.AlterPartDefinition(builder => builder + .WithField(part => part.ContentToDisplay, field => field + .WithDisplayName("Content to display") + .WithSettings(new ContentPickerFieldSettings + { + DisplayAllContentTypes = true, + Multiple = true, + })) + .WithField(part => part.DisplayType, field => field.WithDisplayName("Display type")) + .WithField(part => part.GroupId, field => field.WithDisplayName("Group ID")) + ); + + _contentDefinitionManager.AlterTypeDefinition(WidgetTypes.ContentItemWidget, builder => builder + .Securable() + .Stereotype(CommonStereotypes.Widget) + .WithPart(contentItemWidgetPartName) + ); + + return 5; } public int UpdateFrom1() @@ -90,4 +110,21 @@ public int UpdateFrom3() return 4; } + + public int UpdateFrom4() + { + var contentItemWidgetPartName = _contentDefinitionManager.AlterPartDefinition(builder => builder + .WithField(part => part.ContentToDisplay, field => field.WithDisplayName("Content to display")) + .WithField(part => part.DisplayType, field => field.WithDisplayName("Display type")) + .WithField(part => part.GroupId, field => field.WithDisplayName("Group ID")) + ); + + _contentDefinitionManager.AlterTypeDefinition(WidgetTypes.ContentItemWidget, builder => builder + .Securable() + .Stereotype(CommonStereotypes.Widget) + .WithPart(contentItemWidgetPartName) + ); + + return 5; + } } diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Models/ContentItemWidget.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Models/ContentItemWidget.cs new file mode 100644 index 00000000..d7949861 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Models/ContentItemWidget.cs @@ -0,0 +1,11 @@ +using OrchardCore.ContentFields.Fields; +using OrchardCore.ContentManagement; + +namespace Lombiq.HelpfulExtensions.Extensions.Widgets.Models; + +public class ContentItemWidget : ContentPart +{ + public ContentPickerField ContentToDisplay { get; set; } = new(); + public TextField DisplayType { get; set; } = new(); + public TextField GroupId { get; set; } = new(); +} diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Models/MvcCondition.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Models/MvcCondition.cs new file mode 100644 index 00000000..1a8667e0 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Models/MvcCondition.cs @@ -0,0 +1,12 @@ +using OrchardCore.Rules; +using System.Collections.Generic; + +namespace Lombiq.HelpfulExtensions.Extensions.Widgets.Models; + +public class MvcCondition : Condition +{ + public string Area { get; set; } + public string Controller { get; set; } + public string Action { get; set; } + public IDictionary OtherRouteValues { get; } = new Dictionary(); +} diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/Startup.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/Startup.cs index fa01c184..3308e134 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Widgets/Startup.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/Startup.cs @@ -1,8 +1,18 @@ +using Lombiq.HelpfulExtensions.Extensions.Widgets.Drivers; +using Lombiq.HelpfulExtensions.Extensions.Widgets.Liquid; +using Lombiq.HelpfulExtensions.Extensions.Widgets.Models; +using Lombiq.HelpfulLibraries.OrchardCore.Liquid; +using Lombiq.HelpfulLibraries.OrchardCore.TagHelpers; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; +using OrchardCore.ContentManagement; +using OrchardCore.ContentManagement.Display.ContentDisplay; using OrchardCore.Data.Migration; +using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.Liquid; using OrchardCore.Modules; +using OrchardCore.Rules; using System; namespace Lombiq.HelpfulExtensions.Extensions.Widgets; @@ -10,9 +20,24 @@ namespace Lombiq.HelpfulExtensions.Extensions.Widgets; [Feature(FeatureIds.Widgets)] public class Startup : StartupBase { - public override void ConfigureServices(IServiceCollection services) => + public override void ConfigureServices(IServiceCollection services) + { services.AddDataMigration(); + services + .AddScoped, MvcConditionDisplayDriver>() + .AddCondition>() + .AddScoped(sp => (IContentDisplayDriver)sp.GetRequiredService()); + + services.AddTagHelpers(); + + services.AddContentPart() + .UseDetailOnlyDriver(); + + services.AddScoped(); + services.AddLiquidFilter("menu"); + } + public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) { // No need for anything here yet. diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/ViewModels/ConditionViewModel.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/ViewModels/ConditionViewModel.cs new file mode 100644 index 00000000..1a7133e3 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/ViewModels/ConditionViewModel.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Html; +using Microsoft.AspNetCore.Mvc.Localization; + +namespace Lombiq.HelpfulExtensions.Extensions.Widgets.ViewModels; + +public class ConditionViewModel +{ + public LocalizedHtmlString Title { get; set; } + public LocalizedHtmlString Description { get; set; } + public IHtmlContent SummaryHint { get; set; } + + public void CopyTo(ConditionViewModel target) + { + target.Title = Title; + target.Description = Description; + target.SummaryHint = SummaryHint; + } +} diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/ViewModels/MenuWidgetViewModel.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/ViewModels/MenuWidgetViewModel.cs index 842bcd39..48e7cdef 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Widgets/ViewModels/MenuWidgetViewModel.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/ViewModels/MenuWidgetViewModel.cs @@ -7,16 +7,23 @@ namespace Lombiq.HelpfulExtensions.Extensions.Widgets.ViewModels; public class MenuWidgetViewModel { public bool NoWrapper { get; set; } + public IEnumerable MenuItems { get; set; } - public MenuWidgetViewModel(bool noWrapper = false, IEnumerable menuItems = null) + public string HtmlClasses { get; set; } = string.Empty; + + public MenuWidgetViewModel() + : this(noWrapper: false, menuItems: Enumerable.Empty()) + { + } + + public MenuWidgetViewModel(bool noWrapper, IEnumerable menuItems) { NoWrapper = noWrapper; MenuItems = menuItems ?? Enumerable.Empty(); } public MenuWidgetViewModel(dynamic model) - : this((model.NoWrapper as bool?) == true, model.MenuItems as IEnumerable) - { - } + : this((model.NoWrapper as bool?) == true, model.MenuItems as IEnumerable) => + HtmlClasses = model.HtmlClasses as string ?? string.Empty; } diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/ViewModels/MvcConditionViewModel.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/ViewModels/MvcConditionViewModel.cs new file mode 100644 index 00000000..a9ab02e6 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/ViewModels/MvcConditionViewModel.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Lombiq.HelpfulExtensions.Extensions.Widgets.ViewModels; + +public class MvcConditionViewModel +{ + public string Area { get; set; } + public string Controller { get; set; } + public string Action { get; set; } + + public IList OtherRouteNames { get; } = new List(); + public IList OtherRouteValues { get; } = new List(); +} diff --git a/Lombiq.HelpfulExtensions/Extensions/Widgets/WidgetTypes.cs b/Lombiq.HelpfulExtensions/Extensions/Widgets/WidgetTypes.cs index 931bf581..1fda568d 100644 --- a/Lombiq.HelpfulExtensions/Extensions/Widgets/WidgetTypes.cs +++ b/Lombiq.HelpfulExtensions/Extensions/Widgets/WidgetTypes.cs @@ -7,4 +7,5 @@ public static class WidgetTypes public const string LiquidWidget = nameof(LiquidWidget); public const string MenuWidget = nameof(MenuWidget); public const string MarkdownWidget = nameof(MarkdownWidget); + public const string ContentItemWidget = nameof(ContentItemWidget); } diff --git a/Lombiq.HelpfulExtensions/Lombiq.HelpfulExtensions.csproj b/Lombiq.HelpfulExtensions/Lombiq.HelpfulExtensions.csproj index 5c79ba03..49d6adc2 100644 --- a/Lombiq.HelpfulExtensions/Lombiq.HelpfulExtensions.csproj +++ b/Lombiq.HelpfulExtensions/Lombiq.HelpfulExtensions.csproj @@ -42,9 +42,11 @@ + + diff --git a/Lombiq.HelpfulExtensions/Views/Condition.Fields.Detail.Title.cshtml b/Lombiq.HelpfulExtensions/Views/Condition.Fields.Detail.Title.cshtml new file mode 100644 index 00000000..26f7f69c --- /dev/null +++ b/Lombiq.HelpfulExtensions/Views/Condition.Fields.Detail.Title.cshtml @@ -0,0 +1,3 @@ +@model ConditionViewModel + +
@Model.Title
\ No newline at end of file diff --git a/Lombiq.HelpfulExtensions/Views/Condition.Fields.Summary.cshtml b/Lombiq.HelpfulExtensions/Views/Condition.Fields.Summary.cshtml new file mode 100644 index 00000000..588ddf1c --- /dev/null +++ b/Lombiq.HelpfulExtensions/Views/Condition.Fields.Summary.cshtml @@ -0,0 +1,3 @@ +@model ConditionViewModel + +@Model.Title@Model.SummaryHint diff --git a/Lombiq.HelpfulExtensions/Views/Condition.Fields.Thumbnail.cshtml b/Lombiq.HelpfulExtensions/Views/Condition.Fields.Thumbnail.cshtml new file mode 100644 index 00000000..022276dd --- /dev/null +++ b/Lombiq.HelpfulExtensions/Views/Condition.Fields.Thumbnail.cshtml @@ -0,0 +1,4 @@ +@model ConditionViewModel + +

@Model.Title

+

@Model.Description

diff --git a/Lombiq.HelpfulExtensions/Views/ContentItemWidget.cshtml b/Lombiq.HelpfulExtensions/Views/ContentItemWidget.cshtml new file mode 100644 index 00000000..a64116a6 --- /dev/null +++ b/Lombiq.HelpfulExtensions/Views/ContentItemWidget.cshtml @@ -0,0 +1,25 @@ +@using OrchardCore.ContentManagement +@using Lombiq.HelpfulExtensions.Extensions.Widgets.Models +@using OrchardCore.ContentManagement.Display +@using OrchardCore.DisplayManagement.ModelBinding + +@inject IContentManager ContentManager +@inject IContentItemDisplayManager ContentItemDisplayManager +@inject IUpdateModelAccessor UpdateModelAccessor + +@{ + if ((Model.ContentItem as ContentItem)?.As() is not { } part) { return; } + + var ids = part.ContentToDisplay?.ContentItemIds ?? Array.Empty(); + var contentItems = await ContentManager.GetAsync(ids); + + var updater = UpdateModelAccessor.ModelUpdater; + var displayType = string.IsNullOrWhiteSpace(part.DisplayType?.Text) ? string.Empty : part.DisplayType.Text; + var groupId = string.IsNullOrWhiteSpace(part.GroupId?.Text) ? string.Empty : part.GroupId.Text; +} + +@foreach (var content in contentItems) +{ + var shape = await ContentItemDisplayManager.BuildDisplayAsync(content, updater, displayType, groupId); + @await DisplayAsync(shape) +} \ No newline at end of file diff --git a/Lombiq.HelpfulExtensions/Views/MenuWidget.cshtml b/Lombiq.HelpfulExtensions/Views/MenuWidget.cshtml index 8768cd6c..68d66eaf 100644 --- a/Lombiq.HelpfulExtensions/Views/MenuWidget.cshtml +++ b/Lombiq.HelpfulExtensions/Views/MenuWidget.cshtml @@ -1,4 +1,3 @@ -@using Lombiq.HelpfulExtensions.Extensions.Widgets.ViewModels @using Lombiq.HelpfulLibraries.Common.Utilities; @using Microsoft.AspNetCore.Http.Extensions @using OrchardCore.Navigation @@ -35,9 +34,9 @@ @if (!viewModel.NoWrapper) { - @: