Browse Source

Merge remote-tracking branch 'upstream/master' into Translate

pull/702/head
maliming 8 years ago
parent
commit
284205a775
  1. 40
      abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml
  2. 3
      abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml
  3. 2758
      abp_io/src/Volo.AbpWebSite.Web/package-lock.json
  4. 2
      abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css
  5. 2
      abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css
  6. 2
      abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss
  7. 2
      common.props
  8. 138
      docs/en/AspNetCore/Auto-API-Controllers.md
  9. 75
      docs/en/AspNetCore/Bundling-Minification.md
  10. 153
      docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md
  11. 2
      docs/en/Getting-Started-AspNetCore-Application.md
  12. 2
      docs/en/Getting-Started-AspNetCore-MVC-Template.md
  13. 90
      docs/en/Index.md
  14. 33
      docs/en/Module-Development-Basics.md
  15. 475
      docs/en/Modules/Docs.md
  16. 26
      docs/en/Modules/Index.md
  17. 2
      docs/en/Tutorials/AspNetCore-Mvc/Part-I.md
  18. 18
      docs/en/docs-nav.json
  19. BIN
      docs/en/images/bookstore-apis.png
  20. BIN
      docs/en/images/docs-module_download-new-abp-project.png
  21. BIN
      docs/en/images/docs-module_download-sample-navigation-menu.png
  22. BIN
      docs/en/images/docs-module_solution-explorer.png
  23. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs
  24. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSize.cs
  25. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSizeExtensions.cs
  26. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelper.cs
  27. 14
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelperServiceBase.cs
  28. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelper.cs
  29. 14
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelperService.cs
  30. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpLinkButtonTagHelper.cs
  31. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/IButtonTagHelperBase.cs
  32. 19
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelper.cs
  33. 23
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelperService.cs
  34. 15
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundType.cs
  35. 15
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBorderColorType.cs
  36. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelper.cs
  37. 14
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelperService.cs
  38. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardImageTagHelper.cs
  39. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelper.cs
  40. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelperService.cs
  41. 19
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelper.cs
  42. 23
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelperService.cs
  43. 16
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorType.cs
  44. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelper.cs
  45. 14
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs
  46. 9
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelper.cs
  47. 46
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelperService.cs
  48. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs
  49. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelper.cs
  50. 14
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelperService.cs
  51. 15
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormControlSize.cs
  52. 7
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs
  53. 155
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
  54. 35
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs
  55. 9
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpReadonlyInputType.cs
  56. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs
  57. 197
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
  58. 18
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/FormControlSize.cs
  59. 18
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputInfoText.cs
  60. 18
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/Placeholder.cs
  61. 7
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs
  62. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelper.cs
  63. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelper.cs
  64. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelperService.cs
  65. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs
  66. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs
  67. 10
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImagePosition.cs
  68. 23
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelper.cs
  69. 68
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelperService.cs
  70. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelper.cs
  71. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs
  72. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelper.cs
  73. 9
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelperService.cs
  74. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelper.cs
  75. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelperService.cs
  76. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressBarTagHelper.cs
  77. 16
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressBarTagHelperService.cs
  78. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressGroupTagHelper.cs
  79. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressGroupTagHelperService.cs
  80. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressTagHelper.cs
  81. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Table/AbpTableStyleTagHelper.cs
  82. 12
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Table/AbpTableStyleTagHelperService.cs
  83. 34
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tooltip/AbpTooltipTagHelperService.cs
  84. 31
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorOptions.cs
  85. 17
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleManager.cs
  86. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Clipboard/ClipboardScriptBundleContributor.cs
  87. 16
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Prismjs/PrismjsScriptBundleContributor.cs
  88. 13
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Prismjs/PrismjsStyleBundleContributor.cs
  89. 12
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  90. 4
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention.cs
  91. 13
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalControllerSetting.cs
  92. 4
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultHttpExceptionStatusCodeFinder.cs
  93. 2
      framework/src/Volo.Abp.Core/System/Collections/Generic/AbpCollectionExtensions.cs
  94. 35
      framework/src/Volo.Abp.Core/Volo/Abp/IO/DirectoryHelper.cs
  95. 35
      framework/src/Volo.Abp.Core/Volo/Abp/IO/FileHelper.cs
  96. 4
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IEntity.cs
  97. 1
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs
  98. 255
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Alerts.cshtml
  99. 207
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Badges.cshtml
  100. 223
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Borders.cshtml

40
abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml

@ -195,34 +195,34 @@
</p> </p>
</div> </div>
<div class="row justify-content-md-center"> <div class="row justify-content-md-center">
<div class="col-md"> <div class="col-lg">
<div class="code-block"> <div class="code-block">
<pre class="line-numbers"> <pre class="line-numbers">
<code class="language-html"> <code class="language-html">
&lt;abp-card&gt; &lt;abp-card&gt;
&lt;img abp-card-image="Top" src="~/images/my-dog.png" /&gt; &lt;img abp-card-image="Top" src="~/images/my-dog.png" /&gt;
&lt;abp-card-body&gt; &lt;abp-card-body&gt;
&lt;abp-card-title&gt;Card title&lt;/abp-card-title&gt; &lt;abp-card-title&gt;Card title&lt;/abp-card-title&gt;
&lt;abp-card-text&gt; &lt;abp-card-text&gt;
&lt;p&gt; &lt;p&gt;
This is a sample card component built by ABP bootstrap This is a sample card component built by ABP bootstrap
card tag helper. ABP has tag helper wrappers for most of card tag helper. ABP has tag helper wrappers for most of
the bootstrap components. the bootstrap components.
&lt;/p&gt; &lt;/p&gt;
&lt;/abp-card-text&gt; &lt;/abp-card-text&gt;
&lt;a abp-button="Primary" href="#"&gt;Go somewhere &amp;rarr;&lt;/a&gt; &lt;a abp-button="Primary" href="#"&gt;Go somewhere &amp;rarr;&lt;/a&gt;
&lt;/abp-card-body&gt; &lt;/abp-card-body&gt;
&lt;/abp-card&gt; &lt;/abp-card&gt;
</code> </code>
</pre> </pre>
</div> </div>
</div> </div>
<div class="col-md-1"> <div class="col-lg-1">
<span class="code-arrow"> <span class="code-arrow">
<i class="fa fa-long-arrow-right"></i> <i class="fa fa-long-arrow-right"></i>
</span> </span>
</div> </div>
<div class="col-md text-dark"> <div class="col-lg text-dark">
<div class="abp-browser"> <div class="abp-browser">
<div class="browser-container"> <div class="browser-container">
<div class="browser-row"> <div class="browser-row">
@ -265,7 +265,7 @@
</div> </div>
<div class="row justify-content-md-center"> <div class="row justify-content-md-center">
<div class="col-md"> <div class="col-lg">
<div class="code-block"> <div class="code-block">
<pre class="line-numbers" data-line=""> <pre class="line-numbers" data-line="">
<code class="language-xml"> <code class="language-xml">
@ -300,12 +300,12 @@ public class PersonModel
</pre> </pre>
</div> </div>
</div> </div>
<div class="col-md-1"> <div class="col-lg-1">
<span class="code-arrow"> <span class="code-arrow">
<i class="fa fa-long-arrow-right"></i> <i class="fa fa-long-arrow-right"></i>
</span> </span>
</div> </div>
<div class="col-md"> <div class="col-lg">
<div class="abp-browser"> <div class="abp-browser">
<div class="browser-container"> <div class="browser-container">
<div class="browser-row"> <div class="browser-row">

3
abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml

@ -26,8 +26,7 @@
<a class="nav-link" href="https://github.com/abpframework/abp/" target="_blank">Github</a> <a class="nav-link" href="https://github.com/abpframework/abp/" target="_blank">Github</a>
</li> </li>
<li class="for-mobile"> <li class="for-mobile">
<button type="button" class="close close-mmenu" aria-label="Close"> <button type="button" class="close close-mmenu" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button> </button>
</li> </li>
</ul> </ul>

2758
abp_io/src/Volo.AbpWebSite.Web/package-lock.json

File diff suppressed because it is too large

2
abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css

@ -600,7 +600,7 @@ span.code-arrow {
.docs-page .docs-page-index { .docs-page .docs-page-index {
display: none; } } display: none; } }
@media (max-width: 767px) { @media (max-width: 992px) {
body { body {
font-size: 14px; } font-size: 14px; }
.for-mobile { .for-mobile {

2
abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css

File diff suppressed because one or more lines are too long

2
abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss

@ -3,7 +3,7 @@
@import "footer.scss"; @import "footer.scss";
@import "home.scss"; @import "home.scss";
@import "docs.scss"; @import "docs.scss";
@media (max-width: 767px) { @media (max-width: 992px) {
@import "responsive.scss"; @import "responsive.scss";
} }

2
common.props

@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Version>0.9.0</Version> <Version>0.10.0</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn> <NoWarn>$(NoWarn);CS1591</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl> <PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io</PackageProjectUrl> <PackageProjectUrl>https://abp.io</PackageProjectUrl>

138
docs/en/AspNetCore/Auto-API-Controllers.md

@ -0,0 +1,138 @@
# Auto API Controllers
Once you create an [application service](Application-Services.md), you generally want to create an API controller to expose this service as an HTTP (REST) API endpoint. A typical API controller does nothing but redirects method calls to the application service and configures the REST API using attributes like [HttpGet], [HttpPost], [Route]... etc.
ABP can **automagically** configures your application services as MVC API Controllers by convention. Most of time you don't care about its detailed configuration, but it's possible fully customize it.
## Configuration
Basic configuration is simple. Just configure `AbpAspNetCoreMvcOptions` and use `ConventionalControllers.Create` method as shown below:
````csharp
[DependsOn(BookStoreApplicationModule)]
public class BookStoreWebModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly);
});
}
}
````
This example code configures all the application services in the assembly containing the class `BookStoreApplicationModule`. The figure below shows the resulting API on the [Swagger UI](https://swagger.io/tools/swagger-ui/).
![bookstore-apis](../images/bookstore-apis.png)
### Examples
Some example method names and the corresponding routes calculated by convention:
| Service Method Name | HTTP Method | Route |
| ----------------------------------------------------- | ----------- | -------------------------- |
| GetAsync(Guid id) | GET | /api/app/book/{id} |
| GetListAsync() | GET | /api/app/book |
| CreateAsync(CreateBookDto input) | POST | /api/app/book |
| UpdateAsync(Guid id, UpdateBookDto input) | PUT | /api/app/book/{id} |
| DeleteAsync(Guid id) | DELETE | /api/app/book/{id} |
| GetEditorsAsync(Guid id) | GET | /api/app/book/{id}/editors |
| CreateEditorAsync(Guid id, BookEditorCreateDto input) | POST | /api/app/book/{id}/editor |
### HTTP Method
ABP uses a naming convention while determining the HTTP method for a service method (action):
- **Get**: Used if the method name starts with 'GetList', 'GetAll' or 'Get'.
- **Put**: Used if the method name starts with 'Put' or 'Update'.
- **Delete**: Used if the method name starts with 'Delete' or 'Remove'.
- **Post**: Used if the method name starts with 'Create', 'Add', 'Insert' or 'Post'.
- **Patch**: Used if the method name starts with 'Patch'.
- Otherwise, **Post** is used **by default**.
If you need to customize HTTP method for a particular method, then you can use one of the standard ASP.NET Core attributes ([HttpPost], [HttpGet], [HttpPut]... etc.). This requires to add [Microsoft.AspNetCore.Mvc.Core](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Core) nuget package to your project that contains the service.
### Route
Route is calculated based on some conventions:
* It always starts with '**/api**'.
* Continues with a **route path**. Default value is '**/app**' and can be configured as like below:
````csharp
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.RootPath = "volosoft/book-store";
});
});
````
Then the route for getting a book will be '**/api/volosoft/book-store/book/{id}**'. This sample uses two-level root path, but you generally use a single level depth.
* Continues with the **normalized controller/service name**. Normalization removes 'AppService', 'ApplicationService' and 'Service' postfixes and converts it to **camelCase**. If your application service class name is 'BookAppService' then it becomes only '/book'.
* If you want to customize naming, then set the `UrlControllerNameNormalizer` option. It's a func delegate which allows you to determine the name per controller/service.
* If the method has an '**id**' parameter then it adds '**/{id}**' ro the route.
* Then it adds the action name if necessary. Action name is obtained from the method name on the service and normalized by;
* Removing '**Async**' postfix. If the method name is 'GetPhonesAsync' then it becomes 'GetPhones'.
* Removing **HTTP method prefix**. 'GetList', 'GetAll', 'Get', 'Put', 'Update', 'Delete', 'Remove', 'Create', 'Add', 'Insert', 'Post' and 'Patch' prefixes are removed based on the selected HTTP method. So, 'GetPhones' becomes 'Phones' since 'Get' prefix is a duplicate for a GET request.
* Converting the result to **camelCase**.
* If the resulting action name is **empty** then it's not added to the route. If it's not empty, it's added to the route (like '/phones'). For 'GetAllAsync' method name it will be empty, for 'GetPhonesAsync' method name is will be 'phones'.
* Normalization can be customized by setting the `UrlActionNameNormalizer` option. It's an action delegate that is called for every method.
* If there is another parameter with 'Id' postfix, then it's also added to the route as the final route segment (like '/phoneId').
## Service Selection
Creating conventional HTTP API controllers are not unique to application services actually.
### IRemoteService Interface
If a class implements the `IRemoteService` interface then it's automatically selected to be a conventional API controller. Since application services inherently implement it, they are considered as natural API controllers.
### RemoteService Attribute
`RemoteService` attribute can be used to mark a class as a remote service or disable for a particular class that inherently implements the `IRemoteService` interface. Example:
````csharp
[RemoteService(IsEnabled = false)] //or simply [RemoteService(false)]
public class PersonAppService : ApplicationService
{
}
````
### TypePredicate Option
You can further filter classes to become an API controller by providing the `TypePedicate` option:
````csharp
services.Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.TypePredicate = type => { return true; };
});
});
````
Instead of returning `true` for every type, you can check it and return `false` if you don't want to expose this type as an API controller.
## API Explorer
API Exploring a service that makes possible to investigate API structure by the clients. Swagger uses it to create a documentation and test UI for an endpoint.
API Explorer is automatically enabled for conventional HTTP API controllers by default. Use `RemoteService` attribute to control it per class or method level. Example:
````csharp
[RemoteService(IsMetadataEnabled = false)]
public class PersonAppService : ApplicationService
{
}
````
Disabled `IsMetadataEnabled` which hides this service from API explorer and it will not be discoverable. However, it still can be usable for the clients know the exact API path/route.

75
docs/en/AspNetCore/Bundling-Minification.md

