diff --git a/README.md b/README.md index 1d7b7e51a7..ebba20da41 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ Love ABP Framework? **Please give a star** to this repository :star: ## Discord Channel -You can use this link to join the ABP Community Discord Server: https://discord.gg/uVGt6hyhcm +You can use this link to join the ABP Community Discord Server: https://discord.gg/abp ## ABP Commercial diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index 023a4b18ed..9f8e88f180 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -380,6 +380,7 @@ "PurchaseItems": "Purchase Items", "SuccessfullyUpdated": "Successfully updated", "SuccessfullyAdded": "Successfully added", - "PurchaseState": "Purchase State" + "PurchaseState": "Purchase State", + "ShowBetweenDayCount": "Show Between Days" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index 8fa96b5ee2..0d7724df56 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -495,7 +495,9 @@ "LicenseTypeNotCorrect": "The license type is not correct!", "Trainings": "Trainings", "ChoseTrainingPlaceholder": "Chose the training...", - "ContactUsToGetQuote": "Contact us to get a quote", + "DoYouNeedTrainings": "Do you need one of these trainings?", + "DoYouNeedTraining": "Do you need {0} training?", + "GetInTouchUs": "Get in touch with us", "ForMoreInformationClickHere": "For more information, click here.", "IsGetOnboardingTraining": "Would you like to get onboarding & web application development training?", "OnboardingWebApplicationDevelopmentTrainingMessage": "To schedule your training calendar, please contact {0} after creating the organization", @@ -503,6 +505,7 @@ "AdditionalNote": "Additional Note", "OnboardingTrainingFaqTitle": "Do you have ABP onboarding training?", "OnboardingTrainingFaqExplanation": "Yes, we have ABP Training Services to help you get your ABP project started fast. You will learn about ABP from an ABP core team member and you will get the skills to begin your ABP project. In the onboarding training, we will explain how to set up your development environment, install the required tools, create a fully functional CRUD page. The training will be live and the Zoom application will be used, and we are open to using other online meeting platforms. The language of the training will be English. You can also ask your questions about ABP during the sessions. A convenient time and date will be planned for both parties. To get more information, contact us at info@abp.io.", - "AddBasket": "Add to Basket" + "AddBasket": "Add to Basket", + "SendTrainingRequest": "Send Training Request" } } diff --git a/docs/en/AspNet-Boilerplate-Migration-Guide.md b/docs/en/AspNet-Boilerplate-Migration-Guide.md index 52a2fced6a..e337b78a6d 100644 --- a/docs/en/AspNet-Boilerplate-Migration-Guide.md +++ b/docs/en/AspNet-Boilerplate-Migration-Guide.md @@ -1,4 +1,4 @@ -# ASP.NET Boilerplate v5+ to ABP Framework Migration +# Migrating from ASP.NET Boilerplate to the ABP Framework ABP Framework is **the successor** of the open source [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework. This guide aims to help you to **migrate your existing solutions** (you developed with the ASP.NET Boilerplate framework) to the ABP Framework. diff --git a/docs/en/Distributed-Locking.md b/docs/en/Distributed-Locking.md index bea10645ca..d57fd45c83 100644 --- a/docs/en/Distributed-Locking.md +++ b/docs/en/Distributed-Locking.md @@ -27,21 +27,25 @@ using Medallion.Threading.Redis; namespace AbpDemo { - public class MyModule : AbpModule - { - public override void ConfigureServices(ServiceConfigurationContext context) - { - var configuration = context.Services.GetConfiguration(); - - context.Services.AddSingleton(sp => - { - var connection = ConnectionMultiplexer + [DependsOn( + typeof(AbpDistributedLockingModule) + //If you have the other dependencies, you should do here + )] + public class MyModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + context.Services.AddSingleton(sp => + { + var connection = ConnectionMultiplexer .Connect(configuration["Redis:Configuration"]); - return new + return new RedisDistributedSynchronizationProvider(connection.GetDatabase()); - }); - } - } + }); + } + } } ```` diff --git a/docs/en/UI/Angular/Theming.md b/docs/en/UI/Angular/Theming.md index 3b7e3d1afd..c7f303763d 100644 --- a/docs/en/UI/Angular/Theming.md +++ b/docs/en/UI/Angular/Theming.md @@ -227,7 +227,7 @@ import { Router } from '@angular/router'; template: ` - {{ data.textTemplate.text | abpLocalization }} + {%{{{ data.textTemplate.text | abpLocalization }}}%} `, }) diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Microsoft/AspNetCore/Authentication/OAuth/Claims/AbpClaimActionCollectionExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Microsoft/AspNetCore/Authentication/OAuth/Claims/AbpClaimActionCollectionExtensions.cs index 01dc489c54..2aedea2608 100644 --- a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Microsoft/AspNetCore/Authentication/OAuth/Claims/AbpClaimActionCollectionExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Microsoft/AspNetCore/Authentication/OAuth/Claims/AbpClaimActionCollectionExtensions.cs @@ -13,6 +13,20 @@ public static class AbpClaimActionCollectionExtensions claimActions.DeleteClaim("name"); claimActions.RemoveDuplicate(AbpClaimTypes.UserName); } + + if (AbpClaimTypes.Name != "given_name") + { + claimActions.MapJsonKey(AbpClaimTypes.Name, "given_name"); + claimActions.DeleteClaim("given_name"); + claimActions.RemoveDuplicate(AbpClaimTypes.Name); + } + + if (AbpClaimTypes.SurName != "family_name") + { + claimActions.MapJsonKey(AbpClaimTypes.SurName, "family_name"); + claimActions.DeleteClaim("family_name"); + claimActions.RemoveDuplicate(AbpClaimTypes.SurName); + } if (AbpClaimTypes.Email != "email") { diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs index 02b292a984..894ba470a8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs @@ -57,8 +57,7 @@ public static class AbpOpenIdConnectExtensions if (receivedContext.Request.Cookies.ContainsKey(tenantKey)) { - receivedContext.TokenEndpointRequest.SetParameter(tenantKey, - receivedContext.Request.Cookies[tenantKey]); + receivedContext.TokenEndpointRequest?.SetParameter(tenantKey, receivedContext.Request.Cookies[tenantKey]); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js index b9bcde13e1..f87b7c27b1 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js @@ -431,9 +431,7 @@ var abp = abp || {}; configuration.language = datatables.defaultConfigurations.language(); - if(configuration.dom){ - configuration.dom += datatables.defaultConfigurations.dom; - }else{ + if(!configuration.dom){ configuration.dom = datatables.defaultConfigurations.dom; } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs index 48ec6121b4..b9d3b83068 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs @@ -82,6 +82,7 @@ public class AbpExceptionHandlingMiddleware : IMiddleware, ITransientDependency httpContext.Response.StatusCode = (int)statusCodeFinder.GetStatusCode(httpContext, exception); httpContext.Response.OnStarting(_clearCacheHeadersDelegate, httpContext.Response); httpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); + httpContext.Response.Headers.Add("Content-Type", "application/json"); await httpContext.Response.WriteAsync( jsonSerializer.Serialize( diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs index 062868a99c..f014942486 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs @@ -81,12 +81,12 @@ public class DatabaseManagementSystemChangeStep : ProjectBuildPipelineStep private void ChangeEntityFrameworkCoreDependency(ProjectBuildContext context, string newPackageName, string newModuleNamespace, string newModuleClass) { - var efCoreProjectFile = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCore.csproj", StringComparison.OrdinalIgnoreCase)); - efCoreProjectFile.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newPackageName); + var efCoreProjectFile = context.Files.FirstOrDefault(f => f.Name.EndsWith("EntityFrameworkCore.csproj", StringComparison.OrdinalIgnoreCase)); + efCoreProjectFile?.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newPackageName); - var efCoreModuleClass = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase)); - efCoreModuleClass.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newModuleNamespace); - efCoreModuleClass.ReplaceText("AbpEntityFrameworkCoreSqlServerModule", newModuleClass); + var efCoreModuleClass = context.Files.FirstOrDefault(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase)); + efCoreModuleClass?.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newModuleNamespace); + efCoreModuleClass?.ReplaceText("AbpEntityFrameworkCoreSqlServerModule", newModuleClass); } private void ChangeUseSqlServer(ProjectBuildContext context, string newUseMethodForEfModule, string newUseMethodForDbContext = null) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs index d4d4a5bed0..dded0d794e 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs @@ -57,8 +57,6 @@ public static class CultureHelper public static string GetBaseCultureName(string cultureName) { - return cultureName.Contains("-") - ? cultureName.Left(cultureName.IndexOf("-", StringComparison.Ordinal)) - : cultureName; + return new CultureInfo(cultureName).Parent.Name; } } diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs index ad09223f05..addbc49171 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs @@ -1,10 +1,23 @@ -namespace Volo.Abp.EventBus.RabbitMq; +using Volo.Abp.RabbitMQ; + +namespace Volo.Abp.EventBus.RabbitMq; public class AbpRabbitMqEventBusOptions { + public const string DefaultExchangeType = RabbitMqConsts.ExchangeTypes.Direct; + public string ConnectionName { get; set; } public string ClientName { get; set; } public string ExchangeName { get; set; } + + public string ExchangeType { get; set; } + + public string GetExchangeTypeOrDefault() + { + return string.IsNullOrEmpty(ExchangeType) + ? DefaultExchangeType + : ExchangeType; + } } diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs index c57d9e9417..a2932de52e 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs @@ -69,7 +69,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe Consumer = MessageConsumerFactory.Create( new ExchangeDeclareConfiguration( AbpRabbitMqEventBusOptions.ExchangeName, - type: "direct", + type: AbpRabbitMqEventBusOptions.GetExchangeTypeOrDefault(), durable: true ), new QueueDeclareConfiguration( @@ -244,7 +244,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe { channel.ExchangeDeclare( AbpRabbitMqEventBusOptions.ExchangeName, - "direct", + AbpRabbitMqEventBusOptions.GetExchangeTypeOrDefault(), durable: true ); diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqConsts.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqConsts.cs index 19b8ddb573..996e88959b 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqConsts.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqConsts.cs @@ -8,4 +8,15 @@ public static class RabbitMqConsts public const int Persistent = 2; } + + public static class ExchangeTypes + { + public const string Direct = "direct"; + + public const string Topic = "topic"; + + public const string Fanout = "fanout"; + + public const string Headers = "headers"; + } } diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs index b8375485f7..6c4bdfff08 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Localization; using Shouldly; @@ -183,6 +183,60 @@ public class AbpLocalization_Tests : AbpIntegratedTest UpdateAsync(Guid id, UpdateBlogPostDto input) { var blogPost = await BlogPostRepository.GetAsync(id); - + blogPost.SetTitle(input.Title); blogPost.SetShortDescription(input.ShortDescription); blogPost.SetContent(input.Content); blogPost.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp); + + if (blogPost.CoverImageMediaId != null && input.CoverImageMediaId == null) + { + await MediaDescriptorAdminAppService.DeleteAsync(blogPost.CoverImageMediaId.Value); + } blogPost.CoverImageMediaId = input.CoverImageMediaId; - + if (blogPost.Slug != input.Slug) { await BlogPostManager.SetSlugUrlAsync(blogPost, input.Slug); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json index 6608a2e1b9..1a2814324d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json @@ -7,6 +7,8 @@ "Volo.CmsKit.Admin.Tags.EntityTagAdminController": { "controllerName": "EntityTagAdmin", "controllerGroupName": "EntityTagAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Admin.Tags.EntityTagAdminController", "interfaces": [ { @@ -154,6 +156,8 @@ "Volo.CmsKit.Admin.Tags.TagAdminController": { "controllerName": "TagAdmin", "controllerGroupName": "TagAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Admin.Tags.TagAdminController", "interfaces": [ { @@ -422,6 +426,8 @@ "Volo.CmsKit.Admin.Pages.PageAdminController": { "controllerName": "PageAdmin", "controllerGroupName": "PageAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Admin.Pages.PageAdminController", "interfaces": [ { @@ -675,6 +681,8 @@ "Volo.CmsKit.Admin.Menus.MenuItemAdminController": { "controllerName": "MenuItemAdmin", "controllerGroupName": "MenuItemAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Admin.Menus.MenuItemAdminController", "interfaces": [ { @@ -1000,6 +1008,8 @@ "Volo.CmsKit.Admin.MediaDescriptors.MediaDescriptorAdminController": { "controllerName": "MediaDescriptorAdmin", "controllerGroupName": "MediaDescriptorAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Admin.MediaDescriptors.MediaDescriptorAdminController", "interfaces": [ { @@ -1118,6 +1128,8 @@ "Volo.CmsKit.Admin.GlobalResources.GlobalResourceAdminController": { "controllerName": "GlobalResourceAdmin", "controllerGroupName": "GlobalResourceAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Admin.GlobalResources.GlobalResourceAdminController", "interfaces": [ { @@ -1182,6 +1194,8 @@ "Volo.CmsKit.Admin.Comments.CommentAdminController": { "controllerName": "CommentAdmin", "controllerGroupName": "CommentAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Admin.Comments.CommentAdminController", "interfaces": [ { @@ -1401,6 +1415,8 @@ "Volo.CmsKit.Admin.Blogs.BlogAdminController": { "controllerName": "BlogAdmin", "controllerGroupName": "BlogAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Admin.Blogs.BlogAdminController", "interfaces": [ { @@ -1654,6 +1670,8 @@ "Volo.CmsKit.Admin.Blogs.BlogFeatureAdminController": { "controllerName": "BlogFeatureAdmin", "controllerGroupName": "BlogFeatureAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Admin.Blogs.BlogFeatureAdminController", "interfaces": [ { @@ -1760,6 +1778,8 @@ "Volo.CmsKit.Admin.Blogs.BlogPostAdminController": { "controllerName": "BlogPostAdmin", "controllerGroupName": "BlogPostAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Admin.Blogs.BlogPostAdminController", "interfaces": [ { diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml index a27ff10906..f48f5e7bd0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml @@ -48,13 +48,17 @@
- @if (Model.ViewModel.CoverImageMediaId != null) - { - -
- } - - +
+ @if (Model.ViewModel.CoverImageMediaId != null) + { + +
+ +
+ } +
+ +
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js index 5902dc111b..d817e0aa0f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js @@ -10,6 +10,7 @@ $(function () { var $blogPostIdInput = $('#Id'); var $tagsInput = $('.tag-editor-form input[name=tags]'); var $fileInput = $('#BlogPostCoverImage'); + var $buttonRemoveCoverImage = $('#button-remove-cover-image'); var UPPY_FILE_ID = "uppy-upload-file"; @@ -152,7 +153,6 @@ $(function () { } } - // ----------------------------------- var fileUploadUri = "/api/cms-kit-admin/media/blogpost"; var fileUriPrefix = "/api/cms-kit/media/"; @@ -225,4 +225,16 @@ $(function () { } }); } + + $buttonRemoveCoverImage.on('click', function () { + abp.message.confirm( + l('RemoveCoverImageConfirmationMessage'), + function (isConfirmed) { + if (isConfirmed) { + $coverImage.val(null); + $('#CurrentCoverImageArea').remove(); + } + } + ); + }); }); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/BlogPostScrollIndexFeature.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/BlogPostScrollIndexFeature.cs new file mode 100644 index 0000000000..9f03f973e1 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/BlogPostScrollIndexFeature.cs @@ -0,0 +1,17 @@ +using JetBrains.Annotations; +using Volo.Abp.GlobalFeatures; + +namespace Volo.CmsKit.GlobalFeatures; + + +[GlobalFeatureName(Name)] +public class BlogPostScrollIndexFeature : GlobalFeature +{ + public const string Name = "CmsKit.BlogPost.ScrollIndex"; + + internal BlogPostScrollIndexFeature( + [NotNull] GlobalCmsKitFeatures cmsKit + ) : base(cmsKit) + { + } +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs index 9c07101616..6a7ca3245a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs @@ -26,6 +26,8 @@ public class GlobalCmsKitFeatures : GlobalModuleFeatures public MenuFeature Menu => GetFeature(); public GlobalResourcesFeature GlobalResources => GetFeature(); + + public BlogPostScrollIndexFeature BlogPostScrollIndex => GetFeature(); public GlobalCmsKitFeatures([NotNull] GlobalFeatureManager featureManager) : base(featureManager) @@ -40,5 +42,6 @@ public class GlobalCmsKitFeatures : GlobalModuleFeatures AddFeature(new CmsUserFeature(this)); AddFeature(new MenuFeature(this)); AddFeature(new GlobalResourcesFeature(this)); + AddFeature(new BlogPostScrollIndexFeature(this)); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json index 78e6108dcd..904acabe21 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json @@ -131,6 +131,7 @@ "SelectAll": "Select All", "Send": "Send", "SendMessage": "Send Message", + "SelectedAuthor": "Author", "ShortDescription": "Short description", "Slug": "Slug", "Source": "Source", @@ -182,6 +183,11 @@ "HasBlogPostWaitingForReviewMessage": "You have a blog post waiting for review. Click to list.", "SelectAStatus": "Select a status", "Status": "Status", - "SelectAnAuthor": "Select an author" + "SelectAnAuthor": "Select an author", + "SavedSuccessfully": "Saved successfully", + "GoToTop": "Go to top", + "InThisDocument": "In this document", + "RemoveCoverImageConfirmationMessage": "Are you sure to remove the cover image?", + "RemoveCoverImage": "Remove the cover image" } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json index 15d64305ce..c0eedc01b8 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json @@ -130,6 +130,7 @@ "SelectAll": "Hepsini seç", "Send": "Gönder", "SendMessage": "Mesajı Gönder", + "SelectedAuthor": "Yazar", "ShortDescription": "Kısa açıklama", "Slug": "Etiket", "Source": "Kaynak", @@ -181,6 +182,11 @@ "HasBlogPostWaitingForReviewMessage": "Yayınlanmak için onay bekleyen blog postlar var! Listelemek için tıklayın.", "SelectAStatus": "Durum seçin", "Status": "Durum", - "SelectAnAuthor": "Bir yazar seçin" + "SelectAnAuthor": "Bir yazar seçin", + "SavedSuccessfully": "Başarıyla kaydedildi", + "GoToTop": "Yukarı Git", + "InThisDocument": "Bu belgede", + "RemoveCoverImageConfirmationMessage": "Kapak resmini kaldırmak istediğinize emin misiniz?", + "RemoveCoverImage": "Kapak resmini kaldır" } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs index aa1b2e134a..2af1036162 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogPostRepository.cs @@ -30,7 +30,16 @@ public interface IBlogPostRepository : IBasicRepository Task GetBySlugAsync(Guid blogId, string slug, CancellationToken cancellationToken = default); - Task> GetAuthorsHasBlogPosts(CancellationToken cancellationToken = default); + Task> GetAuthorsHasBlogPostsAsync( + int skipCount, + int maxResultCount, + string sorting, + string filter, + CancellationToken cancellationToken = default); + + Task GetAuthorsHasBlogPostsCountAsync(string filter, CancellationToken cancellationToken = default); + + Task GetAuthorHasBlogPostAsync(Guid id, CancellationToken cancellationToken = default); Task HasBlogPostWaitingForReviewAsync(CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs index 72ac2e2662..0c359debcc 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogPostRepository.cs @@ -7,6 +7,7 @@ using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; using Volo.Abp; +using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; using Volo.CmsKit.EntityFrameworkCore; @@ -104,13 +105,33 @@ public class EfCoreBlogPostRepository : EfCoreRepository> GetAuthorsHasBlogPosts(CancellationToken cancellationToken = default) + public async Task> GetAuthorsHasBlogPostsAsync(int skipCount, int maxResultCount, string sorting, string filter, CancellationToken cancellationToken = default) { - return await (await GetDbContextAsync()).BlogPosts - .Where(x => x.Status == BlogPostStatus.Published) - .Select(x => x.Author).Distinct() + return await (await CreateAuthorsQueryableAsync()) + .Skip(skipCount) + .Take(maxResultCount) + .WhereIf(!filter.IsNullOrEmpty(), x => x.UserName.Contains(filter.ToLower())) + .OrderBy(sorting.IsNullOrEmpty() ? nameof(CmsUser.UserName) : sorting) .ToListAsync(GetCancellationToken(cancellationToken)); } + + public async Task GetAuthorsHasBlogPostsCountAsync(string filter, CancellationToken cancellationToken = default) + { + return await (await CreateAuthorsQueryableAsync()) + .WhereIf(!filter.IsNullOrEmpty(), x => x.UserName.Contains(filter.ToLower())) + .CountAsync(GetCancellationToken(cancellationToken)); + } + + public async Task GetAuthorHasBlogPostAsync(Guid id, CancellationToken cancellationToken = default) + { + return await (await CreateAuthorsQueryableAsync()).FirstOrDefaultAsync(x => x.Id == id, GetCancellationToken(cancellationToken)) + ?? throw new EntityNotFoundException(typeof(CmsUser), id); + } + + private async Task> CreateAuthorsQueryableAsync() + { + return (await GetDbContextAsync()).BlogPosts.Select(x => x.Author).Distinct(); + } public virtual async Task HasBlogPostWaitingForReviewAsync(CancellationToken cancellationToken = default) { diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs index da1a789f60..fc89b19cb5 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs @@ -8,6 +8,7 @@ using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; using Volo.Abp; +using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; using Volo.CmsKit.Blogs; @@ -108,7 +109,31 @@ public class MongoBlogPostRepository : MongoDbRepository x.BlogId == blogId && x.Slug.ToLower() == slug, cancellationToken); } - public async Task> GetAuthorsHasBlogPosts(CancellationToken cancellationToken = default) + public async Task> GetAuthorsHasBlogPostsAsync(int skipCount, int maxResultCount, string sorting, string filter, CancellationToken cancellationToken = default) + { + var queryable = (await CreateAuthorsQueryableAsync()) + .Skip(skipCount) + .Take(maxResultCount) + .OrderBy(sorting.IsNullOrEmpty() ? nameof(CmsUser.UserName) : sorting) + .WhereIf(!filter.IsNullOrEmpty(), x => x.UserName.Contains(filter.ToLower())); + + return await AsyncExecuter.ToListAsync(queryable, GetCancellationToken(cancellationToken)); + } + + public async Task GetAuthorsHasBlogPostsCountAsync(string filter, CancellationToken cancellationToken = default) + { + return await AsyncExecuter.CountAsync( + (await CreateAuthorsQueryableAsync()) + .WhereIf(!filter.IsNullOrEmpty(), x => x.UserName.Contains(filter.ToLower()))); + } + + public async Task GetAuthorHasBlogPostAsync(Guid id, CancellationToken cancellationToken = default) + { + return await AsyncExecuter.FirstOrDefaultAsync(await CreateAuthorsQueryableAsync(), x => x.Id == id) + ?? throw new EntityNotFoundException(typeof(CmsUser), id); + } + + private async Task> CreateAuthorsQueryableAsync() { cancellationToken = GetCancellationToken(cancellationToken); @@ -117,7 +142,7 @@ public class MongoBlogPostRepository : MongoDbRepository().AsQueryable(); - var queryable = blogPostQueryable + return blogPostQueryable .Join( usersQueryable, o => o.AuthorId, @@ -125,8 +150,6 @@ public class MongoBlogPostRepository : MongoDbRepository new { blogPost, user }) .Select(s => s.user) .Distinct(); - - return await AsyncExecuter.ToListAsync(queryable, cancellationToken); } public virtual async Task HasBlogPostWaitingForReviewAsync(CancellationToken cancellationToken = default) diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostFilteredPagedAndSortedResultRequestDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostFilteredPagedAndSortedResultRequestDto.cs new file mode 100644 index 0000000000..cb930ea37c --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostFilteredPagedAndSortedResultRequestDto.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Application.Dtos; + +namespace Volo.CmsKit.Public.Blogs; + +public class BlogPostFilteredPagedAndSortedResultRequestDto : PagedAndSortedResultRequestDto +{ + public string Filter { get; set; } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs index 02b6d2a5f4..42161f884c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.CmsKit.Users; +using System; namespace Volo.CmsKit.Public.Blogs; @@ -12,6 +13,8 @@ public interface IBlogPostPublicAppService : IApplicationService Task> GetListAsync([NotNull] string blogSlug, BlogPostGetListInput input); Task GetAsync([NotNull] string blogSlug, [NotNull] string blogPostSlug); - - Task> GetAuthorsHasBlogPostsAsync(); + + Task> GetAuthorsHasBlogPostsAsync(BlogPostFilteredPagedAndSortedResultRequestDto input); + + Task GetAuthorHasBlogPostAsync(Guid id); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs index aa893f41c8..94847fba11 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs @@ -1,4 +1,5 @@ using JetBrains.Annotations; +using System; using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; @@ -15,7 +16,6 @@ public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPub protected IBlogRepository BlogRepository { get; } protected IBlogPostRepository BlogPostRepository { get; } - public BlogPostPublicAppService( IBlogRepository blogRepository, @@ -46,9 +46,20 @@ public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPub ObjectMapper.Map, List>(blogPosts)); } - public virtual async Task> GetAuthorsHasBlogPostsAsync() + public virtual async Task> GetAuthorsHasBlogPostsAsync(BlogPostFilteredPagedAndSortedResultRequestDto input) { - var authors = await BlogPostRepository.GetAuthorsHasBlogPosts(); - return ObjectMapper.Map, List>(authors); + var authors = await BlogPostRepository.GetAuthorsHasBlogPostsAsync(input.SkipCount, input.MaxResultCount, input.Sorting, input.Filter); + var authorDtos = ObjectMapper.Map, List>(authors); + + return new PagedResultDto( + await BlogPostRepository.GetAuthorsHasBlogPostsCountAsync(input.Filter), + authorDtos); + } + + public async Task GetAuthorHasBlogPostAsync(Guid id) + { + var author = await BlogPostRepository.GetAuthorHasBlogPostAsync(id); + + return ObjectMapper.Map(author); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/BlogPostPublicClientProxy.Generated.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/BlogPostPublicClientProxy.Generated.cs index 9cc926515d..b1bbf6be07 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/BlogPostPublicClientProxy.Generated.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/BlogPostPublicClientProxy.Generated.cs @@ -1,6 +1,5 @@ // This file is automatically generated by ABP framework to use MVC Controllers from CSharp using System; -using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Http.Client; @@ -25,7 +24,7 @@ public partial class BlogPostPublicClientProxy : ClientProxyBase> GetListAsync(string blogSlug, BlogPostGetListInput input) { return await RequestAsync>(nameof(GetListAsync), new ClientProxyRequestTypeValue @@ -35,8 +34,19 @@ public partial class BlogPostPublicClientProxy : ClientProxyBase> GetAuthorsHasBlogPostsAsync() + public virtual async Task> GetAuthorsHasBlogPostsAsync(BlogPostFilteredPagedAndSortedResultRequestDto input) + { + return await RequestAsync>(nameof(GetAuthorsHasBlogPostsAsync), new ClientProxyRequestTypeValue + { + { typeof(BlogPostFilteredPagedAndSortedResultRequestDto), input } + }); + } + + public virtual async Task GetAuthorHasBlogPostAsync(Guid id) { - return await RequestAsync>(nameof(GetAuthorsHasBlogPostsAsync)); + return await RequestAsync(nameof(GetAuthorHasBlogPostAsync), new ClientProxyRequestTypeValue + { + { typeof(Guid), id } + }); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.Generated.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.Generated.cs new file mode 100644 index 0000000000..d7354b9e87 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.Generated.cs @@ -0,0 +1,27 @@ +// This file is automatically generated by ABP framework to use MVC Controllers from CSharp +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Http.Client; +using Volo.Abp.Http.Modeling; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Client.ClientProxying; +using Volo.CmsKit.Public.GlobalResources; + +// ReSharper disable once CheckNamespace +namespace Volo.CmsKit.Public.GlobalResources.ClientProxies; + +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(IGlobalResourcePublicAppService), typeof(GlobalResourcePublicClientProxy))] +public partial class GlobalResourcePublicClientProxy : ClientProxyBase, IGlobalResourcePublicAppService +{ + public virtual async Task GetGlobalScriptAsync() + { + return await RequestAsync(nameof(GetGlobalScriptAsync)); + } + + public virtual async Task GetGlobalStyleAsync() + { + return await RequestAsync(nameof(GetGlobalStyleAsync)); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.cs new file mode 100644 index 0000000000..76549aec1e --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/GlobalResourcePublicClientProxy.cs @@ -0,0 +1,7 @@ +// This file is part of GlobalResourcePublicClientProxy, you can customize it here +// ReSharper disable once CheckNamespace +namespace Volo.CmsKit.Public.GlobalResources.ClientProxies; + +public partial class GlobalResourcePublicClientProxy +{ +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json index 0387176b02..d39e795845 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json @@ -7,6 +7,8 @@ "Volo.CmsKit.Public.Tags.TagPublicController": { "controllerName": "TagPublic", "controllerGroupName": "TagPublic", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Public.Tags.TagPublicController", "interfaces": [ { @@ -76,6 +78,8 @@ "Volo.CmsKit.Public.Reactions.ReactionPublicController": { "controllerName": "ReactionPublic", "controllerGroupName": "ReactionPublic", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Public.Reactions.ReactionPublicController", "interfaces": [ { @@ -299,6 +303,8 @@ "Volo.CmsKit.Public.Ratings.RatingPublicController": { "controllerName": "RatingPublic", "controllerGroupName": "RatingPublic", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Public.Ratings.RatingPublicController", "interfaces": [ { @@ -502,6 +508,8 @@ "Volo.CmsKit.Public.Pages.PagesPublicController": { "controllerName": "PagesPublic", "controllerGroupName": "PagesPublic", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Public.Pages.PagesPublicController", "interfaces": [ { @@ -551,6 +559,8 @@ "Volo.CmsKit.Public.Menus.MenuItemPublicController": { "controllerName": "MenuItemPublic", "controllerGroupName": "MenuItemPublic", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Public.Menus.MenuItemPublicController", "interfaces": [ { @@ -575,9 +585,55 @@ } } }, + "Volo.CmsKit.Public.GlobalResources.GlobalResourcePublicController": { + "controllerName": "GlobalResourcePublic", + "controllerGroupName": "GlobalResourcePublic", + "isRemoteService": true, + "apiVersion": null, + "type": "Volo.CmsKit.Public.GlobalResources.GlobalResourcePublicController", + "interfaces": [ + { + "type": "Volo.CmsKit.Public.GlobalResources.IGlobalResourcePublicAppService" + } + ], + "actions": { + "GetGlobalScriptAsync": { + "uniqueName": "GetGlobalScriptAsync", + "name": "GetGlobalScriptAsync", + "httpMethod": "GET", + "url": "api/cms-kit-public/global-resources/script", + "supportedVersions": [], + "parametersOnMethod": [], + "parameters": [], + "returnValue": { + "type": "Volo.CmsKit.Public.GlobalResources.GlobalResourceDto", + "typeSimple": "Volo.CmsKit.Public.GlobalResources.GlobalResourceDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.CmsKit.Public.GlobalResources.IGlobalResourcePublicAppService" + }, + "GetGlobalStyleAsync": { + "uniqueName": "GetGlobalStyleAsync", + "name": "GetGlobalStyleAsync", + "httpMethod": "GET", + "url": "api/cms-kit-public/global-resources/style", + "supportedVersions": [], + "parametersOnMethod": [], + "parameters": [], + "returnValue": { + "type": "Volo.CmsKit.Public.GlobalResources.GlobalResourceDto", + "typeSimple": "Volo.CmsKit.Public.GlobalResources.GlobalResourceDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.CmsKit.Public.GlobalResources.IGlobalResourcePublicAppService" + } + } + }, "Volo.CmsKit.Public.Comments.CommentPublicController": { "controllerName": "CommentPublic", "controllerGroupName": "CommentPublic", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Public.Comments.CommentPublicController", "interfaces": [ { @@ -818,6 +874,8 @@ "Volo.CmsKit.Public.Blogs.BlogPostPublicController": { "controllerName": "BlogPostPublic", "controllerGroupName": "BlogPostPublic", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.CmsKit.Public.Blogs.BlogPostPublicController", "interfaces": [ { @@ -899,9 +957,9 @@ }, { "name": "input", - "typeAsString": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto, Volo.Abp.Ddd.Application.Contracts", - "type": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto", - "typeSimple": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto", + "typeAsString": "Volo.CmsKit.Public.Blogs.BlogPostGetListInput, Volo.CmsKit.Public.Application.Contracts", + "type": "Volo.CmsKit.Public.Blogs.BlogPostGetListInput", + "typeSimple": "Volo.CmsKit.Public.Blogs.BlogPostGetListInput", "isOptional": false, "defaultValue": null } @@ -919,6 +977,30 @@ "bindingSourceId": "Path", "descriptorName": "" }, + { + "nameOnMethod": "input", + "name": "AuthorId", + "jsonName": null, + "type": "System.Guid?", + "typeSimple": "string?", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Sorting", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, { "nameOnMethod": "input", "name": "SkipCount", @@ -942,6 +1024,43 @@ "constraintTypes": null, "bindingSourceId": "ModelBinding", "descriptorName": "input" + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.PagedResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.CmsKit.Public.Blogs.IBlogPostPublicAppService" + }, + "GetAuthorsHasBlogPostsAsyncByInput": { + "uniqueName": "GetAuthorsHasBlogPostsAsyncByInput", + "name": "GetAuthorsHasBlogPostsAsync", + "httpMethod": "GET", + "url": "api/cms-kit-public/blog-posts/authors", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.CmsKit.Public.Blogs.BlogPostFilteredPagedAndSortedResultRequestDto, Volo.CmsKit.Public.Application.Contracts", + "type": "Volo.CmsKit.Public.Blogs.BlogPostFilteredPagedAndSortedResultRequestDto", + "typeSimple": "Volo.CmsKit.Public.Blogs.BlogPostFilteredPagedAndSortedResultRequestDto", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "Filter", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" }, { "nameOnMethod": "input", @@ -954,11 +1073,72 @@ "constraintTypes": null, "bindingSourceId": "ModelBinding", "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "SkipCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "MaxResultCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" } ], "returnValue": { - "type": "Volo.Abp.Application.Dtos.PagedResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + "type": "Volo.Abp.Application.Dtos.PagedResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.CmsKit.Public.Blogs.IBlogPostPublicAppService" + }, + "GetAuthorHasBlogPostAsyncById": { + "uniqueName": "GetAuthorHasBlogPostAsyncById", + "name": "GetAuthorHasBlogPostAsync", + "httpMethod": "GET", + "url": "api/cms-kit-public/blog-posts/authors/{id}", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "id", + "typeAsString": "System.Guid, System.Private.CoreLib", + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "id", + "name": "id", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.CmsKit.Users.CmsUserDto", + "typeSimple": "Volo.CmsKit.Users.CmsUserDto" }, "allowAnonymous": null, "implementFrom": "Volo.CmsKit.Public.Blogs.IBlogPostPublicAppService" diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs index 8a788f7a34..9f43d65766 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs @@ -40,8 +40,15 @@ public class BlogPostPublicController : CmsKitPublicControllerBase, IBlogPostPub [HttpGet] [Route("authors")] - public virtual Task> GetAuthorsHasBlogPostsAsync() + public Task> GetAuthorsHasBlogPostsAsync(BlogPostFilteredPagedAndSortedResultRequestDto input) { - return BlogPostPublicAppService.GetAuthorsHasBlogPostsAsync(); + return BlogPostPublicAppService.GetAuthorsHasBlogPostsAsync(input); + } + + [HttpGet] + [Route("authors/{id}")] + public Task GetAuthorHasBlogPostAsync(Guid id) + { + return BlogPostPublicAppService.GetAuthorHasBlogPostAsync(id); } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml index 496ce7f8c5..709d96182f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml @@ -16,94 +16,133 @@ @inject IMarkdownToHtmlRenderer MarkdownRenderer + +@{ + string dummyImageSource = "https://dummyimage.com/1280x720/a3a3a3/fff.png?text=" + Model.BlogPost.Title; + var isScrollIndexEnabled = GlobalFeatureManager.Instance.IsEnabled(); +} + @section styles{ - - - - + @if (isScrollIndexEnabled) + { + + + + } + + + + } @section scripts{ - - - - -} + @if (isScrollIndexEnabled) + { + + + + + } -@{ - string dummyImageSource = "https://dummyimage.com/1280x720/a3a3a3/fff.png?text=" + Model.BlogPost.Title; + + + + } - - - - -
-

@Model.BlogPost.Title

-

- - @@@Model.BlogPost.Author?.UserName - - @Model.BlogPost.CreationTime -

- - @if(!Model.BlogPost.Content.IsNullOrEmpty()) - { - @Html.Raw(await MarkdownRenderer.RenderAsync(Model.BlogPost.Content)) - } - -

- @if (Model.BlogPost.LastModificationTime != null) - { - @L["LastModification"].Value : @Model.BlogPost.LastModificationTime - } -

-
- - @if (GlobalFeatureManager.Instance.IsEnabled()) - { - if (Model.TagsFeature?.IsEnabled == true) - { - @await Component.InvokeAsync(typeof(TagViewComponent), new - { - entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, - entityId = Model.BlogPost.Id.ToString() - }) - } - } -
-
- - - - @if (GlobalFeatureManager.Instance.IsEnabled()) - { - if (Model.ReactionsFeature?.IsEnabled == true) - { - @await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new + +
+
+ + + + +
+

@Model.BlogPost.Title

+

+ + @@@Model.BlogPost.Author?.UserName + + @Model.BlogPost.CreationTime +

+ @if (!Model.BlogPost.Content.IsNullOrEmpty()) + { + @Html.Raw(await MarkdownRenderer.RenderAsync(Model.BlogPost.Content)) + } + +

+ @if (Model.BlogPost.LastModificationTime != null) + { + @L["LastModification"].Value : @Model.BlogPost.LastModificationTime + } +

+
+ + @if (GlobalFeatureManager.Instance.IsEnabled()) + { + if (Model.TagsFeature?.IsEnabled == true) + { + @await Component.InvokeAsync(typeof(TagViewComponent), new + { + entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, + entityId = Model.BlogPost.Id.ToString() + }) + } + } +
+
+ + + + @if (GlobalFeatureManager.Instance.IsEnabled()) { - entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, - entityId = Model.BlogPost.Id.ToString() - }) - } - } - - - @if (GlobalFeatureManager.Instance.IsEnabled()) - { - if (Model.RatingsFeature?.IsEnabled == true) - { - @await Component.InvokeAsync(typeof(RatingViewComponent), new + if (Model.ReactionsFeature?.IsEnabled == true) + { + @await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new + { + entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, + entityId = Model.BlogPost.Id.ToString() + }) + } + } + + + @if (GlobalFeatureManager.Instance.IsEnabled()) { - entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, - entityId = Model.BlogPost.Id.ToString() - }) - } - } - - -
-
+ if (Model.RatingsFeature?.IsEnabled == true) + { + @await Component.InvokeAsync(typeof(RatingViewComponent), new + { + entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, + entityId = Model.BlogPost.Id.ToString() + }) + } + } + + + + +
+ @if (isScrollIndexEnabled) + { +
+
+
@L["InThisDocument"]
+ + + +
+
+ } + +
@if (GlobalFeatureManager.Instance.IsEnabled()) { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml index dbc0d699ef..060f0c5c95 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml @@ -24,19 +24,21 @@
- - + + @if(Model.SelectedAuthor != null) + { + }
@@ -76,4 +78,4 @@ -
\ No newline at end of file +
diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs index c9dc49931d..c7f667382b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs @@ -20,16 +20,15 @@ public class IndexModel : CmsKitPublicPageModelBase [BindProperty(SupportsGet = true)] public int CurrentPage { get; set; } = 1; - + [BindProperty(SupportsGet = true)] public Guid? AuthorId { get; set; } public PagedResultDto Blogs { get; private set; } public PagerModel PagerModel => new PagerModel(Blogs.TotalCount, Blogs.Items.Count, CurrentPage, PageSize, Request.Path.ToString()); - - [BindProperty(SupportsGet = true)] - public List Authors { get; set; } + + public CmsUserDto SelectedAuthor { get; set; } protected IBlogPostPublicAppService BlogPostPublicAppService { get; } @@ -48,7 +47,10 @@ public class IndexModel : CmsKitPublicPageModelBase MaxResultCount = PageSize, AuthorId = AuthorId }); - - Authors = await BlogPostPublicAppService.GetAuthorsHasBlogPostsAsync(); + + if (AuthorId != null) + { + SelectedAuthor = await BlogPostPublicAppService.GetAuthorHasBlogPostAsync(AuthorId.Value); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogPost.css b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogPost.css index 98c4a3100d..d09be3150d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogPost.css +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogPost.css @@ -20,4 +20,21 @@ span.area-title { } .popover { min-width: 276px; +} + +#scroll-index { + position: sticky; + top: 20px; +} + +#scroll-index .scroll-top-btn.showup{ + display: block; +} + +#scroll-index .scroll-top-btn{ + display: none; + font-size: .85em; + color: #aaa; + text-decoration: none; + padding-left: 18px; } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogpost-scroll-index.js b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogpost-scroll-index.js new file mode 100644 index 0000000000..603649e2c9 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogpost-scroll-index.js @@ -0,0 +1,46 @@ +$(function () { + var $myNav = $('#blog-post-sticky-index'); + var $scrollToTopBtn = $('.scroll-top-btn'); + + window.Toc.helpers.createNavList = function () { + return $(''); + }; + + window.Toc.helpers.createChildNavList = function ($parent) { + var $childList = this.createNavList(); + $parent.append($childList); + return $childList; + }; + + window.Toc.helpers.generateNavEl = function (anchor, text) { + var $a = $(''); + $a.attr('href', '#' + anchor); + $a.text(text); + var $li = $(''); + $li.append($a); + return $li; + }; + + Toc.init($myNav); + + $('body').scrollspy({ + target: $myNav, + }); + + $scrollToTopBtn.click(function () { + $('html, body').animate({scrollTop: 0}, 'fast'); + }); + + // When the user scrolls down 20px from the top of the document, show the button + window.onscroll = function () { + scrollFunction() + }; + + function scrollFunction() { + if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) { + $scrollToTopBtn.addClass('showup'); + } else { + $scrollToTopBtn.removeClass('showup'); + } + } +}); diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/bootstrap-toc.css b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/bootstrap-toc.css new file mode 100644 index 0000000000..b15e18ee85 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/bootstrap-toc.css @@ -0,0 +1,60 @@ +/*! + * Bootstrap Table of Contents v<%= version %> (http://afeld.github.io/bootstrap-toc/) + * Copyright 2015 Aidan Feldman + * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ + +/* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ + +/* All levels of nav */ +nav[data-toggle='toc'] .nav > li > a { + display: block; + padding: 4px 20px; + font-size: 13px; + font-weight: 500; + color: #767676; +} +nav[data-toggle='toc'] .nav > li > a:hover, +nav[data-toggle='toc'] .nav > li > a:focus { + padding-left: 19px; + color: #563d7c; + text-decoration: none; + background-color: transparent; + border-left: 1px solid #563d7c; +} +nav[data-toggle='toc'] .nav-link.active, +nav[data-toggle='toc'] .nav-link.active:hover, +nav[data-toggle='toc'] .nav-link.active:focus { + padding-left: 18px; + font-weight: bold; + color: #563d7c; + background-color: transparent; + border-left: 2px solid #563d7c; +} + +/* Nav: second level (shown on .active) */ +nav[data-toggle='toc'] .nav-link + ul { + display: none; /* Hide by default, but at >768px, show it */ + padding-bottom: 10px; +} + +nav[data-toggle='toc'] .nav .nav > li > a { + padding-top: 1px; + padding-bottom: 1px; + padding-left: 30px; + font-size: 12px; + font-weight: normal; +} +nav[data-toggle='toc'] .nav .nav > li > a:hover, +nav[data-toggle='toc'] .nav .nav > li > a:focus { + padding-left: 29px; +} +nav[data-toggle='toc'] .nav .nav > li > .active, +nav[data-toggle='toc'] .nav .nav > li > .active:hover, +nav[data-toggle='toc'] .nav .nav > li > .active:focus { + padding-left: 28px; + font-weight: 500; +} + +nav[data-toggle='toc'] .nav-link.active + ul { + display: block; +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/bootstrap-toc.js b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/bootstrap-toc.js new file mode 100644 index 0000000000..13a4d1f6a5 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/bootstrap-toc.js @@ -0,0 +1,168 @@ +/*! + * Bootstrap Table of Contents v1.0.0 (http://afeld.github.io/bootstrap-toc/) + * Copyright 2015 Aidan Feldman + * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ +(function ($) { + 'use strict'; + + window.Toc = { + helpers: { + // return all matching elements in the set, or their descendants + findOrFilter: function ($el, selector) { + // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ + // http://stackoverflow.com/a/12731439/358804 + var $descendants = $el.find(selector); + return $el + .filter(selector) + .add($descendants) + .filter(':not([data-toc-skip])'); + }, + + generateUniqueIdBase: function (el) { + var text = $(el).text(); + var anchor = text + .trim() + .toLowerCase() + .replace(/[^A-Za-z0-9]+/g, '-'); + return anchor || el.tagName.toLowerCase(); + }, + + generateUniqueId: function (el) { + var anchorBase = this.generateUniqueIdBase(el); + for (var i = 0; ; i++) { + var anchor = anchorBase; + if (i > 0) { + // add suffix + anchor += '-' + i; + } + // check if ID already exists + if (!document.getElementById(anchor)) { + return anchor; + } + } + }, + + generateAnchor: function (el) { + if (el.id) { + return el.id; + } else { + var anchor = this.generateUniqueId(el); + el.id = anchor; + return anchor; + } + }, + + createNavList: function () { + return $(''); + }, + + createChildNavList: function ($parent) { + var $childList = this.createNavList(); + $parent.append($childList); + return $childList; + }, + + generateNavEl: function (anchor, text) { + var $a = $(''); + $a.attr('href', '#' + anchor); + $a.text(text); + var $li = $('
  • '); + $li.append($a); + return $li; + }, + + generateNavItem: function (headingEl) { + var anchor = this.generateAnchor(headingEl); + var $heading = $(headingEl); + var text = $heading.data('toc-text') || $heading.text(); + return this.generateNavEl(anchor, text); + }, + + // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). + getTopLevel: function ($scope) { + for (var i = 1; i <= 6; i++) { + var $headings = this.findOrFilter($scope, 'h' + i); + if ($headings.length > 1) { + return i; + } + } + + return 1; + }, + + // returns the elements for the top level, and the next below it + getHeadings: function ($scope, topLevel) { + var topSelector = 'h' + topLevel; + + var secondaryLevel = topLevel + 1; + var secondarySelector = 'h' + secondaryLevel; + + return this.findOrFilter( + $scope, + topSelector + ',' + secondarySelector + ); + }, + + getNavLevel: function (el) { + return parseInt(el.tagName.charAt(1), 10); + }, + + populateNav: function ($topContext, topLevel, $headings) { + var $context = $topContext; + var $prevNav; + + var helpers = this; + $headings.each(function (i, el) { + var $newNav = helpers.generateNavItem(el); + var navLevel = helpers.getNavLevel(el); + + // determine the proper $context + if (navLevel === topLevel) { + // use top level + $context = $topContext; + } else if ($prevNav && $context === $topContext) { + // create a new level of the tree and switch to it + $context = helpers.createChildNavList($prevNav); + } // else use the current $context + + $context.append($newNav); + + $prevNav = $newNav; + }); + }, + + parseOps: function (arg) { + var opts; + if (arg.jquery) { + opts = { + $nav: arg, + }; + } else { + opts = arg; + } + opts.$scope = opts.$scope || $(document.body); + return opts; + }, + }, + + // accepts a jQuery object, or an options object + init: function (opts) { + opts = this.helpers.parseOps(opts); + + // ensure that the data attribute is in place for styling + opts.$nav.attr('data-toggle', 'toc'); + + var $topContext = this.helpers.createChildNavList(opts.$nav); + var topLevel = this.helpers.getTopLevel(opts.$scope); + var $headings = this.helpers.getHeadings(opts.$scope, topLevel); + this.helpers.populateNav($topContext, topLevel, $headings); + }, + }; + + $(function () { + $('nav[data-toggle="toc"]').each(function (i, el) { + var $nav = $(el); + Toc.init($nav); + }); + }); +})(jQuery); diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/wwwroot/client-proxies/cms-kit-proxy.js b/modules/cms-kit/src/Volo.CmsKit.Public.Web/wwwroot/client-proxies/cms-kit-proxy.js index a135611cac..6b2e3f1b04 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/wwwroot/client-proxies/cms-kit-proxy.js +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/wwwroot/client-proxies/cms-kit-proxy.js @@ -112,6 +112,28 @@ })(); + // controller volo.cmsKit.public.globalResources.globalResourcePublic + + (function(){ + + abp.utils.createNamespace(window, 'volo.cmsKit.public.globalResources.globalResourcePublic'); + + volo.cmsKit.public.globalResources.globalResourcePublic.getGlobalScript = function(ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/cms-kit-public/global-resources/script', + type: 'GET' + }, ajaxParams)); + }; + + volo.cmsKit.public.globalResources.globalResourcePublic.getGlobalStyle = function(ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/cms-kit-public/global-resources/style', + type: 'GET' + }, ajaxParams)); + }; + + })(); + // controller volo.cmsKit.public.comments.commentPublic (function(){ diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs index 37ec33b83c..ccbac2d80f 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogPostRepository_Test.cs @@ -155,7 +155,7 @@ public abstract class BlogPostRepository_Test : CmsKitTestBase