From 49bb6646a64a8c40faa701b1cd983aa4b498b975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 20 Jul 2019 18:09:39 +0300 Subject: [PATCH] Auto add styles/scripts of a used widget in the page #297 --- docs/en/AspNetCore/Dashboards.md | 3 + docs/en/AspNetCore/Widgets.md | 84 ++++++++++++++++++ docs/en/images/widget-basic-files.png | Bin 0 -> 10185 bytes ... BundleContributorCollectionExtensions.cs} | 2 +- .../Themes/Basic/Layouts/Account.cshtml | 8 +- .../Themes/Basic/Layouts/Application.cshtml | 6 ++ .../Themes/Basic/Layouts/Empty.cshtml | 6 ++ .../AbpAspNetCoreMvcUiThemeSharedModule.cs | 4 +- ....Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj | 1 + .../Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj | 7 +- .../AbpAspNetCoreMvcUiWidgetsModule.cs | 15 +++- .../Components/WidgetResourcesViewModel.cs | 9 ++ .../Components/WidgetScripts/Default.cshtml | 21 +++++ .../WidgetScriptsViewComponent.cs | 31 +++++++ .../Components/WidgetStyles/Default.cshtml | 21 +++++ .../WidgetStyles/WidgetStylesViewComponent.cs | 30 +++++++ .../UI/Widgets/Components/_ViewImports.cshtml | 3 + .../Mvc/UI/Widgets/IPageWidgetManager.cs | 11 +++ .../Mvc/UI/Widgets/PageWidgetManager.cs | 48 ++++++++++ .../Mvc/UI/Widgets/WidgetDefinition.cs | 66 +++++++++++++- .../Mvc/UI/Widgets/WidgetRenderer.cs | 6 +- .../Mvc/UI/Widgets/WidgetResourceItem.cs | 24 +++++ 22 files changed, 393 insertions(+), 13 deletions(-) create mode 100644 docs/en/AspNetCore/Dashboards.md create mode 100644 docs/en/AspNetCore/Widgets.md create mode 100644 docs/en/images/widget-basic-files.png rename framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/{BundleContributorListExtensions.cs => BundleContributorCollectionExtensions.cs} (80%) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetResourcesViewModel.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetScripts/Default.cshtml create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetScripts/WidgetScriptsViewComponent.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetStyles/Default.cshtml create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetStyles/WidgetStylesViewComponent.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/_ViewImports.cshtml create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/IPageWidgetManager.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/PageWidgetManager.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetResourceItem.cs diff --git a/docs/en/AspNetCore/Dashboards.md b/docs/en/AspNetCore/Dashboards.md new file mode 100644 index 0000000000..26b6a77461 --- /dev/null +++ b/docs/en/AspNetCore/Dashboards.md @@ -0,0 +1,3 @@ +# Dashboards + +TODO \ No newline at end of file diff --git a/docs/en/AspNetCore/Widgets.md b/docs/en/AspNetCore/Widgets.md new file mode 100644 index 0000000000..b51ffb901e --- /dev/null +++ b/docs/en/AspNetCore/Widgets.md @@ -0,0 +1,84 @@ +# Widgets + +ABP provides a model and infrastructure to create **reusable widgets**. It relies on [ASP.NET Core's ViewComponent](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components) system, so any view component can be used as a widget. Widget system is especially useful when you want to; + +* Define widgets in reusable **[modules](../Module-Development-Basics.md)**. +* Have **scripts & styles** for your widget. +* Create **[dashboards](Dashboards.md)** with widgets used in (widgets you've built yourself or defined by modules you are using). +* Co-operate widgets with **[authorization](../Authorization.md)** and **[bundling](Bundling-Minification.md)** systems. + +## Basic Widget Definition + +### Create a View Component + +As the first step, create a regular ASP.NET Core View Component: + +![widget-basic-files](../images/widget-basic-files.png) + +**MySimpleWidgetViewComponent.cs**: + +````csharp +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc; + +namespace DashboardDemo.Web.Pages.Components.MySimpleWidget +{ + public class MySimpleWidgetViewComponent : AbpViewComponent + { + public IViewComponentResult Invoke() + { + return View(); + } + } +} +```` + +**Default.cshtml**: + +```xml +
+

My Simple Widget

+

This is a simple widget!