@ -1,5 +1,5 @@
## ASP.NET Core MVC Bundling & Minification # ASP.NET Core MVC Bundling & Minification
There are many ways of bundling & minification of client side resources (JavaScript and CSS files). Most common ways are: There are many ways of bundling & minification of client side resources (JavaScript and CSS files). Most common ways are:
@ -8,7 +8,7 @@ There are many ways of bundling & minification of client side resources (JavaScr
ABP offers a simple, dynamic, powerful, modular and built-in way. ABP offers a simple, dynamic, powerful, modular and built-in way.
### Volo.Abp.AspNetCore.Mvc.UI.Bundling Package ## Volo.Abp.AspNetCore.Mvc.UI.Bundling Package
> This package is already installed by default with the startup templates. So, most of the time, you don't need to install it manually. > This package is already installed by default with the startup templates. So, most of the time, you don't need to install it manually.
@ -34,7 +34,7 @@ namespace MyCompany.MyProject
} }
```` ````
### Razor Bundling Tag Helpers ## Razor Bundling Tag Helpers
The simplest way of creating a bundle is to use `abp-script-bundle` or `abp-style-bundle` tag helpers. Example: The simplest way of creating a bundle is to use `abp-script-bundle` or `abp-style-bundle` tag helpers. Example:
@ -54,7 +54,7 @@ This bundle defines a style bundle with a **unique name**: `MyGlobalBundle`. It'
* The bundle files may be **physical** files or [**virtual/embedded** files](../Virtual-File-System.md). * The bundle files may be **physical** files or [**virtual/embedded** files](../Virtual-File-System.md).
* ABP automatically adds **version query string** to the bundle file URL to prevent browsers from caching when the bundle is being updated. (like ?_v=67872834243042 - generated from last change date of the related files). The versioning works even if the bundle files are individually added to the page (on the development environment). * ABP automatically adds **version query string** to the bundle file URL to prevent browsers from caching when the bundle is being updated. (like ?_v=67872834243042 - generated from last change date of the related files). The versioning works even if the bundle files are individually added to the page (on the development environment).
#### Importing The Bundling Tag Helpers ### Importing The Bundling Tag Helpers
> This is already imported by default with the startup templates. So, most of the time, you don't need to add it manually. > This is already imported by default with the startup templates. So, most of the time, you don't need to add it manually.
@ -64,7 +64,7 @@ In order to use bundle tag helpers, you need to add it into your `_ViewImports.c
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling @addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
```` ````
#### Unnamed Bundles ### Unnamed Bundles
The `name` is **optional** for the razor bundle tag helpers. If you don't define a name, it's automatically **calculated** based on the used bundle file names (they are **concatenated** and **hashed**). Example: The `name` is **optional** for the razor bundle tag helpers. If you don't define a name, it's automatically **calculated** based on the used bundle file names (they are **concatenated** and **hashed**). Example:
@ -90,7 +90,7 @@ Advantages of **named** bundles:
* Other **modules can contribute** to the bundle by its name (see the sections below). * Other **modules can contribute** to the bundle by its name (see the sections below).
#### Single File ### Single File
If you need to just add a single file to the page, you can use the `abp-script` or `abp-style` tag without a wrapping in the `abp-script-bundle` or `abp-style-bundle` tag. Example: If you need to just add a single file to the page, you can use the `abp-script` or `abp-style` tag without a wrapping in the `abp-script-bundle` or `abp-style-bundle` tag. Example:
@ -100,11 +100,11 @@ If you need to just add a single file to the page, you can use the `abp-script`
The bundle name will be *scripts.my-scripts* for the example above ("/" is replaced by "."). All bundling features are work as expected for single file bundles too. The bundle name will be *scripts.my-scripts* for the example above ("/" is replaced by "."). All bundling features are work as expected for single file bundles too.
### Bundling Options ## Bundling Options
If you need to use same bundle in **multiple pages** or want to use some more **powerful features**, you can configure bundles **by code** in your [module](../Module-Development-Basics.md) class. If you need to use same bundle in **multiple pages** or want to use some more **powerful features**, you can configure bundles **by code** in your [module](../Module-Development-Basics.md) class.
#### Creating A New Bundle ### Creating A New Bundle
Example usage: Example usage:
@ -141,10 +141,9 @@ After defining such a bundle, it can be included into a page using the same tag
This time, no file defined in the tag helper definition because the bundle files are defined by the code. This time, no file defined in the tag helper definition because the bundle files are defined by the code.
#### Configuring An Existing Bundle ### Configuring An Existing Bundle
ABP supports [modularity](../Module-Development-Basics.md) for bundling as well. A module can modify an existing bundle that is created by a dependant module. ABP supports [modularity](../Module-Development-Basics.md) for bundling as well. A module can modify an existing bundle that is created by a dependant module. Example:
Example:
````C# ````C#
[DependsOn(typeof(MyWebModule))] [DependsOn(typeof(MyWebModule))]
@ -168,7 +167,7 @@ public class MyWebExtensionModule : AbpModule
> It's not possible to configure unnamed bundle tag helpers by code, because their name are not known at the development time. It's suggested to always use a name for a bundle tag helper. > It's not possible to configure unnamed bundle tag helpers by code, because their name are not known at the development time. It's suggested to always use a name for a bundle tag helper.
### Bundle Contributors ## Bundle Contributors
Adding files to an existing bundle seems useful. What if you need to **replace** a file in the bundle or you want to **conditionally** add files? Defining a bundle contributor provides extra power for such cases. Adding files to an existing bundle seems useful. What if you need to **replace** a file in the bundle or you want to **conditionally** add files? Defining a bundle contributor provides extra power for such cases.
@ -187,7 +186,7 @@ public class MyExtensionGlobalStyleContributor : BundleContributor
} }
```` ````
Then you can use this contributor as below: Then you can use this contributor as like below:
````C# ````C#
services.Configure<BundlingOptions>(options => services.Configure<BundlingOptions>(options =>
@ -200,8 +199,9 @@ services.Configure<BundlingOptions>(options =>
}); });
```` ````
Contributors can also be used in the bundle tag helpers. > You can also add contributors while creating a new bundle.
Example:
Contributors can also be used in the bundle tag helpers. Example:
````xml ````xml
<abp-style-bundle> <abp-style-bundle>
@ -213,7 +213,7 @@ Example:
`abp-style` and `abp-script` tags can get `type` attributes (instead of `src` attributes) as shown in this sample. When you add a bundle contributor, its dependencies are also automatically added to the bundle. `abp-style` and `abp-script` tags can get `type` attributes (instead of `src` attributes) as shown in this sample. When you add a bundle contributor, its dependencies are also automatically added to the bundle.
#### Contributor Dependencies ### Contributor Dependencies
A bundle contributor can have one or more dependencies to other contributors. A bundle contributor can have one or more dependencies to other contributors.
Example: Example:
@ -230,11 +230,40 @@ When a bundle contributor is added, its dependencies are **automatically and rec
Creating contributors and defining dependencies is a way of organizing bundle creation across different modules. Creating contributors and defining dependencies is a way of organizing bundle creation across different modules.
#### Accessing to the IServiceProvider ### Contributor Extensions
In some advanced scenarios, you may want to do some additional configuration whenever a bundle contributor is used. Contributor extensions works seamlessly when the extended contributor is used.
The example below adds some styles for prism.js library:
````csharp
public class MyPrismjsStyleExtension : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/prismjs/plugins/toolbar/prism-toolbar.css");
}
}
````
Then you can configure `BundleContributorOptions` to extend existing `PrismjsStyleBundleContributor`.
````csharp
Configure<BundleContributorOptions>(options =>
{
options
.Extensions<PrismjsStyleBundleContributor>()
.Add<MyPrismjsStyleExtension>();
});
````
Whenever `PrismjsStyleBundleContributor` is added into a bundle, `MyPrismjsStyleExtension` will also be automatically added.
### Accessing to the IServiceProvider
While it is rarely needed, `BundleConfigurationContext` has a `ServiceProvider` property that you can resolve service dependencies inside the `ConfigureBundle` method. While it is rarely needed, `BundleConfigurationContext` has a `ServiceProvider` property that you can resolve service dependencies inside the `ConfigureBundle` method.
#### Standard Package Contributors ### Standard Package Contributors
Adding a specific NPM package resource (js, css files) into a bundle is pretty straight forward for that package. For example you always add the `bootstrap.css` file for the bootstrap NPM package. Adding a specific NPM package resource (js, css files) into a bundle is pretty straight forward for that package. For example you always add the `bootstrap.css` file for the bootstrap NPM package.
@ -255,7 +284,7 @@ Using the built-in contributors for standard packages;
* Prevents multiple modules adding the **duplicate the files**. * Prevents multiple modules adding the **duplicate the files**.
* Manages **dependencies recursively** (adds dependencies of dependencies, if necessary). * Manages **dependencies recursively** (adds dependencies of dependencies, if necessary).
##### Volo.Abp.AspNetCore.Mvc.UI.Packages Package #### Volo.Abp.AspNetCore.Mvc.UI.Packages Package
> This package is already installed by default in the startup templates. So, most of the time, you don't need to install it manually. > This package is already installed by default in the startup templates. So, most of the time, you don't need to install it manually.
@ -282,7 +311,7 @@ namespace MyCompany.MyProject
} }
```` ````
#### Bundle Inheritance ### Bundle Inheritance
In some specific cases, it may be needed to create a **new** bundle **inherited** from other bundle(s). Inheriting from a bundle (recursively) inherits all files/contributors of that bundle. Then the derived bundle can add or modify files/contributors **without modifying** the original bundle. In some specific cases, it may be needed to create a **new** bundle **inherited** from other bundle(s). Inheriting from a bundle (recursively) inherits all files/contributors of that bundle. Then the derived bundle can add or modify files/contributors **without modifying** the original bundle.
Example: Example:
@ -302,11 +331,11 @@ services.Configure<BundlingOptions>(options =>
}); });
```` ````
### Themes ## Themes
Themes uses the standard package contributors to add library resources to page layouts. Themes may also define some standard/global bundles, so any module can contribute to these standard/global bundles. See the [theming documentation](Theming.md) for more. Themes uses the standard package contributors to add library resources to page layouts. Themes may also define some standard/global bundles, so any module can contribute to these standard/global bundles. See the [theming documentation](Theming.md) for more.
### Best Practices & Suggestions ## Best Practices & Suggestions
It's suggested to define multiple bundles for an application, each one is used for different purposes. It's suggested to define multiple bundles for an application, each one is used for different purposes.
@ -317,7 +346,7 @@ It's suggested to define multiple bundles for an application, each one is used f
Establish a balance between performance, network bandwidth usage and count of many bundles. Establish a balance between performance, network bandwidth usage and count of many bundles.
### See Also ## See Also
* [Client Side Package Management](Client-Side-Package-Management.md) * [Client Side Package Management](Client-Side-Package-Management.md)
* [Theming](Theming.md) * [Theming](Theming.md)

153
docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md

@ -0,0 +1,153 @@
# Dynamic C# API Clients
ABP can dynamically create C# API client proxies to call remote HTTP services (REST APIs). In this way, you don't need to deal with `HttpClient` and other low level HTTP features to call remote services and get results.
## Service Interface
Your service/controller should implement an interface that is shared between the server and the client. So, first define a service interface in a shared library project. Example:
````csharp
public interface IBookService : IApplicationService
{
Task<List<BookDto>> GetListAsync();
}
````
Your interface should implement the `IRemoteService` interface. Since the `IApplicationService` inherits the `IRemoteService` interface, the `IBookService` above satisfies this condition.
Implement this class in your service application. You can use [auto API controller system](Auto-API-Controllers.md) to expose the service as a REST API endpoint.
## Client Proxy Generation
First, add [Volo.Abp.Http.Client](https://www.nuget.org/packages/Volo.Abp.Http.Client) nuget package to your client project:
````
Install-Package Volo.Abp.Http.Client
````
Then add `AbpHttpClientModule` dependency to your module:
````csharp
[DependsOn(typeof(AbpHttpClientModule))] //add the dependency
public class MyClientAppModule : AbpModule
{
}
````
Now, it's ready to create the client proxies. Example:
````csharp
[DependsOn(
typeof(AbpHttpClientModule), //used to create client proxies
typeof(BookStoreApplicationModule) //contains the application service interfaces
)]
public class MyClientAppModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//Configure remote end point
context.Services.Configure<RemoteServiceOptions>(options =>
{
options.RemoteServices.Default =
new RemoteServiceConfiguration("http://localhost:53929/");
});
//Create dynamic client proxies
context.Services.AddHttpClientProxies(
typeof(BookStoreApplicationModule).Assembly
);
}
}
````
`RemoteServiceOptions` is used to configure endpoints for remote services (This example sets the default endpoint while you can have different service endpoints used by different clients. See the "Multiple Remote Service Endpoint" section).
`AddHttpClientProxies` method gets an assembly, finds all service interfaces in the given assembly, creates and registers proxy classes.
## Usage
It's straightforward to use. Just inject the service interface in the client application code:
````csharp
public class MyService : ITransientDependency
{
private readonly IBookService _bookService;
public MyService(IBookService bookService)
{
_bookService = bookService;
}
public async Task DoIt()
{
var books = await _bookService.GetListAsync();
foreach (var book in books)
{
Console.WriteLine($"[BOOK {book.Id}] Name={book.Name}");
}
}
}
````
This sample injects the `IBookService` service interface defined above. The dynamic client proxy implementation makes an HTTP call whenever a service method is called by the client.
## Configuration Details
### RemoteServiceOptions
While you can configure `RemoteServiceOptions` as the example shown above, you can let it to read from your `appsettings.json` file. Add a `RemoteServices` section to your `appsettings.json` file:
````json
{
"RemoteServices": {
"Default": {
"BaseUrl": "http://localhost:53929/"
}
}
}
````
Then you can pass your `IConfigurationRoot` instance directly to the `Configure<RemoteServiceOptions>()` method as shown below:
````csharp
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
context.Services.Configure<RemoteServiceOptions>(configuration);
````
This approach is useful since it's easy to change the configuration later without touching to the code.
#### Multiple Remote Service Endpoint
The examples above have configured the "Default" remote service endpoint. You may have different endpoints for different services (as like in a microservice approach where each microservice has different endpoint). In this case, you can add other endpoints to your configuration file:
````json
{
"RemoteServices": {
"Default": {
"BaseUrl": "http://localhost:53929/"
},
"BookStore": {
"BaseUrl": "http://localhost:48392/"
}
}
}
````
See the next section to learn how to use this new endpoint.
### AddHttpClientProxies Method
`AddHttpClientProxies` method can get an additional parameter for the remote service name. Example:
````csharp
context.Services.AddHttpClientProxies(
typeof(BookStoreApplicationModule).Assembly,
remoteServiceName: "BookStore"
);
````
`remoteServiceName` parameter matches the service endpoint configured via `RemoteServiceOptions`. If the `BookStore` endpoint is not defined then it fallbacks to the `Default` endpoint.

2
docs/en/Getting-Started-AspNetCore-Application.md

@ -1,6 +1,6 @@
# Getting Started ABP With AspNet Core MVC Web Application # Getting Started ABP With AspNet Core MVC Web Application
This tutorial explains how to start ABP from scratch with minimal dependencies. You generally want to start with a **[startup template](https://abp.io/Templates)**. This tutorial explains how to start ABP from scratch with minimal dependencies. You generally want to start with the **[startup template](Getting-Started-AspNetCore-MVC-Template.md)**.
## Create A New Project ## Create A New Project

2
docs/en/Getting-Started-AspNetCore-MVC-Template.md

@ -1,5 +1,7 @@
## ASP.NET Core MVC Template ## ASP.NET Core MVC Template
This tutorials explains how to create a new ASP.NET Core MVC web application using the startup template, configure and run it.
### Creating a new project ### Creating a new project
Go to [the template creation page](https://abp.io/Templates), enter a project name and create your project as shown below: Go to [the template creation page](https://abp.io/Templates), enter a project name and create your project as shown below:

90
docs/en/Index.md

@ -1,64 +1,30 @@
# ABP Documentation # ABP Documentation
* Getting Started ABP is an **open source application framework** focused on ASP.NET Core based web application development, but also supports developing other types of applications.
* From Startup Templates
* [ASP.NET Core MVC Template](Getting-Started-AspNetCore-MVC-Template.md) Explore the left navigation menu to deep dive in the documentation.
* From Empty Projects
* [With Console Application](Getting-Started-Console-Application.md) ## Project Status
* [With ASP.NET Core Web Application](Getting-Started-AspNetCore-Application.md)
* Tutorials ABP is the **next generation** of the open source [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework. It's currently in early preview stage and not ready to use in production. The documentation is in progress and currently is very incomplete.
* Application Development
* [With ASP.NET Core MVC](Tutorials/AspNetCore-Mvc/Part-I.md) For short-term and production applications, it's suggested to use the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework which is feature rich, mature, maintained and up-to-date.
* Fundamentals
* [Dependency Injection](Dependency-Injection.md) ## Getting Started
* [AutoFac Integration](Autofac-Integration.md)
* [Virtual File System](Virtual-File-System.md) Easiest way to start a new project with ABP is to use the Startup templates:
* [Localization](Localization.md)
* [Exception Handling](Exception-Handling.md) * [ASP.NET Core MVC Template](Getting-Started-AspNetCore-MVC-Template.md)
* Validation
* Authorization If you want to start from scratch (with an empty project) then manually install the ABP framework, use the following tutorials:
* Caching
* Auditing * [Console Application](Getting-Started-Console-Application.md)
* Setting Management * [ASP.NET Core Web Application](Getting-Started-AspNetCore-Application.md)
* Object to Object Mapping
* AutoMapper Integration ## Source Code
* Events
* Event Bus (local) ABP is being developed on GitHub. See [the source code](https://github.com/abpframework/abp).
* Distributed Event Bus
* RabbitMQ Integration ## Want to Contribute?
* Services
* Object Serialization ABP is a community-driven open source project. See [the contribution guide](Contribution/Index.md) if you want to be a part of this project.
* JSON Serialization
* Emailing
* GUIDs
* Threading
* Timing
* [Multi Tenancy](Multi-Tenancy.md)
* Module Development
* [Basics](Module-Development-Basics.md)
* Plug-In Modules
* [Best Practices](Best-Practices/Index.md)
* Domain Driven Design
* Domain Layer
* [Entities & Aggregate Roots](Entities.md)
* Value Objects
* [Repositories](Repositories.md)
* Domain Services
* Specifications
* Application Layer
* Application Services
* Data Transfer Objects
* Unit Of Work
* ASP.NET Core MVC
* API Versioning
* User Interface
* [Client Side Package Management](AspNetCore/Client-Side-Package-Management.md)
* [Bundling & Minification](AspNetCore/Bundling-Minification.md)
* [Tag Helpers](Tag-Helpers.md)
* [Theming](AspNetCore/Theming.md)
* Data Access
* [Entity Framework Core Integration](Entity-Framework-Core.md)
* [MongoDB Integration](MongoDB.md)
* Background
* [Background Jobs](Background-Jobs.md)
* Testing

33
docs/en/Module-Development-Basics.md

@ -1,10 +1,10 @@
## Module Development # Module Development
### Introduction ## Introduction
ABP is itself a modular framework. It also provides an infrastructure and architectural model to develop your own modules. ABP is a **modular application framework** which consists of dozens of **nuget packages**. It also provides a complete infrastructure to build your own application modules which may have entities, services, database integration, APIs, UI components and so on.
### Module Class ## Module Class
Every module should define a module class. The simplest way of defining a module class is to create a class derived from ``AbpModule`` as shown below: Every module should define a module class. The simplest way of defining a module class is to create a class derived from ``AbpModule`` as shown below:
@ -16,9 +16,9 @@ public class BlogModule : AbpModule
```` ````
#### Configuring Dependency Injection & Other Modules ### Configuring Dependency Injection & Other Modules
##### ConfigureServices Method #### ConfigureServices Method
``ConfigureServices`` is the main method to add your services to the dependency injection system and configure other modules. Example: ``ConfigureServices`` is the main method to add your services to the dependency injection system and configure other modules. Example:
@ -52,15 +52,15 @@ public class BlogModule : AbpModule
See Configuration (TODO: link) document for more about the configuration system. See Configuration (TODO: link) document for more about the configuration system.
##### Pre & Post Configure Services #### Pre & Post Configure Services
``AbpModule`` class also defines ``PreConfigureServices`` and ``PostConfigureServices`` methods to override and write your code just before and just after ``ConfigureServices``. Notice that the code you have written into these methods will be executed before/after the ``ConfigureServices`` methods of all other modules. ``AbpModule`` class also defines ``PreConfigureServices`` and ``PostConfigureServices`` methods to override and write your code just before and just after ``ConfigureServices``. Notice that the code you have written into these methods will be executed before/after the ``ConfigureServices`` methods of all other modules.
#### Application Initialization ### Application Initialization
Once all the services of all modules are configured, the application starts by initializing all modules. In this phase, you can resolve services from ``IServiceProvider`` since it's ready and available. Once all the services of all modules are configured, the application starts by initializing all modules. In this phase, you can resolve services from ``IServiceProvider`` since it's ready and available.
##### OnApplicationInitialization Method #### OnApplicationInitialization Method
You can override ``OnApplicationInitialization`` method to execute code while application is being started. Example: You can override ``OnApplicationInitialization`` method to execute code while application is being started. Example:
@ -102,15 +102,15 @@ public class AppModule : AbpModule
You can also perform startup logic if your module requires it You can also perform startup logic if your module requires it
##### Pre & Post Application Initialization #### Pre & Post Application Initialization
``AbpModule`` class also defines ``OnPreApplicationInitialization`` and ``OnPostApplicationInitialization`` methods to override and write your code just before and just after ``OnApplicationInitialization``. Notice that the code you have written into these methods will be executed before/after the ``OnApplicationInitialization`` methods of all other modules. ``AbpModule`` class also defines ``OnPreApplicationInitialization`` and ``OnPostApplicationInitialization`` methods to override and write your code just before and just after ``OnApplicationInitialization``. Notice that the code you have written into these methods will be executed before/after the ``OnApplicationInitialization`` methods of all other modules.
#### Application Shutdown ### Application Shutdown
Lastly, you can override ``OnApplicationShutdown`` method if you want to execute some code while application is beign shutdown. Lastly, you can override ``OnApplicationShutdown`` method if you want to execute some code while application is being shutdown.
### Module Dependencies ## Module Dependencies
In a modular application, it's not unusual for one module to depend upon another module(s). An Abp module must declare ``[DependsOn]`` attribute if it does have a dependcy upon another module, as shown below: In a modular application, it's not unusual for one module to depend upon another module(s). An Abp module must declare ``[DependsOn]`` attribute if it does have a dependcy upon another module, as shown below:
@ -126,3 +126,10 @@ public class BlogModule
You can use multiple ``DependsOn`` attribute or pass multiple module types to a single ``DependsOn`` attribute depending on your preference. You can use multiple ``DependsOn`` attribute or pass multiple module types to a single ``DependsOn`` attribute depending on your preference.
A depended module may depend on another module, but you only need to define your direct dependencies. ABP investigates the dependency graph for the application at startup and initializes/shutdowns modules in the correct order. A depended module may depend on another module, but you only need to define your direct dependencies. ABP investigates the dependency graph for the application at startup and initializes/shutdowns modules in the correct order.
## Framework Modules vs Application Modules
There are **two types of modules.** They don't have any structural difference but categorized by functionality and purpose:
- **Framework modules**: These are **core modules of the framework** like caching, emailing, theming, security, serialization, validation, EF Core integration, MongoDB integration... etc. They do not have application/business functionalities but makes your daily development easier by providing common infrastructure, integration and abstractions.
- **Application modules**: These modules implement **specific application/business functionalities** like blogging, document management, identity management, tenant management... etc. They generally have their own entities, services, APIs and UI components. See [pre-built application modules](Modules/Index.md).

475
docs/en/Modules/Docs.md

@ -0,0 +1,475 @@
# Docs Module
## What is Docs Module?
Docs module is an application module for ABP framework. It simplifies software documentation. This module is free and open-source.
### Integration
Currently docs module provides you to store your docs both on GitHub and file system.
### Hosting
Docs module is an application module and does not offer any hosting solution. You can host your docs on-premise or on cloud.
### Versioning
When you use GitHub to store your docs, Docs Module supports versioning. If you have multiple versions for your docs, there will be a combo-box on the UI to switch between versions. If you choose file system to store your docs, it does not support multiple versions.
[The documents](https://abp.io/documents/) for ABP framework is also using this module.
> Docs module follows the [module architecture best practices](../Best-Practices/Module-Architecture.md) guide.
## Installation
### 1- Download
If you do not have an existing ABP project, this step shows you how to create a new project from [abp.io](https://abp.io) to add the Docs Module. If you already have an ABP project, you can skip this step.
Navigate to https://abp.io/Templates. Enter your project name as `Acme.MyProject`, select `ASP.NET Core Mvc Application` and select `Entity Framework Core` for the database provider.
Note that this document covers `Entity Framework Core` provider but you can also select `MongoDB` as your database provider.
![Create new project](../images/docs-module_download-new-abp-project.png)
### 2- Running The Empty Application
After you download the project, extract the ZIP file and open `Acme.MyProject.sln`. You will see that the solution consists of `Application`, `Domain `, `EntityFrameworkCore` and `Web` projects. Right click on `Acme.MyProject.Web` project and **Set as StartUp Project**.
![Create a new project](../images/docs-module_solution-explorer.png)
The database connection string is located in `appsettings.json` of your `Acme.MyProject.Web` project. If you have a different database configuration, change the connection string.
```json
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=MyProject;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
```
Open `Package Manager Console` in the Visual Studio and choose `src\Acme.MyProject.EntityFrameworkCore` as the default project. Run `Update-Database` command to create your new database. The database `MyProject` will be created in your database server.
Now an empty ABP project has been created! You can now run your project and see the empty website.
To login your website enter `admin` as the username and `1q2w3E*` as the password.
### 2- Referencing Docs Module Packages
Docs module packages are hosted on NuGet. There are 4 packages that needs be to installed to your application. Each package has to be installed to the relevant project.
* [Volo.Docs.Domain](https://www.nuget.org/packages/Volo.Docs.Domain/) needs to be referenced to `Acme.MyProject.Domain` project.
* Edit `Acme.MyProject.Domain.csproj`file and add the below line to as a reference. Note that you need to change version (v0.9.0) to the latest.
```csharp
<PackageReference Include="Volo.Docs.Domain" Version="0.9.0" />
```
* [Volo.Docs.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Docs.EntityFrameworkCore/) needs to be referenced to `Acme.MyProject.EntityFrameworkCore` project.
- Edit `Acme.MyProject.EntityFrameworkCore.csproj`file and add the below line to as a reference. Note that you need to change version (v0.9.0) to the latest.
```csharp
<PackageReference Include="Volo.Docs.EntityFrameworkCore" Version="0.9.0" />
```
* [Volo.Docs.Application](https://www.nuget.org/packages/Volo.Docs.Application/) needs to be referenced to `Acme.MyProject.Application` project.
* Edit `Acme.MyProject.Application.csproj`file and add the below line to as a reference. Note that you need to change version (v0.9.0) to the latest.
```csharp
<PackageReference Include="Volo.Docs.Application" Version="0.9.0" />
```
* [Volo.Docs.Web ](https://www.nuget.org/packages/Volo.Docs.Web/)needs to be referenced to `Acme.MyProject.Web` project.
- Edit `Acme.MyProject.Web.csproj`file and add the below line to as a reference. Note that you need to change version (v0.9.0) to the latest.
```csharp
<PackageReference Include="Volo.Docs.Web" Version="0.9.0" />
```
### 3- Adding Module Dependencies
An ABP module must declare `[DependsOn]` attribute if it has a dependency upon another module. Each module has to be added in`[DependsOn]` attribute to the relevant project.
* Open `MyProjectDomainModule.cs`and add `typeof(DocsDomainModule)` as shown below;
```csharp
[DependsOn(
typeof(DocsDomainModule),
typeof(AbpIdentityDomainModule),
typeof(AbpAuditingModule),
typeof(BackgroundJobsDomainModule),
typeof(AbpAuditLoggingDomainModule)
)]
public class MyProjectDomainModule : AbpModule
{
//...
}
```
* Open `MyProjectEntityFrameworkCoreModule.cs`and add `typeof(DocsEntityFrameworkCoreModule)` as shown below;
```csharp
[DependsOn(
typeof(DocsEntityFrameworkCoreModule),
typeof(MyProjectDomainModule),
typeof(AbpIdentityEntityFrameworkCoreModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCoreSqlServerModule),
typeof(BackgroundJobsEntityFrameworkCoreModule),
typeof(AbpAuditLoggingEntityFrameworkCoreModule)
)]
public class MyProjectEntityFrameworkCoreModule : AbpModule
{
//...
}
```
* Open `MyProjectApplicationModule.cs`and add `typeof(DocsApplicationModule)` as shown below;
```csharp
[DependsOn(
typeof(DocsApplicationModule),
typeof(MyProjectDomainModule),
typeof(AbpIdentityApplicationModule))]
public class MyProjectApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<PermissionOptions>(options =>
{
options.DefinitionProviders.Add<MyProjectPermissionDefinitionProvider>();
});
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<MyProjectApplicationAutoMapperProfile>();
});
}
}
```
* Open `MyProjectWebModule.cs`and add `typeof(DocsWebModule)` as shown below;
```csharp
[DependsOn(
typeof(DocsWebModule),
typeof(MyProjectApplicationModule),
typeof(MyProjectEntityFrameworkCoreModule),
typeof(AbpAutofacModule),
typeof(AbpIdentityWebModule),
typeof(AbpAccountWebModule),
typeof(AbpAspNetCoreMvcUiBasicThemeModule)
)]
public class MyProjectWebModule : AbpModule
{
//...
}
```
### 4- Database Integration
#### 4.1- Entity Framework Integration
If you choose Entity Framework as your database provider, you need to configure the Docs Module in your DbContext. To do this;
- Open `MyProjectDbContext.cs` and add `modelBuilder.ConfigureDocs()` to the `OnModelCreating()`
```csharp
[ConnectionStringName("Default")]
public class MyProjectDbContext : AbpDbContext<MyProjectDbContext>
{
public MyProjectDbContext(DbContextOptions<MyProjectDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//...
modelBuilder.ConfigureDocs();
}
}
```
* Open `Package Manager Console` in `Visual Studio` and choose `Acme.MyProject.EntityFrameworkCore` as default project. Then write the below command to add the migration for Docs Module.
```csharp
add-migration Added_Docs_Module
```
When the command successfully executes , you will see a new migration file named as `20181221111621_Added_Docs_Module` in the folder `Acme.MyProject.EntityFrameworkCore\Migrations`.
Now, update the database for Docs module database changes. To do this run the below code on `Package Manager Console` in `Visual Studio`. Be sure `Acme.MyProject.EntityFrameworkCore` is still default project.
```csharp
update-database
```
Finally, you can check your database to see the newly created tables. For example you can see `DocsProjects` table must be added to your database.
### 5- Linking Docs Module
The default route for Docs module is;
```
/Documents
```
To add Docs module link to your application menu;
* Open `MyProjectMenuContributor.cs` and add the below line to the method `ConfigureMainMenuAsync()`.
```csharp
context.Menu.Items.Add(new ApplicationMenuItem("MyProject.Docs", l["Menu:Docs"], "/Documents"));
```
Final look of **MyProjectMenuContributor.cs**
```csharp
private async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
{
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<MyProjectResource>>();
context.Menu.Items.Insert(0, new ApplicationMenuItem("MyProject.Home", l["Menu:Home"], "/"));
context.Menu.Items.Add(new ApplicationMenuItem("MyProject.Docs", l["Menu:Docs"], "/Documents"));
}
```
The `Menu:Docs` keyword is a localization key. To localize the menu text, open `Localization\MyProject\en.json` in the project `Acme.MyProject.Domain`. And add the below line
```json
"Menu:Docs": "Documents"
```
Final look of **en.json**
```json
{
"culture": "en",
"texts": {
"Menu:Home": "Home",
"Welcome": "Welcome",
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.",
"Menu:Docs": "Documents"
}
}
```
The new menu item for Docs Module is added to the menu. Run your web application and browse to `http://localhost:YOUR_PORT_NUMBER/documents` URL.
You will see a warning says;
```
There are no projects yet!
```
As we have not added any projects yet, this warning is normal.
### 6- Adding New Docs Project
Open `DocsProjects` in your database, and insert a new record with the following field information;
* **Name**: The display name of the document name which will be shown on the web page.
* **ShortName**: A short and URL friendly name that will be used in your docs URL.
* **Format**: The format of the document (for Markdown: `md`, for HTML: `html`)
* **DefaultDocumentName**: The document for the initial page.
* **NavigationDocumentName**: The document to be used for the navigation menu (index).
* **MinimumVersion**: The minimum version to show the docs. Below version will not be listed.
* **DocumentStoreType**: The source of the documents (for GitHub:`GitHub`, for file system`FileSystem`)
* **ExtraProperties**: A serialized `JSON` that stores special configuration for the selected `DocumentStoreType`.
* **MainWebsiteUrl**: The URL when user clicks to the logo of the Docs module page. You can simply set as `/` to link to your website root address.
* **LatestVersionBranchName**: This is a config for GitHub. It's the branch name which to retrieve the docs. You can set it as `master`.
#### Sample Project Record for "GitHub"
You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documents to configure your GitHub document store.
- Name: `ABP framework (GitHub)`
- ShortName: `abp`
- Format: `md`
- DefaultDocumentName: `Index`
- NavigationDocumentName: `docs-nav.json`
- MinimumVersion: `<NULL>` (no minimum version)
- DocumentStoreType: `GitHub`
- ExtraProperties:
```json
{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/en/","GitHubAccessToken":"***"}
```
Note that `GitHubAccessToken` is masked with `***`. It's a private token that you must get it from GitHub. See https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
- MainWebsiteUrl: `/`
- LatestVersionBranchName: `master`
For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939658', N'ABP framework (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/en/","GitHubAccessToken":"***"}', N'/', N'master')
```
Be aware that `GitHubAccessToken` is masked. It's a private token and you must get your own token and replace the `***` string.
#### Sample Project Record for "FileSystem"
You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documents to configure your GitHub document store.
- Name: `ABP framework (FileSystem)`
- ShortName: `abp`
- Format: `md`
- DefaultDocumentName: `Index`
- NavigationDocumentName: `docs-nav.json`
- MinimumVersion: `<NULL>` (no minimum version)
- DocumentStoreType: `FileSystem`
- ExtraProperties:
```json
{"Path":"C:\\Github\\abp\\docs\\en"}
```
Note that `Path` must be replaced with your local docs directory. You can fetch the ABP Framework's documents from https://github.com/abpframework/abp/tree/master/docs/en and copy to the directory `C:\\Github\\abp\\docs\\en` to get it work.
- MainWebsiteUrl: `/`
- LatestVersionBranchName: `<NULL>`
For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs\\en"}', N'/', NULL)
```
Add one of the sample projects above and run the application. In the menu you will see `Documents` link, click the menu link to open the documents page.
So far, we have created a new application from abp.io website and made it up and ready for Docs module.
### 7- Creating a New Document
In the sample Project records, you see that `Format` is specified as `md` which refers to [Mark Down](https://en.wikipedia.org/wiki/Markdown). You can see the mark down cheat sheet following the below link;
https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet
ABP Docs Module can render mark down to HTML.
Now let's have a look a sample document in markdown format.
~~~markdown
# This is a header
Welcome to Docs Module.
## This is a sub header
[This is a link](https://abp.io)
![This is an image](https://abp.io/assets/my-image.png)
## This is a code block
```csharp
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
}
```
~~~
As an example you can see ABP Framework documentation:
[https://github.com/abpframework/abp/blob/master/docs/en/](https://github.com/abpframework/abp/blob/master/docs/en/)
### 8- Creating the Navigation Document
Navigation document is the main menu of the documents page. It is located on the left side of the page. It is a `JSON` file. Take a look at the below sample navigation document to understand the structure.
```json
{
"items":[
{
"text":"Sample Menu Item - 1",
"items":[
{
"text":"Sample Menu Item - 1.1",
"items":[
{
"text":"Sample Menu Item - 1.1.1",
"path":"SampleMenuItem_1_1_1.md"
}
]
},
{
"text":"Sample Menu Item - 1.2",
"items":[
{
"text":"Sample Menu Item - 1.2.1",
"path":"SampleMenuItem_1_2_1.md"
},
{
"text":"Sample Menu Item - 1.2.2",
"path":"SampleMenuItem_1_2_2.md"
}
]
}
]
},
{
"text":"Sample Menu Item - 2",
"items":[
{
"text":"Sample Menu Item - 2.1",
"items":[
{
"text":"Sample Menu Item - 2.1.1",
"path":"SampleMenuItem_2_1_1.md"
}
]
}
]
}
]
}
```
The upper sample `JSON` file renders the below navigation menu as `HTML`.
![Navigation menu](../images/docs-module_download-sample-navigation-menu.png)
Finally a new Docs Module is added to your project which is feeded with GitHub.

26
docs/en/Modules/Index.md

@ -0,0 +1,26 @@
# Application Modules
ABP is a **modular application framework** which consists of dozens of **nuget packages**. It also provides a complete infrastructure to build your own application modules which may have entities, services, database integration, APIs, UI components and so on.
There are **two types of modules.** They don't have any structural difference but categorized by functionality and purpose:
* [**Framework modules**](https://github.com/abpframework/abp/tree/master/framework/src): These are **core modules of the framework** like caching, emailing, theming, security, serialization, validation, EF Core integration, MongoDB integration... etc. They do not have application/business functionalities but makes your daily development easier by providing common infrastructure, integration and abstractions.
* [**Application modules**](https://github.com/abpframework/abp/tree/master/modules): These modules implement specific application/business functionalities like blogging, document management, identity management, tenant management... etc. They generally have their own entities, services, APIs and UI components.
## Open Source Application Modules
There are some **free and open source** application modules developed and maintained by the ABP community:
* **Account**: Used to make user login/register to the application.
* **Audit Logging**: Used to persist audit logs to a database.
* **Background Jobs**: Used to persist background jobs when using default background job manager.
* **Blogging**: Used to create fancy blogs. ABP's [own blog](https://abp.io/blog/abp/) already using this module.
* [**Docs**](Docs.md): Used to create technical documentation pages. ABP's [own documentation](https://abp.io/documents/) already using this module.
* **Identity**: Used to manage roles, users and their permissions.
* **Identity Server**: Integrates to IdentityServer4.
* **Permission Management**: Used to persist permissions.
* **Setting Management**: Used to persist settings.
* **Tenant Management**: Used to manage tenants for a [multi-tenant](../Multi-Tenancy.md) application.
* **Users**: Used the abstract users, so other modules can depend on this instead of the Identity module.
Documenting the modules is in the progress. See [this repository](https://github.com/abpframework/abp/tree/master/modules) for source code of all modules.

2
docs/en/Tutorials/AspNetCore-Mvc/Part-I.md

@ -236,7 +236,7 @@ namespace Acme.BookStore
You normally create **Controllers** to expose application services as **HTTP API** endpoints. Thus allowing browser or 3rd-party clients to call them via AJAX. You normally create **Controllers** to expose application services as **HTTP API** endpoints. Thus allowing browser or 3rd-party clients to call them via AJAX.
ABP can **automagically** configures your application services as MVC API Controllers by convention. ABP can [**automagically**](../../AspNetCore/Auto-API-Controllers.md) configures your application services as MVC API Controllers by convention.
#### Swagger UI #### Swagger UI

18
docs/en/docs-nav.json

@ -186,10 +186,20 @@
] ]
}, },
{ {
"text": "ASP.NET Core MVC", "text": "ASP.NET Core",
"items": [ "items": [
{ {
"text": "API Versioning" "text": "API",
"items": [
{
"text": "Auto API Controllers",
"path": "AspNetCore/Auto-API-Controllers.md"
},
{
"text": "Dynamic C# API Clients",
"path": "AspNetCore/Dynamic-CSharp-API-Clients.md"
}
]
}, },
{ {
"text": "User Interface", "text": "User Interface",
@ -246,6 +256,10 @@
} }
] ]
}, },
{
"text": "Application Modules",
"path": "Modules/Index.md"
},
{ {
"text": "Testing" "text": "Testing"
}, },

BIN
docs/en/images/bookstore-apis.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/en/images/docs-module_download-new-abp-project.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/en/images/docs-module_download-sample-navigation-menu.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/en/images/docs-module_solution-explorer.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs

@ -66,6 +66,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString()); var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString());
tagHelper.Init(context);
if (runAsync) if (runAsync)
{ {
AsyncHelper.RunSync(() => tagHelper.ProcessAsync(innerContext, innerOutput)); AsyncHelper.RunSync(() => tagHelper.ProcessAsync(innerContext, innerOutput));

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSize.cs

@ -5,6 +5,10 @@
Default, Default,
Small, Small,
Medium, Medium,
Large Large,
Block,
Block_Small,
Block_Medium,
Block_Large,
} }
} }

