From 63bc860d757a9a953306ba6d62bab1e7b8e78099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 24 Jun 2019 18:35:57 +0300 Subject: [PATCH] Resolved #1361: Layout Hook Feature for MVC UI --- .../Themes/Basic/Layouts/Account.cshtml | 12 +++++++-- .../Themes/Basic/Layouts/Application.cshtml | 8 ++++++ .../Themes/Basic/Layouts/Empty.cshtml | 8 ++++++ .../Volo.Abp.AspNetCore.Mvc.UI.csproj | 5 ++++ .../Mvc/UI/AbpAspNetCoreMvcUiModule.cs | 9 ++++++- .../UI/Components/LayoutHook/Default.cshtml | 9 +++++++ .../Components/LayoutHook/LayoutHookInfo.cs | 24 +++++++++++++++++ .../LayoutHook/LayoutHookOptions.cs | 24 +++++++++++++++++ .../LayoutHook/LayoutHookViewComponent.cs | 27 +++++++++++++++++++ .../LayoutHook/LayoutHookViewModel.cs | 15 +++++++++++ .../UI/Components/LayoutHook/LayoutHooks.cs | 17 ++++++++++++ ...ViewComponentHelperLayoutHookExtensions.cs | 24 +++++++++++++++++ 12 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/Default.cshtml create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookInfo.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookOptions.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewComponent.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewModel.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHooks.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/ViewComponentHelperLayoutHookExtensions.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml index 43c05559f9..c5ff3762b2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml @@ -2,11 +2,13 @@ @using Microsoft.Extensions.Options @using Volo.Abp.AspNetCore.MultiTenancy @using Volo.Abp.AspNetCore.Mvc.AntiForgery +@using Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook @using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.MainNavbar @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.PageAlerts @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components +@using Volo.Abp.AspNetCore.Mvc.UI.Theming @using Volo.Abp.MultiTenancy @inject IAbpAntiForgeryManager AbpAntiForgeryManager @inject IBrandingProvider BrandingProvider @@ -25,6 +27,8 @@ + @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.First, StandardLayouts.Account) + @@ -34,16 +38,19 @@ @await RenderSectionAsync("styles", false) + + @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Account) + @await Component.InvokeLayoutHookAsync(LayoutHooks.Body.First, StandardLayouts.Account) @(await Component.InvokeAsync())
- @if (MultiTenancyOptions.Value.IsEnabled && - (TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(CookieTenantResolveContributor.ContributorName) == true)) + @if (MultiTenancyOptions.Value.IsEnabled && + (TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(CookieTenantResolveContributor.ContributorName) == true)) {
@MultiTenancyStringLocalizer["Tenant"]: @@ -73,5 +80,6 @@ @await RenderSectionAsync("scripts", false) + @await Component.InvokeLayoutHookAsync(LayoutHooks.Body.Last, StandardLayouts.Account) \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml index b189bf8e40..db8f8e1a6b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml @@ -1,9 +1,11 @@ @using Volo.Abp.AspNetCore.Mvc.AntiForgery +@using Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook @using Volo.Abp.AspNetCore.Mvc.UI.Layout @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.MainNavbar @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.PageAlerts @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components +@using Volo.Abp.AspNetCore.Mvc.UI.Theming @inject IAbpAntiForgeryManager AbpAntiForgeryManager @inject IBrandingProvider BrandingProvider @inject IPageLayout PageLayout @@ -29,6 +31,8 @@ + @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.First, StandardLayouts.Application) + @@ -38,8 +42,11 @@ @await RenderSectionAsync("styles", false) + + @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Application) + @await Component.InvokeLayoutHookAsync(LayoutHooks.Body.First, StandardLayouts.Application) @(await Component.InvokeAsync()) @@ -58,5 +65,6 @@ @await RenderSectionAsync("scripts", false) + @await Component.InvokeLayoutHookAsync(LayoutHooks.Body.Last, StandardLayouts.Application) \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml index 59fd80ea1d..da7c119de4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml @@ -1,8 +1,10 @@ @using Volo.Abp.AspNetCore.Mvc.AntiForgery +@using Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook @using Volo.Abp.AspNetCore.Mvc.UI.Layout @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.PageAlerts @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components +@using Volo.Abp.AspNetCore.Mvc.UI.Theming @inject IAbpAntiForgeryManager AbpAntiForgeryManager @inject IBrandingProvider BrandingProvider @inject IPageLayout PageLayout @@ -28,6 +30,8 @@ + @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.First, StandardLayouts.Empty) + @@ -37,8 +41,11 @@ @await RenderSectionAsync("styles", false) + + @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Empty) + @await Component.InvokeLayoutHookAsync(LayoutHooks.Body.First, StandardLayouts.Empty)
@(await Component.InvokeAsync()) @@ -52,5 +59,6 @@ @await RenderSectionAsync("scripts", false) + @await Component.InvokeLayoutHookAsync(LayoutHooks.Body.Last, StandardLayouts.Empty) \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj index 9911b60b5c..34367260f9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj @@ -10,6 +10,11 @@ + + + + + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/AbpAspNetCoreMvcUiModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/AbpAspNetCoreMvcUiModule.cs index cafc4c87fc..60a142bda5 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/AbpAspNetCoreMvcUiModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/AbpAspNetCoreMvcUiModule.cs @@ -1,5 +1,6 @@ using Volo.Abp.Modularity; using Volo.Abp.UI.Navigation; +using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.AspNetCore.Mvc.UI { @@ -7,6 +8,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI [DependsOn(typeof(AbpUiNavigationModule))] public class AbpAspNetCoreMvcUiModule : AbpModule { - + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/Default.cshtml new file mode 100644 index 0000000000..61e9afbf6e --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/Default.cshtml @@ -0,0 +1,9 @@ +@using Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook +@model LayoutHookViewModel +@if (Model.Hooks.Any()) +{ + foreach (var hook in Model.Hooks) + { + @await Component.InvokeAsync(hook.ComponentType, new { layout = Model.Layout }) + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookInfo.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookInfo.cs new file mode 100644 index 0000000000..7828ba6536 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookInfo.cs @@ -0,0 +1,24 @@ +using System; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook +{ + public class LayoutHookInfo + { + /// + /// ViewComponent type. + /// + public Type ComponentType { get; } + + /// + /// Specifies the layout name to apply this hook. + /// null indicates that this hook will be applied to all layouts. + /// + public string Layout { get; } + + public LayoutHookInfo(Type componentType, string layout = null) + { + ComponentType = componentType; + Layout = layout; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookOptions.cs new file mode 100644 index 0000000000..e51f491f64 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookOptions.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook +{ + public class LayoutHookOptions + { + public IDictionary> Hooks { get; } + + public LayoutHookOptions() + { + Hooks = new Dictionary>(); + } + + public LayoutHookOptions Add(string name, Type componentType, string layout = null) + { + Hooks + .GetOrAdd(name, () => new List()) + .Add(new LayoutHookInfo(componentType, layout)); + + return this; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewComponent.cs new file mode 100644 index 0000000000..85527037a8 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewComponent.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook +{ + public class LayoutHookViewComponent : AbpViewComponent + { + protected LayoutHookOptions Options { get; } + + public LayoutHookViewComponent(IOptions options) + { + Options = options.Value; + } + + public virtual IViewComponentResult Invoke(string name, string layout) + { + var hooks = Options.Hooks.GetOrDefault(name)?.ToArray() ?? Array.Empty(); + + return View( + "~/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/Default.cshtml", + new LayoutHookViewModel(hooks, layout) + ); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewModel.cs new file mode 100644 index 0000000000..3e71c5cd2d --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewModel.cs @@ -0,0 +1,15 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook +{ + public class LayoutHookViewModel + { + public LayoutHookInfo[] Hooks { get; } + + public string Layout { get; } + + public LayoutHookViewModel(LayoutHookInfo[] hooks, string layout) + { + Hooks = hooks; + Layout = layout; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHooks.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHooks.cs new file mode 100644 index 0000000000..ab3ef8e903 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHooks.cs @@ -0,0 +1,17 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook +{ + public static class LayoutHooks + { + public static class Head + { + public const string First = "Header.First"; + public const string Last = "Header.Last"; + } + + public static class Body + { + public const string First = "Body.First"; + public const string Last = "Body.Last"; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/ViewComponentHelperLayoutHookExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/ViewComponentHelperLayoutHookExtensions.cs new file mode 100644 index 0000000000..99b6596401 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/ViewComponentHelperLayoutHookExtensions.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Html; +using Microsoft.AspNetCore.Mvc; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook +{ + public static class ViewComponentHelperLayoutHookExtensions + { + public static Task InvokeLayoutHookAsync( + this IViewComponentHelper componentHelper, + string name, + string layout) + { + return componentHelper.InvokeAsync( + typeof(LayoutHookViewComponent), + new + { + name = name, + layout = layout + } + ); + } + } +}