+
+``` + +### Define the Widget + +Second step is to define a widget using the `WidgetOptions` (in the `ConfigureServices` method of your Web module): + +````csharp +Configure(options => +{ + options.Widgets.Add( + new WidgetDefinition( + "MySimpleWidget", //Unique Widget name + typeof(MySimpleWidgetViewComponent) //Type of the ViewComponent + ) + ); +}); +```` + +Widget name should be unique in the application. + +*TODO: This is in development and will probably change!* + +### Render the Widget + +Whenever you want to render a widget, you can inject the `IWidgetRenderer` and use the `RenderAsync` method with the unique widget name. + +````xml +@inject IWidgetRenderer WidgetRenderer + +@await WidgetRenderer.RenderAsync(Component, "MySimpleWidget") +```` + +You could do the same with standard `Component.InvokeAsync` method. The main difference is that `IWidgetRenderer` uses the widget name defined before. The essential benefit of the `WidgetRenderer` comes when your widget has additional resources, like script and style files. + +## Style & Script Dependencies + +There are some challenges when your widget has script and style files; + +* Any page uses the widget should also include the **its script & styles** files into the page. +* The page should also care about **depended libraries/files** of the widget. + +ABP solves all these issues when you properly relate the resources with the widget. You don't care about dependencies of the widget. \ No newline at end of file diff --git a/docs/en/images/widget-basic-files.png b/docs/en/images/widget-basic-files.png new file mode 100644 index 0000000000000000000000000000000000000000..bf5f122d42a2b86342d85017532f268e732cf5ec GIT binary patch literal 10185 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 CGo0!G literal 0 HcmV?d00001 diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorListExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorCollectionExtensions.cs similarity index 80% rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorListExtensions.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorCollectionExtensions.cs index 2e2087435b..8261706431 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorListExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorCollectionExtensions.cs @@ -1,6 +1,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling { - public static class BundleContributorListExtensions + public static class BundleContributorCollectionExtensions { public static void AddFiles(this BundleContributorCollection contributors, params string[] files) { 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 6eb41a7546..2e95453185 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 @@ -9,6 +9,8 @@ @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.AspNetCore.Mvc.UI.Widgets.Components.WidgetScripts +@using Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetStyles @using Volo.Abp.MultiTenancy @inject IAbpAntiForgeryManager AbpAntiForgeryManager @inject IBrandingProvider BrandingProvider @@ -39,6 +41,8 @@ @await RenderSectionAsync("styles", false) + @await Component.InvokeAsync(typeof(WidgetStylesViewComponent)) + @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Account) @@ -50,7 +54,7 @@ @if (MultiTenancyOptions.Value.IsEnabled && - (TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(CookieTenantResolveContributor.ContributorName) == true)) + (TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(CookieTenantResolveContributor.ContributorName) == true)) {
@MultiTenancyStringLocalizer["Tenant"]: @@ -80,6 +84,8 @@ @await RenderSectionAsync("scripts", false) + @await Component.InvokeAsync(typeof(WidgetScriptsViewComponent)) + @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 a492b4abfe..9bb54dea09 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 @@ -6,6 +6,8 @@ @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.AspNetCore.Mvc.UI.Widgets.Components.WidgetScripts +@using Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetStyles @inject IAbpAntiForgeryManager AbpAntiForgeryManager @inject IBrandingProvider BrandingProvider @inject IPageLayout PageLayout @@ -41,6 +43,8 @@ + @await Component.InvokeAsync(typeof(WidgetStylesViewComponent)) + @await RenderSectionAsync("styles", false) @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Application) @@ -63,6 +67,8 @@ + @await Component.InvokeAsync(typeof(WidgetScriptsViewComponent)) + @await RenderSectionAsync("scripts", false) @await Component.InvokeLayoutHookAsync(LayoutHooks.Body.Last, StandardLayouts.Application) 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 62f94f6ede..f4f18202c7 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 @@ -5,6 +5,8 @@ @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.AspNetCore.Mvc.UI.Widgets.Components.WidgetScripts +@using Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetStyles @inject IAbpAntiForgeryManager AbpAntiForgeryManager @inject IBrandingProvider BrandingProvider @inject IPageLayout PageLayout @@ -40,6 +42,8 @@ + @await Component.InvokeAsync(typeof(WidgetStylesViewComponent)) + @await RenderSectionAsync("styles", false) @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Empty) @@ -59,6 +63,8 @@ @await RenderSectionAsync("scripts", false) + @await Component.InvokeAsync(typeof(WidgetScriptsViewComponent)) + @await Component.InvokeLayoutHookAsync(LayoutHooks.Body.Last, StandardLayouts.Empty) \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs index fb8619b60a..28ae429028 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs @@ -2,6 +2,7 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Packages; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Bundling; +using Volo.Abp.AspNetCore.Mvc.UI.Widgets; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; @@ -9,7 +10,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared { [DependsOn( typeof(AbpAspNetCoreMvcUiBootstrapModule), - typeof(AbpAspNetCoreMvcUiPackagesModule) + typeof(AbpAspNetCoreMvcUiPackagesModule), + typeof(AbpAspNetCoreMvcUiWidgetsModule) )] public class AbpAspNetCoreMvcUiThemeSharedModule : AbpModule { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj index 5bf8e5fcb1..898d7c1a0d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj @@ -39,6 +39,7 @@ + \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj index 26634c6270..ae41d65026 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj @@ -10,7 +10,12 @@ - + + + + + + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs index cdf1db75cd..8f2d205cad 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs @@ -1,13 +1,22 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; +using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets { [DependsOn( - typeof(AbpAspNetCoreMvcUiBootstrapModule) - )] + typeof(AbpAspNetCoreMvcUiBootstrapModule), + typeof(AbpAspNetCoreMvcUiBundlingModule) + )] public class AbpAspNetCoreMvcUiWidgetsModule : AbpModule { - + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetResourcesViewModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetResourcesViewModel.cs new file mode 100644 index 0000000000..50bb947054 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetResourcesViewModel.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components +{ + public class WidgetResourcesViewModel + { + public IReadOnlyList Widgets { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetScripts/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetScripts/Default.cshtml new file mode 100644 index 0000000000..f81d2ad0f4 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetScripts/Default.cshtml @@ -0,0 +1,21 @@ +@model Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetResourcesViewModel +@if (Model.Widgets.Any()) +{ + var resourceItems = Model.Widgets.SelectMany(w => w.Scripts).ToArray(); + if (resourceItems.Any()) + { + + @foreach (var resourceItem in resourceItems) + { + if (resourceItem.Src != null) + { + + } + else + { + + } + } + + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetScripts/WidgetScriptsViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetScripts/WidgetScriptsViewComponent.cs new file mode 100644 index 0000000000..88f7214c7a --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetScripts/WidgetScriptsViewComponent.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetStyles; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetScripts +{ + public class WidgetScriptsViewComponent : AbpViewComponent + { + protected IPageWidgetManager PageWidgetManager { get; } + protected WidgetOptions Options { get; } + + public WidgetScriptsViewComponent( + IPageWidgetManager pageWidgetManager, + IOptions options) + { + PageWidgetManager = pageWidgetManager; + Options = options.Value; + } + + public virtual IViewComponentResult Invoke() + { + return View( + "~/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetScripts/Default.cshtml", + new WidgetResourcesViewModel + { + Widgets = PageWidgetManager.GetAll() + } + ); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetStyles/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetStyles/Default.cshtml new file mode 100644 index 0000000000..c253d2e83d --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetStyles/Default.cshtml @@ -0,0 +1,21 @@ +@model Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetResourcesViewModel +@if (Model.Widgets.Any()) +{ + var resourceItems = Model.Widgets.SelectMany(w => w.Styles).ToArray(); + if (resourceItems.Any()) + { + + @foreach (var resourceItem in resourceItems) + { + if (resourceItem.Src != null) + { + + } + else + { + + } + } + + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetStyles/WidgetStylesViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetStyles/WidgetStylesViewComponent.cs new file mode 100644 index 0000000000..1a5b150b09 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetStyles/WidgetStylesViewComponent.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetStyles +{ + public class WidgetStylesViewComponent : AbpViewComponent + { + protected IPageWidgetManager PageWidgetManager { get; } + protected WidgetOptions Options { get; } + + public WidgetStylesViewComponent( + IPageWidgetManager pageWidgetManager, + IOptions options) + { + PageWidgetManager = pageWidgetManager; + Options = options.Value; + } + + public virtual IViewComponentResult Invoke() + { + return View( + "~/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/WidgetStyles/Default.cshtml", + new WidgetResourcesViewModel + { + Widgets = PageWidgetManager.GetAll() + } + ); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/_ViewImports.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/_ViewImports.cshtml new file mode 100644 index 0000000000..225780c2c2 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/Components/_ViewImports.cshtml @@ -0,0 +1,3 @@ +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/IPageWidgetManager.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/IPageWidgetManager.cs new file mode 100644 index 0000000000..78ef563d82 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/IPageWidgetManager.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets +{ + public interface IPageWidgetManager + { + bool TryAdd(WidgetDefinition widget); + + IReadOnlyList GetAll(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/PageWidgetManager.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/PageWidgetManager.cs new file mode 100644 index 0000000000..450bf492cf --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/PageWidgetManager.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using Microsoft.AspNetCore.Http; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets +{ + public class PageWidgetManager : IPageWidgetManager, IScopedDependency + { + public const string HttpContextItemName = "__AbpCurrentWidgets"; + + private readonly IHttpContextAccessor _httpContextAccessor; + + public PageWidgetManager(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public bool TryAdd(WidgetDefinition widget) + { + return GetWidgetList() + .AddIfNotContains(widget); + } + + private List GetWidgetList() + { + var httpContext = _httpContextAccessor.HttpContext; + if (httpContext == null) + { + throw new AbpException($"{typeof(PageWidgetManager).AssemblyQualifiedName} should be used in a web request! Can not get IHttpContextAccessor.HttpContext."); + } + + var widgets = httpContext.Items[HttpContextItemName] as List; + if (widgets == null) + { + widgets = new List(); + httpContext.Items[HttpContextItemName] = widgets; + } + + return widgets; + } + + public IReadOnlyList GetAll() + { + return GetWidgetList().ToImmutableArray(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetDefinition.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetDefinition.cs index b1b404215e..deac09e0c2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetDefinition.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetDefinition.cs @@ -32,27 +32,85 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets public List RequiredPermissions { get; set; } + public List Styles { get; } + + public List Scripts { get; } + public WidgetDefinition( [NotNull] string name, - [CanBeNull] ILocalizableString displayName, - [NotNull] Type viewComponentType) + [NotNull] Type viewComponentType, + [CanBeNull] ILocalizableString displayName = null) { Name = Check.NotNullOrWhiteSpace(name, nameof(name)); ViewComponentType = Check.NotNull(viewComponentType, nameof(viewComponentType)); DisplayName = displayName ?? new FixedLocalizableString(name); + RequiredPermissions = new List(); + Styles = new List(); + Scripts = new List(); } - public WidgetDefinition AddRequiredPermission(string permissionName) + public WidgetDefinition WithPermission([NotNull] string permissionName) { + Check.NotNullOrWhiteSpace(permissionName, nameof(permissionName)); RequiredPermissions.Add(permissionName); return this; } - public WidgetDefinition SetDefaultDimension(int width, int height) + public WidgetDefinition WithDefaultDimensions(int width, int height) { DefaultDimensions = new WidgetDimensions(width, height); return this; } + + public WidgetDefinition WithStyles(params string[] files) + { + return WithResources(Styles, files); + } + + public WidgetDefinition WithStyles(params Type[] bundleContributorTypes) + { + return WithResources(Styles, bundleContributorTypes); + } + + public WidgetDefinition WithScripts(params string[] files) + { + return WithResources(Scripts, files); + } + + public WidgetDefinition WithScripts(params Type[] bundleContributorTypes) + { + return WithResources(Scripts, bundleContributorTypes); + } + + private WidgetDefinition WithResources(List resourceItems, Type[] bundleContributorTypes) + { + if (bundleContributorTypes.IsNullOrEmpty()) + { + return this; + } + + foreach (var bundleContributorType in bundleContributorTypes) + { + resourceItems.Add(new WidgetResourceItem(bundleContributorType)); + } + + return this; + } + + private WidgetDefinition WithResources(List resourceItems, string[] files) + { + if (files.IsNullOrEmpty()) + { + return this; + } + + foreach (var file in files) + { + resourceItems.Add(new WidgetResourceItem(file)); + } + + return this; + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetRenderer.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetRenderer.cs index 821e53e853..c6c7b059d8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetRenderer.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetRenderer.cs @@ -9,16 +9,18 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets public class WidgetRenderer : IWidgetRenderer { private readonly WidgetOptions _widgetOptions; + private readonly IPageWidgetManager _pageWidgetManager; - public WidgetRenderer(IOptions widgetOptions) + public WidgetRenderer(IOptions widgetOptions, IPageWidgetManager pageWidgetManager) { + _pageWidgetManager = pageWidgetManager; _widgetOptions = widgetOptions.Value; } public async Task RenderAsync(IViewComponentHelper componentHelper, string widgetName, object args = null) { var widget = _widgetOptions.Widgets.Single(w=>w.Name.Equals(widgetName)); - + _pageWidgetManager.TryAdd(widget); return await componentHelper.InvokeAsync(widget.ViewComponentType, args ?? new object()); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetResourceItem.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetResourceItem.cs new file mode 100644 index 0000000000..0e5cd195f6 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetResourceItem.cs @@ -0,0 +1,24 @@ +using System; +using JetBrains.Annotations; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets +{ + public class WidgetResourceItem + { + [CanBeNull] + public string Src { get; } + + [CanBeNull] + public Type Type { get; } + + public WidgetResourceItem([NotNull] string src) + { + Src = Check.NotNullOrWhiteSpace(src, nameof(src)); + } + + public WidgetResourceItem([NotNull] Type type) + { + Type = Check.NotNull(type, nameof(type)); + } + } +} \ No newline at end of file