8
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSizeExtensions.cs

@ -12,6 +12,14 @@
return "btn-md"; return "btn-md";
case AbpButtonSize.Large: case AbpButtonSize.Large:
return "btn-lg"; return "btn-lg";
case AbpButtonSize.Block:
return "btn-block";
case AbpButtonSize.Block_Small:
return "btn-sm btn-block";
case AbpButtonSize.Block_Medium:
return "btn-md btn-block";
case AbpButtonSize.Block_Large:
return "btn-lg btn-block";
case AbpButtonSize.Default: case AbpButtonSize.Default:
return ""; return "";
default: default:

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelper.cs

@ -9,14 +9,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
public AbpButtonSize Size { get; set; } = AbpButtonSize.Default; public AbpButtonSize Size { get; set; } = AbpButtonSize.Default;
public bool? Block { get; set; } = false;
public string BusyText { get; set; } public string BusyText { get; set; }
public string Text { get; set; } public string Text { get; set; }
public string Icon { get; set; } public string Icon { get; set; }
public bool? Disabled { get; set; }
public FontIconType IconType { get; set; } = FontIconType.FontAwesome; public FontIconType IconType { get; set; } = FontIconType.FontAwesome;
public AbpButtonTagHelper(AbpButtonTagHelperService service) public AbpButtonTagHelper(AbpButtonTagHelperService service)

14
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelperServiceBase.cs

@ -13,6 +13,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
AddClasses(context, output); AddClasses(context, output);
AddIcon(context, output); AddIcon(context, output);
AddText(context, output); AddText(context, output);
AddDisabled(context, output);
} }
protected virtual void NormalizeTagMode(TagHelperContext context, TagHelperOutput output) protected virtual void NormalizeTagMode(TagHelperContext context, TagHelperOutput output)
@ -33,11 +34,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
{ {
output.Attributes.AddClass(TagHelper.Size.ToClassName()); output.Attributes.AddClass(TagHelper.Size.ToClassName());
} }
if (TagHelper.Block ?? false)
{
output.Attributes.AddClass("btn-block");
}
} }
protected virtual void AddIcon(TagHelperContext context, TagHelperOutput output) protected virtual void AddIcon(TagHelperContext context, TagHelperOutput output)
@ -70,5 +66,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
output.Content.AppendHtml($"<span>{TagHelper.Text}</span>"); output.Content.AppendHtml($"<span>{TagHelper.Text}</span>");
} }
protected virtual void AddDisabled(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.Disabled ?? false)
{
output.Attributes.Add("disabled", "disabled");
}
}
} }
} }

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelper.cs

@ -0,0 +1,11 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
{
public class AbpButtonToolbarTagHelper : AbpTagHelper<AbpButtonToolbarTagHelper, AbpButtonToolbarTagHelperService>
{
public AbpButtonToolbarTagHelper(AbpButtonToolbarTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

14
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelperService.cs

@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
{
public class AbpButtonToolbarTagHelperService : AbpTagHelperService<AbpButtonToolbarTagHelper>
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.AddClass("btn-toolbar");
output.Attributes.Add("role","toolbar");
}
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpLinkButtonTagHelper.cs

@ -11,12 +11,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button
public AbpButtonSize Size { get; set; } = AbpButtonSize.Default; public AbpButtonSize Size { get; set; } = AbpButtonSize.Default;
public bool? Block { get; set; } = false;
public string Text { get; set; } public string Text { get; set; }
public string Icon { get; set; } public string Icon { get; set; }
public bool? Disabled { get; set; }
public FontIconType IconType { get; } = FontIconType.FontAwesome; public FontIconType IconType { get; } = FontIconType.FontAwesome;
public AbpLinkButtonTagHelper(AbpLinkButtonTagHelperService service) public AbpLinkButtonTagHelper(AbpLinkButtonTagHelperService service)

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/IButtonTagHelperBase.cs

@ -6,12 +6,12 @@
AbpButtonSize Size { get; } AbpButtonSize Size { get; }
bool? Block { get;}
string Text { get; } string Text { get; }
string Icon { get; } string Icon { get; }
bool? Disabled { get; }
FontIconType IconType { get; } FontIconType IconType { get; }
} }
} }

19
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelper.cs

@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{
[HtmlTargetElement("abp-card", Attributes = "background")]
[HtmlTargetElement("abp-card-header", Attributes = "background")]
[HtmlTargetElement("abp-card-body", Attributes = "background")]
[HtmlTargetElement("abp-card-footer", Attributes = "background")]
public class AbpCardBackgroundTagHelper : AbpTagHelper<AbpCardBackgroundTagHelper, AbpCardBackgroundTagHelperService>
{
public AbpCardBackgroundType Background { get; set; } = AbpCardBackgroundType.Default;
public AbpCardBackgroundTagHelper(AbpCardBackgroundTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

23
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelperService.cs

@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{
public class AbpCardBackgroundTagHelperService : AbpTagHelperService<AbpCardBackgroundTagHelper>
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
SetBackground(context, output);
}
protected virtual void SetBackground(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.Background == AbpCardBackgroundType.Default)
{
return;
}
output.Attributes.AddClass("bg-" + TagHelper.Background.ToString().ToLowerInvariant());
}
}
}

15
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundType.cs

@ -0,0 +1,15 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{
public enum AbpCardBackgroundType
{
Default,
Primary,
Secondary,
Success,
Danger,
Warning,
Info,
Light,
Dark,
}
}

15
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBorderColorType.cs

@ -0,0 +1,15 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{
public enum AbpCardBorderColorType
{
Default,
Primary,
Secondary,
Success,
Danger,
Warning,
Info,
Light,
Dark,
}
}

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelper.cs

@ -0,0 +1,11 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{
public class AbpCardFooterTagHelper : AbpTagHelper<AbpCardFooterTagHelper, AbpCardFooterTagHelperService>
{
public AbpCardFooterTagHelper(AbpCardFooterTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

14
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelperService.cs

@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{
public class AbpCardFooterTagHelperService : AbpTagHelperService<AbpCardFooterTagHelper>
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.AddClass("card-footer");
output.TagName = "div";
}
}
}

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardImageTagHelper.cs

@ -3,6 +3,7 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{ {
[HtmlTargetElement("img", Attributes = "abp-card-image", TagStructure = TagStructure.WithoutEndTag)] [HtmlTargetElement("img", Attributes = "abp-card-image", TagStructure = TagStructure.WithoutEndTag)]
[HtmlTargetElement("abp-image", Attributes = "abp-card-image", TagStructure = TagStructure.WithoutEndTag)]
public class AbpCardImageTagHelper : AbpTagHelper<AbpCardImageTagHelper, AbpCardImageTagHelperService> public class AbpCardImageTagHelper : AbpTagHelper<AbpCardImageTagHelper, AbpCardImageTagHelperService>
{ {
[HtmlAttributeName("abp-card-image")] [HtmlAttributeName("abp-card-image")]

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelper.cs

@ -2,6 +2,8 @@
{ {
public class AbpCardTagHelper : AbpTagHelper<AbpCardTagHelper, AbpCardTagHelperService> public class AbpCardTagHelper : AbpTagHelper<AbpCardTagHelper, AbpCardTagHelperService>
{ {
public AbpCardBorderColorType Border { get; set; } = AbpCardBorderColorType.Default;
public AbpCardTagHelper(AbpCardTagHelperService tagHelperService) public AbpCardTagHelper(AbpCardTagHelperService tagHelperService)
: base(tagHelperService) : base(tagHelperService)
{ {

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelperService.cs

@ -9,6 +9,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{ {
output.TagName = "div"; output.TagName = "div";
output.Attributes.AddClass("card"); output.Attributes.AddClass("card");
SetBorder(context, output);
}
protected virtual void SetBorder(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.Border == AbpCardBorderColorType.Default)
{
return;
}
output.Attributes.AddClass("border-" + TagHelper.Border.ToString().ToLowerInvariant());
} }
} }
} }

19
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelper.cs

@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{
[HtmlTargetElement("abp-card", Attributes = "text-color")]
[HtmlTargetElement("abp-card-header", Attributes = "text-color")]
[HtmlTargetElement("abp-card-body", Attributes = "text-color")]
[HtmlTargetElement("abp-card-footer", Attributes = "text-color")]
public class AbpCardTextColorTagHelper : AbpTagHelper<AbpCardTextColorTagHelper, AbpCardTextColorTagHelperService>
{
public AbpCardTextColorType TextColor { get; set; } = AbpCardTextColorType.Default;
public AbpCardTextColorTagHelper(AbpCardTextColorTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

23
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelperService.cs

@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{
public class AbpCardTextColorTagHelperService : AbpTagHelperService<AbpCardTextColorTagHelper>
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
SetTextColor(context, output);
}
protected virtual void SetTextColor(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.TextColor == AbpCardTextColorType.Default)
{
return;
}
output.Attributes.AddClass("text-" + TagHelper.TextColor.ToString().ToLowerInvariant());
}
}
}

16
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorType.cs

@ -0,0 +1,16 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card
{
public enum AbpCardTextColorType
{
Default,
White,
Primary,
Secondary,
Success,
Danger,
Warning,
Info,
Light,
Dark
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelper.cs

@ -4,6 +4,8 @@
{ {
public string Id { get; set; } public string Id { get; set; }
public bool? Multi { get; set; }
public bool? Show { get; set; } public bool? Show { get; set; }
public AbpCollapseBodyTagHelper(AbpCollapseBodyTagHelperService tagHelperService) public AbpCollapseBodyTagHelper(AbpCollapseBodyTagHelperService tagHelperService)

14
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs

@ -17,16 +17,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
output.Attributes.AddClass("show"); output.Attributes.AddClass("show");
} }
var innerContent = (await output.GetChildContentAsync()).GetContent(); if (TagHelper.Multi ?? false)
{
var body = GetBody(context, output, innerContent); output.Attributes.AddClass("multi-collapse");
}
output.Content.SetHtmlContent(body); var innerContent = (await output.GetChildContentAsync()).GetContent();
}
protected virtual string GetBody(TagHelperContext context, TagHelperOutput output, string innerContent) output.Content.SetHtmlContent(innerContent);
{
return "<div class=\"card card-body\">" + innerContent + "</div>";
} }
} }
} }

9
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelper.cs

@ -1,11 +1,14 @@
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button; using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{ {
[HtmlTargetElement("abp-button", Attributes = "abp-collapse-id")]
[HtmlTargetElement("a", Attributes = "abp-collapse-id")]
public class AbpCollapseButtonTagHelper : AbpTagHelper<AbpCollapseButtonTagHelper, AbpCollapseButtonTagHelperService> public class AbpCollapseButtonTagHelper : AbpTagHelper<AbpCollapseButtonTagHelper, AbpCollapseButtonTagHelperService>
{ {
public AbpButtonType ButonType { get; set; } = AbpButtonType.Default; [HtmlAttributeName("abp-collapse-id")]
public string BodyId { get; set; } public string BodyId { get; set; }
public AbpCollapseButtonTagHelper(AbpCollapseButtonTagHelperService tagHelperService) public AbpCollapseButtonTagHelper(AbpCollapseButtonTagHelperService tagHelperService)

46
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelperService.cs

@ -8,20 +8,48 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{ {
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {
output.TagName = "button";
output.Attributes.AddClass("btn");
output.Attributes.Add("data-toggle","collapse"); AddCommonAttributes(context, output);
output.Attributes.Add("aria-expanded","false");
output.Attributes.Add("type","button"); if (output.TagName == "abp-button" || output.TagName == "button")
output.Attributes.Add("data-target", "#" +TagHelper.BodyId); {
AddButtonAttributes(context,output);
}
else if (output.TagName == "a")
{
AddLinkAttributes(context, output);
}
}
protected virtual void AddCommonAttributes(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.Add("data-toggle", "collapse");
output.Attributes.Add("aria-expanded", "false");
output.Attributes.Add("aria-controls", TagHelper.BodyId); output.Attributes.Add("aria-controls", TagHelper.BodyId);
}
protected virtual void AddButtonAttributes(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.BodyId.Trim().Split(' ').Length > 1)
{
output.Attributes.Add("data-target", ".multi-collapse");
return;
}
if (TagHelper.ButonType != AbpButtonType.Default) output.Attributes.Add("data-target", "#" + TagHelper.BodyId);
}
protected virtual void AddLinkAttributes(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.BodyId.Trim().Split(' ').Length > 1)
{ {
output.Attributes.AddClass("btn-" + TagHelper.ButonType.ToString().ToLowerInvariant()); output.Attributes.Add("href", ".multi-collapse");
return;
} }
output.Attributes.Add("href", "#" + TagHelper.BodyId);
} }
} }
} }

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs

@ -125,6 +125,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
buttonTag.TagName = "a"; buttonTag.TagName = "a";
buttonTag.Attributes.RemoveAll("type"); buttonTag.Attributes.RemoveAll("type");
buttonTag.Attributes.Add("roles", "button"); buttonTag.Attributes.Add("roles", "button");
buttonTag.Attributes.Add("href", "#");
if (TagHelper.NavLink??false) if (TagHelper.NavLink??false)
{ {

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelper.cs

@ -0,0 +1,11 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
{
public class AbpDropdownItemTextTagHelper : AbpTagHelper<AbpDropdownItemTextTagHelper, AbpDropdownItemTextTagHelperService>
{
public AbpDropdownItemTextTagHelper(AbpDropdownItemTextTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

14
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelperService.cs

@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
{
public class AbpDropdownItemTextTagHelperService : AbpTagHelperService<AbpDropdownItemTextTagHelper>
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.AddClass("dropdown-item-text");
output.TagName = "span";
}
}
}

15
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormControlSize.cs

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
public enum AbpFormControlSize
{
Default,
Small,
Medium,
Large
}
}

7
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs

@ -10,14 +10,19 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
public string Label { get; set; } public string Label { get; set; }
[HtmlAttributeName("info")]
public string InfoText { get; set; }
[HtmlAttributeName("disabled")] [HtmlAttributeName("disabled")]
public bool IsDisabled { get; set; } = false; public bool IsDisabled { get; set; } = false;
[HtmlAttributeName("readonly")] [HtmlAttributeName("readonly")]
public bool IsReadonly { get; set; } = false; public AbpReadonlyInputType IsReadonly { get; set; } = AbpReadonlyInputType.False;
public bool AutoFocus { get; set; } public bool AutoFocus { get; set; }
public AbpFormControlSize Size { get; set; } = AbpFormControlSize.Default;
[HtmlAttributeNotBound] [HtmlAttributeNotBound]
[ViewContext] [ViewContext]
public ViewContext ViewContext { get; set; } public ViewContext ViewContext { get; set; }

155
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs

@ -1,9 +1,13 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.TagHelpers; using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
@ -12,11 +16,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
private readonly IHtmlGenerator _generator; private readonly IHtmlGenerator _generator;
private readonly HtmlEncoder _encoder; private readonly HtmlEncoder _encoder;
private readonly IStringLocalizerFactory _stringLocalizerFactory;
private readonly AbpMvcDataAnnotationsLocalizationOptions _options;
public AbpInputTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder) public AbpInputTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IOptions<AbpMvcDataAnnotationsLocalizationOptions> options, IStringLocalizerFactory stringLocalizerFactory)
{ {
_generator = generator; _generator = generator;
_encoder = encoder; _encoder = encoder;
_stringLocalizerFactory = stringLocalizerFactory;
_options = options.Value;
} }
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
@ -50,12 +58,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string GetFormInputGroupAsHtml(TagHelperContext context, TagHelperOutput output, out bool isCheckbox) protected virtual string GetFormInputGroupAsHtml(TagHelperContext context, TagHelperOutput output, out bool isCheckbox)
{ {
var inputTag = GetInputTagHelperOutput(context, output, out isCheckbox); var inputTag = GetInputTagHelperOutput(context, output, out isCheckbox);
var inputHtml = RenderTagHelperOutput(inputTag, _encoder); var inputHtml = RenderTagHelperOutput(inputTag, _encoder);
var label = GetLabelAsHtml(context, output, inputTag, isCheckbox); var label = GetLabelAsHtml(context, output, inputTag, isCheckbox);
var info = GetInfoAsHtml(context, output, inputTag, isCheckbox);
var validation = isCheckbox ? "" : GetValidationAsHtml(context, output, inputTag); var validation = isCheckbox ? "" : GetValidationAsHtml(context, output, inputTag);
return GetContent(context, output, label, inputHtml, validation, isCheckbox); return GetContent(context, output, label, inputHtml, validation, info, isCheckbox);
} }
protected virtual string GetValidationAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag) protected virtual string GetValidationAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
@ -76,14 +85,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return RenderTagHelper(attributeList, context, validationMessageTagHelper, _encoder, "span", TagMode.StartTagAndEndTag, true); return RenderTagHelper(attributeList, context, validationMessageTagHelper, _encoder, "span", TagMode.StartTagAndEndTag, true);
} }
protected virtual string GetContent(TagHelperContext context, TagHelperOutput output, string label, string inputHtml, string validation, bool isCheckbox) protected virtual string GetContent(TagHelperContext context, TagHelperOutput output, string label, string inputHtml, string validation, string infoHtml, bool isCheckbox)
{ {
var innerContent = isCheckbox ? var innerContent = isCheckbox ?
inputHtml + Environment.NewLine + label : inputHtml + label :
label + Environment.NewLine + inputHtml; label + inputHtml;
return Environment.NewLine + innerContent + Environment.NewLine + return innerContent + infoHtml + validation;
Environment.NewLine + validation + Environment.NewLine;
} }
protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml, bool isCheckbox) protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml, bool isCheckbox)
@ -121,14 +129,33 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ConvertToTextAreaIfTextArea(inputTagHelperOutput); ConvertToTextAreaIfTextArea(inputTagHelperOutput);
AddDisabledAttribute(inputTagHelperOutput); AddDisabledAttribute(inputTagHelperOutput);
AddReadOnlyAttribute(inputTagHelperOutput);
AddAutoFocusAttribute(inputTagHelperOutput); AddAutoFocusAttribute(inputTagHelperOutput);
isCheckbox = IsInputCheckbox(context, output, inputTagHelperOutput.Attributes); isCheckbox = IsInputCheckbox(context, output, inputTagHelperOutput.Attributes);
inputTagHelperOutput.Attributes.AddClass(isCheckbox ? "form-check-input" : "form-control"); AddFormControlClass(context, output, isCheckbox, inputTagHelperOutput);
AddReadOnlyAttribute(inputTagHelperOutput);
AddPlaceholderAttribute(inputTagHelperOutput);
AddInfoTextId(inputTagHelperOutput);
return inputTagHelperOutput; return inputTagHelperOutput;
} }
private void AddFormControlClass(TagHelperContext context, TagHelperOutput output, bool isCheckbox, TagHelperOutput inputTagHelperOutput)
{
var className = "form-control";
var readonlyAttribute = GetAttribute<ReadOnlyInput>(TagHelper.AspFor.ModelExplorer);
if (isCheckbox)
{
className = "form-check-input";
}
else if (TagHelper.IsReadonly == AbpReadonlyInputType.True_PlainText || (readonlyAttribute != null && readonlyAttribute.PlainText))
{
className = "form-control-plaintext";
}
inputTagHelperOutput.Attributes.AddClass(className + " " + GetSize(context, output));
}
protected virtual void AddAutoFocusAttribute(TagHelperOutput inputTagHelperOutput) protected virtual void AddAutoFocusAttribute(TagHelperOutput inputTagHelperOutput)
{ {
if (TagHelper.AutoFocus && !inputTagHelperOutput.Attributes.ContainsName("data-auto-focus")) if (TagHelper.AutoFocus && !inputTagHelperOutput.Attributes.ContainsName("data-auto-focus"))
@ -139,26 +166,65 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput) protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput)
{ {
if (inputTagHelperOutput.Attributes.ContainsName("disabled")) if (inputTagHelperOutput.Attributes.ContainsName("disabled") == false &&
(TagHelper.IsDisabled || GetAttribute<DisabledInput>(TagHelper.AspFor.ModelExplorer) != null))
{
inputTagHelperOutput.Attributes.Add("disabled", "");
}
}
protected virtual void AddReadOnlyAttribute(TagHelperOutput inputTagHelperOutput)
{
if (inputTagHelperOutput.Attributes.ContainsName("readonly") == false &&
(TagHelper.IsReadonly != AbpReadonlyInputType.False || GetAttribute<ReadOnlyInput>(TagHelper.AspFor.ModelExplorer) != null))
{
inputTagHelperOutput.Attributes.Add("readonly", "");
}
}
protected virtual void AddPlaceholderAttribute(TagHelperOutput inputTagHelperOutput)
{
if (inputTagHelperOutput.Attributes.ContainsName("placeholder"))
{ {
return; return;
} }
else if (TagHelper.IsDisabled || GetAttribute<DisabledInput>(TagHelper.AspFor.ModelExplorer) != null)
var attribute = GetAttribute<Placeholder>(TagHelper.AspFor.ModelExplorer);
if (attribute != null)
{ {
inputTagHelperOutput.Attributes.Add("disabled", ""); inputTagHelperOutput.Attributes.Add("placeholder", LocalizeText(attribute.Value));
} }
} }
protected virtual void AddReadOnlyAttribute(TagHelperOutput inputTagHelperOutput) protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput)
{ {
if (inputTagHelperOutput.Attributes.ContainsName("readonly")) if (GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer) == null)
{ {
return; return;
} }
else if (TagHelper.IsReadonly || GetAttribute<ReadOnlyInput>(TagHelper.AspFor.ModelExplorer) != null)
var idAttr = inputTagHelperOutput.Attributes.FirstOrDefault(a => a.Name == "id");
if (idAttr == null)
{ {
inputTagHelperOutput.Attributes.Add("readonly", ""); return;
} }
inputTagHelperOutput.Attributes.Add("aria-describedby", LocalizeText(idAttr.Value + "InfoText"));
}
protected virtual string LocalizeText(string text)
{
IStringLocalizer localizer = null;
var resourceType = _options.AssemblyResources.GetOrDefault(TagHelper.AspFor.ModelExplorer.ModelType.Assembly);
if (resourceType != null)
{
localizer = _stringLocalizerFactory.Create(resourceType);
}
return localizer == null? text: localizer[text].Value;
} }
protected virtual bool IsInputCheckbox(TagHelperContext context, TagHelperOutput output, TagHelperAttributeList attributes) protected virtual bool IsInputCheckbox(TagHelperContext context, TagHelperOutput output, TagHelperAttributeList attributes)
@ -185,6 +251,39 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
"</label>"; "</label>";
} }
protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox)
{
if (isCheckbox)
{
return "";
}
string text = "";
if (!string.IsNullOrEmpty(TagHelper.InfoText))
{
text = TagHelper.InfoText;
}
else
{
var infoAttribute = GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer);
if (infoAttribute != null)
{
text = infoAttribute.Text;
}
else
{
return "";
}
}
var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id");
return "<small id=\""+ idAttr?.Value + "InfoText\" class=\"form-text text-muted\">" +
LocalizeText(text) +
"</small>";
}
protected virtual string GetLabelAsHtmlUsingTagHelper(TagHelperContext context, TagHelperOutput output, bool isCheckbox) protected virtual string GetLabelAsHtmlUsingTagHelper(TagHelperContext context, TagHelperOutput output, bool isCheckbox)
{ {
var labelTagHelper = new LabelTagHelper(_generator) var labelTagHelper = new LabelTagHelper(_generator)
@ -254,5 +353,27 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
output.Attributes.Add(newAttritube); output.Attributes.Add(newAttritube);
} }
} }
protected virtual string GetSize(TagHelperContext context, TagHelperOutput output)
{
var attribute = GetAttribute<FormControlSize>(TagHelper.AspFor.ModelExplorer);
if (attribute != null)
{
TagHelper.Size = attribute.Size;
}
switch (TagHelper.Size)
{
case AbpFormControlSize.Small:
return "form-control-sm";
case AbpFormControlSize.Medium:
return "form-control-md";
case AbpFormControlSize.Large:
return "form-control-lg";
}
return "";
}
} }
} }

35
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs

@ -6,11 +6,23 @@ using System.Text;
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.Localization;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
public class AbpRadioInputTagHelperService : AbpTagHelperService<AbpRadioInputTagHelper> public class AbpRadioInputTagHelperService : AbpTagHelperService<AbpRadioInputTagHelper>
{ {
private readonly AbpMvcDataAnnotationsLocalizationOptions _options;
private readonly IStringLocalizerFactory _stringLocalizerFactory;
public AbpRadioInputTagHelperService(IOptions<AbpMvcDataAnnotationsLocalizationOptions> options, IStringLocalizerFactory stringLocalizerFactory)
{
_options = options.Value;
_stringLocalizerFactory = stringLocalizerFactory;
}
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {
var selectItems = GetSelectItems(context,output); var selectItems = GetSelectItems(context,output);
@ -19,7 +31,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var html = GetHtml(context, output, selectItems); var html = GetHtml(context, output, selectItems);
AddGroupToFormGroupContents(context, TagHelper.AspFor.Name, html, order, out var surpress); AddGroupToFormGroupContents(context, TagHelper.AspFor.Name, html, order, out var surpress);
if (surpress) if (surpress)
@ -76,12 +87,32 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual bool GetSelectItemsIfProvidedByEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List<SelectListItem> selectItems) protected virtual bool GetSelectItemsIfProvidedByEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List<SelectListItem> selectItems)
{ {
IStringLocalizer localizer = null;
var resourceType = _options.AssemblyResources.GetOrDefault(explorer.ModelType.Assembly);
if (resourceType != null)
{
localizer = _stringLocalizerFactory.Create(resourceType);
}
selectItems = explorer.Metadata.IsEnum ? explorer.ModelType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static) selectItems = explorer.Metadata.IsEnum ? explorer.ModelType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static)
.Select((t, i) => new SelectListItem { Value = i.ToString(), Text = t.Name }).ToList() : null; .Select((t, i) => new SelectListItem { Value = i.ToString(), Text = GetLocalizedPropertyName(localizer, explorer.ModelType, t.Name) }).ToList() : null;
return selectItems != null; return selectItems != null;
} }
protected virtual string GetLocalizedPropertyName(IStringLocalizer localizer, Type enumType, string propertyName)
{
if (localizer == null)
{
return propertyName;
}
var localizedString = localizer[enumType.Name + "." + propertyName];
return !localizedString.ResourceNotFound ? localizedString.Value : localizer[propertyName].Value;
}
protected virtual bool GetSelectItemsIfProvidedFromAttribute(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List<SelectListItem> selectItems) protected virtual bool GetSelectItemsIfProvidedFromAttribute(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List<SelectListItem> selectItems)
{ {
selectItems = GetAttribute<SelectItems>(explorer)?.GetItems(explorer)?.ToList(); selectItems = GetAttribute<SelectItems>(explorer)?.GetItems(explorer)?.ToList();

9
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpReadonlyInputType.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
public enum AbpReadonlyInputType
{
False,
True,
True_PlainText
}
}

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs

@ -13,6 +13,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
public IEnumerable<SelectListItem> AspItems { get; set; } public IEnumerable<SelectListItem> AspItems { get; set; }
public AbpFormControlSize Size { get; set; } = AbpFormControlSize.Default;
[HtmlAttributeName("info")]
public string InfoText { get; set; }
[HtmlAttributeNotBound] [HtmlAttributeNotBound]
[ViewContext] [ViewContext]
public ViewContext ViewContext { get; set; } public ViewContext ViewContext { get; set; }

197
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -7,6 +8,9 @@ using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.TagHelpers; using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
@ -15,11 +19,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
private readonly IHtmlGenerator _generator; private readonly IHtmlGenerator _generator;
private readonly HtmlEncoder _encoder; private readonly HtmlEncoder _encoder;
private readonly IStringLocalizerFactory _stringLocalizerFactory;
private readonly AbpMvcDataAnnotationsLocalizationOptions _options;
public AbpSelectTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder) public AbpSelectTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IOptions<AbpMvcDataAnnotationsLocalizationOptions> options, IStringLocalizerFactory stringLocalizerFactory)
{ {
_generator = generator; _generator = generator;
_encoder = encoder; _encoder = encoder;
_stringLocalizerFactory = stringLocalizerFactory;
_options = options.Value;
} }
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
@ -37,6 +45,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
else else
{ {
output.TagName = "div"; output.TagName = "div";
LeaveOnlyGroupAttributes(context, output);
output.Attributes.AddClass("form-group"); output.Attributes.AddClass("form-group");
output.TagMode = TagMode.StartTagAndEndTag; output.TagMode = TagMode.StartTagAndEndTag;
output.Content.SetHtmlContent(innerHtml); output.Content.SetHtmlContent(innerHtml);
@ -48,8 +57,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var selectTag = GetSelectTag(context, output); var selectTag = GetSelectTag(context, output);
var selectAsHtml = RenderTagHelperOutput(selectTag, _encoder); var selectAsHtml = RenderTagHelperOutput(selectTag, _encoder);
var label = GetLabelAsHtml(context, output, selectTag); var label = GetLabelAsHtml(context, output, selectTag);
var validation = GetValidationAsHtml(context, output, selectTag);
var infoText = GetInfoAsHtml(context, output, selectTag);
return label + Environment.NewLine + selectAsHtml; return label + Environment.NewLine + selectAsHtml + Environment.NewLine + infoText+ Environment.NewLine + validation;
} }
protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml) protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml)
@ -59,21 +70,21 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual TagHelperOutput GetSelectTag(TagHelperContext context, TagHelperOutput output) protected virtual TagHelperOutput GetSelectTag(TagHelperContext context, TagHelperOutput output)
{ {
var selectItems = GetSelectItems(context, output);
var selectTagHelper = new SelectTagHelper(_generator) var selectTagHelper = new SelectTagHelper(_generator)
{ {
For = TagHelper.AspFor, For = TagHelper.AspFor,
Items = selectItems, Items = GetSelectItems(context, output),
ViewContext = TagHelper.ViewContext ViewContext = TagHelper.ViewContext
}; };
var inputTagHelperOutput = GetInnerTagHelper(new TagHelperAttributeList(), context, selectTagHelper, "select", TagMode.StartTagAndEndTag); var selectTagHelperOutput = GetInnerTagHelper(GetInputAttributes(context, output), context, selectTagHelper, "select", TagMode.StartTagAndEndTag);
inputTagHelperOutput.Attributes.Add("class", "form-control"); selectTagHelperOutput.Attributes.AddClass("form-control");
AddDisabledAttribute(inputTagHelperOutput); selectTagHelperOutput.Attributes.AddClass(GetSize(context,output));
AddDisabledAttribute(selectTagHelperOutput);
AddInfoTextId(selectTagHelperOutput);
return inputTagHelperOutput; return selectTagHelperOutput;
} }
protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput) protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput)
@ -97,8 +108,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
throw new Exception("No items provided for select attribute."); throw new Exception("No items provided for select attribute.");
} }
SetSelectedValue(context, output, selectItems);
return selectItems; return selectItems;
} }
@ -112,14 +121,93 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return GetLabelAsHtmlUsingTagHelper(context, output); return GetLabelAsHtmlUsingTagHelper(context, output);
} }
protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput)
{
if (GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer) == null)
{
return;
}
var idAttr = inputTagHelperOutput.Attributes.FirstOrDefault(a => a.Name == "id");
if (idAttr == null)
{
return;
}
inputTagHelperOutput.Attributes.Add("aria-describedby", LocalizeText(idAttr.Value + "InfoText"));
}
protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
{
string text = "";
if (!string.IsNullOrEmpty(TagHelper.InfoText))
{
text = TagHelper.InfoText;
}
else
{
var infoAttribute = GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer);
if (infoAttribute != null)
{
text = infoAttribute.Text;
}
else
{
return "";
}
}
var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id");
return "<small id=\"" + idAttr?.Value + "InfoText\" class=\"form-text text-muted\">" +
LocalizeText(text) +
"</small>";
}
protected virtual string LocalizeText(string text)
{
var localizer = GetLocalizer();
return localizer == null ? text : localizer[text].Value;
}
protected virtual IStringLocalizer GetLocalizer()
{
IStringLocalizer localizer = null;
var resourceType = _options.AssemblyResources.GetOrDefault(TagHelper.AspFor.ModelExplorer.ModelType.Assembly);
if (resourceType != null)
{
localizer = _stringLocalizerFactory.Create(resourceType);
}
return localizer;
}
protected virtual bool GetSelectItemsIfProvidedByEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List<SelectListItem> selectItems) protected virtual bool GetSelectItemsIfProvidedByEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List<SelectListItem> selectItems)
{ {
var localizer = GetLocalizer();
selectItems = explorer.Metadata.IsEnum ? explorer.ModelType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static) selectItems = explorer.Metadata.IsEnum ? explorer.ModelType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static)
.Select((t, i) => new SelectListItem { Value = i.ToString(), Text = t.Name }).ToList() : null; .Select((t, i) => new SelectListItem { Value = i.ToString(), Text = GetLocalizedPropertyName(localizer, explorer.ModelType, t.Name) }).ToList() : null;
return selectItems != null; return selectItems != null;
} }
protected virtual string GetLocalizedPropertyName(IStringLocalizer localizer, Type enumType, string propertyName)
{
if (localizer == null)
{
return propertyName;
}
var localizedString = localizer[enumType.Name + "." + propertyName];
return !localizedString.ResourceNotFound ? localizedString.Value : localizer[propertyName].Value;
}
protected virtual bool GetSelectItemsIfProvidedFromAttribute(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List<SelectListItem> selectItems) protected virtual bool GetSelectItemsIfProvidedFromAttribute(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List<SelectListItem> selectItems)
{ {
selectItems = GetAttribute<SelectItems>(explorer)?.GetItems(explorer)?.ToList(); selectItems = GetAttribute<SelectItems>(explorer)?.GetItems(explorer)?.ToList();
@ -127,48 +215,85 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return selectItems != null; return selectItems != null;
} }
protected virtual void SetSelectedValue(TagHelperContext context, TagHelperOutput output, List<SelectListItem> selectItems) protected virtual string GetLabelAsHtmlUsingTagHelper(TagHelperContext context, TagHelperOutput output)
{ {
if (!selectItems.Any(si => si.Selected)) var labelTagHelper = new LabelTagHelper(_generator)
{ {
var selectedValue = GetSelectedValue(context, output); For = TagHelper.AspFor,
ViewContext = TagHelper.ViewContext
var itemToBeSelected = selectItems.FirstOrDefault(si => si.Value.ToString() == selectedValue); };
if (itemToBeSelected != null) return RenderTagHelper(new TagHelperAttributeList(), context, labelTagHelper, _encoder, "label", TagMode.StartTagAndEndTag, true);
{
itemToBeSelected.Selected = true;
}
}
} }
protected virtual string GetSelectedValue(TagHelperContext context, TagHelperOutput output) protected virtual string GetValidationAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
{ {
var modelExplorer = TagHelper.AspFor.ModelExplorer; if (inputTag.Attributes.Any(a => a.Name.ToLowerInvariant() == "type" && a.Value.ToString().ToLowerInvariant() == "hidden"))
{
return "";
}
if (modelExplorer.Metadata.IsEnum) var validationMessageTagHelper = new ValidationMessageTagHelper(_generator)
{ {
var baseType = modelExplorer.Model?.GetType().GetEnumUnderlyingType(); For = TagHelper.AspFor,
ViewContext = TagHelper.ViewContext
};
var attributeList = new TagHelperAttributeList { { "class", "text-danger" } };
return RenderTagHelper(attributeList, context, validationMessageTagHelper, _encoder, "span", TagMode.StartTagAndEndTag, true);
}
if (baseType == null) { return null; } protected virtual string GetSize(TagHelperContext context, TagHelperOutput output)
{
var attribute = GetAttribute<FormControlSize>(TagHelper.AspFor.ModelExplorer);
return Convert.ChangeType(modelExplorer.Model, baseType)?.ToString() ?? ""; if (attribute != null)
{
TagHelper.Size = attribute.Size;
} }
else
switch (TagHelper.Size)
{ {
return modelExplorer.Model?.ToString(); case AbpFormControlSize.Small:
return "form-control-sm";
case AbpFormControlSize.Medium:
return "form-control-md";
case AbpFormControlSize.Large:
return "form-control-lg";
} }
return "";
} }
protected virtual string GetLabelAsHtmlUsingTagHelper(TagHelperContext context, TagHelperOutput output) protected virtual TagHelperAttributeList GetInputAttributes(TagHelperContext context, TagHelperOutput output)
{ {
var labelTagHelper = new LabelTagHelper(_generator) var groupPrefix = "group-";
var tagHelperAttributes = output.Attributes.Where(a => !a.Name.StartsWith(groupPrefix)).ToList();
var attrList = new TagHelperAttributeList();
foreach (var tagHelperAttribute in tagHelperAttributes)
{ {
For = TagHelper.AspFor, attrList.Add(tagHelperAttribute);
ViewContext = TagHelper.ViewContext }
};
return RenderTagHelper(new TagHelperAttributeList(), context, labelTagHelper, _encoder, "label", TagMode.StartTagAndEndTag, true); return attrList;
}
protected virtual void LeaveOnlyGroupAttributes(TagHelperContext context, TagHelperOutput output)
{
var groupPrefix = "group-";
var tagHelperAttributes = output.Attributes.Where(a => a.Name.StartsWith(groupPrefix)).ToList();
output.Attributes.Clear();
foreach (var tagHelperAttribute in tagHelperAttributes)
{
var nameWithoutPrefix = tagHelperAttribute.Name.Substring(groupPrefix.Length);
var newAttritube = new TagHelperAttribute(nameWithoutPrefix, tagHelperAttribute.Value);
output.Attributes.Add(newAttritube);
}
} }
} }
} }

18
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/FormControlSize.cs

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
[AttributeUsage(AttributeTargets.Property)]
public class FormControlSize : Attribute
{
public AbpFormControlSize Size { get; set; }
public FormControlSize(AbpFormControlSize size)
{
Size = size;
}
}
}

18
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputInfoText.cs

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
[AttributeUsage(AttributeTargets.Property)]
public class InputInfoText : Attribute
{
public string Text { get; set; }
public InputInfoText(string text)
{
Text = text;
}
}
}

18
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/Placeholder.cs

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
[AttributeUsage(AttributeTargets.Property)]
public class Placeholder : Attribute
{
public string Value { get; set; }
public Placeholder(string value)
{
Value = value;
}
}
}

7
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs

@ -8,8 +8,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
public class ReadOnlyInput : Attribute public class ReadOnlyInput : Attribute
{ {
public bool PlainText { get; set; }
public ReadOnlyInput() public ReadOnlyInput()
{ {
} }
public ReadOnlyInput(bool plainText)
{
PlainText = plainText;
}
} }
} }

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelper.cs

@ -1,11 +0,0 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
{
public class AbpColBreakTagHelper : AbpTagHelper<AbpColBreakTagHelper, AbpColBreakTagHelperService>
{
public AbpColBreakTagHelper(AbpColBreakTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelper.cs

@ -0,0 +1,11 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
{
public class AbpColumnBreakerTagHelper : AbpTagHelper<AbpColumnBreakerTagHelper, AbpColumnBreakerTagHelperService>
{
public AbpColumnBreakerTagHelper(AbpColumnBreakerTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelperService.cs → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelperService.cs

@ -3,7 +3,7 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
{ {
public class AbpColBreakTagHelperService : AbpTagHelperService<AbpColBreakTagHelper> public class AbpColumnBreakerTagHelperService : AbpTagHelperService<AbpColumnBreakerTagHelper>
{ {
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs

@ -6,6 +6,8 @@
public HorizontalAlign HAlign { get; set; } = HorizontalAlign.Default; public HorizontalAlign HAlign { get; set; } = HorizontalAlign.Default;
public bool? Gutters { get; set; } = true;
public AbpRowTagHelper(AbpRowTagHelperService tagHelperService) public AbpRowTagHelper(AbpRowTagHelperService tagHelperService)
: base(tagHelperService) : base(tagHelperService)
{ {

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs

@ -12,6 +12,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
ProcessVerticalAlign(output); ProcessVerticalAlign(output);
ProcessHorizontalAlign(output); ProcessHorizontalAlign(output);
ProcessGutters(output);
} }
protected virtual void ProcessVerticalAlign(TagHelperOutput output) protected virtual void ProcessVerticalAlign(TagHelperOutput output)
@ -33,5 +34,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
output.Attributes.AddClass("justify-content-" + TagHelper.HAlign.ToString().ToLowerInvariant()); output.Attributes.AddClass("justify-content-" + TagHelper.HAlign.ToString().ToLowerInvariant());
} }
protected virtual void ProcessGutters(TagHelperOutput output)
{
if (TagHelper.Gutters ?? true)
{
return;
}
output.Attributes.AddClass("no-gutters");
}
} }
} }

10
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImagePosition.cs

@ -1,10 +0,0 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Image
{
public enum AbpImagePosition
{
Default,
Right,
Left,
Center
}
}

23
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelper.cs

@ -1,23 +0,0 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Image
{
public class AbpImageTagHelper : AbpTagHelper<AbpImageTagHelper, AbpImageTagHelperService>
{
public bool? Responsive { get; set; }
public bool? Thumbnail { get; set; }
public bool? Rounded { get; set; }
public AbpImagePosition Position { get; set; } = AbpImagePosition.Default;
public string Alt { get; set; }
public string Src { get; set; }
public AbpImageTagHelper(AbpImageTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

68
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelperService.cs

@ -1,68 +0,0 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Image
{
public class AbpImageTagHelperService : AbpTagHelperService<AbpImageTagHelper>
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "img";
SetSourceFile(context,output);
SetPosition(context,output);
SetResponsive(context,output);
SetThumbnail(context,output);
SetRounded(context,output);
SetAlt(context,output);
}
protected virtual void SetSourceFile(TagHelperContext context, TagHelperOutput output) {
output.Attributes.Add("src",TagHelper.Src);
}
protected virtual void SetPosition(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.Position == default)
{
return;
}
if (TagHelper.Position == AbpImagePosition.Left || TagHelper.Position == AbpImagePosition.Right)
{
output.Attributes.AddClass("float-" + TagHelper.Position.ToString().ToLowerInvariant());
}
if (TagHelper.Position == AbpImagePosition.Center)
{
output.PreElement.SetHtmlContent("<div class=\"text-center\">");
output.PostElement.SetHtmlContent("</div>");
}
}
protected virtual void SetResponsive(TagHelperContext context, TagHelperOutput output) {
if (TagHelper.Responsive ?? false)
{
output.Attributes.AddClass("img-fluid");
}
}
protected virtual void SetThumbnail(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.Thumbnail ?? false)
{
output.Attributes.AddClass("img-thumbnail");
}
}
protected virtual void SetRounded(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.Rounded ?? false)
{
output.Attributes.AddClass("rounded");
}
}
protected virtual void SetAlt(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.Add("alt",TagHelper.Alt);
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelper.cs

@ -4,6 +4,8 @@
{ {
public AbpModalSize Size { get; set; } = AbpModalSize.Default; public AbpModalSize Size { get; set; } = AbpModalSize.Default;
public bool? Centered { get; set; } = false;
public AbpModalTagHelper(AbpModalTagHelperService tagHelperService) public AbpModalTagHelper(AbpModalTagHelperService tagHelperService)
: base(tagHelperService) : base(tagHelperService)
{ {

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs

@ -36,6 +36,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
{ {
var classNames = new StringBuilder("modal-dialog"); var classNames = new StringBuilder("modal-dialog");
if (TagHelper.Centered ?? false)
{
classNames.Append(" ");
classNames.Append("modal-dialog-centered");
}
if (TagHelper.Size != AbpModalSize.Default) if (TagHelper.Size != AbpModalSize.Default)
{ {
classNames.Append(" "); classNames.Append(" ");

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelper.cs

@ -2,8 +2,6 @@
{ {
public class AbpNavItemTagHelper : AbpTagHelper<AbpNavItemTagHelper, AbpNavItemTagHelperService> public class AbpNavItemTagHelper : AbpTagHelper<AbpNavItemTagHelper, AbpNavItemTagHelperService>
{ {
public bool? Active { get; set; }
public bool? Dropdown { get; set; } public bool? Dropdown { get; set; }
public AbpNavItemTagHelper(AbpNavItemTagHelperService tagHelperService) public AbpNavItemTagHelper(AbpNavItemTagHelperService tagHelperService)

9
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelperService.cs

@ -11,7 +11,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Nav
output.Attributes.AddClass("nav-item"); output.Attributes.AddClass("nav-item");
SetDropdownClass(context, output); SetDropdownClass(context, output);
SetActiveClass(context, output);
} }
protected virtual void SetDropdownClass(TagHelperContext context, TagHelperOutput output) protected virtual void SetDropdownClass(TagHelperContext context, TagHelperOutput output)
@ -21,13 +20,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Nav
output.Attributes.AddClass("dropdown"); output.Attributes.AddClass("dropdown");
} }
} }
protected virtual void SetActiveClass(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.Active ?? false)
{
output.Attributes.AddClass("active");
}
}
} }
} }

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelper.cs

@ -8,8 +8,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Nav
public bool? Active { get; set; } public bool? Active { get; set; }
public bool? Disabled { get; set; } public bool? Disabled { get; set; }
public string Href { get; set; }
public AbpNavLinkTagHelper(AbpNavLinkTagHelperService tagHelperService) public AbpNavLinkTagHelper(AbpNavLinkTagHelperService tagHelperService)
: base(tagHelperService) : base(tagHelperService)

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelperService.cs

@ -13,11 +13,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Nav
output.TagName = "a"; output.TagName = "a";
output.TagMode = TagMode.StartTagAndEndTag; output.TagMode = TagMode.StartTagAndEndTag;
SetClasses(context, output); SetClasses(context, output);
if (!string.IsNullOrWhiteSpace(TagHelper.Href))
{
output.Attributes.Add("href", TagHelper.Href);
}
} }
protected virtual void SetClasses(TagHelperContext context, TagHelperOutput output) protected virtual void SetClasses(TagHelperContext context, TagHelperOutput output)

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressBarTagHelper.cs

@ -1,5 +1,9 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar
{ {
[HtmlTargetElement("abp-progress-bar")]
[HtmlTargetElement("abp-progress-part")]
public class AbpProgressBarTagHelper : AbpTagHelper<AbpProgressBarTagHelper, AbpProgressBarTagHelperService> public class AbpProgressBarTagHelper : AbpTagHelper<AbpProgressBarTagHelper, AbpProgressBarTagHelperService>
{ {
public double Value { get; set; } public double Value { get; set; }

16
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressBarTagHelperService.cs

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Razor.TagHelpers; using System;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar
@ -7,6 +8,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar
{ {
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {
SetParentElement(context, output);
output.Attributes.AddClass("progress-bar"); output.Attributes.AddClass("progress-bar");
output.Attributes.Add("role","progressbar"); output.Attributes.Add("role","progressbar");
@ -51,6 +54,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar
} }
} }
protected virtual void SetParentElement(TagHelperContext context, TagHelperOutput output)
{
if (output.TagName == "abp-progress-part")
{
return;
}
output.PreElement.SetHtmlContent("<div class=\"progress\">" + Environment.NewLine);
output.PostElement.SetHtmlContent(Environment.NewLine + "</div>");
}
protected virtual int CalculateStyleWidth() protected virtual int CalculateStyleWidth()
{ {
return (int)((TagHelper.Value - TagHelper.MinValue) * (100 / (TagHelper.MaxValue - TagHelper.MinValue))); return (int)((TagHelper.Value - TagHelper.MinValue) * (100 / (TagHelper.MaxValue - TagHelper.MinValue)));

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressGroupTagHelper.cs

@ -0,0 +1,11 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar
{
public class AbpProgressGroupTagHelper : AbpTagHelper<AbpProgressGroupTagHelper, AbpProgressGroupTagHelperService>
{
public AbpProgressGroupTagHelper(AbpProgressGroupTagHelperService groupTagHelperService)
: base(groupTagHelperService)
{
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressTagHelperService.cs → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressGroupTagHelperService.cs

@ -3,7 +3,7 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar
{ {
public class AbpProgressTagHelperService : AbpTagHelperService<AbpProgressTagHelper> public class AbpProgressGroupTagHelperService : AbpTagHelperService<AbpProgressGroupTagHelper>
{ {
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressTagHelper.cs

@ -1,11 +0,0 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar
{
public class AbpProgressTagHelper : AbpTagHelper<AbpProgressTagHelper, AbpProgressTagHelperService>
{
public AbpProgressTagHelper(AbpProgressTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Table/AbpTableStyleTagHelper.cs

@ -6,9 +6,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Table
[HtmlTargetElement("td")] [HtmlTargetElement("td")]
public class AbpTableStyleTagHelper : AbpTagHelper<AbpTableStyleTagHelper, AbpTableStyleTagHelperService> public class AbpTableStyleTagHelper : AbpTagHelper<AbpTableStyleTagHelper, AbpTableStyleTagHelperService>
{ {
public AbpTableStyle AbpTableStyle { get; set; } = AbpTableStyle.Default; public AbpTableStyle TableStyle { get; set; } = AbpTableStyle.Default;
public AbpTableStyle AbpDarkTableStyle { get; set; } = AbpTableStyle.Default;
public AbpTableStyleTagHelper(AbpTableStyleTagHelperService tagHelperService) public AbpTableStyleTagHelper(AbpTableStyleTagHelperService tagHelperService)
: base(tagHelperService) : base(tagHelperService)

12
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Table/AbpTableStyleTagHelperService.cs

@ -12,17 +12,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Table
protected virtual void SetStyle(TagHelperContext context, TagHelperOutput output) protected virtual void SetStyle(TagHelperContext context, TagHelperOutput output)
{ {
if (TagHelper.AbpTableStyle != AbpTableStyle.Default) if (TagHelper.TableStyle != AbpTableStyle.Default)
{ {
output.Attributes.AddClass("table-" + TagHelper.AbpTableStyle.ToString().ToLowerInvariant()); output.Attributes.AddClass("table-" + TagHelper.TableStyle.ToString().ToLowerInvariant());
}
}
protected virtual void SetDarkTableStyle(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.AbpDarkTableStyle != AbpTableStyle.Default)
{
output.Attributes.AddClass("bg-" + TagHelper.AbpDarkTableStyle.ToString().ToLowerInvariant());
} }
} }
} }

34
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tooltip/AbpTooltipTagHelperService.cs

@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Razor.TagHelpers; using System;
using System.Linq;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tooltip namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tooltip
{ {
@ -6,19 +8,40 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tooltip
{ {
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {
if (IsButtonDisabled(context, output))
{
SetParentElementWithTooltip(context, output);
return;
}
SetDataToggle(context, output); SetDataToggle(context, output);
SetDataPlacement(context, output); SetDataPlacement(context, output);
SetTooltipTitle(context, output); SetTooltipTitle(context, output);
} }
protected virtual void SetParentElementWithTooltip(TagHelperContext context, TagHelperOutput output)
{
var directory = GetDirectory() != TooltipDirectory.Default ? GetDirectory() : TooltipDirectory.Top;
output.Attributes.Add("data-placement", directory.ToString().ToLowerInvariant());
output.PreElement.SetHtmlContent(
"<span class=\"d-inline-block\" tabindex=\"0\" data-toggle=\"tooltip\" " +
"data-placement=\"" + directory.ToString().ToLowerInvariant() +
"\" title=\"" + GetTitle() + "\">" + Environment.NewLine);
output.PostElement.SetHtmlContent(Environment.NewLine + "</span>");
output.Attributes.Add("style", "pointer-events: none;");
}
protected virtual void SetDataToggle(TagHelperContext context, TagHelperOutput output) protected virtual void SetDataToggle(TagHelperContext context, TagHelperOutput output)
{ {
output.Attributes.Add("data-toggle","tooltip"); output.Attributes.Add("data-toggle", "tooltip");
} }
protected virtual void SetDataPlacement(TagHelperContext context, TagHelperOutput output) protected virtual void SetDataPlacement(TagHelperContext context, TagHelperOutput output)
{ {
var directory = GetDirectory() != TooltipDirectory.Default ? GetDirectory() : TooltipDirectory.Bottom; var directory = GetDirectory() != TooltipDirectory.Default ? GetDirectory() : TooltipDirectory.Top;
output.Attributes.Add("data-placement", directory.ToString().ToLowerInvariant()); output.Attributes.Add("data-placement", directory.ToString().ToLowerInvariant());
} }
@ -65,5 +88,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tooltip
return TooltipDirectory.Default; return TooltipDirectory.Default;
} }
protected virtual bool IsButtonDisabled(TagHelperContext context, TagHelperOutput output)
{
return output.Attributes.Any(a => a.Name == "disabled");
}
} }
} }

31
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleContributorOptions.cs

@ -0,0 +1,31 @@
using System;
using System.Collections.Concurrent;
using JetBrains.Annotations;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
{
public class BundleContributorOptions
{
public ConcurrentDictionary<Type, BundleContributorCollection> AllExtensions { get; }
public BundleContributorOptions()
{
AllExtensions = new ConcurrentDictionary<Type, BundleContributorCollection>();
}
public BundleContributorCollection Extensions<TContributor>()
{
return Extensions(typeof(TContributor));
}
public BundleContributorCollection Extensions([NotNull] Type contributorType)
{
Check.NotNull(contributorType, nameof(contributorType));
return AllExtensions.GetOrAdd(
contributorType,
_ => new BundleContributorCollection()
);
}
}
}

17
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleManager.cs

@ -21,6 +21,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
public ILogger<BundleManager> Logger { get; set; } public ILogger<BundleManager> Logger { get; set; }
protected readonly BundlingOptions Options; protected readonly BundlingOptions Options;
protected readonly BundleContributorOptions ContributorOptions;
protected readonly IWebContentFileProvider WebContentFileProvider; protected readonly IWebContentFileProvider WebContentFileProvider;
protected readonly IHostingEnvironment HostingEnvironment; protected readonly IHostingEnvironment HostingEnvironment;
protected readonly IScriptBundler ScriptBundler; protected readonly IScriptBundler ScriptBundler;
@ -32,6 +33,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
public BundleManager( public BundleManager(
IOptions<BundlingOptions> options, IOptions<BundlingOptions> options,
IOptions<BundleContributorOptions> contributorOptions,
IScriptBundler scriptBundler, IScriptBundler scriptBundler,
IStyleBundler styleBundler, IStyleBundler styleBundler,
IHostingEnvironment hostingEnvironment, IHostingEnvironment hostingEnvironment,
@ -41,6 +43,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
IWebContentFileProvider webContentFileProvider, IWebContentFileProvider webContentFileProvider,
IWebRequestResources requestResources) IWebRequestResources requestResources)
{ {
Options = options.Value;
ContributorOptions = contributorOptions.Value;
HostingEnvironment = hostingEnvironment; HostingEnvironment = hostingEnvironment;
ScriptBundler = scriptBundler; ScriptBundler = scriptBundler;
ServiceProvider = serviceProvider; ServiceProvider = serviceProvider;
@ -49,7 +53,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
WebContentFileProvider = webContentFileProvider; WebContentFileProvider = webContentFileProvider;
RequestResources = requestResources; RequestResources = requestResources;
StyleBundler = styleBundler; StyleBundler = styleBundler;
Options = options.Value;
Logger = NullLogger<BundleManager>.Instance; Logger = NullLogger<BundleManager>.Instance;
} }
@ -202,7 +205,19 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
protected virtual List<BundleContributor> GetContributors(BundleConfigurationCollection bundles, string bundleName) protected virtual List<BundleContributor> GetContributors(BundleConfigurationCollection bundles, string bundleName)
{ {
var contributors = new List<BundleContributor>(); var contributors = new List<BundleContributor>();
AddContributorsWithBaseBundles(contributors, bundles, bundleName); AddContributorsWithBaseBundles(contributors, bundles, bundleName);
for (var i = 0; i < contributors.Count; ++i)
{
var extensions = ContributorOptions.Extensions(contributors[i].GetType()).GetAll();
if (extensions.Count > 0)
{
contributors.InsertRange(i + 1, extensions);
i += extensions.Count;
}
}
return contributors; return contributors;
} }

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Clipboard/ClipboardScriptBundleContributor.cs

@ -1,6 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Clipboard namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Clipboard

16
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Prismjs/PrismjsScriptBundleContributor.cs

@ -0,0 +1,16 @@
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Clipboard;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Prismjs
{
[DependsOn(typeof(ClipboardScriptBundleContributor))]
public class PrismjsScriptBundleContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/prismjs/prism.js");
}
}
}

13
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Prismjs/PrismjsStyleBundleContributor.cs

@ -0,0 +1,13 @@
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Prismjs
{
public class PrismjsStyleBundleContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/prismjs/themes/prism-okaidia.css");
}
}
}

12
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

@ -75,14 +75,22 @@ namespace Volo.Abp.AspNetCore.Mvc
var mvcCoreBuilder = context.Services.AddMvcCore(); var mvcCoreBuilder = context.Services.AddMvcCore();
context.Services.ExecutePreConfiguredActions(mvcCoreBuilder); context.Services.ExecutePreConfiguredActions(mvcCoreBuilder);
var abpMvcDataAnnotationsLocalizationOptions = context.Services.ExecutePreConfiguredActions(new AbpMvcDataAnnotationsLocalizationOptions());
context.Services
.AddSingleton<IOptions<AbpMvcDataAnnotationsLocalizationOptions>>(
new OptionsWrapper<AbpMvcDataAnnotationsLocalizationOptions>(
abpMvcDataAnnotationsLocalizationOptions
)
);
var mvcBuilder = context.Services.AddMvc() var mvcBuilder = context.Services.AddMvc()
.AddDataAnnotationsLocalization(options => .AddDataAnnotationsLocalization(options =>
{ {
var assemblyResources = context.Services.ExecutePreConfiguredActions(new AbpMvcDataAnnotationsLocalizationOptions()).AssemblyResources;
options.DataAnnotationLocalizerProvider = (type, factory) => options.DataAnnotationLocalizerProvider = (type, factory) =>
{ {
var resourceType = assemblyResources.GetOrDefault(type.Assembly); var resourceType = abpMvcDataAnnotationsLocalizationOptions.AssemblyResources.GetOrDefault(type.Assembly);
return factory.Create(resourceType ?? type); return factory.Create(resourceType ?? type);
}; };
}) })

4
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention.cs

@ -233,11 +233,11 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
var controllerSetting = GetControllerSettingOrNull(controllerType); var controllerSetting = GetControllerSettingOrNull(controllerType);
if (controllerSetting?.RootPath != null) if (controllerSetting?.RootPath != null)
{ {
return GetControllerSettingOrNull(controllerType)?.RootPath; return controllerSetting.RootPath;
} }
var areaAttribute = controllerType.GetCustomAttributes().OfType<AreaAttribute>().FirstOrDefault(); var areaAttribute = controllerType.GetCustomAttributes().OfType<AreaAttribute>().FirstOrDefault();
if (areaAttribute.RouteValue != null) if (areaAttribute?.RouteValue != null)
{ {
return areaAttribute.RouteValue; return areaAttribute.RouteValue;
} }

13
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalControllerSetting.cs

@ -1,12 +1,11 @@
using System; using JetBrains.Annotations;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.AspNetCore.Mvc.Versioning;
using Volo.Abp.Application.Services; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Volo.Abp.Reflection; using Volo.Abp.Reflection;
namespace Volo.Abp.AspNetCore.Mvc.Conventions namespace Volo.Abp.AspNetCore.Mvc.Conventions
@ -17,7 +16,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
public Assembly Assembly { get; } public Assembly Assembly { get; }
[NotNull] [NotNull]
public HashSet<Type> ControllerTypes { get; } public HashSet<Type> ControllerTypes { get; } //TODO: Internal?
[NotNull] [NotNull]
public string RootPath public string RootPath

4
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultHttpExceptionStatusCodeFinder.cs

@ -39,6 +39,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
: HttpStatusCode.Unauthorized; : HttpStatusCode.Unauthorized;
} }
//TODO: Handle SecurityException..?
if (exception is AbpValidationException) if (exception is AbpValidationException)
{ {
return HttpStatusCode.BadRequest; return HttpStatusCode.BadRequest;
@ -58,7 +60,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
{ {
return HttpStatusCode.Forbidden; return HttpStatusCode.Forbidden;
} }
return HttpStatusCode.InternalServerError; return HttpStatusCode.InternalServerError;
} }
} }

2
framework/src/Volo.Abp.Core/System/Collections/Generic/AbpCollectionExtensions.cs

@ -75,7 +75,7 @@ namespace System.Collections.Generic
public static bool AddIfNotContains<T>([NotNull] this ICollection<T> source, [NotNull] Func<T, bool> predicate, [NotNull] Func<T> itemFactory) public static bool AddIfNotContains<T>([NotNull] this ICollection<T> source, [NotNull] Func<T, bool> predicate, [NotNull] Func<T> itemFactory)
{ {
Check.NotNull(source, nameof(source)); Check.NotNull(source, nameof(source));
Check.NotNull(source, nameof(predicate)); Check.NotNull(predicate, nameof(predicate));
Check.NotNull(itemFactory, nameof(itemFactory)); Check.NotNull(itemFactory, nameof(itemFactory));
if (source.Any(predicate)) if (source.Any(predicate))

35
framework/src/Volo.Abp.Core/Volo/Abp/IO/DirectoryHelper.cs

@ -1,4 +1,5 @@
using System.IO; using System.IO;
using JetBrains.Annotations;
namespace Volo.Abp.IO namespace Volo.Abp.IO
{ {
@ -7,10 +8,6 @@ namespace Volo.Abp.IO
/// </summary> /// </summary>
public static class DirectoryHelper public static class DirectoryHelper
{ {
/// <summary>
/// Creates a new directory if it does not exists.
/// </summary>
/// <param name="directory">Directory to create</param>
public static void CreateIfNotExists(string directory) public static void CreateIfNotExists(string directory)
{ {
if (!Directory.Exists(directory)) if (!Directory.Exists(directory))
@ -18,5 +15,35 @@ namespace Volo.Abp.IO
Directory.CreateDirectory(directory); Directory.CreateDirectory(directory);
} }
} }
public static bool IsSubDirectoryOf([NotNull] string parentDirectoryPath, [NotNull] string childDirectoryPath)
{
Check.NotNull(parentDirectoryPath, nameof(parentDirectoryPath));
Check.NotNull(childDirectoryPath, nameof(childDirectoryPath));
return IsSubDirectoryOf(
new DirectoryInfo(parentDirectoryPath),
new DirectoryInfo(childDirectoryPath)
);
}
public static bool IsSubDirectoryOf([NotNull] DirectoryInfo parentDirectory, [NotNull] DirectoryInfo childDirectory)
{
Check.NotNull(parentDirectory, nameof(parentDirectory));
Check.NotNull(childDirectory, nameof(childDirectory));
if (parentDirectory.FullName == childDirectory.FullName)
{
return true;
}
var parentOfChild = childDirectory.Parent;
if (parentOfChild == null)
{
return false;
}
return IsSubDirectoryOf(parentDirectory, parentOfChild);
}
} }
} }

35
framework/src/Volo.Abp.Core/Volo/Abp/IO/FileHelper.cs

@ -1,4 +1,7 @@
using System.IO; using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace Volo.Abp.IO namespace Volo.Abp.IO
@ -41,5 +44,35 @@ namespace Volo.Abp.IO
return fileNameWithExtension.Substring(lastDotIndex + 1); return fileNameWithExtension.Substring(lastDotIndex + 1);
} }
/// <summary>
/// Opens a text file, reads all lines of the file, and then closes the file.
/// </summary>
/// <param name="path">The file to open for reading.</param>
/// <returns>A string containing all lines of the file.</returns>
public static async Task<string> ReadAllTextAsync(string path)
{
using (var reader = File.OpenText(path))
{
return await reader.ReadToEndAsync();
}
}
/// <summary>
/// Opens a text file, reads all lines of the file, and then closes the file.
/// </summary>
/// <param name="path">The file to open for reading.</param>
/// <returns>A string containing all lines of the file.</returns>
public static async Task<byte[]> ReadAllBytesAsync(string path)
{
using (var stream = File.Open(path, FileMode.Open))
{
var result = new byte[stream.Length];
await stream.ReadAsync(result, 0, (int)stream.Length);
return result;
}
}
//TODO: ReadAllLinesAsync
} }
} }

4
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IEntity.cs

@ -6,6 +6,10 @@
/// </summary> /// </summary>
public interface IEntity public interface IEntity
{ {
/// <summary>
/// Returns an array of ordered keys for this entity.
/// </summary>
/// <returns></returns>
object[] GetKeys(); object[] GetKeys();
} }

1
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs

@ -14,7 +14,6 @@ using Volo.Abp.Localization.Resources.AbpValidation;
using Volo.Abp.MemoryDb; using Volo.Abp.MemoryDb;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.TestApp; using Volo.Abp.TestApp;
using Volo.Abp.UI;
using Volo.Abp.VirtualFileSystem; using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Mvc namespace Volo.Abp.AspNetCore.Mvc

255
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Alerts.cshtml

@ -10,84 +10,269 @@
</abp-style-bundle> </abp-style-bundle>
} }
@section scripts {
<abp-script-bundle>
@*<abp-script src="/libs/highlight.js/lib/highlight.js" />
<abp-script src="/Pages/Components/highlightCode.js" />*@
</abp-script-bundle>
}
<link rel="stylesheet"
href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/default.min.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<h2>Alerts</h2> <h2>Alerts</h2>
<p>Based on <a href="https://getbootstrap.com/docs/4.1/components/alerts/" target="_blank"> Bootstrap Alert</a>.</p> <p>Based on <a href="https://getbootstrap.com/docs/4.1/components/alerts/" target="_blank"> Bootstrap Alert</a>.</p>
<h4># Alert Example</h4> <h4>Examples</h4>
<div class="demo-with-code"> <div class="demo-with-code">
<div class="demo-area"> <div class="demo-area">
<abp-alert alert-type="Primary">
A simple primary alert—check it out!
</abp-alert>
<abp-alert alert-type="Secondary">
A simple secondary alert—check it out!
</abp-alert>
<abp-alert alert-type="Success">
A simple success alert—check it out!
</abp-alert>
<abp-alert alert-type="Danger"> <abp-alert alert-type="Danger">
I'm an abp alert! A simple danger alert—check it out!
</abp-alert>
<abp-alert alert-type="Warning">
A simple warning alert—check it out!
</abp-alert>
<abp-alert alert-type="Info">
A simple info alert—check it out!
</abp-alert>
<abp-alert alert-type="Light">
A simple light alert—check it out!
</abp-alert>
<abp-alert alert-type="Dark">
A simple dark alert—check it out!
</abp-alert> </abp-alert>
</div> </div>
<div class="code-area"> <div class="code-area">
<pre> <abp-tabs>
<abp-tab title="Tag Helper">
<pre><code>
&lt;abp-alert alert-type=&quot;Primary&quot;&gt;
A simple primary alert&mdash;check it out!
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Secondary&quot;&gt;
A simple secondary alert&mdash;check it out!
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Success&quot;&gt;
A simple success alert&mdash;check it out!
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Danger&quot;&gt; &lt;abp-alert alert-type=&quot;Danger&quot;&gt;
I&#39;m an abp alert! A simple danger alert&mdash;check it out!
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Warning&quot;&gt;
A simple warning alert&mdash;check it out!
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Info&quot;&gt;
A simple info alert&mdash;check it out!
&lt;/abp-alert&gt; &lt;/abp-alert&gt;
</pre> &lt;abp-alert alert-type=&quot;Light&quot;&gt;
A simple light alert&mdash;check it out!
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Dark&quot;&gt;
A simple dark alert&mdash;check it out!
&lt;/abp-alert&gt;
</code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
A simple primary alert&mdash;check it out!
&lt;/div&gt;
&lt;div class=&quot;alert alert-secondary&quot; role=&quot;alert&quot;&gt;
A simple secondary alert&mdash;check it out!
&lt;/div&gt;
&lt;div class=&quot;alert alert-success&quot; role=&quot;alert&quot;&gt;
A simple success alert&mdash;check it out!
&lt;/div&gt;
&lt;div class=&quot;alert alert-danger&quot; role=&quot;alert&quot;&gt;
A simple danger alert&mdash;check it out!
&lt;/div&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;
A simple warning alert&mdash;check it out!
&lt;/div&gt;
&lt;div class=&quot;alert alert-info&quot; role=&quot;alert&quot;&gt;
A simple info alert&mdash;check it out!
&lt;/div&gt;
&lt;div class=&quot;alert alert-light&quot; role=&quot;alert&quot;&gt;
A simple light alert&mdash;check it out!
&lt;/div&gt;
&lt;div class=&quot;alert alert-dark&quot; role=&quot;alert&quot;&gt;
A simple dark alert&mdash;check it out!
&lt;/div&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div> </div>
</div> </div>
<h4># Dismissible Alert Example</h4> <h4>Link color</h4>
<div class="demo-with-code"> <div class="demo-with-code">
<div class="demo-area"> <div class="demo-area">
<abp-alert alert-type="Primary">
<abp-alert alert-type="Warning" dismissible="true"> A simple primary alert with <a abp-alert-link href="#">an example link</a>. Give it a click if you like.
I'm a dismissible abp alert! </abp-alert>
<abp-alert alert-type="Secondary">
A simple secondary alert with <a abp-alert-link href="#">an example link</a>. Give it a click if you like.
</abp-alert>
<abp-alert alert-type="Success">
A simple success alert with <a abp-alert-link href="#">an example link</a>. Give it a click if you like.
</abp-alert>
<abp-alert alert-type="Danger">
A simple danger alert with <a abp-alert-link href="#">an example link</a>. Give it a click if you like.
</abp-alert>
<abp-alert alert-type="Warning">
A simple warning alert with <a abp-alert-link href="#">an example link</a>. Give it a click if you like.
</abp-alert>
<abp-alert alert-type="Info">
A simple info alert with <a abp-alert-link href="#">an example link</a>. Give it a click if you like.
</abp-alert>
<abp-alert alert-type="Light">
A simple light alert with <a abp-alert-link href="#">an example link</a>. Give it a click if you like.
</abp-alert>
<abp-alert alert-type="Dark">
A simple dark alert with <a abp-alert-link href="#">an example link</a>. Give it a click if you like.
</abp-alert> </abp-alert>
</div> </div>
<div class="code-area"> <div class="code-area">
<pre> <abp-tabs>
&lt;abp-alert alert-type=&quot;Warning&quot; dismissible=&quot;true&quot;&gt; <abp-tab title="Tag Helper">
I&#39;m a dismissible abp alert! <pre><code>
&lt;abp-alert alert-type=&quot;Primary&quot;&gt;
A simple primary alert with &lt;a abp-alert-link href=&quot;#&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Secondary&quot;&gt;
A simple secondary alert with &lt;a abp-alert-link href=&quot;#&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Success&quot;&gt;
A simple success alert with &lt;a abp-alert-link href=&quot;#&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Danger&quot;&gt;
A simple danger alert with &lt;a abp-alert-link href=&quot;#&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/abp-alert&gt; &lt;/abp-alert&gt;
</pre> &lt;abp-alert alert-type=&quot;Warning&quot;&gt;
A simple warning alert with &lt;a abp-alert-link href=&quot;#&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Info&quot;&gt;
A simple info alert with &lt;a abp-alert-link href=&quot;#&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Light&quot;&gt;
A simple light alert with &lt;a abp-alert-link href=&quot;#&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/abp-alert&gt;
&lt;abp-alert alert-type=&quot;Dark&quot;&gt;
A simple dark alert with &lt;a abp-alert-link href=&quot;#&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/abp-alert&gt;
</code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;div class=&quot;alert alert-primary&quot; role=&quot;alert&quot;&gt;
A simple primary alert with &lt;a href=&quot;#&quot; class=&quot;alert-link&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/div&gt;
&lt;div class=&quot;alert alert-secondary&quot; role=&quot;alert&quot;&gt;
A simple secondary alert with &lt;a href=&quot;#&quot; class=&quot;alert-link&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/div&gt;
&lt;div class=&quot;alert alert-success&quot; role=&quot;alert&quot;&gt;
A simple success alert with &lt;a href=&quot;#&quot; class=&quot;alert-link&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/div&gt;
&lt;div class=&quot;alert alert-danger&quot; role=&quot;alert&quot;&gt;
A simple danger alert with &lt;a href=&quot;#&quot; class=&quot;alert-link&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/div&gt;
&lt;div class=&quot;alert alert-warning&quot; role=&quot;alert&quot;&gt;
A simple warning alert with &lt;a href=&quot;#&quot; class=&quot;alert-link&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/div&gt;
&lt;div class=&quot;alert alert-info&quot; role=&quot;alert&quot;&gt;
A simple info alert with &lt;a href=&quot;#&quot; class=&quot;alert-link&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/div&gt;
&lt;div class=&quot;alert alert-light&quot; role=&quot;alert&quot;&gt;
A simple light alert with &lt;a href=&quot;#&quot; class=&quot;alert-link&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/div&gt;
&lt;div class=&quot;alert alert-dark&quot; role=&quot;alert&quot;&gt;
A simple dark alert with &lt;a href=&quot;#&quot; class=&quot;alert-link&quot;&gt;an example link&lt;/a&gt;. Give it a click if you like.
&lt;/div&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div> </div>
</div> </div>
<h4># Alert With Link Example</h4> <h4>Additional content</h4>
<div class="demo-with-code"> <div class="demo-with-code">
<div class="demo-area"> <div class="demo-area">
<abp-alert alert-type="Success">
<abp-alert alert-type="Secondary"> <h4>Well done!</h4>
I'm an abp alert with <a abp-alert-link href="#">Link</a>! <p>Aww yeah, you successfully read this important alert message. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.</p>
<hr>
<p class="mb-0">Whenever you need to, be sure to use margin utilities to keep things nice and tidy.</p>
</abp-alert> </abp-alert>
</div> </div>
<div class="code-area"> <div class="code-area">
<pre> <abp-tabs>
&lt;abp-alert alert-type=&quot;Info&quot;&gt; <abp-tab title="Tag Helper">
I&#39;m an abp alert with &lt;a abp-alert-link href=&quot;#&quot;&gt;Link&lt;/a&gt;! <pre><code>
&lt;abp-alert alert-type=&quot;Success&quot;&gt;
&lt;h4&gt;Well done!&lt;/h4&gt;
&lt;p&gt;Aww yeah, you successfully read this important alert message. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.&lt;/p&gt;
&lt;hr&gt;
&lt;p class=&quot;mb-0&quot;&gt;Whenever you need to, be sure to use margin utilities to keep things nice and tidy.&lt;/p&gt;
&lt;/abp-alert&gt; &lt;/abp-alert&gt;
</pre> </code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;div class=&quot;alert alert-success&quot; role=&quot;alert&quot;&gt;
&lt;h4 class=&quot;alert-heading&quot;&gt;Well done!&lt;/h4&gt;
&lt;p&gt;Aww yeah, you successfully read this important alert message. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.&lt;/p&gt;
&lt;hr&gt;
&lt;p class=&quot;mb-0&quot;&gt;Whenever you need to, be sure to use margin utilities to keep things nice and tidy.&lt;/p&gt;
&lt;/div&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div> </div>
</div> </div>
<h4># Alert With Header Example</h4> <h4>Dismissing</h4>
<div class="demo-with-code"> <div class="demo-with-code">
<div class="demo-area"> <div class="demo-area">
<abp-alert alert-type="Primary"> <abp-alert alert-type="Warning" dismissible="true">
<h4>Header</h4> Holy guacamole! You should check in on some of those fields below.
I'm an abp alert!
</abp-alert> </abp-alert>
</div> </div>
<div class="code-area"> <div class="code-area">
<pre> <abp-tabs>
&lt;abp-alert alert-type=&quot;Primary&quot;&gt; <abp-tab title="Tag Helper">
&lt;h4&gt;Header&lt;/h4&gt; <pre><code>
I&#39;m an abp alert! &lt;abp-alert alert-type=&quot;Warning&quot; dismissible=&quot;true&quot;&gt;
Holy guacamole! You should check in on some of those fields below.
&lt;/abp-alert&gt; &lt;/abp-alert&gt;
</pre> </code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;div class=&quot;alert alert-warning alert-dismissible fade show&quot; role=&quot;alert&quot;&gt;
Holy guacamole! You should check in on some of those fields below.
&lt;button type=&quot;button&quot; class=&quot;close&quot; data-dismiss=&quot;alert&quot; aria-label=&quot;Close&quot;&gt;
&lt;span aria-hidden=&quot;true&quot;&gt;&amp;times;&lt;/span&gt;
&lt;/button&gt;
&lt;/div&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div> </div>
</div> </div>

207
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Badges.cshtml

@ -10,30 +10,215 @@
</abp-style-bundle> </abp-style-bundle>
} }
@section scripts {
<abp-script-bundle>
@*<abp-script src="/libs/highlight.js/lib/highlight.js" />
<abp-script src="/Pages/Components/highlightCode.js" />*@
</abp-script-bundle>
}
<link rel="stylesheet"
href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/default.min.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<h2>Badges</h2> <h2>Badges</h2>
<p>Based on <a href="https://getbootstrap.com/docs/4.1/components/badge/" target="_blank"> Bootstrap Badge</a>.</p> <p>Based on <a href="https://getbootstrap.com/docs/4.1/components/badge/" target="_blank"> Bootstrap Badge</a>.</p>
<h4># Badges Examples</h4> <h4>Example</h4>
<div class="demo-with-code"> <div class="demo-with-code">
<div class="demo-area"> <div class="demo-area">
<span abp-badge="Primary">I'm an abp badge!</span> <h1>Example heading <span abp-badge="Secondary">New</span></h1>
<span abp-badge-pill="Warning">I'm an abp pill badge!</span> <h2>Example heading <span abp-badge="Secondary">New</span></h2>
<a abp-badge="Danger" href="#">I'm an abp badge link!</a> <h3>Example heading <span abp-badge="Secondary">New</span></h3>
<a abp-badge-pill="Success" href="#">I'm an abp pill badge link!</a> <h4>Example heading <span abp-badge="Secondary">New</span></h4>
<h5>Example heading <span abp-badge="Secondary">New</span></h5>
<h6>Example heading <span abp-badge="Secondary">New</span></h6>
</div>
<div class="code-area">
<abp-tabs>
<abp-tab title="Tag Helper">
<pre><code>
&lt;h1&gt;Example heading &lt;span abp-badge=&quot;Secondary&quot;&gt;New&lt;/span&gt;&lt;/h1&gt;
&lt;h2&gt;Example heading &lt;span abp-badge=&quot;Secondary&quot;&gt;New&lt;/span&gt;&lt;/h2&gt;
&lt;h3&gt;Example heading &lt;span abp-badge=&quot;Secondary&quot;&gt;New&lt;/span&gt;&lt;/h3&gt;
&lt;h4&gt;Example heading &lt;span abp-badge=&quot;Secondary&quot;&gt;New&lt;/span&gt;&lt;/h4&gt;
&lt;h5&gt;Example heading &lt;span abp-badge=&quot;Secondary&quot;&gt;New&lt;/span&gt;&lt;/h5&gt;
&lt;h6&gt;Example heading &lt;span abp-badge=&quot;Secondary&quot;&gt;New&lt;/span&gt;&lt;/h6&gt;
</code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;h1&gt;Example heading &lt;span class=&quot;badge badge-secondary&quot;&gt;New&lt;/span&gt;&lt;/h1&gt;
&lt;h2&gt;Example heading &lt;span class=&quot;badge badge-secondary&quot;&gt;New&lt;/span&gt;&lt;/h2&gt;
&lt;h3&gt;Example heading &lt;span class=&quot;badge badge-secondary&quot;&gt;New&lt;/span&gt;&lt;/h3&gt;
&lt;h4&gt;Example heading &lt;span class=&quot;badge badge-secondary&quot;&gt;New&lt;/span&gt;&lt;/h4&gt;
&lt;h5&gt;Example heading &lt;span class=&quot;badge badge-secondary&quot;&gt;New&lt;/span&gt;&lt;/h5&gt;
&lt;h6&gt;Example heading &lt;span class=&quot;badge badge-secondary&quot;&gt;New&lt;/span&gt;&lt;/h6&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div>
</div>
<div class="demo-with-code">
<div class="demo-area">
<abp-button button-type="Primary">
Notifications <span abp-badge="Light">4</span>
</abp-button>
</div> </div>
<div class="code-area"> <div class="code-area">
<pre> <abp-tabs>
&lt;span abp-badge=&quot;Primary&quot; &gt;I&#39;m an abp badge!&lt;/span&gt; <abp-tab title="Tag Helper">
<pre><code>
&lt;abp-button button-type=&quot;Primary&quot;&gt;
Notifications &lt;span abp-badge=&quot;Light&quot;&gt;4&lt;/span&gt;
&lt;/abp-button&gt;
</code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;button type=&quot;button&quot; class=&quot;btn btn-primary&quot;&gt;
Notifications &lt;span class=&quot;badge badge-light&quot;&gt;4&lt;/span&gt;
&lt;/button&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div>
</div>
&lt;span abp-badge-pill=&quot;Warning&quot; &gt;I&#39;m an abp pill badge!&lt;/span&gt; <h4>Contextual variations</h4>
&lt;a abp-badge=&quot;Danger&quot; href=&quot;#&quot; &gt;I&#39;m an abp badge link!&lt;/a&gt; <div class="demo-with-code">
<div class="demo-area">
&lt;a abp-badge-pill=&quot;Success&quot; href=&quot;#&quot; &gt;I&#39;m an abp pill badge link!&lt;/a&gt; <span abp-badge="Primary">Primary</span>
</pre> <span abp-badge="Secondary">Secondary</span>
<span abp-badge="Success">Success</span>
<span abp-badge="Danger">Danger</span>
<span abp-badge="Warning">Warning</span>
<span abp-badge="Info">Info</span>
<span abp-badge="Light">Light</span>
<span abp-badge="Dark">Dark</span>
</div>
<div class="code-area">
<abp-tabs>
<abp-tab title="Tag Helper">
<pre><code>
&lt;span abp-badge=&quot;Primary&quot;&gt;Primary&lt;/span&gt;
&lt;span abp-badge=&quot;Secondary&quot;&gt;Secondary&lt;/span&gt;
&lt;span abp-badge=&quot;Success&quot;&gt;Success&lt;/span&gt;
&lt;span abp-badge=&quot;Danger&quot;&gt;Danger&lt;/span&gt;
&lt;span abp-badge=&quot;Warning&quot;&gt;Warning&lt;/span&gt;
&lt;span abp-badge=&quot;Info&quot;&gt;Info&lt;/span&gt;
&lt;span abp-badge=&quot;Light&quot;&gt;Light&lt;/span&gt;
&lt;span abp-badge=&quot;Dark&quot;&gt;Dark&lt;/span&gt;
</code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;span class=&quot;badge badge-primary&quot;&gt;Primary&lt;/span&gt;
&lt;span class=&quot;badge badge-secondary&quot;&gt;Secondary&lt;/span&gt;
&lt;span class=&quot;badge badge-success&quot;&gt;Success&lt;/span&gt;
&lt;span class=&quot;badge badge-danger&quot;&gt;Danger&lt;/span&gt;
&lt;span class=&quot;badge badge-warning&quot;&gt;Warning&lt;/span&gt;
&lt;span class=&quot;badge badge-info&quot;&gt;Info&lt;/span&gt;
&lt;span class=&quot;badge badge-light&quot;&gt;Light&lt;/span&gt;
&lt;span class=&quot;badge badge-dark&quot;&gt;Dark&lt;/span&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div> </div>
</div> </div>
<h4>Pill badges</h4>
<div class="demo-with-code">
<div class="demo-area">
<span abp-badge-pill="Primary">Primary</span>
<span abp-badge-pill="Secondary">Secondary</span>
<span abp-badge-pill="Success">Success</span>
<span abp-badge-pill="Danger">Danger</span>
<span abp-badge-pill="Warning">Warning</span>
<span abp-badge-pill="Info">Info</span>
<span abp-badge-pill="Light">Light</span>
<span abp-badge-pill="Dark">Dark</span>
</div>
<div class="code-area">
<abp-tabs>
<abp-tab title="Tag Helper">
<pre><code>
&lt;span abp-badge-pill=&quot;Primary&quot;&gt;Primary&lt;/span&gt;
&lt;span abp-badge-pill=&quot;Secondary&quot;&gt;Secondary&lt;/span&gt;
&lt;span abp-badge-pill=&quot;Success&quot;&gt;Success&lt;/span&gt;
&lt;span abp-badge-pill=&quot;Danger&quot;&gt;Danger&lt;/span&gt;
&lt;span abp-badge-pill=&quot;Warning&quot;&gt;Warning&lt;/span&gt;
&lt;span abp-badge-pill=&quot;Info&quot;&gt;Info&lt;/span&gt;
&lt;span abp-badge-pill=&quot;Light&quot;&gt;Light&lt;/span&gt;
&lt;span abp-badge-pill=&quot;Dark&quot;&gt;Dark&lt;/span&gt;
</code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;span class=&quot;badge badge-pill badge-primary&quot;&gt;Primary&lt;/span&gt;
&lt;span class=&quot;badge badge-pill badge-secondary&quot;&gt;Secondary&lt;/span&gt;
&lt;span class=&quot;badge badge-pill badge-success&quot;&gt;Success&lt;/span&gt;
&lt;span class=&quot;badge badge-pill badge-danger&quot;&gt;Danger&lt;/span&gt;
&lt;span class=&quot;badge badge-pill badge-warning&quot;&gt;Warning&lt;/span&gt;
&lt;span class=&quot;badge badge-pill badge-info&quot;&gt;Info&lt;/span&gt;
&lt;span class=&quot;badge badge-pill badge-light&quot;&gt;Light&lt;/span&gt;
&lt;span class=&quot;badge badge-pill badge-dark&quot;&gt;Dark&lt;/span&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div>
</div>
<h4>Links</h4>
<div class="demo-with-code">
<div class="demo-area">
<a href="#" abp-badge="Primary">Primary</a>
<a href="#" abp-badge="Secondary">Secondary</a>
<a href="#" abp-badge="Success">Success</a>
<a href="#" abp-badge="Danger">Danger</a>
<a href="#" abp-badge="Warning">Warning</a>
<a href="#" abp-badge="Info">Info</a>
<a href="#" abp-badge="Light">Light</a>
<a href="#" abp-badge="Dark">Dark</a>
</div>
<div class="code-area">
<abp-tabs>
<abp-tab title="Tag Helper">
<pre><code>
&lt;a href=&quot;#&quot; abp-badge=&quot;Primary&quot;&gt;Primary&lt;/a&gt;
&lt;a href=&quot;#&quot; abp-badge=&quot;Secondary&quot;&gt;Secondary&lt;/a&gt;
&lt;a href=&quot;#&quot; abp-badge=&quot;Success&quot;&gt;Success&lt;/a&gt;
&lt;a href=&quot;#&quot; abp-badge=&quot;Danger&quot;&gt;Danger&lt;/a&gt;
&lt;a href=&quot;#&quot; abp-badge=&quot;Warning&quot;&gt;Warning&lt;/a&gt;
&lt;a href=&quot;#&quot; abp-badge=&quot;Info&quot;&gt;Info&lt;/a&gt;
&lt;a href=&quot;#&quot; abp-badge=&quot;Light&quot;&gt;Light&lt;/a&gt;
&lt;a href=&quot;#&quot; abp-badge=&quot;Dark&quot;&gt;Dark&lt;/a&gt;
</code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;a href=&quot;#&quot; class=&quot;badge badge-primary&quot;&gt;Primary&lt;/a&gt;
&lt;a href=&quot;#&quot; class=&quot;badge badge-secondary&quot;&gt;Secondary&lt;/a&gt;
&lt;a href=&quot;#&quot; class=&quot;badge badge-success&quot;&gt;Success&lt;/a&gt;
&lt;a href=&quot;#&quot; class=&quot;badge badge-danger&quot;&gt;Danger&lt;/a&gt;
&lt;a href=&quot;#&quot; class=&quot;badge badge-warning&quot;&gt;Warning&lt;/a&gt;
&lt;a href=&quot;#&quot; class=&quot;badge badge-info&quot;&gt;Info&lt;/a&gt;
&lt;a href=&quot;#&quot; class=&quot;badge badge-light&quot;&gt;Light&lt;/a&gt;
&lt;a href=&quot;#&quot; class=&quot;badge badge-dark&quot;&gt;Dark&lt;/a&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div>
</div>

223
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Borders.cshtml

@ -10,43 +10,206 @@
</abp-style-bundle> </abp-style-bundle>
} }
@section scripts {
<abp-script-bundle>
@*<abp-script src="/libs/highlight.js/lib/highlight.js" />
<abp-script src="/Pages/Components/highlightCode.js" />*@
</abp-script-bundle>
}
<style>
.border-span span {
display: inline-block;
width: 5rem;
height: 5rem;
margin: .25rem;
background-color: #f5f5f5;
}
</style>
<link rel="stylesheet"
href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/default.min.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<h2>Borders</h2> <h2>Borders</h2>
<p>Based on <a href="https://getbootstrap.com/docs/4.1/components/border/" target="_blank"> Bootstrap Border</a>.</p> <p>Based on <a href="https://getbootstrap.com/docs/4.1/components/border/" target="_blank"> Bootstrap Border</a>.</p>
<h4># Borders Examples</h4> <h4>Border</h4>
<h5>Additive</h5>
<div class="demo-with-code"> <div class="demo-with-code">
<div class="demo-area"> <div class="demo-area border-span">
<span abp-border="Default">aaa</span> <span abp-border="Default"></span>
<span abp-border="Top">bbb</span> <span abp-border="Top"></span>
<span abp-border="Right">ccc</span> <span abp-border="Right"></span>
<span abp-border="Left">ddd</span> <span abp-border="Bottom"></span>
<span abp-border="Bottom">eee</span> <span abp-border="Left"></span>
<span abp-border="Top_0">fff</span>
<span abp-border="Right_0">ggg</span>
<span abp-border="Left_0">hhh</span>
<span abp-border="Bottom_0">iii</span>
<span abp-border="Top_Primary">jjj</span>
<span abp-border="Warning_0">kkk</span>
<span abp-border="Bottom_Primary_0">lll</span>
<span abp-border="Left_Danger">mmm</span>
</div> </div>
<div class="code-area"> <div class="code-area">
<pre> <abp-tabs>
&lt;span abp-border=&quot;Default&quot;&gt;aaa&lt;/span&gt; <abp-tab title="Tag Helper">
&lt;span abp-border=&quot;Top&quot;&gt;bbb&lt;/span&gt; <pre><code>
&lt;span abp-border=&quot;Right&quot;&gt;ccc&lt;/span&gt; &lt;span abp-border=&quot;Default&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Left&quot;&gt;ddd&lt;/span&gt; &lt;span abp-border=&quot;Top&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Bottom&quot;&gt;eee&lt;/span&gt; &lt;span abp-border=&quot;Right&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Top_0&quot;&gt;fff&lt;/span&gt; &lt;span abp-border=&quot;Bottom&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Right_0&quot;&gt;ggg&lt;/span&gt; &lt;span abp-border=&quot;Left&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Left_0&quot;&gt;hhh&lt;/span&gt; </code></pre>
&lt;span abp-border=&quot;Bottom_0&quot;&gt;iii&lt;/span&gt; </abp-tab>
&lt;span abp-border=&quot;Top_Primary&quot;&gt;jjj&lt;/span&gt; <abp-tab title="Rendered">
&lt;span abp-border=&quot;Warning_0&quot;&gt;kkk&lt;/span&gt; <pre><code>
&lt;span abp-border=&quot;Bottom_Primary_0&quot;&gt;lll&lt;/span&gt; &lt;span class=&quot;border&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Left_Danger&quot;&gt;mmm&lt;/span&gt; &lt;span class=&quot;border-top&quot;&gt;&lt;/span&gt;
</pre> &lt;span class=&quot;border-right&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border-bottom&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border-left&quot;&gt;&lt;/span&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div> </div>
</div> </div>
<h5>Subtractive</h5>
<div class="demo-with-code">
<div class="demo-area border-span">
<span abp-border="_0"></span>
<span abp-border="Top_0"></span>
<span abp-border="Right_0"></span>
<span abp-border="Bottom_0"></span>
<span abp-border="Left_0"></span>
</div>
<div class="code-area">
<abp-tabs>
<abp-tab title="Tag Helper">
<pre><code>
&lt;span abp-border=&quot;_0&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Top_0&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Right_0&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Bottom_0&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Left_0&quot;&gt;&lt;/span&gt;
</code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;span class=&quot;borde-0&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border-top-0&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border-right-0&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border-bottom-0&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border-left-0&quot;&gt;&lt;/span&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div>
</div>
<h4>Border color</h4>
<div class="demo-with-code">
<div class="demo-area border-span">
<span abp-border="Primary"></span>
<span abp-border="Secondary"></span>
<span abp-border="Success"></span>
<span abp-border="Danger"></span>
<span abp-border="Info"></span>
<span abp-border="Light"></span>
<span abp-border="Dark"></span>
<span abp-border="White" ></span>
<br/>
<span abp-border="Left_Primary"></span>
<span abp-border="Top_Secondary"></span>
<span abp-border="Right_Success"></span>
<span abp-border="Bottom_Danger"></span>
<span abp-border="Bottom_Warning"></span>
<span abp-border="Left_Info"></span>
<span abp-border="Top_Light"></span>
<span abp-border="Right_Dark"></span>
</div>
<div class="code-area">
<abp-tabs>
<abp-tab title="Tag Helper">
<pre><code>
&lt;span abp-border=&quot;Primary&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Secondary&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Success&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Danger&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Info&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Light&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Dark&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;White&quot;&gt;&lt;/span&gt;
&lt;br/&gt;
&lt;span abp-border=&quot;Left_Primary&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Top_Secondary&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Right_Success&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Bottom_Danger&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;bottom_Warning&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Left_Info&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Top_Light&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Right_Dark&quot;&gt;&lt;/span&gt;
</code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;span class=&quot;border border-primary&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-secondary&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-success&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-danger&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-warning&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-info&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-light&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-dark&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-white&quot;&gt;&lt;/span&gt;
&lt;br/&gt;
&lt;span class=&quot;border border-left border-primary&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-top border-secondary&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-right border-success&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-bottom border-danger&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-bottom border-warning&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-left border-info&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-top border-light&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-right border-dark&quot;&gt;&lt;/span&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div>
</div>
<h4>Border-radius</h4>
<div class="demo-with-code">
<div class="demo-area border-span">
<span abp-border="Primary" abp-rounded="Default"></span>
<span abp-border="Primary" abp-rounded="_0"></span>
<span abp-border="Primary" abp-rounded="Top"></span>
<span abp-border="Primary" abp-rounded="Left"></span>
<span abp-border="Primary" abp-rounded="Bottom"></span>
<span abp-border="Primary" abp-rounded="Right"></span>
</div>
<div class="code-area">
<abp-tabs>
<abp-tab title="Tag Helper">
<pre><code>
&lt;span abp-border=&quot;Primary&quot; abp-rounded=&quot;Default&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Primary&quot; abp-rounded=&quot;_0&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Primary&quot; abp-rounded=&quot;Top&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Primary&quot; abp-rounded=&quot;Left&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Primary&quot; abp-rounded=&quot;Bottom&quot;&gt;&lt;/span&gt;
&lt;span abp-border=&quot;Primary&quot; abp-rounded=&quot;Right&quot;&gt;&lt;/span&gt;
</code></pre>
</abp-tab>
<abp-tab title="Rendered">
<pre><code>
&lt;span class=&quot;border border-primary rounded&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-primary rounded-0&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-primary rounded-top&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-primary rounded-left&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-primary rounded-bottom&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;border border-primary rounded-right&quot;&gt;&lt;/span&gt;
</code></pre>
</abp-tab>
</abp-tabs>
</div>
</div>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save