diff --git a/.gitignore b/.gitignore index cd63ac2e6c..9d3c3957aa 100644 --- a/.gitignore +++ b/.gitignore @@ -285,3 +285,12 @@ framework/test/Volo\.Abp\.AspNetCore\.Mvc\.UI\.Bootstrap\.Demo/package-lock\.jso modules/blogging/app/Volo\.BloggingTestApp/package-lock\.json templates/mvc/src/MyCompanyName\.MyProjectName\.Web/package-lock\.json +samples/MicroserviceDemo/applications/AuthServer.Host/Logs/logs.txt +samples/MicroserviceDemo/microservices/IdentityService.Host/Logs/logs.txt +samples/MicroserviceDemo/applications/BackendAdminApp.Host/Logs/logs.txt +samples/MicroserviceDemo/microservices/ProductService.Host/Logs/logs.txt +samples/MicroserviceDemo/gateways/InternalGateway.Host/Logs/logs.txt +samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/Logs/logs.txt +samples/MicroserviceDemo/applications/PublicWebSite.Host/Logs/logs.txt +samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/Logs/logs.txt +samples/MicroserviceDemo/microservices/BloggingService.Host/Logs/logs.txt diff --git a/README.md b/README.md index 5074216c59..f6304ad5b3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ABP -[![Build Status](http://vjenkins.dynu.net:5480/job/abp/badge/icon)](http://vjenkins.dynu.net:5480/blue/organizations/jenkins/abp/activity) +[![Build Status](http://vjenkins.dynu.net:5480/job/abp/badge/icon)](http://ci.volosoft.com:5480/blue/organizations/jenkins/abp/activity) This project is the next generation of the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) web application framework. See [the announcement](https://abp.io/blog/abp/Abp-vNext-Announcement). @@ -22,7 +22,7 @@ See the documentation. #### Pre Requirements -- Visual Studio 2017 15.7.0+ +- Visual Studio 2017 15.9.0+ #### Framework diff --git a/abp_io/src/Volo.AbpWebSite.Application/Volo.AbpWebSite.Application.csproj b/abp_io/src/Volo.AbpWebSite.Application/Volo.AbpWebSite.Application.csproj index ec07e51ed1..4a5c64eb64 100644 --- a/abp_io/src/Volo.AbpWebSite.Application/Volo.AbpWebSite.Application.csproj +++ b/abp_io/src/Volo.AbpWebSite.Application/Volo.AbpWebSite.Application.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp2.2 diff --git a/abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj b/abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj index b0ac5294bc..b0c9926b35 100644 --- a/abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj +++ b/abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp2.2 @@ -12,7 +12,7 @@ - + diff --git a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.Designer.cs b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.Designer.cs new file mode 100644 index 0000000000..9a3dd1e999 --- /dev/null +++ b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.Designer.cs @@ -0,0 +1,826 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.AbpWebSite.EntityFrameworkCore; + +namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations +{ + [DbContext(typeof(AbpWebSiteDbContext))] + [Migration("20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties")] + partial class Added_ConcurrencyStamp_IsDeleted_ExtraProperties + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.4-rtm-31024") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("Description") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256); + + b.Property("Regex") + .HasMaxLength(512); + + b.Property("RegexDescription") + .HasMaxLength(128); + + b.Property("Required"); + + b.Property("ValueType"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasMaxLength(1024); + + b.Property("RoleId"); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnName("AccessFailedCount") + .HasDefaultValue(0); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .HasColumnName("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("EmailConfirmed") + .HasDefaultValue(false); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("LockoutEnabled") + .HasDefaultValue(false); + + b.Property("LockoutEnd"); + + b.Property("Name") + .HasColumnName("Name") + .HasMaxLength(64); + + b.Property("NormalizedEmail") + .HasColumnName("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .IsRequired() + .HasColumnName("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnName("PasswordHash") + .HasMaxLength(256); + + b.Property("PhoneNumber") + .HasColumnName("PhoneNumber") + .HasMaxLength(16); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("PhoneNumberConfirmed") + .HasDefaultValue(false); + + b.Property("SecurityStamp") + .IsRequired() + .HasColumnName("SecurityStamp") + .HasMaxLength(256); + + b.Property("Surname") + .HasColumnName("Surname") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("TwoFactorEnabled") + .HasDefaultValue(false); + + b.Property("UserName") + .IsRequired() + .HasColumnName("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasMaxLength(1024); + + b.Property("TenantId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(64); + + b.Property("ProviderDisplayName") + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196); + + b.Property("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.Property("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(64); + + b.Property("Name") + .HasMaxLength(128); + + b.Property("TenantId"); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpPermissionGrants"); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasMaxLength(64); + + b.Property("ProviderName") + .HasMaxLength(64); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpSettings"); + }); + + modelBuilder.Entity("Volo.Blogging.Blogs.Blog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnName("Description") + .HasMaxLength(1024); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnName("Name") + .HasMaxLength(256); + + b.Property("ShortName") + .IsRequired() + .HasColumnName("ShortName") + .HasMaxLength(32); + + b.HasKey("Id"); + + b.ToTable("BlgBlogs"); + }); + + modelBuilder.Entity("Volo.Blogging.Comments.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); + + b.Property("PostId") + .HasColumnName("PostId"); + + b.Property("RepliedCommentId") + .HasColumnName("RepliedCommentId"); + + b.Property("Text") + .IsRequired() + .HasColumnName("Text") + .HasMaxLength(1024); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("RepliedCommentId"); + + b.ToTable("BlgComments"); + }); + + modelBuilder.Entity("Volo.Blogging.Posts.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BlogId") + .HasColumnName("BlogId"); + + b.Property("ConcurrencyStamp"); + + b.Property("Content") + .HasColumnName("Content") + .HasMaxLength(1048576); + + b.Property("CoverImage") + .IsRequired() + .HasColumnName("CoverImage"); + + b.Property("CreationTime") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); + + b.Property("ReadCount"); + + b.Property("Title") + .IsRequired() + .HasColumnName("Title") + .HasMaxLength(512); + + b.Property("Url") + .IsRequired() + .HasColumnName("Url") + .HasMaxLength(64); + + b.HasKey("Id"); + + b.HasIndex("BlogId"); + + b.ToTable("BlgPosts"); + }); + + modelBuilder.Entity("Volo.Blogging.Posts.PostTag", b => + { + b.Property("PostId") + .HasColumnName("PostId"); + + b.Property("TagId") + .HasColumnName("TagId"); + + b.Property("CreationTime"); + + b.Property("CreatorId"); + + b.HasKey("PostId", "TagId"); + + b.HasIndex("TagId"); + + b.ToTable("BlgPostTags"); + }); + + modelBuilder.Entity("Volo.Blogging.Tagging.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BlogId"); + + b.Property("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnName("Description") + .HasMaxLength(512); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnName("Name") + .HasMaxLength(64); + + b.Property("UsageCount") + .HasColumnName("UsageCount"); + + b.HasKey("Id"); + + b.ToTable("BlgTags"); + }); + + modelBuilder.Entity("Volo.Blogging.Users.BlogUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp"); + + b.Property("Email") + .HasColumnName("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("EmailConfirmed") + .HasDefaultValue(false); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .HasColumnName("Name") + .HasMaxLength(64); + + b.Property("PhoneNumber") + .HasColumnName("PhoneNumber") + .HasMaxLength(16); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("PhoneNumberConfirmed") + .HasDefaultValue(false); + + b.Property("Surname") + .HasColumnName("Surname") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId"); + + b.Property("UserName") + .IsRequired() + .HasColumnName("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.ToTable("BlgUsers"); + }); + + modelBuilder.Entity("Volo.Docs.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); + + b.Property("DefaultDocumentName") + .IsRequired() + .HasMaxLength(128); + + b.Property("DocumentStoreType"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("Format"); + + b.Property("LatestVersionBranchName") + .HasMaxLength(128); + + b.Property("MainWebsiteUrl"); + + b.Property("MinimumVersion"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("NavigationDocumentName") + .IsRequired() + .HasMaxLength(128); + + b.Property("ShortName") + .IsRequired() + .HasMaxLength(32); + + b.HasKey("Id"); + + b.ToTable("DocsProjects"); + }); + + modelBuilder.Entity("Volo.Utils.SolutionTemplating.DownloadInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDuration"); + + b.Property("CreationTime") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnName("CreatorId"); + + b.Property("DatabaseProvider"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("ProjectName") + .IsRequired() + .HasMaxLength(128); + + b.Property("TemplateName") + .IsRequired() + .HasMaxLength(42); + + b.Property("Version") + .IsRequired() + .HasMaxLength(20); + + b.HasKey("Id"); + + b.ToTable("Downloads"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole") + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Blogging.Comments.Comment", b => + { + b.HasOne("Volo.Blogging.Posts.Post") + .WithMany() + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Volo.Blogging.Comments.Comment") + .WithMany() + .HasForeignKey("RepliedCommentId"); + }); + + modelBuilder.Entity("Volo.Blogging.Posts.Post", b => + { + b.HasOne("Volo.Blogging.Blogs.Blog") + .WithMany() + .HasForeignKey("BlogId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Blogging.Posts.PostTag", b => + { + b.HasOne("Volo.Blogging.Posts.Post") + .WithMany("Tags") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Volo.Blogging.Tagging.Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.cs b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.cs new file mode 100644 index 0000000000..c354338499 --- /dev/null +++ b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/20181227114311_Added_ConcurrencyStamp_IsDeleted_ExtraProperties.cs @@ -0,0 +1,77 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations +{ + public partial class Added_ConcurrencyStamp_IsDeleted_ExtraProperties : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "IsDeleted", + table: "AbpUsers", + nullable: false, + defaultValue: false, + oldClrType: typeof(bool)); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "AbpUsers", + nullable: true, + oldClrType: typeof(string), + oldMaxLength: 256); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "AbpRoles", + maxLength: 256, + nullable: false, + oldClrType: typeof(string), + oldNullable: true); + + migrationBuilder.AddColumn( + name: "ConcurrencyStamp", + table: "AbpClaimTypes", + maxLength: 256, + nullable: false, + defaultValue: ""); + + migrationBuilder.AddColumn( + name: "ExtraProperties", + table: "AbpClaimTypes", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ConcurrencyStamp", + table: "AbpClaimTypes"); + + migrationBuilder.DropColumn( + name: "ExtraProperties", + table: "AbpClaimTypes"); + + migrationBuilder.AlterColumn( + name: "IsDeleted", + table: "AbpUsers", + nullable: false, + oldClrType: typeof(bool), + oldDefaultValue: false); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "AbpUsers", + maxLength: 256, + nullable: false, + oldClrType: typeof(string), + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "AbpRoles", + nullable: true, + oldClrType: typeof(string), + oldMaxLength: 256); + } + } +} diff --git a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/AbpWebSiteDbContextModelSnapshot.cs b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/AbpWebSiteDbContextModelSnapshot.cs index f1af866317..b997aae5ca 100644 --- a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/AbpWebSiteDbContextModelSnapshot.cs +++ b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Migrations/AbpWebSiteDbContextModelSnapshot.cs @@ -15,7 +15,7 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.1.1-rtm-30846") + .HasAnnotation("ProductVersion", "2.1.4-rtm-31024") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -24,9 +24,18 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + b.Property("Description") .HasMaxLength(256); + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + b.Property("IsStatic"); b.Property("Name") @@ -53,7 +62,11 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations b.Property("Id") .ValueGeneratedOnAdd(); - b.Property("ConcurrencyStamp"); + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); b.Property("ExtraProperties") .HasColumnName("ExtraProperties"); @@ -118,17 +131,20 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations .HasDefaultValue(0); b.Property("ConcurrencyStamp") - .IsRequired() - .HasColumnName("ConcurrencyStamp") - .HasMaxLength(256); + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); - b.Property("CreationTime"); + b.Property("CreationTime") + .HasColumnName("CreationTime"); - b.Property("CreatorId"); + b.Property("CreatorId") + .HasColumnName("CreatorId"); - b.Property("DeleterId"); + b.Property("DeleterId") + .HasColumnName("DeleterId"); - b.Property("DeletionTime"); + b.Property("DeletionTime") + .HasColumnName("DeletionTime"); b.Property("Email") .HasColumnName("Email") @@ -142,11 +158,16 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations b.Property("ExtraProperties") .HasColumnName("ExtraProperties"); - b.Property("IsDeleted"); + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasDefaultValue(false); - b.Property("LastModificationTime"); + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); - b.Property("LastModifierId"); + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); b.Property("LockoutEnabled") .ValueGeneratedOnAdd() @@ -641,7 +662,9 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations b.Property("Id") .ValueGeneratedOnAdd(); - b.Property("ConcurrencyStamp"); + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); b.Property("DefaultDocumentName") .IsRequired() @@ -685,13 +708,16 @@ namespace Volo.AbpWebSite.EntityFrameworkCore.Migrations .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property("ConcurrencyStamp") - .IsConcurrencyToken(); + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); b.Property("CreationDuration"); - b.Property("CreationTime"); + b.Property("CreationTime") + .HasColumnName("CreationTime"); - b.Property("CreatorId"); + b.Property("CreatorId") + .HasColumnName("CreatorId"); b.Property("DatabaseProvider"); diff --git a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Volo.AbpWebSite.EntityFrameworkCore.csproj b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Volo.AbpWebSite.EntityFrameworkCore.csproj index 892d56593c..936a8cca19 100644 --- a/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Volo.AbpWebSite.EntityFrameworkCore.csproj +++ b/abp_io/src/Volo.AbpWebSite.EntityFrameworkCore/Volo.AbpWebSite.EntityFrameworkCore.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp2.2 @@ -11,7 +11,7 @@ - + diff --git a/abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs b/abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs index a66d7bb11a..bbbce26cee 100644 --- a/abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs +++ b/abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs @@ -1,22 +1,20 @@ -using System.Globalization; -using System.IO; +using System.IO; using System.Linq; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Localization; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Volo.Abp; using Volo.Abp.Account.Web; -using Volo.Abp.AspNetCore.Modularity; using Volo.Abp.AspNetCore.Mvc.UI; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Theming; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.Autofac; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; @@ -24,9 +22,10 @@ using Volo.Abp.Identity; using Volo.Abp.Identity.Web; using Volo.Abp.Localization; using Volo.Abp.Modularity; +using Volo.Abp.PermissionManagement; +using Volo.Abp.PermissionManagement.Identity; using Volo.Abp.Threading; using Volo.Abp.UI; -using Volo.Abp.UI.Navigation; using Volo.Abp.VirtualFileSystem; using Volo.AbpWebSite.Bundling; using Volo.Blogging; @@ -44,30 +43,33 @@ namespace Volo.AbpWebSite typeof(AbpAccountWebModule), typeof(AbpIdentityApplicationModule), typeof(AbpIdentityWebModule), + typeof(AbpPermissionManagementApplicationModule), + typeof(AbpPermissionManagementDomainIdentityModule), typeof(BloggingApplicationModule), typeof(BloggingWebModule) )] public class AbpWebSiteWebModule : AbpModule { - public override void PreConfigureServices(ServiceConfigurationContext context) - { - context.Services.PreConfigure(options => - { - options.UserSecretsAssembly = typeof(AbpWebSiteWebModule).Assembly; - }); - } - public override void ConfigureServices(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); var configuration = context.Services.GetConfiguration(); + ConfigureLanguages(context.Services); ConfigureDatabaseServices(context.Services, configuration); ConfigureVirtualFileSystem(context.Services, hostingEnvironment); ConfigureBundles(context.Services); ConfigureTheme(context.Services); } + private static void ConfigureLanguages(IServiceCollection services) + { + services.Configure(options => + { + options.Languages.Add(new LanguageInfo("en-US", "en-US", "English")); + }); + } + private static void ConfigureBundles(IServiceCollection services) { services.Configure(options => @@ -112,14 +114,14 @@ namespace Volo.AbpWebSite { services.Configure(options => { - options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.UI", Path.DirectorySeparatorChar))); - options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI", Path.DirectorySeparatorChar))); - options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI.Bootstrap", Path.DirectorySeparatorChar))); - options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared", Path.DirectorySeparatorChar))); - options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Domain", Path.DirectorySeparatorChar))); - options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Web", Path.DirectorySeparatorChar))); - options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}blogging{0}src{0}Volo.Blogging.Web", Path.DirectorySeparatorChar))); - options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}account{0}src{0}Volo.Abp.Account.Web", Path.DirectorySeparatorChar))); + options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.UI", Path.DirectorySeparatorChar))); + options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI", Path.DirectorySeparatorChar))); + options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI.Bootstrap", Path.DirectorySeparatorChar))); + options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}framework{0}src{0}Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared", Path.DirectorySeparatorChar))); + options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Domain", Path.DirectorySeparatorChar))); + options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}docs{0}src{0}Volo.Docs.Web", Path.DirectorySeparatorChar))); + options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}blogging{0}src{0}Volo.Blogging.Web", Path.DirectorySeparatorChar))); + options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}..{0}modules{0}account{0}src{0}Volo.Abp.Account.Web", Path.DirectorySeparatorChar))); }); } } @@ -138,12 +140,7 @@ namespace Volo.AbpWebSite var app = context.GetApplicationBuilder(); var env = context.GetEnvironment(); - app.UseRequestLocalization(options => - { - options.DefaultRequestCulture = new RequestCulture("en-US", "en-US"); - options.AddSupportedCultures("en-US"); - options.AddSupportedUICultures("en-US"); - }); + app.UseAbpRequestLocalization(); if (env.IsDevelopment()) { @@ -165,29 +162,28 @@ namespace Volo.AbpWebSite app.UseVirtualFiles(); app.UseAuthentication(); - - //TODO: Create an extension method! - app.UseMvc(routes => - { - routes.MapRoute( - name: "defaultWithArea", - template: "{area}/{controller=Home}/{action=Index}/{id?}"); - routes.MapRoute( - name: "default", - template: "{controller=Home}/{action=Index}/{id?}"); - }); + app.UseMvcWithDefaultRouteAndArea(); - AsyncHelper.RunSync(async () => + using (var scope = context.ServiceProvider.CreateScope()) { - await context.ServiceProvider - .GetRequiredService() - .SeedAsync( - "1q2w3E*", - IdentityPermissions.GetAll() - .Union(BloggingPermissions.GetAll()) - ); - }); + AsyncHelper.RunSync(async () => + { + await scope.ServiceProvider + .GetRequiredService() + .SeedAsync( + "1q2w3E*" + ); + + await scope.ServiceProvider + .GetRequiredService() + .SeedAsync( + RolePermissionValueProvider.ProviderName, + "admin", + IdentityPermissions.GetAll().Union(BloggingPermissions.GetAll()) + ); + }); + } } } } diff --git a/abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml b/abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml index bf74126618..010209c690 100644 --- a/abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml +++ b/abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml @@ -195,34 +195,34 @@

-
+
 
                     
-<abp-card>
-    <img abp-card-image="Top" src="~/images/my-dog.png" />
-    <abp-card-body>
-        <abp-card-title>Card title</abp-card-title>
-        <abp-card-text>
-            <p>
-                This is a sample card component built by ABP bootstrap
-                card tag helper. ABP has tag helper wrappers for most of 
-                the bootstrap components.
-            </p>
-        </abp-card-text>
-        <a abp-button="Primary" href="#">Go somewhere &rarr;</a>
-    </abp-card-body>
-</abp-card>
+                    <abp-card>
+                        <img abp-card-image="Top" src="~/images/my-dog.png" />
+                        <abp-card-body>
+                            <abp-card-title>Card title</abp-card-title>
+                            <abp-card-text>
+                                <p>
+                                    This is a sample card component built by ABP bootstrap
+                                    card tag helper. ABP has tag helper wrappers for most of 
+                                    the bootstrap components.
+                                </p>
+                            </abp-card-text>
+                            <a abp-button="Primary" href="#">Go somewhere &rarr;</a>
+                        </abp-card-body>
+                    </abp-card>
                         
                     
-
+
-
+
@@ -265,7 +265,7 @@
-
+
 
                     
@@ -300,12 +300,12 @@ public class PersonModel
                     
-
+
-
+
diff --git a/abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml b/abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml index c3d877b425..8c25d6592b 100644 --- a/abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml +++ b/abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml @@ -26,8 +26,7 @@ Github
  • -
  • diff --git a/abp_io/src/Volo.AbpWebSite.Web/Startup.cs b/abp_io/src/Volo.AbpWebSite.Web/Startup.cs index 471337df1c..efbfda982a 100644 --- a/abp_io/src/Volo.AbpWebSite.Web/Startup.cs +++ b/abp_io/src/Volo.AbpWebSite.Web/Startup.cs @@ -15,6 +15,7 @@ namespace Volo.AbpWebSite services.AddApplication(options => { options.UseAutofac(); + options.Configuration.UserSecretsAssembly = typeof(AbpWebSiteWebModule).Assembly; }); return services.BuildServiceProviderFromFactory(); diff --git a/abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj b/abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj index 06fad8f448..8fbbbfd711 100644 --- a/abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj +++ b/abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp2.2 Volo.AbpWebSite $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; true @@ -14,7 +14,7 @@ - + @@ -31,6 +31,8 @@ + + @@ -38,7 +40,7 @@ Always - + Always diff --git a/abp_io/src/Volo.AbpWebSite.Web/package-lock.json b/abp_io/src/Volo.AbpWebSite.Web/package-lock.json new file mode 100644 index 0000000000..5e26238da6 --- /dev/null +++ b/abp_io/src/Volo.AbpWebSite.Web/package-lock.json @@ -0,0 +1,2758 @@ +{ + "name": "volo.aspnetzero.support", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@abp/anchor-js": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@abp/anchor-js/-/anchor-js-0.5.1.tgz", + "integrity": "sha512-9N/iPP9tDdq9lKRNFQuqRL+QYSv5fq789KgHHGG1/MqExJ6KTPcqUDHvQ53kz96pUgJA+Fyn3dpwgPqLVYI3Yg==", + "requires": { + "@abp/core": "^0.4.9", + "anchor-js": "^4.1.1" + } + }, + "@abp/aspnetcore.mvc.ui": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-0.4.9.tgz", + "integrity": "sha512-AveMEi6WRQmD1tM9yVNLAe6ffcbtoL3ZGQKTPA95Q+dy5xBXVg4Y8jdhxawNPK64KYArhfrVkQDfa4mq3pW5Qw==", + "requires": { + "ansi-colors": "^1.1.0", + "extend-object": "^1.0.0", + "gulp": "^3.9.1", + "merge-stream": "^1.0.1", + "path": "^0.12.7", + "rimraf": "^2.6.2" + } + }, + "@abp/aspnetcore.mvc.ui.theme.basic": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-0.4.9.tgz", + "integrity": "sha512-g3Zby8x8+vWw3oTJsSPasjm4tv7BG4270PEf7jK9w925+lIyKYHn6UxOcFbSU2pi9mJTnaF+Fk/rScIcdxwZZw==", + "requires": { + "@abp/aspnetcore.mvc.ui.theme.shared": "^0.4.9" + } + }, + "@abp/aspnetcore.mvc.ui.theme.shared": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-0.4.9.tgz", + "integrity": "sha512-Fe4UfQ215Pz2V6D5HUYhDJFeJWjKLcv2gsZfOheWLlOBgYh274pdnUIwceoZ4Btpa9aPECLG+LAH4dTbs8vjRg==", + "requires": { + "@abp/aspnetcore.mvc.ui": "^0.4.9", + "@abp/bootstrap": "^0.4.9", + "@abp/datatables.net-bs4": "^0.4.9", + "@abp/font-awesome": "^0.4.9", + "@abp/jquery-form": "^0.4.9", + "@abp/jquery-validation-unobtrusive": "^0.4.9", + "@abp/lodash": "^0.4.9", + "@abp/select2": "^0.4.9", + "@abp/sweetalert": "^0.4.9", + "@abp/timeago": "^0.4.9", + "@abp/toastr": "^0.4.9" + } + }, + "@abp/blogging": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/blogging/-/blogging-0.4.9.tgz", + "integrity": "sha512-cMFLekebHCM1ZAGPxcli3yzEy0kq1nV8ZuV9JbaczoiC/KDOnBp8CWq61CwLxgnfZpVIO5RTdtDye9pDtBJdmg==", + "requires": { + "@abp/aspnetcore.mvc.ui.theme.shared": "^0.4.9", + "@abp/owl.carousel": "^0.4.9", + "@abp/tui-editor": "^0.4.9" + } + }, + "@abp/bootstrap": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/bootstrap/-/bootstrap-0.4.9.tgz", + "integrity": "sha512-A7lDHo43KnqjINo0xWECx/WzNQe3vqvE3GPv6uXq3KDi+gStQLAFBq3bVcVW/kSxiquDQ/tuCLRpE0qlhoobag==", + "requires": { + "@abp/core": "^0.4.9", + "bootstrap": "^4.1.1" + } + }, + "@abp/clipboard": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@abp/clipboard/-/clipboard-0.5.1.tgz", + "integrity": "sha512-efOPloVL0moRqGpAMA7DU5o+vzzu7ipGOFcG9nOfDD6uGY9AsOztFc71GwIFrtwADvJSiJHD6OfEIfR++dCT0w==", + "requires": { + "@abp/core": "^0.4.9", + "clipboard": "^2.0.4" + } + }, + "@abp/codemirror": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/codemirror/-/codemirror-0.4.9.tgz", + "integrity": "sha512-bjuKZKLHyBzr6lWZ5Fh4Io/6u0OILkwsB9LJAZ3cHnDkmBEIRlnQBmuGxCkQ3D0sXcFWrLoqb2FAB9djLxCnUQ==", + "requires": { + "@abp/core": "^0.4.9", + "codemirror": "^5.38.0" + } + }, + "@abp/core": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/core/-/core-0.4.9.tgz", + "integrity": "sha512-JbibIPDz0w/C9YhexNagMD763qbZCclcHLVlTpKEZUcxzp6rZXwPR6ekh/PnvzD0R7wmHOh+bHl0hs5JSdy3oA==" + }, + "@abp/datatables.net": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/datatables.net/-/datatables.net-0.4.9.tgz", + "integrity": "sha512-URimiGMFBusEMo9aAadLFCossbYyrN2R6+6YrQ+heqxdheCPmm2wupsXSFoUBHBhD0tzF4rY+OL//oOg3Wtg4g==", + "requires": { + "@abp/core": "^0.4.9", + "datatables.net": "^1.10.16" + } + }, + "@abp/datatables.net-bs4": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/datatables.net-bs4/-/datatables.net-bs4-0.4.9.tgz", + "integrity": "sha512-Dsz0fy2haBz3dl2MLXWjW2bhDBzp1cpWXSXj8TEEzYazjhyoqBy6AiFlEnRCqO49KZD6Ps1cONSRxx4c4On9Lg==", + "requires": { + "@abp/datatables.net": "^0.4.9", + "datatables.net-bs4": "^1.10.16" + } + }, + "@abp/docs": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@abp/docs/-/docs-0.5.1.tgz", + "integrity": "sha512-3pGYnxZxm2kYPfu2EwDF0QinsNTym2cWlYAo7mVUBuReTPMhwHYtgrE7AX3nCVv1iAo6ltW+mebonGt1s5yXzA==", + "requires": { + "@abp/anchor-js": "^0.5.1", + "@abp/clipboard": "^0.5.1", + "@abp/malihu-custom-scrollbar-plugin": "^0.5.1", + "@abp/popper.js": "^0.5.1", + "@abp/prismjs": "^0.5.1" + } + }, + "@abp/font-awesome": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/font-awesome/-/font-awesome-0.4.9.tgz", + "integrity": "sha512-H4H/PJeSypoq++jP7eqS3y5jpbPIglUByPymHnho7U84gO06tZBUIoK00zyLACUVLzNztWANhmVqyA6OaHQ6xQ==", + "requires": { + "@abp/core": "^0.4.9", + "font-awesome": "^4.7.0" + } + }, + "@abp/highlight.js": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/highlight.js/-/highlight.js-0.4.9.tgz", + "integrity": "sha512-bsXgtOAJ8O4W3AO9arIxwLCC1JZABlZtoB55Pk5WjGiu8mhWiB4+HCXqWtSBE2qXwSLoDBE2FS5KAtIPfGfn+g==", + "requires": { + "@abp/core": "^0.4.9" + } + }, + "@abp/jquery": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/jquery/-/jquery-0.4.9.tgz", + "integrity": "sha512-Lte2rfDhcVXRA18mJMyPs0oFoiX/7x10F9cwMyX4+8e9QulA0dg+MjJZ4HIbxRoKvaYPz0AdE5VZ511folFeTg==", + "requires": { + "@abp/core": "^0.4.9", + "jquery": "^3.3.1" + } + }, + "@abp/jquery-form": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/jquery-form/-/jquery-form-0.4.9.tgz", + "integrity": "sha512-T1LzHNO+L/ATSfsaSu9H5rq9oUGjjBrwcJBVQhWRuGbB/Nsv1t4CdCPZHqbYBsn3ji/6T9C80FMdL+s4iOfy8A==", + "requires": { + "@abp/jquery": "^0.4.9", + "jquery-form": "^4.2.2" + } + }, + "@abp/jquery-validation": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/jquery-validation/-/jquery-validation-0.4.9.tgz", + "integrity": "sha512-8C58G9BTYszW6E0EO6NYqXLEbABXt/yGlOqAFCkPiLVfUcoC6uARqkgIgNVnE99ZUeSmluNsYeCczP0Qb0yNzg==", + "requires": { + "@abp/jquery": "^0.4.9", + "jquery-validation": "^1.17.0" + } + }, + "@abp/jquery-validation-unobtrusive": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-0.4.9.tgz", + "integrity": "sha512-GR62QEPexX4uLcqF3y72V39nlx/70C7ubeaIxS1ZEq+0wGklwAiyq1p19qpB5Cuj2GJL+vFrIig5w+B79P2iAw==", + "requires": { + "@abp/jquery-validation": "^0.4.9", + "jquery-validation-unobtrusive": "^3.2.9" + } + }, + "@abp/lodash": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/lodash/-/lodash-0.4.9.tgz", + "integrity": "sha512-/itYbXQL145WigKIGpnyWgARml7QGie7xqhC1WZG5iUkdqLx+4YBXesdzGFykthDewiQNz8mB2gPk64d376AAw==", + "requires": { + "@abp/core": "^0.4.9", + "lodash": "^4.17.10" + }, + "dependencies": { + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + } + } + }, + "@abp/malihu-custom-scrollbar-plugin": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-0.5.1.tgz", + "integrity": "sha512-i9XorWsWcqb3tbbiwvE4OQCfXXJO38HlkQgvlwzxshB8xDcS9v/JL5fAAvM/Cr66fB2zybsrCseq9QcBXL+yCQ==", + "requires": { + "@abp/core": "^0.4.9", + "malihu-custom-scrollbar-plugin": "^3.1.5" + } + }, + "@abp/markdown-it": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/markdown-it/-/markdown-it-0.4.9.tgz", + "integrity": "sha512-leaY6Iom4zCW9RcZWIZbiYTM8NTmSYSa2Xiq7FW2MzhDCATXbcqV1+EqNAAFBERHAJoq0Hyz2AkIP510L+hz6Q==", + "requires": { + "@abp/core": "^0.4.9", + "markdown-it": "^8.4.1" + } + }, + "@abp/owl.carousel": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/owl.carousel/-/owl.carousel-0.4.9.tgz", + "integrity": "sha512-pgRcdbN1u6vaN6wOfNN9z6Id70va93kGTCBNVY43fJec1ghIq/evpBNp29ef5x9b0lcfe4DhmNb3CFaLbikr0w==", + "requires": { + "@abp/core": "^0.4.9", + "owl.carousel": "^2.3.4" + } + }, + "@abp/popper.js": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@abp/popper.js/-/popper.js-0.5.1.tgz", + "integrity": "sha512-qS97hQQtG78mVPRvmZZtBb7Vu905NpThl9PN3jPWWDiVbOV2/d+BXCTRhTRbfdup3C5cmGdntjaGxfcxlxHt1Q==", + "requires": { + "@abp/core": "^0.4.9", + "popper.js": "^1.14.6" + } + }, + "@abp/prismjs": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@abp/prismjs/-/prismjs-0.5.1.tgz", + "integrity": "sha512-DxoidAVV8LmtgFonbzGJEfszQDUaHEQc+/bcJtyQCuv5l+uflVnpAH+6W8IAErt5N96a0RJbeV9ZBXjIhqOzpA==", + "requires": { + "@abp/core": "^0.4.9", + "prismjs": "^1.15.0" + } + }, + "@abp/select2": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/select2/-/select2-0.4.9.tgz", + "integrity": "sha512-AaJHWy9fkP/LqVkruZGfvzgdZXyT96/FpnflUpoNPXjuvVRptkJpd/BQiWjpyjS+qzuZ+m3X9dms0d0lAyFKYA==", + "requires": { + "@abp/core": "^0.4.9", + "select2": "^4.0.5" + } + }, + "@abp/sweetalert": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/sweetalert/-/sweetalert-0.4.9.tgz", + "integrity": "sha512-FaxtELo7Um/uasasbOGi1j1XuBtZ819mUo7+6pMSWj2CSAkg2A/RyT9NhYcX8oyGpv188W5CjZfJ1DM0bRH+pQ==", + "requires": { + "@abp/core": "^0.4.9", + "sweetalert": "^2.1.0" + } + }, + "@abp/timeago": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/timeago/-/timeago-0.4.9.tgz", + "integrity": "sha512-RsAyJCl+rEWQL0q0Nx/ijy+iOBYm5IC5Re6y4SQ1jYF/B4n88GM2PFy6kLrE+HHGl5Z5hkWr5OGXmFem50Y3Wg==", + "requires": { + "@abp/jquery": "^0.4.9", + "timeago": "^1.6.3" + } + }, + "@abp/toastr": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/toastr/-/toastr-0.4.9.tgz", + "integrity": "sha512-KjnETa1Og5EIMDw/pIxPoKLTABBcsxBN8BqwIG33ya2+BIRfAI7b0lEMoKK+qmwVwI5dkXZlKFGIUmPtb+zVCw==", + "requires": { + "@abp/jquery": "^0.4.9", + "toastr": "^2.1.4" + } + }, + "@abp/tui-editor": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@abp/tui-editor/-/tui-editor-0.4.9.tgz", + "integrity": "sha512-sIXF/rNX2UyQiDCDmj8pv1FeqtAv9B0NquyBJwWDkaXWQsmJJ3YU/drcJHbzabsYg2tBjzRM/4Bb0+eXYR+Mnw==", + "requires": { + "@abp/codemirror": "^0.4.9", + "@abp/highlight.js": "^0.4.9", + "@abp/jquery": "^0.4.9", + "@abp/markdown-it": "^0.4.9", + "tui-editor": "^1.2.6" + } + }, + "almond": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/almond/-/almond-0.3.3.tgz", + "integrity": "sha1-oOfJWsdiTWQXtElLHmi/9pMWiiA=" + }, + "anchor-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/anchor-js/-/anchor-js-4.1.1.tgz", + "integrity": "sha512-c2Wl9F1X0C4jkYKLla1SNE2uI6xJrSKsRC7HCCg4yLNQ5sL5D+tDEWrjRaoTuTlMTqBCnF6kOuR3dx59Erxpvw==" + }, + "ansi-colors": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "requires": { + "ansi-wrap": "^0.1.0" + } + }, + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=" + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=" + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "babel-polyfill": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", + "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "requires": { + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "regenerator-runtime": "^0.10.5" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "beeper": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=" + }, + "bootstrap": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.3.tgz", + "integrity": "sha512-rDFIzgXcof0jDyjNosjv4Sno77X4KuPeFxG2XZZv1/Kc8DRVGVADdoQyyOVDwPqL36DDmtCQbrpMCqvpPLJQ0w==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clipboard": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", + "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=" + }, + "codemirror": { + "version": "5.40.2", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.40.2.tgz", + "integrity": "sha512-yoWuvEiD3v5vTwdoMc/wu/Ld6dh9K/yEiEBTKOPGM+/pN0gTAqFNtrLHv1IJ1UJvzFpNRvMi92XCi3+8/iIaEw==" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "datatables.net": { + "version": "1.10.19", + "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.19.tgz", + "integrity": "sha512-+ljXcI6Pj3PTGy5pesp3E5Dr3x3AV45EZe0o1r0gKENN2gafBKXodVnk2ypKwl2tTmivjxbkiqoWnipTefyBTA==", + "requires": { + "jquery": ">=1.7" + } + }, + "datatables.net-bs4": { + "version": "1.10.19", + "resolved": "https://registry.npmjs.org/datatables.net-bs4/-/datatables.net-bs4-1.10.19.tgz", + "integrity": "sha512-pgeP17w4aPR7HIxIwuJghfqXULjdg1K6xMUUKDyCERJRSNNK4MRToFfELtIsluLNN555YBK4Kx8nihX5/ZT1Fw==", + "requires": { + "datatables.net": "1.10.19", + "jquery": ">=1.7" + } + }, + "dateformat": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", + "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "requires": { + "clone": "^1.0.2" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" + }, + "deprecated": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", + "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=" + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" + }, + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "requires": { + "readable-stream": "~1.1.9" + } + }, + "end-of-stream": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", + "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", + "requires": { + "once": "~1.3.0" + } + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" + }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eve": { + "version": "git://github.com/adobe-webplatform/eve.git#eef80ed8d188423c2272746fb8ae5cc8dad84cb1", + "from": "git://github.com/adobe-webplatform/eve.git#eef80ed" + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/extend-object/-/extend-object-1.0.0.tgz", + "integrity": "sha1-QlFPhAFdE1bK9Rh5ad+yvBvaCCM=" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fancy-log": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", + "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", + "requires": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "time-stamp": "^1.0.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-index": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", + "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=" + }, + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "fined": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz", + "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "first-chunk-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", + "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=" + }, + "flagged-respawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.0.tgz", + "integrity": "sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c=" + }, + "font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "requires": { + "for-in": "^1.0.1" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "gaze": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", + "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", + "requires": { + "globule": "~0.1.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "glob": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", + "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^2.0.1", + "once": "^1.3.0" + } + }, + "glob-stream": { + "version": "3.1.18", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", + "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", + "requires": { + "glob": "^4.3.1", + "glob2base": "^0.0.12", + "minimatch": "^2.0.1", + "ordered-read-streams": "^0.1.0", + "through2": "^0.6.1", + "unique-stream": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.34", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "requires": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, + "glob-watcher": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", + "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", + "requires": { + "gaze": "^0.5.1" + } + }, + "glob2base": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", + "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "requires": { + "find-index": "^0.1.1" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globule": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", + "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", + "requires": { + "glob": "~3.1.21", + "lodash": "~1.0.1", + "minimatch": "~0.2.11" + }, + "dependencies": { + "glob": { + "version": "3.1.21", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", + "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", + "requires": { + "graceful-fs": "~1.2.0", + "inherits": "1", + "minimatch": "~0.2.11" + } + }, + "graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=" + }, + "inherits": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", + "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=" + }, + "minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + } + } + }, + "glogg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.1.tgz", + "integrity": "sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==", + "requires": { + "sparkles": "^1.0.0" + } + }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "requires": { + "delegate": "^3.1.2" + } + }, + "graceful-fs": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", + "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", + "requires": { + "natives": "^1.1.0" + } + }, + "gulp": { + "version": "3.9.1", + "resolved": "http://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", + "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", + "requires": { + "archy": "^1.0.0", + "chalk": "^1.0.0", + "deprecated": "^0.0.1", + "gulp-util": "^3.0.0", + "interpret": "^1.0.0", + "liftoff": "^2.1.0", + "minimist": "^1.1.0", + "orchestrator": "^0.3.0", + "pretty-hrtime": "^1.0.0", + "semver": "^4.1.0", + "tildify": "^1.0.0", + "v8flags": "^2.0.2", + "vinyl-fs": "^0.3.0" + } + }, + "gulp-util": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", + "requires": { + "array-differ": "^1.0.0", + "array-uniq": "^1.0.2", + "beeper": "^1.0.0", + "chalk": "^1.0.0", + "dateformat": "^2.0.0", + "fancy-log": "^1.1.0", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "lodash._reescape": "^3.0.0", + "lodash._reevaluate": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.template": "^3.0.0", + "minimist": "^1.1.0", + "multipipe": "^0.1.2", + "object-assign": "^3.0.0", + "replace-ext": "0.0.1", + "through2": "^2.0.0", + "vinyl": "^0.5.0" + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "requires": { + "glogg": "^1.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-gulplog": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "requires": { + "sparkles": "^1.0.0" + } + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "highlight.js": { + "version": "9.13.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.13.1.tgz", + "integrity": "sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A==" + }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "jquery": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", + "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==" + }, + "jquery-form": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/jquery-form/-/jquery-form-4.2.2.tgz", + "integrity": "sha512-HJTef7DRBSg8ge/RNUw8rUTTtB3l8ozO0OhD16AzDl+eIXp4skgCqRTd9fYPsOzL+pN6+1B9wvbTLGjgikz8Tg==", + "requires": { + "jquery": ">=1.7.2" + } + }, + "jquery-mousewheel": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/jquery-mousewheel/-/jquery-mousewheel-3.1.13.tgz", + "integrity": "sha1-BvAzXxbjU6aV5yBr9QUDy1I6buU=" + }, + "jquery-validation": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/jquery-validation/-/jquery-validation-1.18.0.tgz", + "integrity": "sha512-+MK0pvoegfLrJnwtCU6tx305Vgp9HWevpmdVwDf5TthmINkn0wqqLD0bpa75EERlHsBBjMmza//ppx5ZQPnW3Q==", + "requires": { + "jquery": "^1.7 || ^2.0 || ^3.1" + } + }, + "jquery-validation-unobtrusive": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-3.2.11.tgz", + "integrity": "sha512-3FQPllaWdD+Aq55zJLGSW39+eXPDz1HhwAvrSwYi8zHQ8DVcu5IJ1HVeTiCl0BnCnrIBvfFU3zEB/DrGdcoRIQ==", + "requires": { + "jquery": ">=1.8", + "jquery-validation": ">=1.16" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + }, + "liftoff": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", + "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", + "requires": { + "extend": "^3.0.0", + "findup-sync": "^2.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + } + }, + "linkify-it": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz", + "integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=", + "requires": { + "uc.micro": "^1.0.1" + } + }, + "lodash": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", + "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=" + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=" + }, + "lodash._basetostring": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=" + }, + "lodash._basevalues": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=" + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=" + }, + "lodash._reescape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", + "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=" + }, + "lodash._reevaluate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", + "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" + }, + "lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" + }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "requires": { + "lodash._root": "^3.0.0" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" + }, + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" + } + }, + "lodash.templatesettings": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0" + } + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "malihu-custom-scrollbar-plugin": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-3.1.5.tgz", + "integrity": "sha1-MQzsxeWUFaHCnp37XStuAdZqKe8=", + "requires": { + "jquery-mousewheel": ">=3.0.6" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "requires": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "requires": { + "readable-stream": "^2.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "requires": { + "brace-expansion": "^1.0.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multipipe": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "requires": { + "duplexer2": "0.0.2" + } + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natives": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", + "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==" + }, + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "requires": { + "wrappy": "1" + } + }, + "orchestrator": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", + "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", + "requires": { + "end-of-stream": "~0.1.5", + "sequencify": "~0.0.7", + "stream-consume": "~0.1.0" + } + }, + "ordered-read-streams": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", + "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=" + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "owl.carousel": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/owl.carousel/-/owl.carousel-2.3.4.tgz", + "integrity": "sha512-JaDss9+feAvEW8KZppPSpllfposEzQiW+Ytt/Xm5t/3CTJ7YVmkh6RkWixoA2yXk2boIwedYxOvrrppIGzru9A==", + "requires": { + "jquery": ">=1.8.3" + } + }, + "pako": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.3.tgz", + "integrity": "sha1-X1FbDGci4ZgpIK6ABerLC3ynPM8=" + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" + }, + "plantuml-encoder": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/plantuml-encoder/-/plantuml-encoder-1.2.5.tgz", + "integrity": "sha512-viV7Sz+BJNX/sC3iyebh2VfLyAZKuu3+JuBs2ISms8+zoTGwPqwk3/WEDw/zROmGAJ/xD4sNd8zsBw/YmTo7ng==", + "requires": { + "pako": "1.0.3", + "utf8-bytes": "0.0.1" + } + }, + "popper.js": { + "version": "1.14.6", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.6.tgz", + "integrity": "sha512-AGwHGQBKumlk/MDfrSOf0JHhJCImdDMcGNoqKmKkU+68GFazv3CQ6q9r7Ja1sKDZmYWTckY/uLyEznheTDycnA==" + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" + }, + "prismjs": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.15.0.tgz", + "integrity": "sha512-Lf2JrFYx8FanHrjoV5oL8YHCclLQgbJcVZR+gikGGMqz6ub5QVWDTM6YIwm3BuPxM/LOV+rKns3LssXNLIf+DA==", + "requires": { + "clipboard": "^2.0.0" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "promise-polyfill": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-6.1.0.tgz", + "integrity": "sha1-36lpQ+qcEh/KTem1hoyznTRy4Fc=" + }, + "raphael": { + "version": "git+https://github.com/nhnent/raphael.git#78a6ed3ec269f33b6457b0ec66f8c3d1f2ed70e0", + "from": "git+https://github.com/nhnent/raphael.git#2.2.0-c", + "requires": { + "eve": "git://github.com/adobe-webplatform/eve.git#eef80ed8d188423c2272746fb8ae5cc8dad84cb1" + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "^1.1.6" + } + }, + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=" + }, + "resize-observer-polyfill": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.0.tgz", + "integrity": "sha512-M2AelyJDVR/oLnToJLtuDJRBBWUGUvvGigj1411hXhAdyFWqMaqHp7TixW3FpiLuVaikIcR1QL+zqoJoZlOgpg==" + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "requires": { + "path-parse": "^1.0.5" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "^7.0.5" + }, + "dependencies": { + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=" + }, + "select2": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.5.tgz", + "integrity": "sha1-eqxQaSVhmFs007guxV4ib4lg1Ao=", + "requires": { + "almond": "~0.3.1", + "jquery-mousewheel": "~3.1.13" + } + }, + "semver": { + "version": "4.3.6", + "resolved": "http://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=" + }, + "sequencify": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", + "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=" + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==" + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "squire-rte": { + "version": "github:neilj/Squire#306230d0df9b38047cd06204476ddc0582569cfd", + "from": "github:neilj/Squire#306230d0df9b38047cd06204476ddc0582569cfd" + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stream-consume": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", + "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==" + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", + "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", + "requires": { + "first-chunk-stream": "^1.0.0", + "is-utf8": "^0.2.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "sweetalert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sweetalert/-/sweetalert-2.1.0.tgz", + "integrity": "sha512-9YKj0SvjKyBfRWco50UOsIbXVeifYbxzT9Qda7EsqC01eafHGCSG0IR7g942ufjzt7lnwO8ZZBwr6emXv2fQrg==", + "requires": { + "es6-object-assign": "^1.1.0", + "promise-polyfill": "^6.0.2" + } + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "tildify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", + "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "requires": { + "os-homedir": "^1.0.0" + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" + }, + "timeago": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/timeago/-/timeago-1.6.3.tgz", + "integrity": "sha512-x97d1X1KsNapWJTgCOOAy/59XagYu2WsDTAH/yvPsWi5bqtGbLPaVZBv3HZ3jTpakHR+JGGyrI9qC0yuvIAvnQ==", + "requires": { + "jquery": ">=1.2.3" + } + }, + "tiny-emitter": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.0.2.tgz", + "integrity": "sha512-2NM0auVBGft5tee/OxP4PI3d8WItkDM+fPnaRAVo6xTDI2knbz9eC5ArWGqtGlYqiH3RU5yMpdyTTO7MguC4ow==" + }, + "to-mark": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/to-mark/-/to-mark-1.1.3.tgz", + "integrity": "sha512-Wai0j2IPk5vEsuPHgTBjK/xzGwUAmddUbUVLZgAvOiTZKEJwmVHRdEHO3yTta4LxgY4W9761sP1MkAZbYVXcig==" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toastr": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/toastr/-/toastr-2.1.4.tgz", + "integrity": "sha1-i0O+ZPudDEFIcURvLbjoyk6V8YE=", + "requires": { + "jquery": ">=1.12.0" + } + }, + "tui-chart": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tui-chart/-/tui-chart-3.4.0.tgz", + "integrity": "sha512-gPIJ1SsPhISj/SlzysA9fkLJMlnPV1PLaUE+gxUioZaDtfoZ+TxSE+Vs1rOvoXUUmT/v5+qlH2iM2fkaLvDU0A==", + "requires": { + "babel-polyfill": "^6.26.0", + "raphael": "git+https://github.com/nhnent/raphael.git#78a6ed3ec269f33b6457b0ec66f8c3d1f2ed70e0", + "tui-code-snippet": "^1.4.0" + } + }, + "tui-code-snippet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tui-code-snippet/-/tui-code-snippet-1.4.0.tgz", + "integrity": "sha512-a7XzHRbRDi6Tt4lGcopq6ctQjVrzmnw9JMoTFqur5gczgtw5tmgUqXHjg8D9IonDkzZNq5gYLhkzykx4fmn+GA==" + }, + "tui-color-picker": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tui-color-picker/-/tui-color-picker-2.2.0.tgz", + "integrity": "sha512-oAzMxF19bDExbvv7jVWQBPlrJ8sO3jQe+1rHqKkM4FtpvtGNlJO/ty19LW6pk9CCi1y43cgoG3QUt41ctGmygQ==", + "requires": { + "tui-code-snippet": "^1.3.0" + } + }, + "tui-editor": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/tui-editor/-/tui-editor-1.2.6.tgz", + "integrity": "sha512-sVvs8yx3G1a/+YbR4VxzzfHFxPIPgattai+RDAHaUYeDkRhFPi3LeKN8A89jPyvUhyM8NhZWlhVd8ZTYx9ykNg==", + "requires": { + "codemirror": "^5.33.0", + "highlight.js": "^9.12.0", + "jquery": "^3.3.1", + "markdown-it": "^8.4.0", + "plantuml-encoder": "^1.2.5", + "resize-observer-polyfill": "^1.5.0", + "squire-rte": "github:neilj/Squire#306230d0df9b38047cd06204476ddc0582569cfd", + "to-mark": "^1.1.2", + "tui-chart": "^3.0.1", + "tui-code-snippet": "^1.3.0", + "tui-color-picker": "^2.2.0" + } + }, + "uc.micro": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz", + "integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg==" + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "unique-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", + "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=" + }, + "utf8-bytes": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/utf8-bytes/-/utf8-bytes-0.0.1.tgz", + "integrity": "sha1-EWsCVEjJtQAIHN+/H01sbDfYg30=" + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "v8flags": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", + "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "requires": { + "user-home": "^1.1.1" + } + }, + "vinyl": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "requires": { + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" + } + }, + "vinyl-fs": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", + "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", + "requires": { + "defaults": "^1.0.0", + "glob-stream": "^3.1.5", + "glob-watcher": "^0.0.6", + "graceful-fs": "^3.0.0", + "mkdirp": "^0.5.0", + "strip-bom": "^1.0.0", + "through2": "^0.6.1", + "vinyl": "^0.4.0" + }, + "dependencies": { + "clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=" + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "requires": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "vinyl": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", + "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "requires": { + "clone": "^0.2.0", + "clone-stats": "^0.0.1" + } + } + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + } + } +} diff --git a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css b/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css index 36bfe30a55..ad4f5adca0 100644 --- a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css +++ b/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css @@ -600,7 +600,7 @@ span.code-arrow { .docs-page .docs-page-index { display: none; } } -@media (max-width: 767px) { +@media (max-width: 992px) { body { font-size: 14px; } .for-mobile { diff --git a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css b/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css index b8f9189bf2..524731f0ff 100644 --- a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css +++ b/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css @@ -1 +1 @@ -body{position:relative;font-family:'PT Sans',sans-serif;background:url(../assets/tools/bg.jpg) center center no-repeat;background-attachment:fixed;}h1,h2,h3,h4,h5,h6{font-family:'PT Sans Caption',sans-serif;}h1{font-size:2.25em;margin:1.5rem 0 .75rem;}h2{font-size:1.75em;margin:1.5rem 0 .75rem;}h3{font-size:1.5em;margin:1.5rem 0 .75rem;}h4{font-size:1.25em;margin:1.5rem 0 .75rem;}h5{font-size:1em;margin:1.5rem 0 .75rem;}h6{font-size:1em;margin:1.5rem 0 .75rem;}img{max-width:100%;}.navbar{padding:1.75rem 2rem;}.nav-link{padding-left:1rem !important;padding-right:1rem !important;}.navbar-dark .navbar-nav .nav-link{color:#fff;}.text-success{color:#e90052 !important;}a.text-success:hover,a.text-success:focus{color:#e90052 !important;}.bg-success,.btn-success,.badge-success{background-color:#e90052 !important;border-color:#e90052 !important;}.bg-success{background-color:rgba(233,0,82,.8) !important;}.bg-blue,.btn-blue,.badge-blue{background-color:#03abed !important;border-color:#03abed !important;color:#fff;}.bg-blue:hover,.btn-blue:hover,.badge-blue:hover{background-color:#0095d0 !important;border-color:#0095d0 !important;color:#fff !important;}.btn:focus,.btn:active,.btn:visited,a:focus,a:active,a:visited{outline:none !important;box-shadow:none;}.text-primary{color:#38003c !important;}.bg-primary,.btn-primary,.badge-primary{background-color:#38003c !important;border-color:#38003c !important;}.bg-primary{background-color:rgba(56,0,60,.9) !important;}.btn-outline-primary{color:#38003c !important;border-color:#38003c !important;}.btn-outline-primary:hover{background-color:#38003c !important;color:#fff !important;}.dropdown-menu{padding:1rem 0;border-radius:.15rem;border:none;box-shadow:5px 5px 40px rgba(0,0,0,.3);}.dropdown-menu .dropdown-item{padding:.75rem 1.5rem;}#index-video{position:fixed;right:0;bottom:0;min-width:100%;min-height:100%;z-index:-1;}.bg-gradient-horizontal{background:#fff;}@media(min-width:480px){.bg-gradient-horizontal{background:#fff;background:-moz-linear-gradient(left,#fff 50%,#f2f2f2 50%);background:-webkit-linear-gradient(left,#fff 50%,#f2f2f2 50%);background:linear-gradient(to right,#fff 50%,#f2f2f2 50%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='#f2f2f2',GradientType=1);}}.bg-transparency{background:rgba(255,255,255,.9);}.bg-light{background:#eee;}.for-mobile{display:none;}.for-desktop{display:inline-block;}.breadcrumb{background:none;font-size:.85em;border-radius:0;border-bottom:1px solid #f5f5f5;margin:0 -15px;padding:.5rem 0;text-align:center;display:block;}.breadcrumb .breadcrumb-item+.breadcrumb-item{padding-left:.2rem;}.breadcrumb .breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.4rem;color:#eee;content:"|";}.breadcrumb .breadcrumb-item{color:#eee;display:inline-block;}.breadcrumb .breadcrumb-item a{color:#aaa;}.close{font-weight:300;}hr{margin-top:2rem;margin-bottom:2.5rem;border-top:1px solid rgba(0,0,0,.05);}span.with-br-name{font-size:.75em;}span.br-name{display:block;font-size:1.25em;}span.br-name-1{display:block;font-size:1em;}.btn-fifty{display:flex;}.btn-fifty .btn{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%;}.p-responsive{padding:120px 0;}.global-header{display:none;}.global-header .navbar{background:rgba(255,255,255,.2);}.global-header .navbar .products-link{border:1px solid rgba(255,255,255,.75);border-radius:.2rem;margin:0 10px;padding-top:.36rem;padding-bottom:.36rem;}.global-header .navbar .search-item{position:relative;}.global-header .navbar .search-item input.form-control{background:none;border:1px solid rgba(255,255,255,.25);border-radius:.2rem;color:#fff;padding-left:2.5rem;min-width:280px;}.global-header .navbar .search-item input.form-control::-webkit-input-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control:-moz-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control::-moz-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control:-ms-input-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item .btn-search{position:absolute;top:-2px;left:-1px;background:none;}header .btn{background:#fff;}header .btn.btn-login,header .btn.btn-logout{border:2px solid #fff;color:#fff;background:transparent;margin-right:6px;}header .btn.btn-login:hover,header .btn.btn-logout:hover{background:#fff;color:#e90052;}.product-header{font-size:1.1rem;}.product-header .navbar-brand{font-size:1.75rem;}.home-logo{width:120px;}.jumbotron-logo{width:240px;margin-bottom:40px;}.forkme{position:fixed;bottom:0;right:0;}.footer-logo{width:140px;}.jumbotron{background:#006bf0;background:-moz-linear-gradient(left,#006bf0 0%,#40ffb0 100%);background:-webkit-linear-gradient(left,#006bf0 0%,#40ffb0 100%);background:linear-gradient(to right,rgba(56,0,60,.9) 0%,rgba(185,0,74,.78) 100%);margin-top:-120px;border-radius:0;margin-bottom:0;height:90vh;}.jumbotron.jumbocover{padding:120px 0 20px;height:auto;}.jumbotron>.row{height:calc(90vh - 120px);}.jumbotron .abp-version{position:absolute;font-size:11px;right:1px;top:-2px;padding:1px 4px 0;display:inline-block;color:#fff;background:rgba(233,3,82,.7);border-radius:3px;opacity:.8;}.jumbotron .desc-span{font-size:1.4em;font-style:italic;opacity:.7;}.section-with-logos img{margin:25px;max-height:50px;transition:.4s;opacity:.6;-webkit-filter:grayscale(60%);filter:grayscale(60%);}.section-with-logos img:hover{opacity:1;-webkit-filter:grayscale(0%);filter:grayscale(0%);}img.subsection-icon{width:64px;height:64px;}.toggle-row{display:none;}.btn-toggle .lessText{display:none;}.btn-toggle .moreText{display:block;}.btn-toggle.less .lessText{display:block;}.btn-toggle.less .moreText{display:none;}.abp-browser{margin:3rem 0 1rem;text-align:left;border-radius:6px;overflow:hidden;}.abp-browser .browser-container{border:1px solid #eee;}.abp-browser .browser-row{padding:4px 10px;background:#e5e5e5;}.abp-browser .browser-row:after{content:"";display:table;clear:both;}.abp-browser .browser-dot{margin-top:2px;margin-right:2px;height:12px;width:12px;background-color:#bbb;border-radius:50%;display:inline-block;}.abp-browser .abp-browser input[type=text]{width:100%;border-radius:3px;border:none;background-color:#fff;margin-top:-8px;height:25px;color:#666;padding:5px;}.abp-browser .browser-bar{width:17px;height:3px;background-color:#aaa;margin:3px 0;display:block;}.abp-browser .browser-content{padding:2rem;background:#f5f5f5;}.abp-browser .bg-primary,.abp-browser .btn-primary,.abp-browser .badge-primary{background-color:#007bff !important;border-color:#007bff !important;}.abp-browser .btn-outline-primary{color:#007bff !important;border-color:#007bff !important;}.abp-browser .btn-outline-primary:hover{background-color:#007bff !important;color:#fff !important;}span.code-arrow{padding:52px 0 18px;display:block;font-size:40px;}.docs-page{background:#f5f7f9;}.docs-page .docs-sidebar{background:#f5f7f9;padding-right:1.5rem;position:relative;width:270px;}.docs-page .docs-sidebar .docs-sidebar-wrapper{width:270px;top:0;position:fixed;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{height:calc(100vh - 190px);overflow:hidden;overflow-y:auto;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search{position:relative;padding:0 0 1.25rem 1.5rem;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search input.form-control{background:none;border-radius:.2rem;padding-left:2.5rem;width:100%;background:#eeeff2;border:0;font-size:.85em;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search .btn-search{position:absolute;top:-5px;left:22px;background:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul{font-size:.913em;list-style:none;padding:0 0 0 20px;margin:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li{margin-left:0;padding-left:24px;display:block;width:100%;position:relative;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label{margin:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle{transition:.3s;display:inline-block;width:18px;height:18px;text-align:center;padding:0;line-height:normal;border-radius:50%;margin-right:4px;position:absolute;left:0;top:8px;cursor:pointer;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle img{width:14px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle:not(.last-link).opened{transform:rotate(180deg);}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a{color:#101010;font-weight:700;padding:7px 0;display:block;border-bottom:1px solid #eeeff3;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li label.tree-toggle{top:6px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li a{font-weight:400;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul li a{font-weight:300;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a{color:#38003c;font-weight:bold;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:2rem;font-weight:700;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand .docs-logo{width:130px;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand strong{font-weight:300;font-size:1.2rem;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:.85em;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc strong{display:block;}.docs-page .docs-content .docs-text-field{padding:3rem;}.docs-page .docs-page-index{position:relative;}.docs-page .docs-page-index .docs-inner-anchors{position:fixed;top:0;max-width:270px;padding:10px;font-size:.9em;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills{font-size:.95em;margin-left:18px;border-left:1px solid #e5e5e5;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link{padding:.2rem 0 .2rem 1rem;color:#aaa;line-height:1.1;position:relative;border-left:3px solid transparent;border-radius:0;margin-left:-2px;margin-top:2px;margin-bottom:2px;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link.active{background:none;color:#38003b;border-color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-link.active{color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-pills .nav-link.active{color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors>.navbar{margin-left:-18px;}.docs-page .docs-page-index .docs-inner-anchors .docs-anchors-wrapper{max-width:300px;float:left;}.docs-page .docs-page-index .docs-inner-anchors .inner-title{padding-left:18px;}.docs-page .docs-page-index .scroll-top-btn{display:none;font-size:.85em;color:#aaa;text-decoration:underline;padding-left:18px;}.docs-page .docs-page-index .scroll-top-btn.showup{display:block;}@media(min-width:1200px){.container{max-width:1180px;}}@media(min-width:1366px){.container{max-width:1340px;}}@media(min-width:1440px){.container{max-width:1400px;}}@media(max-width:767px){.docs-page{background:#f5f7f9;}.docs-page>.container-fluid{display:block;}.docs-page>.container-fluid>.row{display:block;}.docs-page .docs-sidebar{position:fixed;max-width:100%;width:100%;display:block;padding:0 !important;top:0;left:0;z-index:100;right:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper{max-width:100%;width:100%;top:0;position:relative;margin:0 !important;height:72px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{padding:.5rem 1.5rem 2rem 1.5rem;height:calc(100vh - 72px);overflow:hidden;overflow-y:auto;position:fixed;top:72px;font-size:17px;left:0;width:100%;z-index:100;background:#f5f7f9;display:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search{position:relative;padding:0 0 1rem !important;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search .btn-search{top:-14px;left:-2px;}.docs-page .docs-sidebar .docs-top .navbar-logo{padding:0;padding-top:.3rem;display:block;text-align:center;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:2rem;font-weight:700;display:block;margin-right:0;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand .docs-logo{width:110px;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:1em;display:none;}.docs-page .docs-sidebar .docs-top .open-dmenu{position:absolute;top:10px;left:20px;}.docs-page .docs-content{padding-top:72px;max-width:100%;display:block !important;}.docs-page .docs-content .docs-text-field{padding:1rem 1.5rem;}.docs-page .docs-page-index{display:none;}}@media(max-width:767px){body{font-size:14px;}.for-mobile{display:inline-block;}.for-desktop{display:none;}.close-mmenu,.close-dmenu{position:absolute;top:-78px;left:25px;color:#fff;font-size:68px;background:#fff;opacity:0;}.navbar{padding:.5rem 1.75rem;}.navbar .navbar-collapse{background:#38003d;position:fixed;top:86px;left:0;width:100%;height:100vh;height:calc(100vh - 86px);z-index:100 !important;}.navbar .navbar-collapse .navbar-nav{height:100vh;padding:20px 30px;overflow:auto;}.navbar .navbar-collapse .navbar-nav .nav-link{padding:1.2rem !important;}.navbar .navbar-toggler{padding:.5rem .75rem;font-size:1.5rem;line-height:1;background-color:transparent;border:0;border-radius:.25rem;color:#fff !important;margin-left:-1rem;}.jumbotron .btn,footer .btn{display:block;margin-bottom:10px;}.multi-tenancy{text-align:center !important;}.section-with-logos img{margin:15px;opacity:1;-webkit-filter:grayscale(0%);filter:grayscale(0%);}.jumbotron{padding-top:160px;margin-top:-160px;border-radius:0;padding-bottom:40px;margin-bottom:0;font-size:.85em;padding-left:45px;padding-right:45px;}span.code-arrow{padding:0 0 0;display:block;transform:rotate(90deg);font-size:2em;}.mb-5,.my-5{margin-bottom:2rem !important;}.jumbotron{height:calc(100vh + 120px);}.jumbotron.jumbocover{height:auto;padding:160px 0 20px;}.jumbotron hr{display:none;}.jumbotron .btn{margin-bottom:0 !important;}.jumbotron .jumbotron-logo{margin-bottom:0;width:180px;height:62px;margin-top:-30px;}.jumbotron .jlogo-wrapper{height:62px;}}.vs-blog{margin-top:-88px !important;}.abp-account-container{max-width:400px;margin:0 auto;margin-top:-88px !important;}body{background-size:cover;} \ No newline at end of file +body{position:relative;font-family:'PT Sans',sans-serif;background:url(../assets/tools/bg.jpg) center center no-repeat;background-attachment:fixed;}h1,h2,h3,h4,h5,h6{font-family:'PT Sans Caption',sans-serif;}h1{font-size:2.25em;margin:1.5rem 0 .75rem;}h2{font-size:1.75em;margin:1.5rem 0 .75rem;}h3{font-size:1.5em;margin:1.5rem 0 .75rem;}h4{font-size:1.25em;margin:1.5rem 0 .75rem;}h5{font-size:1em;margin:1.5rem 0 .75rem;}h6{font-size:1em;margin:1.5rem 0 .75rem;}img{max-width:100%;}.navbar{padding:1.75rem 2rem;}.nav-link{padding-left:1rem !important;padding-right:1rem !important;}.navbar-dark .navbar-nav .nav-link{color:#fff;}.text-success{color:#e90052 !important;}a.text-success:hover,a.text-success:focus{color:#e90052 !important;}.bg-success,.btn-success,.badge-success{background-color:#e90052 !important;border-color:#e90052 !important;}.bg-success{background-color:rgba(233,0,82,.8) !important;}.bg-blue,.btn-blue,.badge-blue{background-color:#03abed !important;border-color:#03abed !important;color:#fff;}.bg-blue:hover,.btn-blue:hover,.badge-blue:hover{background-color:#0095d0 !important;border-color:#0095d0 !important;color:#fff !important;}.btn:focus,.btn:active,.btn:visited,a:focus,a:active,a:visited{outline:none !important;box-shadow:none;}.text-primary{color:#38003c !important;}.bg-primary,.btn-primary,.badge-primary{background-color:#38003c !important;border-color:#38003c !important;}.bg-primary{background-color:rgba(56,0,60,.9) !important;}.btn-outline-primary{color:#38003c !important;border-color:#38003c !important;}.btn-outline-primary:hover{background-color:#38003c !important;color:#fff !important;}.dropdown-menu{padding:1rem 0;border-radius:.15rem;border:none;box-shadow:5px 5px 40px rgba(0,0,0,.3);}.dropdown-menu .dropdown-item{padding:.75rem 1.5rem;}#index-video{position:fixed;right:0;bottom:0;min-width:100%;min-height:100%;z-index:-1;}.bg-gradient-horizontal{background:#fff;}@media(min-width:480px){.bg-gradient-horizontal{background:#fff;background:-moz-linear-gradient(left,#fff 50%,#f2f2f2 50%);background:-webkit-linear-gradient(left,#fff 50%,#f2f2f2 50%);background:linear-gradient(to right,#fff 50%,#f2f2f2 50%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='#f2f2f2',GradientType=1);}}.bg-transparency{background:rgba(255,255,255,.9);}.bg-light{background:#eee;}.for-mobile{display:none;}.for-desktop{display:inline-block;}.breadcrumb{background:none;font-size:.85em;border-radius:0;border-bottom:1px solid #f5f5f5;margin:0 -15px;padding:.5rem 0;text-align:center;display:block;}.breadcrumb .breadcrumb-item+.breadcrumb-item{padding-left:.2rem;}.breadcrumb .breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.4rem;color:#eee;content:"|";}.breadcrumb .breadcrumb-item{color:#eee;display:inline-block;}.breadcrumb .breadcrumb-item a{color:#aaa;}.close{font-weight:300;}hr{margin-top:2rem;margin-bottom:2.5rem;border-top:1px solid rgba(0,0,0,.05);}span.with-br-name{font-size:.75em;}span.br-name{display:block;font-size:1.25em;}span.br-name-1{display:block;font-size:1em;}.btn-fifty{display:flex;}.btn-fifty .btn{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%;}.p-responsive{padding:120px 0;}.global-header{display:none;}.global-header .navbar{background:rgba(255,255,255,.2);}.global-header .navbar .products-link{border:1px solid rgba(255,255,255,.75);border-radius:.2rem;margin:0 10px;padding-top:.36rem;padding-bottom:.36rem;}.global-header .navbar .search-item{position:relative;}.global-header .navbar .search-item input.form-control{background:none;border:1px solid rgba(255,255,255,.25);border-radius:.2rem;color:#fff;padding-left:2.5rem;min-width:280px;}.global-header .navbar .search-item input.form-control::-webkit-input-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control:-moz-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control::-moz-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item input.form-control:-ms-input-placeholder{color:rgba(255,255,255,.25) !important;}.global-header .navbar .search-item .btn-search{position:absolute;top:-2px;left:-1px;background:none;}header .btn{background:#fff;}header .btn.btn-login,header .btn.btn-logout{border:2px solid #fff;color:#fff;background:transparent;margin-right:6px;}header .btn.btn-login:hover,header .btn.btn-logout:hover{background:#fff;color:#e90052;}.product-header{font-size:1.1rem;}.product-header .navbar-brand{font-size:1.75rem;}.home-logo{width:120px;}.jumbotron-logo{width:240px;margin-bottom:40px;}.forkme{position:fixed;bottom:0;right:0;}.footer-logo{width:140px;}.jumbotron{background:#006bf0;background:-moz-linear-gradient(left,#006bf0 0%,#40ffb0 100%);background:-webkit-linear-gradient(left,#006bf0 0%,#40ffb0 100%);background:linear-gradient(to right,rgba(56,0,60,.9) 0%,rgba(185,0,74,.78) 100%);margin-top:-120px;border-radius:0;margin-bottom:0;height:90vh;}.jumbotron.jumbocover{padding:120px 0 20px;height:auto;}.jumbotron>.row{height:calc(90vh - 120px);}.jumbotron .abp-version{position:absolute;font-size:11px;right:1px;top:-2px;padding:1px 4px 0;display:inline-block;color:#fff;background:rgba(233,3,82,.7);border-radius:3px;opacity:.8;}.jumbotron .desc-span{font-size:1.4em;font-style:italic;opacity:.7;}.section-with-logos img{margin:25px;max-height:50px;transition:.4s;opacity:.6;-webkit-filter:grayscale(60%);filter:grayscale(60%);}.section-with-logos img:hover{opacity:1;-webkit-filter:grayscale(0%);filter:grayscale(0%);}img.subsection-icon{width:64px;height:64px;}.toggle-row{display:none;}.btn-toggle .lessText{display:none;}.btn-toggle .moreText{display:block;}.btn-toggle.less .lessText{display:block;}.btn-toggle.less .moreText{display:none;}.abp-browser{margin:3rem 0 1rem;text-align:left;border-radius:6px;overflow:hidden;}.abp-browser .browser-container{border:1px solid #eee;}.abp-browser .browser-row{padding:4px 10px;background:#e5e5e5;}.abp-browser .browser-row:after{content:"";display:table;clear:both;}.abp-browser .browser-dot{margin-top:2px;margin-right:2px;height:12px;width:12px;background-color:#bbb;border-radius:50%;display:inline-block;}.abp-browser .abp-browser input[type=text]{width:100%;border-radius:3px;border:none;background-color:#fff;margin-top:-8px;height:25px;color:#666;padding:5px;}.abp-browser .browser-bar{width:17px;height:3px;background-color:#aaa;margin:3px 0;display:block;}.abp-browser .browser-content{padding:2rem;background:#f5f5f5;}.abp-browser .bg-primary,.abp-browser .btn-primary,.abp-browser .badge-primary{background-color:#007bff !important;border-color:#007bff !important;}.abp-browser .btn-outline-primary{color:#007bff !important;border-color:#007bff !important;}.abp-browser .btn-outline-primary:hover{background-color:#007bff !important;color:#fff !important;}span.code-arrow{padding:52px 0 18px;display:block;font-size:40px;}.docs-page{background:#f5f7f9;}.docs-page .docs-sidebar{background:#f5f7f9;padding-right:1.5rem;position:relative;width:270px;}.docs-page .docs-sidebar .docs-sidebar-wrapper{width:270px;top:0;position:fixed;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{height:calc(100vh - 190px);overflow:hidden;overflow-y:auto;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search{position:relative;padding:0 0 1.25rem 1.5rem;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search input.form-control{background:none;border-radius:.2rem;padding-left:2.5rem;width:100%;background:#eeeff2;border:0;font-size:.85em;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search .btn-search{position:absolute;top:-5px;left:22px;background:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul{font-size:.913em;list-style:none;padding:0 0 0 20px;margin:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li{margin-left:0;padding-left:24px;display:block;width:100%;position:relative;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label{margin:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle{transition:.3s;display:inline-block;width:18px;height:18px;text-align:center;padding:0;line-height:normal;border-radius:50%;margin-right:4px;position:absolute;left:0;top:8px;cursor:pointer;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle img{width:14px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li label.tree-toggle:not(.last-link).opened{transform:rotate(180deg);}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a{color:#101010;font-weight:700;padding:7px 0;display:block;border-bottom:1px solid #eeeff3;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li label.tree-toggle{top:6px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li a{font-weight:400;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul li a{font-weight:300;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a{color:#38003c;font-weight:bold;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:2rem;font-weight:700;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand .docs-logo{width:130px;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand strong{font-weight:300;font-size:1.2rem;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:.85em;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc strong{display:block;}.docs-page .docs-content .docs-text-field{padding:3rem;}.docs-page .docs-page-index{position:relative;}.docs-page .docs-page-index .docs-inner-anchors{position:fixed;top:0;max-width:270px;padding:10px;font-size:.9em;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills{font-size:.95em;margin-left:18px;border-left:1px solid #e5e5e5;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link{padding:.2rem 0 .2rem 1rem;color:#aaa;line-height:1.1;position:relative;border-left:3px solid transparent;border-radius:0;margin-left:-2px;margin-top:2px;margin-bottom:2px;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link.active{background:none;color:#38003b;border-color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-link.active{color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-pills .nav-link.active{color:#38003b;}.docs-page .docs-page-index .docs-inner-anchors>.navbar{margin-left:-18px;}.docs-page .docs-page-index .docs-inner-anchors .docs-anchors-wrapper{max-width:300px;float:left;}.docs-page .docs-page-index .docs-inner-anchors .inner-title{padding-left:18px;}.docs-page .docs-page-index .scroll-top-btn{display:none;font-size:.85em;color:#aaa;text-decoration:underline;padding-left:18px;}.docs-page .docs-page-index .scroll-top-btn.showup{display:block;}@media(min-width:1200px){.container{max-width:1180px;}}@media(min-width:1366px){.container{max-width:1340px;}}@media(min-width:1440px){.container{max-width:1400px;}}@media(max-width:767px){.docs-page{background:#f5f7f9;}.docs-page>.container-fluid{display:block;}.docs-page>.container-fluid>.row{display:block;}.docs-page .docs-sidebar{position:fixed;max-width:100%;width:100%;display:block;padding:0 !important;top:0;left:0;z-index:100;right:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper{max-width:100%;width:100%;top:0;position:relative;margin:0 !important;height:72px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{padding:.5rem 1.5rem 2rem 1.5rem;height:calc(100vh - 72px);overflow:hidden;overflow-y:auto;position:fixed;top:72px;font-size:17px;left:0;width:100%;z-index:100;background:#f5f7f9;display:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search{position:relative;padding:0 0 1rem !important;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-search .btn-search{top:-14px;left:-2px;}.docs-page .docs-sidebar .docs-top .navbar-logo{padding:0;padding-top:.3rem;display:block;text-align:center;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:2rem;font-weight:700;display:block;margin-right:0;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand .docs-logo{width:110px;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:1em;display:none;}.docs-page .docs-sidebar .docs-top .open-dmenu{position:absolute;top:10px;left:20px;}.docs-page .docs-content{padding-top:72px;max-width:100%;display:block !important;}.docs-page .docs-content .docs-text-field{padding:1rem 1.5rem;}.docs-page .docs-page-index{display:none;}}@media(max-width:992px){body{font-size:14px;}.for-mobile{display:inline-block;}.for-desktop{display:none;}.close-mmenu,.close-dmenu{position:absolute;top:-78px;left:25px;color:#fff;font-size:68px;background:#fff;opacity:0;}.navbar{padding:.5rem 1.75rem;}.navbar .navbar-collapse{background:#38003d;position:fixed;top:86px;left:0;width:100%;height:100vh;height:calc(100vh - 86px);z-index:100 !important;}.navbar .navbar-collapse .navbar-nav{height:100vh;padding:20px 30px;overflow:auto;}.navbar .navbar-collapse .navbar-nav .nav-link{padding:1.2rem !important;}.navbar .navbar-toggler{padding:.5rem .75rem;font-size:1.5rem;line-height:1;background-color:transparent;border:0;border-radius:.25rem;color:#fff !important;margin-left:-1rem;}.jumbotron .btn,footer .btn{display:block;margin-bottom:10px;}.multi-tenancy{text-align:center !important;}.section-with-logos img{margin:15px;opacity:1;-webkit-filter:grayscale(0%);filter:grayscale(0%);}.jumbotron{padding-top:160px;margin-top:-160px;border-radius:0;padding-bottom:40px;margin-bottom:0;font-size:.85em;padding-left:45px;padding-right:45px;}span.code-arrow{padding:0 0 0;display:block;transform:rotate(90deg);font-size:2em;}.mb-5,.my-5{margin-bottom:2rem !important;}.jumbotron{height:calc(100vh + 120px);}.jumbotron.jumbocover{height:auto;padding:160px 0 20px;}.jumbotron hr{display:none;}.jumbotron .btn{margin-bottom:0 !important;}.jumbotron .jumbotron-logo{margin-bottom:0;width:180px;height:62px;margin-top:-30px;}.jumbotron .jlogo-wrapper{height:62px;}}.vs-blog{margin-top:-88px !important;}.abp-account-container{max-width:400px;margin:0 auto;margin-top:-88px !important;}body{background-size:cover;} \ No newline at end of file diff --git a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss b/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss index 07bfa1b354..4d9cb4a995 100644 --- a/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss +++ b/abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss @@ -3,7 +3,7 @@ @import "footer.scss"; @import "home.scss"; @import "docs.scss"; -@media (max-width: 767px) { +@media (max-width: 992px) { @import "responsive.scss"; } diff --git a/abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj b/abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj index f445e989d1..254d8b65c5 100644 --- a/abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj +++ b/abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj @@ -15,9 +15,9 @@ - + - + diff --git a/build-all.ps1 b/build-all.ps1 index 935cfeb8a9..5d800ebdf9 100644 --- a/build-all.ps1 +++ b/build-all.ps1 @@ -20,7 +20,8 @@ $solutionPaths = ( "abp_io", "templates/module", "templates/service", - "templates/mvc" + "templates/mvc", + "samples/MicroserviceDemo" ) # Build all solutions @@ -31,6 +32,7 @@ foreach ($solutionPath in $solutionPaths) { dotnet build if (-Not $?) { Write-Host ("Build failed for the solution: " + $solutionPath) + Set-Location $rootFolder exit $LASTEXITCODE } } diff --git a/common.DotSettings b/common.DotSettings new file mode 100644 index 0000000000..cb0b2c919f --- /dev/null +++ b/common.DotSettings @@ -0,0 +1,23 @@ + + True + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + Required + Required + Required + Required + False + True + False + False + True + False + False + SQL + \ No newline at end of file diff --git a/common.props b/common.props index 15df803252..040172c6d4 100644 --- a/common.props +++ b/common.props @@ -1,7 +1,7 @@ latest - 0.9.0 + 0.13.0 $(NoWarn);CS1591 https://abp.io/assets/abp_nupkg.png https://abp.io @@ -11,7 +11,7 @@ - + \ No newline at end of file diff --git a/docs/en/AspNetCore/Auto-API-Controllers.md b/docs/en/AspNetCore/Auto-API-Controllers.md new file mode 100644 index 0000000000..48567b6919 --- /dev/null +++ b/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(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(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(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. \ No newline at end of file diff --git a/docs/en/AspNetCore/Bundling-Minification.md b/docs/en/AspNetCore/Bundling-Minification.md index b8d70d8624..7170690ef3 100644 --- a/docs/en/AspNetCore/Bundling-Minification.md +++ b/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: @@ -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. -### 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. @@ -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: @@ -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). * 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. @@ -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 ```` -#### 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: @@ -90,7 +90,7 @@ Advantages of **named** bundles: * 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: @@ -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. -### 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. -#### Creating A New Bundle +### Creating A New Bundle 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. -#### 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. -Example: +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: ````C# [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. -### 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. @@ -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# services.Configure(options => @@ -200,8 +199,9 @@ services.Configure(options => }); ```` -Contributors can also be used in the bundle tag helpers. -Example: +> You can also add contributors while creating a new bundle. + +Contributors can also be used in the bundle tag helpers. Example: ````xml @@ -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. -#### Contributor Dependencies +### Contributor Dependencies A bundle contributor can have one or more dependencies to other contributors. 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. -#### 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(options => +{ + options + .Extensions() + .Add(); +}); +```` + +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. -#### 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. @@ -255,7 +284,7 @@ Using the built-in contributors for standard packages; * Prevents multiple modules adding the **duplicate the files**. * 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. @@ -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. Example: @@ -302,11 +331,11 @@ services.Configure(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. -### Best Practices & Suggestions +## Best Practices & Suggestions 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. -### See Also +## See Also * [Client Side Package Management](Client-Side-Package-Management.md) * [Theming](Theming.md) diff --git a/docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md b/docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md new file mode 100644 index 0000000000..0b0667dd0d --- /dev/null +++ b/docs/en/AspNetCore/Dynamic-CSharp-API-Clients.md @@ -0,0 +1,165 @@ +# 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 IBookAppService : IApplicationService +{ + Task> GetListAsync(); +} +```` + +Your interface should implement the `IRemoteService` interface to be automatically discovered. Since the `IApplicationService` inherits the `IRemoteService` interface, the `IBookAppService` 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) + { + //Create dynamic client proxies + context.Services.AddHttpClientProxies( + typeof(BookStoreApplicationModule).Assembly + ); + } +} +```` + +`AddHttpClientProxies` method gets an assembly, finds all service interfaces in the given assembly, creates and registers proxy classes. + +### Endpoint Configuration + +`RemoteServices` section in the `appsettings.json` file is used to get remote service address by default. Simplest configuration is shown below: + +```` +{ + "RemoteServices": { + "Default": { + "BaseUrl": "http://localhost:53929/" + } + } +} +```` + +See the "RemoteServiceOptions" section below for more detailed configuration. + +## Usage + +It's straightforward to use. Just inject the service interface in the client application code: + +````csharp +public class MyService : ITransientDependency +{ + private readonly IBookAppService _bookService; + + public MyService(IBookAppService 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 `IBookAppService` service interface defined above. The dynamic client proxy implementation makes an HTTP call whenever a service method is called by the client. + +### IHttpClientProxy Interface + +While you can inject `IBookAppService` like above to use the client proxy, you could inject `IHttpClientProxy` for a more explicit usage. In this case you will use the `Service` property of the `IHttpClientProxy` interface. + +## Configuration + +### RemoteServiceOptions + +`RemoteServiceOptions` is automatically set from the `appsettings.json` by default. Alternatively, you can use `Configure` method to set or override it. Example: + +````csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + context.Services.Configure(options => + { + options.RemoteServices.Default = + new RemoteServiceConfiguration("http://localhost:53929/"); + }); + + //... +} +```` + +### Multiple Remote Service Endpoints + +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 endpoints). In this case, you can add other endpoints to your configuration file: + +````json +{ + "RemoteServices": { + "Default": { + "BaseUrl": "http://localhost:53929/" + }, + "BookStore": { + "BaseUrl": "http://localhost:48392/" + } + } +} +```` + +`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. + +### As Default Services + +When you create a service proxy for `IBookAppService`, you can directly inject the `IBookAppService` to use the proxy client (as shown in the usage section). You can pass `asDefaultServices: false` to the `AddHttpClientProxies` method to disable this feature. + +````csharp +context.Services.AddHttpClientProxies( + typeof(BookStoreApplicationModule).Assembly, + asDefaultServices: false +); +```` + +Using `asDefaultServices: false` may only be needed if your application has already an implementation of the service and you do not want to override/replace the other implementation by your client proxy. + +> If you disable `asDefaultServices`, you can only use `IHttpClientProxy` interface to use the client proxies (see the related section above). \ No newline at end of file diff --git a/docs/en/Autofac-Integration.md b/docs/en/Autofac-Integration.md new file mode 100644 index 0000000000..b3aced3e94 --- /dev/null +++ b/docs/en/Autofac-Integration.md @@ -0,0 +1,84 @@ +# Autofac Integration + +Autofac is one of the most used dependency injection frameworks for .Net. It provides some advanced features compared to .Net Core standard DI library, like dynamic proxying and property injection. + +## Install Autofac Integration + +> All startup templates and samples are Autofac integrated. So, most of the time you don't need to manually install this package. + +Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) nuget package to your project (for a multi-projects application, it's suggested to add to the executable/web project.) + +```` +Install-Package Volo.Abp.Autofac +```` + +Then add `AbpAutofacModule` dependency to your module: + +```csharp +using Volo.Abp.Modularity; +using Volo.Abp.Autofac; + +namespace MyCompany.MyProject +{ + [DependsOn(typeof(AbpAutofacModule))] + public class MyModule : AbpModule + { + //... + } +} +``` + +Finally, configure `AbpApplicationCreationOptions` to replace default dependency injection services by Autofac. It depends on the application type. + +### ASP.NET Core Application + +Call `UseAutofac()` in the **Startup.cs** file as shown below: + +````csharp +public class Startup +{ + public IServiceProvider ConfigureServices(IServiceCollection services) + { + services.AddApplication(options => + { + //Integrate Autofac! + options.UseAutofac(); + }); + + return services.BuildServiceProviderFromFactory(); + } + + public void Configure(IApplicationBuilder app) + { + app.InitializeApplication(); + } +} +```` + +### Console Application + +Call `UseAutofac()` method in the `AbpApplicationFactory.Create` options as shown below: + +````csharp +using System; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; + +namespace AbpConsoleDemo +{ + class Program + { + static void Main(string[] args) + { + using (var application = AbpApplicationFactory.Create(options => + { + options.UseAutofac(); //Autofac integration + })) + { + //... + } + } + } +} +```` + diff --git a/docs/en/Best-Practices/MongoDB-Integration.md b/docs/en/Best-Practices/MongoDB-Integration.md index 32eefadd6a..76b6e8561f 100644 --- a/docs/en/Best-Practices/MongoDB-Integration.md +++ b/docs/en/Best-Practices/MongoDB-Integration.md @@ -103,34 +103,6 @@ public class IdentityMongoModelBuilderConfigurationOptions } ``` -* **Do** explicitly configure `BsonClassMap` for all entities. Create a static method for this purpose. Example: - -````C# -public static class AbpIdentityBsonClassMap -{ - private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); - - public static void Configure() - { - OneTimeRunner.Run(() => - { - BsonClassMap.RegisterClassMap(map => - { - map.AutoMap(); - map.ConfigureExtraProperties(); - }); - - BsonClassMap.RegisterClassMap(map => - { - map.AutoMap(); - }); - }); - } -} -```` - -`BsonClassMap` works with static methods. So, it is only needed to configure entities once in an application. `OneTimeRunner` guarantees that it runs in a thread safe manner and only once in the application life. Such a mapping above ensures that unit test properly run. This code will be called by the **module class** below. - ### Repository Implementation - **Do** **inherit** the repository from the `MongoDbRepository` class and implement the corresponding repository interface. Example: @@ -187,8 +159,6 @@ public class AbpIdentityMongoDbModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { - AbpIdentityBsonClassMap.Configure(); - context.Services.AddMongoDbContext(options => { options.AddRepository(); diff --git a/docs/en/Dependency-Injection.md b/docs/en/Dependency-Injection.md index a001d52ec9..d1ca14950c 100644 --- a/docs/en/Dependency-Injection.md +++ b/docs/en/Dependency-Injection.md @@ -1,8 +1,10 @@ -## Dependency Injection +# Dependency Injection ABP's Dependency Injection system is developed based on Microsoft's [dependency injection extension](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) library (Microsoft.Extensions.DependencyInjection nuget package). So, it's documentation is valid in ABP too. -### Modularity +> While ABP has no core dependency to any 3rd-party DI provider, it's required to use a provider that supports dynamic proxying and some other advanced features to make some ABP features properly work. Startup templates come with Autofac installed. See [Autofac integration](Autofac-Integration.md) document for more information. + +## Modularity Since ABP is a modular framework, every module defines it's own services and registers via dependency injection in it's own seperate [module class](Module-Development-Basics.md). Example: @@ -16,7 +18,7 @@ public class BlogModule : AbpModule } ```` -### Conventional Registration +## Conventional Registration ABP introduces conventional service registration. You need not do anything to register a service by convention. It's automatically done. If you want to disable it, you can set `SkipAutoServiceRegistration` to `true` by overriding the `PreConfigureServices` method. @@ -49,7 +51,7 @@ public class BlogModule : AbpModule The section below explains the conventions and configurations. -#### Inherently Registered Types +### Inherently Registered Types Some specific types are registered to dependency injection by default. Examples: @@ -71,7 +73,7 @@ public class BlogPostAppService : ApplicationService ``BlogPostAppService`` is automatically registered with transient lifetime since it's derived from a known base class. -#### Dependency Interfaces +### Dependency Interfaces If you implement these interfaces, your class is registered to dependency injection automatically: @@ -89,7 +91,7 @@ public class TaxCalculator : ITransientDependency ``TaxCalculator`` is automatically registered with a transient lifetime since it implements ``ITransientDependency``. -#### Dependency Attribute +### Dependency Attribute Another way of configuring a service for dependency injection is to use ``DependencyAttribute``. It has the following properties: @@ -110,7 +112,7 @@ public class TaxCalculator ``Dependency`` attribute has a higher priority than other dependency interfaces if it defines the ``Lifetime`` property. -#### ExposeServices Attribute +### ExposeServices Attribute ``ExposeServicesAttribute`` is used to control which services are provided by the related class. Example: @@ -124,14 +126,14 @@ public class TaxCalculator: ICalculator, ITaxCalculator, ICanCalculate, ITransie ``TaxCalculator`` class only exposes ``ITaxCalculator`` interface. That means you can only inject ``ITaxCalculator``, but can not inject ``TaxCalculator`` or ``ICalculator`` in your application. -#### Exposed Services by Convention +### Exposed Services by Convention If you do not specify which services to expose, ABP expose services by convention. So taking the ``TaxCalculator`` defined above: * The class itself is exposed by default. That means you can inject it by ``TaxCalculator`` class. * Default interfaces are exposed by default. Default interfaces are determined by naming convention. In this example, ``ICalculator`` and ``ITaxCalculator`` are default interfaces of ``TaxCalculator``, but ``ICanCalculate`` is not. -#### Combining All Together +### Combining All Together Combining attributes and interfaces is possible as long as it's meaningful. @@ -144,7 +146,7 @@ public class TaxCalculator : ITaxCalculator, ITransientDependency } ```` -#### Manually Registering +### Manually Registering In some cases, you may need to register a service to the `IServiceCollection` manually, especially if you need to use custom factory methods or singleton instances. In that case, you can directly add services just as [Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) describes. Example: @@ -157,16 +159,18 @@ public class BlogModule : AbpModule context.Services.AddSingleton(new TaxCalculator(taxRatio: 0.18)); //Register a factory method that resolves from IServiceProvider - context.Services.AddScoped(sp => sp.GetRequiredService()); + context.Services.AddScoped( + sp => sp.GetRequiredService() + ); } } ```` -### Injecting Dependencies +## Injecting Dependencies There are three common ways of using a service that has already been registered. -#### Contructor Injection +### Contructor Injection This is the most common way of injecting a service into a class. For example: @@ -191,7 +195,7 @@ public class TaxAppService : ApplicationService Constructor injection is preffered way of injecting dependencies to a class. In that way, the class can not be constructed unless all constructor-injected dependencies are provided. Thus, the class explicitly declares it's required services. -#### Property Injection +### Property Injection Property injection is not supported by Microsoft Dependency Injection library. However, ABP can integrate with 3rd-party DI providers ([Autofac](https://autofac.org/), for example) to make property injection possible. Example: @@ -222,7 +226,7 @@ One restriction of property injection is that you cannot use the dependency in y Property injection is also useful when you want to design a base class that has some common services injected by default. If you're going to use constructor injection, all derived classes should also inject depended services into their own constructors which makes development harder. However, be very careful using property injection for non-optional services as it makes it harder to clearly see the requirements of a class. -#### Resolve Service from IServiceProvider +### Resolve Service from IServiceProvider You may want to resolve a service directly from ``IServiceProvider``. In that case, you can inject IServiceProvider into your class and use ``GetService`` method as shown below: @@ -244,7 +248,7 @@ public class MyService : ITransientDependency } ```` -#### Releasing/Disposing Services +### Releasing/Disposing Services If you used a constructor or property injection, you don't need to be concerned about releasing the service's resources. However, if you have resolved a service from ``IServiceProvider``, you might, in some cases, need to take care about releasing the service resources. @@ -266,6 +270,54 @@ using (var scope = _serviceProvider.CreateScope()) Both services are released when the created scope is disposed (at the end of the using block). -### See Also +## Advanced Features + +### IServiceCollection.OnRegistred Event + +You may want to perform an action for every service registered to the dependency injection. In the `PreConfigureServices` method of your module, register a callback using the `OnRegistred` method as shown below: + +````csharp +public class AppModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + context.Services.OnRegistred(ctx => + { + var type = ctx.ImplementationType; + //... + }); + } +} +```` + +`ImplementationType` provides the service type. This callback is generally used to add interceptor to a service. Example: + +````csharp +public class AppModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + context.Services.OnRegistred(ctx => + { + if (ctx.ImplementationType.IsDefined(typeof(MyLogAttribute), true)) + { + ctx.Interceptors.TryAdd(); + } + }); + } +} +```` + +This example simply checks if the service class has `MyLogAttribute` attribute and adds `MyLogInterceptor` to the interceptor list if so. + +> Notice that `OnRegistred` callback might be called multiple times for the same service class if it exposes more than one service/interface. So, it's safe to use `Interceptors.TryAdd` method instead of `Interceptors.Add` method. See [the documentation](Dynamic-Proxying-Interceptors.md) of dynamic proxying / interceptors. + +## 3rd-Party Providers + +While ABP has no core dependency to any 3rd-party DI provider, it's required to use a provider that supports dynamic proxying and some other advanced features to make some ABP features properly work. + +Startup templates come with Autofac installed. See [Autofac integration](Autofac-Integration.md) document for more information. + +## See Also * [ASP.NET Core Dependency Injection Best Practices, Tips & Tricks](https://medium.com/volosoft/asp-net-core-dependency-injection-best-practices-tips-tricks-c6e9c67f9d96) diff --git a/docs/en/Dynamic-Proxying-Interceptors.md b/docs/en/Dynamic-Proxying-Interceptors.md new file mode 100644 index 0000000000..76a23daa8f --- /dev/null +++ b/docs/en/Dynamic-Proxying-Interceptors.md @@ -0,0 +1,3 @@ +## Dynamic Proxying / Interceptors + +TODO \ No newline at end of file diff --git a/docs/en/Entities.md b/docs/en/Entities.md index 89688d58c8..a90b95d100 100644 --- a/docs/en/Entities.md +++ b/docs/en/Entities.md @@ -41,7 +41,7 @@ public class UserRole : Entity public DateTime CreationTime { get; set; } - public Phone() + public UserRole() { } diff --git a/docs/en/Entity-Framework-Core.md b/docs/en/Entity-Framework-Core.md index 4f9ff367ee..e608736bcd 100644 --- a/docs/en/Entity-Framework-Core.md +++ b/docs/en/Entity-Framework-Core.md @@ -1,8 +1,8 @@ -## Entity Framework Core Integration +# Entity Framework Core Integration This document explains how to integrate EF Core as an ORM provider to ABP based applications and how to configure it. -### Installation +## Installation `Volo.Abp.EntityFrameworkCore` is the main nuget package for the EF Core integration. Install it to your project (for a layered application, to your data/infrastructure layer): @@ -28,7 +28,7 @@ namespace MyCompany.MyProject > Note: Instead, you can directly download a [startup template](https://abp.io/Templates) with EF Core pre-installed. -### Creating DbContext +## Creating DbContext You can create your DbContext as you normally do. It should be derived from `AbpDbContext` as shown below: @@ -50,7 +50,21 @@ namespace MyCompany.MyProject } ```` -### Registering DbContext To Dependency Injection +### Configure the Connection String Selection + +If you have multiple databases in your application, you can configure the connection string name for your DbContext using the `[ConnectionStringName]` attribute. Example: + +```csharp +[ConnectionStringName("MySecondConnString")] +public class MyDbContext : AbpDbContext +{ + +} +``` + +If you don't configure, the `Default` connection string is used. If you configure a specific connection string name, but not define this connection string name in the application configuration then it fallbacks to the `Default` connection string. + +## Registering DbContext To Dependency Injection Use `AddAbpDbContext` method in your module to register your DbContext class for [dependency injection](Dependency-Injection.md) system. @@ -74,7 +88,7 @@ namespace MyCompany.MyProject } ```` -#### Add Default Repositories +### Add Default Repositories ABP can automatically create default [generic repositories](Repositories.md) for the entities in your DbContext. Just use `AddDefaultRepositories()` option on the registration: @@ -137,7 +151,7 @@ public class BookManager : DomainService This sample uses `InsertAsync` method to insert a new entity to the database. -#### Add Custom Repositories +### Add Custom Repositories Default generic repositories are powerful enough in most cases (since they implement `IQueryable`). However, you may need to create a custom repository to add your own repository methods. @@ -173,7 +187,7 @@ public class BookRepository : EfCoreRepository, Now, it's possible to [inject](Dependency-Injection.md) the `IBookRepository` and use the `DeleteBooksByType` method when needed. -##### Override Default Generic Repository +#### Override Default Generic Repository Even if you create a custom repository, you can still inject the default generic repository (`IRepository` for this example). Default repository implementation will not use the class you have created. @@ -199,7 +213,7 @@ public override async Task DeleteAsync( } ```` -#### Access to the EF Core API +### Access to the EF Core API In most cases, you want to hide EF Core APIs behind a repository (this is the main purpose of the repository). However, if you want to access the DbContext instance over the repository, you can use `GetDbContext()` or `GetDbSet()` extension methods. Example: @@ -225,9 +239,9 @@ public class BookService > Important: You must reference to the `Volo.Abp.EntityFrameworkCore` package from the project you want to access to the DbContext. This breaks encapsulation, but this is what you want in that case. -#### Advanced Topics +### Advanced Topics -##### Set Default Repository Classes +#### Set Default Repository Classes Default generic repositories are implemented by `EfCoreRepository` class by default. You can create your own implementation and use it for default repository implementation. @@ -272,7 +286,7 @@ context.Services.AddAbpDbContext(options => }); ``` -##### Set Base DbContext Class or Interface for Default Repositories +#### Set Base DbContext Class or Interface for Default Repositories If your DbContext inherits from another DbContext or implements an interface, you can use that base class or interface as DbContext for default repositories. Example: @@ -304,7 +318,7 @@ public class BookRepository : EfCoreRepository, One advantage of using interface for a DbContext is then it becomes replaceable by another implementation. -##### Replace Other DbContextes +#### Replace Other DbContextes Once you properly define and use an interface for DbContext, then any other implementation can replace it using the `ReplaceDbContext` option: diff --git a/docs/en/Event-Bus.md b/docs/en/Event-Bus.md new file mode 100644 index 0000000000..cf2b57c018 --- /dev/null +++ b/docs/en/Event-Bus.md @@ -0,0 +1,3 @@ +# Event Bus + +TODO \ No newline at end of file diff --git a/docs/en/Getting-Started-AspNetCore-Application.md b/docs/en/Getting-Started-AspNetCore-Application.md index f242f8cd46..fe1ff3450b 100644 --- a/docs/en/Getting-Started-AspNetCore-Application.md +++ b/docs/en/Getting-Started-AspNetCore-Application.md @@ -1,8 +1,8 @@ -## 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 1. Create a new empty AspNet Core Web Application from Visual Studio: @@ -14,7 +14,7 @@ This tutorial explains how to start ABP from scratch with minimal dependencies. You could select another template, but I want to show it from a clear project. -### Install Volo.Abp.AspNetCore.Mvc Package +## Install Volo.Abp.AspNetCore.Mvc Package Volo.Abp.AspNetCore.Mvc is AspNet Core MVC integration package for ABP. So, install it to your project: @@ -22,7 +22,7 @@ Volo.Abp.AspNetCore.Mvc is AspNet Core MVC integration package for ABP. So, inst Install-Package Volo.Abp.AspNetCore.Mvc ```` -### Create First ABP Module +## Create First ABP Module ABP is a modular framework and it requires a **startup (root) module** class derived from ``AbpModule``: @@ -62,7 +62,7 @@ ABP packages define module classes and a module can depend on another module. In Instead of Startup class, we are configuring ASP.NET Core pipeline in this module class. -### The Startup Class +## The Startup Class Next step is to modify Startup class to integrate to ABP module system: @@ -95,7 +95,7 @@ Changed ``ConfigureServices`` method to return ``IServiceProvider`` instead of ` ``app.InitializeApplication()`` call in ``Configure`` method initializes and starts the application. -### Hello World! +## Hello World! The application above does nothing. Let's create an MVC controller does something: @@ -120,13 +120,13 @@ If you run the application, you will see a "Hello World!" message on the page. Derived ``HomeController`` from ``AbpController`` instead of standard ``Controller`` class. This is not required, but ``AbpController`` class has useful base properties and methods to make your development easier. -### Using Autofac as the Dependency Injection Framework +## Using Autofac as the Dependency Injection Framework While AspNet Core's Dependency Injection (DI) system is fine for basic requirements, Autofac provides advanced features like Property Injection and Method Interception which are required by ABP to perform advanced application framework features. Replacing AspNet Core's DI system by Autofac and integrating to ABP is pretty easy. -1. Install Volo.Abp.Autofac package +1. Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) package ```` Install-Package Volo.Abp.Autofac @@ -152,6 +152,6 @@ services.AddApplication(options => }); ```` -### Source Code +## Source Code Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp/tree/master/samples/BasicAspNetCoreApplication). diff --git a/docs/en/Getting-Started-AspNetCore-MVC-Template.md b/docs/en/Getting-Started-AspNetCore-MVC-Template.md index 665cec98b1..de9a5b09cb 100644 --- a/docs/en/Getting-Started-AspNetCore-MVC-Template.md +++ b/docs/en/Getting-Started-AspNetCore-MVC-Template.md @@ -1,5 +1,7 @@ ## 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 Go to [the template creation page](https://abp.io/Templates), enter a project name and create your project as shown below: diff --git a/docs/en/Getting-Started-Console-Application.md b/docs/en/Getting-Started-Console-Application.md index 00c3d1e0a2..faaa8cd376 100644 --- a/docs/en/Getting-Started-Console-Application.md +++ b/docs/en/Getting-Started-Console-Application.md @@ -1,14 +1,14 @@ -## Getting Started ABP With Console Application +# Getting Started ABP With Console 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)**. -### Create A New Project +## Create A New Project Create a new Regular .Net Core Console Application from Visual Studio: ![](images/create-new-net-core-console-application.png) -### Install Volo.Abp Package +## Install Volo.Abp Package Volo.Abp.Core is the core nuget package to create ABP based applications. So, install it to your project: @@ -16,7 +16,7 @@ Volo.Abp.Core is the core nuget package to create ABP based applications. So, in Install-Package Volo.Abp.Core ```` -### Create First ABP Module +## Create First ABP Module ABP is a modular framework and it requires a **startup (root) module** class derived from ``AbpModule``: @@ -35,7 +35,7 @@ namespace AbpConsoleDemo ``AppModule`` is a good name for the startup module for an application. -### Initialize The Application +## Initialize The Application The next step is to bootstrap the application using the startup module created above: @@ -64,7 +64,7 @@ namespace AbpConsoleDemo ``AbpApplicationFactory`` is used to create the application and load all modules taking ``AppModule`` as the startup module. ``Initialize()`` method starts the application. -### Hello World! +## Hello World! The application above does nothing. Let's create a service that does something: @@ -117,8 +117,65 @@ namespace AbpConsoleDemo } ```` -While it's enough for this simple code example, it's always suggested to create scopes in case of directly resolving dependencies from ``IServiceProvider`` (TODO: see DI documentation). +While it's enough for this simple code example, it's always suggested to create scopes in case of directly resolving dependencies from ``IServiceProvider`` (see the [Dependency Injection documentation](Dependency-Injection.md)). -### Source Code +## Using Autofac as the Dependency Injection Framework -Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp/tree/master/samples/BasicConsoleApplication. +While AspNet Core's Dependency Injection (DI) system is fine for basic requirements, Autofac provides advanced features like Property Injection and Method Interception which are required by ABP to perform advanced application framework features. + +Replacing AspNet Core's DI system by Autofac and integrating to ABP is pretty easy. + +1. Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) package + +``` +Install-Package Volo.Abp.Autofac +``` + +1. Add ``AbpAutofacModule`` Dependency + +```c# +[DependsOn(typeof(AbpAutofacModule))] //Add dependency to the AbpAutofacModule +public class AppModule : AbpModule +{ + +} +``` + +1. Change ``Program.cs`` file as shown below: + +```c# +using System; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; + +namespace AbpConsoleDemo +{ + class Program + { + static void Main(string[] args) + { + using (var application = AbpApplicationFactory.Create(options => + { + options.UseAutofac(); //Autofac integration + })) + { + application.Initialize(); + + //Resolve a service and use it + var helloWorldService = + application.ServiceProvider.GetService(); + helloWorldService.SayHello(); + + Console.WriteLine("Press ENTER to stop application..."); + Console.ReadLine(); + } + } + } +} +``` + +Just called `options.UseAutofac()` method in the `AbpApplicationFactory.Create` options. + +## Source Code + +Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp/tree/master/samples/BasicConsoleApplication). diff --git a/docs/en/Index.md b/docs/en/Index.md index 443579e40e..b1bccab0ea 100644 --- a/docs/en/Index.md +++ b/docs/en/Index.md @@ -1,66 +1,30 @@ # ABP Documentation -## Table of Contents +ABP is an **open source application framework** focused on ASP.NET Core based web application development, but also supports developing other types of applications. -* Getting Started - * From Startup Templates - * [ASP.NET Core MVC Template](Getting-Started-AspNetCore-MVC-Template.md) - * From Empty Projects - * [With Console Application](Getting-Started-Console-Application.md) - * [With ASP.NET Core Web Application](Getting-Started-AspNetCore-Application.md) -* Tutorials - * Application Development - * [With ASP.NET Core MVC](Tutorials/AspNetCore-Mvc/Part-I.md) -* Fundamentals - * [Dependency Injection](Dependency-Injection.md) - * AutoFac Integration - * [Virtual File System](Virtual-File-System.md) - * [Localization](Localization.md) - * [Exception Handling](Exception-Handling.md) - * Validation - * Authorization - * Caching - * Auditing - * Setting Management - * Object to Object Mapping - * AutoMapper Integration -* Events - * Event Bus (local) - * Distributed Event Bus - * RabbitMQ Integration -* Services - * Object Serialization - * 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 +Explore the left navigation menu to deep dive in the documentation. + +## Project Status + +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 still in progress and it is incomplete yet. + +For short-term and production level applications, it's suggested to use [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework which has rich feature set, mature, actively maintained and up-to-date. + +## Getting Started + +Easiest way to start a new project with ABP is to use the startup templates: + +* [ASP.NET Core MVC Template](Getting-Started-AspNetCore-MVC-Template.md) + +If you want to start from scratch (with an empty project) then manually install the ABP Framework and use the following tutorials: + +* [Console Application](Getting-Started-Console-Application.md) +* [ASP.NET Core Web Application](Getting-Started-AspNetCore-Application.md) + +## Source Code + +ABP is hosted on GitHub. See [the source code](https://github.com/abpframework/abp). + +## Want to Contribute? + +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. diff --git a/docs/en/Localization.md b/docs/en/Localization.md index b6d27cc9ce..d34dc8232a 100644 --- a/docs/en/Localization.md +++ b/docs/en/Localization.md @@ -1,8 +1,8 @@ -## Localization +# Localization ABP's localization system is seamlessly integrated to the `Microsoft.Extensions.Localization` package and compatible with the [Microsoft's localization documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization). It adds some useful features and enhancements to make it easier to use in real life application scenarios. -### Volo.Abp.Localization Package +## Volo.Abp.Localization Package > This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually. @@ -28,9 +28,9 @@ namespace MyCompany.MyProject } ``` -#### Creating A Localization Resource +## Creating A Localization Resource -A localization resource is used to group related localization strings together and separate them from other localization strings of the application. A module generally defines its own localization resource. Localization resource is just a plain class. Example: +A localization resource is used to group related localization strings together and separate them from other localization strings of the application. A [module](Module-Development-Basics.md) generally defines its own localization resource. Localization resource is just a plain class. Example: ````C# public class TestResource @@ -52,7 +52,8 @@ public class MyModule : AbpModule }); Configure(options => - { + { + //Define a new localization resource (TestResource) options.Resources .Add("en") .AddVirtualJson("/Localization/Resources/Test"); @@ -65,7 +66,7 @@ In this example; * Added a new localization resource with "en" (English) as the default culture. * Used JSON files to store the localization strings. -* JSON files are embedded into the assembly using the [virtual file system](Virtual-File-System.md). +* JSON files are embedded into the assembly using `VirtualFileSystemOptions` (see [virtual file system](Virtual-File-System.md)). JSON files are located under "/Localization/Resources/Test" project folder as shown below: @@ -85,7 +86,7 @@ A JSON localization file content is shown below: * Every localization file should define the `culture` code for the file (like "en" or "en-US"). * `texts` section just contains key-value collection of the localization strings (keys may have spaces too). -##### Short Localization Resource Name +### Short Localization Resource Name Localization resources are also available in the client (JavaScript) side. So, setting a short name for the localization resource makes it easy to use localization texts. Example: @@ -98,7 +99,7 @@ public class TestResource See the Getting Localized Test / Client Side section below. -##### Inherit From Other Resources +### Inherit From Other Resources A resource can inherit from other resources which makes possible to re-use existing localization strings without referring the existing resource. Example: @@ -124,7 +125,7 @@ services.Configure(options => * A resource may inherit from multiple resources. * If the new resource defines the same localized string, it overrides the string. -##### Extending Existing Resource +### Extending Existing Resource Inheriting from a resource creates a new resource without modifying the existing one. In some cases, you may want to not create a new resource but directly extend an existing resource. Example: @@ -139,13 +140,13 @@ services.Configure(options => * If an extension file defines the same localized string, it overrides the string. -#### Getting Localized Texts +## Getting Localized Texts -##### Server Side +### Server Side Getting the localized text on the server side is pretty standard. -###### Simplest Usage In A Class +#### Simplest Usage In A Class ````C# public class MyService @@ -164,7 +165,7 @@ public class MyService } ```` -###### Simplest Usage In A Razor View/Page +#### Simplest Usage In A Razor View/Page ````c# @inject IHtmlLocalizer Localizer @@ -174,7 +175,7 @@ public class MyService Refer to the [Microsoft's localization documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) for details about using localization on the server side. -##### Client Side +### Client Side ABP provides JavaScript services to use the same localized texts in the client side. diff --git a/docs/en/Microservice-Architecture.md b/docs/en/Microservice-Architecture.md new file mode 100644 index 0000000000..e30c070a01 --- /dev/null +++ b/docs/en/Microservice-Architecture.md @@ -0,0 +1,30 @@ +# Microservice Architecture + +*"Microservices are a software development technique—a variant of the **service-oriented architecture** (SOA) architectural style that structures an application as a collection of **loosely coupled services**. In a microservices architecture, services are **fine-grained** and the protocols are **lightweight**. The benefit of decomposing an application into different smaller services is that it improves **modularity**. This makes the application easier to understand, develop, test, and become more resilient to architecture erosion. It **parallelizes development** by enabling small autonomous teams to **develop, deploy and scale** their respective services independently. It also allows the architecture of an individual service to emerge through **continuous refactoring**. Microservices-based architectures enable **continuous delivery and deployment**."* + +— [Wikipedia](https://en.wikipedia.org/wiki/Microservices) + +## Introduction + +One of the major goals of the ABP framework is to provide a convenient infrastructure to create microservice solutions. To make this possible, + +* Provides a [module system](Module-Development-Basics.md) that allows you to split your application into modules where each module may have its own database, entities, services, APIs, UI components/pages... etc. +* Offers an [architectural model](Best-Practices/Module-Architecture.md) to develop your modules to be compatible to microservice development and deployment. +* Provides [best practices guide](Best-Practices/Index.md) to develop your module standards-compliance. +* Provides base infrastructure to implement [Domain Driven Design](Domain-Driven-Design.md) in your microservices. +* Provide services to [automatically create REST-style APIs](AspNetCore/Auto-API-Controllers.md) from your application services. +* Provide services to [automatically create C# API clients](AspNetCore/Dynamic-CSharp-API-Clients.md) that makes easy to consume your services from another service/application. +* Provides a [distributed event bus](Event-Bus.md) to communicate your services. +* Provides many other services to make your daily development easier. + +## Microservice for New Applications + +One common advise to start a new solution is **always to start with a monolith**, keep it modular and split into microservices once the monolith becomes a problem. This makes your progress fast in the beginning especially if your team is small and you don't want to deal with challanges of the microservice architecture. + +However, developing such a well-modular application can be a problem since it is **hard to keep modules isolated** from each other as you would do it for microservices (see [Stefan Tilkov's article](https://martinfowler.com/articles/dont-start-monolith.html) about that). Microservice architecture naturally forces you to develop well isolated services, but in a modular monolithic application it's easy to tight couple modules to each other and design **weak module boundaries** and API contracts. + +ABP can help you in that point by oferring a **microservice-compatible, strict module architecture** where your module is splitted into multiple layers/projects and developed in its own VS solution completely isolated and independent from other modules. Such a developed module is a natural microservice yet it can be easily plugged-in a monolithic application. See the [module development best practice guide](Best-Practices/Index.md) that offers a **microservice-first module design**. All [standard ABP modules](https://github.com/abpframework/abp/tree/master/modules) are developed based on this guide. So, you can use these modules by embedding into your monolithic solution or deploy them separately and use via remote APIs. They can share a single database or can have their own database based on your simple configuration. + +## Microservice Demo Solution + +The [sample microservice solution](Samples/Microservice-Demo.md) demonstrates a complete microservice solution based on the ABP framework. \ No newline at end of file diff --git a/docs/en/Module-Development-Basics.md b/docs/en/Module-Development-Basics.md index 6e1c724669..6a0561a0c5 100644 --- a/docs/en/Module-Development-Basics.md +++ b/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: @@ -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: @@ -52,15 +52,15 @@ public class BlogModule : AbpModule 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. -#### 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. -##### OnApplicationInitialization Method +#### OnApplicationInitialization Method 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 -##### 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. -#### 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: @@ -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. 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). \ No newline at end of file diff --git a/docs/en/Modules/Docs.md b/docs/en/Modules/Docs.md new file mode 100644 index 0000000000..1aa81621f5 --- /dev/null +++ b/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 + + ``` +* [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 + + ``` +* [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 + + ``` +* [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 + + ``` + + + +### 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(options => + { + options.DefinitionProviders.Add(); + }); + + Configure(options => + { + options.AddProfile(); + }); + } + } + ``` + + +* 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 + { + public MyProjectDbContext(DbContextOptions 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>(); + + 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: `` (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: `` (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: `` + +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. \ No newline at end of file diff --git a/docs/en/Modules/Index.md b/docs/en/Modules/Index.md new file mode 100644 index 0000000000..9dc5da7a99 --- /dev/null +++ b/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. \ No newline at end of file diff --git a/docs/en/MongoDB.md b/docs/en/MongoDB.md index c03c6f4f2c..e7d8084f41 100644 --- a/docs/en/MongoDB.md +++ b/docs/en/MongoDB.md @@ -1,8 +1,8 @@ -## MongoDB Integration +# MongoDB Integration This document explains how to integrate MongoDB as a database provider to ABP based applications and how to configure it. -### Installation +## Installation `Volo.Abp.MongoDB` is the main nuget package for the MongoDB integration. Install it to your project (for a layered application, to your data/infrastructure layer): @@ -26,7 +26,7 @@ namespace MyCompany.MyProject } ``` -### Creating a Mongo Db Context +## Creating a Mongo Db Context ABP introduces **Mongo Db Context** concept (which is similar to Entity Framework Core's DbContext) to make it easier to use collections and configure them. An example is shown below: @@ -39,19 +39,62 @@ public class MyDbContext : AbpMongoDbContext protected override void CreateModel(IMongoModelBuilder modelBuilder) { - modelBuilder.Entity(b => - { - b.CollectionName = "Questions"; - }); + base.CreateModel(modelBuilder); + + //Customize the configuration for your collections. } } ``` * It's derived from `AbpMongoDbContext` class. * Adds a public `IMongoCollection` property for each mongo collection. ABP uses these properties to create default repositories by default. -* Overriding `CreateModel` method allows to configure collections (like their collection name in the database). +* Overriding `CreateModel` method allows to configure collection configuration. + +### Configure Mapping for a Collection + +ABP automatically register entities to MongoDB client library for all `IMongoCollection` properties in your DbContext. For the example above, `Question` and `Category` entities are automatically registered. + +For each registered entity, it calls `AutoMap()` and configures known properties of your entity. For instance, if your entity implements `IHasExtraProperties` interface (which is already implemented for every aggregate root by default), it automatically configures `ExtraProperties`. + +So, most of times you don't need to explicitly configure registration for your entities. However, if you need it you can do it by overriding the `CreateModel` method in your DbContext. Example: + +````csharp +protected override void CreateModel(IMongoModelBuilder modelBuilder) +{ + base.CreateModel(modelBuilder); + + modelBuilder.Entity(b => + { + b.CollectionName = "MyQuestions"; //Sets the collection name + b.BsonMap.UnmapProperty(x => x.MyProperty); //Ignores 'MyProperty' + }); +} +```` + +This example changes the mapped collection name to 'MyQuestions' in the database and ignores a property in the `Question` class. + +If you only need to configure the collection name, you can also use `[MongoCollection]` attribute for the collection in your DbContext. Example: + +````csharp +[MongoCollection("MyQuestions")] //Sets the collection name +public IMongoCollection Questions => Collection(); +```` + +### Configure the Connection String Selection + +If you have multiple databases in your application, you can configure the connection string name for your DbContext using the `[ConnectionStringName]` attribute. Example: + +````csharp +[ConnectionStringName("MySecondConnString")] +public class MyDbContext : AbpMongoDbContext +{ + +} +```` + +If you don't configure, the `Default` connection string is used. If you configure a specific connection string name, but not define this connection string name in the application configuration then it fallbacks to the `Default` connection string. -### Registering DbContext To Dependency Injection +## Registering DbContext To Dependency Injection Use `AddAbpDbContext` method in your module to register your DbContext class for [dependency injection](Dependency-Injection.md) system. @@ -75,7 +118,7 @@ namespace MyCompany.MyProject } ``` -#### Add Default Repositories +### Add Default Repositories ABP can automatically create default [generic repositories](Repositories.md) for the entities in your DbContext. Just use `AddDefaultRepositories()` option on the registration: @@ -138,7 +181,7 @@ public class BookManager : DomainService This sample uses `InsertAsync` method to insert a new entity to the database. -#### Add Custom Repositories +### Add Custom Repositories Default generic repositories are powerful enough in most cases (since they implement `IQueryable`). However, you may need to create a custom repository to add your own repository methods. @@ -182,7 +225,7 @@ public class BookRepository : Now, it's possible to [inject](Dependency-Injection.md) the `IBookRepository` and use the `DeleteBooksByType` method when needed. -##### Override Default Generic Repository +#### Override Default Generic Repository Even if you create a custom repository, you can still inject the default generic repository (`IRepository` for this example). Default repository implementation will not use the class you have created. @@ -208,7 +251,7 @@ public override async Task DeleteAsync( } ``` -#### Access to the MongoDB API +### Access to the MongoDB API In most cases, you want to hide MongoDB APIs behind a repository (this is the main purpose of the repository). However, if you want to access the MongoDB API over the repository, you can use `GetDatabase()` or `GetCollection()` extension methods. Example: @@ -232,9 +275,9 @@ public class BookService > Important: You must reference to the `Volo.Abp.MongoDB` package from the project you want to access to the MongoDB API. This breaks encapsulation, but this is what you want in that case. -#### Advanced Topics +### Advanced Topics -##### Set Default Repository Classes +#### Set Default Repository Classes Default generic repositories are implemented by `MongoDbRepository` class by default. You can create your own implementation and use it for default repository implementation. @@ -279,7 +322,7 @@ context.Services.AddMongoDbContext(options => }); ``` -##### Set Base MongoDbContext Class or Interface for Default Repositories +#### Set Base MongoDbContext Class or Interface for Default Repositories If your MongoDbContext inherits from another MongoDbContext or implements an interface, you can use that base class or interface as the MongoDbContext for default repositories. Example: @@ -313,7 +356,7 @@ public class BookRepository One advantage of using interface for a MongoDbContext is then it becomes replaceable by another implementation. -##### Replace Other DbContextes +#### Replace Other DbContextes Once you properly define and use an interface for a MongoDbContext , then any other implementation can replace it using the `ReplaceDbContext` option: diff --git a/docs/en/Samples/Microservice-Demo.md b/docs/en/Samples/Microservice-Demo.md new file mode 100644 index 0000000000..747c733683 --- /dev/null +++ b/docs/en/Samples/Microservice-Demo.md @@ -0,0 +1,40 @@ +# Microservice Demo Solution + +*"Microservices are a software development technique—a variant of the **service-oriented architecture** (SOA) architectural style that structures an application as a collection of **loosely coupled services**. In a microservices architecture, services are **fine-grained** and the protocols are **lightweight**. The benefit of decomposing an application into different smaller services is that it improves **modularity**. This makes the application easier to understand, develop, test, and become more resilient to architecture erosion. It **parallelizes development** by enabling small autonomous teams to **develop, deploy and scale** their respective services independently. It also allows the architecture of an individual service to emerge through **continuous refactoring**. Microservices-based architectures enable **continuous delivery and deployment**."* + +— [Wikipedia](https://en.wikipedia.org/wiki/Microservices) + +## Introduction + +One of the major goals of the ABP framework is to provide a [convenient infrastructure to create microservice solutions](../Microservice-Architecture.md). + +This sample aims to demonstrate a simple yet complete microservice solution; + +* Has multiple, independent, self-deployable **microservices**. +* Multiple **web applications**, each uses a different API gateway. +* Has multiple **gateways** / BFFs (Backend for Frontends) developed using the [Ocelot](https://github.com/ThreeMammals/Ocelot) library. +* Has an **authentication service** developed using the [IdentityServer](https://identityserver.io/) framework. It's also a SSO (Single Sign On) application with necessary UIs. +* Has **multiple databases**. Some microservices has their own database while some services/applications shares a database (to demonstrate different use cases). +* Has different types of databases: **SQL Server** (with **Entity Framework Core** ORM) and **MongoDB**. +* Has a **console application** to show the simplest way of using a service by authenticating. +* Uses [Redis](https://redis.io/) for **distributed caching**. +* Uses [RabbitMQ](https://www.rabbitmq.com/) for service-to-service **messaging**. +* Uses [Kubernates](https://kubernetes.io/) to **deploy** & run all services and applications. + +The diagram below shows the system: + +![microservice-sample-diagram](../images/microservice-sample-diagram.png) + +### Source Code + +You can get the source code from [the GitHub repository](https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo). + +### Status + +This sample is still in development, not completed yet. + +## Microservices + +### Identity Service + +... \ No newline at end of file diff --git a/docs/en/Tutorials/AspNetCore-Mvc/Part-I.md b/docs/en/Tutorials/AspNetCore-Mvc/Part-I.md index 9a48022e27..6db6766c0b 100644 --- a/docs/en/Tutorials/AspNetCore-Mvc/Part-I.md +++ b/docs/en/Tutorials/AspNetCore-Mvc/Part-I.md @@ -82,11 +82,11 @@ namespace Acme.BookStore EF Core requires you to relate entities with your DbContext. The easiest way to do this is to add a `DbSet` property to the `BookStoreDbContext` class in the `Acme.BookStore.EntityFrameworkCore` project, as shown below: ````C# -public class BookStoreDbContext : AbpDbContext -{ - public DbSet Book { get; set; } - ... -} + public class BookStoreDbContext : AbpDbContext + { + public DbSet Book { get; set; } + ... + } ```` #### Add New Migration & Update the Database @@ -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. -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 diff --git a/docs/en/Virtual-File-System.md b/docs/en/Virtual-File-System.md index 9a27f3c426..c89a2a34ef 100644 --- a/docs/en/Virtual-File-System.md +++ b/docs/en/Virtual-File-System.md @@ -108,7 +108,7 @@ Embedding a file into a module assembly and being able to use it from another pr Let's assume that you're developing a module that contains an embedded JavaScript file. Whenever you change this file you must re-compile the project, re-start the application and refresh the browser page to take the change. Obviously, this is very time consuming and tedious. -What is needed is the ability for the application to directly use the physical file at development time and a have a browser refresh reflect any change made in the JavaScript file. The `ReplaceEmbeddedByPyhsical` method makes all this possible. +What is needed is the ability for the application to directly use the physical file at development time and a have a browser refresh reflect any change made in the JavaScript file. The `ReplaceEmbeddedByPhysical` method makes all this possible. The example below shows an application that depends on a module (`MyModule`) that itself contains embedded files. The application can reach the source code of the module at development time. @@ -124,8 +124,8 @@ public class MyWebAppModule : AbpModule { Configure(options => { - //ReplaceEmbeddedByPyhsical gets the root folder of the MyModule project - options.FileSets.ReplaceEmbeddedByPyhsical( + //ReplaceEmbeddedByPhysical gets the root folder of the MyModule project + options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}MyModuleProject", Path.DirectorySeparatorChar)) ); }); diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index fa8ec3552e..905821c73a 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -49,7 +49,8 @@ "path": "Dependency-Injection.md", "items": [ { - "text": "AutoFac Integration" + "text": "AutoFac Integration", + "path": "Autofac-Integration.md" } ] }, @@ -185,10 +186,20 @@ ] }, { - "text": "ASP.NET Core MVC", + "text": "ASP.NET Core", "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", @@ -245,6 +256,23 @@ } ] }, + { + "text": "Samples", + "items": [ + { + "text": "Microservice Demo", + "path": "Samples/Microservice-Demo.md" + } + ] + }, + { + "text": "Application Modules", + "path": "Modules/Index.md" + }, + { + "text": "Microservice Architecture", + "path": "Microservice-Architecture.md" + }, { "text": "Testing" }, diff --git a/docs/en/images/bookstore-apis.png b/docs/en/images/bookstore-apis.png new file mode 100644 index 0000000000..aedd79c7f1 Binary files /dev/null and b/docs/en/images/bookstore-apis.png differ diff --git a/docs/en/images/docs-module_download-new-abp-project.png b/docs/en/images/docs-module_download-new-abp-project.png new file mode 100644 index 0000000000..0da3b7a67a Binary files /dev/null and b/docs/en/images/docs-module_download-new-abp-project.png differ diff --git a/docs/en/images/docs-module_download-sample-navigation-menu.png b/docs/en/images/docs-module_download-sample-navigation-menu.png new file mode 100644 index 0000000000..9a1232f198 Binary files /dev/null and b/docs/en/images/docs-module_download-sample-navigation-menu.png differ diff --git a/docs/en/images/docs-module_solution-explorer.png b/docs/en/images/docs-module_solution-explorer.png new file mode 100644 index 0000000000..cafc38f0b0 Binary files /dev/null and b/docs/en/images/docs-module_solution-explorer.png differ diff --git a/docs/en/images/microservice-sample-diagram.png b/docs/en/images/microservice-sample-diagram.png new file mode 100644 index 0000000000..b1d9f6c66e Binary files /dev/null and b/docs/en/images/microservice-sample-diagram.png differ diff --git a/docs/zh-Hans/AspNetCore/Auto-API-Controllers.md b/docs/zh-Hans/AspNetCore/Auto-API-Controllers.md new file mode 100644 index 0000000000..afe8ea700b --- /dev/null +++ b/docs/zh-Hans/AspNetCore/Auto-API-Controllers.md @@ -0,0 +1,138 @@ +# 自动API控制器 + +创建[应用程序服务](Application-Services.md)后, 通常需要创建API控制器以将此服务公开为HTTP(REST)API端点. 典型的API控制器除了将方法调用重定向到应用程序服务并使用[HttpGet],[HttpPost],[Route]等属性配置REST API之外什么都不做. + +ABP可以按照惯例 **自动** 将你的应用程序服务配置为MVC API控制器. 大多数时候你不关心它的详细配置,但它可以完全被自定义. + +## 配置 + +基本配置很简单. 只需配置`AbpAspNetCoreMvcOptions`并使用`ConventionalControllers.Create`方法,如下所示: + +````csharp +[DependsOn(BookStoreApplicationModule)] +public class BookStoreWebModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly); + }); + } +} +```` + +此示例代码配置包含类`BookStoreApplicationModule`的程序集中的所有应用程序服务.下图显示了[Swagger UI](https://swagger.io/tools/swagger-ui/)上的API内容. + +![bookstore-apis](../images/bookstore-apis.png) + +### 例子 + +一些示例方法名称和按约定生成的相应路由: + +| 服务方法名称 | HTTP Method | 路由 | +| ----------------------------------------------------- | ----------- | -------------------------- | +| 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在确定服务方法的HTTP Method时使用命名约定: + +- **Get**: 如果方法名称以`GetList`,`GetAll`或`Get`开头. +- **Put**: 如果方法名称以`Put`或`Update`开头. +- **Delete**: 如果方法名称以`Delete`或`Remove`开头. +- **Post**: 如果方法名称以`Create`,`Add`,`Insert`或`Post`开头. +- **Patch**: 如果方法名称以`Patch`开头. +- 其他情况, **Post** 为 **默认方式**. + +如果需要为特定方法自定义HTTP Method, 则可以使用标准ASP.NET Core的属性([HttpPost], [HttpGet], [HttpPut]... 等等.). 这需要添加[Microsoft.AspNetCore.Mvc.Core](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Core)的Nuget包. + +### 路由 + +路由根据一些惯例生成: + +* 它始终以 **/api**开头. +* 接着是**路由路径**. 默认值为"**/app**", 可以进行如下配置: + +````csharp +Configure(options => +{ + options.ConventionalControllers + .Create(typeof(BookStoreApplicationModule).Assembly, opts => + { + opts.RootPath = "volosoft/book-store"; + }); +}); +```` + +然后获得一本书的路由将是'**/api/volosoft/book-store/book/{id}**'. 此示例使用两级根路径,但通常使用单个级别的深度. + +* 接着 **标准化控制器/服务名称**. 会删除`AppService`,`ApplicationService`和`Service`的后缀并将其转换为 **camelCase**. 如果你的应用程序服务类名称为`BookAppService`.那么它将变为`/book`. + * 如果要自定义命名, 则设置`UrlControllerNameNormalizer`选项. 它是一个委托允许你自定义每个控制器/服务的名称. +* 如果该方法具有 '**id**'参数, 则会在路由中添加'**/{id}**'. +* 如有必要,它会添加操作名称. 操作名称从服务上的方法名称获取并标准化; + * 删除'**Async**'后缀. 如果方法名称为'GetPhonesAsync',则变为`GetPhones`. + * 删除**HTTP method前缀**. 基于的HTTP method删除`GetList`,`GetAll`,`Get`,`Put`,`Update`,`Delete`,`Remove`,`Create`,`Add`,`Insert`,`Post`和`Patch`前缀, 因此`GetPhones`变为`Phones`, 因为`Get`前缀和GET请求重复. + * 将结果转换为**camelCase**. + * 如果生成的操作名称为**空**,则它不会添加到路径中.否则它会被添加到路由中(例如'/phones').对于`GetAllAsync`方法名称,它将为空,因为`GetPhonesAsync`方法名称将为`phone`. + * 可以通过设置`UrlActionNameNormalizer`选项来自定义.It's an action delegate that is called for every method. +* 如果有另一个带有'Id'后缀的参数,那么它也会作为最终路线段添加到路线中(例如'/phoneId'). + +## 服务选择 + +创建的HTTP API控制器并不是应用服务所独有的功能. + +### IRemoteService 接口 + +如果一个类实现了`IRemoteService`接口, 那么它会被自动选择为API控制器. 由于应用程序服务本身实现了`IRemoteService`接口, 因此它自然就成为API控制器. + +### RemoteService Attribute + +`RemoteService`可用于将实现`IRemoteService`接口的类标记为远程服务或禁用它. 例如: + +````csharp +[RemoteService(IsEnabled = false)] //or simply [RemoteService(false)] +public class PersonAppService : ApplicationService +{ + +} +```` + +### TypePredicate 选项 + +你可以通过提供`TypePedicate`选项进一步过滤类以成为API控制器: + +````csharp +services.Configure(options => +{ + options.ConventionalControllers + .Create(typeof(BookStoreApplicationModule).Assembly, opts => + { + opts.TypePredicate = type => { return true; }; + }); +}); +```` + +如果你不想将此类型公开为API控制器, 则可以在类型检查时返回`false`. + +## API Explorer + +API Explorer是可以由客户端获取API结构的服务. Swagger使用它为endpoint创建文档和test UI. + +默认情况下, HTTP API控制器会自动启用API Explorer, 可以使用`RemoteService`按类或方法的级别控制它. 例如: + +````csharp +[RemoteService(IsMetadataEnabled = false)] +public class PersonAppService : ApplicationService +{ + +} +```` + +禁用`IsMetadataEnabled`从而从API Explorer中隐藏此服务, 并且无法被发现. 但是它仍然可以被知道确切API路径/路由的客户端使用. \ No newline at end of file diff --git a/docs/zh-Hans/AspNetCore/Dynamic-CSharp-API-Clients.md b/docs/zh-Hans/AspNetCore/Dynamic-CSharp-API-Clients.md new file mode 100644 index 0000000000..f964ac9013 --- /dev/null +++ b/docs/zh-Hans/AspNetCore/Dynamic-CSharp-API-Clients.md @@ -0,0 +1,165 @@ +# 动态 C# API 客户端 + +ABP可以自动创建C# API 客户端代理来调用远程HTTP服务(REST APIS).通过这种方式,你不需要通过 `HttpClient` 或者其他低级的HTTP功能调用远程服务并获取数据. + +## 服务接口 + +你的service或controller需要实现一个在服务端和客户端共享的接口.因此,首先需要在一个共享的类库项目中定义一个服务接口.例如: + +````csharp +public interface IBookAppService : IApplicationService +{ + Task> GetListAsync(); +} +```` + +为了能自动被发现,你的接口需要实现`IRemoteService`接口.由于`IApplicationService`继承自`IRemoteService`接口.所以`IBookAppService`完全满足这个条件. + +在你的服务中实现这个类,你可以使用[auto API controller system](Auto-API-Controllers.md)将你的服务暴漏为一个REST API 端点. + +## 客户端代理生成 + +首先,将[Volo.Abp.Http.Client](https://www.nuget.org/packages/Volo.Abp.Http.Client) nuget包添加到你的客户端项目中: + +```` +Install-Package Volo.Abp.Http.Client +```` + +然后给你的模块添加`AbpHttpClientModule`依赖: + +````csharp +[DependsOn(typeof(AbpHttpClientModule))] //添加依赖 +public class MyClientAppModule : AbpModule +{ +} +```` + +现在,已经可以创建客户端代理了.例如: + +````csharp +[DependsOn( + typeof(AbpHttpClientModule), //用来创建客户端代理 + typeof(BookStoreApplicationModule) //包含应用服务接口 + )] +public class MyClientAppModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + //创建动态客户端代理 + context.Services.AddHttpClientProxies( + typeof(BookStoreApplicationModule).Assembly + ); + } +} +```` + +`AddHttpClientproxies`方法获得一个程序集,找到这个程序集中所有的服务接口,创建并注册代理类. + +### Endpoint配置 + +`appsettings.json`文件中的`RemoteServices`节点被用来设置默认的服务地址.下面是最简单的配置: + +```` +{ + "RemoteServices": { + "Default": { + "BaseUrl": "http://localhost:53929/" + } + } +} +```` + +查看下面的"RemoteServiceOptions"章节获取更多详细配置. + +## 使用 + +可以很直接地使用.只需要在你的客户端程序中注入服务接口: + +````csharp +public class MyService : ITransientDependency +{ + private readonly IBookAppService _bookService; + + public MyService(IBookAppService 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}"); + } + } +} +```` + +本例注入了上面定义的`IBookAppService`服务接口.当客户端调用服务方法的时候动态客户端代理就会创建一个HTTP调用. + +### IHttpClientProxy接口 + +你可以像上面那样注入`IBookAppService`来使用客户端代理,也可以注入`IHttpClientProxy`获取更多明确的用法.这种情况下你可以使用`IHttpClientProxy`接口的`Service`属性. + +## 配置 + +### RemoteServiceOptions + +默认情况下`RemoteServiceOptions`从`appsettings.json`获取.或者,你可以使用`Configure`方法来设置或重写它.如: + +````csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + context.Services.Configure(options => + { + options.RemoteServices.Default = + new RemoteServiceConfiguration("http://localhost:53929/"); + }); + + //... +} +```` + +### 多个远程服务端点 + +上面的例子已经配置了"Default"远程服务端点.你可能需要为不同的服务创建不同的端点.(就像在微服务方法中一样,每个微服务具有不同的端点).在这种情况下,你可以在你的配置文件中添加其他的端点: + +````json +{ + "RemoteServices": { + "Default": { + "BaseUrl": "http://localhost:53929/" + }, + "BookStore": { + "BaseUrl": "http://localhost:48392/" + } + } +} +```` + +`AddHttpClientProxies`方法有一个可选的参数来定义远程服务的名字: + +````csharp +context.Services.AddHttpClientProxies( + typeof(BookStoreApplicationModule).Assembly, + remoteServiceName: "BookStore" +); +```` + +`remoteServiceName`参数会匹配通过`RemoteServiceOptions`配置的服务端点.如果`BookStore`端点没有定义就会使用默认的`Default`端点. + +### 作为默认服务 + +当你为`IBookAppService`创建了一个服务代理,你可以直接注入`IBookAppService`来使用代理客户端(像上面章节中将的那样).你可以传递`asDefaultService:false`到`AddHttpClientProxies`方法来禁用此功能. + +````csharp +context.Services.AddHttpClientProxies( + typeof(BookStoreApplicationModule).Assembly, + asDefaultServices: false +); +```` + +如果你的程序中已经有一个服务的实现并且你不想用你的客户端代理重写或替换其他的实现,就需要使用`asDefaultServices:false` + +> 如果你禁用了`asDefaultService`,你只能使用`IHttpClientProxy`接口去使用客户端代理.(参见上面的相关章节). \ No newline at end of file diff --git a/docs/zh-Hans/Autofac-Integration.md b/docs/zh-Hans/Autofac-Integration.md new file mode 100644 index 0000000000..9b1d249e4e --- /dev/null +++ b/docs/zh-Hans/Autofac-Integration.md @@ -0,0 +1,84 @@ +# 集成 Autofac + +Autofac 是.Net世界中最常用的依赖注入框架之一. 相比.Net Core标准的依赖注入库, 它提供了更多高级特性, 比如动态代理和属性注入. + +## 安装 Autofac + +> 所有的启动模板和示例都已经集成了 Autofac. 所以, 多数时候你无需手动安装这个包. + +安装 [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) nuget 包到你的项目 (对于一个多项目应用程序, 建议安装到可执行项目或者Web项目中.) + +```` +Install-Package Volo.Abp.Autofac +```` + +然后为你的模块添加 `AbpAutofacModule` 依赖: + +```csharp +using Volo.Abp.Modularity; +using Volo.Abp.Autofac; + +namespace MyCompany.MyProject +{ + [DependsOn(typeof(AbpAutofacModule))] + public class MyModule : AbpModule + { + //... + } +} +``` + +最后, 配置 `AbpApplicationCreationOptions` 用 Autofac 替换默认的依赖注入服务. 根据应用程序类型, 情况有所不同. + +### ASP.NET Core 应用程序 + +如下所示, 在 **Startup.cs** 文件中调用 `UseAutofac()`: + +````csharp +public class Startup +{ + public IServiceProvider ConfigureServices(IServiceCollection services) + { + services.AddApplication(options => + { + //Integrate Autofac! + options.UseAutofac(); + }); + + return services.BuildServiceProviderFromFactory(); + } + + public void Configure(IApplicationBuilder app) + { + app.InitializeApplication(); + } +} +```` + +### 控制台应用程序 + +如下所示, 在 `AbpApplicationFactory.Create` 中用options调用 `UseAutofac()` 方法: + +````csharp +using System; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; + +namespace AbpConsoleDemo +{ + class Program + { + static void Main(string[] args) + { + using (var application = AbpApplicationFactory.Create(options => + { + options.UseAutofac(); //Autofac integration + })) + { + //... + } + } + } +} +```` + diff --git a/docs/zh-Hans/Event-Bus.md b/docs/zh-Hans/Event-Bus.md new file mode 100644 index 0000000000..0adb56101d --- /dev/null +++ b/docs/zh-Hans/Event-Bus.md @@ -0,0 +1,3 @@ +# Event Bus + + TODO \ No newline at end of file diff --git a/docs/zh-Hans/Microservice-Architecture.md b/docs/zh-Hans/Microservice-Architecture.md new file mode 100644 index 0000000000..166591e779 --- /dev/null +++ b/docs/zh-Hans/Microservice-Architecture.md @@ -0,0 +1,30 @@ +# 微服务架构 + +*"作为**面向服务架构**(SOA)的一个变体,微服务是一种将应用程序分解成**松散耦合服务**的新型架构风格. 通过**细粒度**的服务和**轻量级**的协议,微服务提供了更多的**模块化**,使应用程序更容易理解,开发,测试,并且更容易抵抗架构侵蚀. 它使小型团队能够**开发,部署和扩展**各自的服务,实现开发的**并行化**.它还允许通过**连续重构**形成单个服务的架构. 基于微服务架构可以实现**持续交付和部署**."* + +— [维基百科](https://zh.wikipedia.org/wiki/Microservices) + +## 介绍 + +ABP框架的主要目标之一就是提供**便捷的基础设施来创建微服务解决方案**. 我们做了以下工作: + +* 提供[模块系统](Module-Development-Basics.md),允许将应用程序拆分为模块,其中每个模块可以拥有自己的数据库,实体,服务,API,UI组件/页面....等. +* 提供[架构模型](Best-Practices/Module-Architecture.md)来开发模块,与微服务开发和部署兼容. +* 提供[最佳实践指南](Best-Practices/Index.md)制定模块开发标准. +* 提供基础设施来实现微服务中的[领域驱动设计](Domain-Driven-Design.md). +* 提供从应用程序服务[自动生成REST风格的API](AspNetCore/Auto-API-Controllers.md)的服务. +* 提供[自动创建C#API客户端](AspNetCore/Dynamic-CSharp-API-Clients.md)服务,以便从其他服务/应用程序使用你服务. +* 提供[分布式事件总线](Event-Bus.md)用于服务通信. +* 提供更多其他服务,使日常开发更加简便. + +## 在新应用程序中使用微服务 + +开始一个新解决方案建议**始终从单体开始**, 保持模块化,在单体成为问题时将其拆分为微服务.这使初期进度会很快,特别是如果你的团队人数不多,并且不想处理微服务架构带来的各种挑战. + +然而开发一个良好的模块化应用程序不是那么简单,因为很难像微服务那样**保持模块之间的隔离** (参阅 [Stefan Tilkov的文章](https://martinfowler.com/articles/dont-start-monolith.html)). 微服务架构会自然的让你开发隔离的服务,但是在模块化的单体应用程序中,模块很容易彼此紧密耦合并设计出**弱模块边界**和API约定. + +ABP可以帮助你,它提供了与**与微服务兼容的严格模块架构** 在这个架构中你的模块被分割成多个层/项目,在自己的VS解决方案中进行开发,该解决方案完成独立于其它模块. 这种方式开发的模块是一种天然的微服务,但是它可以很容易的插入到单体应用程序中. 请参阅**微服务优先的模块设计**的[模块开发最佳实践指南](Best-Practices/Index.md). 所有[标准的ABP模块](https://github.com/abpframework/abp/tree/master/modules)都是基于本指南开发的. 因此你可以将这些模块嵌入到单体解决方案中使用它们,也可以单独部署通过远程API调用. 它们可以共享一个数据库,也可以通过简单配置使用自己的数据库. + +## 微服务解决方案示例 + +[微服务解决方案示例](Samples/Microservice-Demo.md)演示了基于ABP框架的完整的微服务的解决方案. \ No newline at end of file diff --git a/docs/zh-Hans/Module-Development-Basics.md b/docs/zh-Hans/Module-Development-Basics.md index 044016e17a..9feaa8c7f9 100644 --- a/docs/zh-Hans/Module-Development-Basics.md +++ b/docs/zh-Hans/Module-Development-Basics.md @@ -125,3 +125,10 @@ public class BlogModule 你可以根据需要使用多个``DependsOn``属性或将多个模块类型传递给单个``DependsOn``属性. 依赖模块可能依赖于另一个模块,但你只需要定义直接依赖项.ABP在启动时会调查应用程序的依赖关系,并以正确的顺序初始化/关闭模块. + +## 框架模块 vs 应用程序模块 + +**模块分为两种类型.** 这两种类型并没有任何结构上的区别,只是按功能和用途分类: + +- **框架模块**: 这些是**框架的核心模块** 如缓存, 邮件, 主题, 安全, 序列化, 验证, EF Core集成, MongoDB集成... 等. 它们没有应用/业务功能,它们提供了日常开发经常用到的基础设施,集成和抽象. +- **应用程序模块**: 这些模块实现了 **特定的应用/业务功能** 像博客, 文档管理, 身份管理, 租房管理... 等等. 它们通过有自己的实体,服务,API和UI组件. 请参阅 [预构建的应用程序模块](Modules/Index.md). diff --git a/docs/zh-Hans/Modules/Docs.md b/docs/zh-Hans/Modules/Docs.md new file mode 100644 index 0000000000..cfe287082b --- /dev/null +++ b/docs/zh-Hans/Modules/Docs.md @@ -0,0 +1,467 @@ +# 文档模块 + +## 什么是文档模块? + +文档模块是ABP框架的一个应用程序模块. 它简化了软件文档的制作. 这个模块是开源免费的. + +### 集成 + +目前文档模块提供提供了两种支持的存储,Github与文件系统. + +### 托管 + +文档模块是一个应用程序模块,不提供任何托管的解决方案,你可以在本地或云上托管文档. + +### 版本 + +当你使用GitHub存储文档时,文档模块支持多版本. 如果你的文档具有多个版本, UI上有一个组合框,用于切换版本. 如果你选择使用文件系统存储文档, 那么它不支持多版本. + +ABP框架的[文档](https://abp.io/documents/)也是使用的此模块. + +> 文档模块遵循 [模块化架构最佳实践](../Best-Practices/Module-Architecture.md) 指南. + + + +## 安装 + +### 1- 下载 + +如果你没有现有的ABP项目, 这个步骤向你展示如何在[abp.io](https://cn.abp.io)创建一个新项目并添加文档模块. 如果你本地已经有了一个ABP项目, 那么你可以跳过这一步. + +打开 https://cn.abp.io/Templates. 输入项目名称为 `Acme.MyProject`, 选择 `ASP.NET Core Mvc Application` 和选择 `Entity Framework Core` 做为数据库提供者. + +请注意,本文档包含了 `Entity Framework Core` 提供者 不过你也可以选择 `MongoDB` 做为数据库提供者. + +![创建新项目](../images/docs-module_download-new-abp-project.png) + +### 2- 运行这个空项目 + +下载项目后, 解压压缩文档并且打开 `Acme.MyProject.sln`. 你可以看到这个解决方案包含了 `Application`, `Domain `, `EntityFrameworkCore` 和 `Web` 项目. 右键选择 `Acme.MyProject.Web` 项目**设置为启动项目**. + +![创建新项目](../images/docs-module_solution-explorer.png) + +数据库连接字符串位于`Acme.MyProject.Web`项目的`appsettings.json`中. 如果你有不同的数据库配置, 可以修改这个连接字符串. + +```json +{ + "ConnectionStrings": { + "Default": "Server=localhost;Database=MyProject;Trusted_Connection=True;MultipleActiveResultSets=true" + } +} +``` + +打开Visual Studio包管理控制台选择`src\Acme.MyProject.EntityFrameworkCore` 做为默认项目. 运行 `Update-Database` 命令创建数据库. 数据库`MyProject`将在数据库服务器中创建. + +现在一个空的ABP项目已经创建完成! 现在你可以运行项目并且查看网站. + +输入用户名 `admin` 密码 `1q2w3E*` 登录到网站. + +### 2- 引用文档模块包 + +文档模块包托管在Nuget上面. 需要有四个包安装到你的应用程序中. 每个包必须安装到相关的项目. + +* [Volo.Docs.Domain](https://www.nuget.org/packages/Volo.Docs.Domain/) 需要安装到 `Acme.MyProject.Domain` 项目. + + * 修改 `Acme.MyProject.Domain.csproj` 文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本. + + ```csharp + + ``` +* [Volo.Docs.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Docs.EntityFrameworkCore/) 需要安装到 `Acme.MyProject.EntityFrameworkCore` 项目. + + - 修改 `Acme.MyProject.EntityFrameworkCore.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本. + + ```csharp + + ``` +* [Volo.Docs.Application](https://www.nuget.org/packages/Volo.Docs.Application/) 需要安装到 `Acme.MyProject.Application` 项目. + + * 修改 `Acme.MyProject.Application.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本. + + ```csharp + + ``` +* [Volo.Docs.Web ](https://www.nuget.org/packages/Volo.Docs.Web/) 需要安装到 `Acme.MyProject.Web` 项目. + + - 修改 `Acme.MyProject.Web.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本. + + ```csharp + + ``` + + + +### 3- 添加模块添加 + +一个ABP模块必须声明 `[DependsOn]` attribute 如果它依赖于另一个模块. 每个模块都必须在相关的项目的`[DependsOn]`Attribute 中添加. + +* 打开 `MyProjectDomainModule.cs`并且添加 `typeof(DocsDomainModule)` 如下所示; + + ```csharp + [DependsOn( + typeof(DocsDomainModule), + typeof(AbpIdentityDomainModule), + typeof(AbpAuditingModule), + typeof(BackgroundJobsDomainModule), + typeof(AbpAuditLoggingDomainModule) + )] + public class MyProjectDomainModule : AbpModule + { + //... + } + ``` + +* 打开 `MyProjectEntityFrameworkCoreModule.cs`并且添加 `typeof(DocsEntityFrameworkCoreModule)` 如下所示; + + ```csharp + [DependsOn( + typeof(DocsEntityFrameworkCoreModule), + typeof(MyProjectDomainModule), + typeof(AbpIdentityEntityFrameworkCoreModule), + typeof(AbpPermissionManagementEntityFrameworkCoreModule), + typeof(AbpSettingManagementEntityFrameworkCoreModule), + typeof(AbpEntityFrameworkCoreSqlServerModule), + typeof(BackgroundJobsEntityFrameworkCoreModule), + typeof(AbpAuditLoggingEntityFrameworkCoreModule) + )] + public class MyProjectEntityFrameworkCoreModule : AbpModule + { + //... + } + ``` + + +* 打开 `MyProjectApplicationModule.cs`并且添加 `typeof(DocsApplicationModule)` 如下所示; + + ```csharp + [DependsOn( + typeof(DocsApplicationModule), + typeof(MyProjectDomainModule), + typeof(AbpIdentityApplicationModule))] + public class MyProjectApplicationModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.DefinitionProviders.Add(); + }); + + Configure(options => + { + options.AddProfile(); + }); + } + } + ``` + + +* 打开 `MyProjectWebModule.cs`并且添加 `typeof(DocsWebModule)` 如下所示; + + ```csharp + [DependsOn( + typeof(DocsWebModule), + typeof(MyProjectApplicationModule), + typeof(MyProjectEntityFrameworkCoreModule), + typeof(AbpAutofacModule), + typeof(AbpIdentityWebModule), + typeof(AbpAccountWebModule), + typeof(AbpAspNetCoreMvcUiBasicThemeModule) + )] + public class MyProjectWebModule : AbpModule + { + //... + } + ``` + + + +### 4- 数据库集成 + +#### 4.1- Entity Framework 集成 + +如果你选择了Entity Framework 做为数据库供应者,你需要在DbContext中配置文档模块. 做以下操作; + +- 打开 `MyProjectDbContext.cs` 并且添加 `modelBuilder.ConfigureDocs()` 到 `OnModelCreating()` 方法中 + + ```csharp + [ConnectionStringName("Default")] + public class MyProjectDbContext : AbpDbContext + { + public MyProjectDbContext(DbContextOptions options) + : base(options) + { + + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + //... + modelBuilder.ConfigureDocs(); + } + } + ``` + +* 打开 `Visual Studio` 的 `包管理控制台` 选择 `Acme.MyProject.EntityFrameworkCore` 做为默认项目. 然后编写以下命令为文档模块添加迁移. + + ```csharp + add-migration Added_Docs_Module + ``` + + 当命令执行成功后 , 你会看到`Acme.MyProject.EntityFrameworkCore\Migrations` 目录下有名为 `20181221111621_Added_Docs_Module` 的迁移文件. + + 现在更新数据库. 在 `Visual Studio` 的 `包管理控制台` 中执行以下代码. 要确认已 `Acme.MyProject.EntityFrameworkCore` 项目设置为默认项目. + + ```csharp + update-database + ``` + + 最后你可以查看数据库中创建的新表,例如你可以看到 `DocsProjects` 表已经添加到数据库中. + + +### 5- 链接文档模块 + +文档模块的默认路由是; + +``` +/Documents +``` + +添加文档模块的链接到你的应用程序菜单中; + +* 打开 `MyProjectMenuContributor.cs` 并且在 `ConfigureMainMenuAsync()` 方法方法中添加以下代码. + + ```csharp + context.Menu.Items.Add(new ApplicationMenuItem("MyProject.Docs", l["Menu:Docs"], "/Documents")); + ``` + + 最后 **MyProjectMenuContributor.cs** 有以下内容 + + ```csharp + private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) + { + var l = context.ServiceProvider.GetRequiredService>(); + + context.Menu.Items.Insert(0, new ApplicationMenuItem("MyProject.Home", l["Menu:Home"], "/")); + + context.Menu.Items.Add(new ApplicationMenuItem("MyProject.Docs", l["Menu:Docs"], "/Documents")); + } + ``` + +`Menu:Docs` 关键词是本地化的Key. 要本地化菜单文本, 打开`Acme.MyProject.Domain` 中的 `Localization\MyProject\zh-Hans.json`. 添加以下行. + +```json +"Menu:Docs": "文档" +``` + +最后 **zh-Hans.json** 有以下内容 + +```json +{ + "culture": "zh-Hans", + "texts": { + "Menu:Home": "首页", + "Welcome": "欢迎", + "LongWelcomeMessage": "欢迎来到该应用程序. 这是一个基于ABP框架的启动项目. 有关更多信息, 请访问 cn.abp.io.", + "Menu:Docs": "文档" + } +} +``` + +现在菜单中已经添加了文档模块项. 运行Web应用程序并且在浏览器中打开 `http://localhost:YOUR_PORT_NUMBER/documents` URL. + +你会看到一个警告; + +``` +There are no projects yet! +``` + +这个警告是正常的,因为我们还没有添加任何项目. + +### 6- 添加文档项目 + +在数据库中打开 `DocsProjects`, 并且插入包含以下字段的新记录; + +* **Name**: 在Web页面上文档的显示名称. +* **ShortName**: 在文档URL中使用的友好的简短URL名称. +* **Format**: 文档的格式 ( Markdown: `md`, HTML: `html`) +* **DefaultDocumentName**: 文档的初始页面. +* **NavigationDocumentName**: 导航菜单(索引)的文档. +* **MinimumVersion**: 显示文档的最低版本. 低于此的版本不会列出. +* **DocumentStoreType**: 文档的来源 ( GitHub:`GitHub`,文件系统`FileSystem`). +* **ExtraProperties**: 序列化的`JSON`, 它存储所选 `DocumentStoreType` 的特殊配置. +* **MainWebsiteUrl**: 用户单击文档模块页面Logo时跳转的URL.你只需设置为`/`即可链接到网站根地址. +* **LatestVersionBranchName**: 这是GitHub的配置.它是检索文档的分支名称.你可以将其设置为`master`. + +#### "GitHub" 项目的示例记录 + +你可以使用 [ABP Framework](https://github.com/abpframework/abp/) GitHub文档来配置Github文档存储. + +- Name: `ABP framework (GitHub)` + +- ShortName: `abp` + +- Format: `md` + +- DefaultDocumentName: `Index` + +- NavigationDocumentName: `docs-nav.json` + +- MinimumVersion: `` (no minimum version) + +- DocumentStoreType: `GitHub` + +- ExtraProperties: + + ```json + {"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/zh-Hans/","GitHubAccessToken":"***"} + ``` + + 注意 `GitHubAccessToken` 用 `***` 掩盖. 这是一个私人令牌,你必须从GitHub获取它. 请参阅 https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/ + +- MainWebsiteUrl: `/` + +- LatestVersionBranchName: `master` + +对于 `SQL` 数据库,你可以使用下面的 `T-SQL` 命令将指定的示例插入到 `DocsProjects` 表中: + +```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/zh-Hans/","GitHubAccessToken":"***"}', N'/', N'master') +``` + +请注意,`GitHubAccessToken` 被屏蔽了.它是一个私人令牌,你必须获得自己的令牌并替换 `***` 字符串. + +#### "FileSystem" 项目的示例记录 + +你可以使用 [ABP Framework](https://github.com/abpframework/abp/) GitHub文档来配置你的文件系统存储. + +- Name: `ABP framework (FileSystem)` + +- ShortName: `abp` + +- Format: `md` + +- DefaultDocumentName: `Index` + +- NavigationDocumentName: `docs-nav.json` + +- MinimumVersion: `` (no minimum version) + +- DocumentStoreType: `FileSystem` + +- ExtraProperties: + + ```json + {"Path":"C:\\Github\\abp\\docs\\zh-Hans"} + ``` + + 请注意 `Path` 必须使用本地docs目录替换. 你可以从https://github.com/abpframework/abp/tree/master/docs/zh-hans获取ABP Framework的文档并且复制到该目录 `C:\\Github\\abp\\docs\\zh-Hans` 使其正常工作. + +- MainWebsiteUrl: `/` + +- LatestVersionBranchName: `` + +对于 `SQL` 数据库,你可以使用下面的 `T-SQL` 命令将指定的示例插入到 `DocsProjects` 表中: + +```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\\zh-Hans"}', N'/', NULL) +``` + +添加上面的一个示例项目后运行该应用程序. 在菜单中你会看到`文档` 链接,点击菜单链接打开文档页面. + +到目前为止, 我们已经从abp.io网站创建了一个新的应用程序,并为Docs模块做好准备. + +### 7- 添加一个新文档 + +在示例项目记录中, 你可以看到 `Format` 被指定为 `md` 指的是 [Mark Down](https://en.wikipedia.org/wiki/Markdown). 你可以打开下面的链接查看语法; + +https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet + +ABP文档模块可以把MarkDown渲染为HTML. + +现在让我们看一下Markdown格式的示例文档. + +~~~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; } +} +``` +~~~ + +你可以使用 ABP Framework 的文档做为示例: + +[https://github.com/abpframework/abp/blob/master/docs/zh-Hans/](https://github.com/abpframework/abp/blob/master/docs/zh-Hans/) + +### 8- 创建文档导航 + +导航文档是文档页面的主菜单. 它位于页面的左侧,是一个`JSON` 文件. 请查看以下示例导航文档以了解结构. + +```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" + } + ] + } + ] + } + ] +} +``` + +上面的示例 `JSON` 文件将下面的导航菜单呈现为 `HTML` . + +![Navigation menu](../images/docs-module_download-sample-navigation-menu.png) + +最后,为您的项目添加了一个新的Docs模块, 该模块由GitHub提供. \ No newline at end of file diff --git a/docs/zh-Hans/Modules/Index.md b/docs/zh-Hans/Modules/Index.md new file mode 100644 index 0000000000..8e5edf35b6 --- /dev/null +++ b/docs/zh-Hans/Modules/Index.md @@ -0,0 +1,26 @@ +# 应用程序模块 + +ABP是一个 **模块化的应用程序框架** 由十多个 **nuget packages** 组成. 它提供了一个完整的基础设施来构建你自己的应用程序模块,这些模块包含实体,服务,数据库集成,API,UI组件等. + +**有两种类型的模块.** 它们没有任何结构上的差异,只是按照功能和目地分类: + +* [**框架模块**](https://github.com/abpframework/abp/tree/master/framework/src): 这些是 **框架的核心模块**,像缓存,邮件,主题,安全性,序列化,验证,Ef Core集成,MongoDB集成...等等. 它们没有应用程序/业务功能,但通过提供通用基础架构,集成和抽象会使你的日常开发更加容易. +* [**应用程序模块**](https://github.com/abpframework/abp/tree/master/modules): 这些模块是实现特定的应用程序/业务功能,像 博客, 文档管理, 身份管理, 租户管理... 等等. 它是通常有自己的实体,服务,API和UI组件. + +## 开源的应用程序模块 + +有一些由ABP社区开发和维护的 **开源免费** 的应用程序模块: + +* **Account**: 用于用户登录/注册应用程序. +* **Audit Logging**: 用于将审计日志持久化到数据库. +* **Background Jobs**: 用于在使用默认后台作业管理器时保存后台作业. +* **Blogging**: 用于创建精美的博客. ABP的[博客](https://abp.io/blog/abp/) 就使用了此模块. +* [**Docs**](Docs.md): 用于创建技术文档页面. ABP的[文档](https://abp.io/documents/) 就使用了此模块. +* **Identity**: 用于管理角色,用户和他们的权限. +* **Identity Server**: 集成了IdentityServer4. +* **Permission Management**: 用于保存权限. +* **Setting Management**: 用于保存设置. +* **Tenant Management**: 用于管理[多租户](../Multi-Tenancy.md)应用程序的租户. +* **Users**: 用于抽象用户, 因此其他模块可以依赖此模块而不是Identity模块. + +模块化文档正在编写中. 请参阅[这个仓库](https://github.com/abpframework/abp/tree/master/modules)获取所有模块的源代码. \ No newline at end of file diff --git a/docs/zh-Hans/Samples/Microservice-Demo.md b/docs/zh-Hans/Samples/Microservice-Demo.md new file mode 100644 index 0000000000..eeac6e0749 --- /dev/null +++ b/docs/zh-Hans/Samples/Microservice-Demo.md @@ -0,0 +1,40 @@ +# 微服务解决方案示例 + +*"作为**面向服务架构**(SOA)的一个变体,微服务是一种将应用程序分解成**松散耦合服务**的新型架构风格. 通过**细粒度**的服务和**轻量级**的协议,微服务提供了更多的**模块化**,使应用程序更容易理解,开发,测试,并且更容易抵抗架构侵蚀. 它使小型团队能够**开发,部署和扩展**各自的服务,实现开发的**并行化**.它还允许通过**连续重构**形成单个服务的架构. 基于微服务架构可以实现**持续交付和部署**."* + +— [维基百科](https://zh.wikipedia.org/wiki/Microservices) + +## 介绍 + +ABP框架的主要目标之一就是提供[便捷的基础设施来创建微服务解决方案](../Microservice-Architecture.md). + +此示例演示了一个简单而完整的微服务解决方案; + +* 拥有多个可独立可单独部署的**微服务**. +* 多个**Web应用程序**, 每一个都使用不同的API网关. +* 使用[Ocelot](https://github.com/ThreeMammals/Ocelot)库开发了多个**网关** / BFFs ([用于前端的后端](https://docs.microsoft.com/zh-cn/azure/architecture/patterns/backends-for-frontends)). +* 包含使用[IdentityServer](https://identityserver.io/)框架开发的 **身份认证服务**. 它也是一个带有UI的SSO(单点登陆)应用程序. +* 有**多个数据库**. 一些微服务有自己的数据库,也有一些服务/应用程序共享同一个数据库(以演示不同的用例). +* 有不同类型的数据库: **SQL Server** (与 **Entity Framework Core** ORM) 和 **MongoDB**. +* 有一个**控制台应用程序**使用身份验证展示使用服务最简单的方法. +* 使用[Redis](https://redis.io/)做**分布式缓存**. +* 使用[RabbitMQ](https://www.rabbitmq.com/)做服务间的**消息**传递. +* 使用[Kubernates](https://kubernetes.io/)**部署**和运行所有的服务和应用程序. + +下图显示了该系统: + +![microservice-sample-diagram](../images/microservice-sample-diagram.png) + +### 源码 + +你可以从[GitHub仓库](https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo)获取源码. + +### 状态 + +此示例仍处于开发阶段,尚未完成. + +## 微服务 + +### 身份认证服务 + +... \ No newline at end of file diff --git a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md index a9e333690f..34acc3f01f 100644 --- a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md +++ b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md @@ -238,7 +238,7 @@ namespace Acme.BookStore 你通常需要创建 **Controllers** 将应用服务暴露为 **HTTP API**.这样浏览器或第三方客户端可以通过AJAX的方式访问它们. -ABP可以 **自动地** 将应用服务转换成MVC API Controllers. +ABP可以 **自动地** (../../AspNetCore/Auto-API-Controllers.md)将应用服务转换成MVC API Controllers. #### Swagger UI diff --git a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md index 418c29a119..6b31e9ba84 100644 --- a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md +++ b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md @@ -1,6 +1,6 @@ -## ASP.NET Core MVC Tutorial - Part III +## ASP.NET Core MVC 教程 - 第三章 -### About this Tutorial +### 关于本教程 这是本教程所有章节中的第三章.下面是所有的章节: @@ -214,4 +214,4 @@ public async Task Should_Not_Create_A_Book_Without_Name() ### 测试 Web 页面 -TODO \ No newline at end of file +TODO diff --git a/docs/zh-Hans/Virtual-File-System.md b/docs/zh-Hans/Virtual-File-System.md index e25d7f61b4..05d8f59a85 100644 --- a/docs/zh-Hans/Virtual-File-System.md +++ b/docs/zh-Hans/Virtual-File-System.md @@ -109,7 +109,7 @@ public class MyService 假设你正在开发一个包含嵌入式JavaScript文件的模块. 当你更改文件时, 你必须重新编译项目, 重新启动应用程序并刷新浏览器页面以进行更改. 显然, 这是非常耗时和乏味的. -我们需要的是应用程序在开发时直接使用物理文件的能力, 让浏览器刷新时同步JavaScript文件的任何更改. `ReplaceEmbeddedByPyhsical` 方法使其成为可能. +我们需要的是应用程序在开发时直接使用物理文件的能力, 让浏览器刷新时同步JavaScript文件的任何更改. `ReplaceEmbeddedByPhysical` 方法使其成为可能. 下面的示例展示了应用程序依赖于包含嵌入文件的模块("MyModule"), 并且应用程序可以在开发过程中直接使用模块的源代码. @@ -125,8 +125,8 @@ public class MyWebAppModule : AbpModule { Configure(options => { - //ReplaceEmbeddedByPyhsical gets the root folder of the MyModule project - options.FileSets.ReplaceEmbeddedByPyhsical( + //ReplaceEmbeddedByPhysical gets the root folder of the MyModule project + options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, "..\\MyModuleProject") ); }); diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json index 362e6fbc65..d9ac2aea60 100644 --- a/docs/zh-Hans/docs-nav.json +++ b/docs/zh-Hans/docs-nav.json @@ -16,11 +16,11 @@ "text": "从空项目开始", "items": [ { - "text": "使用Console Application", + "text": "使用ASP.NET Core Web Application", "path": "Getting-Started-AspNetCore-Application.md" }, { - "text": "使用 ASP.NET Core Web Application", + "text": "使用Console Application", "path": "Getting-Started-Console-Application.md" } ] @@ -49,7 +49,8 @@ "path": "Dependency-Injection.md", "items": [ { - "text": "AutoFac 集成" + "text": "AutoFac 集成", + "path": "Autofac-Integration.md" } ] }, @@ -170,7 +171,8 @@ "text": "应用服务层", "items": [ { - "text": "应用服务" + "text": "应用服务", + "path": "Application-Services.md" }, { "text": "数据传输对象(DTO)" @@ -183,10 +185,20 @@ ] }, { - "text": "ASP.NET Core MVC", + "text": "ASP.NET Core", "items": [ { - "text": "API 版本控制" + "text": "API", + "items": [ + { + "text": "自动API控制器", + "path": "AspNetCore/Auto-API-Controllers.md" + }, + { + "text": "动态C# API客户端", + "path": "AspNetCore/Dynamic-CSharp-API-Clients.md" + } + ] }, { "text": "用户界面", @@ -243,6 +255,23 @@ } ] }, + { + "text": "示例", + "items": [ + { + "text": "微服务示例", + "path": "Samples/Microservice-Demo.md" + } + ] + }, + { + "text": "应用模块", + "path": "Modules/Index.md" + }, + { + "text": "微服务架构", + "path": "Microservice-Architecture.md" + }, { "text": "测试" }, @@ -251,4 +280,4 @@ "path": "Contribution/Index.md" } ] -} \ No newline at end of file +} diff --git a/docs/zh-Hans/images/bookstore-apis.png b/docs/zh-Hans/images/bookstore-apis.png new file mode 100644 index 0000000000..aedd79c7f1 Binary files /dev/null and b/docs/zh-Hans/images/bookstore-apis.png differ diff --git a/docs/zh-Hans/images/docs-module_download-new-abp-project.png b/docs/zh-Hans/images/docs-module_download-new-abp-project.png new file mode 100644 index 0000000000..0da3b7a67a Binary files /dev/null and b/docs/zh-Hans/images/docs-module_download-new-abp-project.png differ diff --git a/docs/zh-Hans/images/docs-module_download-sample-navigation-menu.png b/docs/zh-Hans/images/docs-module_download-sample-navigation-menu.png new file mode 100644 index 0000000000..9a1232f198 Binary files /dev/null and b/docs/zh-Hans/images/docs-module_download-sample-navigation-menu.png differ diff --git a/docs/zh-Hans/images/docs-module_solution-explorer.png b/docs/zh-Hans/images/docs-module_solution-explorer.png new file mode 100644 index 0000000000..cafc38f0b0 Binary files /dev/null and b/docs/zh-Hans/images/docs-module_solution-explorer.png differ diff --git a/docs/zh-Hans/images/microservice-sample-diagram.png b/docs/zh-Hans/images/microservice-sample-diagram.png new file mode 100644 index 0000000000..b1d9f6c66e Binary files /dev/null and b/docs/zh-Hans/images/microservice-sample-diagram.png differ diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index d6518a0af3..08104ef769 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -168,7 +168,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.MongoDB.Tests", "t EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EntityFrameworkCore.SqlServer", "src\Volo.Abp.EntityFrameworkCore.SqlServer\Volo.Abp.EntityFrameworkCore.SqlServer.csproj", "{6EABA98D-0B71-4ED7-A939-AFDA106D1151}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EventBus.RabbitMQ", "src\Volo.Abp.EventBus.Distributed.RabbitMQ\Volo.Abp.EventBus.RabbitMQ.csproj", "{468C3DCB-8C00-40E7-AE51-0738EAAB312A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EventBus.RabbitMQ", "src\Volo.Abp.EventBus.RabbitMQ\Volo.Abp.EventBus.RabbitMQ.csproj", "{468C3DCB-8C00-40E7-AE51-0738EAAB312A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic", "src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj", "{2F5EE6D9-511B-4998-BD62-0B9F03E02432}" EndProject @@ -212,7 +212,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EntityFrameworkCore.PostgreSql", "src\Volo.Abp.EntityFrameworkCore.PostgreSql\Volo.Abp.EntityFrameworkCore.PostgreSql.csproj", "{882E82F1-1A57-4BB9-B126-4CBF700C8F0C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Localization.Abstractions", "src\Volo.Abp.Localization.Abstractions\Volo.Abp.Localization.Abstractions.csproj", "{20513A4E-FAC7-4106-8976-5D79A3BDFED1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Localization.Abstractions", "src\Volo.Abp.Localization.Abstractions\Volo.Abp.Localization.Abstractions.csproj", "{20513A4E-FAC7-4106-8976-5D79A3BDFED1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Security.Tests", "test\Volo.Abp.Security.Tests\Volo.Abp.Security.Tests.csproj", "{7CE07034-7E02-4C78-B981-F1039412CA5E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Settings.Tests", "test\Volo.Abp.Settings.Tests\Volo.Abp.Settings.Tests.csproj", "{5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Http.Client.IdentityModel", "src\Volo.Abp.Http.Client.IdentityModel\Volo.Abp.Http.Client.IdentityModel.csproj", "{D211A446-38FA-4F97-9A95-1F004A0FFF69}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.IdentityModel", "src\Volo.Abp.IdentityModel\Volo.Abp.IdentityModel.csproj", "{64D99E19-EE25-465A-82E5-17B25F4C4E18}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.Client", "src\Volo.Abp.AspNetCore.Mvc.Client\Volo.Abp.AspNetCore.Mvc.Client.csproj", "{E803DDB8-81EA-454B-9A66-9C2941100B67}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.Contracts", "src\Volo.Abp.AspNetCore.Mvc.Contracts\Volo.Abp.AspNetCore.Mvc.Contracts.csproj", "{88F6D091-CA16-4B71-9499-8D5B8FA2E712}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -604,6 +616,30 @@ Global {20513A4E-FAC7-4106-8976-5D79A3BDFED1}.Debug|Any CPU.Build.0 = Debug|Any CPU {20513A4E-FAC7-4106-8976-5D79A3BDFED1}.Release|Any CPU.ActiveCfg = Release|Any CPU {20513A4E-FAC7-4106-8976-5D79A3BDFED1}.Release|Any CPU.Build.0 = Release|Any CPU + {7CE07034-7E02-4C78-B981-F1039412CA5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7CE07034-7E02-4C78-B981-F1039412CA5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7CE07034-7E02-4C78-B981-F1039412CA5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7CE07034-7E02-4C78-B981-F1039412CA5E}.Release|Any CPU.Build.0 = Release|Any CPU + {5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403}.Release|Any CPU.Build.0 = Release|Any CPU + {D211A446-38FA-4F97-9A95-1F004A0FFF69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D211A446-38FA-4F97-9A95-1F004A0FFF69}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D211A446-38FA-4F97-9A95-1F004A0FFF69}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D211A446-38FA-4F97-9A95-1F004A0FFF69}.Release|Any CPU.Build.0 = Release|Any CPU + {64D99E19-EE25-465A-82E5-17B25F4C4E18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64D99E19-EE25-465A-82E5-17B25F4C4E18}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64D99E19-EE25-465A-82E5-17B25F4C4E18}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64D99E19-EE25-465A-82E5-17B25F4C4E18}.Release|Any CPU.Build.0 = Release|Any CPU + {E803DDB8-81EA-454B-9A66-9C2941100B67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E803DDB8-81EA-454B-9A66-9C2941100B67}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E803DDB8-81EA-454B-9A66-9C2941100B67}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E803DDB8-81EA-454B-9A66-9C2941100B67}.Release|Any CPU.Build.0 = Release|Any CPU + {88F6D091-CA16-4B71-9499-8D5B8FA2E712}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {88F6D091-CA16-4B71-9499-8D5B8FA2E712}.Debug|Any CPU.Build.0 = Debug|Any CPU + {88F6D091-CA16-4B71-9499-8D5B8FA2E712}.Release|Any CPU.ActiveCfg = Release|Any CPU + {88F6D091-CA16-4B71-9499-8D5B8FA2E712}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -707,6 +743,12 @@ Global {77A621CF-9562-411B-A707-C7C02CC3B8FA} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {882E82F1-1A57-4BB9-B126-4CBF700C8F0C} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {20513A4E-FAC7-4106-8976-5D79A3BDFED1} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {7CE07034-7E02-4C78-B981-F1039412CA5E} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {5F3A2D1E-EA89-40A7-8D2F-FB4EB2092403} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {D211A446-38FA-4F97-9A95-1F004A0FFF69} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {64D99E19-EE25-465A-82E5-17B25F4C4E18} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {E803DDB8-81EA-454B-9A66-9C2941100B67} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {88F6D091-CA16-4B71-9499-8D5B8FA2E712} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/Volo.Abp.sln.DotSettings b/framework/Volo.Abp.sln.DotSettings index b8ca469cfe..b1de84b369 100644 --- a/framework/Volo.Abp.sln.DotSettings +++ b/framework/Volo.Abp.sln.DotSettings @@ -1,2 +1,8 @@  - SQL \ No newline at end of file + SQL + True + D:\Github\abp\common.DotSettings + ..\..\common.DotSettings + True + 1 + \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj index 42b81370fd..722b6033ed 100644 --- a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj @@ -19,7 +19,7 @@ - + diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs index 7f00a58069..7ba8766dd8 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs @@ -14,10 +14,10 @@ namespace Volo.Abp.AspNetCore.MultiTenancy { Configure(options => { - options.TenantResolvers.Add(new QueryStringTenantResolveContributer()); - options.TenantResolvers.Add(new RouteTenantResolveContributer()); - options.TenantResolvers.Add(new HeaderTenantResolveContributer()); - options.TenantResolvers.Add(new CookieTenantResolveContributer()); + options.TenantResolvers.Add(new QueryStringTenantResolveContributor()); + options.TenantResolvers.Add(new RouteTenantResolveContributor()); + options.TenantResolvers.Add(new HeaderTenantResolveContributor()); + options.TenantResolvers.Add(new CookieTenantResolveContributor()); }); } } diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributer.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributor.cs similarity index 81% rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributer.cs rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributor.cs index ebce890ea9..5b27a9d93c 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributer.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/CookieTenantResolveContributor.cs @@ -3,7 +3,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.AspNetCore.MultiTenancy { - public class CookieTenantResolveContributer : HttpTenantResolveContributerBase + public class CookieTenantResolveContributor : HttpTenantResolveContributorBase { protected override string GetTenantIdOrNameFromHttpContextOrNull(ITenantResolveContext context, HttpContext httpContext) { diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributer.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributor.cs similarity index 87% rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributer.cs rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributor.cs index 2894fcf0df..e342cb8f40 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributer.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributor.cs @@ -7,11 +7,11 @@ namespace Volo.Abp.AspNetCore.MultiTenancy { //TODO: Create a better domain format. We can accept regex for example. - public class DomainTenantResolveContributer : HttpTenantResolveContributerBase + public class DomainTenantResolveContributor : HttpTenantResolveContributorBase { private readonly string _domainFormat; - public DomainTenantResolveContributer(string domainFormat) + public DomainTenantResolveContributor(string domainFormat) { _domainFormat = domainFormat.RemovePreFix("http://", "https://"); } diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributer.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributor.cs similarity index 93% rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributer.cs rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributor.cs index 58acdc493c..3f5e93bd36 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributer.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolveContributor.cs @@ -7,7 +7,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.AspNetCore.MultiTenancy { - public class HeaderTenantResolveContributer : HttpTenantResolveContributerBase + public class HeaderTenantResolveContributor : HttpTenantResolveContributorBase { protected override string GetTenantIdOrNameFromHttpContextOrNull(ITenantResolveContext context, HttpContext httpContext) { @@ -36,7 +36,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy { context .ServiceProvider - .GetRequiredService>() + .GetRequiredService>() .LogWarning(text); } } diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs index 51bdc57323..d2971063a5 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs @@ -7,7 +7,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.AspNetCore.MultiTenancy { - public abstract class HttpTenantResolveContributerBase : ITenantResolveContributer + public abstract class HttpTenantResolveContributorBase : ITenantResolveContributor { public virtual void Resolve(ITenantResolveContext context) { @@ -24,7 +24,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy catch (Exception e) { context.ServiceProvider - .GetRequiredService>() + .GetRequiredService>() .LogWarning(e.ToString()); } } diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributer.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributor.cs similarity index 85% rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributer.cs rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributor.cs index 88bd3bcc0d..9899e2613e 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributer.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/QueryStringTenantResolveContributor.cs @@ -3,7 +3,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.AspNetCore.MultiTenancy { - public class QueryStringTenantResolveContributer : HttpTenantResolveContributerBase + public class QueryStringTenantResolveContributor : HttpTenantResolveContributorBase { protected override string GetTenantIdOrNameFromHttpContextOrNull(ITenantResolveContext context, HttpContext httpContext) { diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributer.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributor.cs similarity index 87% rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributer.cs rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributor.cs index 10d4f1ebe1..3be155c68d 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributer.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/RouteTenantResolveContributor.cs @@ -5,7 +5,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.AspNetCore.MultiTenancy { - public class RouteTenantResolveContributer : HttpTenantResolveContributerBase + public class RouteTenantResolveContributor : HttpTenantResolveContributorBase { protected override string GetTenantIdOrNameFromHttpContextOrNull(ITenantResolveContext context, HttpContext httpContext) { diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs index 8e6d3ae7ea..a162f1750e 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs @@ -8,8 +8,8 @@ namespace Volo.Abp.MultiTenancy public static void AddDomainTenantResolver(this TenantResolveOptions options, string domainFormat) { options.TenantResolvers.InsertAfter( - r => r is CurrentClaimsPrincipalTenantResolveContributer, - new DomainTenantResolveContributer(domainFormat) + r => r is CurrentClaimsPrincipalTenantResolveContributor, + new DomainTenantResolveContributor(domainFormat) ); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj new file mode 100644 index 0000000000..911782697b --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj @@ -0,0 +1,22 @@ + + + + + + netstandard2.0 + Volo.Abp.AspNetCore.Mvc.Client + Volo.Abp.AspNetCore.Mvc.Client + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + + + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs new file mode 100644 index 0000000000..3f1ed47435 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Caching; +using Volo.Abp.Http.Client; +using Volo.Abp.Modularity; + +namespace Volo.Abp.AspNetCore.Mvc.Client +{ + [DependsOn( + typeof(AbpHttpClientModule), + typeof(AbpAspNetCoreMvcContractsModule), + typeof(AbpCachingModule) + )] + public class AbpAspNetCoreMvcClientModule : AbpModule + { + public const string RemoteServiceName = "AbpMvcClient"; + + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddHttpClientProxies( + typeof(AbpAspNetCoreMvcContractsModule).Assembly, + RemoteServiceName, + asDefaultServices: false + ); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs new file mode 100644 index 0000000000..f7df64b257 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs @@ -0,0 +1,65 @@ +using System; +using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Distributed; +using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Client.DynamicProxying; +using Volo.Abp.Users; + +namespace Volo.Abp.AspNetCore.Mvc.Client +{ + public class CachedApplicationConfigurationClient : ICachedApplicationConfigurationClient, ITransientDependency + { + public IHttpContextAccessor HttpContextAccessor { get; set; } + + protected IHttpClientProxy Proxy { get; } + protected ICurrentUser CurrentUser { get; } + protected IDistributedCache Cache { get; } + + public CachedApplicationConfigurationClient( + IDistributedCache cache, + IHttpClientProxy proxy, + ICurrentUser currentUser, + IHttpContextAccessor httpContextAccessor) + { + Proxy = proxy; + CurrentUser = currentUser; + HttpContextAccessor = httpContextAccessor; + Cache = cache; + } + + public async Task GetAsync() + { + var cacheKey = CreateCacheKey(); + var httpContext = HttpContextAccessor?.HttpContext; + + if (httpContext != null && httpContext.Items[cacheKey] is ApplicationConfigurationDto configuration) + { + return configuration; + } + + configuration = await Cache.GetOrAddAsync( + CreateCacheKey(), + async () => await Proxy.Service.GetAsync(), + () => new DistributedCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(5) + } + ); + + if (httpContext != null) + { + httpContext.Items[cacheKey] = configuration; + } + + return configuration; + } + + protected virtual string CreateCacheKey() + { + return $"ApplicationConfiguration_{CurrentUser.Id?.ToString("N") ?? "Anonymous"}"; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/ICachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/ICachedApplicationConfigurationClient.cs new file mode 100644 index 0000000000..71d9d8cddf --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/ICachedApplicationConfigurationClient.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; + +namespace Volo.Abp.AspNetCore.Mvc.Client +{ + public interface ICachedApplicationConfigurationClient + { + Task GetAsync(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs new file mode 100644 index 0000000000..46e13bcc3d --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs @@ -0,0 +1,32 @@ +using System.Security.Claims; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.Mvc.Client +{ + public class RemotePermissionChecker : IPermissionChecker, ITransientDependency + { + protected ICachedApplicationConfigurationClient ConfigurationClient { get; } + + public RemotePermissionChecker(ICachedApplicationConfigurationClient configurationClient) + { + ConfigurationClient = configurationClient; + } + + public async Task CheckAsync(string name) + { + var configuration = await ConfigurationClient.GetAsync(); + + return new PermissionGrantInfo( + name, + configuration.Auth.GrantedPolicies.ContainsKey(name) + ); + } + + public Task CheckAsync(ClaimsPrincipal claimsPrincipal, string name) + { + return CheckAsync(name); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj new file mode 100644 index 0000000000..8141097dc6 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj @@ -0,0 +1,20 @@ + + + + + + netstandard2.0 + Volo.Abp.AspNetCore.Mvc.Contracts + Volo.Abp.AspNetCore.Mvc.Contracts + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcContractsModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcContractsModule.cs new file mode 100644 index 0000000000..54a7589dd4 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcContractsModule.cs @@ -0,0 +1,13 @@ +using Volo.Abp.Application; +using Volo.Abp.Modularity; + +namespace Volo.Abp.AspNetCore.Mvc +{ + [DependsOn( + typeof(AbpDddApplicationModule) + )] + public class AbpAspNetCoreMvcContractsModule : AbpModule + { + + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs similarity index 86% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs index 4981955ba0..39b3ca394b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationAuthConfigurationDto.cs @@ -1,7 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations { + [Serializable] public class ApplicationAuthConfigurationDto { public Dictionary Policies { get; set; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs similarity index 57% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs index d7aab53482..ecafcb3274 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs @@ -1,9 +1,14 @@ -namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations +using System; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations { + [Serializable] public class ApplicationConfigurationDto { public ApplicationLocalizationConfigurationDto Localization { get; set; } public ApplicationAuthConfigurationDto Auth { get; set; } + + public CurrentUserDto CurrentUser { get; set; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs similarity index 83% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs index 716061d507..05b5d8c7a6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs @@ -1,7 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations { + [Serializable] public class ApplicationLocalizationConfigurationDto { public Dictionary> Values { get; set; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs new file mode 100644 index 0000000000..702af56dba --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs @@ -0,0 +1,16 @@ +using System; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations +{ + [Serializable] + public class CurrentUserDto + { + public bool IsAuthenticated { get; set; } + + public Guid? Id { get; set; } + + public Guid? TenantId { get; set; } + + public string UserName { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IApplicationConfigurationBuilder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs similarity index 57% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IApplicationConfigurationBuilder.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs index 2b820f48c6..4c521b9efc 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IApplicationConfigurationBuilder.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs @@ -1,8 +1,9 @@ using System.Threading.Tasks; +using Volo.Abp.Application.Services; namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations { - public interface IApplicationConfigurationBuilder + public interface IAbpApplicationConfigurationAppService : IApplicationService { Task GetAsync(); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs new file mode 100644 index 0000000000..9f047c5b3c --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Mvc.Localization; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers +{ + public class AbpTagHelperLocalizer : IAbpTagHelperLocalizer + { + private readonly IStringLocalizerFactory _stringLocalizerFactory; + private readonly AbpMvcDataAnnotationsLocalizationOptions _options; + + public AbpTagHelperLocalizer(IOptions options, IStringLocalizerFactory stringLocalizerFactory) + { + _stringLocalizerFactory = stringLocalizerFactory; + _options = options.Value; + } + + public string GetLocalizedText(string text, ModelExplorer explorer) + { + var resourceType = GetResourceTypeFromModelExplorer(explorer); + var localizer = GetStringLocalizer(resourceType); + + return localizer == null ? text : localizer[text].Value; + } + + public IStringLocalizer GetLocalizer(ModelExplorer explorer) + { + var resourceType = GetResourceTypeFromModelExplorer(explorer); + return GetStringLocalizer(resourceType); + } + + public IStringLocalizer GetLocalizer(Assembly assembly) + { + var resourceType = _options.AssemblyResources.GetOrDefault(assembly); + return GetStringLocalizer(resourceType); + } + + public IStringLocalizer GetLocalizer(Type resourceType) + { + return GetStringLocalizer(resourceType); + } + + private IStringLocalizer GetStringLocalizer(Type resourceType) + { + return resourceType == null ? null : _stringLocalizerFactory.Create(resourceType); + } + + private Type GetResourceTypeFromModelExplorer(ModelExplorer explorer) + { + var assembly = explorer.Container.ModelType.Assembly; + return _options.AssemblyResources.GetOrDefault(assembly); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs index 332210271b..ce47163be0 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs +++ b/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()); + tagHelper.Init(context); + if (runAsync) { AsyncHelper.RunSync(() => tagHelper.ProcessAsync(innerContext, innerOutput)); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Alert/AbpAlertLinkTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Alert/AbpAlertLinkTagHelperService.cs index eed121566f..79372688c3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Alert/AbpAlertLinkTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Alert/AbpAlertLinkTagHelperService.cs @@ -8,6 +8,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Alert public override void Process(TagHelperContext context, TagHelperOutput output) { output.Attributes.AddClass("alert-link"); + output.Attributes.RemoveAll("abp-alert-link"); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupDirection.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupDirection.cs new file mode 100644 index 0000000000..53f3c3b6f9 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupDirection.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button +{ + public enum AbpButtonGroupDirection + { + Horizontal, + Vertical + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupSize.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupSize.cs new file mode 100644 index 0000000000..42635dd232 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupSize.cs @@ -0,0 +1,10 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button +{ + public enum AbpButtonGroupSize + { + Default, + Small, + Medium, + Large + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelper.cs new file mode 100644 index 0000000000..b1958fc8af --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelper.cs @@ -0,0 +1,15 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button +{ + public class AbpButtonGroupTagHelper : AbpTagHelper + { + public AbpButtonGroupDirection Direction { get; set; } = AbpButtonGroupDirection.Horizontal; + + public AbpButtonGroupSize Size { get; set; } = AbpButtonGroupSize.Default; + + public AbpButtonGroupTagHelper(AbpButtonGroupTagHelperService tagHelperService) + : base(tagHelperService) + { + + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelperService.cs new file mode 100644 index 0000000000..602e956e1e --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonGroupTagHelperService.cs @@ -0,0 +1,55 @@ +using System; +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 AbpButtonGroupTagHelperService : AbpTagHelperService + { + public override void Process(TagHelperContext context, TagHelperOutput output) + { + AddButtonGroupClass(context, output); + AddSizeClass(context, output); + AddAttributes(context, output); + } + + protected virtual void AddSizeClass(TagHelperContext context, TagHelperOutput output) + { + switch (TagHelper.Size) + { + case AbpButtonGroupSize.Default: + break; + case AbpButtonGroupSize.Small: + output.Attributes.AddClass("btn-group-sm"); + break; + case AbpButtonGroupSize.Medium: + output.Attributes.AddClass("btn-group-md"); + break; + case AbpButtonGroupSize.Large: + output.Attributes.AddClass("btn-group-lg"); + break; + } + } + + protected virtual void AddButtonGroupClass(TagHelperContext context, TagHelperOutput output) + { + switch (TagHelper.Direction) + { + case AbpButtonGroupDirection.Horizontal: + output.Attributes.AddClass("btn-group"); + break; + case AbpButtonGroupDirection.Vertical: + output.Attributes.AddClass("btn-group-vertical"); + break; + default: + output.Attributes.AddClass("btn-group"); + break; + } + } + + protected virtual void AddAttributes(TagHelperContext context, TagHelperOutput output) + { + output.Attributes.Add("role", "group"); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSize.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSize.cs index 65a0842d7b..dd07ff22bf 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSize.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSize.cs @@ -5,6 +5,10 @@ Default, Small, Medium, - Large + Large, + Block, + Block_Small, + Block_Medium, + Block_Large, } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSizeExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSizeExtensions.cs index 4231ac7ba6..408ba37573 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSizeExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonSizeExtensions.cs @@ -12,6 +12,14 @@ return "btn-md"; case AbpButtonSize.Large: 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: return ""; default: diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelper.cs index 1be9524800..56143ea059 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelper.cs +++ b/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 bool? Block { get; set; } = false; - public string BusyText { get; set; } public string Text { get; set; } public string Icon { get; set; } + public bool? Disabled { get; set; } + public FontIconType IconType { get; set; } = FontIconType.FontAwesome; public AbpButtonTagHelper(AbpButtonTagHelperService service) @@ -26,3 +26,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button } } } + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelperServiceBase.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelperServiceBase.cs index 3d8a3bf4e8..419aff7c08 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonTagHelperServiceBase.cs +++ b/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); AddIcon(context, output); AddText(context, output); + AddDisabled(context, output); } protected virtual void NormalizeTagMode(TagHelperContext context, TagHelperOutput output) @@ -26,18 +27,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button if (TagHelper.ButtonType != AbpButtonType.Default) { - output.Attributes.AddClass("btn-" + TagHelper.ButtonType.ToString().ToLowerInvariant()); + output.Attributes.AddClass("btn-" + TagHelper.ButtonType.ToString().ToLowerInvariant().Replace("_","-")); } if (TagHelper.Size != AbpButtonSize.Default) { output.Attributes.AddClass(TagHelper.Size.ToClassName()); } - - if (TagHelper.Block ?? false) - { - output.Attributes.AddClass("btn-block"); - } } protected virtual void AddIcon(TagHelperContext context, TagHelperOutput output) @@ -70,5 +66,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button output.Content.AppendHtml($"{TagHelper.Text}"); } + + protected virtual void AddDisabled(TagHelperContext context, TagHelperOutput output) + { + if (TagHelper.Disabled ?? false) + { + output.Attributes.Add("disabled", "disabled"); + } + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelper.cs new file mode 100644 index 0000000000..7c716b88f8 --- /dev/null +++ b/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 + { + public AbpButtonToolbarTagHelper(AbpButtonToolbarTagHelperService tagHelperService) + : base(tagHelperService) + { + + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonToolbarTagHelperService.cs new file mode 100644 index 0000000000..87b378e559 --- /dev/null +++ b/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 + { + public override void Process(TagHelperContext context, TagHelperOutput output) + { + output.Attributes.AddClass("btn-toolbar"); + output.Attributes.Add("role","toolbar"); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonType.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonType.cs index 07d7e0a50b..a6ced457e0 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonType.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpButtonType.cs @@ -11,6 +11,14 @@ Info, Light, Dark, + Outline_Primary, + Outline_Secondary, + Outline_Success, + Outline_Danger, + Outline_Warning, + Outline_Info, + Outline_Light, + Outline_Dark, Link } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpLinkButtonTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpLinkButtonTagHelper.cs index 8e517ea493..9a553a1be5 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/AbpLinkButtonTagHelper.cs +++ b/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 bool? Block { get; set; } = false; - public string Text { get; set; } public string Icon { get; set; } + public bool? Disabled { get; set; } + public FontIconType IconType { get; } = FontIconType.FontAwesome; public AbpLinkButtonTagHelper(AbpLinkButtonTagHelperService service) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/IButtonTagHelperBase.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/IButtonTagHelperBase.cs index dbe20def2a..ee88c4d294 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/IButtonTagHelperBase.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Button/IButtonTagHelperBase.cs @@ -6,12 +6,12 @@ AbpButtonSize Size { get; } - bool? Block { get;} - string Text { get; } string Icon { get; } + bool? Disabled { get; } + FontIconType IconType { get; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelper.cs new file mode 100644 index 0000000000..5e95e8bf87 --- /dev/null +++ b/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 + { + public AbpCardBackgroundType Background { get; set; } = AbpCardBackgroundType.Default; + + public AbpCardBackgroundTagHelper(AbpCardBackgroundTagHelperService tagHelperService) + : base(tagHelperService) + { + + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundTagHelperService.cs new file mode 100644 index 0000000000..248d737648 --- /dev/null +++ b/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 + { + 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()); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundType.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBackgroundType.cs new file mode 100644 index 0000000000..2eb9732ce8 --- /dev/null +++ b/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, + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBorderColorType.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardBorderColorType.cs new file mode 100644 index 0000000000..0f5ccc3363 --- /dev/null +++ b/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, + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelper.cs new file mode 100644 index 0000000000..44b8588576 --- /dev/null +++ b/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 + { + public AbpCardFooterTagHelper(AbpCardFooterTagHelperService tagHelperService) + : base(tagHelperService) + { + + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardFooterTagHelperService.cs new file mode 100644 index 0000000000..2a127a495b --- /dev/null +++ b/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 + { + public override void Process(TagHelperContext context, TagHelperOutput output) + { + output.Attributes.AddClass("card-footer"); + output.TagName = "div"; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardImageTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardImageTagHelper.cs index 6bafed3376..4a173968d0 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardImageTagHelper.cs +++ b/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 { [HtmlTargetElement("img", Attributes = "abp-card-image", TagStructure = TagStructure.WithoutEndTag)] + [HtmlTargetElement("abp-image", Attributes = "abp-card-image", TagStructure = TagStructure.WithoutEndTag)] public class AbpCardImageTagHelper : AbpTagHelper { [HtmlAttributeName("abp-card-image")] diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelper.cs index 4dcf439e01..c186e8857c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelper.cs @@ -2,6 +2,8 @@ { public class AbpCardTagHelper : AbpTagHelper { + public AbpCardBorderColorType Border { get; set; } = AbpCardBorderColorType.Default; + public AbpCardTagHelper(AbpCardTagHelperService tagHelperService) : base(tagHelperService) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelperService.cs index 4eb0c286f8..29a462797d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTagHelperService.cs +++ b/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.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()); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelper.cs new file mode 100644 index 0000000000..f9787b1f18 --- /dev/null +++ b/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 + { + public AbpCardTextColorType TextColor { get; set; } = AbpCardTextColorType.Default; + + public AbpCardTextColorTagHelper(AbpCardTextColorTagHelperService tagHelperService) + : base(tagHelperService) + { + + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorTagHelperService.cs new file mode 100644 index 0000000000..36484a33f8 --- /dev/null +++ b/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 + { + 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()); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorType.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Card/AbpCardTextColorType.cs new file mode 100644 index 0000000000..eb415945b0 --- /dev/null +++ b/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 + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs index 749218cab0..ffba80fb6f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs @@ -127,7 +127,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel { if (string.IsNullOrWhiteSpace(TagHelper.Id)) { - TagHelper.Id = Guid.NewGuid().ToString("N"); + TagHelper.Id = "C" + Guid.NewGuid().ToString("N"); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs index fabdb36452..1f9f57c567 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs @@ -59,7 +59,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse { if (string.IsNullOrWhiteSpace(TagHelper.Id)) { - TagHelper.Id = Guid.NewGuid().ToString("N"); + TagHelper.Id = "A" + Guid.NewGuid().ToString("N"); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs index 1d0a9234fd..20e62604a9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs @@ -55,7 +55,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse { if (string.IsNullOrWhiteSpace(TagHelper.Id)) { - TagHelper.Id = Guid.NewGuid().ToString("N"); + TagHelper.Id = "A" + Guid.NewGuid().ToString("N"); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelper.cs index 0d4aecab31..a50907addb 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelper.cs @@ -4,6 +4,8 @@ { public string Id { get; set; } + public bool? Multi { get; set; } + public bool? Show { get; set; } public AbpCollapseBodyTagHelper(AbpCollapseBodyTagHelperService tagHelperService) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs index 56b04df63d..10e49b92a7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs +++ b/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"); } - var innerContent = (await output.GetChildContentAsync()).GetContent(); - - var body = GetBody(context, output, innerContent); + if (TagHelper.Multi ?? false) + { + 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) - { - return "
    " + innerContent + "
    "; + output.Content.SetHtmlContent(innerContent); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelper.cs index 2e6da81cf0..6b8fc8c30b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelper.cs +++ b/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 { + + [HtmlTargetElement("abp-button", Attributes = "abp-collapse-id")] + [HtmlTargetElement("a", Attributes = "abp-collapse-id")] public class AbpCollapseButtonTagHelper : AbpTagHelper { - public AbpButtonType ButonType { get; set; } = AbpButtonType.Default; - + [HtmlAttributeName("abp-collapse-id")] public string BodyId { get; set; } public AbpCollapseButtonTagHelper(AbpCollapseButtonTagHelperService tagHelperService) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelperService.cs index c2221035c1..6b7d74b866 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseButtonTagHelperService.cs +++ b/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) { - output.TagName = "button"; - output.Attributes.AddClass("btn"); - output.Attributes.Add("data-toggle","collapse"); - output.Attributes.Add("aria-expanded","false"); - output.Attributes.Add("type","button"); - output.Attributes.Add("data-target", "#" +TagHelper.BodyId); + + + AddCommonAttributes(context, output); + + if (output.TagName == "abp-button" || output.TagName == "button") + { + 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); + } + 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); } - + } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs index 60a34a71f1..8b01781602 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs +++ b/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.Attributes.RemoveAll("type"); buttonTag.Attributes.Add("roles", "button"); + buttonTag.Attributes.Add("href", "#"); if (TagHelper.NavLink??false) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelper.cs new file mode 100644 index 0000000000..4c5e82fac7 --- /dev/null +++ b/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 + { + public AbpDropdownItemTextTagHelper(AbpDropdownItemTextTagHelperService tagHelperService) + : base(tagHelperService) + { + + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownItemTextTagHelperService.cs new file mode 100644 index 0000000000..8cd84eade6 --- /dev/null +++ b/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 + { + public override void Process(TagHelperContext context, TagHelperOutput output) + { + output.Attributes.AddClass("dropdown-item-text"); + output.TagName = "span"; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs index a6c5c80c06..141d995fd7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs @@ -18,6 +18,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form public bool? SubmitButton { get; set; } + public bool? RequiredSymbols { get; set; } = true; + #region MvcFormTagHelperAttiributes private const string ActionAttributeName = "asp-action"; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs index 3d7504f72d..fa3ec9cce6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs @@ -192,6 +192,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form var abpInputTagHelper = _serviceProvider.GetRequiredService(); abpInputTagHelper.AspFor = model; abpInputTagHelper.ViewContext = TagHelper.ViewContext; + abpInputTagHelper.DisplayRequiredSymbol = TagHelper.RequiredSymbols ?? true; RenderTagHelper(new TagHelperAttributeList(), context, abpInputTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormControlSize.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormControlSize.cs new file mode 100644 index 0000000000..79070b559e --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpFormControlSize.cs @@ -0,0 +1,10 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form +{ + public enum AbpFormControlSize + { + Default, + Small, + Medium, + Large + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs index de93ff4b1d..0c5ac5dd22 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs @@ -10,14 +10,22 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form public string Label { get; set; } + [HtmlAttributeName("info")] + public string InfoText { get; set; } + [HtmlAttributeName("disabled")] public bool IsDisabled { get; set; } = false; [HtmlAttributeName("readonly")] - public bool IsReadonly { get; set; } = false; + public bool? IsReadonly { get; set; } = false; public bool AutoFocus { get; set; } + public AbpFormControlSize Size { get; set; } = AbpFormControlSize.Default; + + [HtmlAttributeNotBound] + public bool DisplayRequiredSymbol { get; set; } = true; + [HtmlAttributeNotBound] [ViewContext] public ViewContext ViewContext { get; set; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index b5abe780ae..bc48d7b1d8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Mvc.TagHelpers; @@ -12,11 +13,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { private readonly IHtmlGenerator _generator; private readonly HtmlEncoder _encoder; + private readonly IAbpTagHelperLocalizer _tagHelperLocalizer; - public AbpInputTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder) + public AbpInputTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IAbpTagHelperLocalizer tagHelperLocalizer) { _generator = generator; _encoder = encoder; + _tagHelperLocalizer = tagHelperLocalizer; } public override void Process(TagHelperContext context, TagHelperOutput output) @@ -43,6 +46,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form output.TagName = "div"; LeaveOnlyGroupAttributes(context, output); output.Attributes.AddClass(isCheckbox ? "form-check" : "form-group"); + output.Attributes.AddClass(isCheckbox ? "mb-2" : ""); output.Content.SetHtmlContent(output.Content.GetContent() + innerHtml); } } @@ -50,17 +54,18 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual string GetFormInputGroupAsHtml(TagHelperContext context, TagHelperOutput output, out bool isCheckbox) { var inputTag = GetInputTagHelperOutput(context, output, out isCheckbox); + var inputHtml = RenderTagHelperOutput(inputTag, _encoder); var label = GetLabelAsHtml(context, output, inputTag, isCheckbox); - + var info = GetInfoAsHtml(context, output, inputTag, isCheckbox); 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) { - if (inputTag.Attributes.Any(a => a.Name.ToLowerInvariant() == "type" && a.Value.ToString().ToLowerInvariant() == "hidden")) + if (IsOutputHidden(inputTag)) { return ""; } @@ -76,14 +81,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form 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 ? - inputHtml + Environment.NewLine + label : - label + Environment.NewLine + inputHtml; + inputHtml + label : + label + inputHtml; - return Environment.NewLine + innerContent + Environment.NewLine + - Environment.NewLine + validation + Environment.NewLine; + return innerContent + infoHtml + validation; } protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml, bool isCheckbox) @@ -121,14 +125,28 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form ConvertToTextAreaIfTextArea(inputTagHelperOutput); AddDisabledAttribute(inputTagHelperOutput); - AddReadOnlyAttribute(inputTagHelperOutput); AddAutoFocusAttribute(inputTagHelperOutput); 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; } + private void AddFormControlClass(TagHelperContext context, TagHelperOutput output, bool isCheckbox, TagHelperOutput inputTagHelperOutput) + { + var className = "form-control"; + + if (isCheckbox) + { + className = "form-check-input"; + } + + inputTagHelperOutput.Attributes.AddClass(className + " " + GetSize(context, output)); + } + protected virtual void AddAutoFocusAttribute(TagHelperOutput inputTagHelperOutput) { if (TagHelper.AutoFocus && !inputTagHelperOutput.Attributes.ContainsName("data-auto-focus")) @@ -139,26 +157,56 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput) { - if (inputTagHelperOutput.Attributes.ContainsName("disabled")) + if (inputTagHelperOutput.Attributes.ContainsName("disabled") == false && + (TagHelper.IsDisabled || GetAttribute(TagHelper.AspFor.ModelExplorer) != null)) + { + inputTagHelperOutput.Attributes.Add("disabled", ""); + } + } + + protected virtual void AddReadOnlyAttribute(TagHelperOutput inputTagHelperOutput) + { + if (inputTagHelperOutput.Attributes.ContainsName("readonly") == false && + (TagHelper.IsReadonly != false || GetAttribute(TagHelper.AspFor.ModelExplorer) != null)) + { + inputTagHelperOutput.Attributes.Add("readonly", ""); + } + } + + protected virtual void AddPlaceholderAttribute(TagHelperOutput inputTagHelperOutput) + { + if (inputTagHelperOutput.Attributes.ContainsName("placeholder")) { return; } - else if (TagHelper.IsDisabled || GetAttribute(TagHelper.AspFor.ModelExplorer) != null) + + var attribute = GetAttribute(TagHelper.AspFor.ModelExplorer); + + if (attribute != null) { - inputTagHelperOutput.Attributes.Add("disabled", ""); + var placeholderLocalized = _tagHelperLocalizer.GetLocalizedText(attribute.Value, TagHelper.AspFor.ModelExplorer); + + inputTagHelperOutput.Attributes.Add("placeholder", placeholderLocalized); } } - protected virtual void AddReadOnlyAttribute(TagHelperOutput inputTagHelperOutput) + protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput) { - if (inputTagHelperOutput.Attributes.ContainsName("readonly")) + if (GetAttribute(TagHelper.AspFor.ModelExplorer) == null) { return; } - else if (TagHelper.IsReadonly || GetAttribute(TagHelper.AspFor.ModelExplorer) != null) + + var idAttr = inputTagHelperOutput.Attributes.FirstOrDefault(a => a.Name == "id"); + + if (idAttr == null) { - inputTagHelperOutput.Attributes.Add("readonly", ""); + return; } + + var infoText = _tagHelperLocalizer.GetLocalizedText(idAttr.Value + "InfoText", TagHelper.AspFor.ModelExplorer); + + inputTagHelperOutput.Attributes.Add("aria-describedby", infoText); } protected virtual bool IsInputCheckbox(TagHelperContext context, TagHelperOutput output, TagHelperAttributeList attributes) @@ -168,21 +216,70 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual string GetLabelAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox) { - if (inputTag.Attributes.Any(a => a.Name.ToLowerInvariant() == "type" && a.Value.ToString().ToLowerInvariant() == "hidden")) + if (IsOutputHidden(inputTag)) { return ""; } if (string.IsNullOrEmpty(TagHelper.Label)) { - return GetLabelAsHtmlUsingTagHelper(context, output, isCheckbox); + return GetLabelAsHtmlUsingTagHelper(context, output, isCheckbox) + GetRequiredSymbol(context, output, inputTag); } var checkboxClass = isCheckbox ? "class=\"form-check-label\" " : ""; return ""; + "" + GetRequiredSymbol(context, output, inputTag); + } + + protected virtual string GetRequiredSymbol(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag) + { + if (!TagHelper.DisplayRequiredSymbol) + { + return ""; + } + + return GetAttribute(TagHelper.AspFor.ModelExplorer) != null ? " * ":""; + } + + protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox) + { + if (IsOutputHidden(inputTag)) + { + return ""; + } + + if (isCheckbox) + { + return ""; + } + + var text = ""; + + if (!string.IsNullOrEmpty(TagHelper.InfoText)) + { + text = TagHelper.InfoText; + } + else + { + var infoAttribute = GetAttribute(TagHelper.AspFor.ModelExplorer); + if (infoAttribute != null) + { + text = infoAttribute.Text; + } + else + { + return ""; + } + } + + var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id"); + var localizedText = _tagHelperLocalizer.GetLocalizedText(text, TagHelper.AspFor.ModelExplorer); + + return "" + + localizedText + + ""; } protected virtual string GetLabelAsHtmlUsingTagHelper(TagHelperContext context, TagHelperOutput output, bool isCheckbox) @@ -254,5 +351,32 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form output.Attributes.Add(newAttritube); } } + + protected virtual string GetSize(TagHelperContext context, TagHelperOutput output) + { + var attribute = GetAttribute(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 ""; + } + + protected virtual bool IsOutputHidden(TagHelperOutput inputTag) + { + return inputTag.Attributes.Any(a => a.Name.ToLowerInvariant() == "type" && a.Value.ToString().ToLowerInvariant() == "hidden"); + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs index d3635a4753..c299826a07 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelper.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using JetBrains.Annotations; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs index 13b3d29cf7..2968085781 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs @@ -6,20 +6,28 @@ using System.Text; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Localization; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { public class AbpRadioInputTagHelperService : AbpTagHelperService { + private readonly IAbpTagHelperLocalizer _tagHelperLocalizer; + + public AbpRadioInputTagHelperService(IAbpTagHelperLocalizer tagHelperLocalizer) + { + _tagHelperLocalizer = tagHelperLocalizer; + } + public override void Process(TagHelperContext context, TagHelperOutput output) { var selectItems = GetSelectItems(context,output); + SetSelectedValue(context, output, selectItems); var order = GetInputOrder(TagHelper.AspFor.ModelExplorer); var html = GetHtml(context, output, selectItems); - AddGroupToFormGroupContents(context, TagHelper.AspFor.Name, html, order, out var surpress); if (surpress) @@ -60,33 +68,59 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual List GetSelectItems(TagHelperContext context, TagHelperOutput output) { - var selectItems = TagHelper.AspItems?.ToList(); + if (TagHelper.AspItems != null) + { + return TagHelper.AspItems.ToList(); + } - if (TagHelper.AspItems == null && - !GetSelectItemsIfProvidedByEnum(context, output, TagHelper.AspFor.ModelExplorer, out selectItems) && - !GetSelectItemsIfProvidedFromAttribute(context, output, TagHelper.AspFor.ModelExplorer, out selectItems)) + if (TagHelper.AspFor.ModelExplorer.Metadata.IsEnum) { - throw new Exception("No items provided for select attribute."); + return GetSelectItemsFromEnum(context, output, TagHelper.AspFor.ModelExplorer); } - SetSelectedValue(context, output, selectItems); + var selectItemsAttribute = GetAttribute(TagHelper.AspFor.ModelExplorer); + if (selectItemsAttribute != null) + { + return GetSelectItemsFromAttribute(selectItemsAttribute, TagHelper.AspFor.ModelExplorer); + } + + throw new Exception("No items provided for select attribute."); + } + + protected virtual List GetSelectItemsFromEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer) + { + var localizer = _tagHelperLocalizer.GetLocalizer(explorer); + + var selectItems = explorer.Metadata.IsEnum ? explorer.ModelType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static) + .Select((t, i) => new SelectListItem { Value = i.ToString(), Text = GetLocalizedPropertyName(localizer, explorer.ModelType, t.Name) }).ToList() : null; return selectItems; } - protected virtual bool GetSelectItemsIfProvidedByEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List selectItems) + protected virtual string GetLocalizedPropertyName(IStringLocalizer localizer, Type enumType, string propertyName) { - 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; + if (localizer == null) + { + return propertyName; + } + + var localizedString = localizer[enumType.Name + "." + propertyName]; - return selectItems != null; + return !localizedString.ResourceNotFound ? localizedString.Value : localizer[propertyName].Value; } - protected virtual bool GetSelectItemsIfProvidedFromAttribute(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List selectItems) + protected virtual List GetSelectItemsFromAttribute( + SelectItems selectItemsAttribute, + ModelExplorer explorer) { - selectItems = GetAttribute(explorer)?.GetItems(explorer)?.ToList(); + var selectItems = selectItemsAttribute.GetItems(explorer)?.ToList(); + + if (selectItems == null) + { + return new List(); + } - return selectItems != null; + return selectItems; } protected virtual void SetSelectedValue(TagHelperContext context, TagHelperOutput output, List selectItems) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpReadonlyInputType.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpReadonlyInputType.cs new file mode 100644 index 0000000000..415abf2ef7 --- /dev/null +++ b/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 + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs index 889fe4208d..f8cdd35a7e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs @@ -13,6 +13,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form public IEnumerable AspItems { get; set; } + public AbpFormControlSize Size { get; set; } = AbpFormControlSize.Default; + + [HtmlAttributeName("info")] + public string InfoText { get; set; } + + [HtmlAttributeNotBound] + public bool DisplayRequiredSymbol { get; set; } = true; + [HtmlAttributeNotBound] [ViewContext] public ViewContext ViewContext { get; set; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs index 8607348fff..2df060e2e5 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; using System.Text.Encodings.Web; @@ -7,6 +8,7 @@ using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.TagHelpers; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form @@ -15,11 +17,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { private readonly IHtmlGenerator _generator; private readonly HtmlEncoder _encoder; + private readonly IAbpTagHelperLocalizer _tagHelperLocalizer; - public AbpSelectTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder) + public AbpSelectTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IAbpTagHelperLocalizer tagHelperLocalizer) { _generator = generator; _encoder = encoder; + _tagHelperLocalizer = tagHelperLocalizer; } public override void Process(TagHelperContext context, TagHelperOutput output) @@ -37,6 +41,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form else { output.TagName = "div"; + LeaveOnlyGroupAttributes(context, output); output.Attributes.AddClass("form-group"); output.TagMode = TagMode.StartTagAndEndTag; output.Content.SetHtmlContent(innerHtml); @@ -48,8 +53,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form var selectTag = GetSelectTag(context, output); var selectAsHtml = RenderTagHelperOutput(selectTag, _encoder); 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) @@ -59,21 +66,21 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual TagHelperOutput GetSelectTag(TagHelperContext context, TagHelperOutput output) { - var selectItems = GetSelectItems(context, output); - var selectTagHelper = new SelectTagHelper(_generator) { For = TagHelper.AspFor, - Items = selectItems, + Items = GetSelectItems(context, output), 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"); - AddDisabledAttribute(inputTagHelperOutput); + selectTagHelperOutput.Attributes.AddClass("form-control"); + selectTagHelperOutput.Attributes.AddClass(GetSize(context, output)); + AddDisabledAttribute(selectTagHelperOutput); + AddInfoTextId(selectTagHelperOutput); - return inputTagHelperOutput; + return selectTagHelperOutput; } protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput) @@ -88,76 +95,128 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual List GetSelectItems(TagHelperContext context, TagHelperOutput output) { - var selectItems = TagHelper.AspItems?.ToList(); + if (TagHelper.AspItems != null) + { + return TagHelper.AspItems.ToList(); + } - if (TagHelper.AspItems == null && - !GetSelectItemsIfProvidedByEnum(context, output, TagHelper.AspFor.ModelExplorer, out selectItems) && - !GetSelectItemsIfProvidedFromAttribute(context, output, TagHelper.AspFor.ModelExplorer, out selectItems)) + if (TagHelper.AspFor.ModelExplorer.Metadata.IsEnum) { - throw new Exception("No items provided for select attribute."); + return GetSelectItemsFromEnum(context, output, TagHelper.AspFor.ModelExplorer); } - SetSelectedValue(context, output, selectItems); + var selectItemsAttribute = GetAttribute(TagHelper.AspFor.ModelExplorer); + if (selectItemsAttribute != null) + { + return GetSelectItemsFromAttribute(selectItemsAttribute, TagHelper.AspFor.ModelExplorer); + } - return selectItems; + throw new Exception("No items provided for select attribute."); } protected virtual string GetLabelAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput selectTag) { if (!string.IsNullOrEmpty(TagHelper.Label)) { - return ""; + return "" + GetRequiredSymbol(context, output); } - return GetLabelAsHtmlUsingTagHelper(context, output); + return GetLabelAsHtmlUsingTagHelper(context, output) + GetRequiredSymbol(context, output); } - protected virtual bool GetSelectItemsIfProvidedByEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List selectItems) + + protected virtual string GetRequiredSymbol(TagHelperContext context, TagHelperOutput output) { - 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; + if (!TagHelper.DisplayRequiredSymbol) + { + return ""; + } - return selectItems != null; + return GetAttribute(TagHelper.AspFor.ModelExplorer) != null ? " * " : ""; } - protected virtual bool GetSelectItemsIfProvidedFromAttribute(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer, out List selectItems) + protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput) { - selectItems = GetAttribute(explorer)?.GetItems(explorer)?.ToList(); + if (GetAttribute(TagHelper.AspFor.ModelExplorer) == null) + { + return; + } - return selectItems != null; - } + var idAttr = inputTagHelperOutput.Attributes.FirstOrDefault(a => a.Name == "id"); - protected virtual void SetSelectedValue(TagHelperContext context, TagHelperOutput output, List selectItems) - { - if (!selectItems.Any(si => si.Selected)) + if (idAttr == null) { - var selectedValue = GetSelectedValue(context, output); + return; + } - var itemToBeSelected = selectItems.FirstOrDefault(si => si.Value.ToString() == selectedValue); + var infoText = _tagHelperLocalizer.GetLocalizedText(idAttr.Value + "InfoText", TagHelper.AspFor.ModelExplorer); - if (itemToBeSelected != null) + inputTagHelperOutput.Attributes.Add("aria-describedby", infoText); + } + + protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag) + { + var text = ""; + + if (!string.IsNullOrEmpty(TagHelper.InfoText)) + { + text = TagHelper.InfoText; + } + else + { + var infoAttribute = GetAttribute(TagHelper.AspFor.ModelExplorer); + if (infoAttribute != null) + { + text = infoAttribute.Text; + } + else { - itemToBeSelected.Selected = true; + return ""; } } + + var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id"); + var localizedText = _tagHelperLocalizer.GetLocalizedText(text, TagHelper.AspFor.ModelExplorer); + + return "" + + localizedText + + ""; } - protected virtual string GetSelectedValue(TagHelperContext context, TagHelperOutput output) + protected virtual List GetSelectItemsFromEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer) { - var modelExplorer = TagHelper.AspFor.ModelExplorer; + var localizer = _tagHelperLocalizer.GetLocalizer(explorer); - if (modelExplorer.Metadata.IsEnum) - { - var baseType = modelExplorer.Model?.GetType().GetEnumUnderlyingType(); + var selectItems = explorer.Metadata.IsEnum ? explorer.ModelType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static) + .Select((t, i) => new SelectListItem { Value = i.ToString(), Text = GetLocalizedPropertyName(localizer, explorer.ModelType, t.Name) }).ToList() : null; - if (baseType == null) { return null; } + return selectItems; + } - return Convert.ChangeType(modelExplorer.Model, baseType)?.ToString() ?? ""; + protected virtual string GetLocalizedPropertyName(IStringLocalizer localizer, Type enumType, string propertyName) + { + if (localizer == null) + { + return propertyName; } - else + + var localizedString = localizer[enumType.Name + "." + propertyName]; + + return !localizedString.ResourceNotFound ? localizedString.Value : localizer[propertyName].Value; + } + + protected virtual List GetSelectItemsFromAttribute( + SelectItems selectItemsAttribute, + ModelExplorer explorer) + { + var selectItems = selectItemsAttribute.GetItems(explorer)?.ToList(); + + if (selectItems == null) { - return modelExplorer.Model?.ToString(); + return new List(); } + + return selectItems; } protected virtual string GetLabelAsHtmlUsingTagHelper(TagHelperContext context, TagHelperOutput output) @@ -170,5 +229,70 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form return RenderTagHelper(new TagHelperAttributeList(), context, labelTagHelper, _encoder, "label", TagMode.StartTagAndEndTag, true); } + + protected virtual string GetValidationAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag) + { + var validationMessageTagHelper = new ValidationMessageTagHelper(_generator) + { + For = TagHelper.AspFor, + ViewContext = TagHelper.ViewContext + }; + + var attributeList = new TagHelperAttributeList { { "class", "text-danger" } }; + + return RenderTagHelper(attributeList, context, validationMessageTagHelper, _encoder, "span", TagMode.StartTagAndEndTag, true); + } + + protected virtual string GetSize(TagHelperContext context, TagHelperOutput output) + { + var attribute = GetAttribute(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 ""; + } + + protected virtual TagHelperAttributeList GetInputAttributes(TagHelperContext context, TagHelperOutput output) + { + var groupPrefix = "group-"; + + var tagHelperAttributes = output.Attributes.Where(a => !a.Name.StartsWith(groupPrefix)).ToList(); + var attrList = new TagHelperAttributeList(); + + foreach (var tagHelperAttribute in tagHelperAttributes) + { + attrList.Add(tagHelperAttribute); + } + + 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); + } + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisabledInput.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisabledInput.cs index f43754cc22..6ef18e1d57 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisabledInput.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DisabledInput.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/FormControlSize.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/FormControlSize.cs new file mode 100644 index 0000000000..f85775f156 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/FormControlSize.cs @@ -0,0 +1,15 @@ +using System; + +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; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputInfoText.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputInfoText.cs new file mode 100644 index 0000000000..004ab7dc64 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/InputInfoText.cs @@ -0,0 +1,15 @@ +using System; + +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; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/Placeholder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/Placeholder.cs new file mode 100644 index 0000000000..829301021b --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/Placeholder.cs @@ -0,0 +1,15 @@ +using System; + +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; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs index 6cef8594b3..f22c3d53da 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/ReadOnlyInput.cs @@ -1,15 +1,19 @@ 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 ReadOnlyInput : Attribute { + public bool PlainText { get; set; } + public ReadOnlyInput() { } + + public ReadOnlyInput(bool plainText) + { + PlainText = plainText; + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/TextArea.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/TextArea.cs index fc8ce1016a..7c5a0c0724 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/TextArea.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/TextArea.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelper.cs deleted file mode 100644 index fdd6b973a4..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelper.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid -{ - public class AbpColBreakTagHelper : AbpTagHelper - { - public AbpColBreakTagHelper(AbpColBreakTagHelperService tagHelperService) - : base(tagHelperService) - { - - } - } -} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelper.cs new file mode 100644 index 0000000000..492a16ff21 --- /dev/null +++ b/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 + { + public AbpColumnBreakerTagHelper(AbpColumnBreakerTagHelperService tagHelperService) + : base(tagHelperService) + { + + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelperService.cs similarity index 82% rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelperService.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnBreakerTagHelperService.cs index b483f275b2..f6190f2332 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColBreakTagHelperService.cs +++ b/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 { - public class AbpColBreakTagHelperService : AbpTagHelperService + public class AbpColumnBreakerTagHelperService : AbpTagHelperService { public override void Process(TagHelperContext context, TagHelperOutput output) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs index 900b72fe25..ead3367ac7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs @@ -6,6 +6,8 @@ public HorizontalAlign HAlign { get; set; } = HorizontalAlign.Default; + public bool? Gutters { get; set; } = true; + public AbpRowTagHelper(AbpRowTagHelperService tagHelperService) : base(tagHelperService) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs index 12609600d7..ecbe5db97e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs +++ b/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); ProcessHorizontalAlign(output); + ProcessGutters(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()); } + + protected virtual void ProcessGutters(TagHelperOutput output) + { + if (TagHelper.Gutters ?? true) + { + return; + } + + output.Attributes.AddClass("no-gutters"); + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/IAbpTagHelperLocalizer.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/IAbpTagHelperLocalizer.cs new file mode 100644 index 0000000000..8351e47082 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/IAbpTagHelperLocalizer.cs @@ -0,0 +1,19 @@ +using System; +using System.Reflection; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.Extensions.Localization; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers +{ + public interface IAbpTagHelperLocalizer : ITransientDependency + { + string GetLocalizedText(string text, ModelExplorer explorer); + + IStringLocalizer GetLocalizer(ModelExplorer explorer); + + IStringLocalizer GetLocalizer(Assembly assembly); + + IStringLocalizer GetLocalizer(Type resourceType); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImagePosition.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImagePosition.cs deleted file mode 100644 index 4a2f1cb622..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImagePosition.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Image -{ - public enum AbpImagePosition - { - Default, - Right, - Left, - Center - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelper.cs deleted file mode 100644 index afc36f660c..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelper.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Image -{ - public class AbpImageTagHelper : AbpTagHelper - { - 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) - { - - } - } -} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelperService.cs deleted file mode 100644 index c03eee480e..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Image/AbpImageTagHelperService.cs +++ /dev/null @@ -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 - { - 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("
    "); - output.PostElement.SetHtmlContent("
    "); - } - } - - 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); - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelper.cs index 5524f221ff..aa61832ab9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelper.cs @@ -4,6 +4,8 @@ { public AbpModalSize Size { get; set; } = AbpModalSize.Default; + public bool? Centered { get; set; } = false; + public AbpModalTagHelper(AbpModalTagHelperService tagHelperService) : base(tagHelperService) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs index 23453df1d0..8106db4661 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs +++ b/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"); + if (TagHelper.Centered ?? false) + { + classNames.Append(" "); + classNames.Append("modal-dialog-centered"); + } + if (TagHelper.Size != AbpModalSize.Default) { classNames.Append(" "); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelper.cs index e7655c6073..40f25951fe 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelper.cs @@ -2,8 +2,6 @@ { public class AbpNavItemTagHelper : AbpTagHelper { - public bool? Active { get; set; } - public bool? Dropdown { get; set; } public AbpNavItemTagHelper(AbpNavItemTagHelperService tagHelperService) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelperService.cs index b4e8575ac8..ced733272c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavItemTagHelperService.cs +++ b/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"); SetDropdownClass(context, output); - SetActiveClass(context, 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"); } } - - protected virtual void SetActiveClass(TagHelperContext context, TagHelperOutput output) - { - if (TagHelper.Active ?? false) - { - output.Attributes.AddClass("active"); - } - } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelper.cs index 7809adc98b..1a534b5efb 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelper.cs +++ b/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? Disabled { get; set; } - - public string Href { get; set; } public AbpNavLinkTagHelper(AbpNavLinkTagHelperService tagHelperService) : base(tagHelperService) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelperService.cs index 48f4867662..75f4285530 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavLinkTagHelperService.cs +++ b/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.TagMode = TagMode.StartTagAndEndTag; SetClasses(context, output); - - if (!string.IsNullOrWhiteSpace(TagHelper.Href)) - { - output.Attributes.Add("href", TagHelper.Href); - } } protected virtual void SetClasses(TagHelperContext context, TagHelperOutput output) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavbarToggleTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavbarToggleTagHelperService.cs index 400769a992..1b53894ac2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavbarToggleTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Nav/AbpNavbarToggleTagHelperService.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Nav { if (string.IsNullOrWhiteSpace(TagHelper.Id)) { - TagHelper.Id = Guid.NewGuid().ToString("N"); + TagHelper.Id = "N" + Guid.NewGuid().ToString("N"); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs index 6fda6ccd63..e3293cddca 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs @@ -13,13 +13,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination { private readonly IHtmlGenerator _generator; private readonly HtmlEncoder _encoder; - private readonly IStringLocalizer _localizer; + private readonly IAbpTagHelperLocalizer _tagHelperLocalizer; - public AbpPaginationTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IStringLocalizer localizer) + public AbpPaginationTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IAbpTagHelperLocalizer tagHelperLocalizer) { _generator = generator; _encoder = encoder; - _localizer = localizer; + _tagHelperLocalizer = tagHelperLocalizer; } public override void Process(TagHelperContext context, TagHelperOutput output) @@ -117,11 +117,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination protected virtual string RenderAnchorTagHelperLinkHtml(TagHelperContext context, TagHelperOutput output, string currentPage, string localizationKey) { + var localizer = _tagHelperLocalizer.GetLocalizer(typeof(AbpUiResource)); + var anchorTagHelper = GetAnchorTagHelper(currentPage, out var attributeList); var tagHelperOutput = GetInnerTagHelper(attributeList, context, anchorTagHelper, "a", TagMode.StartTagAndEndTag); - tagHelperOutput.Content.SetHtmlContent(_localizer[localizationKey]); + tagHelperOutput.Content.SetHtmlContent(localizer[localizationKey]); var renderedHtml = RenderTagHelperOutput(tagHelperOutput, _encoder); @@ -150,15 +152,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination protected virtual string GetOpeningTags(TagHelperContext context, TagHelperOutput output) { + var localizer = _tagHelperLocalizer.GetLocalizer(typeof(AbpUiResource)); + var pagerInfo = (TagHelper.ShowInfo ?? false) ? - "
    " + _localizer["PagerInfo", TagHelper.Model.ShowingFrom, TagHelper.Model.ShowingTo, TagHelper.Model.TotalItemsCount] + "
    \r\n" + "
    " + localizer["PagerInfo", TagHelper.Model.ShowingFrom, TagHelper.Model.ShowingTo, TagHelper.Model.TotalItemsCount] + "
    \r\n" : ""; return pagerInfo + "
    \r\n" + "
    -

    # Form with Button Example

    +

    Order Attribute Example

    - -
    -
    Posted Values:
    -
    - Name: @Model.PersonInput.Name
    - Surname: @Model.PersonInput.Surname
    - City: @Model.PersonInput.City
    - Phone.Name: @Model.PersonInput.Phone.Name
    - Phone.Number: @Model.PersonInput.Phone.Number
    - Day: @Model.PersonInput.Day.ToString("yyyy-MM-dd")
    - Country: @Model.PersonInput.Country
    - IsActive: @Model.PersonInput.IsActive
    -
    +
    -
    -<abp-dynamic-form abp-model="Model.PersonInput" submit-button="true"/>
    -
    + + +
    
    +public class DynamicFormsModel : PageModel
    +    {
    +        public OrderExampleModel MyOrderExampleModel { get; set; }
    +
    +        public void OnGet()
    +        {
    +            MyOrderExampleModel = new OrderExampleModel();
    +        }
    +
    +        public class OrderExampleModel
    +        {
    +            [DisplayOrder(10005)]
    +            public string Surname{ get; set; }
    +
    +            //Default 10000
    +            public string EmailAddress { get; set; }
    +
    +            [DisplayOrder(10003)]
    +            public string Name { get; set; }
    +
    +            [DisplayOrder(9999)]
    +            public string City { get; set; }
    +        }
    +    }
    +
    +
    + +
    
    +    <abp-dynamic-form abp-model="Model.MyOrderExampleModel"/>
    +
    +
    + +
    
    +<form method="post">
    +    <div class="form-group">
    +        <label for="MyOrderExampleModel_City">City</label>
    +        <input type="text" id="MyOrderExampleModel_City" name="MyOrderExampleModel.City" value="" class="form-control ">
    +        <span class="text-danger field-validation-valid" data-valmsg-for="MyOrderExampleModel.City" data-valmsg-replace="true"></span>
    +    </div>
    +    <div class="form-group">
    +        <label for="MyOrderExampleModel_EmailAddress">EmailAddress</label>
    +        <input type="text" id="MyOrderExampleModel_EmailAddress" name="MyOrderExampleModel.EmailAddress" value="" class="form-control ">
    +        <span class="text-danger field-validation-valid" data-valmsg-for="MyOrderExampleModel.EmailAddress" data-valmsg-replace="true"></span>
    +    </div>
    +    <div class="form-group">
    +        <label for="MyOrderExampleModel_Name">Name</label>
    +        <input type="text" id="MyOrderExampleModel_Name" name="MyOrderExampleModel.Name" value="" class="form-control ">
    +        <span class="text-danger field-validation-valid" data-valmsg-for="MyOrderExampleModel.Name" data-valmsg-replace="true"></span>
    +    </div>
    +    <div class="form-group">
    +        <label for="MyOrderExampleModel_Surname">Surname</label>
    +        <input type="text" id="MyOrderExampleModel_Surname" name="MyOrderExampleModel.Surname" value="" class="form-control ">
    +        <span class="text-danger field-validation-valid" data-valmsg-for="MyOrderExampleModel.Surname" data-valmsg-replace="true"></span>
    +    </div>
    +    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8Kbwu8pRBWJCh6KUtTDoAuQICDXiCEgWpOHc7uIzSQ2dKiezdDkWplt2D8XLsCX39Z8B_GnplHrAfZgZ5GkNZN-tkEgKlMtyjoWv9MADyYb2MmWw-LuW8wfUXI9YSza5lo_8P03Vff4NxmrV3boG0xQ">
    +</form>
    +
    +
    +
    -

    # Non-dynamic Form

    +

    Attribute Examples

    -
    - - - - - - - - - - - -
    -
    Posted Values:
    -
    - Name: @Model.PersonInput.Name
    - Surname: @Model.PersonInput.Surname
    - Age: @Model.PersonInput.Age
    - Is Active: @Model.PersonInput.IsActive
    - Day: @Model.PersonInput.Day
    - City: @Model.PersonInput.City
    - Country: @Model.PersonInput.Country
    - Phone.Number: @Model.PersonInput.Phone.Number
    - Phone.Name: @Model.PersonInput.Phone.Name
    -
    +
    -
    +        
    +            
    +                
    
    +public class DynamicFormsModel : PageModel
    +    {
    +        public AttributeExamplesModel MyAttributeExamplesModel { get; set; }
    +
    +        public void OnGet()
    +        {
    +            MyAttributeExamplesModel = new AttributeExamplesModel();
    +            MyAttributeExamplesModel.DisabledInput = "Disabled Input";
    +            MyAttributeExamplesModel.ReadonlyInput = "Readonly Input";
    +            MyAttributeExamplesModel.LargeInput = "Large Input";
    +            MyAttributeExamplesModel.SmallInput = "Small Input";
    +        }
    +
    +        public class AttributeExamplesModel
    +        {
    +            [HiddenInput]
    +            public string HiddenInput { get; set; }
    +
    +            [DisabledInput]
    +            public string DisabledInput{ get; set; }
    +
    +            [ReadOnlyInput]
    +            public string ReadonlyInput { get; set; }
    +
    +            [FormControlSize(AbpFormControlSize.Large)]
    +            public string LargeInput { get; set; }
    +
    +            [FormControlSize(AbpFormControlSize.Small)]
    +            public string SmallInput { get; set; }
    +        }
    +    }
    +
    +
    + +
    
    +    <abp-dynamic-form abp-model="Model.MyAttributeExamplesModel"/>
    +
    +
    + +
    
     <form method="post">
    -    <abp-input asp-for="Model.PersonInput.Name" />
    -    <abp-input asp-for="Model.PersonInput.Surname" />
    -    <abp-input asp-for="Model.PersonInput.Age" />
    -    <abp-input asp-for="Model.PersonInput.IsActive" />
    -    <abp-input asp-for="Model.PersonInput.Day" />
    -    <abp-select asp-for="Model.PersonInput.City" />
    -    <abp-select asp-for="Model.PersonInput.Country" />
    -    <abp-input asp-for="Model.PersonInput.Phone.Number" />
    -    <abp-input asp-for="Model.PersonInput.Phone.Name" />
    -    <abp-button type="submit" button-type="Primary" text="Submit" />
    +    <div class="form-group">
    +        <input type="hidden" id="MyAttributeExamplesModel_HiddenInput" name="MyAttributeExamplesModel.HiddenInput" value="" class="form-control ">
    +    </div>
    +    <div class="form-group">
    +        <label for="MyAttributeExamplesModel_DisabledInput">DisabledInput</label>
    +        <input type="text" id="MyAttributeExamplesModel_DisabledInput" name="MyAttributeExamplesModel.DisabledInput" value="Disabled Input" disabled="" class="form-control ">
    +        <span class="text-danger field-validation-valid" data-valmsg-for="MyAttributeExamplesModel.DisabledInput" data-valmsg-replace="true"></span>
    +    </div>
    +    <div class="form-group">
    +        <label for="MyAttributeExamplesModel_ReadonlyInput">ReadonlyInput</label>
    +        <input type="text" id="MyAttributeExamplesModel_ReadonlyInput" name="MyAttributeExamplesModel.ReadonlyInput" value="Readonly Input" class="form-control " readonly="">
    +        <span class="text-danger field-validation-valid" data-valmsg-for="MyAttributeExamplesModel.ReadonlyInput" data-valmsg-replace="true"></span>
    +    </div>
    +    <div class="form-group">
    +        <label for="MyAttributeExamplesModel_LargeInput">LargeInput</label>
    +        <input type="text" id="MyAttributeExamplesModel_LargeInput" name="MyAttributeExamplesModel.LargeInput" value="Large Input" class="form-control form-control-lg">
    +        <span class="text-danger field-validation-valid" data-valmsg-for="MyAttributeExamplesModel.LargeInput" data-valmsg-replace="true"></span>
    +    </div>
    +    <div class="form-group">
    +        <label for="MyAttributeExamplesModel_SmallInput">SmallInput</label>
    +        <input type="text" id="MyAttributeExamplesModel_SmallInput" name="MyAttributeExamplesModel.SmallInput" value="Small Input" class="form-control form-control-sm">
    +        <span class="text-danger field-validation-valid" data-valmsg-for="MyAttributeExamplesModel.SmallInput" data-valmsg-replace="true"></span>
    +    </div>
    +    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8Kbwu8pRBWJCh6KUtTDoAuSUKLRRJ2JhujqxKEZfzYxIDYQtg1knqOh9zyG1DjaXRnoavm1876JtbePc4El_6aDqwMUKuXshQhXIunS_hrygXH5v-Tm6Qw_zL-JEJnSmd6Q4EwCtwDBwGX0in4-swG8">
     </form>
    -
    +
    + +
    -

    # Form Content Placement

    +

    Form Content Placement

    - + +
    + First Div!
    + --------- +
    + - + +
    + ---------
    + Second Div! +
    -
    -
    Posted Values:
    -
    - Name: @Model.PersonInput.Name
    - Name: @Model.PersonInput.Surname
    - City: @Model.PersonInput.City
    - Phone.Name: @Model.PersonInput.Phone.Name
    - Phone.Number: @Model.PersonInput.Phone.Number
    - Day: @Model.PersonInput.Day.ToString("yyyy-MM-dd")
    - Country: @Model.PersonInput.Country
    - IsActive: @Model.PersonInput.IsActive
    -
    -
    -<abp-dynamic-form abp-model="@Model.PersonInput">
    -     <abp-form-content />
    -     <abp-button button-type="Primary" type="submit" text="submit" />
    +        
    +            
    +                
    
    +public class DynamicFormsModel : PageModel
    +    {
    +        public FormContentExampleModel MyFormContentExampleModel { get; set; }
    +
    +        public void OnGet()
    +        {
    +            MyFormContentExampleModel = new FormContentExampleModel();
    +        }
    +
    +        public class FormContentExampleModel
    +        {
    +            public string SampleInput { get; set; }
    +        }
    +    }
    +
    +
    + +
    
    +<abp-dynamic-form abp-model="@@Model.MyFormContentExampleModel">
    +    <div>
    +        First Div!  <br />
    +        ---------
    +    </div>
    +
    +    <abp-form-content />
    +
    +    <div>
    +        ---------  <br />
    +        Second Div!
    +    </div>
     </abp-dynamic-form>
    -
    -
    -
    + + + +
    
    +<form method="post">
    +    <div>
    +        First Div!  <br />
    +        ---------
    +    </div>
    +
    +    <div>
    +        <div class="form-group">
    +            <label for="MyFormContentExampleModel_SampleInput">SampleInput</label>
    +            <input type="text" id="MyFormContentExampleModel_SampleInput" name="MyFormContentExampleModel.SampleInput" value="" class="form-control ">
    +            <span class="text-danger field-validation-valid" data-valmsg-for="MyFormContentExampleModel.SampleInput" data-valmsg-replace="true"></span>
    +        </div>
    +    </div>
     
    +    <div>
    +        ---------  <br />
    +        Second Div!
    +    </div>
    +    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8Kbwu8pRBWJCh6KUtTDoAuS4l6PkkSnj6NFFQcJPBjnUn13wQKxp0lm1Dw84zvR-1QrE4byCemr2_qENxB-Ob_YEc6yw3bvQcqN6VQ0ZPN4Sv6DvX5okAWE52wRXmNcHlTliFOPdjLcKcv3qBFXXlVk">
    +</form>
    +
    +
    + +
    +
    \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml.cs index 27075bf09a..c61423c6a6 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml.cs @@ -12,9 +12,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components public class DynamicFormsModel : PageModel { [BindProperty] - public PersonModel PersonInput { get; set; } + public DetailedModel MyDetailedModel { get; set; } - public List Countries { get; set; } = new List + public OrderExampleModel MyOrderExampleModel { get; set; } + + public AttributeExamplesModel MyAttributeExamplesModel { get; set; } + + public FormContentExampleModel MyFormContentExampleModel { get; set; } + + public List CountryList { get; set; } = new List { new SelectListItem { Value = "CA", Text = "Canada"}, new SelectListItem { Value = "US", Text = "USA"}, @@ -24,72 +30,123 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components public void OnGet() { - if (PersonInput == null) - { - PersonInput = new PersonModel + MyDetailedModel = new DetailedModel { - Name = "John", + Name = "", + Description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + IsActive = true, Age = 65, - Country = "CA", Day = DateTime.Now, - City = Cities.NewJersey, - Phone = new PhoneModel { Number = "326346231", Name = "MyPhone" } + MyCarType = CarType.Coupe, + YourCarType = CarType.Sedan, + Country = "RU", + NeighborCountries = new List() { "UK", "CA" } }; - } + + MyFormContentExampleModel = new FormContentExampleModel(); + + MyOrderExampleModel = new OrderExampleModel(); + + MyAttributeExamplesModel = new AttributeExamplesModel + { + DisabledInput = "Disabled Input", + ReadonlyInput = "Readonly Input", + LargeInput = "Large Input", + SmallInput = "Small Input" + }; + } - public void OnPost() + public class FormContentExampleModel { + public string SampleInput { get; set; } + } + public class AttributeExamplesModel + { + [HiddenInput] + public string HiddenInput { get; set; } + + [DisabledInput] + public string DisabledInput{ get; set; } + + [ReadOnlyInput] + public string ReadonlyInput { get; set; } + + [FormControlSize(AbpFormControlSize.Large)] + public string LargeInput { get; set; } + + [FormControlSize(AbpFormControlSize.Small)] + public string SmallInput { get; set; } } - public class PersonModel + public class OrderExampleModel + { + [DisplayOrder(10005)] + public string Surname{ get; set; } + + //Default 10000 + public string EmailAddress { get; set; } + + [DisplayOrder(10003)] + public string Name { get; set; } + + [DisplayOrder(9999)] + public string City { get; set; } + } + + public class DetailedModel { [Required] + [Placeholder("Enter your name...")] + [Display(Name = "Name")] public string Name { get; set; } [TextArea(Rows = 4)] - public string Surname { get; set; } + [Display(Name = "Description")] + [InputInfoText("Describe Yourself")] + public string Description { get; set; } + + [Required] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string Password { get; set; } + + [Display(Name = "Is Active")] + public bool IsActive { get; set; } [Required] - [Range(1, 100)] + [Display(Name = "Age")] public int Age { get; set; } [Required] - public Cities City { get; set; } + [Display(Name = "My Car Type")] + public CarType MyCarType { get; set; } - public PhoneModel Phone { get; set; } + [Required] + [AbpRadioButton(Inline = true)] + [Display(Name = "Your Car Type")] + public CarType YourCarType { get; set; } [DataType(DataType.Date)] - [DisplayOrder(10003)] + [Display(Name = "Day")] public DateTime Day { get; set; } - public bool IsActive { get; set; } - - [AbpRadioButton(Inline = true)] - [SelectItems(nameof(Countries))] + [SelectItems(nameof(CountryList))] + [Display(Name = "Country")] public string Country { get; set; } + + [SelectItems(nameof(CountryList))] + [Display(Name = "Neighbor Countries")] + public List NeighborCountries { get; set; } } - public class PhoneModel - { - [Required] - [DisplayOrder(10002)] - public string Number { get; set; } - - [Required] - [DisplayOrder(10001)] - [DisplayName("PhoneName")] - public string Name { get; set; } - } - - public enum Cities + public enum CarType { - NewJersey, - Moscow, - Istanbul, - London, - Beijing + Sedan, + Hatchback, + StationWagon, + Coupe } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml new file mode 100644 index 0000000000..3dfea6bcb6 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml @@ -0,0 +1,457 @@ +@page +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components +@model FormElementsModel + +@{ + ViewData["Title"] = "Form Elements"; +} + +@section styles { + + + +} + +@section scripts { + + @* + *@ + +} + + + + + + + +

    Form Elements

    + +

    Example

    + +
    +
    + + + +
    +
    + + +
    
    + public class FormElementsModel : PageModel
    +    {
    +        public SampleModel MyModel { get; set; }
    +
    +        public void OnGet()
    +        {
    +            MyModel = new SampleModel();
    +        }
    +
    +        public class SampleModel
    +        {
    +            [Required]
    +            public string Name { get; set; }
    +
    +            [Required]
    +            [DataType(DataType.Password)]
    +            public string Password { get; set; }
    +
    +            public bool CheckMeOut { get; set; }
    +        }
    +    }
    +
    +
    + +
    
    +<abp-input asp-for="@@Model.MyModel.Name" label="Name"/>
    +<abp-input asp-for="@@Model.MyModel.Password" label="Password" />
    +<abp-input asp-for="@@Model.MyModel.CheckMeOut" label="Check Me Out" />
    +
    +
    + +
    
    +<div class="form-group">
    +<label for="MyModel_Name">Name</label>
    +<input type="text" data-val="true" data-val-required="The Name field is required." id="MyModel_Name" name="MyModel.Name" value="" class="form-control ">
    +<span class="text-danger field-validation-valid" data-valmsg-for="MyModel.Name" data-valmsg-replace="true"></span>
    +</div>
    +<div class="form-group">
    +<label for="MyModel_Password">Password</label>
    +<input type="password" data-val="true" data-val-required="The Password field is required." id="MyModel_Password" name="MyModel.Password" class="form-control ">
    +<span class="text-danger field-validation-valid" data-valmsg-for="MyModel.Password" data-valmsg-replace="true"></span>
    +</div>
    +<div class="form-check">
    +<input type="checkbox" data-val="true" data-val-required="The CheckMeOut field is required." id="MyModel_CheckMeOut" name="MyModel.CheckMeOut" value="true" class="form-check-input "><input name="MyModel.CheckMeOut" type="hidden" value="false">
    +<label class="form-check-label" for="MyModel_CheckMeOut">Check Me Out</label>
    +</div>
    +
    +
    +
    +
    +
    + +

    Form controls

    + +
    +
    + + + + +
    +
    + + +
    
    + public class FormElementsModel : PageModel
    +    {
    +        public SampleModel MyModel { get; set; }
    +                    
    +        public List<SelectListItem> CityList { get; set; } = new List<SelectListItem>
    +        {
    +            new SelectListItem { Value = "NY", Text = "New York"},
    +            new SelectListItem { Value = "LDN", Text = "London"},
    +            new SelectListItem { Value = "IST", Text = "Istanbul"},
    +            new SelectListItem { Value = "MOS", Text = "Moscow"}
    +        };
    +
    +        public void OnGet()
    +        {
    +            MyModel = new SampleModel();
    +        }
    +
    +        public class SampleModel
    +        {
    +            [Required]
    +            public string EmailAddress { get; set; }
    +
    +            public string City { get; set; }
    +
    +            public List<string> Cities { get; set; }
    +
    +            [TextArea]
    +            public string Description { get; set; }
    +        }
    +    }
    +
    +
    + +
    
    +<abp-input asp-for="@@Model.MyModel.EmailAddress" label="Email Address" placeholder="name@example.com" />
    +<abp-select asp-for="@@Model.MyModel.City" asp-items="@@Model.CityList" label="City" />
    +<abp-select asp-for="@@Model.MyModel.Cities" asp-items="@@Model.CityList" label="Cities" />
    +<abp-input asp-for="@@Model.MyModel.Description" label="Description" />
    +
    +
    + +
    
    +    <div class="form-group">
    +        <label for="MyModel_EmailAddress">Email Address</label>
    +        <input placeholder="name@example.com" type="text" data-val="true" data-val-required="The EmailAddress field is required." id="MyModel_EmailAddress" name="MyModel.EmailAddress" value="" class="form-control ">
    +        <span class="text-danger field-validation-valid" data-valmsg-for="MyModel.EmailAddress" data-valmsg-replace="true"></span>
    +    </div>
    +    <div class="form-group">
    +        <label for="MyModel_City">City</label>
    +        <select id="MyModel_City" name="MyModel.City" class="form-control">
    +            <option value="NY">New York</option>
    +            <option value="LDN">London</option>
    +            <option value="IST">Istanbul</option>
    +            <option value="MOS">Moscow</option>
    +        </select>
    +    </div>
    +    <div class="form-group">
    +        <label for="MyModel_Cities">Cities</label>
    +        <select id="MyModel_Cities" multiple="multiple" name="MyModel.Cities" class="form-control">
    +            <option value="NY">New York</option>
    +            <option value="LDN">London</option>
    +            <option value="IST">Istanbul</option>
    +            <option value="MOS">Moscow</option>
    +        </select>
    +    </div>
    +    <div class="form-group">
    +        <label for="MyModel_Description">Description</label>
    +        <textarea id="MyModel_Description" name="MyModel.Description" class="form-control "></textarea>
    +        <span class="text-danger field-validation-valid" data-valmsg-for="MyModel.Description" data-valmsg-replace="true"></span>
    +    </div>
    +
    +
    +
    +
    +
    + +

    Sizing

    + +
    +
    + + +
    +
    + + +
    
    + public class FormElementsModel : PageModel
    +    {
    +        public SampleModel MyModel { get; set; }
    +
    +        public void OnGet()
    +        {
    +            MyModel = new SampleModel();
    +        }
    +
    +        public class SampleModel
    +        {
    +            public string LargeInput { get; set; }
    +
    +            public string SmallInput { get; set; }
    +        }
    +    }
    +
    +
    + +
    
    +<abp-input asp-for="@@Model.MyModel.LargeInput" size="Large" />
    +<abp-input asp-for="@@Model.MyModel.SmallInput" size="Small" />
    +
    +
    + +
    
    +<div class="form-group">
    +    <label for="MyModel_LargeInput">LargeInput</label>
    +    <input type="text" id="MyModel_LargeInput" name="MyModel.LargeInput" value="" class="form-control form-control-lg">
    +    <span class="text-danger field-validation-valid" data-valmsg-for="MyModel.LargeInput" data-valmsg-replace="true"></span>
    +</div>
    +<div class="form-group">
    +    <label for="MyModel_SmallInput">SmallInput</label>
    +    <input type="text" id="MyModel_SmallInput" name="MyModel.SmallInput" value="" class="form-control form-control-sm">
    +    <span class="text-danger field-validation-valid" data-valmsg-for="MyModel.SmallInput" data-valmsg-replace="true"></span>
    +</div>
    +
    +
    +
    +
    +
    + +

    Disabled And ReadOnly

    + +
    +
    + + +
    +
    + + +
    
    + public class FormElementsModel : PageModel
    +    {
    +        public SampleModel MyModel { get; set; }
    +
    +        public void OnGet()
    +        {
    +            MyModel = new SampleModel();
    +            MyModel.SampleInput0 = "This is a disabled input.";
    +            MyModel.SampleInput0 = "This is a disabled input.";
    +            MyModel.SampleInput1 = "This is a readonly input.";
    +        }
    +
    +        public class SampleModel
    +        {
    +            public string SampleInput0 { get; set; }
    +                    
    +            public string SampleInput1 { get; set; }
    +
    +            public string SampleInput2 { get; set; }
    +        }
    +    }
    +
    +
    + +
    
    +<abp-input asp-for="@@Model.MyModel.SampleInput0" disabled="true" />
    +<abp-input asp-for="@@Model.MyModel.SampleInput1" readonly="True" />
    +
    +
    + +
    
    +<div class="form-group">
    +    <label for="MyModel_SampleInput0">SampleInput0</label>
    +    <input type="text" id="MyModel_SampleInput0" name="MyModel.SampleInput0" value="This is a disabled input." disabled="" class="form-control ">
    +    <span class="text-danger field-validation-valid" data-valmsg-for="MyModel.SampleInput0" data-valmsg-replace="true"></span>
    +</div>
    +<div class="form-group">
    +    <label for="MyModel_SampleInput1">SampleInput1</label>
    +    <input type="text" id="MyModel_SampleInput1" name="MyModel.SampleInput1" value="This is a readonly input." class="form-control " readonly="">
    +    <span class="text-danger field-validation-valid" data-valmsg-for="MyModel.SampleInput1" data-valmsg-replace="true"></span>
    +</div>
    +
    +
    +
    +
    +
    + +

    Checkboxes and radios

    + +
    +
    + + +
    +
    + + +
    
    + public class FormElementsModel : PageModel
    +    {
    +        public SampleModel MyModel { get; set; }
    +
    +        public void OnGet()
    +        {
    +            MyModel = new SampleModel();
    +        }
    +
    +        public class SampleModel
    +        {
    +            public bool DefaultCheckbox { get; set; }
    +
    +            public bool DisabledCheckbox { get; set; }
    +        }
    +    }
    +
    +
    + +
    
    +<abp-input asp-for="@@Model.MyModel.DefaultCheckbox"/>
    +<abp-input asp-for="@@Model.MyModel.DisabledCheckbox" disabled="true"/>
    +
    +
    + +
    
    +<div class="form-check">
    +    <input type="checkbox" data-val="true" data-val-required="The DefaultCheckbox field is required." id="MyModel_DefaultCheckbox" name="MyModel.DefaultCheckbox" value="true" class="form-check-input "><input name="MyModel.DefaultCheckbox" type="hidden" value="false">
    +    <label class="form-check-label" for="MyModel_DefaultCheckbox">DefaultCheckbox</label>
    +</div>
    +<div class="form-check">
    +    <input type="checkbox" data-val="true" data-val-required="The DisabledCheckbox field is required." id="MyModel_DisabledCheckbox" name="MyModel.DisabledCheckbox" value="true" disabled="" class="form-check-input "><input name="MyModel.DisabledCheckbox" type="hidden" value="false">
    +    <label class="form-check-label" for="MyModel_DisabledCheckbox">DisabledCheckbox</label>
    +</div>
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + + +
    
    + public class FormElementsModel : PageModel
    +    {
    +        public SampleModel MyModel { get; set; }
    +
    +        public void OnGet()
    +        {
    +            MyModel = new SampleModel();
    +            MyModel.CityRadio = "IST";
    +        }
    +
    +        public class SampleModel
    +        {
    +            [Display(Name="City")]
    +            public string CityRadio { get; set; }
    +        }
    +    }
    +
    +
    + +
    
    +<abp-radio asp-for="@@Model.MyModel.CityRadio" asp-items="@@Model.CityList" inline="true"/>
    +
    +
    + +
    
    +<div>
    +    <div class="custom-control custom-radio custom-control-inline">
    +        <input type="radio" id="MyModel.CityRadioRadioNY" name="MyModel.CityRadio" value="NY" class="custom-control-input">
    +        <label class="custom-control-label" for="MyModel.CityRadioRadioNY">New York</label>
    +    </div>
    +    <div class="custom-control custom-radio custom-control-inline">
    +        <input type="radio" id="MyModel.CityRadioRadioLDN" name="MyModel.CityRadio" value="LDN" class="custom-control-input">
    +        <label class="custom-control-label" for="MyModel.CityRadioRadioLDN">London</label>
    +    </div>
    +    <div class="custom-control custom-radio custom-control-inline">
    +        <input type="radio" id="MyModel.CityRadioRadioIST" name="MyModel.CityRadio" value="IST" checked="checked" class="custom-control-input">
    +        <label class="custom-control-label" for="MyModel.CityRadioRadioIST">Istanbul</label>
    +    </div>
    +    <div class="custom-control custom-radio custom-control-inline">
    +        <input type="radio" id="MyModel.CityRadioRadioMOS" name="MyModel.CityRadio" value="MOS" class="custom-control-input">
    +        <label class="custom-control-label" for="MyModel.CityRadioRadioMOS">Moscow</label>
    +    </div>
    +</div>
    +
    +
    +
    +
    +
    + +

    Enum

    + +
    +
    + +
    +
    + + +
    
    + public class FormElementsModel : PageModel
    +    {
    +        public SampleModel MyModel { get; set; }
    +
    +        public void OnGet()
    +        {
    +            MyModel = new SampleModel();
    +        }
    +
    +        public class SampleModel
    +        {
    +            public CarType CarType { get; set; }
    +        }
    +
    +        public enum CarType
    +        {
    +            Sedan,
    +            Hatchback,
    +            StationWagon,
    +            Coupe
    +        }
    +    }
    +
    +
    + +
    
    +<abp-select asp-for="@Model.MyModel.CarType"/>
    +
    +
    + +
    
    + <div class="form-group">
    +     <label for="MyModel_CarType">CarType</label>
    +     <select data-val="true" data-val-required="The CarType field is required." id="MyModel_CarType" name="MyModel.CarType" class="form-control">
    +         <option selected="selected" value="0">Sedan</option>
    +         <option value="1">Hatchback</option>
    +         <option value="2">StationWagon</option>
    +         <option value="3">Coupe</option>
    +     </select>
    + </div>
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml.cs new file mode 100644 index 0000000000..dca438d5a8 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.Rendering; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components +{ + public class FormElementsModel : PageModel + { + [BindProperty] + public SampleModel MyModel { get; set; } + + public List CityList { get; set; } = new List + { + new SelectListItem { Value = "NY", Text = "New York"}, + new SelectListItem { Value = "LDN", Text = "London"}, + new SelectListItem { Value = "IST", Text = "Istanbul"}, + new SelectListItem { Value = "MOS", Text = "Moscow"} + }; + + public void OnGet() + { + MyModel = new SampleModel(); + MyModel.SampleInput0 = "This is a disabled input."; + MyModel.SampleInput1 = "This is a readonly input."; + MyModel.CityRadio = "IST"; + } + + public class SampleModel + { + public string Name { get; set; } + + public string SampleInput0 { get; set; } + + public string SampleInput1 { get; set; } + + public string SampleInput2 { get; set; } + + public string LargeInput { get; set; } + + public string SmallInput { get; set; } + + [TextArea] + public string Description { get; set; } + + public string EmailAddress { get; set; } + + [Required] + [DataType(DataType.Password)] + public string Password { get; set; } + + public bool CheckMeOut { get; set; } + + public bool DefaultCheckbox { get; set; } + + public bool DisabledCheckbox { get; set; } + + public CarType CarType { get; set; } + + public string City { get; set; } + + [Display(Name="City")] + public string CityRadio { get; set; } + + public List Cities { get; set; } + } + + public enum CarType + { + Sedan, + Hatchback, + StationWagon, + Coupe + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Grids.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Grids.cshtml index 4957fd3636..097b670e70 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Grids.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Grids.cshtml @@ -10,260 +10,838 @@ } +@section scripts { + + @* + *@ + +} + + + + +

    Grids

    Based on Bootstrap grid.

    -

    # Example

    +

    Equal-width

    -
    +
    - One of two columns - One of two columns + 1 of 2 + 2 of 2 + + + 1 of 3 + 2 of 3 + 3 of 3 + +
    +
    + + +
    
    +        <abp-container>
    +            <abp-row>
    +                <abp-column>1 of 2</abp-column>
    +                <abp-column>2 of 2</abp-column>
    +            </abp-row>
    +            <abp-row>
    +                <abp-column>1 of 3</abp-column>
    +                <abp-column>2 of 3</abp-column>
    +                <abp-column>3 of 3</abp-column>
    +            </abp-row>
    +        </abp-container>
    +
    +
    + +
    
    +        <div class="container">
    +            <div class="row">
    +                <div class="col">1 of 2</div>
    +                <div class="col">2 of 2</div>
    +            </div>
    +            <div class="row">
    +                <div class="col">1 of 3</div>
    +                <div class="col">2 of 3</div>
    +                <div class="col">3 of 3</div>
    +            </div>
    +        </div>
    +
    +
    +
    +
    +
    + +

    Column Breaker

    + +
    +
    + - One of three columns - One of three columns - One of three columns + column + column + + column + column
    -
    -<abp-container>
    -     <abp-row>
    -         <abp-column size-sm="C6">One of two columns</abp-column>
    -         <abp-column size-sm="C6">One of two columns</abp-column>
    -     </abp-row>
    -     <abp-row>
    -         <abp-column size-sm="C4">One of three columns</abp-column>
    -         <abp-column size-sm="C4">One of three columns</abp-column>
    -         <abp-column size-sm="C4">One of three columns</abp-column>
    -     </abp-row>
    -</abp-container>
    -
    + + +
    
    +        <abp-container>
    +            <abp-row>
    +                <abp-column>column</abp-column>
    +                <abp-column>column</abp-column>
    +                <abp-column-breaker/>
    +                <abp-column>column</abp-column>
    +                <abp-column>column</abp-column>
    +            </abp-row>
    +        </abp-container>
    +
    +
    + +
    
    +        <div class="container">
    +            <div class="row">
    +                <div class="col">column</div>
    +                <div class="col">column</div>
    +                <div class="w-100"></div>
    +                <div class="col">column</div>
    +                <div class="col">column</div>
    +            </div>
    +        </div>
    +
    +
    +
    -

    # Break Column Example

    +

    Setting one column width

    -
    +
    - One of three columns - One of three columns - @* TODO: abp-column-break *@ - One of three columns + 1 of 3 + 2 of 3 (wider) + 3 of 3 + + + 1 of 3 + 2 of 3 (wider) + 3 of 3
    -
    - <abp-container>
    -     <abp-row>
    -         <abp-column>One of three columns</abp-column>
    -         <abp-column>One of three columns</abp-column>
    -         <abp-col-break /> @* TODO: abp-column-break *@
    -         <abp-column>One of three columns</abp-column>
    -     </abp-row>
    - </abp-container>
    -
    + + +
    
    +        <abp-container>
    +            <abp-row>
    +                <abp-column>1 of 3</abp-column>
    +                <abp-column size="_6">2 of 3 (wider)</abp-column>
    +                <abp-column>3 of 3</abp-column>
    +            </abp-row>
    +            <abp-row>
    +                <abp-column>1 of 3</abp-column>
    +                <abp-column size="_5">2 of 3 (wider)</abp-column>
    +                <abp-column>3 of 3</abp-column>
    +            </abp-row>
    +        </abp-container>
    +
    +
    + +
    
    +        <div class="container">
    +            <div class="row">
    +                <div class="col">1 of 3</div>
    +                <div class="col col-6">2 of 3 (wider)</div>
    +                <div class="col">3 of 3</div>
    +            </div>
    +            <div class="row">
    +                <div class="col">1 of 3</div>
    +                <div class="col col-5">2 of 3 (wider)</div>
    +                <div class="col">3 of 3</div>
    +            </div>
    +        </div>
    +
    +
    +
    -

    # Vertical alignment Example

    +

    Variable width content

    -
    +
    + + + 1 of 3 + Variable width content + 3 of 3 + + + 1 of 3 + Variable width content + 3 of 3 + + +
    +
    + + +
    
    +        <abp-container>
    +            <abp-row h-align="Center">
    +                <abp-column size-lg="_2">1 of 3</abp-column>
    +                <abp-column size-md="Auto">Variable width content</abp-column>
    +                <abp-column size-lg="_2">3 of 3</abp-column>
    +            </abp-row>
    +            <abp-row>
    +                <abp-column>1 of 3</abp-column>
    +                <abp-column size-md="Auto">Variable width content</abp-column>
    +                <abp-column size-lg="_2">3 of 3</abp-column>
    +            </abp-row>
    +        </abp-container>
    +
    +
    + +
    
    +        <div class="container">
    +            <div class="row justify-content-center">
    +                <div class="col col-lg-2">1 of 3</div>
    +                <div class="col col-md-auto">Variable width content</div>
    +                <div class="col col-lg-2">3 of 3</div>
    +            </div>
    +            <div class="row">
    +                <div class="col">1 of 3</div>
    +                <div class="col col-md-auto">Variable width content</div>
    +                <div class="col col-lg-2">3 of 3</div>
    +            </div>
    +        </div>
    +
    +
    +
    +
    +
    + +

    Responsive classes

    + +
    All breakpoints
    + +
    +
    + + col + col + col + col + + + col-8 + col-4 + +
    +
    + + +
    
    +            <abp-row>
    +                <abp-column>col</abp-column>
    +                <abp-column>col</abp-column>
    +                <abp-column>col</abp-column>
    +                <abp-column>col</abp-column>
    +            </abp-row>
    +            <abp-row>
    +                <abp-column size="_8">col-8</abp-column>
    +                <abp-column size="_4">col-4</abp-column>
    +            </abp-row>
    +
    +
    + +
    
    +            <div class="row">
    +                <div class="col">col</div>
    +                <div class="col">col</div>
    +                <div class="col">col</div>
    +                <div class="col">col</div>
    +            </div>
    +            <div class="row">
    +                <div class="col col-8">col-8</div>
    +                <div class="col col-4">col-4</div>
    +            </div>
    +
    +
    +
    +
    +
    + +
    All breakpoints
    + +
    +
    + + col-sm-8 + col-sm-4 + + + col-sm + col-sm + col-sm + col-sm + +
    +
    + + +
    
    +        <abp-row>
    +            <abp-column size-sm="_8">col-sm-8</abp-column>
    +            <abp-column size-sm="_4">col-sm-4</abp-column>
    +        </abp-row>
    +        <abp-row>
    +            <abp-column size-sm="_">col-sm</abp-column>
    +            <abp-column size-sm="_">col-sm</abp-column>
    +            <abp-column size-sm="_">col-sm</abp-column>
    +            <abp-column size-sm="_">col-sm</abp-column>
    +        </abp-row>
    +
    +
    + +
    
    +         <div class="row">
    +            <div class="col col-sm-8">col-sm-8</div>
    +            <div class="col col-sm-4">col-sm-4</div>
    +        </div>
    +        <div class="row">
    +            <div class="col col-sm">col-sm</div>
    +            <div class="col col-sm">col-sm</div>
    +            <div class="col col-sm">col-sm</div>
    +            <div class="col col-sm">col-sm</div>
    +        </div>
    +
    +
    +
    +
    +
    + +
    Mix and match
    + +
    +
    + + .col-12 .col-md-8 + .col-6 .col-md-4 + + + .col-6 .col-md-4 + .col-6 .col-md-4 + .col-6 .col-md-4 + + + .col-6 + .col-6 + +
    +
    + + +
    
    +        <!-- Stack the columns on mobile by making one full-width and the other half-width -->
    +        <abp-row>
    +            <abp-column size="_12" size-md="_8">.col-12 .col-md-8</abp-column>
    +            <abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column>
    +        </abp-row>
    +
    +        <!-- Columns start at 50% wide on mobile and bump up to 33.3% wide on desktop -->
    +        <abp-row>
    +            <abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column>
    +            <abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column>
    +            <abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column>
    +        </abp-row>
    +
    +        <!-- Columns are always 50% wide, on mobile and desktop -->
    +        <abp-row>
    +            <abp-column size="_6">.col-6</abp-column>
    +            <abp-column size="_6">.col-6</abp-column>
    +        </abp-row>
    +
    +
    + +
    
    +        <div class="row">
    +            <div class="col col-12 col-md-8">.col-12 .col-md-8</div>
    +            <div class="col col-6 col-md-4">.col-6 .col-md-4</div>
    +        </div>
    +        <div class="row">
    +            <div class="col col-6 col-md-4">.col-6 .col-md-4</div>
    +            <div class="col col-6 col-md-4">.col-6 .col-md-4</div>
    +            <div class="col col-6 col-md-4">.col-6 .col-md-4</div>
    +        </div>
    +        <div class="row">
    +            <div class="col col-6">.col-6</div>
    +            <div class="col col-6">.col-6</div>
    +        </div>
    +
    +
    +
    +
    +
    + +

    Alignment

    + +
    Vertical Alignment
    + +
    +
    - One of three columns - One of three columns - One of three columns + column + column + column - One of three columns - One of three columns - One of three columns + column + column + column - One of three columns - One of three columns - One of three columns + column + column + column
    -
    -<abp-container>
    -     <abp-row v-align="Start">
    -        <abp-column>One of three columns</abp-column>
    -        <abp-column>One of three columns</abp-column>
    -        <abp-column>One of three columns</abp-column>
    -     </abp-row>
    -     <abp-row v-align="Center">
    -         <abp-column>One of three columns</abp-column>
    -         <abp-column>One of three columns</abp-column>
    -         <abp-column>One of three columns</abp-column>
    -     </abp-row>
    -     <abp-row v-align="End">
    -         <abp-column>One of three columns</abp-column>
    -         <abp-column>One of three columns</abp-column>
    -         <abp-column>One of three columns</abp-column>
    -     </abp-row>
    - </abp-container>
    -
    + + +
    
    +        <abp-container>
    +            <abp-row v-align="Start">
    +                <abp-column>column</abp-column>
    +                <abp-column>column</abp-column>
    +                <abp-column>column</abp-column>
    +            </abp-row>
    +            <abp-row v-align="Center">
    +                <abp-column>column</abp-column>
    +                <abp-column>column</abp-column>
    +                <abp-column>column</abp-column>
    +            </abp-row>
    +            <abp-row v-align="End">
    +                <abp-column>column</abp-column>
    +                <abp-column>column</abp-column>
    +                <abp-column>column</abp-column>
    +            </abp-row>
    +        </abp-container>
    +
    +
    + +
    
    +        <div class="container">
    +            <div class="row align-items-start">
    +                <div class="col">column</div>
    +                <div class="col">column</div>
    +                <div class="col">column</div>
    +            </div>
    +            <div class="row align-items-center">
    +                <div class="col">column</div>
    +                <div class="col">column</div>
    +                <div class="col">column</div>
    +            </div>
    +            <div class="row align-items-end">
    +                <div class="col">column</div>
    +                <div class="col">column</div>
    +                <div class="col">column</div>
    +            </div>
    +        </div>
    +
    +
    +
    -

    # Vertical alignment Example 2

    -
    -
    +
    - - One of three columns - One of three columns - One of three columns + + column + column + column
    -
    - <abp-container>
    -    <abp-row>
    -        <abp-column v-align="Start">One of three columns</abp-column>
    -        <abp-column v-align="Center">One of three columns</abp-column>
    -        <abp-column v-align="End">One of three columns</abp-column>
    -     </abp-row>
    - </abp-container>
    -
    + + +
    
    +        <abp-container>
    +            <abp-row v-align="Start">
    +                <abp-column v-align="Start">column</abp-column>
    +                <abp-column v-align="Center">column</abp-column>
    +                <abp-column v-align="End">column</abp-column>
    +            </abp-row>
    +        </abp-container>
    +
    +
    + +
    
    +        <div class="container">
    +            <div class="row align-items-start">
    +                <div class="col align-self-start">column</div>
    +                <div class="col align-self-center">column</div>
    +                <div class="col align-self-end">column</div>
    +            </div>
    +        </div>
    +
    +
    +
    -

    # Horizontal alignment Example

    +
    Horizontal alignment
    -
    +
    - One of three columns - One of three columns + One of two columns + One of two columns - One of three columns - One of three columns + One of two columns + One of two columns - One of three columns - One of three columns + One of two columns + One of two columns - One of three columns - One of three columns + One of two columns + One of two columns - One of three columns - One of three columns + One of two columns + One of two columns + + +
    +
    + + +
    
    +        <abp-container>
    +            <abp-row h-align="Start">
    +                <abp-column size="_4">One of two columns</abp-column>
    +                <abp-column size="_4">One of two columns</abp-column>
    +            </abp-row>
    +            <abp-row h-align="Center">
    +                <abp-column size="_4">One of two columns</abp-column>
    +                <abp-column size="_4">One of two columns</abp-column>
    +            </abp-row>
    +            <abp-row h-align="End">
    +                <abp-column size="_4">One of two columns</abp-column>
    +                <abp-column size="_4">One of two columns</abp-column>
    +            </abp-row>
    +            <abp-row h-align="Around">
    +                <abp-column size="_4">One of two columns</abp-column>
    +                <abp-column size="_4">One of two columns</abp-column>
    +            </abp-row>
    +            <abp-row h-align="Between">
    +                <abp-column size="_4">One of two columns</abp-column>
    +                <abp-column size="_4">One of two columns</abp-column>
    +            </abp-row>
    +        </abp-container>
    +
    +
    + +
    
    +        <div class="container">
    +            <div class="row justify-content-start">
    +                <div class="col col-4">One of two columns</div>
    +                <div class="col col-4">One of two columns</div>
    +            </div>
    +            <div class="row justify-content-center">
    +                <div class="col col-4">One of two columns</div>
    +                <div class="col col-4">One of two columns</div>
    +            </div>
    +            <div class="row justify-content-end">
    +                <div class="col col-4">One of two columns</div>
    +                <div class="col col-4">One of two columns</div>
    +            </div>
    +            <div class="row justify-content-around">
    +                <div class="col col-4">One of two columns</div>
    +                <div class="col col-4">One of two columns</div>
    +            </div>
    +            <div class="row justify-content-between">
    +                <div class="col col-4">One of two columns</div>
    +                <div class="col col-4">One of two columns</div>
    +            </div>
    +        </div>
    +
    +
    +
    +
    +
    + +
    No gutters
    + +
    +
    + + One of two columns + One of two columns + +
    +
    + + +
    
    +            <abp-row gutters="false">
    +                <abp-column size="_8">One of two columns</abp-column>
    +                <abp-column size="_4">One of two columns</abp-column>
    +            </abp-row>
    +
    +
    + +
    
    +            <div class="row no-gutters">
    +                <div class="col col-8">One of two columns</div>
    +                <div class="col col-4">One of two columns</div>
    +            </div>
    +
    +
    +
    +
    +
    + +
    Column wrapping
    + +
    +
    + + .col-9 + .col-4
    Since 9 + 4 = 13 > 12, this 4-column-wide div gets wrapped onto a new line as one contiguous unit.
    + .col-6
    Subsequent columns continue along the new line.s
    +
    +
    +
    + + +
    
    +            <abp-row>
    +                <abp-column size="_9">.col-9</abp-column>
    +                <abp-column size="_4">.col-4<br>Since 9 + 4 = 13 &gt; 12, this 4-column-wide div gets wrapped onto a new line as one contiguous unit.</abp-column>
    +                <abp-column size="_6">.col-6<br>Subsequent columns continue along the new line.s</abp-column>
    +            </abp-row>
    +
    +
    + +
    
    +            <div class="row">
    +                <div class="col col-9">.col-9</div>
    +                <div class="col col-4">.col-4<br>Since 9 + 4 = 13 &gt; 12, this 4-column-wide div gets wrapped onto a new line as one contiguous unit.</div>
    +                <div class="col col-6">.col-6<br>Subsequent columns continue along the new line.s</div>
    +            </div>
    +
    +
    +
    +
    +
    + +

    Reordering

    + +
    Order classes
    + +
    +
    + + + First, but Last + Second, but unordered + Third, but Second + + +
    +
    + + +
    
    +        <abp-container>
    +            <abp-row>
    +                <abp-column order="_12">First, but Last</abp-column>
    +                <abp-column>Second, but unordered</abp-column>
    +                <abp-column order="_6">Third, but Second</abp-column>
    +            </abp-row>
    +        </abp-container>
    +
    +
    + +
    
    +        <div class="container">
    +            <div class="row">
    +                <div class="col order-12">First, but Last</div>
    +                <div class="col">Second, but unordered</div>
    +                <div class="col order-6">Third, but Second</div>
    +            </div>
    +        </div>
    +
    +
    +
    +
    +
    + +
    +
    + + + First, but Last + Second, but unordered + Third, but First
    -
    - <abp-container>
    -    <abp-row h-align="Start">
    -        <abp-column size="C4">One of three columns</abp-column>
    -        <abp-column size="C4">One of three columns</abp-column>
    -    </abp-row>
    -    <abp-row h-align="Center">
    -        <abp-column size="C4">One of three columns</abp-column>
    -        <abp-column size="C4">One of three columns</abp-column>
    -    </abp-row>
    -    <abp-row h-align="End">
    -        <abp-column size="C4">One of three columns</abp-column>
    -        <abp-column size="C4">One of three columns</abp-column>
    -    </abp-row>
    -        <abp-row h-align="Around">
    -        <abp-column size="C4">One of three columns</abp-column>
    -        <abp-column size="C4">One of three columns</abp-column>
    -    </abp-row>
    -    <abp-row h-align="Between">
    -        <abp-column size="C4">One of three columns</abp-column>
    -        <abp-column size="C4">One of three columns</abp-column>
    -    </abp-row>
    - </abp-container>
    -
    + + +
    
    +        <abp-container>
    +            <abp-row>
    +                <abp-column order="Last">First, but Last</abp-column>
    +                <abp-column>Second, but unordered</abp-column>
    +                <abp-column order="First">Third, but First</abp-column>
    +            </abp-row>
    +        </abp-container>
    +
    +
    + +
    
    +        <div class="container">
    +            <div class="row">
    +                <div class="col order-last">First, but Last</div>
    +                <div class="col">Second, but unordered</div>
    +                <div class="col order-first">Third, but First</div>
    +            </div>
    +        </div>
    +
    +
    +
    -

    # Order Example

    +

    Offsetting columns

    + +
    Offset classes
    -
    +
    - First, but unordered - Second, but last - Third, but first + .col-md-4 + .col-md-4 .offset-md-4 + + + .col-md-3 .offset-md-3 + .col-md-3 .offset-md-3 - First, but unordered - Second, but last - Third, but first + .col-md-6 .offset-md-3
    -
    - <abp-container>
    -    <abp-row>
    -        <abp-column> First, but unordered</abp-column>
    -        <abp-column order="C12">Second, but last</abp-column>
    -        <abp-column order="C1">Third, but first</abp-column>
    -    </abp-row>
    -    <abp-row>
    -        <abp-column> First, but unordered</abp-column>
    -        <abp-column order="Last">Second, but last</abp-column>
    -        <abp-column order="First">Third, but first</abp-column>
    -    </abp-row>
    - </abp-container>
    -
    + + +
    
    +        <abp-container>
    +            <abp-row>
    +                <abp-column size-md="_4">.col-md-4</abp-column>
    +                <abp-column size-md="_4" offset-md="_4">.col-md-4 .offset-md-4</abp-column>
    +            </abp-row>
    +            <abp-row>
    +                <abp-column size-md="_3" offset-md="_3">.col-md-3 .offset-md-3</abp-column>
    +                <abp-column size-md="_3" offset-md="_3">.col-md-3 .offset-md-3</abp-column>
    +            </abp-row>
    +            <abp-row>
    +                <abp-column size-md="_6" offset-md="_3">.col-md-6 .offset-md-3</abp-column>
    +            </abp-row>
    +        </abp-container>
    +
    +
    + +
    
    +        <div class="container">
    +            <div class="row">
    +                <div class="col col-md-4">.col-md-4</div>
    +                <div class="col col-md-4 offset-md-4">.col-md-4 .offset-md-4</div>
    +            </div>
    +            <div class="row">
    +                <div class="col col-md-3 offset-md-3">.col-md-3 .offset-md-3</div>
    +                <div class="col col-md-3 offset-md-3">.col-md-3 .offset-md-3</div>
    +            </div>
    +            <div class="row">
    +                <div class="col col-md-6 offset-md-3">.col-md-6 .offset-md-3</div>
    +            </div>
    +        </div>
    +
    +
    +
    -

    # Offset Example

    -
    - - .col-md-4 - .col-md-4 .offset-md-4 - - - .col-md-3 .offset-md-3 - .col-md-3 .offset-md-3 - - - .col-md-6 .offset-md-3 - +
    + + + .col-sm-5 .col-md-6 + .col-sm-5 .offset-sm-2 .col-md-6 .offset-md-0 + + + col-sm-6 .col-md-5 .col-lg-6 + .col-sm-6 .col-md-5 .offset-md-2 .col-lg-6 .offset-lg-0 + +
    -
    - <abp-row>
    -    <abp-column> .col-md-4</abp-column>
    -    <abp-column size-md="C4" offset-md="C4">.col-md-4 .offset-md-4</abp-column>
    - </abp-row>
    - <abp-row>
    -    <abp-column size-md="C3" offset-md="C3">.col-md-3 .offset-md-3</abp-column>
    -    <abp-column size-md="C3" offset-md="C3">.col-md-3 .offset-md-3</abp-column>
    - </abp-row>
    - <abp-row>
    -    <abp-column size-md="C6" offset-md="C3">.col-md-6 .offset-md-3</abp-column>
    - </abp-row>
    -
    + + +
    
    +        <abp-container>
    +            <abp-row>
    +                <abp-column size-sm="_5" size-md="_6">.col-sm-5 .col-md-6</abp-column>
    +                <abp-column size-sm="_5" offset-sm="_2" size-md="_6" offset-md="_">.col-sm-5 .offset-sm-2 .col-md-6 .offset-md-0</abp-column>
    +            </abp-row>
    +            <abp-row>
    +                <abp-column size-sm="_6" size-md="_5" size-lg="_6">col-sm-6 .col-md-5 .col-lg-6</abp-column>
    +                <abp-column size-sm="_6" size-md="_5" offset-md="_2" size-lg="_6" offset-lg="_">.col-sm-6 .col-md-5 .offset-md-2 .col-lg-6 .offset-lg-0</abp-column>
    +            </abp-row>
    +        </abp-container>
    +
    +
    + +
    
    +        <div class="container">
    +            <div class="row">
    +                <div class="col col-sm-5 col-md-6">.col-sm-5 .col-md-6</div>
    +                <div class="col col-sm-5 col-md-6 offset-sm-2 offset-md-0">col-sm-5 .offset-sm-2 .col-md-6 .offset-md-0</div>
    +            </div>
    +            <div class="row">
    +                <div class="col col-sm-6 col-md-5 col-lg-6">col-sm-6 .col-md-5 .col-lg-6</div>
    +                <div class="col col-sm-6 col-md-5 col-lg-6 offset-md-2 offset-lg-0">.col-sm-6 .col-md-5 .offset-md-2 .col-lg-6 .offset-lg-0</div>
    +            </div>
    +        </div>
    +
    +
    +
    diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Images.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Images.cshtml deleted file mode 100644 index 9ec4f0106e..0000000000 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Images.cshtml +++ /dev/null @@ -1,54 +0,0 @@ -@page -@model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.ImagesModel -@{ - ViewData["Title"] = "Images"; -} - -@section styles { - - - -} - -

    Images

    - -

    Based on Bootstrap Images.

    - -

    # Image Examples

    - -
    -
    - -
    -
    -
    -<abp-image src="..." responsive="true"></abp-image>
    -
    -
    -
    - -
    -
    - -
    -
    -
    -<abp-image src="..." thumbnail="true" rounded="true"></abp-image>
    -
    -
    -
    - -
    -
    - - - -
    -
    -
    -<abp-image src="..." rounded="true" position="Left"></abp-image>
    -<abp-image src="..." rounded="true" position="Center"></abp-image>
    -<abp-image src="..." rounded="true" position="Right"></abp-image>
    -
    -
    -
    diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ListGroup.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ListGroup.cshtml index 90097a3c4d..40a5cb5c65 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ListGroup.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ListGroup.cshtml @@ -10,11 +10,23 @@ } +@section scripts { + + @* + *@ + +} + + + + +

    List Groups

    Based on Bootstrap List Group.

    -

    # List Group Example

    +

    Basic example

    @@ -25,116 +37,329 @@ Morbi leo risus Vestibulum at eros -
    -
    +        
    +            
    +                
    
     <abp-list-group>
    -    <abp-list-group-item active="true">Cras justo odio</abp-list-group-item>
    +    <abp-list-group-item>Cras justo odio</abp-list-group-item>
         <abp-list-group-item>Dapibus ac facilisis in</abp-list-group-item>
         <abp-list-group-item>Morbi leo risus</abp-list-group-item>
    -    <abp-list-group-item disabled="true">Vestibulum at eros</abp-list-group-item>
    +    <abp-list-group-item>Vestibulum at eros</abp-list-group-item>
     </abp-list-group>
    -
    +
    + + +
    
    +<ul class="list-group">
    +  <li class="list-group-item">Cras justo odio</li>
    +  <li class="list-group-item">Dapibus ac facilisis in</li>
    +  <li class="list-group-item">Morbi leo risus</li>
    +  <li class="list-group-item">Porta ac consectetur ac</li>
    +</ul>
    +
    +
    +
    -

    # List Group Flush Example

    +

    Active & disabled items

    - + Cras justo odio - Dapibus ac facilisis in + Dapibus ac facilisis in Morbi leo risus - Vestibulum at eros + Vestibulum at eros -
    -
    -<abp-list-group flush="true">
    +        
    +            
    +                
    
    +<abp-list-group>
         <abp-list-group-item>Cras justo odio</abp-list-group-item>
    -    <abp-list-group-item>Dapibus ac facilisis in</abp-list-group-item>
    +    <abp-list-group-item active="true">Dapibus ac facilisis in</abp-list-group-item>
         <abp-list-group-item>Morbi leo risus</abp-list-group-item>
    -    <abp-list-group-item>Vestibulum at eros</abp-list-group-item>
    +    <abp-list-group-item disabled="true">Vestibulum at eros</abp-list-group-item>
     </abp-list-group>
    -
    +
    + + +
    
    +<ul class="list-group">
    +  <li class="list-group-item active">Cras justo odio</li>
    +  <li class="list-group-item">Dapibus ac facilisis in</li>
    +  <li class="list-group-item">Morbi leo risus</li>
    +  <li class="list-group-item disabled">Porta ac consectetur ac</li>
    +</ul>
    +
    +
    +
    -

    # List Group Link Example

    +

    Links and buttons

    - Cras justo odio + Cras justo odio Dapibus ac facilisis in Morbi leo risus - Vestibulum at eros + Vestibulum at eros -
    -
    +        
    +            
    +                
    
     <abp-list-group>
    -    <abp-list-group-item href="#">Cras justo odio</abp-list-group-item>
    +    <abp-list-group-item href="#" active="true">Cras justo odio</abp-list-group-item>
         <abp-list-group-item href="#">Dapibus ac facilisis in</abp-list-group-item>
         <abp-list-group-item href="#">Morbi leo risus</abp-list-group-item>
    -    <abp-list-group-item href="#">Vestibulum at eros</abp-list-group-item>
    +    <abp-list-group-item href="#" disabled="true">Vestibulum at eros</abp-list-group-item>
     </abp-list-group>
    -
    +
    + + +
    
    +<div class="list-group">
    +  <a href="#" class="list-group-item list-group-item-action active">Cras justo odio</a>
    +  <a href="#" class="list-group-item list-group-item-action">Dapibus ac facilisis in</a>
    +  <a href="#" class="list-group-item list-group-item-action">Morbi leo risus</a>
    +  <a href="#" class="list-group-item list-group-item-action disabled">Vestibulum at eros</a>
    +</div>
    +
    +
    +
    -

    # List Group Button Example

    -
    - Cras justo odio + Cras justo odio Dapibus ac facilisis in Morbi leo risus Vestibulum at eros -
    -
    -<abp-list-group flush="true">
    -    <abp-list-group-item tag-type="Button">Cras justo odio</abp-list-group-item>
    +        
    +            
    +                
    
    +<abp-list-group>
    +    <abp-list-group-item tag-type="Button" active="true">Cras justo odio</abp-list-group-item>
         <abp-list-group-item tag-type="Button">Dapibus ac facilisis in</abp-list-group-item>
         <abp-list-group-item tag-type="Button">Morbi leo risus</abp-list-group-item>
         <abp-list-group-item tag-type="Button">Vestibulum at eros</abp-list-group-item>
     </abp-list-group>
    -
    +
    + + +
    
    +<div class="list-group">
    +  <button type="button" class="list-group-item list-group-item-action active">
    +    Cras justo odio
    +  </button>
    +  <button type="button" class="list-group-item list-group-item-action">Morbi leo risus</button>
    +  <button type="button" class="list-group-item list-group-item-action">Porta ac consectetur ac</button>
    +  <button type="button" class="list-group-item list-group-item-action" disabled>Vestibulum at eros</button>
    +</div>
    +
    +
    +
    -

    # List Group style Contextual classes Example

    +

    Flush

    + +
    +
    + + + Cras justo odio + Dapibus ac facilisis in + Morbi leo risus + Vestibulum at eros + +
    +
    + + +
    
    +<abp-list-group flush="true">
    +    <abp-list-group-item>Cras justo odio</abp-list-group-item>
    +    <abp-list-group-item>Dapibus ac facilisis in</abp-list-group-item>
    +    <abp-list-group-item>Morbi leo risus</abp-list-group-item>
    +    <abp-list-group-item>Vestibulum at eros</abp-list-group-item>
    +</abp-list-group>
    +
    +
    + +
    
    +<ul class="list-group list-group-flush">
    +  <li class="list-group-item">Cras justo odio</li>
    +  <li class="list-group-item">Dapibus ac facilisis in</li>
    +  <li class="list-group-item">Morbi leo risus</li>
    +  <li class="list-group-item">Vestibulum at eros</li>
    +</ul>
    +
    +
    +
    +
    +
    + +

    Contextual classes

    - Cras justo odio - Dapibus ac facilisis in - Morbi leo risus 42 - Vestibulum at eros 5 + Cras justo odio + A simple Primary list group item + A simple Secondary list group item + A simple Success list group item + A simple Danger list group item + A simple Warning list group item + A simple Info list group item + A simple Light list group item + A simple Dark list group item +
    +
    + + +
    
    +<abp-list-group>
    +    <abp-list-group-item>Cras justo odio</abp-list-group-item>
    +    <abp-list-group-item type="Primary">A simple Primary list group item</abp-list-group-item>
    +    <abp-list-group-item type="Secondary">A simple Secondary list group item</abp-list-group-item>
    +    <abp-list-group-item type="Success">A simple Success list group item</abp-list-group-item>
    +    <abp-list-group-item type="Danger">A simple Danger list group item</abp-list-group-item>
    +    <abp-list-group-item type="Warning">A simple Warning list group item</abp-list-group-item>
    +    <abp-list-group-item type="Info">A simple Info list group item</abp-list-group-item>
    +    <abp-list-group-item type="Light">A simple Light list group item</abp-list-group-item>
    +    <abp-list-group-item type="Dark">A simple Dark list group item</abp-list-group-item>
    +</abp-list-group>
    +
    +
    + +
    
    +<ul class="list-group">
    +  <li class="list-group-item">Dapibus ac facilisis in</li>
    +  <li class="list-group-item list-group-item-primary">A simple primary list group item</li>
    +  <li class="list-group-item list-group-item-secondary">A simple secondary list group item</li>
    +  <li class="list-group-item list-group-item-success">A simple success list group item</li>
    +  <li class="list-group-item list-group-item-danger">A simple danger list group item</li>
    +  <li class="list-group-item list-group-item-warning">A simple warning list group item</li>
    +  <li class="list-group-item list-group-item-info">A simple info list group item</li>
    +  <li class="list-group-item list-group-item-light">A simple light list group item</li>
    +  <li class="list-group-item list-group-item-dark">A simple dark list group item</li>
    +</ul>
    +
    +
    +
    +
    +
    +
    +
    + + + Cras justo odio + A simple Primary list group item + A simple Secondary list group item + A simple Success list group item + A simple Danger list group item + A simple Warning list group item + A simple Info list group item + A simple Light list group item + A simple Dark list group item +
    -
    -<abp-list-group flush="true">
    -    <abp-list-group-item type="Warning">Cras justo odio</abp-list-group-item>
    -    <abp-list-group-item type="Danger">Dapibus ac facilisis in</abp-list-group-item>
    -    <abp-list-group-item type="Success">Morbi leo risus <span abp-badge-pill="Success">42</span></abp-list-group-item>
    -    <abp-list-group-item type="Secondary">Vestibulum at eros <span abp-badge-pill="Warning">5</span></abp-list-group-item>
    +        
    +            
    +                
    
    +<abp-list-group>
    +    <abp-list-group-item href="#">Cras justo odio</abp-list-group-item>
    +    <abp-list-group-item href="#" type="Primary">A simple Primary list group item</abp-list-group-item>
    +    <abp-list-group-item href="#" type="Secondary">A simple Secondary list group item</abp-list-group-item>
    +    <abp-list-group-item href="#" type="Success">A simple Success list group item</abp-list-group-item>
    +    <abp-list-group-item href="#" type="Danger">A simple Danger list group item</abp-list-group-item>
    +    <abp-list-group-item href="#" type="Warning">A simple Warning list group item</abp-list-group-item>
    +    <abp-list-group-item href="#" type="Info">A simple Info list group item</abp-list-group-item>
    +    <abp-list-group-item href="#" type="Light">A simple Light list group item</abp-list-group-item>
    +    <abp-list-group-item href="#" type="Dark">A simple Dark list group item</abp-list-group-item>
    +</abp-list-group>
    +
    +
    + +
    
    +<div class="list-group">
    +  <a href="#" class="list-group-item list-group-item-action">Dapibus ac facilisis in</a>
    +  <a href="#" class="list-group-item list-group-item-action list-group-item-primary">A simple primary list group item</a>
    +  <a href="#" class="list-group-item list-group-item-action list-group-item-secondary">A simple secondary list group item</a>
    +  <a href="#" class="list-group-item list-group-item-action list-group-item-success">A simple success list group item</a>
    +  <a href="#" class="list-group-item list-group-item-action list-group-item-danger">A simple danger list group item</a>
    +  <a href="#" class="list-group-item list-group-item-action list-group-item-warning">A simple warning list group item</a>
    +  <a href="#" class="list-group-item list-group-item-action list-group-item-info">A simple info list group item</a>
    +  <a href="#" class="list-group-item list-group-item-action list-group-item-light">A simple light list group item</a>
    +  <a href="#" class="list-group-item list-group-item-action list-group-item-dark">A simple dark list group item</a>
    +</div>
    +
    +
    +
    +
    +
    + +

    With badges

    + +
    +
    + + + Cras justo odio 14 + Dapibus ac facilisis in 2 + Morbi leo risus 1 + +
    +
    + + +
    
    +<abp-list-group>
    +    <abp-list-group-item>Cras justo odio <span abp-badge-pill="Primary">14</span></abp-list-group-item>
    +    <abp-list-group-item>Dapibus ac facilisis in <span abp-badge-pill="Primary">2</span></abp-list-group-item>
    +    <abp-list-group-item>Morbi leo risus <span abp-badge-pill="Primary">1</span></abp-list-group-item>
     </abp-list-group>
    -
    + +
    + +
    
    +<ul class="list-group">
    +  <li class="list-group-item">
    +    Cras justo odio
    +    <span class="badge badge-primary badge-pill">14</span>
    +  </li>
    +  <li class="list-group-item">
    +    Dapibus ac facilisis in
    +    <span class="badge badge-primary badge-pill">2</span>
    +  </li>
    +  <li class="list-group-item">
    +    Morbi leo risus
    +    <span class="badge badge-primary badge-pill">1</span>
    +  </li>
    +</ul>
    +
    +
    +
    diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Modals.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Modals.cshtml index 0a3aa3d8b9..74116488ad 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Modals.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Modals.cshtml @@ -11,38 +11,81 @@ } +@section scripts { + + @* + *@ + +} + + + + + +

    Modals

    Based on Bootstrap Modal.

    -

    # Modal Example

    +

    Example

    - Launch modal - - - - + Launch modal + + - Body + Woohoo, you're reading this text in a modal! - - -
    -
    -<abp-modal id="myModal">
    -   <abp-modal-header title="Header"></abp-modal-header>
    +        
    +            
    +                
    
    +<abp-button button-type="Primary" data-toggle="modal" data-target="#myModal">Launch modal</abp-button>
    +
    +<abp-modal centered="true" size="Large" id="myModal">
    +   <abp-modal-header title="Modal title"></abp-modal-header>
        <abp-modal-body>
    -       Body
    +       Woohoo, you're reading this text in a modal!
        </abp-modal-body>
        <abp-modal-footer buttons="(AbpModalButtons.Save|AbpModalButtons.Close)"></abp-modal-footer>
     </abp-modal>
    -
    +
    + + +
    
    +<!-- Button trigger modal -->
    +<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
    +  Launch demo modal
    +</button>
    +
    +<!-- Modal -->
    +<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
    +  <div class="modal-dialog modal-dialog-centered modal-lg" role="document">
    +    <div class="modal-content">
    +      <div class="modal-header">
    +        <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
    +        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
    +          <span aria-hidden="true">&times;</span>
    +        </button>
    +      </div>
    +      <div class="modal-body">
    +        ...
    +      </div>
    +      <div class="modal-footer">
    +        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
    +        <button type="button" class="btn btn-primary">Save</button>
    +      </div>
    +    </div>
    +  </div>
    +</div>
    +
    +
    +
    diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Navs.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Navs.cshtml index d351878652..8adeabf964 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Navs.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Navs.cshtml @@ -10,18 +10,31 @@ } +@section scripts { + + @* + *@ + +} + + + + + +

    Navs

    Based on Bootstrap Navs.

    -

    # Navs Examples

    +

    Base nav

    - Active + Active Longer nav link @@ -33,29 +46,59 @@ disabled -
    -
    -        <abp-nav nav-style="Pill" align="Center">
    -            <abp-nav-item>
    -                <a abp-nav-link Active="true" href="#">Active</a>
    -            </abp-nav-item>
    -            <abp-nav-item >
    -                <a abp-nav-link  href="#">Longer nav link</a>
    -            </abp-nav-item>
    -            <abp-nav-item >
    -                <a abp-nav-link  href="#">link</a>
    -            </abp-nav-item>
    -            <abp-nav-item >
    -                <a abp-nav-link disabled="true" href="#">disabled</a>
    -            </abp-nav-item>
    -        </abp-nav>
    -
    + + +
    
    +
    +<abp-nav nav-style="Pill" align="Center">
    +    <abp-nav-item>
    +<a abp-nav-link active="true" href="#">Active</a>
    +    </abp-nav-item>
    +    <abp-nav-item>
    +<a abp-nav-link href="#">Longer nav link</a>
    +    </abp-nav-item>
    +    <abp-nav-item>
    +<a abp-nav-link href="#">link</a>
    +    </abp-nav-item>
    +    <abp-nav-item>
    +<a abp-nav-link disabled="true" href="#">disabled</a>
    +    </abp-nav-item>
    +</abp-nav>
    +
    +
    + +
    
    +<ul class="nav justify-content-center nav-pills">
    +   <li class="nav-item">
    +       <a href="#" class="nav-link active">Active</a>
    +   </li>
    +   <li class="nav-item">
    +       <a href="#" class="nav-link">Longer nav link</a>
    +   </li>
    +   <li class="nav-item">
    +       <a href="#" class="nav-link">link</a>
    +   </li>
    +   <li class="nav-item">
    +       <a href="#" class="nav-link disabled">disabled</a>
    +   </li>
    +</ul>
    +
    +
    +
    +
    + +
    +
      +
    • + For vertical nav, set nav-style "PillVertical". +
    • +
    -

    # Navs Examples

    +

    Base nav

    @@ -92,42 +135,85 @@ -
    -
    -        <abp-nav-bar size="Lg" navbar-style="Dark_Warning">
    -            <a abp-navbar-brand href="#">Navbar</a>
    -            <abp-navbar-toggle>
    -                <abp-navbar-nav>
    -                    <abp-nav-item active="true">
    -                        <a abp-nav-link href="#">Home <span class="sr-only">(current)</span></a>
    -                    </abp-nav-item>
    -                    <abp-nav-item>
    -                        <a abp-nav-link href="#">Link</a>
    -                    </abp-nav-item>
    -                    <abp-nav-item dropdown="true">
    -                        <abp-dropdown>
    -                            <abp-dropdown-button nav-link="true" text="Dropdown" />
    -                            <abp-dropdown-menu>
    -                                <abp-dropdown-header>Dropdown header</abp-dropdown-header>
    -                                <abp-dropdown-item href="#" active="true">Action</abp-dropdown-item>
    -                                <abp-dropdown-item href="#" disabled="true">Another disabled action</abp-dropdown-item>
    -                                <abp-dropdown-item href="#">Something else here</abp-dropdown-item>
    -                                <abp-dropdown-divider />
    -                                <abp-dropdown-item href="#">Separated link</abp-dropdown-item>
    -                            </abp-dropdown-menu>
    -                        </abp-dropdown>
    -                    </abp-nav-item>
    -                    <abp-nav-item>
    -                        <a abp-nav-link disabled="true" href="#">Disabled</a>
    -                    </abp-nav-item>
    -                </abp-navbar-nav>            
    -            <span abp-navbar-text>
    +        
    +            
    +                
    
    +
    +<abp-nav-bar size="Lg" navbar-style="Dark_Warning">
    +    <a abp-navbar-brand href="#">Navbar</a>
    +    <abp-navbar-toggle>
    +        <abp-navbar-nav>
    +            <abp-nav-item active="true">
    +                <a abp-nav-link href="#">Home <span class="sr-only">(current)</span></a>
    +            </abp-nav-item>
    +            <abp-nav-item>
    +                <a abp-nav-link href="#">Link</a>
    +            </abp-nav-item>
    +            <abp-nav-item dropdown="true">
    +                <abp-dropdown>
    +                    <abp-dropdown-button nav-link="true" text="Dropdown" />
    +                    <abp-dropdown-menu>
    +                        <abp-dropdown-header>Dropdown header</abp-dropdown-header>
    +                        <abp-dropdown-item href="#" active="true">Action</abp-dropdown-item>
    +                        <abp-dropdown-item href="#" disabled="true">Another disabled action</abp-dropdown-item>
    +                        <abp-dropdown-item href="#">Something else here</abp-dropdown-item>
    +                        <abp-dropdown-divider />
    +                        <abp-dropdown-item href="#">Separated link</abp-dropdown-item>
    +                    </abp-dropdown-menu>
    +                </abp-dropdown>
    +            </abp-nav-item>
    +            <abp-nav-item>
    +                <a abp-nav-link disabled="true" href="#">Disabled</a>
    +            </abp-nav-item>
    +        </abp-navbar-nav>            
    +        <span abp-navbar-text>
    +          Sample Text
    +        </span>
    +    </abp-navbar-toggle>
    +</abp-nav-bar>
    +
    +
    + +
    
    +<nav class="navbar navbar-expand-lg navbar-dark bg-warning">
    +    <a href="#" class="navbar-brand">Navbar</a>
    +    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#13da550319ec478099dd4c9c3efb3d09" aria-controls="13da550319ec478099dd4c9c3efb3d09" aria-expanded="false" aria-label="Toggle navigation">
    +    <span class="navbar-toggler-icon"></span>
    +    </button><div class="collapse navbar-collapse" id="13da550319ec478099dd4c9c3efb3d09">
    +        <ul class="navbar-nav">
    +            <li active="true" class="nav-item">
    +                <a href="#" class="nav-link">Home <span class="sr-only">(current)</span></a>
    +            </li>
    +            <li class="nav-item">
    +                <a href="#" class="nav-link">Link</a>
    +            </li>
    +            <li class="nav-item dropdown">
    +                <div class="btn-group">
    +                    <a class="dropdown-toggle btn nav-link" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-busy-text="Processing..." roles="button" href="#"><span>Dropdown</span></a>
    +                    <div></div>
    +                    <div class="dropdown-menu">
    +                        <h6 class="dropdown-header">Dropdown header</h6>
    +                        <a href="#" class="dropdown-item active">Action</a>
    +                        <a href="#" class="dropdown-item disabled">Another disabled action</a>
    +                        <a href="#" class="dropdown-item">Something else here</a>
    +                        <div class="dropdown-divider"></div>
    +                        <a href="#" class="dropdown-item">Separated link</a>
    +                    </div>
    +                </div>
    +            </li>
    +            <li class="nav-item">
    +                <a href="#" class="nav-link disabled">Disabled</a>
    +            </li>
    +            <span class="navbar-text">
                      Sample Text
                 </span>
    -            </abp-navbar-toggle>
    -        </abp-nav-bar>
    -
    + </ul> + </div> +</nav> +
    + +
    diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml index bcf117945c..be26fb5251 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml @@ -10,34 +10,99 @@ } -

    Paginator

    +@section scripts { + + @* + *@ + +} -

    # Paginator Examples

    + + + -
    -
    - +

    Paginator

    + + +

    Example

    -
    -
    -
    -<abp-paginator model="Model.PagerModel"/>
    -
    -
    -
    -
    -
    -
    - -
    -
    -<abp-paginator model="Model.PagerModel" show-info="true"/>
    -
    + + +
    
    +using Microsoft.AspNetCore.Mvc.RazorPages;
    +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination;
    +
    +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components
    +{
    +    public class PaginatorModel : PageModel
    +    {
    +        public PagerModel PagerModel { get; set; }
    +
    +        public void OnGet(int currentPage, string sort)
    +        {
    +            PagerModel = new PagerModel(100, 10, currentPage, 10, "Paginator", sort);
    +        }
    +    }
    +}
    +
    +
    + +
    
    +<abp-paginator model="Model.PagerModel" show-info="true" />
    +
    +
    + +
    
    +<div class="row mt-3">    
    +    <div class="col-sm-12 col-md-5">
    +        Showing 80 to 90 of 100 entries.
    +    </div>
    +    <div class="col-sm-12 col-md-7">
    +        <nav aria-label="Page navigation">
    +            <ul class="pagination justify-content-end">
    +                <li class="page-item ">
    +                    <a tabindex="-1" class="page-link" href="/Components/Paginator?currentPage=7">Previous</a>
    +                </li>
    +                <li class="page-item ">
    +                    <a tabindex="-1" class="page-link" href="/Components/Paginator?currentPage=1">1</a>
    +                </li>
    +                <li class="page-item ">
    +                    <a tabindex="-1" class="page-link" href="/Components/Paginator?currentPage=2">2</a>
    +                </li>
    +                <li class="page-item ">
    +                    <span class="page-link gap">…</span>
    +                </li>
    +                <li class="page-item ">
    +                    <a tabindex="-1" class="page-link" href="/Components/Paginator?currentPage=7">7</a>
    +                </li>
    +                <li class="page-item active">
    +                     <span class="page-link">
    +                        8
    +                        <span class="sr-only">(current)</span>
    +                     </span>
    +                </li>
    +                <li class="page-item ">
    +                    <a tabindex="-1" class="page-link" href="/Components/Paginator?currentPage=9">9</a>
    +                </li>
    +                <li class="page-item ">
    +                    <a tabindex="-1" class="page-link" href="/Components/Paginator?currentPage=10">10</a>
    +                </li>
    +                <li class="page-item ">
    +                    <a tabindex="-1" class="page-link" href="/Components/Paginator?currentPage=9">Next</a>
    +                </li>
    +            </ul>
    +         <!-- nav-->
    +    </nav></div>
    +</div>
    +
    +
    +
    -
    +
    \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml.cs index 40afff2016..15b31db6da 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.RazorPages; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Popovers.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Popovers.cshtml index f9563a5c8b..7f43407831 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Popovers.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Popovers.cshtml @@ -1,7 +1,7 @@ @page @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.PopoversModel @{ - ViewData["Title"] = "Badges"; + ViewData["Title"] = "Popovers"; } @section styles { @@ -10,11 +10,25 @@ } +@section scripts { + + @* + *@ + +} + + + + + +

    Popovers

    Based on Bootstrap Popovers.

    -

    # Popovers Examples

    + +

    Example

    @@ -31,23 +45,41 @@ Disabled Popover -
    -
    -<abp-button abp-popover="Hi, i'm popover content!">
    -   Popover Default
    +        
    +            
    +                
    
    +<abp-button abp-popover="Hi, i'm popover content!">
    +       Popover Default
     </abp-button>
    -<abp-button abp-popover-top="Hi, i'm popover content!" title="Popover Title">
    -   Popover With Title
    +<abp-button abp-popover-top="Hi, i'm popover content!" title="Popover Title">
    +       Popover With Title
     </abp-button>
    -<abp-button abp-popover-right="Hi, i'm popover content!" title="Popover Title" dismissible="true">
    -   Dismissible Popover
    +<abp-button abp-popover-right="Hi, i'm popover content!" title="Popover Title" dismissible="true">
    +       Dismissible Popover
     </abp-button>
    -<abp-button abp-popover-left="Hi, i'm popover content!" title="Popover Title" disabled="true">
    -   Disabled Popover
    +<abp-button abp-popover-left="Hi, i'm popover content!" title="Popover Title" disabled="true">
    +       Disabled Popover
     </abp-button>
    -
    +
    + + +
    
    +<button class="btn" type="button" data-busy-text="Processing..." data-toggle="popover" data-placement="bottom" data-content="Hi, i'm popover content!" data-original-title="" title="">
    +      Popover Default
    +</button>
    +<button title="" class="btn" type="button" data-busy-text="Processing..." data-toggle="popover" data-placement="top" data-content="Hi, i'm popover content!" data-original-title="Popover Title">
    +      Popover With Title
    +</button>
    +<button title="" class="btn" type="button" data-busy-text="Processing..." data-toggle="popover" data-placement="right" data-content="Hi, i'm popover content!" data-trigger="focus" data-original-title="Popover Title">
    +      Dismissible Popover
    +</button>
    +<span class="d-inline-block" title="" data-placement="left" data-toggle="popover" data-content="Hi, i'm popover content!" data-original-title="Popover Title"><button title="Popover Title" class="btn" type="button" data-busy-text="Processing..." style="pointer-events: none;">
    +      Disabled Popover
    +</button></span>
    +
    +
    +
    - diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ProgressBars.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ProgressBars.cshtml index 3e3e1e28e7..25f7f5b96e 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ProgressBars.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ProgressBars.cshtml @@ -14,65 +14,70 @@

    Based on Bootstrap Progress Bars.

    -

    # Progress Bar Examples

    + +

    Example

    - - - +
    - - - %25 - - + %25
    - - - - +
    - - - %50 - - + %50
    - - - - - %10 - - - - + + + %10 + +
    -
    -<abp-progress>
    -  <abp-progress-bar value="70"/>
    -</abp-progress>
    +        
    +            
    +                
    
    +<abp-progress-bar value="70" />
    +
    +<abp-progress-bar type="Warning" value="25"> %25 </abp-progress-bar>
    +
    +<abp-progress-bar type="Success" value="40" strip="true"/>
    +
    +<abp-progress-bar type="Dark" value="10" min-value="5" max-value="15" strip="true"> %50 </abp-progress-bar>
    +
    +<abp-progress-group>
    +    <abp-progress-part type="Success" value="25"/>
    +    <abp-progress-part type="Danger" value="10" strip="true"> %10 </abp-progress-part>
    +    <abp-progress-part type="Primary" value="50" animation="true" strip="true" />
    +</abp-progress-group>
    +
    +
    + +
    
    +<div class="progress">
    +    <div class="progress-bar" role="progressbar" style="width: 70%" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100"></div>
    +</div>
     
    -<abp-progress>
    -  <abp-progress-bar type="Warning" value="25">%25</abp-progress-bar>
    -</abp-progress>
    +<div class="progress">
    +    <div class="progress-bar bg-warning" role="progressbar" style="width: 25%" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"> %25 </div>
    +</div>
     
    -<abp-progress>
    -  <abp-progress-bar type="Success" value="40" strip="true"/>
    -</abp-progress>
    +<div class="progress">
    +    <div class="progress-bar progress-bar-striped bg-success" role="progressbar" style="width: 40%" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
    +</div>
     
    -<abp-progress>
    -  <abp-progress-bar type="Dark" value="10" min-value="5" max-value="15"  strip="true">%50</abp-progress-bar>
    -</abp-progress>
    +<div class="progress">
    +    <div class="progress-bar progress-bar-striped bg-dark" role="progressbar" style="width: 50%" aria-valuenow="10" aria-valuemin="5" aria-valuemax="15"> %50 </div>
    +</div>
     
    -<abp-progress>
    -  <abp-progress-bar type="Success" value="25"/>
    -  <abp-progress-bar type="Danger" value="10" strip="true">%10</abp-progress-bar>
    -  <abp-progress-bar type="Primary" value="50" animation="true" strip="true"/>
    -</abp-progress>
    -
    +<div class="progress"> + <div class="progress-bar bg-success" role="progressbar" style="width: 25%" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div> + <div class="progress-bar progress-bar-striped bg-danger" role="progressbar" style="width: 10%" aria-valuenow="10" aria-valuemin="0" aria-valuemax="100"> %10 </div> + <div class="progress-bar progress-bar-animated progress-bar-striped bg-primary" role="progressbar" style="width: 50%" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div> +</div> +
    + +
    diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tables.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tables.cshtml index 127cd61715..b77606f148 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tables.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tables.cshtml @@ -10,17 +10,30 @@ } +@section scripts { + + @* + *@ + +} + + + + + +

    Tables

    Based on Bootstrap Tables.

    -

    # Tables Examples

    +

    Examples

    - - + + # First @@ -33,9 +46,9 @@ 1 Mark Otto - mdo + mdo - + 2 Jacob Thornton @@ -43,46 +56,413 @@ 3 - Larry + Larry the Bird twitter -
    -
    -        <abp-table striped-rows="true" small="true" hoverable-rows="true" responsive-sm="true">
    -            <thead theme="Dark">
    +        
    +            
    +                
    
    +<abp-table hoverable-rows="true" responsive-sm="true">
    +    <thead>
    +    <tr>
    +        <th scope="Column">#</th>
    +        <th scope="Column">First</th>
    +        <th scope="Column">Last</th>
    +        <th scope="Column">Handle</th>
    +    </tr>
    +    </thead>
    +    <tbody>
    +    <tr>
    +        <th scope="Row">1</th>
    +        <td>Mark</td>
    +        <td>Otto</td>
    +        <td table-style="Danger">mdo</td>
    +    </tr>
    +    <tr table-style="Warning">
    +        <th scope="Row">2</th>
    +        <td>Jacob</td>
    +        <td>Thornton</td>
    +        <td>fat</td>
    +    </tr>
    +    <tr>
    +        <th scope="Row">3</th>
    +        <td table-style="Success">Larry</td>
    +        <td>the Bird</td>
    +        <td>twitter</td>
    +    </tr>
    +    </tbody>
    +</abp-table>
    +
    +
    + +
    
    +<div class="table-responsive-sm">
    +       <table class="table table-hover">
    +            <thead>
                 <tr>
    -                <th scope="Column">#</th>
    -                <th scope="Column">First</th>
    -                <th scope="Column">Last</th>
    -                <th scope="Column">Handle</th>
    +                <th scope="col">#</th>
    +                <th scope="col">First</th>
    +                <th scope="col">Last</th>
    +                <th scope="col">Handle</th>
                 </tr>
                 </thead>
                 <tbody>
                 <tr>
    -                <th scope="Row">1</th>
    +                <th scope="row">1</th>
                     <td>Mark</td>
                     <td>Otto</td>
    -                <td  abp-table-style="Danger">mdo</td>
    +                <td class="table-danger">mdo</td>
                 </tr>
    -            <tr abp-table-style="Warning">
    -                <th scope="Row">2</th>
    +            <tr class="table-warning">
    +                <th scope="row">2</th>
                     <td>Jacob</td>
                     <td>Thornton</td>
                     <td>fat</td>
                 </tr>
                 <tr>
    -                <th scope="Row">3</th>
    -                <td abp-table-style="Success">Larry</td>
    +                <th scope="row">3</th>
    +                <td class="table-success">Larry</td>
                     <td>the Bird</td>
                     <td>twitter</td>
                 </tr>
                 </tbody>
    -        </abp-table>
    -
    + </table> +</div> +
    + + +
    +
    + +
    +
    + + + + + # + First + Last + Handle + + + + + 1 + Mark + Otto + mdo + + + 2 + Jacob + Thornton + fat + + + 3 + Larry + the Bird + twitter + + + +
    +
    + + +
    
    +<abp-table small="true" striped-rows="true" border-style="Bordered">
    +    <thead Theme="Dark">
    +        <tr>
    +            <th scope="Column">#</th>
    +            <th scope="Column">First</th>
    +            <th scope="Column">Last</th>
    +            <th scope="Column">Handle</th>
    +        </tr>
    +    </thead>
    +    <tbody>
    +        <tr>
    +            <th scope="Row">1</th>
    +            <td>Mark</td>
    +            <td>Otto</td>
    +            <td>mdo</td>
    +        </tr>
    +        <tr>
    +            <th scope="Row">2</th>
    +            <td>Jacob</td>
    +            <td>Thornton</td>
    +            <td>fat</td>
    +        </tr>
    +        <tr>
    +            <th scope="Row">3</th>
    +            <td>Larry</td>
    +            <td>the Bird</td>
    +            <td>twitter</td>
    +        </tr>
    +    </tbody>
    +</abp-table>
    +
    +
    + +
    
    +<table class="table table-sm table-striped table-bordered">
    +    <thead class="thead-dark">
    +        <tr>
    +            <th scope="col">#</th>
    +            <th scope="col">First</th>
    +            <th scope="col">Last</th>
    +            <th scope="col">Handle</th>
    +        </tr>
    +    </thead>
    +    <tbody>
    +        <tr>
    +            <th scope="row">1</th>
    +            <td>Mark</td>
    +            <td>Otto</td>
    +            <td>mdo</td>
    +        </tr>
    +        <tr>
    +            <th scope="row">2</th>
    +            <td>Jacob</td>
    +            <td>Thornton</td>
    +            <td>fat</td>
    +        </tr>
    +        <tr>
    +            <th scope="row">3</th>
    +            <td>Larry</td>
    +            <td>the Bird</td>
    +            <td>twitter</td>
    +        </tr>
    +    </tbody>
    +</table>
    +
    +
    +
    +
    +
    + +
    +
    + + + List of users + + + # + First + Last + Handle + + + + + 1 + Mark + Otto + mdo + + + 2 + Jacob + Thornton + fat + + + 3 + Larry + the Bird + twitter + + + +
    +
    + + +
    
    +<abp-table striped-rows="true" dark-theme="true">
    +    <caption>List of users</caption>
    +    <thead>
    +        <tr>
    +            <th scope="Column">#</th>
    +            <th scope="Column">First</th>
    +            <th scope="Column">Last</th>
    +            <th scope="Column">Handle</th>
    +        </tr>
    +    </thead>
    +    <tbody>
    +        <tr>
    +            <th scope="Row">1</th>
    +            <td>Mark</td>
    +            <td>Otto</td>
    +            <td>mdo</td>
    +        </tr>
    +        <tr>
    +            <th scope="Row">2</th>
    +            <td>Jacob</td>
    +            <td>Thornton</td>
    +            <td>fat</td>
    +        </tr>
    +        <tr>
    +            <th scope="Row">3</th>
    +            <td>Larry</td>
    +            <td>the Bird</td>
    +            <td>twitter</td>
    +        </tr>
    +    </tbody>
    +</abp-table>
    +
    +
    + +
    
    +<table class="table table-dark table-striped">
    +    <caption>List of users</caption>
    +    <thead>
    +        <tr>
    +            <th scope="col">#</th>
    +            <th scope="col">First</th>
    +            <th scope="col">Last</th>
    +            <th scope="col">Handle</th>
    +        </tr>
    +    </thead>
    +    <tbody>
    +        <tr>
    +            <th scope="row">1</th>
    +            <td>Mark</td>
    +            <td>Otto</td>
    +            <td>mdo</td>
    +        </tr>
    +        <tr>
    +            <th scope="row">2</th>
    +            <td>Jacob</td>
    +            <td>Thornton</td>
    +            <td>fat</td>
    +        </tr>
    +        <tr>
    +            <th scope="row">3</th>
    +            <td>Larry</td>
    +            <td>the Bird</td>
    +            <td>twitter</td>
    +        </tr>
    +    </tbody>
    +</table>
    +
    +
    +
    +
    +
    + + +
    +
    + + + + + # + First + Last + Handle + + + + + 1 + Mark + Otto + mdo + + + 2 + Jacob + Thornton + fat + + + 3 + Larry + the Bird + twitter + + + +
    +
    + + +
    
    +<abp-table border-style="Borderless">
    +    <thead>
    +        <tr>
    +            <th scope="Column">#</th>
    +            <th scope="Column">First</th>
    +            <th scope="Column">Last</th>
    +            <th scope="Column">Handle</th>
    +        </tr>
    +    </thead>
    +    <tbody>
    +        <tr>
    +            <th scope="Row">1</th>
    +            <td>Mark</td>
    +            <td>Otto</td>
    +            <td>mdo</td>
    +        </tr>
    +        <tr>
    +            <th scope="Row">2</th>
    +            <td>Jacob</td>
    +            <td>Thornton</td>
    +            <td>fat</td>
    +        </tr>
    +        <tr>
    +            <th scope="Row">3</th>
    +            <td>Larry</td>
    +            <td>the Bird</td>
    +            <td>twitter</td>
    +        </tr>
    +    </tbody>
    +</abp-table>
    +
    +
    + +
    
    +<table class="table table-borderless">
    +    <thead>
    +        <tr>
    +            <th scope="col">#</th>
    +            <th scope="col">First</th>
    +            <th scope="col">Last</th>
    +            <th scope="col">Handle</th>
    +        </tr>
    +    </thead>
    +    <tbody>
    +        <tr>
    +            <th scope="row">1</th>
    +            <td>Mark</td>
    +            <td>Otto</td>
    +            <td>mdo</td>
    +        </tr>
    +        <tr>
    +            <th scope="row">2</th>
    +            <td>Jacob</td>
    +            <td>Thornton</td>
    +            <td>fat</td>
    +        </tr>
    +        <tr>
    +            <th scope="row">3</th>
    +            <td>Larry</td>
    +            <td>the Bird</td>
    +            <td>twitter</td>
    +        </tr>
    +    </tbody>
    +</table>
    +
    +
    +
    diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tabs.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tabs.cshtml index c2c17a389d..367fe710b2 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tabs.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tabs.cshtml @@ -10,19 +10,33 @@ } +@section scripts { + + @* + *@ + +} + + + + + +

    Tabs

    Based on Bootstrap tab.

    -

    # Most Simple Tabs Example

    +

    Example

    + Content_Home - + Content_Profile @@ -37,14 +51,16 @@
    -
    -<abp-tabs name="TabId">
    +        
    +            
    +                
    
    +<abp-tabs>
         <abp-tab title="Home">
    -        Content_Home
    -    </abp-tab>   
    -    <abp-tab-link title="Link" name="LinkId" href="#"/>
    +             Content_Home
    +    </abp-tab>
    +    <abp-tab-link title="Link" href="#" />
         <abp-tab title="profile">
    -        Content_Profile
    +            Content_Profile
         </abp-tab>
         <abp-tab-dropdown title="Contact" name="ContactDropdown">
             <abp-tab title="Contact 1" parent-dropdown-name="ContactDropdown">
    @@ -55,11 +71,44 @@
             </abp-tab>
         </abp-tab-dropdown>
     </abp-tabs>
    -
    +
    + + +
    
    +<div>
    +    <ul class="nav nav-tabs" id="48c14227782f4edab7f153b413ac1429" role="tablist">
    +        <li class="nav-item"><a class="nav-link active" id="48c14227782f4edab7f153b413ac1429_0-tab" data-toggle="tab" href="#48c14227782f4edab7f153b413ac1429_0" role="tab" aria-controls="48c14227782f4edab7f153b413ac1429_0" aria-selected="true">Home</a></li>
    +        <li class="nav-item"><a class="nav-link" id="LinkId-tab" href="#">Link</a></li>
    +        <li class="nav-item"><a class="nav-link" id="48c14227782f4edab7f153b413ac1429_2-tab" data-toggle="tab" href="#48c14227782f4edab7f153b413ac1429_2" role="tab" aria-controls="48c14227782f4edab7f153b413ac1429_2" aria-selected="false">profile</a></li>
    +        <li class="nav-item dropdown">
    +            <a class="nav-link dropdown-toggle" id="ContactDropdown-tab" data-toggle="dropdown" href="#ContactDropdown" role="button" aria-haspopup="true" aria-expanded="false">Contact</a><div class="dropdown-menu">
    +                <a class="dropdown-item" id="48c14227782f4edab7f153b413ac1429_3-tab" href="#48c14227782f4edab7f153b413ac1429_3" data-toggle="tab" role="tab" aria-controls="48c14227782f4edab7f153b413ac1429_3" aria-selected="false">Contact 1</a>
    +                <a class="dropdown-item" id="48c14227782f4edab7f153b413ac1429_4-tab" href="#48c14227782f4edab7f153b413ac1429_4" data-toggle="tab" role="tab" aria-controls="48c14227782f4edab7f153b413ac1429_4" aria-selected="false">Contact 2</a>
    +            </div>
    +        </li>
    +    </ul>
    +    <div class="tab-content" id="48c14227782f4edab7f153b413ac1429Content">
    +        <div class="tab-pane fade show active" id="48c14227782f4edab7f153b413ac1429_0" role="tabpanel" aria-labelledby="48c14227782f4edab7f153b413ac1429_0-tab">
    +              Content_Home
    +        </div>
    +        <div class="tab-pane fade" id="48c14227782f4edab7f153b413ac1429_2" role="tabpanel" aria-labelledby="48c14227782f4edab7f153b413ac1429_2-tab">
    +              Content_Profile
    +        </div>
    +        <div class="tab-pane fade" id="48c14227782f4edab7f153b413ac1429_3" role="tabpanel" aria-labelledby="48c14227782f4edab7f153b413ac1429_3-tab">
    +              Content_1_Content
    +        </div>
    +        <div class="tab-pane fade" id="48c14227782f4edab7f153b413ac1429_4" role="tabpanel" aria-labelledby="48c14227782f4edab7f153b413ac1429_4-tab">
    +              Content_2_Content
    +        </div>
    +    </div>
    +</div>
    +
    +
    +
    -

    # Tabs With Name Attiribute Example

    +

    Tab attributes

    @@ -76,7 +125,9 @@
    -
    +        
    +            
    +                
    
     <abp-tabs name="TabId">
         <abp-tab name="nav-home" title="Home">
             Content_Home
    @@ -88,16 +139,50 @@
             Content_Contact
         </abp-tab>
     </abp-tabs>
    -
    +
    + + +
    
    +<div>
    +    <ul class="nav nav-tabs" id="TabId" role="tablist">
    +        <li class="nav-item"><a class="nav-link" id="nav-home-tab" data-toggle="tab" href="#nav-home" role="tab" aria-controls="nav-home" aria-selected="false">Home</a></li>
    +        <li class="nav-item"><a class="nav-link" id="nav-profile-tab" data-toggle="tab" href="#nav-profile" role="tab" aria-controls="nav-profile" aria-selected="false">profile</a></li>
    +        <li class="nav-item"><a class="nav-link active show" id="nav-contact-tab" data-toggle="tab" href="#nav-contact" role="tab" aria-controls="nav-contact" aria-selected="true">Contact</a></li>
    +    </ul>
    +    <div class="tab-content" id="TabIdContent">
    +        <div class="tab-pane fade" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab">
    +             Content_Home
    +        </div>
    +        <div class="tab-pane fade" id="nav-profile" role="tabpanel" aria-labelledby="nav-profile-tab">
    +             Content_Profile
    +        </div>
    +        <div class="tab-pane fade active show" id="nav-contact" role="tabpanel" aria-labelledby="nav-contact-tab">
    +             Content_Contact
    +        </div>
    +    </div>
    +</div>
    +
    +
    + +
    +
    +
      +
    • + name: Sets "id" attribute of generated elements. Default value is a Guid. Not needed unless tabs are changed or modified with Jquery. +
    • +
    • + active: Sets the active tab. +
    • +
    -

    # Pill Example

    +

    Pill Example

    - + Content_Home @@ -109,28 +194,56 @@
    -
    -<abp-tabs tab-style="Pill" >
    -    <abp-tab active="true" title="Home">
    -        Content_Home
    -    </abp-tab>   
    +        
    +            
    +                
    
    +<abp-tabs tab-style="Pill">
    +    <abp-tab title="Home">
    +         Content_Home
    +    </abp-tab>
         <abp-tab title="profile">
    -        Content_Profile
    +         Content_Profile
         </abp-tab>
         <abp-tab title="Contact">
    -        Content_Contact
    +         Content_Contact
         </abp-tab>
     </abp-tabs>
    -
    + +
    + + +
    
    +<div>
    +    <ul class="nav nav-pills" id="2eaad131e42c4a90962fcb3c4e55c946" role="tablist">
    +        <li class="nav-item"><a class="nav-link active" id="2eaad131e42c4a90962fcb3c4e55c946_0-tab" data-toggle="pill" href="#2eaad131e42c4a90962fcb3c4e55c946_0" role="tab" aria-controls="2eaad131e42c4a90962fcb3c4e55c946_0" aria-selected="true">Home</a></li>
    +        <li class="nav-item"><a class="nav-link" id="2eaad131e42c4a90962fcb3c4e55c946_1-tab" data-toggle="pill" href="#2eaad131e42c4a90962fcb3c4e55c946_1" role="tab" aria-controls="2eaad131e42c4a90962fcb3c4e55c946_1" aria-selected="false">profile</a></li>
    +        <li class="nav-item"><a class="nav-link" id="2eaad131e42c4a90962fcb3c4e55c946_2-tab" data-toggle="pill" href="#2eaad131e42c4a90962fcb3c4e55c946_2" role="tab" aria-controls="2eaad131e42c4a90962fcb3c4e55c946_2" aria-selected="false">Contact</a></li>
    +    </ul>
    +    <div class="tab-content" id="2eaad131e42c4a90962fcb3c4e55c946Content">
    +        <div class="tab-pane fade show active" id="2eaad131e42c4a90962fcb3c4e55c946_0" role="tabpanel" aria-labelledby="2eaad131e42c4a90962fcb3c4e55c946_0-tab">
    +               Content_Home
    +        </div>
    +        <div class="tab-pane fade" id="2eaad131e42c4a90962fcb3c4e55c946_1" role="tabpanel" aria-labelledby="2eaad131e42c4a90962fcb3c4e55c946_1-tab">
    +               Content_Profile
    +        </div>
    +        <div class="tab-pane fade" id="2eaad131e42c4a90962fcb3c4e55c946_2" role="tabpanel" aria-labelledby="2eaad131e42c4a90962fcb3c4e55c946_2-tab">
    +               Content_Contact
    +        </div>
    +    </div>
    +</div>
    +
    +
    +
    +
    -

    # Vertical Example

    +

    Vertical Example

    - + Content_Home @@ -142,8 +255,10 @@
    -
    -<abp-tabs name="TabId"  tab-style="Pill" vertical-header-size="_2" >
    +        
    +            
    +                
    
    +<abp-tabs tab-style="PillVertical" vertical-header-size="_2" >
         <abp-tab active="true" title="Home">
             Content_Home
         </abp-tab>   
    @@ -154,6 +269,44 @@
             Content_Contact
         </abp-tab>
     </abp-tabs>
    -
    + +
    + + +
    
    +<div class="row">
    +    <div class="col-2">
    +        <ul class="nav flex-column  nav-pills" id="2f347a2276af424ebbd67f85653edf1f" role="tablist">
    +            <li class="nav-item"><a class="nav-link active" id="2f347a2276af424ebbd67f85653edf1f_0-tab" data-toggle="pill" href="#2f347a2276af424ebbd67f85653edf1f_0" role="tab" aria-controls="2f347a2276af424ebbd67f85653edf1f_0" aria-selected="true">Home</a></li>
    +            <li class="nav-item"><a class="nav-link" id="2f347a2276af424ebbd67f85653edf1f_1-tab" data-toggle="pill" href="#2f347a2276af424ebbd67f85653edf1f_1" role="tab" aria-controls="2f347a2276af424ebbd67f85653edf1f_1" aria-selected="false">profile</a></li>
    +            <li class="nav-item"><a class="nav-link" id="2f347a2276af424ebbd67f85653edf1f_2-tab" data-toggle="pill" href="#2f347a2276af424ebbd67f85653edf1f_2" role="tab" aria-controls="2f347a2276af424ebbd67f85653edf1f_2" aria-selected="false">Contact</a></li>
    +        </ul>
    +    </div>
    +    <div class="col-10">
    +        <div class="tab-content" id="2f347a2276af424ebbd67f85653edf1fContent">
    +            <div class="tab-pane fade show active" id="2f347a2276af424ebbd67f85653edf1f_0" role="tabpanel" aria-labelledby="2f347a2276af424ebbd67f85653edf1f_0-tab">
    +                 Content_Home
    +            </div>
    +            <div class="tab-pane fade" id="2f347a2276af424ebbd67f85653edf1f_1" role="tabpanel" aria-labelledby="2f347a2276af424ebbd67f85653edf1f_1-tab">
    +                 Content_Profile
    +            </div>
    +            <div class="tab-pane fade" id="2f347a2276af424ebbd67f85653edf1f_2" role="tabpanel" aria-labelledby="2f347a2276af424ebbd67f85653edf1f_2-tab">
    +                 Content_Contact
    +            </div>
    +        </div>
    +    </div>
    +</div>
    +
    +
    +
    +
    -
    + +
    +
      +
    • + vertical-header-size: Sets the column width of tab headers. +
    • +
    +
    +
    \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tooltips.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tooltips.cshtml index fe0aeebae4..a5bc9f27db 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tooltips.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tooltips.cshtml @@ -1,7 +1,7 @@ @page @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.TooltipsModel @{ - ViewData["Title"] = "Badges"; + ViewData["Title"] = "Tooltips"; } @section styles { @@ -14,46 +14,77 @@

    Based on Bootstrap Tooltips.

    -

    # Tooltips Examples

    +

    Example

    - + Tooltip Default - + Tooltip on top - + Tooltip on right - + Tooltip on bottom - - Tooltip on left + + Disabled button Tooltip -
    -
    -<abp-button  abp-tooltip="Tooltip Default">
    -  Tooltip Default
    +        
    +            
    +                
    
    +<abp-button abp-tooltip="Tooltip">
    +      Tooltip Default
     </abp-button>
    -<abp-button abp-tooltip-top="Tooltip on top">
    -   Tooltip on top
    +
    +<abp-button abp-tooltip-top="Tooltip">
    +      Tooltip on top
     </abp-button>
    -<abp-button abp-tooltip-right="Tooltip on right">
    -  Tooltip on right
    +
    +<abp-button abp-tooltip-right="Tooltip">
    +      Tooltip on right
     </abp-button>
    -<abp-button abp-tooltip-bottom="Tooltip on bottom">
    -  Tooltip on bottom
    +
    +<abp-button abp-tooltip-bottom="Tooltip">
    +      Tooltip on bottom
     </abp-button>
    -<abp-button abp-tooltip-left="Tooltip on left">
    -  Tooltip on left
    +
    +<abp-button disabled="true" abp-tooltip="Tooltip">
    +      Disabled button Tooltip
     </abp-button>
    -
    +
    + + +
    
    +<button class="btn" type="button" data-busy-text="Processing..." data-toggle="tooltip" data-placement="top" title="" data-original-title="Tooltip">
    +    Tooltip Default
    +</button>
    +
    +<button class="btn" type="button" data-busy-text="Processing..." data-toggle="tooltip" data-placement="top" title="" data-original-title="Tooltip">
    +    Tooltip on top
    +</button>
    +
    +<button class="btn" type="button" data-busy-text="Processing..." data-toggle="tooltip" data-placement="right" title="" data-original-title="Tooltip">
    +     Tooltip on right
    +</button>
    +
    +<button class="btn" type="button" data-busy-text="Processing..." data-toggle="tooltip" data-placement="bottom" title="" data-original-title="Tooltip">
    +    Tooltip on bottom
    +</button>
    +
    +<span class="d-inline-block" tabindex="0" data-toggle="tooltip" data-placement="top" title="" data-original-title="Tooltip">
    +    <button class="btn" disabled="disabled" type="button" data-busy-text="Processing..." data-placement="top" style="pointer-events: none;">
    +        Disabled button Tooltip
    +    </button>
    +</span>
    +
    +
    +
    - diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/highlightCode.js b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/highlightCode.js new file mode 100644 index 0000000000..a20784d518 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/highlightCode.js @@ -0,0 +1,5 @@ +$(document).ready(function () { + $('pre code').each(function (i, block) { + hljs.highlightBlock(block); + }); +}); \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Index.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Index.cshtml index 9164ee5d87..6888267210 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Index.cshtml +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Index.cshtml @@ -7,27 +7,28 @@

    Components

    diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj index cdb3e11d54..e6843fd726 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp2.2 $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo @@ -17,8 +17,8 @@ - - + + diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/abp.resourcemapping.js b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/abp.resourcemapping.js index 8f527171c0..d4d18c1f07 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/abp.resourcemapping.js +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/abp.resourcemapping.js @@ -7,6 +7,6 @@ "@libs" ], mappings: { - + "@node_modules/highlight.js/**/*.*": "@libs/highlight.js/" } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json index 8e2fcccc97..29e8cca7cb 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json @@ -3,8 +3,8 @@ "name": "asp.net", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.shared": "^0.4.3" + "@abp/aspnetcore.mvc.ui.theme.shared": "^0.4.3", + "highlight.js": "^9.13.1" }, - "devDependencies": { - } -} \ No newline at end of file + "devDependencies": {} +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.css b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.css index c207771001..297eea1679 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.css +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.css @@ -2,9 +2,17 @@ padding-bottom: 10px; margin-bottom: 10px; } .demo-with-code .demo-area { + margin-top: 20px; margin-bottom: 1em; } + .demo-with-code .grid .col { + background: #ffc9c9; + border: 1.5px solid #000000; } + .demo-with-code .large-row .row { + min-height: 10rem; + background: #fcdede; + margin-top: 1rem; } .demo-with-code .code-area { border: 1px solid #ddd; padding: 10px; + margin-top: 10px; font-size: 0.9em; } - diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.min.css b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.min.css index 6721b78939..87e8a549a8 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.min.css +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.min.css @@ -1 +1 @@ -.demo-with-code{padding-bottom:10px;margin-bottom:10px;}.demo-with-code .demo-area{margin-bottom:1em;}.demo-with-code .code-area{border:1px solid #ddd;padding:10px;font-size:.9em;} \ No newline at end of file +.demo-with-code{padding-bottom:10px;margin-bottom:10px;}.demo-with-code .demo-area{margin-top:20px;margin-bottom:1em;}.demo-with-code .grid .col{background:#ffc9c9;border:1.5px solid #000;}.demo-with-code .large-row .row{min-height:10rem;background:#fcdede;margin-top:1rem;}.demo-with-code .code-area{border:1px solid #ddd;padding:10px;margin-top:10px;font-size:.9em;} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.scss b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.scss index c9c78fa28b..04e085f22e 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.scss +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/css/demo.scss @@ -7,6 +7,17 @@ margin-bottom: 1em; } + .grid .col { + background: #ffc9c9; + border: 1.5px solid #000000; + } + + .large-row .row { + min-height: 10rem; + background: #fcdede; + margin-top: 1rem; + } + .code-area { border: 1px solid #ddd; padding: 10px; diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/README.md b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/README.md new file mode 100644 index 0000000000..6cf523594c --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/README.md @@ -0,0 +1,186 @@ +# Highlight.js + +[![Build Status](https://travis-ci.org/highlightjs/highlight.js.svg?branch=master)](https://travis-ci.org/highlightjs/highlight.js) + +Highlight.js is a syntax highlighter written in JavaScript. It works in +the browser as well as on the server. It works with pretty much any +markup, doesn’t depend on any framework, and has automatic language +detection. + +## Getting Started + +The bare minimum for using highlight.js on a web page is linking to the +library along with one of the styles and calling +[`initHighlightingOnLoad`][1]: + +```html + + + +``` + +This will find and highlight code inside of `
    ` tags; it tries
    +to detect the language automatically. If automatic detection doesn’t
    +work for you, you can specify the language in the `class` attribute:
    +
    +```html
    +
    ...
    +``` + +The list of supported language classes is available in the [class +reference][2]. Classes can also be prefixed with either `language-` or +`lang-`. + +To make arbitrary text look like code, but without highlighting, use the +`plaintext` class: + +```html +
    ...
    +``` + +To disable highlighting altogether use the `nohighlight` class: + +```html +
    ...
    +``` + +## Custom Initialization + +When you need a bit more control over the initialization of +highlight.js, you can use the [`highlightBlock`][3] and [`configure`][4] +functions. This allows you to control *what* to highlight and *when*. + +Here’s an equivalent way to calling [`initHighlightingOnLoad`][1] using +jQuery: + +```javascript +$(document).ready(function() { + $('pre code').each(function(i, block) { + hljs.highlightBlock(block); + }); +}); +``` + +You can use any tags instead of `
    ` to mark up your code. If
    +you don't use a container that preserves line breaks you will need to
    +configure highlight.js to use the `
    ` tag: + +```javascript +hljs.configure({useBR: true}); + +$('div.code').each(function(i, block) { + hljs.highlightBlock(block); +}); +``` + +For other options refer to the documentation for [`configure`][4]. + + +## Web Workers + +You can run highlighting inside a web worker to avoid freezing the browser +window while dealing with very big chunks of code. + +In your main script: + +```javascript +addEventListener('load', function() { + var code = document.querySelector('#code'); + var worker = new Worker('worker.js'); + worker.onmessage = function(event) { code.innerHTML = event.data; } + worker.postMessage(code.textContent); +}) +``` + +In worker.js: + +```javascript +onmessage = function(event) { + importScripts('/highlight.pack.js'); + var result = self.hljs.highlightAuto(event.data); + postMessage(result.value); +} +``` + + +## Getting the Library + +You can get highlight.js as a hosted, or custom-build, browser script or +as a server module. Right out of the box the browser script supports +both AMD and CommonJS, so if you wish you can use RequireJS or +Browserify without having to build from source. The server module also +works perfectly fine with Browserify, but there is the option to use a +build specific to browsers rather than something meant for a server. +Head over to the [download page][5] for all the options. + +**Don't link to GitHub directly.** The library is not supposed to work straight +from the source, it requires building. If none of the pre-packaged options +work for you refer to the [building documentation][6]. + +**The CDN-hosted package doesn't have all the languages.** Otherwise it'd be +too big. If you don't see the language you need in the ["Common" section][5], +it can be added manually: + +```html + +``` + +**On Almond.** You need to use the optimizer to give the module a name. For +example: + +``` +r.js -o name=hljs paths.hljs=/path/to/highlight out=highlight.js +``` + + +### CommonJS + +You can import Highlight.js as a CommonJS-module: + +```bash +npm install highlight.js --save +``` + +In your application: + +```javascript +import hljs from 'highlight.js'; +``` + +The default import imports all languages! Therefore it is likely to be more efficient to import only the library and the languages you need: + +```javascript +import hljs from 'highlight.js/lib/highlight'; +import javascript from 'highlight.js/lib/languages/javascript'; +hljs.registerLanguage('javascript', javascript); +``` + +To set the syntax highlighting style, if your build tool processes CSS from your JavaScript entry point, you can import the stylesheet directly into your CommonJS-module: + +```javascript +import hljs from 'highlight.js/lib/highlight'; +import 'highlight.js/styles/github.css' +``` + +## License + +Highlight.js is released under the BSD License. See [LICENSE][7] file +for details. + +## Links + +The official site for the library is at . + +Further in-depth documentation for the API and other topics is at +. + +Authors and contributors are listed in the [AUTHORS.en.txt][8] file. + +[1]: http://highlightjs.readthedocs.io/en/latest/api.html#inithighlightingonload +[2]: http://highlightjs.readthedocs.io/en/latest/css-classes-reference.html +[3]: http://highlightjs.readthedocs.io/en/latest/api.html#highlightblock-block +[4]: http://highlightjs.readthedocs.io/en/latest/api.html#configure-options +[5]: https://highlightjs.org/download/ +[6]: http://highlightjs.readthedocs.io/en/latest/building-testing.html +[7]: https://github.com/highlightjs/highlight.js/blob/master/LICENSE +[8]: https://github.com/highlightjs/highlight.js/blob/master/AUTHORS.en.txt diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/api.rst b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/api.rst new file mode 100644 index 0000000000..d8039539d3 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/api.rst @@ -0,0 +1,120 @@ +Library API +=========== + +Highlight.js exports a few functions as methods of the ``hljs`` object. + + +``highlight(name, value, ignore_illegals, continuation)`` +--------------------------------------------------------- + +Core highlighting function. +Accepts a language name, or an alias, and a string with the code to highlight. +The ``ignore_illegals`` parameter, when present and evaluates to a true value, +forces highlighting to finish even in case of detecting illegal syntax for the +language instead of throwing an exception. +The ``continuation`` is an optional mode stack representing unfinished parsing. +When present, the function will restart parsing from this state instead of +initializing a new one. +Returns an object with the following properties: + +* ``language``: language name, same as the one passed into a function, returned for consistency with ``highlightAuto`` +* ``relevance``: integer value +* ``value``: HTML string with highlighting markup +* ``top``: top of the current mode stack + + +``highlightAuto(value, languageSubset)`` +---------------------------------------- + +Highlighting with language detection. +Accepts a string with the code to highlight and an optional array of language names and aliases restricting detection to only those languages. The subset can also be set with ``configure``, but the local parameter overrides the option if set. +Returns an object with the following properties: + +* ``language``: detected language +* ``relevance``: integer value +* ``value``: HTML string with highlighting markup +* ``second_best``: object with the same structure for second-best heuristically detected language, may be absent + + +``fixMarkup(value)`` +-------------------- + +Post-processing of the highlighted markup. Currently consists of replacing indentation TAB characters and using ``
    `` tags instead of new-line characters. Options are set globally with ``configure``. + +Accepts a string with the highlighted markup. + + +``highlightBlock(block)`` +------------------------- + +Applies highlighting to a DOM node containing code. + +This function is the one to use to apply highlighting dynamically after page load +or within initialization code of third-party Javascript frameworks. + +The function uses language detection by default but you can specify the language +in the ``class`` attribute of the DOM node. See the :doc:`class reference +` for all available language names and aliases. + + +``configure(options)`` +---------------------- + +Configures global options: + +* ``tabReplace``: a string used to replace TAB characters in indentation. +* ``useBR``: a flag to generate ``
    `` tags instead of new-line characters in the output, useful when code is marked up using a non-``
    `` container.
    +* ``classPrefix``: a string prefix added before class names in the generated markup, used for backwards compatibility with stylesheets.
    +* ``languages``: an array of language names and aliases restricting auto detection to only these languages.
    +
    +Accepts an object representing options with the values to updated. Other options don't change
    +::
    +
    +  hljs.configure({
    +    tabReplace: '    ', // 4 spaces
    +    classPrefix: ''     // don't append class prefix
    +                        // … other options aren't changed
    +  })
    +  hljs.initHighlighting();
    +
    +
    +``initHighlighting()``
    +----------------------
    +
    +Applies highlighting to all ``
    ..
    `` blocks on a page. + + + +``initHighlightingOnLoad()`` +---------------------------- + +Attaches highlighting to the page load event. + + +``registerLanguage(name, language)`` +------------------------------------ + +Adds new language to the library under the specified name. Used mostly internally. + +* ``name``: a string with the name of the language being registered +* ``language``: a function that returns an object which represents the + language definition. The function is passed the ``hljs`` object to be able + to use common regular expressions defined within it. + + +``listLanguages()`` +---------------------------- + +Returns the languages names list. + + + +.. _getLanguage: + + +``getLanguage(name)`` +--------------------- + +Looks up a language by name or alias. + +Returns the language object if found, ``undefined`` otherwise. diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/building-testing.rst b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/building-testing.rst new file mode 100644 index 0000000000..16292cb84a --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/building-testing.rst @@ -0,0 +1,88 @@ +Building and testing +==================== + +To actually run highlight.js it is necessary to build it for the environment +where you're going to run it: a browser, the node.js server, etc. + + +Building +-------- + +The build tool is written in JavaScript using node.js. Before running the +script, make sure to have node installed and run ``npm install`` to get the +dependencies. + +The tool is located in ``tools/build.js``. A few useful examples: + +* Build for a browser using only common languages:: + + node tools/build.js :common + +* Build for node.js including all available languages:: + + node tools/build.js -t node + +* Build two specific languages for debugging, skipping compression in this case:: + + node tools/build.js -n python ruby + +On some systems the node binary is named ``nodejs``; simply replace ``node`` +with ``nodejs`` in the examples above if that is the case. + +The full option reference is available with the usual ``--help`` option. + +The build result will be in the ``build/`` directory. + +.. _basic-testing: + +Basic testing +------------- + +The usual approach to debugging and testing a language is first doing it +visually. You need to build highlight.js with only the language you're working +on (without compression, to have readable code in browser error messages) and +then use the Developer tool in ``tools/developer.html`` to see how it highlights +a test snippet in that language. + +A test snippet should be short and give the idea of the overall look of the +language. It shouldn't include every possible syntactic element and shouldn't +even make practical sense. + +After you satisfied with the result you need to make sure that language +detection still works with your language definition included in the whole suite. + +Testing is done using `Mocha `_ and the +files are found in the ``test/`` directory. You can use the node build to +run the tests in the command line with ``npm test`` after installing the +dependencies with ``npm install``. + +**Note**: for Debian-based machine, like Ubuntu, you might need to create an +alias or symbolic link for nodejs to node. The reason for this is the +dependencies that are requires to test highlight.js has a reference to +"node". + +Place the snippet you used inside the browser in +``test/detect//default.txt``, build the package with all the languages +for node and run the test suite. If your language breaks auto-detection, it +should be fixed by :ref:`improving relevance `, which is a black art +in and of itself. When in doubt, please refer to the discussion group! + + +Testing markup +-------------- + +You can also provide additional markup tests for the language to test isolated +cases of various syntactic construct. If your language has 19 different string +literals or complicated heuristics for telling division (``/``) apart from +regexes (``/ .. /``) -- this is the place. + +A test case consists of two files: + +* ``test/markup//.txt``: test code +* ``test/markup//.expect.txt``: reference rendering + +To generate reference rendering use the Developer tool located at +``tools/developer.html``. Make sure to explicitly select your language in the +drop-down menu, as automatic detection is unlikely to work in this case. + + diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/css-classes-reference.rst b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/css-classes-reference.rst new file mode 100644 index 0000000000..1975f235b8 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/css-classes-reference.rst @@ -0,0 +1,460 @@ +CSS classes reference +===================== + + +Stylable classes +---------------- + ++------------------------------------------------------------------------------+ +| **General-purpose** | ++--------------------------+---------------------------------------------------+ +| keyword | keyword in a regular Algol-style language | ++--------------------------+---------------------------------------------------+ +| built_in | built-in or library object (constant, class, | +| | function) | ++--------------------------+---------------------------------------------------+ +| type | user-defined type in a language with first-class | +| | syntactically significant types, like Haskell | ++--------------------------+---------------------------------------------------+ +| literal | special identifier for a built-in value ("true", | +| | "false", "null") | ++--------------------------+---------------------------------------------------+ +| number | number, including units and modifiers, if any. | ++--------------------------+---------------------------------------------------+ +| regexp | literal regular expression | ++--------------------------+---------------------------------------------------+ +| string | literal string, character | ++--------------------------+---------------------------------------------------+ +| subst | parsed section inside a literal string | ++--------------------------+---------------------------------------------------+ +| symbol | symbolic constant, interned string, goto label | ++--------------------------+---------------------------------------------------+ +| class | class or class-level declaration (interfaces, | +| | traits, modules, etc) | ++--------------------------+---------------------------------------------------+ +| function | function or method declaration | ++--------------------------+---------------------------------------------------+ +| title | name of a class or a function at the place of | +| | declaration | ++--------------------------+---------------------------------------------------+ +| params | block of function arguments (parameters) at the | +| | place of declaration | ++--------------------------+---------------------------------------------------+ +| **Meta** | ++--------------------------+---------------------------------------------------+ +| comment | comment | ++--------------------------+---------------------------------------------------+ +| doctag | documentation markup within comments | ++--------------------------+---------------------------------------------------+ +| meta | flags, modifiers, annotations, processing | +| | instructions, preprocessor directive, etc | ++--------------------------+---------------------------------------------------+ +| meta-keyword | keyword or built-in within meta construct | ++--------------------------+---------------------------------------------------+ +| meta-string | string within meta construct | ++--------------------------+---------------------------------------------------+ +| **Tags, attributes, configs** | ++--------------------------+---------------------------------------------------+ +| section | heading of a section in a config file, heading in | +| | text markup | ++--------------------------+---------------------------------------------------+ +| tag | XML/HTML tag | ++--------------------------+---------------------------------------------------+ +| name | name of an XML tag, the first word in an | +| | s-expression | ++--------------------------+---------------------------------------------------+ +| builtin-name | s-expression name from the language standard | +| | library | ++--------------------------+---------------------------------------------------+ +| attr | name of an attribute with no language defined | +| | semantics (keys in JSON, setting names in .ini), | +| | also sub-attribute within another highlighted | +| | object, like XML tag | ++--------------------------+---------------------------------------------------+ +| attribute | name of an attribute followed by a structured | +| | value part, like CSS properties | ++--------------------------+---------------------------------------------------+ +| variable | variable in a config or a template file, | +| | environment var expansion in a script | ++--------------------------+---------------------------------------------------+ +| **Markup** | ++--------------------------+---------------------------------------------------+ +| bullet | list item bullet in text markup | ++--------------------------+---------------------------------------------------+ +| code | code block in text markup | ++--------------------------+---------------------------------------------------+ +| emphasis | emphasis in text markup | ++--------------------------+---------------------------------------------------+ +| strong | strong emphasis in text markup | ++--------------------------+---------------------------------------------------+ +| formula | mathematical formula in text markup | ++--------------------------+---------------------------------------------------+ +| link | hyperlink in text markup | ++--------------------------+---------------------------------------------------+ +| quote | quotation in text markup | ++--------------------------+---------------------------------------------------+ +| **CSS** | ++--------------------------+---------------------------------------------------+ +| selector-tag | tag selector in CSS | ++--------------------------+---------------------------------------------------+ +| selector-id | #id selector in CSS | ++--------------------------+---------------------------------------------------+ +| selector-class | .class selector in CSS | ++--------------------------+---------------------------------------------------+ +| selector-attr | [attr] selector in CSS | ++--------------------------+---------------------------------------------------+ +| selector-pseudo | :pseudo selector in CSS | ++--------------------------+---------------------------------------------------+ +| **Templates** | ++--------------------------+---------------------------------------------------+ +| template-tag | tag of a template language | ++--------------------------+---------------------------------------------------+ +| template-variable | variable in a template language | ++--------------------------+---------------------------------------------------+ +| **diff** | ++--------------------------+---------------------------------------------------+ +| addition | added or changed line in a diff | ++--------------------------+---------------------------------------------------+ +| deletion | deleted line in a diff | ++--------------------------+---------------------------------------------------+ +| **ReasonML** | ++--------------------------+---------------------------------------------------+ +| operator | reasonml operator such as pipe | ++--------------------------+---------------------------------------------------+ +| pattern-match | reasonml pattern matching matchers | ++--------------------------+---------------------------------------------------+ +| typing | type signatures on function parameters | ++--------------------------+---------------------------------------------------+ +| constructor | type constructors | ++--------------------------+---------------------------------------------------+ +| module-access | scope access into a ReasonML module | ++--------------------------+---------------------------------------------------+ +| module | ReasonML module reference within scope access | ++--------------------------+---------------------------------------------------+ + + +Language names and aliases +-------------------------- + ++-------------------------+---------------------------------------------------+ +| 1C | 1c | ++-------------------------+---------------------------------------------------+ +| ABNF | abnf | ++-------------------------+---------------------------------------------------+ +| Access logs | accesslog | ++-------------------------+---------------------------------------------------+ +| Ada | ada | ++-------------------------+---------------------------------------------------+ +| ARM assembler | armasm, arm | ++-------------------------+---------------------------------------------------+ +| AVR assembler | avrasm | ++-------------------------+---------------------------------------------------+ +| ActionScript | actionscript, as | ++-------------------------+---------------------------------------------------+ +| AngelScript | angelscript, asc | ++-------------------------+---------------------------------------------------+ +| Apache | apache, apacheconf | ++-------------------------+---------------------------------------------------+ +| AppleScript | applescript, osascript | ++-------------------------+---------------------------------------------------+ +| Arcade | arcade | ++-------------------------+---------------------------------------------------+ +| AsciiDoc | asciidoc, adoc | ++-------------------------+---------------------------------------------------+ +| AspectJ | aspectj | ++-------------------------+---------------------------------------------------+ +| AutoHotkey | autohotkey | ++-------------------------+---------------------------------------------------+ +| AutoIt | autoit | ++-------------------------+---------------------------------------------------+ +| Awk | awk, mawk, nawk, gawk | ++-------------------------+---------------------------------------------------+ +| Axapta | axapta | ++-------------------------+---------------------------------------------------+ +| Bash | bash, sh, zsh | ++-------------------------+---------------------------------------------------+ +| Basic | basic | ++-------------------------+---------------------------------------------------+ +| BNF | bnf | ++-------------------------+---------------------------------------------------+ +| Brainfuck | brainfuck, bf | ++-------------------------+---------------------------------------------------+ +| C# | cs, csharp | ++-------------------------+---------------------------------------------------+ +| C++ | cpp, c, cc, h, c++, h++, hpp | ++-------------------------+---------------------------------------------------+ +| C/AL | cal | ++-------------------------+---------------------------------------------------+ +| Cache Object Script | cos, cls | ++-------------------------+---------------------------------------------------+ +| CMake | cmake, cmake.in | ++-------------------------+---------------------------------------------------+ +| Coq | coq | ++-------------------------+---------------------------------------------------+ +| CSP | csp | ++-------------------------+---------------------------------------------------+ +| CSS | css | ++-------------------------+---------------------------------------------------+ +| Cap’n Proto | capnproto, capnp | ++-------------------------+---------------------------------------------------+ +| Clojure | clojure, clj | ++-------------------------+---------------------------------------------------+ +| CoffeeScript | coffeescript, coffee, cson, iced | ++-------------------------+---------------------------------------------------+ +| Crmsh | crmsh, crm, pcmk | ++-------------------------+---------------------------------------------------+ +| Crystal | crystal, cr | ++-------------------------+---------------------------------------------------+ +| D | d | ++-------------------------+---------------------------------------------------+ +| DNS Zone file | dns, zone, bind | ++-------------------------+---------------------------------------------------+ +| DOS | dos, bat, cmd | ++-------------------------+---------------------------------------------------+ +| Dart | dart | ++-------------------------+---------------------------------------------------+ +| Delphi | delphi, dpr, dfm, pas, pascal, freepascal, | +| | lazarus, lpr, lfm | ++-------------------------+---------------------------------------------------+ +| Diff | diff, patch | ++-------------------------+---------------------------------------------------+ +| Django | django, jinja | ++-------------------------+---------------------------------------------------+ +| Dockerfile | dockerfile, docker | ++-------------------------+---------------------------------------------------+ +| dsconfig | dsconfig | ++-------------------------+---------------------------------------------------+ +| DTS (Device Tree) | dts | ++-------------------------+---------------------------------------------------+ +| Dust | dust, dst | ++-------------------------+---------------------------------------------------+ +| EBNF | ebnf | ++-------------------------+---------------------------------------------------+ +| Elixir | elixir | ++-------------------------+---------------------------------------------------+ +| Elm | elm | ++-------------------------+---------------------------------------------------+ +| Erlang | erlang, erl | ++-------------------------+---------------------------------------------------+ +| Excel | excel, xls, xlsx | ++-------------------------+---------------------------------------------------+ +| F# | fsharp, fs | ++-------------------------+---------------------------------------------------+ +| FIX | fix | ++-------------------------+---------------------------------------------------+ +| Fortran | fortran, f90, f95 | ++-------------------------+---------------------------------------------------+ +| G-Code | gcode, nc | ++-------------------------+---------------------------------------------------+ +| Gams | gams, gms | ++-------------------------+---------------------------------------------------+ +| GAUSS | gauss, gss | ++-------------------------+---------------------------------------------------+ +| Gherkin | gherkin | ++-------------------------+---------------------------------------------------+ +| Go | go, golang | ++-------------------------+---------------------------------------------------+ +| Golo | golo, gololang | ++-------------------------+---------------------------------------------------+ +| Gradle | gradle | ++-------------------------+---------------------------------------------------+ +| Groovy | groovy | ++-------------------------+---------------------------------------------------+ +| HTML, XML | xml, html, xhtml, rss, atom, xjb, xsd, xsl, plist | ++-------------------------+---------------------------------------------------+ +| HTTP | http, https | ++-------------------------+---------------------------------------------------+ +| Haml | haml | ++-------------------------+---------------------------------------------------+ +| Handlebars | handlebars, hbs, html.hbs, html.handlebars | ++-------------------------+---------------------------------------------------+ +| Haskell | haskell, hs | ++-------------------------+---------------------------------------------------+ +| Haxe | haxe, hx | ++-------------------------+---------------------------------------------------+ +| Hy | hy, hylang | ++-------------------------+---------------------------------------------------+ +| Ini, TOML | ini, toml | ++-------------------------+---------------------------------------------------+ +| Inform7 | inform7, i7 | ++-------------------------+---------------------------------------------------+ +| IRPF90 | irpf90 | ++-------------------------+---------------------------------------------------+ +| JSON | json | ++-------------------------+---------------------------------------------------+ +| Java | java, jsp | ++-------------------------+---------------------------------------------------+ +| JavaScript | javascript, js, jsx | ++-------------------------+---------------------------------------------------+ +| Leaf | leaf | ++-------------------------+---------------------------------------------------+ +| Lasso | lasso, ls, lassoscript | ++-------------------------+---------------------------------------------------+ +| Less | less | ++-------------------------+---------------------------------------------------+ +| LDIF | ldif | ++-------------------------+---------------------------------------------------+ +| Lisp | lisp | ++-------------------------+---------------------------------------------------+ +| LiveCode Server | livecodeserver | ++-------------------------+---------------------------------------------------+ +| LiveScript | livescript, ls | ++-------------------------+---------------------------------------------------+ +| Lua | lua | ++-------------------------+---------------------------------------------------+ +| Makefile | makefile, mk, mak | ++-------------------------+---------------------------------------------------+ +| Markdown | markdown, md, mkdown, mkd | ++-------------------------+---------------------------------------------------+ +| Mathematica | mathematica, mma | ++-------------------------+---------------------------------------------------+ +| Matlab | matlab | ++-------------------------+---------------------------------------------------+ +| Maxima | maxima | ++-------------------------+---------------------------------------------------+ +| Maya Embedded Language | mel | ++-------------------------+---------------------------------------------------+ +| Mercury | mercury | ++-------------------------+---------------------------------------------------+ +| Mizar | mizar | ++-------------------------+---------------------------------------------------+ +| Mojolicious | mojolicious | ++-------------------------+---------------------------------------------------+ +| Monkey | monkey | ++-------------------------+---------------------------------------------------+ +| Moonscript | moonscript, moon | ++-------------------------+---------------------------------------------------+ +| N1QL | n1ql | ++-------------------------+---------------------------------------------------+ +| NSIS | nsis | ++-------------------------+---------------------------------------------------+ +| Nginx | nginx, nginxconf | ++-------------------------+---------------------------------------------------+ +| Nimrod | nimrod, nim | ++-------------------------+---------------------------------------------------+ +| Nix | nix | ++-------------------------+---------------------------------------------------+ +| OCaml | ocaml, ml | ++-------------------------+---------------------------------------------------+ +| Objective C | objectivec, mm, objc, obj-c | ++-------------------------+---------------------------------------------------+ +| OpenGL Shading Language | glsl | ++-------------------------+---------------------------------------------------+ +| OpenSCAD | openscad, scad | ++-------------------------+---------------------------------------------------+ +| Oracle Rules Language | ruleslanguage | ++-------------------------+---------------------------------------------------+ +| Oxygene | oxygene | ++-------------------------+---------------------------------------------------+ +| PF | pf, pf.conf | ++-------------------------+---------------------------------------------------+ +| PHP | php, php3, php4, php5, php6 | ++-------------------------+---------------------------------------------------+ +| Parser3 | parser3 | ++-------------------------+---------------------------------------------------+ +| Perl | perl, pl, pm | ++-------------------------+---------------------------------------------------+ +| Plaintext: no highlight | plaintext | ++-------------------------+---------------------------------------------------+ +| Pony | pony | ++-------------------------+---------------------------------------------------+ +| PostgreSQL & PL/pgSQL | pgsql, postgres, postgresql | ++-------------------------+---------------------------------------------------+ +| PowerShell | powershell, ps | ++-------------------------+---------------------------------------------------+ +| Processing | processing | ++-------------------------+---------------------------------------------------+ +| Prolog | prolog | ++-------------------------+---------------------------------------------------+ +| Properties | properties | ++-------------------------+---------------------------------------------------+ +| Protocol Buffers | protobuf | ++-------------------------+---------------------------------------------------+ +| Puppet | puppet, pp | ++-------------------------+---------------------------------------------------+ +| Python | python, py, gyp | ++-------------------------+---------------------------------------------------+ +| Python profiler results | profile | ++-------------------------+---------------------------------------------------+ +| Q | k, kdb | ++-------------------------+---------------------------------------------------+ +| QML | qml | ++-------------------------+---------------------------------------------------+ +| R | r | ++-------------------------+---------------------------------------------------+ +| ReasonML | reasonml, re | ++-------------------------+---------------------------------------------------+ +| RenderMan RIB | rib | ++-------------------------+---------------------------------------------------+ +| RenderMan RSL | rsl | ++-------------------------+---------------------------------------------------+ +| Roboconf | graph, instances | ++-------------------------+---------------------------------------------------+ +| Ruby | ruby, rb, gemspec, podspec, thor, irb | ++-------------------------+---------------------------------------------------+ +| Rust | rust, rs | ++-------------------------+---------------------------------------------------+ +| SCSS | scss | ++-------------------------+---------------------------------------------------+ +| SQL | sql | ++-------------------------+---------------------------------------------------+ +| STEP Part 21 | p21, step, stp | ++-------------------------+---------------------------------------------------+ +| Scala | scala | ++-------------------------+---------------------------------------------------+ +| Scheme | scheme | ++-------------------------+---------------------------------------------------+ +| Scilab | scilab, sci | ++-------------------------+---------------------------------------------------+ +| Shell | shell, console | ++-------------------------+---------------------------------------------------+ +| Smali | smali | ++-------------------------+---------------------------------------------------+ +| Smalltalk | smalltalk, st | ++-------------------------+---------------------------------------------------+ +| Stan | stan | ++-------------------------+---------------------------------------------------+ +| Stata | stata | ++-------------------------+---------------------------------------------------+ +| SAS | SAS, sas | ++-------------------------+---------------------------------------------------+ +| Stylus | stylus, styl | ++-------------------------+---------------------------------------------------+ +| SubUnit | subunit | ++-------------------------+---------------------------------------------------+ +| Swift | swift | ++-------------------------+---------------------------------------------------+ +| Test Anything Protocol | tap | ++-------------------------+---------------------------------------------------+ +| Tcl | tcl, tk | ++-------------------------+---------------------------------------------------+ +| TeX | tex | ++-------------------------+---------------------------------------------------+ +| Thrift | thrift | ++-------------------------+---------------------------------------------------+ +| TP | tp | ++-------------------------+---------------------------------------------------+ +| Twig | twig, craftcms | ++-------------------------+---------------------------------------------------+ +| TypeScript | typescript, ts | ++-------------------------+---------------------------------------------------+ +| VB.Net | vbnet, vb | ++-------------------------+---------------------------------------------------+ +| VBScript | vbscript, vbs | ++-------------------------+---------------------------------------------------+ +| VHDL | vhdl | ++-------------------------+---------------------------------------------------+ +| Vala | vala | ++-------------------------+---------------------------------------------------+ +| Verilog | verilog, v | ++-------------------------+---------------------------------------------------+ +| Vim Script | vim | ++-------------------------+---------------------------------------------------+ +| x86 Assembly | x86asm | ++-------------------------+---------------------------------------------------+ +| XL | xl, tao | ++-------------------------+---------------------------------------------------+ +| XQuery | xpath, xq | ++-------------------------+---------------------------------------------------+ +| Zephir | zephir, zep | ++-------------------------+---------------------------------------------------+ diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/index.rst b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/index.rst new file mode 100644 index 0000000000..3288758bb5 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/index.rst @@ -0,0 +1,44 @@ +.. highlight.js documentation master file, created by + sphinx-quickstart on Wed Sep 12 23:48:27 2012. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +``highlight.js`` developer documentation +========================================== + +Contents: + +.. toctree:: + :maxdepth: 1 + + api + language-guide + reference + css-classes-reference + style-guide + language-contribution + building-testing + maintainers-guide + +Miscellaneous: + +.. toctree:: + :maxdepth: 1 + + line-numbers + language-requests + +Links: + +- Code: https://github.com/highlightjs/highlight.js +- Discussion: http://groups.google.com/group/highlightjs +- Bug tracking: https://github.com/highlightjs/highlight.js/issues + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/language-contribution.rst b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/language-contribution.rst new file mode 100644 index 0000000000..614e816339 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/language-contribution.rst @@ -0,0 +1,77 @@ +Language contributor checklist +============================== + +1. Put language definition into a .js file +------------------------------------------ + +The file defines a function accepting a reference to the library and returning a language object. +The library parameter is useful to access common modes and regexps. You should not immediately call this function, +this is done during the build process and details differ for different build targets. + +:: + + function(hljs) { + return { + keywords: 'foo bar', + contains: [ ..., hljs.NUMBER_MODE, ... ] + } + } + +The name of the file is used as a short language identifier and should be usable as a class name in HTML and CSS. + + +2. Provide meta data +-------------------- + +At the top of the file there is a specially formatted comment with meta data processed by a build system. +Meta data format is simply key-value pairs each occupying its own line: + +:: + + /* + Language: Superlanguage + Requires: java.js, sql.js + Author: John Smith + Contributors: Mike Johnson <...@...>, Matt Wilson <...@...> + Description: Some cool language definition + */ + +``Language`` — the only required header giving a human-readable language name. + +``Requires`` — a list of other language files required for this language to work. +This make it possible to describe languages that extend definitions of other ones. +Required files aren't processed in any special way. +The build system just makes sure that they will be in the final package in +``LANGUAGES`` object. + +The meaning of the other headers is pretty obvious. + + +3. Create a code example +------------------------ + +The code example is used both to test language detection and for the demo page +on https://highlightjs.org/. Put it in ``test/detect//default.txt``. + +Take inspiration from other languages in ``test/detect/`` and read +:ref:`testing instructions ` for more details. + + +4. Write class reference +------------------------ + +Class reference lives in the :doc:`CSS classes reference `.. +Describe shortly names of all meaningful modes used in your language definition. + + +5. Add yourself to AUTHORS.*.txt and CHANGES.md +----------------------------------------------- + +If you're a new contributor add yourself to the authors list. +Also it will be good to update CHANGES.md. + + +6. Create a pull request +------------------------ + +Send your contribution as a pull request on GitHub. diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/language-guide.rst b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/language-guide.rst new file mode 100644 index 0000000000..a3cf8d806a --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/language-guide.rst @@ -0,0 +1,264 @@ +Language definition guide +========================= + +Highlighting overview +--------------------- + +Programming language code consists of parts with different rules of parsing: keywords like ``for`` or ``if`` +don't make sense inside strings, strings may contain backslash-escaped symbols like ``\"`` +and comments usually don't contain anything interesting except the end of the comment. + +In highlight.js such parts are called "modes". + +Each mode consists of: + +* starting condition +* ending condition +* list of contained sub-modes +* lexing rules and keywords +* …exotic stuff like another language inside a language + +The parser's work is to look for modes and their keywords. +Upon finding, it wraps them into the markup ``...`` +and puts the name of the mode ("string", "comment", "number") +or a keyword group name ("keyword", "literal", "built-in") as the span's class name. + + +General syntax +-------------- + +A language definition is a JavaScript object describing the default parsing mode for the language. +This default mode contains sub-modes which in turn contain other sub-modes, effectively making the language definition a tree of modes. + +Here's an example: + +:: + + { + case_insensitive: true, // language is case-insensitive + keywords: 'for if while', + contains: [ + { + className: 'string', + begin: '"', end: '"' + }, + hljs.COMMENT( + '/\\*', // begin + '\\*/', // end + { + contains: [ + { + className: 'doc', begin: '@\\w+' + } + ] + } + ) + ] + } + +Usually the default mode accounts for the majority of the code and describes all language keywords. +A notable exception here is XML in which a default mode is just a user text that doesn't contain any keywords, +and most interesting parsing happens inside tags. + + +Keywords +-------- + +In the simple case language keywords are defined in a string, separated by space: + +:: + + { + keywords: 'else for if while' + } + +Some languages have different kinds of "keywords" that might not be called as such by the language spec +but are very close to them from the point of view of a syntax highlighter. These are all sorts of "literals", "built-ins", "symbols" and such. +To define such keyword groups the attribute ``keywords`` becomes an object each property of which defines its own group of keywords: + +:: + + { + keywords: { + keyword: 'else for if while', + literal: 'false true null' + } + } + +The group name becomes then a class name in a generated markup enabling different styling for different kinds of keywords. + +To detect keywords highlight.js breaks the processed chunk of code into separate words — a process called lexing. +The "word" here is defined by the regexp ``[a-zA-Z][a-zA-Z0-9_]*`` that works for keywords in most languages. +Different lexing rules can be defined by the ``lexemes`` attribute: + +:: + + { + lexemes: '-[a-z]+', + keywords: '-import -export' + } + + +Sub-modes +--------- + +Sub-modes are listed in the ``contains`` attribute: + +:: + + { + keywords: '...', + contains: [ + hljs.QUOTE_STRING_MODE, + hljs.C_LINE_COMMENT, + { ... custom mode definition ... } + ] + } + +A mode can reference itself in the ``contains`` array by using a special keyword ``'self``'. +This is commonly used to define nested modes: + +:: + + { + className: 'object', + begin: '{', end: '}', + contains: [hljs.QUOTE_STRING_MODE, 'self'] + } + + +Comments +-------- + +To define custom comments it is recommended to use a built-in helper function ``hljs.COMMENT`` instead of describing the mode directly, as it also defines a few default sub-modes that improve language detection and do other nice things. + +Parameters for the function are: + +:: + + hljs.COMMENT( + begin, // begin regex + end, // end regex + extra // optional object with extra attributes to override defaults + // (for example {relevance: 0}) + ) + + +Markup generation +----------------- + +Modes usually generate actual highlighting markup — ```` elements with specific class names that are defined by the ``className`` attribute: + +:: + + { + contains: [ + { + className: 'string', + // ... other attributes + }, + { + className: 'number', + // ... + } + ] + } + +Names are not required to be unique, it's quite common to have several definitions with the same name. +For example, many languages have various syntaxes for strings, comments, etc… + +Sometimes modes are defined only to support specific parsing rules and aren't needed in the final markup. +A classic example is an escaping sequence inside strings allowing them to contain an ending quote. + +:: + + { + className: 'string', + begin: '"', end: '"', + contains: [{begin: '\\\\.'}], + } + +For such modes ``className`` attribute should be omitted so they won't generate excessive markup. + + +Mode attributes +--------------- + +Other useful attributes are defined in the :doc:`mode reference `. + + +.. _relevance: + +Relevance +--------- + +Highlight.js tries to automatically detect the language of a code fragment. +The heuristics is essentially simple: it tries to highlight a fragment with all the language definitions +and the one that yields most specific modes and keywords wins. The job of a language definition +is to help this heuristics by hinting relative relevance (or irrelevance) of modes. + +This is best illustrated by example. Python has special kinds of strings defined by prefix letters before the quotes: +``r"..."``, ``u"..."``. If a code fragment contains such strings there is a good chance that it's in Python. +So these string modes are given high relevance: + +:: + + { + className: 'string', + begin: 'r"', end: '"', + relevance: 10 + } + +On the other hand, conventional strings in plain single or double quotes aren't specific to any language +and it makes sense to bring their relevance to zero to lessen statistical noise: + +:: + + { + className: 'string', + begin: '"', end: '"', + relevance: 0 + } + +The default value for relevance is 1. When setting an explicit value it's recommended to use either 10 or 0. + +Keywords also influence relevance. Each of them usually has a relevance of 1, but there are some unique names +that aren't likely to be found outside of their languages, even in the form of variable names. +For example just having ``reinterpret_cast`` somewhere in the code is a good indicator that we're looking at C++. +It's worth to set relevance of such keywords a bit higher. This is done with a pipe: + +:: + + { + keywords: 'for if reinterpret_cast|10' + } + + +Illegal symbols +--------------- + +Another way to improve language detection is to define illegal symbols for a mode. +For example in Python first line of class definition (``class MyClass(object):``) cannot contain symbol "{" or a newline. +Presence of these symbols clearly shows that the language is not Python and the parser can drop this attempt early. + +Illegal symbols are defined as a a single regular expression: + +:: + + { + className: 'class', + illegal: '[${]' + } + + +Pre-defined modes and regular expressions +----------------------------------------- + +Many languages share common modes and regular expressions. Such expressions are defined in core highlight.js code +at the end under "Common regexps" and "Common modes" titles. Use them when possible. + + +Contributing +------------ + +Follow the :doc:`contributor checklist `. diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/language-requests.rst b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/language-requests.rst new file mode 100644 index 0000000000..4e4c2f0b61 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/language-requests.rst @@ -0,0 +1,17 @@ +On requesting new languages +=========================== + +This is a general answer to requests for adding new languages that appear from +time to time in the highlight.js issue tracker and discussion group. + + Highlight.js doesn't have a fundamental plan for implementing languages, + instead the project works by accepting language definitions from + interested contributors. There are also no rules at the moment forbidding + any languages from being added to the library, no matter how obscure or + weird. + + This means that there's no point in requesting a new language without + providing an implementation for it. If you want to see a particular language + included in highlight.js but cannot implement it, the best way to make it + happen is to get another developer interested in doing so. Here's our + :doc:`language-guide`. diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/line-numbers.rst b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/line-numbers.rst new file mode 100644 index 0000000000..674542d4ed --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/line-numbers.rst @@ -0,0 +1,39 @@ +Line numbers +============ + +Highlight.js' notable lack of line numbers support is not an oversight but a +feature. Following is the explanation of this policy from the current project +maintainer (hey guys!): + + One of the defining design principles for highlight.js from the start was + simplicity. Not the simplicity of code (in fact, it's quite complex) but + the simplicity of usage and of the actual look of highlighted snippets on + HTML pages. Many highlighters, in my opinion, are overdoing it with such + things as separate colors for every single type of lexemes, striped + backgrounds, fancy buttons around code blocks and — yes — line numbers. + The more fancy stuff resides around the code the more it distracts a + reader from understanding it. + + This is why it's not a straightforward decision: this new feature will not + just make highlight.js better, it might actually make it worse simply by + making it look more bloated in blog posts around the Internet. This is why + I'm asking people to show that it's worth it. + + The only real use-case that ever was brought up in support of line numbers + is referencing code from the descriptive text around it. On my own blog I + was always solving this either with comments within the code itself or by + breaking the larger snippets into smaller ones and describing each small + part separately. I'm not saying that my solution is better. But I don't + see how line numbers are better either. And the only way to show that they + are better is to set up some usability research on the subject. I doubt + anyone would bother to do it. + + Then there's maintenance. So far the core code of highlight.js is + maintained by only one person — yours truly. Inclusion of any new code in + highlight.js means that from that moment I will have to fix bugs in it, + improve it further, make it work together with the rest of the code, + defend its design. And I don't want to do all this for the feature that I + consider "evil" and probably will never use myself. + +This position is `subject to discuss `_. +Also it doesn't stop anyone from forking the code and maintaining line-numbers implementation separately. diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/maintainers-guide.rst b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/maintainers-guide.rst new file mode 100644 index 0000000000..21bfc52396 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/maintainers-guide.rst @@ -0,0 +1,34 @@ +Maintainer's guide +================== + + +Commit policy +------------- + +* Pull requests from outside contributors require a review from a maintainer. + +* Maintainers should avoid working on a master branch directly and create branches for everything. A code review from another maintainer is recommended but not required, use your best judgment. + + + +Release process +--------------- + +Releases happen on a 6-week schedule. Currently due to a long break the date of the next release is not set. + +* Update CHANGES.md with everything interesting since the last update. + +* Update version numbers using the three-part x.y.z notation everywhere: + + * The header in CHANGES.md (this is where the site looks for the latest version number) + * ``"version"`` attribute in package.json + * ``"version"`` attribute in package-lock.json (run `npm install`) + * Two places in docs/conf.py (``version`` and ``release``) + +* Commit the version changes and tag the commit with the plain version number (no "v." or anything like that) + +* Push the commit and the tags to master (``git push && git push --tags``) + +Pushing the tag triggers the update process which can be monitored at http://highlightjs.org/api/release/ + +When something didn't work *and* it's fixable in code (version numbers mismatch, last minute patches, etc), simply make another release incrementing the third (revision) part of the version number. diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/reference.rst b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/reference.rst new file mode 100644 index 0000000000..de240fd48f --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/wwwroot/libs/highlight.js/docs/reference.rst @@ -0,0 +1,360 @@ +Mode reference +============== + +Types +----- + +Types of attributes values in this reference: + ++------------+-------------------------------------------------------------------------------------+ +| identifier | String suitable to be used as a Javascript variable and CSS class name | +| | (i.e. mostly ``/[A-Za-z0-9_]+/``) | ++------------+-------------------------------------------------------------------------------------+ +| regexp | String representing a Javascript regexp. | +| | Note that since it's not a literal regexp all back-slashes should be repeated twice | ++------------+-------------------------------------------------------------------------------------+ +| boolean | Javascript boolean: ``true`` or ``false`` | ++------------+-------------------------------------------------------------------------------------+ +| number | Javascript number | ++------------+-------------------------------------------------------------------------------------+ +| object | Javascript object: ``{ ... }`` | ++------------+-------------------------------------------------------------------------------------+ +| array | Javascript array: ``[ ... ]`` | ++------------+-------------------------------------------------------------------------------------+ + + +Attributes +---------- + +case_insensitive +^^^^^^^^^^^^^^^^ + +**type**: boolean + +Case insensitivity of language keywords and regexps. Used only on the top-level mode. + + +aliases +^^^^^^^ + +**type**: array + +A list of additional names (besides the canonical one given by the filename) that can be used to identify a language in HTML classes and in a call to :ref:`getLanguage `. + + +className +^^^^^^^^^ + +**type**: identifier + +The name of the mode. It is used as a class name in HTML markup. + +Multiple modes can have the same name. This is useful when a language has multiple variants of syntax +for one thing like string in single or double quotes. + + +begin +^^^^^ + +**type**: regexp + +Regular expression starting a mode. For example a single quote for strings or two forward slashes for C-style comments. +If absent, ``begin`` defaults to a regexp that matches anything, so the mode starts immediately. + + +end +^^^ + +**type**: regexp + +Regular expression ending a mode. For example a single quote for strings or "$" (end of line) for one-line comments. + +It's often the case that a beginning regular expression defines the entire mode and doesn't need any special ending. +For example a number can be defined with ``begin: "\\b\\d+"`` which spans all the digits. + +If absent, ``end`` defaults to a regexp that matches anything, so the mode ends immediately. + +Sometimes a mode can end not by itself but implicitly with its containing (parent) mode. +This is achieved with :ref:`endsWithParent ` attribute. + + +beginKeywords +^^^^^^^^^^^^^^^^ + +**type**: string + +Used instead of ``begin`` for modes starting with keywords to avoid needless repetition: + +:: + + { + begin: '\\b(extends|implements) ', + keywords: 'extends implements' + } + +… becomes: + +:: + + { + beginKeywords: 'extends implements' + } + +Unlike the :ref:`keywords ` attribute, this one allows only a simple list of space separated keywords. +If you do need additional features of ``keywords`` or you just need more keywords for this mode you may include ``keywords`` along with ``beginKeywords``. + + +.. _endsWithParent: + +endsWithParent +^^^^^^^^^^^^^^ + +**type**: boolean + +A flag showing that a mode ends when its parent ends. + +This is best demonstrated by example. In CSS syntax a selector has a set of rules contained within symbols "{" and "}". +Individual rules separated by ";" but the last one in a set can omit the terminating semicolon: + +:: + + p { + width: 100%; color: red + } + +This is when ``endsWithParent`` comes into play: + +:: + + { + className: 'rules', begin: '{', end: '}', + contains: [ + {className: 'rule', /* ... */ end: ';', endsWithParent: true} + ] + } + +.. _endsParent: + +endsParent +^^^^^^^^^^^^^^ + +**type**: boolean + +Forces closing of the parent mode right after the current mode is closed. + +This is used for modes that don't have an easily expressible ending lexeme but +instead could be closed after the last interesting sub-mode is found. + +Here's an example with two ways of defining functions in Elixir, one using a +keyword ``do`` and another using a comma: + +:: + + def foo :clear, list do + :ok + end + + def foo, do: IO.puts "hello world" + +Note that in the first case the parameter list after the function title may also +include a comma. And iIf we're only interested in highlighting a title we can +tell it to end the function definition after itself: + +:: + + { + className: 'function', + beginKeywords: 'def', end: /\B\b/, + contains: [ + { + className: 'title', + begin: hljs.IDENT_RE, endsParent: true + } + ] + } + +(The ``end: /\B\b/`` regex tells function to never end by itself.) + +.. _endSameAsBegin: + +endSameAsBegin +^^^^^^^^^^^^^^ + +**type**: boolean + +Acts as ``end`` matching exactly the same string that was found by the +corresponding ``begin`` regexp. + +For example, in PostgreSQL string constants can uee "dollar quotes", +consisting of a dollar sign, an optional tag of zero or more characters, +and another dollar sign. String constant must be ended with the same +construct using the same tag. It is possible to nest dollar-quoted string +constants by choosing different tags at each nesting level: + +:: + + $foo$ + ... + $bar$ nested $bar$ + ... + $foo$ + +In this case you can't simply specify the same regexp for ``begin`` and +``end`` (say, ``"\\$[a-z]\\$"``), but you can use ``begin: "\\$[a-z]\\$"`` +and ``endSameAsBegin: true``. + +.. _lexemes: + +lexemes +^^^^^^^ + +**type**: regexp + +A regular expression that extracts individual lexemes from language text to find :ref:`keywords ` among them. +Default value is ``hljs.IDENT_RE`` which works for most languages. + + +.. _keywords: + +keywords +^^^^^^^^ + +**type**: object + +Keyword definition comes in two forms: + +* ``'for while if else weird_voodoo|10 ... '`` -- a string of space-separated keywords with an optional relevance over a pipe +* ``{'keyword': ' ... ', 'literal': ' ... '}`` -- an object whose keys are names of different kinds of keywords and values are keyword definition strings in the first form + +For detailed explanation see :doc:`Language definition guide `. + + +illegal +^^^^^^^ + +**type**: regexp + +A regular expression that defines symbols illegal for the mode. +When the parser finds a match for illegal expression it immediately drops parsing the whole language altogether. + + +excludeBegin, excludeEnd +^^^^^^^^^^^^^^^^^^^^^^^^ + +**type**: boolean + +Exclude beginning or ending lexemes out of mode's generated markup. For example in CSS syntax a rule ends with a semicolon. +However visually it's better not to color it as the rule contents. Having ``excludeEnd: true`` forces a ```` element for the rule to close before the semicolon. + + +returnBegin +^^^^^^^^^^^ + +**type**: boolean + +Returns just found beginning lexeme back into parser. This is used when beginning of a sub-mode is a complex expression +that should not only be found within a parent mode but also parsed according to the rules of a sub-mode. + +Since the parser is effectively goes back it's quite possible to create a infinite loop here so use with caution! + + +returnEnd +^^^^^^^^^ + +**type**: boolean + +Returns just found ending lexeme back into parser. This is used for example to parse Javascript embedded into HTML. +A Javascript block ends with the HTML closing tag ```` that cannot be parsed with Javascript rules. +So it is returned back into its parent HTML mode that knows what to do with it. + +Since the parser is effectively goes back it's quite possible to create a infinite loop here so use with caution! + + +contains +^^^^^^^^ + +**type**: array + +The list of sub-modes that can be found inside the mode. For detailed explanation see :doc:`Language definition guide `. + + +starts +^^^^^^ + +**type**: identifier + +The name of the mode that will start right after the current mode ends. The new mode won't be contained within the current one. + +Currently this attribute is used to highlight Javascript and CSS contained within HTML. +Tags `` } @@ -11,7 +19,7 @@ -

    @L["Tenants"]

    + @L["Tenants"]
    diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo.Abp.TenantManagement.Application.Tests.csproj b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo.Abp.TenantManagement.Application.Tests.csproj index bb806e268d..1aeefa647c 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo.Abp.TenantManagement.Application.Tests.csproj +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo.Abp.TenantManagement.Application.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/AbpTenantManagementApplicationTestModule.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/AbpTenantManagementApplicationTestModule.cs index e5417381dc..f15708fd42 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/AbpTenantManagementApplicationTestModule.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/AbpTenantManagementApplicationTestModule.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.TenantManagement { public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.AddAlwaysAllowPermissionChecker(); + context.Services.AddAlwaysAllowAuthorization(); } } } diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests.csproj b/modules/tenant-management/test/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests.csproj index e03ea985d8..6a43666860 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests.csproj +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests.csproj @@ -17,9 +17,9 @@ - - - + + + diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo.Abp.TenantManagement.MongoDB.Tests.csproj b/modules/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo.Abp.TenantManagement.MongoDB.Tests.csproj index 21d7382eb9..5cbe512e99 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo.Abp.TenantManagement.MongoDB.Tests.csproj +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo.Abp.TenantManagement.MongoDB.Tests.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo.Abp.TenantManagement.TestBase.csproj b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo.Abp.TenantManagement.TestBase.csproj index f454b6adac..093196c073 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo.Abp.TenantManagement.TestBase.csproj +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo.Abp.TenantManagement.TestBase.csproj @@ -18,12 +18,12 @@ - + - - - - + + + + diff --git a/modules/users/Volo.Abp.Users.sln.DotSettings b/modules/users/Volo.Abp.Users.sln.DotSettings new file mode 100644 index 0000000000..05bef5f511 --- /dev/null +++ b/modules/users/Volo.Abp.Users.sln.DotSettings @@ -0,0 +1,7 @@ + + True + D:\github\abp\common.DotSettings + ..\..\..\common.DotSettings + True + 1 + \ No newline at end of file diff --git a/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/UserSettingValueProvider.cs b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/UserSettingValueProvider.cs index 8beba5d31e..345b0e6929 100644 --- a/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/UserSettingValueProvider.cs +++ b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/UserSettingValueProvider.cs @@ -22,27 +22,27 @@ namespace Volo.Abp.Users public override async Task GetOrNullAsync(SettingDefinition setting, string providerKey) { - if (providerKey == null) - { - if (CurrentUser.Id == null) - { - return null; - } - - providerKey = CurrentUser.Id.ToString(); - } - - return await SettingStore.GetOrNullAsync(setting.Name, Name, providerKey); + return await SettingStore.GetOrNullAsync(setting.Name, Name, NormalizeProviderKey(providerKey)); } public override Task SetAsync(SettingDefinition setting, string value, string providerKey) { - return SettingStore.SetAsync(setting.Name, value, Name, providerKey); + return SettingStore.SetAsync(setting.Name, value, Name, NormalizeProviderKey(providerKey)); } public override Task ClearAsync(SettingDefinition setting, string providerKey) { - return SettingStore.DeleteAsync(setting.Name, Name, providerKey); + return SettingStore.DeleteAsync(setting.Name, Name, NormalizeProviderKey(providerKey)); + } + + private string NormalizeProviderKey(string providerKey) + { + if (providerKey == null && CurrentUser.Id.HasValue) + { + return CurrentUser.Id.Value.ToString(); + } + + return providerKey; } } } \ No newline at end of file diff --git a/modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo.Abp.Users.EntityFrameworkCore.Tests.csproj b/modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo.Abp.Users.EntityFrameworkCore.Tests.csproj index 678fac2e73..8571a8bd34 100644 --- a/modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo.Abp.Users.EntityFrameworkCore.Tests.csproj +++ b/modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo.Abp.Users.EntityFrameworkCore.Tests.csproj @@ -18,8 +18,8 @@ - - + + diff --git a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo.Abp.Users.MongoDB.Tests.csproj b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo.Abp.Users.MongoDB.Tests.csproj index 3df40c3aac..57af117cf4 100644 --- a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo.Abp.Users.MongoDB.Tests.csproj +++ b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo.Abp.Users.MongoDB.Tests.csproj @@ -18,8 +18,8 @@ - - + + diff --git a/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj b/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj index 674da958ea..484b98b6c8 100644 --- a/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj +++ b/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj @@ -20,12 +20,12 @@ - + - - - - + + + + diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index 3dcccf7d81..27c0f7ff02 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -28,6 +28,8 @@ $projects = ( "framework/src/Volo.Abp.AspNetCore.Authentication.OAuth", "framework/src/Volo.Abp.AspNetCore.MultiTenancy", "framework/src/Volo.Abp.AspNetCore.Mvc", + "framework/src/Volo.Abp.AspNetCore.Mvc.Contracts", + "framework/src/Volo.Abp.AspNetCore.Mvc.Client", "framework/src/Volo.Abp.AspNetCore.Mvc.UI", "framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap", "framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling", @@ -57,14 +59,17 @@ $projects = ( "framework/src/Volo.Abp.EntityFrameworkCore.MySQL", "framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql", "framework/src/Volo.Abp.EventBus", - "framework/src/Volo.Abp.EventBus.Distributed.RabbitMQ", + "framework/src/Volo.Abp.EventBus.RabbitMQ", "framework/src/Volo.Abp.Guids", "framework/src/Volo.Abp.HangFire", "framework/src/Volo.Abp.Http", "framework/src/Volo.Abp.Http.Abstractions", - "framework/src/Volo.Abp.Http.Client", + "framework/src/Volo.Abp.Http.Client", + "framework/src/Volo.Abp.Http.Client.IdentityModel", + "framework/src/Volo.Abp.IdentityModel", "framework/src/Volo.Abp.Json", "framework/src/Volo.Abp.Localization", + "framework/src/Volo.Abp.Localization.Abstractions", "framework/src/Volo.Abp.MemoryDb", "framework/src/Volo.Abp.MongoDB", "framework/src/Volo.Abp.MultiTenancy.Abstractions", @@ -104,6 +109,8 @@ $projects = ( "modules/permission-management/src/Volo.Abp.PermissionManagement.Application", "modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore", "modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB", + "modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi", + "modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client", "modules/permission-management/src/Volo.Abp.PermissionManagement.Web", # modules/tenant-management @@ -118,6 +125,7 @@ $projects = ( "modules/tenant-management/src/Volo.Abp.TenantManagement.Web", # modules/identity + "modules/identity/src/Volo.Abp.Identity.AspNetCore", "modules/identity/src/Volo.Abp.Identity.Application", "modules/identity/src/Volo.Abp.Identity.Application.Contracts", "modules/identity/src/Volo.Abp.Identity.Domain", @@ -127,6 +135,7 @@ $projects = ( "modules/identity/src/Volo.Abp.Identity.HttpApi", "modules/identity/src/Volo.Abp.Identity.HttpApi.Client", "modules/identity/src/Volo.Abp.Identity.Web", + "modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity", # modules/identityserver "modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared", @@ -136,6 +145,7 @@ $projects = ( # modules/account "modules/account/src/Volo.Abp.Account.Web", + "modules/account/src/Volo.Abp.Account.Web.IdentityServer", # modules/docs "modules/docs/src/Volo.Docs.Application", diff --git a/samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/BasicAspNetCoreApplication.csproj b/samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/BasicAspNetCoreApplication.csproj index 0a529120d1..8aeb4809a2 100644 --- a/samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/BasicAspNetCoreApplication.csproj +++ b/samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/BasicAspNetCoreApplication.csproj @@ -1,11 +1,11 @@  - netcoreapp2.1 + netcoreapp2.2 - + diff --git a/samples/BasicConsoleApplication/AbpConsoleDemo/AbpConsoleDemo.csproj b/samples/BasicConsoleApplication/AbpConsoleDemo/AbpConsoleDemo.csproj index 04d1557392..b2557ef085 100644 --- a/samples/BasicConsoleApplication/AbpConsoleDemo/AbpConsoleDemo.csproj +++ b/samples/BasicConsoleApplication/AbpConsoleDemo/AbpConsoleDemo.csproj @@ -2,11 +2,11 @@ Exe - netcoreapp2.1 + netcoreapp2.2 - + diff --git a/samples/BasicConsoleApplication/AbpConsoleDemo/AppModule.cs b/samples/BasicConsoleApplication/AbpConsoleDemo/AppModule.cs index 0449d84b99..85d1d6b816 100644 --- a/samples/BasicConsoleApplication/AbpConsoleDemo/AppModule.cs +++ b/samples/BasicConsoleApplication/AbpConsoleDemo/AppModule.cs @@ -1,13 +1,11 @@ -using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Autofac; using Volo.Abp.Modularity; namespace AbpConsoleDemo { + [DependsOn(typeof(AbpAutofacModule))] public class AppModule : AbpModule { - public override void ConfigureServices(ServiceConfigurationContext context) - { - context.Services.AddAssemblyOf(); - } + } } diff --git a/samples/BasicConsoleApplication/AbpConsoleDemo/Program.cs b/samples/BasicConsoleApplication/AbpConsoleDemo/Program.cs index 5f0dc68d36..651fda3c4f 100644 --- a/samples/BasicConsoleApplication/AbpConsoleDemo/Program.cs +++ b/samples/BasicConsoleApplication/AbpConsoleDemo/Program.cs @@ -8,11 +8,16 @@ namespace AbpConsoleDemo { static void Main(string[] args) { - using (var application = AbpApplicationFactory.Create()) + using (var application = AbpApplicationFactory.Create(options => + { + options.UseAutofac(); //Autofac integration + })) { application.Initialize(); - var helloWorldService = application.ServiceProvider.GetService(); + //Resolve a service and use it + var helloWorldService = + application.ServiceProvider.GetService(); helloWorldService.SayHello(); Console.WriteLine("Press ENTER to stop application..."); diff --git a/samples/BookStore/Acme.BookStore.sln b/samples/BookStore/Acme.BookStore.sln index 49f9115781..b0a02d2dde 100644 --- a/samples/BookStore/Acme.BookStore.sln +++ b/samples/BookStore/Acme.BookStore.sln @@ -19,6 +19,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Application. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Web.Tests", "test\Acme.BookStore.Web.Tests\Acme.BookStore.Web.Tests.csproj", "{5F1B28C6-8D0C-4155-92D0-252F7EA5F674}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Acme.BookStore.ConsoleApiClient", "test\Acme.BookStore.ConsoleApiClient\Acme.BookStore.ConsoleApiClient.csproj", "{3DED9AA7-1FC4-435D-9934-BCD37B43F744}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -49,6 +51,10 @@ Global {5F1B28C6-8D0C-4155-92D0-252F7EA5F674}.Debug|Any CPU.Build.0 = Debug|Any CPU {5F1B28C6-8D0C-4155-92D0-252F7EA5F674}.Release|Any CPU.ActiveCfg = Release|Any CPU {5F1B28C6-8D0C-4155-92D0-252F7EA5F674}.Release|Any CPU.Build.0 = Release|Any CPU + {3DED9AA7-1FC4-435D-9934-BCD37B43F744}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3DED9AA7-1FC4-435D-9934-BCD37B43F744}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3DED9AA7-1FC4-435D-9934-BCD37B43F744}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3DED9AA7-1FC4-435D-9934-BCD37B43F744}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -60,6 +66,7 @@ Global {068855E8-9240-4F1A-910B-CF825794513B} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0} {50B2631D-129C-47B3-A587-029CCD6099BC} = {04DBDB01-70F4-4E06-B468-8F87850B22BE} {5F1B28C6-8D0C-4155-92D0-252F7EA5F674} = {04DBDB01-70F4-4E06-B468-8F87850B22BE} + {3DED9AA7-1FC4-435D-9934-BCD37B43F744} = {04DBDB01-70F4-4E06-B468-8F87850B22BE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F} diff --git a/samples/BookStore/src/Acme.BookStore.Application/Acme.BookStore.Application.csproj b/samples/BookStore/src/Acme.BookStore.Application/Acme.BookStore.Application.csproj index 7f8acd52f5..c4c7a91bd8 100644 --- a/samples/BookStore/src/Acme.BookStore.Application/Acme.BookStore.Application.csproj +++ b/samples/BookStore/src/Acme.BookStore.Application/Acme.BookStore.Application.csproj @@ -1,13 +1,14 @@  - netcoreapp2.1 + netcoreapp2.2 Acme.BookStore - + + diff --git a/samples/BookStore/src/Acme.BookStore.Application/BookStoreApplicationModule.cs b/samples/BookStore/src/Acme.BookStore.Application/BookStoreApplicationModule.cs index e02c84a71d..00f57310f6 100644 --- a/samples/BookStore/src/Acme.BookStore.Application/BookStoreApplicationModule.cs +++ b/samples/BookStore/src/Acme.BookStore.Application/BookStoreApplicationModule.cs @@ -4,12 +4,14 @@ using Volo.Abp.Authorization.Permissions; using Volo.Abp.AutoMapper; using Volo.Abp.Identity; using Volo.Abp.Modularity; +using Volo.Abp.PermissionManagement; namespace Acme.BookStore { [DependsOn( typeof(BookStoreDomainModule), - typeof(AbpIdentityApplicationModule))] + typeof(AbpIdentityApplicationModule), + typeof(AbpPermissionManagementApplicationModule))] public class BookStoreApplicationModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/samples/BookStore/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj b/samples/BookStore/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj index 87a8e297b3..02e24618ee 100644 --- a/samples/BookStore/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj +++ b/samples/BookStore/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj @@ -1,13 +1,14 @@  - netcoreapp2.1 + netcoreapp2.2 Acme.BookStore - - + + + diff --git a/samples/BookStore/src/Acme.BookStore.Domain/BookStoreDomainModule.cs b/samples/BookStore/src/Acme.BookStore.Domain/BookStoreDomainModule.cs index 06d11fd737..f959184126 100644 --- a/samples/BookStore/src/Acme.BookStore.Domain/BookStoreDomainModule.cs +++ b/samples/BookStore/src/Acme.BookStore.Domain/BookStoreDomainModule.cs @@ -5,12 +5,15 @@ using Volo.Abp.Identity; using Volo.Abp.Localization; using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; +using Volo.Abp.PermissionManagement.Identity; using Volo.Abp.Settings; using Volo.Abp.VirtualFileSystem; namespace Acme.BookStore { - [DependsOn(typeof(AbpIdentityDomainModule))] + [DependsOn( + typeof(AbpIdentityDomainModule), + typeof(AbpPermissionManagementDomainIdentityModule))] public class BookStoreDomainModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Acme.BookStore.EntityFrameworkCore.csproj b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Acme.BookStore.EntityFrameworkCore.csproj index 44fb8928f6..88d54432b2 100644 --- a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Acme.BookStore.EntityFrameworkCore.csproj +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Acme.BookStore.EntityFrameworkCore.csproj @@ -1,26 +1,16 @@  - netcoreapp2.1 + netcoreapp2.2 Acme.BookStore - - - - - - - - - - - - - - + + + + diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs index 86d276a6f7..ed7e9862ed 100644 --- a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.Modeling; using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.PermissionManagement.EntityFrameworkCore; using Volo.Abp.SettingManagement.EntityFrameworkCore; diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20181224122651_Upgreded_ABP_Packages.Designer.cs b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20181224122651_Upgreded_ABP_Packages.Designer.cs new file mode 100644 index 0000000000..c3cbd8e6d2 --- /dev/null +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20181224122651_Upgreded_ABP_Packages.Designer.cs @@ -0,0 +1,448 @@ +// +using System; +using Acme.BookStore.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Acme.BookStore.Migrations +{ + [DbContext(typeof(BookStoreDbContext))] + [Migration("20181224122651_Upgreded_ABP_Packages")] + partial class Upgreded_ABP_Packages + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.1-rtm-30846") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Acme.BookStore.Book", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("CreationTime"); + + b.Property("CreatorId"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime"); + + b.Property("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("Price"); + + b.Property("PublishDate"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.ToTable("Books"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("Description") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256); + + b.Property("Regex") + .HasMaxLength(512); + + b.Property("RegexDescription") + .HasMaxLength(128); + + b.Property("Required"); + + b.Property("ValueType"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasMaxLength(1024); + + b.Property("RoleId"); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnName("AccessFailedCount") + .HasDefaultValue(0); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("CreationTime"); + + b.Property("CreatorId"); + + b.Property("DeleterId"); + + b.Property("DeletionTime"); + + b.Property("Email") + .HasColumnName("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("EmailConfirmed") + .HasDefaultValue(false); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted"); + + b.Property("LastModificationTime"); + + b.Property("LastModifierId"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("LockoutEnabled") + .HasDefaultValue(false); + + b.Property("LockoutEnd"); + + b.Property("Name") + .HasColumnName("Name") + .HasMaxLength(64); + + b.Property("NormalizedEmail") + .HasColumnName("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .IsRequired() + .HasColumnName("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnName("PasswordHash") + .HasMaxLength(256); + + b.Property("PhoneNumber") + .HasColumnName("PhoneNumber") + .HasMaxLength(16); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("PhoneNumberConfirmed") + .HasDefaultValue(false); + + b.Property("SecurityStamp") + .IsRequired() + .HasColumnName("SecurityStamp") + .HasMaxLength(256); + + b.Property("Surname") + .HasColumnName("Surname") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("TwoFactorEnabled") + .HasDefaultValue(false); + + b.Property("UserName") + .IsRequired() + .HasColumnName("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasMaxLength(1024); + + b.Property("TenantId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(64); + + b.Property("ProviderDisplayName") + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196); + + b.Property("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.Property("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(64); + + b.Property("Name") + .HasMaxLength(128); + + b.Property("TenantId"); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpPermissionGrants"); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasMaxLength(64); + + b.Property("ProviderName") + .HasMaxLength(64); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpSettings"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole") + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20181224122651_Upgreded_ABP_Packages.cs b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20181224122651_Upgreded_ABP_Packages.cs new file mode 100644 index 0000000000..77545ed9a3 --- /dev/null +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20181224122651_Upgreded_ABP_Packages.cs @@ -0,0 +1,75 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Acme.BookStore.Migrations +{ + public partial class Upgreded_ABP_Packages : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ConcurrencyStamp", + table: "Books", + nullable: true); + + migrationBuilder.AddColumn( + name: "ExtraProperties", + table: "Books", + nullable: true); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "AbpRoles", + maxLength: 256, + nullable: false, + oldClrType: typeof(string), + oldNullable: true); + + migrationBuilder.AddColumn( + name: "ExtraProperties", + table: "AbpRoles", + nullable: true); + + migrationBuilder.AddColumn( + name: "ConcurrencyStamp", + table: "AbpClaimTypes", + maxLength: 256, + nullable: false, + defaultValue: ""); + + migrationBuilder.AddColumn( + name: "ExtraProperties", + table: "AbpClaimTypes", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ConcurrencyStamp", + table: "Books"); + + migrationBuilder.DropColumn( + name: "ExtraProperties", + table: "Books"); + + migrationBuilder.DropColumn( + name: "ExtraProperties", + table: "AbpRoles"); + + migrationBuilder.DropColumn( + name: "ConcurrencyStamp", + table: "AbpClaimTypes"); + + migrationBuilder.DropColumn( + name: "ExtraProperties", + table: "AbpClaimTypes"); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "AbpRoles", + nullable: true, + oldClrType: typeof(string), + oldMaxLength: 256); + } + } +} diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20190111135616_ABP_v0_11_Upgrade.Designer.cs b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20190111135616_ABP_v0_11_Upgrade.Designer.cs new file mode 100644 index 0000000000..457e197cdc --- /dev/null +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20190111135616_ABP_v0_11_Upgrade.Designer.cs @@ -0,0 +1,460 @@ +// +using System; +using Acme.BookStore.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Acme.BookStore.Migrations +{ + [DbContext(typeof(BookStoreDbContext))] + [Migration("20190111135616_ABP_v0_11_Upgrade")] + partial class ABP_v0_11_Upgrade + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.0-rtm-35687") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Acme.BookStore.Book", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("Price"); + + b.Property("PublishDate"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.ToTable("Books"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("Description") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256); + + b.Property("Regex") + .HasMaxLength(512); + + b.Property("RegexDescription") + .HasMaxLength(128); + + b.Property("Required"); + + b.Property("ValueType"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasMaxLength(1024); + + b.Property("RoleId"); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnName("AccessFailedCount") + .HasDefaultValue(0); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .HasColumnName("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("EmailConfirmed") + .HasDefaultValue(false); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("LockoutEnabled") + .HasDefaultValue(false); + + b.Property("LockoutEnd"); + + b.Property("Name") + .HasColumnName("Name") + .HasMaxLength(64); + + b.Property("NormalizedEmail") + .HasColumnName("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .IsRequired() + .HasColumnName("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnName("PasswordHash") + .HasMaxLength(256); + + b.Property("PhoneNumber") + .HasColumnName("PhoneNumber") + .HasMaxLength(16); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("PhoneNumberConfirmed") + .HasDefaultValue(false); + + b.Property("SecurityStamp") + .IsRequired() + .HasColumnName("SecurityStamp") + .HasMaxLength(256); + + b.Property("Surname") + .HasColumnName("Surname") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("TwoFactorEnabled") + .HasDefaultValue(false); + + b.Property("UserName") + .IsRequired() + .HasColumnName("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasMaxLength(1024); + + b.Property("TenantId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(64); + + b.Property("ProviderDisplayName") + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196); + + b.Property("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.Property("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(64); + + b.Property("Name") + .HasMaxLength(128); + + b.Property("TenantId"); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpPermissionGrants"); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasMaxLength(64); + + b.Property("ProviderName") + .HasMaxLength(64); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpSettings"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole") + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20190111135616_ABP_v0_11_Upgrade.cs b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20190111135616_ABP_v0_11_Upgrade.cs new file mode 100644 index 0000000000..b77106644b --- /dev/null +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/20190111135616_ABP_v0_11_Upgrade.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Acme.BookStore.Migrations +{ + public partial class ABP_v0_11_Upgrade : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "IsDeleted", + table: "AbpUsers", + nullable: false, + defaultValue: false, + oldClrType: typeof(bool)); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "AbpUsers", + nullable: true, + oldClrType: typeof(string), + oldMaxLength: 256); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "IsDeleted", + table: "AbpUsers", + nullable: false, + oldClrType: typeof(bool), + oldDefaultValue: false); + + migrationBuilder.AlterColumn( + name: "ConcurrencyStamp", + table: "AbpUsers", + maxLength: 256, + nullable: false, + oldClrType: typeof(string), + oldNullable: true); + } + } +} diff --git a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs index e3bd17d745..646df02f86 100644 --- a/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs +++ b/samples/BookStore/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs @@ -15,7 +15,7 @@ namespace Acme.BookStore.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.1.1-rtm-30846") + .HasAnnotation("ProductVersion", "2.2.0-rtm-35687") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -24,13 +24,24 @@ namespace Acme.BookStore.Migrations b.Property("Id") .ValueGeneratedOnAdd(); - b.Property("CreationTime"); + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnName("CreationTime"); - b.Property("CreatorId"); + b.Property("CreatorId") + .HasColumnName("CreatorId"); - b.Property("LastModificationTime"); + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); - b.Property("LastModifierId"); + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); b.Property("Name") .IsRequired() @@ -52,9 +63,18 @@ namespace Acme.BookStore.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + b.Property("Description") .HasMaxLength(256); + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + b.Property("IsStatic"); b.Property("Name") @@ -81,7 +101,14 @@ namespace Acme.BookStore.Migrations b.Property("Id") .ValueGeneratedOnAdd(); - b.Property("ConcurrencyStamp"); + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); b.Property("IsDefault") .HasColumnName("IsDefault"); @@ -143,17 +170,20 @@ namespace Acme.BookStore.Migrations .HasDefaultValue(0); b.Property("ConcurrencyStamp") - .IsRequired() - .HasColumnName("ConcurrencyStamp") - .HasMaxLength(256); + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); - b.Property("CreationTime"); + b.Property("CreationTime") + .HasColumnName("CreationTime"); - b.Property("CreatorId"); + b.Property("CreatorId") + .HasColumnName("CreatorId"); - b.Property("DeleterId"); + b.Property("DeleterId") + .HasColumnName("DeleterId"); - b.Property("DeletionTime"); + b.Property("DeletionTime") + .HasColumnName("DeletionTime"); b.Property("Email") .HasColumnName("Email") @@ -167,11 +197,16 @@ namespace Acme.BookStore.Migrations b.Property("ExtraProperties") .HasColumnName("ExtraProperties"); - b.Property("IsDeleted"); + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasDefaultValue(false); - b.Property("LastModificationTime"); + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); - b.Property("LastModifierId"); + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); b.Property("LockoutEnabled") .ValueGeneratedOnAdd() diff --git a/samples/BookStore/src/Acme.BookStore.Web/Acme.BookStore.Web.csproj b/samples/BookStore/src/Acme.BookStore.Web/Acme.BookStore.Web.csproj index 5cfa52f2c8..ae71fd38d8 100644 --- a/samples/BookStore/src/Acme.BookStore.Web/Acme.BookStore.Web.csproj +++ b/samples/BookStore/src/Acme.BookStore.Web/Acme.BookStore.Web.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp2.2 Acme.BookStore $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; true @@ -18,7 +18,7 @@ - + @@ -27,10 +27,10 @@ - - - - + + + + diff --git a/samples/BookStore/src/Acme.BookStore.Web/BookStoreWebModule.cs b/samples/BookStore/src/Acme.BookStore.Web/BookStoreWebModule.cs index d658237ddb..6309f6164b 100644 --- a/samples/BookStore/src/Acme.BookStore.Web/BookStoreWebModule.cs +++ b/samples/BookStore/src/Acme.BookStore.Web/BookStoreWebModule.cs @@ -2,7 +2,6 @@ using Localization.Resources.AbpUi; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Acme.BookStore.EntityFrameworkCore; using Acme.BookStore.Localization.BookStore; @@ -10,20 +9,20 @@ using Acme.BookStore.Menus; using Swashbuckle.AspNetCore.Swagger; using Volo.Abp; using Volo.Abp.Account.Web; -using Volo.Abp.AspNetCore.Modularity; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.Autofac; using Volo.Abp.AutoMapper; -using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Identity; using Volo.Abp.Identity.Web; using Volo.Abp.Localization; using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; +using Volo.Abp.PermissionManagement; using Volo.Abp.Threading; using Volo.Abp.UI.Navigation; using Volo.Abp.VirtualFileSystem; @@ -56,52 +55,50 @@ namespace Acme.BookStore public override void ConfigureServices(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); - var configuration = context.Services.BuildConfiguration(); - - ConfigureDatabaseServices(context.Services, configuration); - ConfigureAutoMapper(context.Services); - ConfigureVirtualFileSystem(context.Services, hostingEnvironment); - ConfigureLocalizationServices(context.Services); - ConfigureNavigationServices(context.Services); - ConfigureAutoApiControllers(context.Services); + var configuration = context.Services.GetConfiguration(); + + ConfigureDatabaseServices(); + ConfigureAutoMapper(); + ConfigureVirtualFileSystem(hostingEnvironment); + ConfigureLocalizationServices(); + ConfigureNavigationServices(); + ConfigureAutoApiControllers(); ConfigureSwaggerServices(context.Services); context.Services.AddAssemblyOf(); } - private static void ConfigureDatabaseServices(IServiceCollection services, IConfigurationRoot configuration) + private void ConfigureDatabaseServices() { - services.Configure(options => + Configure(options => { - options.ConnectionStrings.Default = configuration.GetConnectionString("Default"); + options.UseSqlServer(); }); - - services.Configure(options => { options.UseSqlServer(); }); } - private static void ConfigureAutoMapper(IServiceCollection services) + private void ConfigureAutoMapper() { - services.Configure(options => + Configure(options => { options.AddProfile(); }); } - private static void ConfigureVirtualFileSystem(IServiceCollection services, IHostingEnvironment hostingEnvironment) + private void ConfigureVirtualFileSystem(IHostingEnvironment hostingEnvironment) { if (hostingEnvironment.IsDevelopment()) { - services.Configure(options => + Configure(options => { - options.FileSets.ReplaceEmbeddedByPyhsical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Acme.BookStore.Domain", Path.DirectorySeparatorChar))); + options.FileSets.ReplaceEmbeddedByPhysical(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Acme.BookStore.Domain", Path.DirectorySeparatorChar))); }); } } - private static void ConfigureLocalizationServices(IServiceCollection services) + private void ConfigureLocalizationServices() { - services.Configure(options => + Configure(options => { options.Resources .Get() @@ -115,29 +112,30 @@ namespace Acme.BookStore }); } - private static void ConfigureNavigationServices(IServiceCollection services) + private void ConfigureNavigationServices() { - services.Configure(options => + Configure(options => { options.MenuContributors.Add(new BookStoreMenuContributor()); }); } - private static void ConfigureAutoApiControllers(IServiceCollection services) + private void ConfigureAutoApiControllers() { - services.Configure(options => + Configure(options => { options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly); }); } - private static void ConfigureSwaggerServices(IServiceCollection services) + private void ConfigureSwaggerServices(IServiceCollection services) { services.AddSwaggerGen( options => { options.SwaggerDoc("v1", new Info { Title = "BookStore API", Version = "v1" }); options.DocInclusionPredicate((docName, description) => true); + options.CustomSchemaIds(type => type.FullName); }); } @@ -166,6 +164,7 @@ namespace Acme.BookStore options.SwaggerEndpoint("/swagger/v1/swagger.json", "BookStore API"); }); + //TODO: use app.UseMvcWithDefaultRouteAndArea(); after v1.3.0 release app.UseMvc(routes => { routes.MapRoute( @@ -180,17 +179,27 @@ namespace Acme.BookStore SeedDatabase(context); } - private static void SeedDatabase(ApplicationInitializationContext context) + private void SeedDatabase(ApplicationInitializationContext context) { - AsyncHelper.RunSync(async () => + using (var scope = context.ServiceProvider.CreateScope()) { - await context.ServiceProvider - .GetRequiredService() - .SeedAsync( - "1q2w3E*", - IdentityPermissions.GetAll() //.Union(BookStorePermissions.GetAll()) - ); - }); + AsyncHelper.RunSync(async () => + { + await scope.ServiceProvider + .GetRequiredService() + .SeedAsync( + "1q2w3E*" + ); + + await scope.ServiceProvider + .GetRequiredService() + .SeedAsync( + RolePermissionValueProvider.ProviderName, + "admin", + IdentityPermissions.GetAll() //.Union(BookStorePermissions.GetAll()) + ); + }); + } } } } diff --git a/samples/BookStore/test/Acme.BookStore.Application.Tests/Acme.BookStore.Application.Tests.csproj b/samples/BookStore/test/Acme.BookStore.Application.Tests/Acme.BookStore.Application.Tests.csproj index fe3b577dc5..baa40a77a4 100644 --- a/samples/BookStore/test/Acme.BookStore.Application.Tests/Acme.BookStore.Application.Tests.csproj +++ b/samples/BookStore/test/Acme.BookStore.Application.Tests/Acme.BookStore.Application.Tests.csproj @@ -1,26 +1,26 @@  - netcoreapp2.1 + netcoreapp2.2 Acme.BookStore - - + + - + - - - - - - + + + + + + diff --git a/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/Acme.BookStore.ConsoleApiClient.csproj b/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/Acme.BookStore.ConsoleApiClient.csproj new file mode 100644 index 0000000000..0972a7878d --- /dev/null +++ b/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/Acme.BookStore.ConsoleApiClient.csproj @@ -0,0 +1,20 @@ + + + + Exe + netcoreapp2.2 + + + + + + + + + + + Always + + + + diff --git a/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/ApiClientDemoService.cs b/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/ApiClientDemoService.cs new file mode 100644 index 0000000000..5aa617da5e --- /dev/null +++ b/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/ApiClientDemoService.cs @@ -0,0 +1,27 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.DependencyInjection; + +namespace Acme.BookStore.ConsoleApiClient +{ + public class ApiClientDemoService : ITransientDependency + { + private readonly IBookAppService _bookAppService; + + public ApiClientDemoService(IBookAppService bookAppService) + { + _bookAppService = bookAppService; + } + + public async Task RunAsync() + { + //While it seems like a regular method call, it actually calls a remote REST API. + var output = await _bookAppService.GetListAsync(new PagedAndSortedResultRequestDto()); + foreach (var bookDto in output.Items) + { + Console.WriteLine($"[BOOK {bookDto.Id}] Name={bookDto.Name}, Price={bookDto.Price}"); + } + } + } +} diff --git a/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/ConsoleApiClientModule.cs b/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/ConsoleApiClientModule.cs new file mode 100644 index 0000000000..2d2be8b568 --- /dev/null +++ b/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/ConsoleApiClientModule.cs @@ -0,0 +1,22 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Autofac; +using Volo.Abp.Http.Client; +using Volo.Abp.Modularity; + +namespace Acme.BookStore.ConsoleApiClient +{ + [DependsOn( + typeof(AbpAutofacModule), + typeof(AbpHttpClientModule), + typeof(BookStoreApplicationModule) + )] + public class ConsoleApiClientModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddHttpClientProxies( + typeof(BookStoreApplicationModule).Assembly + ); + } + } +} diff --git a/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/Program.cs b/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/Program.cs new file mode 100644 index 0000000000..2e0ffa25c7 --- /dev/null +++ b/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/Program.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; +using Volo.Abp.Threading; + +namespace Acme.BookStore.ConsoleApiClient +{ + /* Before running this application, ensure that the Acme.BookStore.Web application is running. + */ + class Program + { + static void Main(string[] args) + { + using (var application = AbpApplicationFactory.Create(options => + { + options.UseAutofac(); + })) + { + application.Initialize(); + + using (var scope = application.ServiceProvider.CreateScope()) + { + var demoService = scope.ServiceProvider.GetRequiredService(); + AsyncHelper.RunSync(() => demoService.RunAsync()); + } + + Console.WriteLine("Press ENTER to stop application..."); + Console.ReadLine(); + } + } + } +} diff --git a/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/appsettings.json b/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/appsettings.json new file mode 100644 index 0000000000..1f3cc219b5 --- /dev/null +++ b/samples/BookStore/test/Acme.BookStore.ConsoleApiClient/appsettings.json @@ -0,0 +1,7 @@ +{ + "RemoteServices": { + "Default": { + "BaseUrl": "http://localhost:53929/" + } + } +} \ No newline at end of file diff --git a/samples/BookStore/test/Acme.BookStore.Web.Tests/Acme.BookStore.Web.Tests.csproj b/samples/BookStore/test/Acme.BookStore.Web.Tests/Acme.BookStore.Web.Tests.csproj index c10970a304..208552c0a8 100644 --- a/samples/BookStore/test/Acme.BookStore.Web.Tests/Acme.BookStore.Web.Tests.csproj +++ b/samples/BookStore/test/Acme.BookStore.Web.Tests/Acme.BookStore.Web.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp2.2 Exe $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; Acme.BookStore @@ -12,10 +12,10 @@ - + - + diff --git a/samples/BookStore/test/Acme.BookStore.Web.Tests/BookStoreWebTestModule.cs b/samples/BookStore/test/Acme.BookStore.Web.Tests/BookStoreWebTestModule.cs index 42c3fde03d..911b4ba3aa 100644 --- a/samples/BookStore/test/Acme.BookStore.Web.Tests/BookStoreWebTestModule.cs +++ b/samples/BookStore/test/Acme.BookStore.Web.Tests/BookStoreWebTestModule.cs @@ -4,16 +4,13 @@ using Localization.Resources.AbpUi; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc.ApplicationParts; -using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Acme.BookStore.Localization.BookStore; using Acme.BookStore.Menus; using Volo.Abp; using Volo.Abp.Account.Web; -using Volo.Abp.AspNetCore.Modularity; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic; -using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.AspNetCore.TestBase; using Volo.Abp.Identity.Web; using Volo.Abp.Localization; diff --git a/samples/MicroserviceDemo/MicroserviceDemo.sln b/samples/MicroserviceDemo/MicroserviceDemo.sln new file mode 100644 index 0000000000..65c254b4c6 --- /dev/null +++ b/samples/MicroserviceDemo/MicroserviceDemo.sln @@ -0,0 +1,192 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.168 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "microservices", "microservices", "{3B26D176-390B-4F51-BE52-E9B422C28A88}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "applications", "applications", "{8F6834D7-E6FA-4A04-83BB-955F68EA0A0A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{818134CC-2F7F-41B9-ACA6-87F0650F5D52}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "product", "product", "{8FFAECCC-B4A6-4441-AD10-379ADEDD5A19}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F84AC200-1E5A-4FC3-9407-FB2FF527EDA8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D1526262-55E0-43F1-9EF1-C6095E76A9E2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.Domain.Shared", "modules\product\src\ProductManagement.Domain.Shared\ProductManagement.Domain.Shared.csproj", "{44A448CC-D8DD-4AA5-861A-78186FC5CE69}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.Domain", "modules\product\src\ProductManagement.Domain\ProductManagement.Domain.csproj", "{65593638-9904-424B-831F-F5215EC4312B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.Application.Contracts", "modules\product\src\ProductManagement.Application.Contracts\ProductManagement.Application.Contracts.csproj", "{217CD5A1-182F-4D8D-88CA-16DC1EA8525A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.Application", "modules\product\src\ProductManagement.Application\ProductManagement.Application.csproj", "{66B2E371-2495-4E76-A6F9-540125C5FB37}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.EntityFrameworkCore", "modules\product\src\ProductManagement.EntityFrameworkCore\ProductManagement.EntityFrameworkCore.csproj", "{B22DCAA4-FC9E-4F06-B1BA-41169341B215}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.HttpApi", "modules\product\src\ProductManagement.HttpApi\ProductManagement.HttpApi.csproj", "{CFAD2A4B-445A-4EA3-8AF1-C054ECC2DFC5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.HttpApi.Client", "modules\product\src\ProductManagement.HttpApi.Client\ProductManagement.HttpApi.Client.csproj", "{4A1C1CF9-74A6-43F9-876C-BB0083EC6FB8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.Web", "modules\product\src\ProductManagement.Web\ProductManagement.Web.csproj", "{4A8594CB-8877-412B-9C80-90A5D3366095}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.TestBase", "modules\product\test\ProductManagement.TestBase\ProductManagement.TestBase.csproj", "{4D3244F4-487F-4CED-A8C9-E88723EB835A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.EntityFrameworkCore.Tests", "modules\product\test\ProductManagement.EntityFrameworkCore.Tests\ProductManagement.EntityFrameworkCore.Tests.csproj", "{1FA2B816-7841-44B0-931C-D4F84DA7E146}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.Domain.Tests", "modules\product\test\ProductManagement.Domain.Tests\ProductManagement.Domain.Tests.csproj", "{BDCDBC2D-C05B-4A18-A698-86525E3EFC95}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductManagement.Application.Tests", "modules\product\test\ProductManagement.Application.Tests\ProductManagement.Application.Tests.csproj", "{B6F469F0-FB01-4A60-B6A6-D4127907E3B6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gateways", "gateways", "{617037ED-34E3-49A2-8958-BE2013E2D151}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PublicWebSiteGateway.Host", "gateways\PublicWebSiteGateway.Host\PublicWebSiteGateway.Host.csproj", "{D48F6DDC-4AFC-4554-86B1-7763C0679B59}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BackendAdminAppGateway.Host", "gateways\BackendAdminAppGateway.Host\BackendAdminAppGateway.Host.csproj", "{BD4ABDEA-2F09-4CB4-855F-B06C307A352E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InternalGateway.Host", "gateways\InternalGateway.Host\InternalGateway.Host.csproj", "{EAE8C1F5-C8D0-4132-A8CB-D374F2C363E2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BloggingService.Host", "microservices\BloggingService.Host\BloggingService.Host.csproj", "{79B45294-8352-4B19-824C-F5B84E52725A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IdentityService.Host", "microservices\IdentityService.Host\IdentityService.Host.csproj", "{6FDF254B-DEAF-4336-8F70-9E360E3E5B8B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProductService.Host", "microservices\ProductService.Host\ProductService.Host.csproj", "{63E38ABD-0B26-44E5-84CA-557D3DFC9506}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthServer.Host", "applications\AuthServer.Host\AuthServer.Host.csproj", "{F9F6CCC2-5985-4853-BBA1-A85D60373DBC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BackendAdminApp.Host", "applications\BackendAdminApp.Host\BackendAdminApp.Host.csproj", "{2199D857-C926-4948-A7F7-A11E344F90AA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleClientDemo", "applications\ConsoleClientDemo\ConsoleClientDemo.csproj", "{BB8FA269-460D-42BE-90A0-E97D6A3FDEB1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PublicWebSite.Host", "applications\PublicWebSite.Host\PublicWebSite.Host.csproj", "{29A3A4EF-DEC4-4E43-B6B8-D565667F85EC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {44A448CC-D8DD-4AA5-861A-78186FC5CE69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44A448CC-D8DD-4AA5-861A-78186FC5CE69}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44A448CC-D8DD-4AA5-861A-78186FC5CE69}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44A448CC-D8DD-4AA5-861A-78186FC5CE69}.Release|Any CPU.Build.0 = Release|Any CPU + {65593638-9904-424B-831F-F5215EC4312B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {65593638-9904-424B-831F-F5215EC4312B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {65593638-9904-424B-831F-F5215EC4312B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {65593638-9904-424B-831F-F5215EC4312B}.Release|Any CPU.Build.0 = Release|Any CPU + {217CD5A1-182F-4D8D-88CA-16DC1EA8525A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {217CD5A1-182F-4D8D-88CA-16DC1EA8525A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {217CD5A1-182F-4D8D-88CA-16DC1EA8525A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {217CD5A1-182F-4D8D-88CA-16DC1EA8525A}.Release|Any CPU.Build.0 = Release|Any CPU + {66B2E371-2495-4E76-A6F9-540125C5FB37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {66B2E371-2495-4E76-A6F9-540125C5FB37}.Debug|Any CPU.Build.0 = Debug|Any CPU + {66B2E371-2495-4E76-A6F9-540125C5FB37}.Release|Any CPU.ActiveCfg = Release|Any CPU + {66B2E371-2495-4E76-A6F9-540125C5FB37}.Release|Any CPU.Build.0 = Release|Any CPU + {B22DCAA4-FC9E-4F06-B1BA-41169341B215}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B22DCAA4-FC9E-4F06-B1BA-41169341B215}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B22DCAA4-FC9E-4F06-B1BA-41169341B215}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B22DCAA4-FC9E-4F06-B1BA-41169341B215}.Release|Any CPU.Build.0 = Release|Any CPU + {CFAD2A4B-445A-4EA3-8AF1-C054ECC2DFC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CFAD2A4B-445A-4EA3-8AF1-C054ECC2DFC5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CFAD2A4B-445A-4EA3-8AF1-C054ECC2DFC5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CFAD2A4B-445A-4EA3-8AF1-C054ECC2DFC5}.Release|Any CPU.Build.0 = Release|Any CPU + {4A1C1CF9-74A6-43F9-876C-BB0083EC6FB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A1C1CF9-74A6-43F9-876C-BB0083EC6FB8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A1C1CF9-74A6-43F9-876C-BB0083EC6FB8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A1C1CF9-74A6-43F9-876C-BB0083EC6FB8}.Release|Any CPU.Build.0 = Release|Any CPU + {4A8594CB-8877-412B-9C80-90A5D3366095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A8594CB-8877-412B-9C80-90A5D3366095}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A8594CB-8877-412B-9C80-90A5D3366095}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A8594CB-8877-412B-9C80-90A5D3366095}.Release|Any CPU.Build.0 = Release|Any CPU + {4D3244F4-487F-4CED-A8C9-E88723EB835A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D3244F4-487F-4CED-A8C9-E88723EB835A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D3244F4-487F-4CED-A8C9-E88723EB835A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D3244F4-487F-4CED-A8C9-E88723EB835A}.Release|Any CPU.Build.0 = Release|Any CPU + {1FA2B816-7841-44B0-931C-D4F84DA7E146}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FA2B816-7841-44B0-931C-D4F84DA7E146}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FA2B816-7841-44B0-931C-D4F84DA7E146}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FA2B816-7841-44B0-931C-D4F84DA7E146}.Release|Any CPU.Build.0 = Release|Any CPU + {BDCDBC2D-C05B-4A18-A698-86525E3EFC95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BDCDBC2D-C05B-4A18-A698-86525E3EFC95}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BDCDBC2D-C05B-4A18-A698-86525E3EFC95}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BDCDBC2D-C05B-4A18-A698-86525E3EFC95}.Release|Any CPU.Build.0 = Release|Any CPU + {B6F469F0-FB01-4A60-B6A6-D4127907E3B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6F469F0-FB01-4A60-B6A6-D4127907E3B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6F469F0-FB01-4A60-B6A6-D4127907E3B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6F469F0-FB01-4A60-B6A6-D4127907E3B6}.Release|Any CPU.Build.0 = Release|Any CPU + {D48F6DDC-4AFC-4554-86B1-7763C0679B59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D48F6DDC-4AFC-4554-86B1-7763C0679B59}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D48F6DDC-4AFC-4554-86B1-7763C0679B59}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D48F6DDC-4AFC-4554-86B1-7763C0679B59}.Release|Any CPU.Build.0 = Release|Any CPU + {BD4ABDEA-2F09-4CB4-855F-B06C307A352E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD4ABDEA-2F09-4CB4-855F-B06C307A352E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD4ABDEA-2F09-4CB4-855F-B06C307A352E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD4ABDEA-2F09-4CB4-855F-B06C307A352E}.Release|Any CPU.Build.0 = Release|Any CPU + {EAE8C1F5-C8D0-4132-A8CB-D374F2C363E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EAE8C1F5-C8D0-4132-A8CB-D374F2C363E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAE8C1F5-C8D0-4132-A8CB-D374F2C363E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EAE8C1F5-C8D0-4132-A8CB-D374F2C363E2}.Release|Any CPU.Build.0 = Release|Any CPU + {79B45294-8352-4B19-824C-F5B84E52725A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79B45294-8352-4B19-824C-F5B84E52725A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79B45294-8352-4B19-824C-F5B84E52725A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79B45294-8352-4B19-824C-F5B84E52725A}.Release|Any CPU.Build.0 = Release|Any CPU + {6FDF254B-DEAF-4336-8F70-9E360E3E5B8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6FDF254B-DEAF-4336-8F70-9E360E3E5B8B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6FDF254B-DEAF-4336-8F70-9E360E3E5B8B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6FDF254B-DEAF-4336-8F70-9E360E3E5B8B}.Release|Any CPU.Build.0 = Release|Any CPU + {63E38ABD-0B26-44E5-84CA-557D3DFC9506}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {63E38ABD-0B26-44E5-84CA-557D3DFC9506}.Debug|Any CPU.Build.0 = Debug|Any CPU + {63E38ABD-0B26-44E5-84CA-557D3DFC9506}.Release|Any CPU.ActiveCfg = Release|Any CPU + {63E38ABD-0B26-44E5-84CA-557D3DFC9506}.Release|Any CPU.Build.0 = Release|Any CPU + {F9F6CCC2-5985-4853-BBA1-A85D60373DBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F9F6CCC2-5985-4853-BBA1-A85D60373DBC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F9F6CCC2-5985-4853-BBA1-A85D60373DBC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F9F6CCC2-5985-4853-BBA1-A85D60373DBC}.Release|Any CPU.Build.0 = Release|Any CPU + {2199D857-C926-4948-A7F7-A11E344F90AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2199D857-C926-4948-A7F7-A11E344F90AA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2199D857-C926-4948-A7F7-A11E344F90AA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2199D857-C926-4948-A7F7-A11E344F90AA}.Release|Any CPU.Build.0 = Release|Any CPU + {BB8FA269-460D-42BE-90A0-E97D6A3FDEB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BB8FA269-460D-42BE-90A0-E97D6A3FDEB1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BB8FA269-460D-42BE-90A0-E97D6A3FDEB1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BB8FA269-460D-42BE-90A0-E97D6A3FDEB1}.Release|Any CPU.Build.0 = Release|Any CPU + {29A3A4EF-DEC4-4E43-B6B8-D565667F85EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29A3A4EF-DEC4-4E43-B6B8-D565667F85EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29A3A4EF-DEC4-4E43-B6B8-D565667F85EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29A3A4EF-DEC4-4E43-B6B8-D565667F85EC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {8FFAECCC-B4A6-4441-AD10-379ADEDD5A19} = {818134CC-2F7F-41B9-ACA6-87F0650F5D52} + {F84AC200-1E5A-4FC3-9407-FB2FF527EDA8} = {8FFAECCC-B4A6-4441-AD10-379ADEDD5A19} + {D1526262-55E0-43F1-9EF1-C6095E76A9E2} = {8FFAECCC-B4A6-4441-AD10-379ADEDD5A19} + {44A448CC-D8DD-4AA5-861A-78186FC5CE69} = {F84AC200-1E5A-4FC3-9407-FB2FF527EDA8} + {65593638-9904-424B-831F-F5215EC4312B} = {F84AC200-1E5A-4FC3-9407-FB2FF527EDA8} + {217CD5A1-182F-4D8D-88CA-16DC1EA8525A} = {F84AC200-1E5A-4FC3-9407-FB2FF527EDA8} + {66B2E371-2495-4E76-A6F9-540125C5FB37} = {F84AC200-1E5A-4FC3-9407-FB2FF527EDA8} + {B22DCAA4-FC9E-4F06-B1BA-41169341B215} = {F84AC200-1E5A-4FC3-9407-FB2FF527EDA8} + {CFAD2A4B-445A-4EA3-8AF1-C054ECC2DFC5} = {F84AC200-1E5A-4FC3-9407-FB2FF527EDA8} + {4A1C1CF9-74A6-43F9-876C-BB0083EC6FB8} = {F84AC200-1E5A-4FC3-9407-FB2FF527EDA8} + {4A8594CB-8877-412B-9C80-90A5D3366095} = {F84AC200-1E5A-4FC3-9407-FB2FF527EDA8} + {4D3244F4-487F-4CED-A8C9-E88723EB835A} = {D1526262-55E0-43F1-9EF1-C6095E76A9E2} + {1FA2B816-7841-44B0-931C-D4F84DA7E146} = {D1526262-55E0-43F1-9EF1-C6095E76A9E2} + {BDCDBC2D-C05B-4A18-A698-86525E3EFC95} = {D1526262-55E0-43F1-9EF1-C6095E76A9E2} + {B6F469F0-FB01-4A60-B6A6-D4127907E3B6} = {D1526262-55E0-43F1-9EF1-C6095E76A9E2} + {D48F6DDC-4AFC-4554-86B1-7763C0679B59} = {617037ED-34E3-49A2-8958-BE2013E2D151} + {BD4ABDEA-2F09-4CB4-855F-B06C307A352E} = {617037ED-34E3-49A2-8958-BE2013E2D151} + {EAE8C1F5-C8D0-4132-A8CB-D374F2C363E2} = {617037ED-34E3-49A2-8958-BE2013E2D151} + {79B45294-8352-4B19-824C-F5B84E52725A} = {3B26D176-390B-4F51-BE52-E9B422C28A88} + {6FDF254B-DEAF-4336-8F70-9E360E3E5B8B} = {3B26D176-390B-4F51-BE52-E9B422C28A88} + {63E38ABD-0B26-44E5-84CA-557D3DFC9506} = {3B26D176-390B-4F51-BE52-E9B422C28A88} + {F9F6CCC2-5985-4853-BBA1-A85D60373DBC} = {8F6834D7-E6FA-4A04-83BB-955F68EA0A0A} + {2199D857-C926-4948-A7F7-A11E344F90AA} = {8F6834D7-E6FA-4A04-83BB-955F68EA0A0A} + {BB8FA269-460D-42BE-90A0-E97D6A3FDEB1} = {8F6834D7-E6FA-4A04-83BB-955F68EA0A0A} + {29A3A4EF-DEC4-4E43-B6B8-D565667F85EC} = {8F6834D7-E6FA-4A04-83BB-955F68EA0A0A} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {37474F0D-2E52-4D2F-B39B-7FE3FF31B4EC} + EndGlobalSection +EndGlobal diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/AuthServer.Host.csproj b/samples/MicroserviceDemo/applications/AuthServer.Host/AuthServer.Host.csproj new file mode 100644 index 0000000000..324b4abf06 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/AuthServer.Host.csproj @@ -0,0 +1,42 @@ + + + + netcoreapp2.2 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + true + true + true + true + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/AuthServerHostModule.cs b/samples/MicroserviceDemo/applications/AuthServer.Host/AuthServerHostModule.cs new file mode 100644 index 0000000000..3d1112c760 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/AuthServerHostModule.cs @@ -0,0 +1,98 @@ +using AuthServer.Host.EntityFrameworkCore; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; +using Volo.Abp.Account.Web; +using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic; +using Volo.Abp.AuditLogging.EntityFrameworkCore; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.EventBus.RabbitMq; +using Volo.Abp.Autofac; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.SqlServer; +using Volo.Abp.Identity; +using Volo.Abp.Identity.EntityFrameworkCore; +using Volo.Abp.IdentityServer.EntityFrameworkCore; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.PermissionManagement; +using Volo.Abp.PermissionManagement.EntityFrameworkCore; +using Volo.Abp.SettingManagement.EntityFrameworkCore; +using Volo.Abp.Threading; + +namespace AuthServer.Host +{ + [DependsOn( + typeof(AbpAutofacModule), + typeof(AbpEventBusRabbitMqModule), + typeof(AbpPermissionManagementEntityFrameworkCoreModule), + typeof(AbpAuditLoggingEntityFrameworkCoreModule), + typeof(AbpSettingManagementEntityFrameworkCoreModule), + typeof(AbpIdentityEntityFrameworkCoreModule), + typeof(AbpIdentityApplicationContractsModule), + typeof(AbpIdentityServerEntityFrameworkCoreModule), + typeof(AbpEntityFrameworkCoreSqlServerModule), + typeof(AbpAccountWebIdentityServerModule), + typeof(AbpAspNetCoreMvcUiBasicThemeModule) + )] + public class AuthServerHostModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + context.Services.AddAbpDbContext(options => + { + options.AddDefaultRepositories(); + }); + + Configure(options => + { + options.UseSqlServer(); + }); + + Configure(options => + { + options.Languages.Add(new LanguageInfo("en", "en", "English")); + }); + + context.Services.AddDistributedRedisCache(options => + { + options.Configuration = configuration["Redis:Configuration"]; + }); + } + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var app = context.GetApplicationBuilder(); + + app.UseVirtualFiles(); + app.UseIdentityServer(); + app.UseAbpRequestLocalization(); + app.UseAuditing(); + app.UseMvcWithDefaultRouteAndArea(); + + //TODO: Problem on a clustered environment + using (var scope = context.ServiceProvider.CreateScope()) + { + AsyncHelper.RunSync(async () => + { + await scope.ServiceProvider + .GetRequiredService() + .SeedAsync( + adminUserPassword: "1q2w3E*" + ); + + await scope.ServiceProvider + .GetRequiredService() + .SeedAsync( + RolePermissionValueProvider.ProviderName, + "admin", + IdentityPermissions.GetAll() + ); + }); + } + + } + } +} diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/EntityFrameworkCore/AuthServerDbContext.cs b/samples/MicroserviceDemo/applications/AuthServer.Host/EntityFrameworkCore/AuthServerDbContext.cs new file mode 100644 index 0000000000..e17372071c --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/EntityFrameworkCore/AuthServerDbContext.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.AuditLogging.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Identity.EntityFrameworkCore; +using Volo.Abp.IdentityServer.EntityFrameworkCore; +using Volo.Abp.PermissionManagement.EntityFrameworkCore; +using Volo.Abp.SettingManagement.EntityFrameworkCore; + +namespace AuthServer.Host.EntityFrameworkCore +{ + public class AuthServerDbContext : AbpDbContext + { + public AuthServerDbContext(DbContextOptions options) + : base(options) + { + + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.ConfigureIdentity(); + modelBuilder.ConfigureIdentityServer(); + modelBuilder.ConfigureAuditLogging(); + modelBuilder.ConfigurePermissionManagement(); + modelBuilder.ConfigureSettingManagement(); + } + } +} diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/EntityFrameworkCore/AuthServerDbContextFactory.cs b/samples/MicroserviceDemo/applications/AuthServer.Host/EntityFrameworkCore/AuthServerDbContextFactory.cs new file mode 100644 index 0000000000..2a001134dd --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/EntityFrameworkCore/AuthServerDbContextFactory.cs @@ -0,0 +1,29 @@ +using System.IO; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Configuration; + +namespace AuthServer.Host.EntityFrameworkCore +{ + public class AuthServerDbContextFactory : IDesignTimeDbContextFactory + { + public AuthServerDbContext CreateDbContext(string[] args) + { + var configuration = BuildConfiguration(); + + var builder = new DbContextOptionsBuilder() + .UseSqlServer(configuration.GetConnectionString("Default")); + + return new AuthServerDbContext(builder.Options); + } + + private static IConfigurationRoot BuildConfiguration() + { + var builder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false); + + return builder.Build(); + } + } +} diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/Migrations/20190117081756_Initial.Designer.cs b/samples/MicroserviceDemo/applications/AuthServer.Host/Migrations/20190117081756_Initial.Designer.cs new file mode 100644 index 0000000000..fc7980a757 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/Migrations/20190117081756_Initial.Designer.cs @@ -0,0 +1,1142 @@ +// +using System; +using AuthServer.Host.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace AuthServer.Host.Migrations +{ + [DbContext(typeof(AuthServerDbContext))] + [Migration("20190117081756_Initial")] + partial class Initial + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.0-rtm-35687") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BrowserInfo") + .HasColumnName("BrowserInfo") + .HasMaxLength(512); + + b.Property("ClientIpAddress") + .HasColumnName("ClientIpAddress") + .HasMaxLength(64); + + b.Property("ClientName") + .HasColumnName("ClientName") + .HasMaxLength(128); + + b.Property("Comments") + .HasColumnName("Comments") + .HasMaxLength(256); + + b.Property("ConcurrencyStamp"); + + b.Property("Exceptions") + .HasColumnName("Exceptions") + .HasMaxLength(4000); + + b.Property("ExecutionDuration") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasColumnName("HttpMethod") + .HasMaxLength(16); + + b.Property("HttpStatusCode") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorUserId") + .HasColumnName("ImpersonatorUserId"); + + b.Property("TenantId") + .HasColumnName("TenantId"); + + b.Property("Url") + .HasColumnName("Url") + .HasMaxLength(256); + + b.Property("UserId") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasColumnName("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AbpAuditLogs"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuditLogId") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasColumnName("MethodName") + .HasMaxLength(128); + + b.Property("Parameters") + .HasColumnName("Parameters") + .HasMaxLength(2000); + + b.Property("ServiceName") + .HasColumnName("ServiceName") + .HasMaxLength(256); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AbpAuditLogActions"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuditLogId") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .IsRequired() + .HasColumnName("EntityId") + .HasMaxLength(128); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasColumnName("EntityTypeFullName") + .HasMaxLength(128); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("AbpEntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EntityChangeId"); + + b.Property("NewValue") + .HasColumnName("NewValue") + .HasMaxLength(512); + + b.Property("OriginalValue") + .HasColumnName("OriginalValue") + .HasMaxLength(512); + + b.Property("PropertyName") + .IsRequired() + .HasColumnName("PropertyName") + .HasMaxLength(128); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasColumnName("PropertyTypeFullName") + .HasMaxLength(64); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("AbpEntityPropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("Description") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256); + + b.Property("Regex") + .HasMaxLength(512); + + b.Property("RegexDescription") + .HasMaxLength(128); + + b.Property("Required"); + + b.Property("ValueType"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasMaxLength(1024); + + b.Property("RoleId"); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnName("AccessFailedCount") + .HasDefaultValue(0); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .HasColumnName("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("EmailConfirmed") + .HasDefaultValue(false); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("LockoutEnabled") + .HasDefaultValue(false); + + b.Property("LockoutEnd"); + + b.Property("Name") + .HasColumnName("Name") + .HasMaxLength(64); + + b.Property("NormalizedEmail") + .HasColumnName("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .IsRequired() + .HasColumnName("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnName("PasswordHash") + .HasMaxLength(256); + + b.Property("PhoneNumber") + .HasColumnName("PhoneNumber") + .HasMaxLength(16); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("PhoneNumberConfirmed") + .HasDefaultValue(false); + + b.Property("SecurityStamp") + .IsRequired() + .HasColumnName("SecurityStamp") + .HasMaxLength(256); + + b.Property("Surname") + .HasColumnName("Surname") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("TwoFactorEnabled") + .HasDefaultValue(false); + + b.Property("UserName") + .IsRequired() + .HasColumnName("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasMaxLength(1024); + + b.Property("TenantId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(64); + + b.Property("ProviderDisplayName") + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196); + + b.Property("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.Property("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(64); + + b.Property("Name") + .HasMaxLength(128); + + b.Property("TenantId"); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp"); + + b.Property("Description") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasMaxLength(200); + + b.Property("Enabled"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200); + + b.HasKey("Id"); + + b.ToTable("IdentityServerApiResources"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResourceClaim", b => + { + b.Property("ApiResourceId"); + + b.Property("Type") + .HasMaxLength(196); + + b.HasKey("ApiResourceId", "Type"); + + b.ToTable("IdentityServerApiClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScope", b => + { + b.Property("ApiResourceId"); + + b.Property("Name") + .HasMaxLength(196); + + b.Property("Description") + .HasMaxLength(256); + + b.Property("DisplayName") + .HasMaxLength(128); + + b.Property("Emphasize"); + + b.Property("Required"); + + b.Property("ShowInDiscoveryDocument"); + + b.HasKey("ApiResourceId", "Name"); + + b.ToTable("IdentityServerApiScopes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScopeClaim", b => + { + b.Property("ApiResourceId"); + + b.Property("Name") + .HasMaxLength(196); + + b.Property("Type") + .HasMaxLength(196); + + b.HasKey("ApiResourceId", "Name", "Type"); + + b.ToTable("IdentityServerApiScopeClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiSecret", b => + { + b.Property("ApiResourceId"); + + b.Property("Type") + .HasMaxLength(32); + + b.Property("Value") + .HasMaxLength(196); + + b.Property("Description") + .HasMaxLength(256); + + b.Property("Expiration"); + + b.HasKey("ApiResourceId", "Type", "Value"); + + b.ToTable("IdentityServerApiSecrets"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AbsoluteRefreshTokenLifetime"); + + b.Property("AccessTokenLifetime"); + + b.Property("AccessTokenType"); + + b.Property("AllowAccessTokensViaBrowser"); + + b.Property("AllowOfflineAccess"); + + b.Property("AllowPlainTextPkce"); + + b.Property("AllowRememberConsent"); + + b.Property("AlwaysIncludeUserClaimsInIdToken"); + + b.Property("AlwaysSendClientClaims"); + + b.Property("AuthorizationCodeLifetime"); + + b.Property("BackChannelLogoutSessionRequired"); + + b.Property("BackChannelLogoutUri") + .HasMaxLength(2000); + + b.Property("ClientClaimsPrefix") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200); + + b.Property("ClientName") + .HasMaxLength(200); + + b.Property("ClientUri") + .HasMaxLength(2000); + + b.Property("ConcurrencyStamp"); + + b.Property("ConsentLifetime"); + + b.Property("Description") + .HasMaxLength(1000); + + b.Property("EnableLocalLogin"); + + b.Property("Enabled"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("FrontChannelLogoutSessionRequired"); + + b.Property("FrontChannelLogoutUri") + .HasMaxLength(2000); + + b.Property("IdentityTokenLifetime"); + + b.Property("IncludeJwtId"); + + b.Property("LogoUri") + .HasMaxLength(2000); + + b.Property("PairWiseSubjectSalt") + .HasMaxLength(200); + + b.Property("ProtocolType") + .IsRequired() + .HasMaxLength(200); + + b.Property("RefreshTokenExpiration"); + + b.Property("RefreshTokenUsage"); + + b.Property("RequireClientSecret"); + + b.Property("RequireConsent"); + + b.Property("RequirePkce"); + + b.Property("SlidingRefreshTokenLifetime"); + + b.Property("UpdateAccessTokenClaimsOnRefresh"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique(); + + b.ToTable("IdentityServerClients"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientClaim", b => + { + b.Property("ClientId"); + + b.Property("Type") + .HasMaxLength(250); + + b.Property("Value") + .HasMaxLength(250); + + b.HasKey("ClientId", "Type", "Value"); + + b.ToTable("IdentityServerClientClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientCorsOrigin", b => + { + b.Property("ClientId"); + + b.Property("Origin") + .HasMaxLength(150); + + b.HasKey("ClientId", "Origin"); + + b.ToTable("IdentityServerClientCorsOrigins"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientGrantType", b => + { + b.Property("ClientId"); + + b.Property("GrantType") + .HasMaxLength(196); + + b.HasKey("ClientId", "GrantType"); + + b.ToTable("IdentityServerClientGrantTypes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientIdPRestriction", b => + { + b.Property("ClientId"); + + b.Property("Provider") + .HasMaxLength(64); + + b.HasKey("ClientId", "Provider"); + + b.ToTable("IdentityServerClientIdPRestrictions"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientPostLogoutRedirectUri", b => + { + b.Property("ClientId"); + + b.Property("PostLogoutRedirectUri") + .HasMaxLength(2000); + + b.HasKey("ClientId", "PostLogoutRedirectUri"); + + b.ToTable("IdentityServerClientPostLogoutRedirectUris"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientProperty", b => + { + b.Property("ClientId"); + + b.Property("Key") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000); + + b.HasKey("ClientId", "Key"); + + b.ToTable("IdentityServerClientProperties"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientRedirectUri", b => + { + b.Property("ClientId"); + + b.Property("RedirectUri") + .HasMaxLength(2000); + + b.HasKey("ClientId", "RedirectUri"); + + b.ToTable("IdentityServerClientRedirectUris"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientScope", b => + { + b.Property("ClientId"); + + b.Property("Scope") + .HasMaxLength(196); + + b.HasKey("ClientId", "Scope"); + + b.ToTable("IdentityServerClientScopes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientSecret", b => + { + b.Property("ClientId"); + + b.Property("Type") + .HasMaxLength(32); + + b.Property("Value") + .HasMaxLength(196); + + b.Property("Description") + .HasMaxLength(256); + + b.Property("Expiration"); + + b.HasKey("ClientId", "Type", "Value"); + + b.ToTable("IdentityServerClientSecrets"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Grants.PersistedGrant", b => + { + b.Property("Key") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200); + + b.Property("ConcurrencyStamp"); + + b.Property("CreationTime"); + + b.Property("Data") + .IsRequired(); + + b.Property("Expiration"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("Id"); + + b.Property("SubjectId") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.ToTable("IdentityServerPersistedGrants"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityClaim", b => + { + b.Property("IdentityResourceId"); + + b.Property("Type") + .HasMaxLength(196); + + b.HasKey("IdentityResourceId", "Type"); + + b.ToTable("IdentityServerIdentityClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp"); + + b.Property("Description") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasMaxLength(200); + + b.Property("Emphasize"); + + b.Property("Enabled"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200); + + b.Property("Required"); + + b.Property("ShowInDiscoveryDocument"); + + b.HasKey("Id"); + + b.ToTable("IdentityServerIdentityResources"); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpPermissionGrants"); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasMaxLength(64); + + b.Property("ProviderName") + .HasMaxLength(64); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpSettings"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog") + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog") + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange") + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole") + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResourceClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource") + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScope", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource") + .WithMany("Scopes") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScopeClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiScope") + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId", "Name") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiSecret", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource") + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("Claims") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientCorsOrigin", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("AllowedCorsOrigins") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientGrantType", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("AllowedGrantTypes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientIdPRestriction", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("IdentityProviderRestrictions") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientPostLogoutRedirectUri", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("PostLogoutRedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientProperty", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientRedirectUri", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("RedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientScope", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("AllowedScopes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientSecret", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("ClientSecrets") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.IdentityResources.IdentityResource") + .WithMany("UserClaims") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/Migrations/20190117081756_Initial.cs b/samples/MicroserviceDemo/applications/AuthServer.Host/Migrations/20190117081756_Initial.cs new file mode 100644 index 0000000000..6d08db79b9 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/Migrations/20190117081756_Initial.cs @@ -0,0 +1,895 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace AuthServer.Host.Migrations +{ + public partial class Initial : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AbpAuditLogs", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + UserId = table.Column(nullable: true), + UserName = table.Column(maxLength: 256, nullable: true), + TenantId = table.Column(nullable: true), + ImpersonatorUserId = table.Column(nullable: true), + ImpersonatorTenantId = table.Column(nullable: true), + ExecutionTime = table.Column(nullable: false), + ExecutionDuration = table.Column(nullable: false), + ClientIpAddress = table.Column(maxLength: 64, nullable: true), + ClientName = table.Column(maxLength: 128, nullable: true), + BrowserInfo = table.Column(maxLength: 512, nullable: true), + HttpMethod = table.Column(maxLength: 16, nullable: true), + Url = table.Column(maxLength: 256, nullable: true), + Exceptions = table.Column(maxLength: 4000, nullable: true), + Comments = table.Column(maxLength: 256, nullable: true), + HttpStatusCode = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpClaimTypes", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 256, nullable: false), + Name = table.Column(maxLength: 256, nullable: false), + Required = table.Column(nullable: false), + IsStatic = table.Column(nullable: false), + Regex = table.Column(maxLength: 512, nullable: true), + RegexDescription = table.Column(maxLength: 128, nullable: true), + Description = table.Column(maxLength: 256, nullable: true), + ValueType = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpClaimTypes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissionGrants", + columns: table => new + { + Id = table.Column(nullable: false), + TenantId = table.Column(nullable: true), + Name = table.Column(maxLength: 128, nullable: false), + ProviderName = table.Column(maxLength: 64, nullable: false), + ProviderKey = table.Column(maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpRoles", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 256, nullable: false), + TenantId = table.Column(nullable: true), + Name = table.Column(maxLength: 256, nullable: false), + NormalizedName = table.Column(maxLength: 256, nullable: false), + IsDefault = table.Column(nullable: false), + IsStatic = table.Column(nullable: false), + IsPublic = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpSettings", + columns: table => new + { + Id = table.Column(nullable: false), + Name = table.Column(maxLength: 128, nullable: false), + Value = table.Column(maxLength: 2048, nullable: false), + ProviderName = table.Column(maxLength: 64, nullable: true), + ProviderKey = table.Column(maxLength: 64, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpSettings", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpUsers", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + LastModificationTime = table.Column(nullable: true), + LastModifierId = table.Column(nullable: true), + IsDeleted = table.Column(nullable: false, defaultValue: false), + DeleterId = table.Column(nullable: true), + DeletionTime = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + UserName = table.Column(maxLength: 256, nullable: false), + NormalizedUserName = table.Column(maxLength: 256, nullable: false), + Name = table.Column(maxLength: 64, nullable: true), + Surname = table.Column(maxLength: 64, nullable: true), + Email = table.Column(maxLength: 256, nullable: true), + NormalizedEmail = table.Column(maxLength: 256, nullable: true), + EmailConfirmed = table.Column(nullable: false, defaultValue: false), + PasswordHash = table.Column(maxLength: 256, nullable: true), + SecurityStamp = table.Column(maxLength: 256, nullable: false), + PhoneNumber = table.Column(maxLength: 16, nullable: true), + PhoneNumberConfirmed = table.Column(nullable: false, defaultValue: false), + TwoFactorEnabled = table.Column(nullable: false, defaultValue: false), + LockoutEnd = table.Column(nullable: true), + LockoutEnabled = table.Column(nullable: false, defaultValue: false), + AccessFailedCount = table.Column(nullable: false, defaultValue: 0) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerApiResources", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + Name = table.Column(maxLength: 200, nullable: false), + DisplayName = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 1000, nullable: true), + Enabled = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerApiResources", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClients", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + ClientId = table.Column(maxLength: 200, nullable: false), + ClientName = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 1000, nullable: true), + ClientUri = table.Column(maxLength: 2000, nullable: true), + LogoUri = table.Column(maxLength: 2000, nullable: true), + Enabled = table.Column(nullable: false), + ProtocolType = table.Column(maxLength: 200, nullable: false), + RequireClientSecret = table.Column(nullable: false), + RequireConsent = table.Column(nullable: false), + AllowRememberConsent = table.Column(nullable: false), + AlwaysIncludeUserClaimsInIdToken = table.Column(nullable: false), + RequirePkce = table.Column(nullable: false), + AllowPlainTextPkce = table.Column(nullable: false), + AllowAccessTokensViaBrowser = table.Column(nullable: false), + FrontChannelLogoutUri = table.Column(maxLength: 2000, nullable: true), + FrontChannelLogoutSessionRequired = table.Column(nullable: false), + BackChannelLogoutUri = table.Column(maxLength: 2000, nullable: true), + BackChannelLogoutSessionRequired = table.Column(nullable: false), + AllowOfflineAccess = table.Column(nullable: false), + IdentityTokenLifetime = table.Column(nullable: false), + AccessTokenLifetime = table.Column(nullable: false), + AuthorizationCodeLifetime = table.Column(nullable: false), + ConsentLifetime = table.Column(nullable: true), + AbsoluteRefreshTokenLifetime = table.Column(nullable: false), + SlidingRefreshTokenLifetime = table.Column(nullable: false), + RefreshTokenUsage = table.Column(nullable: false), + UpdateAccessTokenClaimsOnRefresh = table.Column(nullable: false), + RefreshTokenExpiration = table.Column(nullable: false), + AccessTokenType = table.Column(nullable: false), + EnableLocalLogin = table.Column(nullable: false), + IncludeJwtId = table.Column(nullable: false), + AlwaysSendClientClaims = table.Column(nullable: false), + ClientClaimsPrefix = table.Column(maxLength: 200, nullable: true), + PairWiseSubjectSalt = table.Column(maxLength: 200, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClients", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerIdentityResources", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + Name = table.Column(maxLength: 200, nullable: false), + DisplayName = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 1000, nullable: true), + Enabled = table.Column(nullable: false), + Required = table.Column(nullable: false), + Emphasize = table.Column(nullable: false), + ShowInDiscoveryDocument = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerIdentityResources", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerPersistedGrants", + columns: table => new + { + Key = table.Column(maxLength: 200, nullable: false), + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + Type = table.Column(maxLength: 50, nullable: false), + SubjectId = table.Column(maxLength: 200, nullable: true), + ClientId = table.Column(maxLength: 200, nullable: false), + CreationTime = table.Column(nullable: false), + Expiration = table.Column(nullable: true), + Data = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerPersistedGrants", x => x.Key); + }); + + migrationBuilder.CreateTable( + name: "AbpAuditLogActions", + columns: table => new + { + Id = table.Column(nullable: false), + TenantId = table.Column(nullable: true), + AuditLogId = table.Column(nullable: false), + ServiceName = table.Column(maxLength: 256, nullable: true), + MethodName = table.Column(maxLength: 128, nullable: true), + Parameters = table.Column(maxLength: 2000, nullable: true), + ExecutionTime = table.Column(nullable: false), + ExecutionDuration = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpAuditLogActions", x => x.Id); + table.ForeignKey( + name: "FK_AbpAuditLogActions_AbpAuditLogs_AuditLogId", + column: x => x.AuditLogId, + principalTable: "AbpAuditLogs", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpEntityChanges", + columns: table => new + { + Id = table.Column(nullable: false), + AuditLogId = table.Column(nullable: false), + TenantId = table.Column(nullable: true), + ChangeTime = table.Column(nullable: false), + ChangeType = table.Column(nullable: false), + EntityId = table.Column(maxLength: 128, nullable: false), + EntityTypeFullName = table.Column(maxLength: 128, nullable: false), + ExtraProperties = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpEntityChanges", x => x.Id); + table.ForeignKey( + name: "FK_AbpEntityChanges_AbpAuditLogs_AuditLogId", + column: x => x.AuditLogId, + principalTable: "AbpAuditLogs", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpRoleClaims", + columns: table => new + { + Id = table.Column(nullable: false), + TenantId = table.Column(nullable: true), + ClaimType = table.Column(maxLength: 256, nullable: false), + ClaimValue = table.Column(maxLength: 1024, nullable: true), + RoleId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AbpRoleClaims_AbpRoles_RoleId", + column: x => x.RoleId, + principalTable: "AbpRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserClaims", + columns: table => new + { + Id = table.Column(nullable: false), + TenantId = table.Column(nullable: true), + ClaimType = table.Column(maxLength: 256, nullable: false), + ClaimValue = table.Column(maxLength: 1024, nullable: true), + UserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AbpUserClaims_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserLogins", + columns: table => new + { + UserId = table.Column(nullable: false), + LoginProvider = table.Column(maxLength: 64, nullable: false), + TenantId = table.Column(nullable: true), + ProviderKey = table.Column(maxLength: 196, nullable: false), + ProviderDisplayName = table.Column(maxLength: 128, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserLogins", x => new { x.UserId, x.LoginProvider }); + table.ForeignKey( + name: "FK_AbpUserLogins_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserRoles", + columns: table => new + { + UserId = table.Column(nullable: false), + RoleId = table.Column(nullable: false), + TenantId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AbpUserRoles_AbpRoles_RoleId", + column: x => x.RoleId, + principalTable: "AbpRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AbpUserRoles_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserTokens", + columns: table => new + { + UserId = table.Column(nullable: false), + LoginProvider = table.Column(maxLength: 64, nullable: false), + Name = table.Column(maxLength: 128, nullable: false), + TenantId = table.Column(nullable: true), + Value = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AbpUserTokens_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerApiClaims", + columns: table => new + { + Type = table.Column(maxLength: 196, nullable: false), + ApiResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerApiClaims", x => new { x.ApiResourceId, x.Type }); + table.ForeignKey( + name: "FK_IdentityServerApiClaims_IdentityServerApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "IdentityServerApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerApiScopes", + columns: table => new + { + ApiResourceId = table.Column(nullable: false), + Name = table.Column(maxLength: 196, nullable: false), + DisplayName = table.Column(maxLength: 128, nullable: true), + Description = table.Column(maxLength: 256, nullable: true), + Required = table.Column(nullable: false), + Emphasize = table.Column(nullable: false), + ShowInDiscoveryDocument = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerApiScopes", x => new { x.ApiResourceId, x.Name }); + table.ForeignKey( + name: "FK_IdentityServerApiScopes_IdentityServerApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "IdentityServerApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerApiSecrets", + columns: table => new + { + Type = table.Column(maxLength: 32, nullable: false), + Value = table.Column(maxLength: 196, nullable: false), + ApiResourceId = table.Column(nullable: false), + Description = table.Column(maxLength: 256, nullable: true), + Expiration = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerApiSecrets", x => new { x.ApiResourceId, x.Type, x.Value }); + table.ForeignKey( + name: "FK_IdentityServerApiSecrets_IdentityServerApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "IdentityServerApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientClaims", + columns: table => new + { + ClientId = table.Column(nullable: false), + Type = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 250, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientClaims", x => new { x.ClientId, x.Type, x.Value }); + table.ForeignKey( + name: "FK_IdentityServerClientClaims_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientCorsOrigins", + columns: table => new + { + ClientId = table.Column(nullable: false), + Origin = table.Column(maxLength: 150, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientCorsOrigins", x => new { x.ClientId, x.Origin }); + table.ForeignKey( + name: "FK_IdentityServerClientCorsOrigins_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientGrantTypes", + columns: table => new + { + ClientId = table.Column(nullable: false), + GrantType = table.Column(maxLength: 196, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientGrantTypes", x => new { x.ClientId, x.GrantType }); + table.ForeignKey( + name: "FK_IdentityServerClientGrantTypes_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientIdPRestrictions", + columns: table => new + { + ClientId = table.Column(nullable: false), + Provider = table.Column(maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientIdPRestrictions", x => new { x.ClientId, x.Provider }); + table.ForeignKey( + name: "FK_IdentityServerClientIdPRestrictions_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientPostLogoutRedirectUris", + columns: table => new + { + ClientId = table.Column(nullable: false), + PostLogoutRedirectUri = table.Column(maxLength: 2000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientPostLogoutRedirectUris", x => new { x.ClientId, x.PostLogoutRedirectUri }); + table.ForeignKey( + name: "FK_IdentityServerClientPostLogoutRedirectUris_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientProperties", + columns: table => new + { + ClientId = table.Column(nullable: false), + Key = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 2000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientProperties", x => new { x.ClientId, x.Key }); + table.ForeignKey( + name: "FK_IdentityServerClientProperties_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientRedirectUris", + columns: table => new + { + ClientId = table.Column(nullable: false), + RedirectUri = table.Column(maxLength: 2000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientRedirectUris", x => new { x.ClientId, x.RedirectUri }); + table.ForeignKey( + name: "FK_IdentityServerClientRedirectUris_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientScopes", + columns: table => new + { + ClientId = table.Column(nullable: false), + Scope = table.Column(maxLength: 196, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientScopes", x => new { x.ClientId, x.Scope }); + table.ForeignKey( + name: "FK_IdentityServerClientScopes_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientSecrets", + columns: table => new + { + Type = table.Column(maxLength: 32, nullable: false), + Value = table.Column(maxLength: 196, nullable: false), + ClientId = table.Column(nullable: false), + Description = table.Column(maxLength: 256, nullable: true), + Expiration = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientSecrets", x => new { x.ClientId, x.Type, x.Value }); + table.ForeignKey( + name: "FK_IdentityServerClientSecrets_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerIdentityClaims", + columns: table => new + { + Type = table.Column(maxLength: 196, nullable: false), + IdentityResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerIdentityClaims", x => new { x.IdentityResourceId, x.Type }); + table.ForeignKey( + name: "FK_IdentityServerIdentityClaims_IdentityServerIdentityResources_IdentityResourceId", + column: x => x.IdentityResourceId, + principalTable: "IdentityServerIdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpEntityPropertyChanges", + columns: table => new + { + Id = table.Column(nullable: false), + TenantId = table.Column(nullable: true), + EntityChangeId = table.Column(nullable: false), + NewValue = table.Column(maxLength: 512, nullable: true), + OriginalValue = table.Column(maxLength: 512, nullable: true), + PropertyName = table.Column(maxLength: 128, nullable: false), + PropertyTypeFullName = table.Column(maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpEntityPropertyChanges", x => x.Id); + table.ForeignKey( + name: "FK_AbpEntityPropertyChanges_AbpEntityChanges_EntityChangeId", + column: x => x.EntityChangeId, + principalTable: "AbpEntityChanges", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerApiScopeClaims", + columns: table => new + { + Type = table.Column(maxLength: 196, nullable: false), + ApiResourceId = table.Column(nullable: false), + Name = table.Column(maxLength: 196, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerApiScopeClaims", x => new { x.ApiResourceId, x.Name, x.Type }); + table.ForeignKey( + name: "FK_IdentityServerApiScopeClaims_IdentityServerApiScopes_ApiResourceId_Name", + columns: x => new { x.ApiResourceId, x.Name }, + principalTable: "IdentityServerApiScopes", + principalColumns: new[] { "ApiResourceId", "Name" }, + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogActions_AuditLogId", + table: "AbpAuditLogActions", + column: "AuditLogId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogActions_TenantId_ServiceName_MethodName_ExecutionTime", + table: "AbpAuditLogActions", + columns: new[] { "TenantId", "ServiceName", "MethodName", "ExecutionTime" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogs_TenantId_ExecutionTime", + table: "AbpAuditLogs", + columns: new[] { "TenantId", "ExecutionTime" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogs_TenantId_UserId_ExecutionTime", + table: "AbpAuditLogs", + columns: new[] { "TenantId", "UserId", "ExecutionTime" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpEntityChanges_AuditLogId", + table: "AbpEntityChanges", + column: "AuditLogId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpEntityChanges_TenantId_EntityTypeFullName_EntityId", + table: "AbpEntityChanges", + columns: new[] { "TenantId", "EntityTypeFullName", "EntityId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpEntityPropertyChanges_EntityChangeId", + table: "AbpEntityPropertyChanges", + column: "EntityChangeId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGrants_Name_ProviderName_ProviderKey", + table: "AbpPermissionGrants", + columns: new[] { "Name", "ProviderName", "ProviderKey" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpRoleClaims_RoleId", + table: "AbpRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpRoles_NormalizedName", + table: "AbpRoles", + column: "NormalizedName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpSettings_Name_ProviderName_ProviderKey", + table: "AbpSettings", + columns: new[] { "Name", "ProviderName", "ProviderKey" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserClaims_UserId", + table: "AbpUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserLogins_LoginProvider_ProviderKey", + table: "AbpUserLogins", + columns: new[] { "LoginProvider", "ProviderKey" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserRoles_RoleId_UserId", + table: "AbpUserRoles", + columns: new[] { "RoleId", "UserId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_Email", + table: "AbpUsers", + column: "Email"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_NormalizedEmail", + table: "AbpUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_NormalizedUserName", + table: "AbpUsers", + column: "NormalizedUserName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_UserName", + table: "AbpUsers", + column: "UserName"); + + migrationBuilder.CreateIndex( + name: "IX_IdentityServerClients_ClientId", + table: "IdentityServerClients", + column: "ClientId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_IdentityServerPersistedGrants_SubjectId_ClientId_Type", + table: "IdentityServerPersistedGrants", + columns: new[] { "SubjectId", "ClientId", "Type" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AbpAuditLogActions"); + + migrationBuilder.DropTable( + name: "AbpClaimTypes"); + + migrationBuilder.DropTable( + name: "AbpEntityPropertyChanges"); + + migrationBuilder.DropTable( + name: "AbpPermissionGrants"); + + migrationBuilder.DropTable( + name: "AbpRoleClaims"); + + migrationBuilder.DropTable( + name: "AbpSettings"); + + migrationBuilder.DropTable( + name: "AbpUserClaims"); + + migrationBuilder.DropTable( + name: "AbpUserLogins"); + + migrationBuilder.DropTable( + name: "AbpUserRoles"); + + migrationBuilder.DropTable( + name: "AbpUserTokens"); + + migrationBuilder.DropTable( + name: "IdentityServerApiClaims"); + + migrationBuilder.DropTable( + name: "IdentityServerApiScopeClaims"); + + migrationBuilder.DropTable( + name: "IdentityServerApiSecrets"); + + migrationBuilder.DropTable( + name: "IdentityServerClientClaims"); + + migrationBuilder.DropTable( + name: "IdentityServerClientCorsOrigins"); + + migrationBuilder.DropTable( + name: "IdentityServerClientGrantTypes"); + + migrationBuilder.DropTable( + name: "IdentityServerClientIdPRestrictions"); + + migrationBuilder.DropTable( + name: "IdentityServerClientPostLogoutRedirectUris"); + + migrationBuilder.DropTable( + name: "IdentityServerClientProperties"); + + migrationBuilder.DropTable( + name: "IdentityServerClientRedirectUris"); + + migrationBuilder.DropTable( + name: "IdentityServerClientScopes"); + + migrationBuilder.DropTable( + name: "IdentityServerClientSecrets"); + + migrationBuilder.DropTable( + name: "IdentityServerIdentityClaims"); + + migrationBuilder.DropTable( + name: "IdentityServerPersistedGrants"); + + migrationBuilder.DropTable( + name: "AbpEntityChanges"); + + migrationBuilder.DropTable( + name: "AbpRoles"); + + migrationBuilder.DropTable( + name: "AbpUsers"); + + migrationBuilder.DropTable( + name: "IdentityServerApiScopes"); + + migrationBuilder.DropTable( + name: "IdentityServerClients"); + + migrationBuilder.DropTable( + name: "IdentityServerIdentityResources"); + + migrationBuilder.DropTable( + name: "AbpAuditLogs"); + + migrationBuilder.DropTable( + name: "IdentityServerApiResources"); + } + } +} diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/Migrations/AuthServerDbContextModelSnapshot.cs b/samples/MicroserviceDemo/applications/AuthServer.Host/Migrations/AuthServerDbContextModelSnapshot.cs new file mode 100644 index 0000000000..d889730472 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/Migrations/AuthServerDbContextModelSnapshot.cs @@ -0,0 +1,1140 @@ +// +using System; +using AuthServer.Host.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace AuthServer.Host.Migrations +{ + [DbContext(typeof(AuthServerDbContext))] + partial class AuthServerDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.0-rtm-35687") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BrowserInfo") + .HasColumnName("BrowserInfo") + .HasMaxLength(512); + + b.Property("ClientIpAddress") + .HasColumnName("ClientIpAddress") + .HasMaxLength(64); + + b.Property("ClientName") + .HasColumnName("ClientName") + .HasMaxLength(128); + + b.Property("Comments") + .HasColumnName("Comments") + .HasMaxLength(256); + + b.Property("ConcurrencyStamp"); + + b.Property("Exceptions") + .HasColumnName("Exceptions") + .HasMaxLength(4000); + + b.Property("ExecutionDuration") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasColumnName("HttpMethod") + .HasMaxLength(16); + + b.Property("HttpStatusCode") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorUserId") + .HasColumnName("ImpersonatorUserId"); + + b.Property("TenantId") + .HasColumnName("TenantId"); + + b.Property("Url") + .HasColumnName("Url") + .HasMaxLength(256); + + b.Property("UserId") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasColumnName("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AbpAuditLogs"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuditLogId") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasColumnName("MethodName") + .HasMaxLength(128); + + b.Property("Parameters") + .HasColumnName("Parameters") + .HasMaxLength(2000); + + b.Property("ServiceName") + .HasColumnName("ServiceName") + .HasMaxLength(256); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AbpAuditLogActions"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuditLogId") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .IsRequired() + .HasColumnName("EntityId") + .HasMaxLength(128); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasColumnName("EntityTypeFullName") + .HasMaxLength(128); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("AbpEntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EntityChangeId"); + + b.Property("NewValue") + .HasColumnName("NewValue") + .HasMaxLength(512); + + b.Property("OriginalValue") + .HasColumnName("OriginalValue") + .HasMaxLength(512); + + b.Property("PropertyName") + .IsRequired() + .HasColumnName("PropertyName") + .HasMaxLength(128); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasColumnName("PropertyTypeFullName") + .HasMaxLength(64); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("AbpEntityPropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("Description") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256); + + b.Property("Regex") + .HasMaxLength(512); + + b.Property("RegexDescription") + .HasMaxLength(128); + + b.Property("Required"); + + b.Property("ValueType"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasMaxLength(1024); + + b.Property("RoleId"); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnName("AccessFailedCount") + .HasDefaultValue(0); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .HasColumnName("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("EmailConfirmed") + .HasDefaultValue(false); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("LockoutEnabled") + .HasDefaultValue(false); + + b.Property("LockoutEnd"); + + b.Property("Name") + .HasColumnName("Name") + .HasMaxLength(64); + + b.Property("NormalizedEmail") + .HasColumnName("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .IsRequired() + .HasColumnName("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnName("PasswordHash") + .HasMaxLength(256); + + b.Property("PhoneNumber") + .HasColumnName("PhoneNumber") + .HasMaxLength(16); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("PhoneNumberConfirmed") + .HasDefaultValue(false); + + b.Property("SecurityStamp") + .IsRequired() + .HasColumnName("SecurityStamp") + .HasMaxLength(256); + + b.Property("Surname") + .HasColumnName("Surname") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("TwoFactorEnabled") + .HasDefaultValue(false); + + b.Property("UserName") + .IsRequired() + .HasColumnName("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasMaxLength(1024); + + b.Property("TenantId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(64); + + b.Property("ProviderDisplayName") + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196); + + b.Property("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.Property("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(64); + + b.Property("Name") + .HasMaxLength(128); + + b.Property("TenantId"); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp"); + + b.Property("Description") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasMaxLength(200); + + b.Property("Enabled"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200); + + b.HasKey("Id"); + + b.ToTable("IdentityServerApiResources"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResourceClaim", b => + { + b.Property("ApiResourceId"); + + b.Property("Type") + .HasMaxLength(196); + + b.HasKey("ApiResourceId", "Type"); + + b.ToTable("IdentityServerApiClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScope", b => + { + b.Property("ApiResourceId"); + + b.Property("Name") + .HasMaxLength(196); + + b.Property("Description") + .HasMaxLength(256); + + b.Property("DisplayName") + .HasMaxLength(128); + + b.Property("Emphasize"); + + b.Property("Required"); + + b.Property("ShowInDiscoveryDocument"); + + b.HasKey("ApiResourceId", "Name"); + + b.ToTable("IdentityServerApiScopes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScopeClaim", b => + { + b.Property("ApiResourceId"); + + b.Property("Name") + .HasMaxLength(196); + + b.Property("Type") + .HasMaxLength(196); + + b.HasKey("ApiResourceId", "Name", "Type"); + + b.ToTable("IdentityServerApiScopeClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiSecret", b => + { + b.Property("ApiResourceId"); + + b.Property("Type") + .HasMaxLength(32); + + b.Property("Value") + .HasMaxLength(196); + + b.Property("Description") + .HasMaxLength(256); + + b.Property("Expiration"); + + b.HasKey("ApiResourceId", "Type", "Value"); + + b.ToTable("IdentityServerApiSecrets"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AbsoluteRefreshTokenLifetime"); + + b.Property("AccessTokenLifetime"); + + b.Property("AccessTokenType"); + + b.Property("AllowAccessTokensViaBrowser"); + + b.Property("AllowOfflineAccess"); + + b.Property("AllowPlainTextPkce"); + + b.Property("AllowRememberConsent"); + + b.Property("AlwaysIncludeUserClaimsInIdToken"); + + b.Property("AlwaysSendClientClaims"); + + b.Property("AuthorizationCodeLifetime"); + + b.Property("BackChannelLogoutSessionRequired"); + + b.Property("BackChannelLogoutUri") + .HasMaxLength(2000); + + b.Property("ClientClaimsPrefix") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200); + + b.Property("ClientName") + .HasMaxLength(200); + + b.Property("ClientUri") + .HasMaxLength(2000); + + b.Property("ConcurrencyStamp"); + + b.Property("ConsentLifetime"); + + b.Property("Description") + .HasMaxLength(1000); + + b.Property("EnableLocalLogin"); + + b.Property("Enabled"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("FrontChannelLogoutSessionRequired"); + + b.Property("FrontChannelLogoutUri") + .HasMaxLength(2000); + + b.Property("IdentityTokenLifetime"); + + b.Property("IncludeJwtId"); + + b.Property("LogoUri") + .HasMaxLength(2000); + + b.Property("PairWiseSubjectSalt") + .HasMaxLength(200); + + b.Property("ProtocolType") + .IsRequired() + .HasMaxLength(200); + + b.Property("RefreshTokenExpiration"); + + b.Property("RefreshTokenUsage"); + + b.Property("RequireClientSecret"); + + b.Property("RequireConsent"); + + b.Property("RequirePkce"); + + b.Property("SlidingRefreshTokenLifetime"); + + b.Property("UpdateAccessTokenClaimsOnRefresh"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique(); + + b.ToTable("IdentityServerClients"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientClaim", b => + { + b.Property("ClientId"); + + b.Property("Type") + .HasMaxLength(250); + + b.Property("Value") + .HasMaxLength(250); + + b.HasKey("ClientId", "Type", "Value"); + + b.ToTable("IdentityServerClientClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientCorsOrigin", b => + { + b.Property("ClientId"); + + b.Property("Origin") + .HasMaxLength(150); + + b.HasKey("ClientId", "Origin"); + + b.ToTable("IdentityServerClientCorsOrigins"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientGrantType", b => + { + b.Property("ClientId"); + + b.Property("GrantType") + .HasMaxLength(196); + + b.HasKey("ClientId", "GrantType"); + + b.ToTable("IdentityServerClientGrantTypes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientIdPRestriction", b => + { + b.Property("ClientId"); + + b.Property("Provider") + .HasMaxLength(64); + + b.HasKey("ClientId", "Provider"); + + b.ToTable("IdentityServerClientIdPRestrictions"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientPostLogoutRedirectUri", b => + { + b.Property("ClientId"); + + b.Property("PostLogoutRedirectUri") + .HasMaxLength(2000); + + b.HasKey("ClientId", "PostLogoutRedirectUri"); + + b.ToTable("IdentityServerClientPostLogoutRedirectUris"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientProperty", b => + { + b.Property("ClientId"); + + b.Property("Key") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000); + + b.HasKey("ClientId", "Key"); + + b.ToTable("IdentityServerClientProperties"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientRedirectUri", b => + { + b.Property("ClientId"); + + b.Property("RedirectUri") + .HasMaxLength(2000); + + b.HasKey("ClientId", "RedirectUri"); + + b.ToTable("IdentityServerClientRedirectUris"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientScope", b => + { + b.Property("ClientId"); + + b.Property("Scope") + .HasMaxLength(196); + + b.HasKey("ClientId", "Scope"); + + b.ToTable("IdentityServerClientScopes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientSecret", b => + { + b.Property("ClientId"); + + b.Property("Type") + .HasMaxLength(32); + + b.Property("Value") + .HasMaxLength(196); + + b.Property("Description") + .HasMaxLength(256); + + b.Property("Expiration"); + + b.HasKey("ClientId", "Type", "Value"); + + b.ToTable("IdentityServerClientSecrets"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Grants.PersistedGrant", b => + { + b.Property("Key") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200); + + b.Property("ConcurrencyStamp"); + + b.Property("CreationTime"); + + b.Property("Data") + .IsRequired(); + + b.Property("Expiration"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("Id"); + + b.Property("SubjectId") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.ToTable("IdentityServerPersistedGrants"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityClaim", b => + { + b.Property("IdentityResourceId"); + + b.Property("Type") + .HasMaxLength(196); + + b.HasKey("IdentityResourceId", "Type"); + + b.ToTable("IdentityServerIdentityClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp"); + + b.Property("Description") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasMaxLength(200); + + b.Property("Emphasize"); + + b.Property("Enabled"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200); + + b.Property("Required"); + + b.Property("ShowInDiscoveryDocument"); + + b.HasKey("Id"); + + b.ToTable("IdentityServerIdentityResources"); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64); + + b.Property("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpPermissionGrants"); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasMaxLength(64); + + b.Property("ProviderName") + .HasMaxLength(64); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpSettings"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog") + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog") + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange") + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole") + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser") + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResourceClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource") + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScope", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource") + .WithMany("Scopes") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScopeClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiScope") + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId", "Name") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiSecret", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource") + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("Claims") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientCorsOrigin", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("AllowedCorsOrigins") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientGrantType", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("AllowedGrantTypes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientIdPRestriction", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("IdentityProviderRestrictions") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientPostLogoutRedirectUri", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("PostLogoutRedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientProperty", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientRedirectUri", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("RedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientScope", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("AllowedScopes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientSecret", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client") + .WithMany("ClientSecrets") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.IdentityResources.IdentityResource") + .WithMany("UserClaims") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/Pages/Index.cshtml b/samples/MicroserviceDemo/applications/AuthServer.Host/Pages/Index.cshtml new file mode 100644 index 0000000000..53bcfed077 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/Pages/Index.cshtml @@ -0,0 +1,23 @@ +@page +@using Volo.Abp.Users +@model AuthServer.Host.Pages.IndexModel +@inject ICurrentUser CurrentUser +

    Running the AuthServer.Host application!

    +

    Current User

    +
      +
    • IsAuthenticated: @CurrentUser.IsAuthenticated
    • +
    • UserName: @CurrentUser.UserName
    • +
    • Email: @CurrentUser.Email
    • +
    • Roles: @CurrentUser.Roles.JoinAsString(", ")
    • + @*
    • Claims: @CurrentUser.GetAllClaims().Select(c => $"{c.Type}={c.Value}").JoinAsString(" | ")
    • *@ +
    • TenantId: @CurrentUser.TenantId
    • +
    + +@if (CurrentUser.IsAuthenticated) +{ + Logout +} +else +{ + Login +} \ No newline at end of file diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/Pages/Index.cshtml.cs b/samples/MicroserviceDemo/applications/AuthServer.Host/Pages/Index.cshtml.cs new file mode 100644 index 0000000000..0894e658dc --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/Pages/Index.cshtml.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace AuthServer.Host.Pages +{ + public class IndexModel : PageModel + { + public void OnGet() + { + } + } +} \ No newline at end of file diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/Pages/_ViewImports.cshtml b/samples/MicroserviceDemo/applications/AuthServer.Host/Pages/_ViewImports.cshtml new file mode 100644 index 0000000000..c1da1f5f10 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/Pages/_ViewImports.cshtml @@ -0,0 +1,4 @@ +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling \ No newline at end of file diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/Program.cs b/samples/MicroserviceDemo/applications/AuthServer.Host/Program.cs new file mode 100644 index 0000000000..84f71ab802 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/Program.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; +using Microsoft.AspNetCore.Hosting; +using Serilog; +using Serilog.Events; + +namespace AuthServer.Host +{ + public class Program + { + public static int Main(string[] args) + { + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Debug() + .MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .Enrich.FromLogContext() + .WriteTo.File("Logs/logs.txt") + .CreateLogger(); + + try + { + Log.Information("Starting AuthServer.Host."); + BuildWebHostInternal(args).Run(); + return 0; + } + catch (Exception ex) + { + Log.Fatal(ex, "AuthServer.Host terminated unexpectedly!"); + return 1; + } + finally + { + Log.CloseAndFlush(); + } + } + + public static IWebHost BuildWebHostInternal(string[] args) => + new WebHostBuilder() + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .UseSerilog() + .Build(); + } +} diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/Properties/launchSettings.json b/samples/MicroserviceDemo/applications/AuthServer.Host/Properties/launchSettings.json new file mode 100644 index 0000000000..64eeed40fe --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:64999", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "AuthServer.Host": { + "commandName": "Project", + "launchBrowser": true, + "applicationUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/Startup.cs b/samples/MicroserviceDemo/applications/AuthServer.Host/Startup.cs new file mode 100644 index 0000000000..f9d963021c --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/Startup.cs @@ -0,0 +1,27 @@ +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Volo.Abp; + +namespace AuthServer.Host +{ + public class Startup + { + public IServiceProvider ConfigureServices(IServiceCollection services) + { + services.AddApplication(options => + { + options.UseAutofac(); + }); + + return services.BuildServiceProviderFromFactory(); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + { + app.InitializeApplication(); + } + } +} diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/abp.resourcemapping.js b/samples/MicroserviceDemo/applications/AuthServer.Host/abp.resourcemapping.js new file mode 100644 index 0000000000..e2189c3c69 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/abp.resourcemapping.js @@ -0,0 +1,11 @@ +module.exports = { + aliases: { + + }, + clean: [ + + ], + mappings: { + + } +}; \ No newline at end of file diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/appsettings.Development.json b/samples/MicroserviceDemo/applications/AuthServer.Host/appsettings.Development.json new file mode 100644 index 0000000000..e203e9407e --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/appsettings.json b/samples/MicroserviceDemo/applications/AuthServer.Host/appsettings.json new file mode 100644 index 0000000000..17a9c1a1fe --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/appsettings.json @@ -0,0 +1,25 @@ +{ + "ConnectionStrings": { + "Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True;MultipleActiveResultSets=true" + }, + "Redis": { + "Configuration": "127.0.0.1" + }, + "RabbitMQ": { + "Connections": { + "Default": { + "HostName": "localhost" + } + }, + "EventBus": { + "ClientName": "MsDemo_AuthServer", + "ExchangeName": "MsDemo" + } + }, + "Logging": { + "LogLevel": { + "Default": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/gulpfile.js b/samples/MicroserviceDemo/applications/AuthServer.Host/gulpfile.js new file mode 100644 index 0000000000..754602029a --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/gulpfile.js @@ -0,0 +1,11 @@ +"use strict"; + +var gulp = require("gulp"), + path = require('path'), + copyResources = require('./node_modules/@abp/aspnetcore.mvc.ui/gulp/copy-resources.js'); + +copyResources.init(path.resolve('./')); + +gulp.task('default', [copyResources.taskName], function () { + +}); \ No newline at end of file diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/package.json b/samples/MicroserviceDemo/applications/AuthServer.Host/package.json new file mode 100644 index 0000000000..7cdd6da8bd --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/package.json @@ -0,0 +1,8 @@ +{ + "version": "0.1.0", + "name": "msdemo-authserver-host", + "private": true, + "dependencies": { + "@abp/aspnetcore.mvc.ui.theme.basic": "^0.4.9" + } +} diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/tempkey.rsa b/samples/MicroserviceDemo/applications/AuthServer.Host/tempkey.rsa new file mode 100644 index 0000000000..51877ea7f0 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/tempkey.rsa @@ -0,0 +1 @@ +{"KeyId":"4a577ea79efd27c042a6b5289cd7e24e","Parameters":{"D":"VyCuYOq48gYJi3HpqUMJbj6QCm0e5K/prRs0q6H8jQb1jl9kzDvHiHfw7XZDvC0mekK7k3ib5Tt3IHviCv7vpL0Ajdts4ex2uvjKnYX20EtaIcz6kkVFsY1NP6OyjUlY6a6idCedw6pTybq2BG0tqCcicnDurwJDhS/R9NG6UnR3xlMAY6qOSbV/1/EGNPOlP5Pn6vcpUOXBx2l/7gMB02uMAtWysSLAR5vcl+nMg0dgCnR6Ea2hf641TDZZj8F6/fWg2UejUk9JJDVdBMR9yNHFE4PXLxLTXAA41pLu6cWJW8m5maDmSHV67fCKKArlcuWhvHSvy3WkMRVltz3kMQ==","DP":"BwIvmgmdx09DmXmPszZgKLvnAzJ4jlNC+sP2WiTVhLYLPhflwBjQ1/Orw88MJqK8xVFk8zte9fEz9eaANAxgXYfkmty3hG873TsS2VRws4anFC8WVDmtFrbfgqirgP2yBEgqY857wcKvGIb7nNBNRpa3t0huM18VzJCevn3F9/U=","DQ":"X5/ZYFlEDLVBp/w88XL6QKzY8gtzSmCaKd+iTZqren7+yp4yZWDIxldeirgIX4oirvTa+YxIxa6+Q8ilUhm9FGXiaHEYdgaaCpJGfNtxydcm6jkdSYZvJkt0uSIaU0Qsfl+aqi6nUwZDdrbk3f9NSgiQ7SubNgaSm7O08+l32eM=","Exponent":"AQAB","InverseQ":"0uInjerGTchFQ1gJYfW+003Ml8zmhiTXXZLR/ONarQYEK/hiJj0/slGVQpLuIOxFvkGgqjfraThlm5Q6+768Bv5EZ5KbhrKJ184R/nlIzFh7+9IjShf5XI7PSJmLrzX4cysaiPCFM94vZGkF4b7BabsL1TEQe5dBPZJ8tOpCa5I=","Modulus":"xU7G8MJp6Nmj8fKrkUqBlf2mRqvVjkRGmWU/gNHTepB1YQe0zoDmdIx8LF0j3Xk2Tvyekry68pV/qdURFJEGb9pmEksJkMQZ927V1+FTUBeWP666Ln4bTkJwkDtSfN4fPC70hmew1zQdeZmZBrc8BbQpIS8tHQ7rOZk9E+H8tgJbCbpLjAqWrg7gzJlgosd5xamm5XOk5R5oU+3QvkKwOLIn5RgOYzjVkkPKE+tOECPIi/2hDRCFVYwSvC5knmGP6UCHbib+mSDnloB4RMX0h95p+i3QXdeiF0daelVQUhGY56ONRqAFKqDpJzzJ/q4g9ci7sHHNUW8amJWwBgt8iQ==","P":"/uTPchvRiNBlQTr7R5x3NSQMX62RTYqOWjPexaNTeB/Q2qgumKhWe/QGvsQLCTfjmFEDyFs7kcgDSDv3RSAqUm8dFqJKmvT2Hxpvb4/GCG6crH1fp1pBZ7OZ7mjd2zvPaSdOIaa4t+TYZOB7SHDP0xtR1EPVWkBhH1BPbggFXDM=","Q":"xin88RYcPBMO6aYz/7U7wvUb/byUou64yxkzY1sqPYZYOxm5v9VfqoT5LT8wcbynDe1yLmjxwshhOTrd3rj2AQL2DdaT6xuQRJ1XHjONpW0VmaHzLtOWxc+Z2P1MzpnhoewcedrCd+XTPkr4of7o1dEGcxCOnL9FQPa8l0vfCFM="}} \ No newline at end of file diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/abp/core/abp.js b/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/abp/core/abp.js new file mode 100644 index 0000000000..4c87489e22 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/abp/core/abp.js @@ -0,0 +1,546 @@ +var abp = abp || {}; +(function () { + + /* Application paths *****************************************/ + + //Current application root path (including virtual directory if exists). + abp.appPath = abp.appPath || '/'; + + abp.pageLoadTime = new Date(); + + //Converts given path to absolute path using abp.appPath variable. + abp.toAbsAppPath = function (path) { + if (path.indexOf('/') == 0) { + path = path.substring(1); + } + + return abp.appPath + path; + }; + + /* LOGGING ***************************************************/ + //Implements Logging API that provides secure & controlled usage of console.log + + abp.log = abp.log || {}; + + abp.log.levels = { + DEBUG: 1, + INFO: 2, + WARN: 3, + ERROR: 4, + FATAL: 5 + }; + + abp.log.level = abp.log.levels.DEBUG; + + abp.log.log = function (logObject, logLevel) { + if (!window.console || !window.console.log) { + return; + } + + if (logLevel != undefined && logLevel < abp.log.level) { + return; + } + + console.log(logObject); + }; + + abp.log.debug = function (logObject) { + abp.log.log("DEBUG: ", abp.log.levels.DEBUG); + abp.log.log(logObject, abp.log.levels.DEBUG); + }; + + abp.log.info = function (logObject) { + abp.log.log("INFO: ", abp.log.levels.INFO); + abp.log.log(logObject, abp.log.levels.INFO); + }; + + abp.log.warn = function (logObject) { + abp.log.log("WARN: ", abp.log.levels.WARN); + abp.log.log(logObject, abp.log.levels.WARN); + }; + + abp.log.error = function (logObject) { + abp.log.log("ERROR: ", abp.log.levels.ERROR); + abp.log.log(logObject, abp.log.levels.ERROR); + }; + + abp.log.fatal = function (logObject) { + abp.log.log("FATAL: ", abp.log.levels.FATAL); + abp.log.log(logObject, abp.log.levels.FATAL); + }; + + /* LOCALIZATION ***********************************************/ + + abp.localization = abp.localization || {}; + + abp.localization.values = {}; + + abp.localization.localize = function (key, sourceName) { + sourceName = sourceName || abp.localization.defaultResourceName; + + var source = abp.localization.values[sourceName]; + + if (!source) { + abp.log.warn('Could not find localization source: ' + sourceName); + return key; + } + + var value = source[key]; + if (value == undefined) { + return key; + } + + var copiedArguments = Array.prototype.slice.call(arguments, 0); + copiedArguments.splice(1, 1); + copiedArguments[0] = value; + + return abp.utils.formatString.apply(this, copiedArguments); + }; + + abp.localization.getResource = function (name) { + return function () { + var copiedArguments = Array.prototype.slice.call(arguments, 0); + copiedArguments.splice(1, 0, name); + return abp.localization.localize.apply(this, copiedArguments); + }; + }; + + abp.localization.defaultResourceName = undefined; + + /* AUTHORIZATION **********************************************/ + + abp.auth = abp.auth || {}; + + abp.auth.policies = abp.auth.policies || {}; + + abp.auth.grantedPolicies = abp.auth.grantedPolicies || {}; + + abp.auth.isGranted = function (policyName) { + return abp.auth.policies[policyName] != undefined && abp.auth.grantedPolicies[policyName] != undefined; + }; + + abp.auth.isAnyGranted = function () { + if (!arguments || arguments.length <= 0) { + return true; + } + + for (var i = 0; i < arguments.length; i++) { + if (abp.auth.isGranted(arguments[i])) { + return true; + } + } + + return false; + }; + + abp.auth.areAllGranted = function () { + if (!arguments || arguments.length <= 0) { + return true; + } + + for (var i = 0; i < arguments.length; i++) { + if (!abp.auth.isGranted(arguments[i])) { + return false; + } + } + + return true; + }; + + abp.auth.tokenCookieName = 'Abp.AuthToken'; + + abp.auth.setToken = function (authToken, expireDate) { + abp.utils.setCookieValue(abp.auth.tokenCookieName, authToken, expireDate, abp.appPath, abp.domain); + }; + + abp.auth.getToken = function () { + return abp.utils.getCookieValue(abp.auth.tokenCookieName); + } + + abp.auth.clearToken = function () { + abp.auth.setToken(); + } + + /* NOTIFICATION *********************************************/ + //Defines Notification API, not implements it + + abp.notify = abp.notify || {}; + + abp.notify.success = function (message, title, options) { + abp.log.warn('abp.notify.success is not implemented!'); + }; + + abp.notify.info = function (message, title, options) { + abp.log.warn('abp.notify.info is not implemented!'); + }; + + abp.notify.warn = function (message, title, options) { + abp.log.warn('abp.notify.warn is not implemented!'); + }; + + abp.notify.error = function (message, title, options) { + abp.log.warn('abp.notify.error is not implemented!'); + }; + + /* MESSAGE **************************************************/ + //Defines Message API, not implements it + + abp.message = abp.message || {}; + + abp.message._showMessage = function (message, title) { + alert((title || '') + ' ' + message); + }; + + abp.message.info = function (message, title) { + abp.log.warn('abp.message.info is not implemented!'); + return abp.message._showMessage(message, title); + }; + + abp.message.success = function (message, title) { + abp.log.warn('abp.message.success is not implemented!'); + return abp.message._showMessage(message, title); + }; + + abp.message.warn = function (message, title) { + abp.log.warn('abp.message.warn is not implemented!'); + return abp.message._showMessage(message, title); + }; + + abp.message.error = function (message, title) { + abp.log.warn('abp.message.error is not implemented!'); + return abp.message._showMessage(message, title); + }; + + abp.message.confirm = function (message, titleOrCallback, callback) { + abp.log.warn('abp.message.confirm is not properly implemented!'); + + if (titleOrCallback && !(typeof titleOrCallback == 'string')) { + callback = titleOrCallback; + } + + var result = confirm(message); + callback && callback(result); + }; + + /* UI *******************************************************/ + + abp.ui = abp.ui || {}; + + /* UI BLOCK */ + //Defines UI Block API, not implements it + + abp.ui.block = function (elm) { + abp.log.warn('abp.ui.block is not implemented!'); + }; + + abp.ui.unblock = function (elm) { + abp.log.warn('abp.ui.unblock is not implemented!'); + }; + + /* UI BUSY */ + //Defines UI Busy API, not implements it + + abp.ui.setBusy = function (elm, optionsOrPromise) { + abp.log.warn('abp.ui.setBusy is not implemented!'); + }; + + abp.ui.clearBusy = function (elm) { + abp.log.warn('abp.ui.clearBusy is not implemented!'); + }; + + /* SIMPLE EVENT BUS *****************************************/ + + abp.event = (function () { + + var _callbacks = {}; + + var on = function (eventName, callback) { + if (!_callbacks[eventName]) { + _callbacks[eventName] = []; + } + + _callbacks[eventName].push(callback); + }; + + var off = function (eventName, callback) { + var callbacks = _callbacks[eventName]; + if (!callbacks) { + return; + } + + var index = -1; + for (var i = 0; i < callbacks.length; i++) { + if (callbacks[i] === callback) { + index = i; + break; + } + } + + if (index < 0) { + return; + } + + _callbacks[eventName].splice(index, 1); + }; + + var trigger = function (eventName) { + var callbacks = _callbacks[eventName]; + if (!callbacks || !callbacks.length) { + return; + } + + var args = Array.prototype.slice.call(arguments, 1); + for (var i = 0; i < callbacks.length; i++) { + callbacks[i].apply(this, args); + } + }; + + // Public interface /////////////////////////////////////////////////// + + return { + on: on, + off: off, + trigger: trigger + }; + })(); + + + /* UTILS ***************************************************/ + + abp.utils = abp.utils || {}; + + /* Creates a name namespace. + * Example: + * var taskService = abp.utils.createNamespace(abp, 'services.task'); + * taskService will be equal to abp.services.task + * first argument (root) must be defined first + ************************************************************/ + abp.utils.createNamespace = function (root, ns) { + var parts = ns.split('.'); + for (var i = 0; i < parts.length; i++) { + if (typeof root[parts[i]] == 'undefined') { + root[parts[i]] = {}; + } + + root = root[parts[i]]; + } + + return root; + }; + + /* Find and replaces a string (search) to another string (replacement) in + * given string (str). + * Example: + * abp.utils.replaceAll('This is a test string', 'is', 'X') = 'ThX X a test string' + ************************************************************/ + abp.utils.replaceAll = function (str, search, replacement) { + var fix = search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + return str.replace(new RegExp(fix, 'g'), replacement); + }; + + /* Formats a string just like string.format in C#. + * Example: + * abp.utils.formatString('Hello {0}','Tuana') = 'Hello Tuana' + ************************************************************/ + abp.utils.formatString = function () { + if (arguments.length < 1) { + return null; + } + + var str = arguments[0]; + + for (var i = 1; i < arguments.length; i++) { + var placeHolder = '{' + (i - 1) + '}'; + str = abp.utils.replaceAll(str, placeHolder, arguments[i]); + } + + return str; + }; + + abp.utils.toPascalCase = function (str) { + if (!str || !str.length) { + return str; + } + + if (str.length === 1) { + return str.charAt(0).toUpperCase(); + } + + return str.charAt(0).toUpperCase() + str.substr(1); + } + + abp.utils.toCamelCase = function (str) { + if (!str || !str.length) { + return str; + } + + if (str.length === 1) { + return str.charAt(0).toLowerCase(); + } + + return str.charAt(0).toLowerCase() + str.substr(1); + } + + abp.utils.truncateString = function (str, maxLength) { + if (!str || !str.length || str.length <= maxLength) { + return str; + } + + return str.substr(0, maxLength); + }; + + abp.utils.truncateStringWithPostfix = function (str, maxLength, postfix) { + postfix = postfix || '...'; + + if (!str || !str.length || str.length <= maxLength) { + return str; + } + + if (maxLength <= postfix.length) { + return postfix.substr(0, maxLength); + } + + return str.substr(0, maxLength - postfix.length) + postfix; + }; + + abp.utils.isFunction = function (obj) { + return !!(obj && obj.constructor && obj.call && obj.apply); + }; + + /** + * parameterInfos should be an array of { name, value } objects + * where name is query string parameter name and value is it's value. + * includeQuestionMark is true by default. + */ + abp.utils.buildQueryString = function (parameterInfos, includeQuestionMark) { + if (includeQuestionMark === undefined) { + includeQuestionMark = true; + } + + var qs = ''; + + function addSeperator() { + if (!qs.length) { + if (includeQuestionMark) { + qs = qs + '?'; + } + } else { + qs = qs + '&'; + } + } + + for (var i = 0; i < parameterInfos.length; ++i) { + var parameterInfo = parameterInfos[i]; + if (parameterInfo.value === undefined) { + continue; + } + + if (parameterInfo.value === null) { + parameterInfo.value = ''; + } + + addSeperator(); + + if (parameterInfo.value.toJSON && typeof parameterInfo.value.toJSON === "function") { + qs = qs + parameterInfo.name + '=' + encodeURIComponent(parameterInfo.value.toJSON()); + } else if (Array.isArray(parameterInfo.value) && parameterInfo.value.length) { + for (var j = 0; j < parameterInfo.value.length; j++) { + if (j > 0) { + addSeperator(); + } + + qs = qs + parameterInfo.name + '[' + j + ']=' + encodeURIComponent(parameterInfo.value[j]); + } + } else { + qs = qs + parameterInfo.name + '=' + encodeURIComponent(parameterInfo.value); + } + } + + return qs; + } + + /** + * Sets a cookie value for given key. + * This is a simple implementation created to be used by ABP. + * Please use a complete cookie library if you need. + * @param {string} key + * @param {string} value + * @param {Date} expireDate (optional). If not specified the cookie will expire at the end of session. + * @param {string} path (optional) + */ + abp.utils.setCookieValue = function (key, value, expireDate, path) { + var cookieValue = encodeURIComponent(key) + '='; + + if (value) { + cookieValue = cookieValue + encodeURIComponent(value); + } + + if (expireDate) { + cookieValue = cookieValue + "; expires=" + expireDate.toUTCString(); + } + + if (path) { + cookieValue = cookieValue + "; path=" + path; + } + + document.cookie = cookieValue; + }; + + /** + * Gets a cookie with given key. + * This is a simple implementation created to be used by ABP. + * Please use a complete cookie library if you need. + * @param {string} key + * @returns {string} Cookie value or null + */ + abp.utils.getCookieValue = function (key) { + var equalities = document.cookie.split('; '); + for (var i = 0; i < equalities.length; i++) { + if (!equalities[i]) { + continue; + } + + var splitted = equalities[i].split('='); + if (splitted.length != 2) { + continue; + } + + if (decodeURIComponent(splitted[0]) === key) { + return decodeURIComponent(splitted[1] || ''); + } + } + + return null; + }; + + /** + * Deletes cookie for given key. + * This is a simple implementation created to be used by ABP. + * Please use a complete cookie library if you need. + * @param {string} key + * @param {string} path (optional) + */ + abp.utils.deleteCookie = function (key, path) { + var cookieValue = encodeURIComponent(key) + '='; + + cookieValue = cookieValue + "; expires=" + (new Date(new Date().getTime() - 86400000)).toUTCString(); + + if (path) { + cookieValue = cookieValue + "; path=" + path; + } + + document.cookie = cookieValue; + } + + /* SECURITY ***************************************/ + abp.security = abp.security || {}; + abp.security.antiForgery = abp.security.antiForgery || {}; + + abp.security.antiForgery.tokenCookieName = 'XSRF-TOKEN'; + abp.security.antiForgery.tokenHeaderName = 'X-XSRF-TOKEN'; + + abp.security.antiForgery.getToken = function () { + return abp.utils.getCookieValue(abp.security.antiForgery.tokenCookieName); + }; + +})(); \ No newline at end of file diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/abp/jquery/abp.jquery.js b/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/abp/jquery/abp.jquery.js new file mode 100644 index 0000000000..6a84bfbb61 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/abp/jquery/abp.jquery.js @@ -0,0 +1,389 @@ +var abp = abp || {}; +(function($) { + + if (!$) { + throw "abp/jquery library requires the jquery library included to the page!"; + } + + // ABP CORE OVERRIDES ///////////////////////////////////////////////////// + + abp.message._showMessage = function (message, title) { + alert((title || '') + ' ' + message); + + return $.Deferred(function ($dfd) { + $dfd.resolve(); + }); + }; + + abp.message.confirm = function (message, titleOrCallback, callback) { + if (titleOrCallback && !(typeof titleOrCallback == 'string')) { + callback = titleOrCallback; + } + + var result = confirm(message); + callback && callback(result); + + return $.Deferred(function ($dfd) { + $dfd.resolve(result); + }); + }; + + abp.utils.isFunction = function (obj) { + return $.isFunction(obj); + }; + + // JQUERY EXTENSIONS ////////////////////////////////////////////////////// + + $.fn.findWithSelf = function (selector) { + return this.filter(selector).add(this.find(selector)); + }; + + // DOM //////////////////////////////////////////////////////////////////// + + abp.dom = abp.dom || {}; + + abp.dom.onNodeAdded = function (callback) { + abp.event.on('abp.dom.nodeAdded', callback); + }; + + abp.dom.onNodeRemoved = function (callback) { + abp.event.on('abp.dom.nodeRemoved', callback); + }; + + var mutationObserverCallback = function (mutationsList) { + for (var i = 0; i < mutationsList.length; i++) { + var mutation = mutationsList[i]; + if (mutation.type === 'childList') { + if (mutation.addedNodes && mutation.removedNodes.length) { + for (var k = 0; k < mutation.removedNodes.length; k++) { + abp.event.trigger( + 'abp.dom.nodeRemoved', + { + $el: $(mutation.removedNodes[k]) + } + ); + } + } + + if (mutation.addedNodes && mutation.addedNodes.length) { + for (var j = 0; j < mutation.addedNodes.length; j++) { + abp.event.trigger( + 'abp.dom.nodeAdded', + { + $el: $(mutation.addedNodes[j]) + } + ); + } + } + } + } + }; + + new MutationObserver(mutationObserverCallback).observe( + $('body')[0], + { + subtree: true, + childList: true + } + ); + + // AJAX /////////////////////////////////////////////////////////////////// + + abp.ajax = function (userOptions) { + userOptions = userOptions || {}; + + var options = $.extend(true, {}, abp.ajax.defaultOpts, userOptions); + + options.success = undefined; + options.error = undefined; + + return $.Deferred(function ($dfd) { + $.ajax(options) + .done(function (data, textStatus, jqXHR) { + $dfd.resolve(data); + userOptions.success && userOptions.success(data); + }).fail(function (jqXHR) { + if (jqXHR.getResponseHeader('_AbpErrorFormat') === 'true') { + abp.ajax.handleAbpErrorResponse(jqXHR, userOptions, $dfd); + } else { + abp.ajax.handleNonAbpErrorResponse(jqXHR, userOptions, $dfd); + } + }); + }); + }; + + $.extend(abp.ajax, { + defaultOpts: { + dataType: 'json', + type: 'POST', + contentType: 'application/json', + headers: { + 'X-Requested-With': 'XMLHttpRequest' + } + }, + + defaultError: { + message: 'An error has occurred!', + details: 'Error detail not sent by server.' + }, + + defaultError401: { + message: 'You are not authenticated!', + details: 'You should be authenticated (sign in) in order to perform this operation.' + }, + + defaultError403: { + message: 'You are not authorized!', + details: 'You are not allowed to perform this operation.' + }, + + defaultError404: { + message: 'Resource not found!', + details: 'The resource requested could not found on the server.' + }, + + logError: function (error) { + abp.log.error(error); + }, + + showError: function (error) { + if (error.details) { + return abp.message.error(error.details, error.message); + } else { + return abp.message.error(error.message || abp.ajax.defaultError.message); + } + }, + + handleTargetUrl: function (targetUrl) { + if (!targetUrl) { + location.href = abp.appPath; + } else { + location.href = targetUrl; + } + }, + + handleErrorStatusCode: function (status) { + switch (status) { + case 401: + abp.ajax.handleUnAuthorizedRequest( + abp.ajax.showError(abp.ajax.defaultError401), + abp.appPath + ); + break; + case 403: + abp.ajax.showError(abp.ajax.defaultError403); + break; + case 404: + abp.ajax.showError(abp.ajax.defaultError404); + break; + default: + abp.ajax.showError(abp.ajax.defaultError); + break; + } + }, + + handleNonAbpErrorResponse: function (jqXHR, userOptions, $dfd) { + if (userOptions.abpHandleError !== false) { + abp.ajax.handleErrorStatusCode(jqXHR.status); + } + + $dfd.reject.apply(this, arguments); + userOptions.error && userOptions.error.apply(this, arguments); + }, + + handleAbpErrorResponse: function (jqXHR, userOptions, $dfd) { + var messagePromise = null; + + if (userOptions.abpHandleError !== false) { + messagePromise = abp.ajax.showError(jqXHR.responseJSON.error); + } + + abp.ajax.logError(jqXHR.responseJSON.error); + + $dfd && $dfd.reject(jqXHR.responseJSON.error, jqXHR); + userOptions.error && userOptions.error(jqXHR.responseJSON.error, jqXHR); + + if (jqXHR.status === 401 && userOptions.abpHandleError !== false) { + abp.ajax.handleUnAuthorizedRequest(messagePromise); + } + }, + + handleUnAuthorizedRequest: function (messagePromise, targetUrl) { + if (messagePromise) { + messagePromise.done(function () { + abp.ajax.handleTargetUrl(targetUrl); + }); + } else { + abp.ajax.handleTargetUrl(targetUrl); + } + }, + + blockUI: function (options) { + if (options.blockUI) { + if (options.blockUI === true) { //block whole page + abp.ui.setBusy(); + } else { //block an element + abp.ui.setBusy(options.blockUI); + } + } + }, + + unblockUI: function (options) { + if (options.blockUI) { + if (options.blockUI === true) { //unblock whole page + abp.ui.clearBusy(); + } else { //unblock an element + abp.ui.clearBusy(options.blockUI); + } + } + }, + + ajaxSendHandler: function (event, request, settings) { + var token = abp.security.antiForgery.getToken(); + if (!token) { + return; + } + + if (!settings.headers || settings.headers[abp.security.antiForgery.tokenHeaderName] === undefined) { + request.setRequestHeader(abp.security.antiForgery.tokenHeaderName, token); + } + } + }); + + $(document).ajaxSend(function (event, request, settings) { + return abp.ajax.ajaxSendHandler(event, request, settings); + }); + + abp.event.on('abp.configurationInitialized', function () { + var l = abp.localization.getResource('AbpUi'); + + abp.ajax.defaultError.message = l('DefaultErrorMessage'); + abp.ajax.defaultError.details = l('DefaultErrorMessageDetail'); + abp.ajax.defaultError401.message = l('DefaultErrorMessage401'); + abp.ajax.defaultError401.details = l('DefaultErrorMessage401Detail'); + abp.ajax.defaultError403.message = l('DefaultErrorMessage403'); + abp.ajax.defaultError403.details = l('DefaultErrorMessage403Detail'); + abp.ajax.defaultError404.message = l('DefaultErrorMessage404'); + abp.ajax.defaultError404.details = l('DefaultErrorMessage404Detail'); + }); + + // RESOURCE LOADER //////////////////////////////////////////////////////// + + /* UrlStates enum */ + var UrlStates = { + LOADING: 'LOADING', + LOADED: 'LOADED', + FAILED: 'FAILED' + }; + + /* UrlInfo class */ + function UrlInfo(url) { + this.url = url; + this.state = UrlStates.LOADING; + this.loadCallbacks = []; + this.failCallbacks = []; + } + + UrlInfo.prototype.succeed = function () { + this.state = UrlStates.LOADED; + for (var i = 0; i < this.loadCallbacks.length; i++) { + this.loadCallbacks[i](); + } + }; + + UrlInfo.prototype.failed = function () { + this.state = UrlStates.FAILED; + for (var i = 0; i < this.failCallbacks.length; i++) { + this.failCallbacks[i](); + } + }; + + UrlInfo.prototype.handleCallbacks = function (loadCallback, failCallback) { + switch (this.state) { + case UrlStates.LOADED: + loadCallback && loadCallback(); + break; + case UrlStates.FAILED: + failCallback && failCallback(); + break; + case UrlStates.LOADING: + this.addCallbacks(loadCallback, failCallback); + break; + } + }; + + UrlInfo.prototype.addCallbacks = function (loadCallback, failCallback) { + loadCallback && this.loadCallbacks.push(loadCallback); + failCallback && this.failCallbacks.push(failCallback); + }; + + /* ResourceLoader API */ + + abp.ResourceLoader = (function () { + + var _urlInfos = {}; + + function getCacheKey(url) { + return url; + } + + function appendTimeToUrl(url) { + + if (url.indexOf('?') < 0) { + url += '?'; + } else { + url += '&'; + } + + url += '_=' + new Date().getTime(); + + return url; + } + + var _loadFromUrl = function (url, loadCallback, failCallback, serverLoader) { + + var cacheKey = getCacheKey(url); + + var urlInfo = _urlInfos[cacheKey]; + + if (urlInfo) { + urlInfo.handleCallbacks(loadCallback, failCallback); + return; + } + + _urlInfos[cacheKey] = urlInfo = new UrlInfo(url); + urlInfo.addCallbacks(loadCallback, failCallback); + + serverLoader(urlInfo); + }; + + var _loadScript = function (url, loadCallback, failCallback) { + _loadFromUrl(url, loadCallback, failCallback, function (urlInfo) { + $.getScript(url) + .done(function () { + urlInfo.succeed(); + }) + .fail(function () { + urlInfo.failed(); + }); + }); + }; + + var _loadStyle = function (url) { + _loadFromUrl(url, undefined, undefined, function (urlInfo) { + + $('', { + rel: 'stylesheet', + type: 'text/css', + href: appendTimeToUrl(url) + }).appendTo('head'); + }); + }; + + return { + loadScript: _loadScript, + loadStyle: _loadStyle + } + })(); + +})(jQuery); \ No newline at end of file diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/bootstrap/css/bootstrap.css b/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/bootstrap/css/bootstrap.css new file mode 100644 index 0000000000..f1980e869a --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/bootstrap/css/bootstrap.css @@ -0,0 +1,9887 @@ +/*! + * Bootstrap v4.2.1 (https://getbootstrap.com/) + * Copyright 2011-2018 The Bootstrap Authors + * Copyright 2011-2018 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +:root { + --blue: #007bff; + --indigo: #6610f2; + --purple: #6f42c1; + --pink: #e83e8c; + --red: #dc3545; + --orange: #fd7e14; + --yellow: #ffc107; + --green: #28a745; + --teal: #20c997; + --cyan: #17a2b8; + --white: #fff; + --gray: #6c757d; + --gray-dark: #343a40; + --primary: #007bff; + --secondary: #6c757d; + --success: #28a745; + --info: #17a2b8; + --warning: #ffc107; + --danger: #dc3545; + --light: #f8f9fa; + --dark: #343a40; + --breakpoint-xs: 0; + --breakpoint-sm: 576px; + --breakpoint-md: 768px; + --breakpoint-lg: 992px; + --breakpoint-xl: 1200px; + --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + font-family: sans-serif; + line-height: 1.15; + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { + display: block; +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + text-align: left; + background-color: #fff; +} + +[tabindex="-1"]:focus { + outline: 0 !important; +} + +hr { + box-sizing: content-box; + height: 0; + overflow: visible; +} + +h1, h2, h3, h4, h5, h6 { + margin-top: 0; + margin-bottom: 0.5rem; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +abbr[title], +abbr[data-original-title] { + text-decoration: underline; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + cursor: help; + border-bottom: 0; + text-decoration-skip-ink: none; +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: 700; +} + +dd { + margin-bottom: .5rem; + margin-left: 0; +} + +blockquote { + margin: 0 0 1rem; +} + +b, +strong { + font-weight: bolder; +} + +small { + font-size: 80%; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -.25em; +} + +sup { + top: -.5em; +} + +a { + color: #007bff; + text-decoration: none; + background-color: transparent; +} + +a:hover { + color: #0056b3; + text-decoration: underline; +} + +a:not([href]):not([tabindex]) { + color: inherit; + text-decoration: none; +} + +a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { + color: inherit; + text-decoration: none; +} + +a:not([href]):not([tabindex]):focus { + outline: 0; +} + +pre, +code, +kbd, +samp { + font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + font-size: 1em; +} + +pre { + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; +} + +figure { + margin: 0 0 1rem; +} + +img { + vertical-align: middle; + border-style: none; +} + +svg { + overflow: hidden; + vertical-align: middle; +} + +table { + border-collapse: collapse; +} + +caption { + padding-top: 0.75rem; + padding-bottom: 0.75rem; + color: #6c757d; + text-align: left; + caption-side: bottom; +} + +th { + text-align: inherit; +} + +label { + display: inline-block; + margin-bottom: 0.5rem; +} + +button { + border-radius: 0; +} + +button:focus { + outline: 1px dotted; + outline: 5px auto -webkit-focus-ring-color; +} + +input, +button, +select, +optgroup, +textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +button, +input { + overflow: visible; +} + +button, +select { + text-transform: none; +} + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + padding: 0; + border-style: none; +} + +input[type="radio"], +input[type="checkbox"] { + box-sizing: border-box; + padding: 0; +} + +input[type="date"], +input[type="time"], +input[type="datetime-local"], +input[type="month"] { + -webkit-appearance: listbox; +} + +textarea { + overflow: auto; + resize: vertical; +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + max-width: 100%; + padding: 0; + margin-bottom: .5rem; + font-size: 1.5rem; + line-height: inherit; + color: inherit; + white-space: normal; +} + +progress { + vertical-align: baseline; +} + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +[type="search"] { + outline-offset: -2px; + -webkit-appearance: none; +} + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-file-upload-button { + font: inherit; + -webkit-appearance: button; +} + +output { + display: inline-block; +} + +summary { + display: list-item; + cursor: pointer; +} + +template { + display: none; +} + +[hidden] { + display: none !important; +} + +h1, h2, h3, h4, h5, h6, +.h1, .h2, .h3, .h4, .h5, .h6 { + margin-bottom: 0.5rem; + font-family: inherit; + font-weight: 500; + line-height: 1.2; + color: inherit; +} + +h1, .h1 { + font-size: 2.5rem; +} + +h2, .h2 { + font-size: 2rem; +} + +h3, .h3 { + font-size: 1.75rem; +} + +h4, .h4 { + font-size: 1.5rem; +} + +h5, .h5 { + font-size: 1.25rem; +} + +h6, .h6 { + font-size: 1rem; +} + +.lead { + font-size: 1.25rem; + font-weight: 300; +} + +.display-1 { + font-size: 6rem; + font-weight: 300; + line-height: 1.2; +} + +.display-2 { + font-size: 5.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-3 { + font-size: 4.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-4 { + font-size: 3.5rem; + font-weight: 300; + line-height: 1.2; +} + +hr { + margin-top: 1rem; + margin-bottom: 1rem; + border: 0; + border-top: 1px solid rgba(0, 0, 0, 0.1); +} + +small, +.small { + font-size: 80%; + font-weight: 400; +} + +mark, +.mark { + padding: 0.2em; + background-color: #fcf8e3; +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline-item { + display: inline-block; +} + +.list-inline-item:not(:last-child) { + margin-right: 0.5rem; +} + +.initialism { + font-size: 90%; + text-transform: uppercase; +} + +.blockquote { + margin-bottom: 1rem; + font-size: 1.25rem; +} + +.blockquote-footer { + display: block; + font-size: 80%; + color: #6c757d; +} + +.blockquote-footer::before { + content: "\2014\00A0"; +} + +.img-fluid { + max-width: 100%; + height: auto; +} + +.img-thumbnail { + padding: 0.25rem; + background-color: #fff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + max-width: 100%; + height: auto; +} + +.figure { + display: inline-block; +} + +.figure-img { + margin-bottom: 0.5rem; + line-height: 1; +} + +.figure-caption { + font-size: 90%; + color: #6c757d; +} + +code { + font-size: 87.5%; + color: #e83e8c; + word-break: break-word; +} + +a > code { + color: inherit; +} + +kbd { + padding: 0.2rem 0.4rem; + font-size: 87.5%; + color: #fff; + background-color: #212529; + border-radius: 0.2rem; +} + +kbd kbd { + padding: 0; + font-size: 100%; + font-weight: 700; +} + +pre { + display: block; + font-size: 87.5%; + color: #212529; +} + +pre code { + font-size: inherit; + color: inherit; + word-break: normal; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +.container { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + .container { + max-width: 540px; + } +} + +@media (min-width: 768px) { + .container { + max-width: 720px; + } +} + +@media (min-width: 992px) { + .container { + max-width: 960px; + } +} + +@media (min-width: 1200px) { + .container { + max-width: 1140px; + } +} + +.container-fluid { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +.row { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -15px; + margin-left: -15px; +} + +.no-gutters { + margin-right: 0; + margin-left: 0; +} + +.no-gutters > .col, +.no-gutters > [class*="col-"] { + padding-right: 0; + padding-left: 0; +} + +.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col, +.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm, +.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md, +.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg, +.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl, +.col-xl-auto { + position: relative; + width: 100%; + padding-right: 15px; + padding-left: 15px; +} + +.col { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; +} + +.col-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; +} + +.col-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; +} + +.col-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; +} + +.col-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; +} + +.col-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; +} + +.col-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; +} + +.col-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; +} + +.col-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; +} + +.col-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; +} + +.col-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; +} + +.col-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; +} + +.col-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; +} + +.col-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; +} + +.order-first { + -ms-flex-order: -1; + order: -1; +} + +.order-last { + -ms-flex-order: 13; + order: 13; +} + +.order-0 { + -ms-flex-order: 0; + order: 0; +} + +.order-1 { + -ms-flex-order: 1; + order: 1; +} + +.order-2 { + -ms-flex-order: 2; + order: 2; +} + +.order-3 { + -ms-flex-order: 3; + order: 3; +} + +.order-4 { + -ms-flex-order: 4; + order: 4; +} + +.order-5 { + -ms-flex-order: 5; + order: 5; +} + +.order-6 { + -ms-flex-order: 6; + order: 6; +} + +.order-7 { + -ms-flex-order: 7; + order: 7; +} + +.order-8 { + -ms-flex-order: 8; + order: 8; +} + +.order-9 { + -ms-flex-order: 9; + order: 9; +} + +.order-10 { + -ms-flex-order: 10; + order: 10; +} + +.order-11 { + -ms-flex-order: 11; + order: 11; +} + +.order-12 { + -ms-flex-order: 12; + order: 12; +} + +.offset-1 { + margin-left: 8.333333%; +} + +.offset-2 { + margin-left: 16.666667%; +} + +.offset-3 { + margin-left: 25%; +} + +.offset-4 { + margin-left: 33.333333%; +} + +.offset-5 { + margin-left: 41.666667%; +} + +.offset-6 { + margin-left: 50%; +} + +.offset-7 { + margin-left: 58.333333%; +} + +.offset-8 { + margin-left: 66.666667%; +} + +.offset-9 { + margin-left: 75%; +} + +.offset-10 { + margin-left: 83.333333%; +} + +.offset-11 { + margin-left: 91.666667%; +} + +@media (min-width: 576px) { + .col-sm { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .col-sm-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-sm-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + .col-sm-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-sm-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-sm-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .col-sm-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + .col-sm-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-sm-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + .col-sm-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + .col-sm-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-sm-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + .col-sm-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + .col-sm-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-sm-first { + -ms-flex-order: -1; + order: -1; + } + .order-sm-last { + -ms-flex-order: 13; + order: 13; + } + .order-sm-0 { + -ms-flex-order: 0; + order: 0; + } + .order-sm-1 { + -ms-flex-order: 1; + order: 1; + } + .order-sm-2 { + -ms-flex-order: 2; + order: 2; + } + .order-sm-3 { + -ms-flex-order: 3; + order: 3; + } + .order-sm-4 { + -ms-flex-order: 4; + order: 4; + } + .order-sm-5 { + -ms-flex-order: 5; + order: 5; + } + .order-sm-6 { + -ms-flex-order: 6; + order: 6; + } + .order-sm-7 { + -ms-flex-order: 7; + order: 7; + } + .order-sm-8 { + -ms-flex-order: 8; + order: 8; + } + .order-sm-9 { + -ms-flex-order: 9; + order: 9; + } + .order-sm-10 { + -ms-flex-order: 10; + order: 10; + } + .order-sm-11 { + -ms-flex-order: 11; + order: 11; + } + .order-sm-12 { + -ms-flex-order: 12; + order: 12; + } + .offset-sm-0 { + margin-left: 0; + } + .offset-sm-1 { + margin-left: 8.333333%; + } + .offset-sm-2 { + margin-left: 16.666667%; + } + .offset-sm-3 { + margin-left: 25%; + } + .offset-sm-4 { + margin-left: 33.333333%; + } + .offset-sm-5 { + margin-left: 41.666667%; + } + .offset-sm-6 { + margin-left: 50%; + } + .offset-sm-7 { + margin-left: 58.333333%; + } + .offset-sm-8 { + margin-left: 66.666667%; + } + .offset-sm-9 { + margin-left: 75%; + } + .offset-sm-10 { + margin-left: 83.333333%; + } + .offset-sm-11 { + margin-left: 91.666667%; + } +} + +@media (min-width: 768px) { + .col-md { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .col-md-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-md-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + .col-md-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-md-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-md-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .col-md-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + .col-md-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-md-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + .col-md-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + .col-md-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-md-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + .col-md-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + .col-md-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-md-first { + -ms-flex-order: -1; + order: -1; + } + .order-md-last { + -ms-flex-order: 13; + order: 13; + } + .order-md-0 { + -ms-flex-order: 0; + order: 0; + } + .order-md-1 { + -ms-flex-order: 1; + order: 1; + } + .order-md-2 { + -ms-flex-order: 2; + order: 2; + } + .order-md-3 { + -ms-flex-order: 3; + order: 3; + } + .order-md-4 { + -ms-flex-order: 4; + order: 4; + } + .order-md-5 { + -ms-flex-order: 5; + order: 5; + } + .order-md-6 { + -ms-flex-order: 6; + order: 6; + } + .order-md-7 { + -ms-flex-order: 7; + order: 7; + } + .order-md-8 { + -ms-flex-order: 8; + order: 8; + } + .order-md-9 { + -ms-flex-order: 9; + order: 9; + } + .order-md-10 { + -ms-flex-order: 10; + order: 10; + } + .order-md-11 { + -ms-flex-order: 11; + order: 11; + } + .order-md-12 { + -ms-flex-order: 12; + order: 12; + } + .offset-md-0 { + margin-left: 0; + } + .offset-md-1 { + margin-left: 8.333333%; + } + .offset-md-2 { + margin-left: 16.666667%; + } + .offset-md-3 { + margin-left: 25%; + } + .offset-md-4 { + margin-left: 33.333333%; + } + .offset-md-5 { + margin-left: 41.666667%; + } + .offset-md-6 { + margin-left: 50%; + } + .offset-md-7 { + margin-left: 58.333333%; + } + .offset-md-8 { + margin-left: 66.666667%; + } + .offset-md-9 { + margin-left: 75%; + } + .offset-md-10 { + margin-left: 83.333333%; + } + .offset-md-11 { + margin-left: 91.666667%; + } +} + +@media (min-width: 992px) { + .col-lg { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .col-lg-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-lg-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + .col-lg-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-lg-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-lg-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .col-lg-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + .col-lg-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-lg-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + .col-lg-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + .col-lg-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-lg-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + .col-lg-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + .col-lg-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-lg-first { + -ms-flex-order: -1; + order: -1; + } + .order-lg-last { + -ms-flex-order: 13; + order: 13; + } + .order-lg-0 { + -ms-flex-order: 0; + order: 0; + } + .order-lg-1 { + -ms-flex-order: 1; + order: 1; + } + .order-lg-2 { + -ms-flex-order: 2; + order: 2; + } + .order-lg-3 { + -ms-flex-order: 3; + order: 3; + } + .order-lg-4 { + -ms-flex-order: 4; + order: 4; + } + .order-lg-5 { + -ms-flex-order: 5; + order: 5; + } + .order-lg-6 { + -ms-flex-order: 6; + order: 6; + } + .order-lg-7 { + -ms-flex-order: 7; + order: 7; + } + .order-lg-8 { + -ms-flex-order: 8; + order: 8; + } + .order-lg-9 { + -ms-flex-order: 9; + order: 9; + } + .order-lg-10 { + -ms-flex-order: 10; + order: 10; + } + .order-lg-11 { + -ms-flex-order: 11; + order: 11; + } + .order-lg-12 { + -ms-flex-order: 12; + order: 12; + } + .offset-lg-0 { + margin-left: 0; + } + .offset-lg-1 { + margin-left: 8.333333%; + } + .offset-lg-2 { + margin-left: 16.666667%; + } + .offset-lg-3 { + margin-left: 25%; + } + .offset-lg-4 { + margin-left: 33.333333%; + } + .offset-lg-5 { + margin-left: 41.666667%; + } + .offset-lg-6 { + margin-left: 50%; + } + .offset-lg-7 { + margin-left: 58.333333%; + } + .offset-lg-8 { + margin-left: 66.666667%; + } + .offset-lg-9 { + margin-left: 75%; + } + .offset-lg-10 { + margin-left: 83.333333%; + } + .offset-lg-11 { + margin-left: 91.666667%; + } +} + +@media (min-width: 1200px) { + .col-xl { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .col-xl-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-xl-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + .col-xl-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-xl-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-xl-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .col-xl-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + .col-xl-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-xl-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + .col-xl-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + .col-xl-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-xl-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + .col-xl-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + .col-xl-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-xl-first { + -ms-flex-order: -1; + order: -1; + } + .order-xl-last { + -ms-flex-order: 13; + order: 13; + } + .order-xl-0 { + -ms-flex-order: 0; + order: 0; + } + .order-xl-1 { + -ms-flex-order: 1; + order: 1; + } + .order-xl-2 { + -ms-flex-order: 2; + order: 2; + } + .order-xl-3 { + -ms-flex-order: 3; + order: 3; + } + .order-xl-4 { + -ms-flex-order: 4; + order: 4; + } + .order-xl-5 { + -ms-flex-order: 5; + order: 5; + } + .order-xl-6 { + -ms-flex-order: 6; + order: 6; + } + .order-xl-7 { + -ms-flex-order: 7; + order: 7; + } + .order-xl-8 { + -ms-flex-order: 8; + order: 8; + } + .order-xl-9 { + -ms-flex-order: 9; + order: 9; + } + .order-xl-10 { + -ms-flex-order: 10; + order: 10; + } + .order-xl-11 { + -ms-flex-order: 11; + order: 11; + } + .order-xl-12 { + -ms-flex-order: 12; + order: 12; + } + .offset-xl-0 { + margin-left: 0; + } + .offset-xl-1 { + margin-left: 8.333333%; + } + .offset-xl-2 { + margin-left: 16.666667%; + } + .offset-xl-3 { + margin-left: 25%; + } + .offset-xl-4 { + margin-left: 33.333333%; + } + .offset-xl-5 { + margin-left: 41.666667%; + } + .offset-xl-6 { + margin-left: 50%; + } + .offset-xl-7 { + margin-left: 58.333333%; + } + .offset-xl-8 { + margin-left: 66.666667%; + } + .offset-xl-9 { + margin-left: 75%; + } + .offset-xl-10 { + margin-left: 83.333333%; + } + .offset-xl-11 { + margin-left: 91.666667%; + } +} + +.table { + width: 100%; + margin-bottom: 1rem; + background-color: transparent; +} + +.table th, +.table td { + padding: 0.75rem; + vertical-align: top; + border-top: 1px solid #dee2e6; +} + +.table thead th { + vertical-align: bottom; + border-bottom: 2px solid #dee2e6; +} + +.table tbody + tbody { + border-top: 2px solid #dee2e6; +} + +.table .table { + background-color: #fff; +} + +.table-sm th, +.table-sm td { + padding: 0.3rem; +} + +.table-bordered { + border: 1px solid #dee2e6; +} + +.table-bordered th, +.table-bordered td { + border: 1px solid #dee2e6; +} + +.table-bordered thead th, +.table-bordered thead td { + border-bottom-width: 2px; +} + +.table-borderless th, +.table-borderless td, +.table-borderless thead th, +.table-borderless tbody + tbody { + border: 0; +} + +.table-striped tbody tr:nth-of-type(odd) { + background-color: rgba(0, 0, 0, 0.05); +} + +.table-hover tbody tr:hover { + background-color: rgba(0, 0, 0, 0.075); +} + +.table-primary, +.table-primary > th, +.table-primary > td { + background-color: #b8daff; +} + +.table-primary th, +.table-primary td, +.table-primary thead th, +.table-primary tbody + tbody { + border-color: #7abaff; +} + +.table-hover .table-primary:hover { + background-color: #9fcdff; +} + +.table-hover .table-primary:hover > td, +.table-hover .table-primary:hover > th { + background-color: #9fcdff; +} + +.table-secondary, +.table-secondary > th, +.table-secondary > td { + background-color: #d6d8db; +} + +.table-secondary th, +.table-secondary td, +.table-secondary thead th, +.table-secondary tbody + tbody { + border-color: #b3b7bb; +} + +.table-hover .table-secondary:hover { + background-color: #c8cbcf; +} + +.table-hover .table-secondary:hover > td, +.table-hover .table-secondary:hover > th { + background-color: #c8cbcf; +} + +.table-success, +.table-success > th, +.table-success > td { + background-color: #c3e6cb; +} + +.table-success th, +.table-success td, +.table-success thead th, +.table-success tbody + tbody { + border-color: #8fd19e; +} + +.table-hover .table-success:hover { + background-color: #b1dfbb; +} + +.table-hover .table-success:hover > td, +.table-hover .table-success:hover > th { + background-color: #b1dfbb; +} + +.table-info, +.table-info > th, +.table-info > td { + background-color: #bee5eb; +} + +.table-info th, +.table-info td, +.table-info thead th, +.table-info tbody + tbody { + border-color: #86cfda; +} + +.table-hover .table-info:hover { + background-color: #abdde5; +} + +.table-hover .table-info:hover > td, +.table-hover .table-info:hover > th { + background-color: #abdde5; +} + +.table-warning, +.table-warning > th, +.table-warning > td { + background-color: #ffeeba; +} + +.table-warning th, +.table-warning td, +.table-warning thead th, +.table-warning tbody + tbody { + border-color: #ffdf7e; +} + +.table-hover .table-warning:hover { + background-color: #ffe8a1; +} + +.table-hover .table-warning:hover > td, +.table-hover .table-warning:hover > th { + background-color: #ffe8a1; +} + +.table-danger, +.table-danger > th, +.table-danger > td { + background-color: #f5c6cb; +} + +.table-danger th, +.table-danger td, +.table-danger thead th, +.table-danger tbody + tbody { + border-color: #ed969e; +} + +.table-hover .table-danger:hover { + background-color: #f1b0b7; +} + +.table-hover .table-danger:hover > td, +.table-hover .table-danger:hover > th { + background-color: #f1b0b7; +} + +.table-light, +.table-light > th, +.table-light > td { + background-color: #fdfdfe; +} + +.table-light th, +.table-light td, +.table-light thead th, +.table-light tbody + tbody { + border-color: #fbfcfc; +} + +.table-hover .table-light:hover { + background-color: #ececf6; +} + +.table-hover .table-light:hover > td, +.table-hover .table-light:hover > th { + background-color: #ececf6; +} + +.table-dark, +.table-dark > th, +.table-dark > td { + background-color: #c6c8ca; +} + +.table-dark th, +.table-dark td, +.table-dark thead th, +.table-dark tbody + tbody { + border-color: #95999c; +} + +.table-hover .table-dark:hover { + background-color: #b9bbbe; +} + +.table-hover .table-dark:hover > td, +.table-hover .table-dark:hover > th { + background-color: #b9bbbe; +} + +.table-active, +.table-active > th, +.table-active > td { + background-color: rgba(0, 0, 0, 0.075); +} + +.table-hover .table-active:hover { + background-color: rgba(0, 0, 0, 0.075); +} + +.table-hover .table-active:hover > td, +.table-hover .table-active:hover > th { + background-color: rgba(0, 0, 0, 0.075); +} + +.table .thead-dark th { + color: #fff; + background-color: #212529; + border-color: #32383e; +} + +.table .thead-light th { + color: #495057; + background-color: #e9ecef; + border-color: #dee2e6; +} + +.table-dark { + color: #fff; + background-color: #212529; +} + +.table-dark th, +.table-dark td, +.table-dark thead th { + border-color: #32383e; +} + +.table-dark.table-bordered { + border: 0; +} + +.table-dark.table-striped tbody tr:nth-of-type(odd) { + background-color: rgba(255, 255, 255, 0.05); +} + +.table-dark.table-hover tbody tr:hover { + background-color: rgba(255, 255, 255, 0.075); +} + +@media (max-width: 575.98px) { + .table-responsive-sm { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + -ms-overflow-style: -ms-autohiding-scrollbar; + } + .table-responsive-sm > .table-bordered { + border: 0; + } +} + +@media (max-width: 767.98px) { + .table-responsive-md { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + -ms-overflow-style: -ms-autohiding-scrollbar; + } + .table-responsive-md > .table-bordered { + border: 0; + } +} + +@media (max-width: 991.98px) { + .table-responsive-lg { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + -ms-overflow-style: -ms-autohiding-scrollbar; + } + .table-responsive-lg > .table-bordered { + border: 0; + } +} + +@media (max-width: 1199.98px) { + .table-responsive-xl { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + -ms-overflow-style: -ms-autohiding-scrollbar; + } + .table-responsive-xl > .table-bordered { + border: 0; + } +} + +.table-responsive { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + -ms-overflow-style: -ms-autohiding-scrollbar; +} + +.table-responsive > .table-bordered { + border: 0; +} + +.form-control { + display: block; + width: 100%; + height: calc(2.25rem + 2px); + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ced4da; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media screen and (prefers-reduced-motion: reduce) { + .form-control { + transition: none; + } +} + +.form-control::-ms-expand { + background-color: transparent; + border: 0; +} + +.form-control:focus { + color: #495057; + background-color: #fff; + border-color: #80bdff; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.form-control::-webkit-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::-moz-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control:-ms-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::-ms-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control:disabled, .form-control[readonly] { + background-color: #e9ecef; + opacity: 1; +} + +select.form-control:focus::-ms-value { + color: #495057; + background-color: #fff; +} + +.form-control-file, +.form-control-range { + display: block; + width: 100%; +} + +.col-form-label { + padding-top: calc(0.375rem + 1px); + padding-bottom: calc(0.375rem + 1px); + margin-bottom: 0; + font-size: inherit; + line-height: 1.5; +} + +.col-form-label-lg { + padding-top: calc(0.5rem + 1px); + padding-bottom: calc(0.5rem + 1px); + font-size: 1.25rem; + line-height: 1.5; +} + +.col-form-label-sm { + padding-top: calc(0.25rem + 1px); + padding-bottom: calc(0.25rem + 1px); + font-size: 0.875rem; + line-height: 1.5; +} + +.form-control-plaintext { + display: block; + width: 100%; + padding-top: 0.375rem; + padding-bottom: 0.375rem; + margin-bottom: 0; + line-height: 1.5; + color: #212529; + background-color: transparent; + border: solid transparent; + border-width: 1px 0; +} + +.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { + padding-right: 0; + padding-left: 0; +} + +.form-control-sm { + height: calc(1.8125rem + 2px); + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.form-control-lg { + height: calc(2.875rem + 2px); + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +select.form-control[size], select.form-control[multiple] { + height: auto; +} + +textarea.form-control { + height: auto; +} + +.form-group { + margin-bottom: 1rem; +} + +.form-text { + display: block; + margin-top: 0.25rem; +} + +.form-row { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -5px; + margin-left: -5px; +} + +.form-row > .col, +.form-row > [class*="col-"] { + padding-right: 5px; + padding-left: 5px; +} + +.form-check { + position: relative; + display: block; + padding-left: 1.25rem; +} + +.form-check-input { + position: absolute; + margin-top: 0.3rem; + margin-left: -1.25rem; +} + +.form-check-input:disabled ~ .form-check-label { + color: #6c757d; +} + +.form-check-label { + margin-bottom: 0; +} + +.form-check-inline { + display: -ms-inline-flexbox; + display: inline-flex; + -ms-flex-align: center; + align-items: center; + padding-left: 0; + margin-right: 0.75rem; +} + +.form-check-inline .form-check-input { + position: static; + margin-top: 0; + margin-right: 0.3125rem; + margin-left: 0; +} + +.valid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #28a745; +} + +.valid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #fff; + background-color: rgba(40, 167, 69, 0.9); + border-radius: 0.25rem; +} + +.was-validated .form-control:valid, .form-control.is-valid { + border-color: #28a745; + padding-right: 2.25rem; + background-repeat: no-repeat; + background-position: center right calc(2.25rem / 4); + background-size: calc(2.25rem / 2) calc(2.25rem / 2); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); +} + +.was-validated .form-control:valid:focus, .form-control.is-valid:focus { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .form-control:valid ~ .valid-feedback, +.was-validated .form-control:valid ~ .valid-tooltip, .form-control.is-valid ~ .valid-feedback, +.form-control.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated textarea.form-control:valid, textarea.form-control.is-valid { + padding-right: 2.25rem; + background-position: top calc(2.25rem / 4) right calc(2.25rem / 4); +} + +.was-validated .custom-select:valid, .custom-select.is-valid { + border-color: #28a745; + padding-right: 3.4375rem; + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") no-repeat center right 1.75rem/1.125rem 1.125rem; +} + +.was-validated .custom-select:valid:focus, .custom-select.is-valid:focus { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .custom-select:valid ~ .valid-feedback, +.was-validated .custom-select:valid ~ .valid-tooltip, .custom-select.is-valid ~ .valid-feedback, +.custom-select.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .form-control-file:valid ~ .valid-feedback, +.was-validated .form-control-file:valid ~ .valid-tooltip, .form-control-file.is-valid ~ .valid-feedback, +.form-control-file.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { + color: #28a745; +} + +.was-validated .form-check-input:valid ~ .valid-feedback, +.was-validated .form-check-input:valid ~ .valid-tooltip, .form-check-input.is-valid ~ .valid-feedback, +.form-check-input.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .custom-control-input:valid ~ .custom-control-label, .custom-control-input.is-valid ~ .custom-control-label { + color: #28a745; +} + +.was-validated .custom-control-input:valid ~ .custom-control-label::before, .custom-control-input.is-valid ~ .custom-control-label::before { + border-color: #28a745; +} + +.was-validated .custom-control-input:valid ~ .valid-feedback, +.was-validated .custom-control-input:valid ~ .valid-tooltip, .custom-control-input.is-valid ~ .valid-feedback, +.custom-control-input.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before, .custom-control-input.is-valid:checked ~ .custom-control-label::before { + border-color: #34ce57; + background-color: #34ce57; +} + +.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before, .custom-control-input.is-valid:focus ~ .custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .custom-control-input:valid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-valid:focus:not(:checked) ~ .custom-control-label::before { + border-color: #28a745; +} + +.was-validated .custom-file-input:valid ~ .custom-file-label, .custom-file-input.is-valid ~ .custom-file-label { + border-color: #28a745; +} + +.was-validated .custom-file-input:valid ~ .valid-feedback, +.was-validated .custom-file-input:valid ~ .valid-tooltip, .custom-file-input.is-valid ~ .valid-feedback, +.custom-file-input.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .custom-file-input:valid:focus ~ .custom-file-label, .custom-file-input.is-valid:focus ~ .custom-file-label { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.invalid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #dc3545; +} + +.invalid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #fff; + background-color: rgba(220, 53, 69, 0.9); + border-radius: 0.25rem; +} + +.was-validated .form-control:invalid, .form-control.is-invalid { + border-color: #dc3545; + padding-right: 2.25rem; + background-repeat: no-repeat; + background-position: center right calc(2.25rem / 4); + background-size: calc(2.25rem / 2) calc(2.25rem / 2); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E"); +} + +.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .form-control:invalid ~ .invalid-feedback, +.was-validated .form-control:invalid ~ .invalid-tooltip, .form-control.is-invalid ~ .invalid-feedback, +.form-control.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid { + padding-right: 2.25rem; + background-position: top calc(2.25rem / 4) right calc(2.25rem / 4); +} + +.was-validated .custom-select:invalid, .custom-select.is-invalid { + border-color: #dc3545; + padding-right: 3.4375rem; + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E") no-repeat center right 1.75rem/1.125rem 1.125rem; +} + +.was-validated .custom-select:invalid:focus, .custom-select.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .custom-select:invalid ~ .invalid-feedback, +.was-validated .custom-select:invalid ~ .invalid-tooltip, .custom-select.is-invalid ~ .invalid-feedback, +.custom-select.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .form-control-file:invalid ~ .invalid-feedback, +.was-validated .form-control-file:invalid ~ .invalid-tooltip, .form-control-file.is-invalid ~ .invalid-feedback, +.form-control-file.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { + color: #dc3545; +} + +.was-validated .form-check-input:invalid ~ .invalid-feedback, +.was-validated .form-check-input:invalid ~ .invalid-tooltip, .form-check-input.is-invalid ~ .invalid-feedback, +.form-check-input.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .custom-control-input:invalid ~ .custom-control-label, .custom-control-input.is-invalid ~ .custom-control-label { + color: #dc3545; +} + +.was-validated .custom-control-input:invalid ~ .custom-control-label::before, .custom-control-input.is-invalid ~ .custom-control-label::before { + border-color: #dc3545; +} + +.was-validated .custom-control-input:invalid ~ .invalid-feedback, +.was-validated .custom-control-input:invalid ~ .invalid-tooltip, .custom-control-input.is-invalid ~ .invalid-feedback, +.custom-control-input.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before, .custom-control-input.is-invalid:checked ~ .custom-control-label::before { + border-color: #e4606d; + background-color: #e4606d; +} + +.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before, .custom-control-input.is-invalid:focus ~ .custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .custom-control-input:invalid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-invalid:focus:not(:checked) ~ .custom-control-label::before { + border-color: #dc3545; +} + +.was-validated .custom-file-input:invalid ~ .custom-file-label, .custom-file-input.is-invalid ~ .custom-file-label { + border-color: #dc3545; +} + +.was-validated .custom-file-input:invalid ~ .invalid-feedback, +.was-validated .custom-file-input:invalid ~ .invalid-tooltip, .custom-file-input.is-invalid ~ .invalid-feedback, +.custom-file-input.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .custom-file-input:invalid:focus ~ .custom-file-label, .custom-file-input.is-invalid:focus ~ .custom-file-label { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.form-inline { + display: -ms-flexbox; + display: flex; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -ms-flex-align: center; + align-items: center; +} + +.form-inline .form-check { + width: 100%; +} + +@media (min-width: 576px) { + .form-inline label { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + margin-bottom: 0; + } + .form-inline .form-group { + display: -ms-flexbox; + display: flex; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -ms-flex-align: center; + align-items: center; + margin-bottom: 0; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .form-control-plaintext { + display: inline-block; + } + .form-inline .input-group, + .form-inline .custom-select { + width: auto; + } + .form-inline .form-check { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + width: auto; + padding-left: 0; + } + .form-inline .form-check-input { + position: relative; + margin-top: 0; + margin-right: 0.25rem; + margin-left: 0; + } + .form-inline .custom-control { + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + } + .form-inline .custom-control-label { + margin-bottom: 0; + } +} + +.btn { + display: inline-block; + font-weight: 400; + color: #212529; + text-align: center; + vertical-align: middle; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: transparent; + border: 1px solid transparent; + padding: 0.375rem 0.75rem; + font-size: 1rem; + line-height: 1.5; + border-radius: 0.25rem; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media screen and (prefers-reduced-motion: reduce) { + .btn { + transition: none; + } +} + +.btn:hover { + color: #212529; + text-decoration: none; +} + +.btn:focus, .btn.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.btn.disabled, .btn:disabled { + opacity: 0.65; +} + +.btn:not(:disabled):not(.disabled) { + cursor: pointer; +} + +a.btn.disabled, +fieldset:disabled a.btn { + pointer-events: none; +} + +.btn-primary { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-primary:hover { + color: #fff; + background-color: #0069d9; + border-color: #0062cc; +} + +.btn-primary:focus, .btn-primary.focus { + box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); +} + +.btn-primary.disabled, .btn-primary:disabled { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active, +.show > .btn-primary.dropdown-toggle { + color: #fff; + background-color: #0062cc; + border-color: #005cbf; +} + +.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus, +.show > .btn-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); +} + +.btn-secondary { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-secondary:hover { + color: #fff; + background-color: #5a6268; + border-color: #545b62; +} + +.btn-secondary:focus, .btn-secondary.focus { + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-secondary.disabled, .btn-secondary:disabled { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active, +.show > .btn-secondary.dropdown-toggle { + color: #fff; + background-color: #545b62; + border-color: #4e555b; +} + +.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus, +.show > .btn-secondary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-success { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-success:hover { + color: #fff; + background-color: #218838; + border-color: #1e7e34; +} + +.btn-success:focus, .btn-success.focus { + box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); +} + +.btn-success.disabled, .btn-success:disabled { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active, +.show > .btn-success.dropdown-toggle { + color: #fff; + background-color: #1e7e34; + border-color: #1c7430; +} + +.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus, +.show > .btn-success.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); +} + +.btn-info { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-info:hover { + color: #fff; + background-color: #138496; + border-color: #117a8b; +} + +.btn-info:focus, .btn-info.focus { + box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); +} + +.btn-info.disabled, .btn-info:disabled { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active, +.show > .btn-info.dropdown-toggle { + color: #fff; + background-color: #117a8b; + border-color: #10707f; +} + +.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus, +.show > .btn-info.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); +} + +.btn-warning { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-warning:hover { + color: #212529; + background-color: #e0a800; + border-color: #d39e00; +} + +.btn-warning:focus, .btn-warning.focus { + box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); +} + +.btn-warning.disabled, .btn-warning:disabled { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active, +.show > .btn-warning.dropdown-toggle { + color: #212529; + background-color: #d39e00; + border-color: #c69500; +} + +.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus, +.show > .btn-warning.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); +} + +.btn-danger { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-danger:hover { + color: #fff; + background-color: #c82333; + border-color: #bd2130; +} + +.btn-danger:focus, .btn-danger.focus { + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-danger.disabled, .btn-danger:disabled { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active, +.show > .btn-danger.dropdown-toggle { + color: #fff; + background-color: #bd2130; + border-color: #b21f2d; +} + +.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus, +.show > .btn-danger.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-light { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-light:hover { + color: #212529; + background-color: #e2e6ea; + border-color: #dae0e5; +} + +.btn-light:focus, .btn-light.focus { + box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); +} + +.btn-light.disabled, .btn-light:disabled { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active, +.show > .btn-light.dropdown-toggle { + color: #212529; + background-color: #dae0e5; + border-color: #d3d9df; +} + +.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus, +.show > .btn-light.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); +} + +.btn-dark { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-dark:hover { + color: #fff; + background-color: #23272b; + border-color: #1d2124; +} + +.btn-dark:focus, .btn-dark.focus { + box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); +} + +.btn-dark.disabled, .btn-dark:disabled { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active, +.show > .btn-dark.dropdown-toggle { + color: #fff; + background-color: #1d2124; + border-color: #171a1d; +} + +.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus, +.show > .btn-dark.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); +} + +.btn-outline-primary { + color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:hover { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:focus, .btn-outline-primary.focus { + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); +} + +.btn-outline-primary.disabled, .btn-outline-primary:disabled { + color: #007bff; + background-color: transparent; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active, +.show > .btn-outline-primary.dropdown-toggle { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); +} + +.btn-outline-secondary { + color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:hover { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:focus, .btn-outline-secondary.focus { + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-outline-secondary.disabled, .btn-outline-secondary:disabled { + color: #6c757d; + background-color: transparent; +} + +.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active, +.show > .btn-outline-secondary.dropdown-toggle { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-secondary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-outline-success { + color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:hover { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:focus, .btn-outline-success.focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-outline-success.disabled, .btn-outline-success:disabled { + color: #28a745; + background-color: transparent; +} + +.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active, +.show > .btn-outline-success.dropdown-toggle { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-success.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-outline-info { + color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:hover { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:focus, .btn-outline-info.focus { + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-outline-info.disabled, .btn-outline-info:disabled { + color: #17a2b8; + background-color: transparent; +} + +.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active, +.show > .btn-outline-info.dropdown-toggle { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-info.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-outline-warning { + color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:hover { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:focus, .btn-outline-warning.focus { + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-outline-warning.disabled, .btn-outline-warning:disabled { + color: #ffc107; + background-color: transparent; +} + +.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active, +.show > .btn-outline-warning.dropdown-toggle { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-warning.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-outline-danger { + color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:hover { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:focus, .btn-outline-danger.focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-outline-danger.disabled, .btn-outline-danger:disabled { + color: #dc3545; + background-color: transparent; +} + +.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active, +.show > .btn-outline-danger.dropdown-toggle { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-danger.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-outline-light { + color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:hover { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:focus, .btn-outline-light.focus { + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-outline-light.disabled, .btn-outline-light:disabled { + color: #f8f9fa; + background-color: transparent; +} + +.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active, +.show > .btn-outline-light.dropdown-toggle { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-light.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-outline-dark { + color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:hover { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:focus, .btn-outline-dark.focus { + box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); +} + +.btn-outline-dark.disabled, .btn-outline-dark:disabled { + color: #343a40; + background-color: transparent; +} + +.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active, +.show > .btn-outline-dark.dropdown-toggle { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-dark.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); +} + +.btn-link { + font-weight: 400; + color: #007bff; +} + +.btn-link:hover { + color: #0056b3; + text-decoration: underline; +} + +.btn-link:focus, .btn-link.focus { + text-decoration: underline; + box-shadow: none; +} + +.btn-link:disabled, .btn-link.disabled { + color: #6c757d; + pointer-events: none; +} + +.btn-lg, .btn-group-lg > .btn { + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +.btn-sm, .btn-group-sm > .btn { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.btn-block { + display: block; + width: 100%; +} + +.btn-block + .btn-block { + margin-top: 0.5rem; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.fade { + transition: opacity 0.15s linear; +} + +@media screen and (prefers-reduced-motion: reduce) { + .fade { + transition: none; + } +} + +.fade:not(.show) { + opacity: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + position: relative; + height: 0; + overflow: hidden; + transition: height 0.35s ease; +} + +@media screen and (prefers-reduced-motion: reduce) { + .collapsing { + transition: none; + } +} + +.dropup, +.dropright, +.dropdown, +.dropleft { + position: relative; +} + +.dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid; + border-right: 0.3em solid transparent; + border-bottom: 0; + border-left: 0.3em solid transparent; +} + +.dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 10rem; + padding: 0.5rem 0; + margin: 0.125rem 0 0; + font-size: 1rem; + color: #212529; + text-align: left; + list-style: none; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 0.25rem; +} + +.dropdown-menu-right { + right: 0; + left: auto; +} + +@media (min-width: 576px) { + .dropdown-menu-sm-right { + right: 0; + left: auto; + } +} + +@media (min-width: 768px) { + .dropdown-menu-md-right { + right: 0; + left: auto; + } +} + +@media (min-width: 992px) { + .dropdown-menu-lg-right { + right: 0; + left: auto; + } +} + +@media (min-width: 1200px) { + .dropdown-menu-xl-right { + right: 0; + left: auto; + } +} + +.dropdown-menu-left { + right: auto; + left: 0; +} + +@media (min-width: 576px) { + .dropdown-menu-sm-left { + right: auto; + left: 0; + } +} + +@media (min-width: 768px) { + .dropdown-menu-md-left { + right: auto; + left: 0; + } +} + +@media (min-width: 992px) { + .dropdown-menu-lg-left { + right: auto; + left: 0; + } +} + +@media (min-width: 1200px) { + .dropdown-menu-xl-left { + right: auto; + left: 0; + } +} + +.dropup .dropdown-menu { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: 0.125rem; +} + +.dropup .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0; + border-right: 0.3em solid transparent; + border-bottom: 0.3em solid; + border-left: 0.3em solid transparent; +} + +.dropup .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropright .dropdown-menu { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: 0.125rem; +} + +.dropright .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0; + border-bottom: 0.3em solid transparent; + border-left: 0.3em solid; +} + +.dropright .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropright .dropdown-toggle::after { + vertical-align: 0; +} + +.dropleft .dropdown-menu { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: 0.125rem; +} + +.dropleft .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; +} + +.dropleft .dropdown-toggle::after { + display: none; +} + +.dropleft .dropdown-toggle::before { + display: inline-block; + margin-right: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0.3em solid; + border-bottom: 0.3em solid transparent; +} + +.dropleft .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropleft .dropdown-toggle::before { + vertical-align: 0; +} + +.dropdown-menu[x-placement^="top"], .dropdown-menu[x-placement^="right"], .dropdown-menu[x-placement^="bottom"], .dropdown-menu[x-placement^="left"] { + right: auto; + bottom: auto; +} + +.dropdown-divider { + height: 0; + margin: 0.5rem 0; + overflow: hidden; + border-top: 1px solid #e9ecef; +} + +.dropdown-item { + display: block; + width: 100%; + padding: 0.25rem 1.5rem; + clear: both; + font-weight: 400; + color: #212529; + text-align: inherit; + white-space: nowrap; + background-color: transparent; + border: 0; +} + +.dropdown-item:first-child { + border-top-left-radius: calc(0.25rem - 1px); + border-top-right-radius: calc(0.25rem - 1px); +} + +.dropdown-item:last-child { + border-bottom-right-radius: calc(0.25rem - 1px); + border-bottom-left-radius: calc(0.25rem - 1px); +} + +.dropdown-item:hover, .dropdown-item:focus { + color: #16181b; + text-decoration: none; + background-color: #f8f9fa; +} + +.dropdown-item.active, .dropdown-item:active { + color: #fff; + text-decoration: none; + background-color: #007bff; +} + +.dropdown-item.disabled, .dropdown-item:disabled { + color: #6c757d; + pointer-events: none; + background-color: transparent; +} + +.dropdown-menu.show { + display: block; +} + +.dropdown-header { + display: block; + padding: 0.5rem 1.5rem; + margin-bottom: 0; + font-size: 0.875rem; + color: #6c757d; + white-space: nowrap; +} + +.dropdown-item-text { + display: block; + padding: 0.25rem 1.5rem; + color: #212529; +} + +.btn-group, +.btn-group-vertical { + position: relative; + display: -ms-inline-flexbox; + display: inline-flex; + vertical-align: middle; +} + +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + -ms-flex: 1 1 auto; + flex: 1 1 auto; +} + +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover { + z-index: 1; +} + +.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active, +.btn-group-vertical > .btn:focus, +.btn-group-vertical > .btn:active, +.btn-group-vertical > .btn.active { + z-index: 1; +} + +.btn-toolbar { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.btn-toolbar .input-group { + width: auto; +} + +.btn-group > .btn:not(:first-child), +.btn-group > .btn-group:not(:first-child) { + margin-left: -1px; +} + +.btn-group > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.btn-group > .btn:not(:first-child), +.btn-group > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.dropdown-toggle-split { + padding-right: 0.5625rem; + padding-left: 0.5625rem; +} + +.dropdown-toggle-split::after, +.dropup .dropdown-toggle-split::after, +.dropright .dropdown-toggle-split::after { + margin-left: 0; +} + +.dropleft .dropdown-toggle-split::before { + margin-right: 0; +} + +.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { + padding-right: 0.375rem; + padding-left: 0.375rem; +} + +.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { + padding-right: 0.75rem; + padding-left: 0.75rem; +} + +.btn-group-vertical { + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-align: start; + align-items: flex-start; + -ms-flex-pack: center; + justify-content: center; +} + +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group { + width: 100%; +} + +.btn-group-vertical > .btn:not(:first-child), +.btn-group-vertical > .btn-group:not(:first-child) { + margin-top: -1px; +} + +.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group-vertical > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.btn-group-vertical > .btn:not(:first-child), +.btn-group-vertical > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.btn-group-toggle > .btn, +.btn-group-toggle > .btn-group > .btn { + margin-bottom: 0; +} + +.btn-group-toggle > .btn input[type="radio"], +.btn-group-toggle > .btn input[type="checkbox"], +.btn-group-toggle > .btn-group > .btn input[type="radio"], +.btn-group-toggle > .btn-group > .btn input[type="checkbox"] { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} + +.input-group { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-align: stretch; + align-items: stretch; + width: 100%; +} + +.input-group > .form-control, +.input-group > .form-control-plaintext, +.input-group > .custom-select, +.input-group > .custom-file { + position: relative; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + width: 1%; + margin-bottom: 0; +} + +.input-group > .form-control + .form-control, +.input-group > .form-control + .custom-select, +.input-group > .form-control + .custom-file, +.input-group > .form-control-plaintext + .form-control, +.input-group > .form-control-plaintext + .custom-select, +.input-group > .form-control-plaintext + .custom-file, +.input-group > .custom-select + .form-control, +.input-group > .custom-select + .custom-select, +.input-group > .custom-select + .custom-file, +.input-group > .custom-file + .form-control, +.input-group > .custom-file + .custom-select, +.input-group > .custom-file + .custom-file { + margin-left: -1px; +} + +.input-group > .form-control:focus, +.input-group > .custom-select:focus, +.input-group > .custom-file .custom-file-input:focus ~ .custom-file-label { + z-index: 3; +} + +.input-group > .custom-file .custom-file-input:focus { + z-index: 4; +} + +.input-group > .form-control:not(:last-child), +.input-group > .custom-select:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group > .form-control:not(:first-child), +.input-group > .custom-select:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.input-group > .custom-file { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; +} + +.input-group > .custom-file:not(:last-child) .custom-file-label, +.input-group > .custom-file:not(:last-child) .custom-file-label::after { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group > .custom-file:not(:first-child) .custom-file-label { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.input-group-prepend, +.input-group-append { + display: -ms-flexbox; + display: flex; +} + +.input-group-prepend .btn, +.input-group-append .btn { + position: relative; + z-index: 2; +} + +.input-group-prepend .btn:focus, +.input-group-append .btn:focus { + z-index: 3; +} + +.input-group-prepend .btn + .btn, +.input-group-prepend .btn + .input-group-text, +.input-group-prepend .input-group-text + .input-group-text, +.input-group-prepend .input-group-text + .btn, +.input-group-append .btn + .btn, +.input-group-append .btn + .input-group-text, +.input-group-append .input-group-text + .input-group-text, +.input-group-append .input-group-text + .btn { + margin-left: -1px; +} + +.input-group-prepend { + margin-right: -1px; +} + +.input-group-append { + margin-left: -1px; +} + +.input-group-text { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + padding: 0.375rem 0.75rem; + margin-bottom: 0; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + text-align: center; + white-space: nowrap; + background-color: #e9ecef; + border: 1px solid #ced4da; + border-radius: 0.25rem; +} + +.input-group-text input[type="radio"], +.input-group-text input[type="checkbox"] { + margin-top: 0; +} + +.input-group-lg > .form-control:not(textarea), +.input-group-lg > .custom-select { + height: calc(2.875rem + 2px); +} + +.input-group-lg > .form-control, +.input-group-lg > .custom-select, +.input-group-lg > .input-group-prepend > .input-group-text, +.input-group-lg > .input-group-append > .input-group-text, +.input-group-lg > .input-group-prepend > .btn, +.input-group-lg > .input-group-append > .btn { + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +.input-group-sm > .form-control:not(textarea), +.input-group-sm > .custom-select { + height: calc(1.8125rem + 2px); +} + +.input-group-sm > .form-control, +.input-group-sm > .custom-select, +.input-group-sm > .input-group-prepend > .input-group-text, +.input-group-sm > .input-group-append > .input-group-text, +.input-group-sm > .input-group-prepend > .btn, +.input-group-sm > .input-group-append > .btn { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.input-group-lg > .custom-select, +.input-group-sm > .custom-select { + padding-right: 1.75rem; +} + +.input-group > .input-group-prepend > .btn, +.input-group > .input-group-prepend > .input-group-text, +.input-group > .input-group-append:not(:last-child) > .btn, +.input-group > .input-group-append:not(:last-child) > .input-group-text, +.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group > .input-group-append > .btn, +.input-group > .input-group-append > .input-group-text, +.input-group > .input-group-prepend:not(:first-child) > .btn, +.input-group > .input-group-prepend:not(:first-child) > .input-group-text, +.input-group > .input-group-prepend:first-child > .btn:not(:first-child), +.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.custom-control { + position: relative; + display: block; + min-height: 1.5rem; + padding-left: 1.5rem; +} + +.custom-control-inline { + display: -ms-inline-flexbox; + display: inline-flex; + margin-right: 1rem; +} + +.custom-control-input { + position: absolute; + z-index: -1; + opacity: 0; +} + +.custom-control-input:checked ~ .custom-control-label::before { + color: #fff; + border-color: #007bff; + background-color: #007bff; +} + +.custom-control-input:focus ~ .custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-control-input:focus:not(:checked) ~ .custom-control-label::before { + border-color: #80bdff; +} + +.custom-control-input:not(:disabled):active ~ .custom-control-label::before { + color: #fff; + background-color: #b3d7ff; + border-color: #b3d7ff; +} + +.custom-control-input:disabled ~ .custom-control-label { + color: #6c757d; +} + +.custom-control-input:disabled ~ .custom-control-label::before { + background-color: #e9ecef; +} + +.custom-control-label { + position: relative; + margin-bottom: 0; + vertical-align: top; +} + +.custom-control-label::before { + position: absolute; + top: 0.25rem; + left: -1.5rem; + display: block; + width: 1rem; + height: 1rem; + pointer-events: none; + content: ""; + background-color: #fff; + border: #adb5bd solid 1px; +} + +.custom-control-label::after { + position: absolute; + top: 0.25rem; + left: -1.5rem; + display: block; + width: 1rem; + height: 1rem; + content: ""; + background-repeat: no-repeat; + background-position: center center; + background-size: 50% 50%; +} + +.custom-checkbox .custom-control-label::before { + border-radius: 0.25rem; +} + +.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e"); +} + +.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before { + border-color: #007bff; + background-color: #007bff; +} + +.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e"); +} + +.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-radio .custom-control-label::before { + border-radius: 50%; +} + +.custom-radio .custom-control-input:checked ~ .custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e"); +} + +.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-switch { + padding-left: 2.25rem; +} + +.custom-switch .custom-control-label::before { + left: -2.25rem; + width: 1.75rem; + pointer-events: all; + border-radius: 0.5rem; +} + +.custom-switch .custom-control-label::after { + top: calc(0.25rem + 2px); + left: calc(-2.25rem + 2px); + width: calc(1rem - 4px); + height: calc(1rem - 4px); + background-color: #adb5bd; + border-radius: 0.5rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out; + transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out; +} + +@media screen and (prefers-reduced-motion: reduce) { + .custom-switch .custom-control-label::after { + transition: none; + } +} + +.custom-switch .custom-control-input:checked ~ .custom-control-label::after { + background-color: #fff; + -webkit-transform: translateX(0.75rem); + transform: translateX(0.75rem); +} + +.custom-switch .custom-control-input:disabled:checked ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-select { + display: inline-block; + width: 100%; + height: calc(2.25rem + 2px); + padding: 0.375rem 1.75rem 0.375rem 0.75rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + vertical-align: middle; + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px; + background-color: #fff; + border: 1px solid #ced4da; + border-radius: 0.25rem; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.custom-select:focus { + border-color: #80bdff; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(128, 189, 255, 0.5); +} + +.custom-select:focus::-ms-value { + color: #495057; + background-color: #fff; +} + +.custom-select[multiple], .custom-select[size]:not([size="1"]) { + height: auto; + padding-right: 0.75rem; + background-image: none; +} + +.custom-select:disabled { + color: #6c757d; + background-color: #e9ecef; +} + +.custom-select::-ms-expand { + opacity: 0; +} + +.custom-select-sm { + height: calc(1.8125rem + 2px); + padding-top: 0.25rem; + padding-bottom: 0.25rem; + padding-left: 0.5rem; + font-size: 0.875rem; +} + +.custom-select-lg { + height: calc(2.875rem + 2px); + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 1rem; + font-size: 1.25rem; +} + +.custom-file { + position: relative; + display: inline-block; + width: 100%; + height: calc(2.25rem + 2px); + margin-bottom: 0; +} + +.custom-file-input { + position: relative; + z-index: 2; + width: 100%; + height: calc(2.25rem + 2px); + margin: 0; + opacity: 0; +} + +.custom-file-input:focus ~ .custom-file-label { + border-color: #80bdff; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-file-input:disabled ~ .custom-file-label { + background-color: #e9ecef; +} + +.custom-file-input:lang(en) ~ .custom-file-label::after { + content: "Browse"; +} + +.custom-file-input ~ .custom-file-label[data-browse]::after { + content: attr(data-browse); +} + +.custom-file-label { + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 1; + height: calc(2.25rem + 2px); + padding: 0.375rem 0.75rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + border: 1px solid #ced4da; + border-radius: 0.25rem; +} + +.custom-file-label::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + z-index: 3; + display: block; + height: 2.25rem; + padding: 0.375rem 0.75rem; + line-height: 1.5; + color: #495057; + content: "Browse"; + background-color: #e9ecef; + border-left: inherit; + border-radius: 0 0.25rem 0.25rem 0; +} + +.custom-range { + width: 100%; + height: calc(1rem + 0.4rem); + padding: 0; + background-color: transparent; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.custom-range:focus { + outline: none; +} + +.custom-range:focus::-webkit-slider-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range:focus::-moz-range-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range:focus::-ms-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range::-moz-focus-outer { + border: 0; +} + +.custom-range::-webkit-slider-thumb { + width: 1rem; + height: 1rem; + margin-top: -0.25rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + -webkit-appearance: none; + appearance: none; +} + +@media screen and (prefers-reduced-motion: reduce) { + .custom-range::-webkit-slider-thumb { + transition: none; + } +} + +.custom-range::-webkit-slider-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-webkit-slider-runnable-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.custom-range::-moz-range-thumb { + width: 1rem; + height: 1rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + -moz-appearance: none; + appearance: none; +} + +@media screen and (prefers-reduced-motion: reduce) { + .custom-range::-moz-range-thumb { + transition: none; + } +} + +.custom-range::-moz-range-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-moz-range-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.custom-range::-ms-thumb { + width: 1rem; + height: 1rem; + margin-top: 0; + margin-right: 0.2rem; + margin-left: 0.2rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} + +@media screen and (prefers-reduced-motion: reduce) { + .custom-range::-ms-thumb { + transition: none; + } +} + +.custom-range::-ms-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-ms-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: transparent; + border-color: transparent; + border-width: 0.5rem; +} + +.custom-range::-ms-fill-lower { + background-color: #dee2e6; + border-radius: 1rem; +} + +.custom-range::-ms-fill-upper { + margin-right: 15px; + background-color: #dee2e6; + border-radius: 1rem; +} + +.custom-range:disabled::-webkit-slider-thumb { + background-color: #adb5bd; +} + +.custom-range:disabled::-webkit-slider-runnable-track { + cursor: default; +} + +.custom-range:disabled::-moz-range-thumb { + background-color: #adb5bd; +} + +.custom-range:disabled::-moz-range-track { + cursor: default; +} + +.custom-range:disabled::-ms-thumb { + background-color: #adb5bd; +} + +.custom-control-label::before, +.custom-file-label, +.custom-select { + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media screen and (prefers-reduced-motion: reduce) { + .custom-control-label::before, + .custom-file-label, + .custom-select { + transition: none; + } +} + +.nav { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: 0.5rem 1rem; +} + +.nav-link:hover, .nav-link:focus { + text-decoration: none; +} + +.nav-link.disabled { + color: #6c757d; + pointer-events: none; + cursor: default; +} + +.nav-tabs { + border-bottom: 1px solid #dee2e6; +} + +.nav-tabs .nav-item { + margin-bottom: -1px; +} + +.nav-tabs .nav-link { + border: 1px solid transparent; + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { + border-color: #e9ecef #e9ecef #dee2e6; +} + +.nav-tabs .nav-link.disabled { + color: #6c757d; + background-color: transparent; + border-color: transparent; +} + +.nav-tabs .nav-link.active, +.nav-tabs .nav-item.show .nav-link { + color: #495057; + background-color: #fff; + border-color: #dee2e6 #dee2e6 #fff; +} + +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav-pills .nav-link { + border-radius: 0.25rem; +} + +.nav-pills .nav-link.active, +.nav-pills .show > .nav-link { + color: #fff; + background-color: #007bff; +} + +.nav-fill .nav-item { + -ms-flex: 1 1 auto; + flex: 1 1 auto; + text-align: center; +} + +.nav-justified .nav-item { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + text-align: center; +} + +.tab-content > .tab-pane { + display: none; +} + +.tab-content > .active { + display: block; +} + +.navbar { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 0.5rem 1rem; +} + +.navbar > .container, +.navbar > .container-fluid { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.navbar-brand { + display: inline-block; + padding-top: 0.3125rem; + padding-bottom: 0.3125rem; + margin-right: 1rem; + font-size: 1.25rem; + line-height: inherit; + white-space: nowrap; +} + +.navbar-brand:hover, .navbar-brand:focus { + text-decoration: none; +} + +.navbar-nav { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.navbar-nav .nav-link { + padding-right: 0; + padding-left: 0; +} + +.navbar-nav .dropdown-menu { + position: static; + float: none; +} + +.navbar-text { + display: inline-block; + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.navbar-collapse { + -ms-flex-preferred-size: 100%; + flex-basis: 100%; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-align: center; + align-items: center; +} + +.navbar-toggler { + padding: 0.25rem 0.75rem; + font-size: 1.25rem; + line-height: 1; + background-color: transparent; + border: 1px solid transparent; + border-radius: 0.25rem; +} + +.navbar-toggler:hover, .navbar-toggler:focus { + text-decoration: none; +} + +.navbar-toggler:not(:disabled):not(.disabled) { + cursor: pointer; +} + +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + content: ""; + background: no-repeat center center; + background-size: 100% 100%; +} + +@media (max-width: 575.98px) { + .navbar-expand-sm > .container, + .navbar-expand-sm > .container-fluid { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 576px) { + .navbar-expand-sm { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-sm .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-sm .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-sm > .container, + .navbar-expand-sm > .container-fluid { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-sm .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-sm .navbar-toggler { + display: none; + } +} + +@media (max-width: 767.98px) { + .navbar-expand-md > .container, + .navbar-expand-md > .container-fluid { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 768px) { + .navbar-expand-md { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-md .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-md .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-md > .container, + .navbar-expand-md > .container-fluid { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-md .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-md .navbar-toggler { + display: none; + } +} + +@media (max-width: 991.98px) { + .navbar-expand-lg > .container, + .navbar-expand-lg > .container-fluid { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 992px) { + .navbar-expand-lg { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-lg .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-lg .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-lg > .container, + .navbar-expand-lg > .container-fluid { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-lg .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-lg .navbar-toggler { + display: none; + } +} + +@media (max-width: 1199.98px) { + .navbar-expand-xl > .container, + .navbar-expand-xl > .container-fluid { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 1200px) { + .navbar-expand-xl { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-xl .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xl .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-xl > .container, + .navbar-expand-xl > .container-fluid { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-xl .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-xl .navbar-toggler { + display: none; + } +} + +.navbar-expand { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.navbar-expand > .container, +.navbar-expand > .container-fluid { + padding-right: 0; + padding-left: 0; +} + +.navbar-expand .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; +} + +.navbar-expand .navbar-nav .dropdown-menu { + position: absolute; +} + +.navbar-expand .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; +} + +.navbar-expand > .container, +.navbar-expand > .container-fluid { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; +} + +.navbar-expand .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; +} + +.navbar-expand .navbar-toggler { + display: none; +} + +.navbar-light .navbar-brand { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-nav .nav-link { + color: rgba(0, 0, 0, 0.5); +} + +.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus { + color: rgba(0, 0, 0, 0.7); +} + +.navbar-light .navbar-nav .nav-link.disabled { + color: rgba(0, 0, 0, 0.3); +} + +.navbar-light .navbar-nav .show > .nav-link, +.navbar-light .navbar-nav .active > .nav-link, +.navbar-light .navbar-nav .nav-link.show, +.navbar-light .navbar-nav .nav-link.active { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-toggler { + color: rgba(0, 0, 0, 0.5); + border-color: rgba(0, 0, 0, 0.1); +} + +.navbar-light .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-light .navbar-text { + color: rgba(0, 0, 0, 0.5); +} + +.navbar-light .navbar-text a { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-dark .navbar-brand { + color: #fff; +} + +.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus { + color: #fff; +} + +.navbar-dark .navbar-nav .nav-link { + color: rgba(255, 255, 255, 0.5); +} + +.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus { + color: rgba(255, 255, 255, 0.75); +} + +.navbar-dark .navbar-nav .nav-link.disabled { + color: rgba(255, 255, 255, 0.25); +} + +.navbar-dark .navbar-nav .show > .nav-link, +.navbar-dark .navbar-nav .active > .nav-link, +.navbar-dark .navbar-nav .nav-link.show, +.navbar-dark .navbar-nav .nav-link.active { + color: #fff; +} + +.navbar-dark .navbar-toggler { + color: rgba(255, 255, 255, 0.5); + border-color: rgba(255, 255, 255, 0.1); +} + +.navbar-dark .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-dark .navbar-text { + color: rgba(255, 255, 255, 0.5); +} + +.navbar-dark .navbar-text a { + color: #fff; +} + +.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus { + color: #fff; +} + +.card { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + min-width: 0; + word-wrap: break-word; + background-color: #fff; + background-clip: border-box; + border: 1px solid rgba(0, 0, 0, 0.125); + border-radius: 0.25rem; +} + +.card > hr { + margin-right: 0; + margin-left: 0; +} + +.card > .list-group:first-child .list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card > .list-group:last-child .list-group-item:last-child { + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.card-body { + -ms-flex: 1 1 auto; + flex: 1 1 auto; + padding: 1.25rem; +} + +.card-title { + margin-bottom: 0.75rem; +} + +.card-subtitle { + margin-top: -0.375rem; + margin-bottom: 0; +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link:hover { + text-decoration: none; +} + +.card-link + .card-link { + margin-left: 1.25rem; +} + +.card-header { + padding: 0.75rem 1.25rem; + margin-bottom: 0; + color: inherit; + background-color: rgba(0, 0, 0, 0.03); + border-bottom: 1px solid rgba(0, 0, 0, 0.125); +} + +.card-header:first-child { + border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0; +} + +.card-header + .list-group .list-group-item:first-child { + border-top: 0; +} + +.card-footer { + padding: 0.75rem 1.25rem; + background-color: rgba(0, 0, 0, 0.03); + border-top: 1px solid rgba(0, 0, 0, 0.125); +} + +.card-footer:last-child { + border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px); +} + +.card-header-tabs { + margin-right: -0.625rem; + margin-bottom: -0.75rem; + margin-left: -0.625rem; + border-bottom: 0; +} + +.card-header-pills { + margin-right: -0.625rem; + margin-left: -0.625rem; +} + +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: 1.25rem; +} + +.card-img { + width: 100%; + border-radius: calc(0.25rem - 1px); +} + +.card-img-top { + width: 100%; + border-top-left-radius: calc(0.25rem - 1px); + border-top-right-radius: calc(0.25rem - 1px); +} + +.card-img-bottom { + width: 100%; + border-bottom-right-radius: calc(0.25rem - 1px); + border-bottom-left-radius: calc(0.25rem - 1px); +} + +.card-deck { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; +} + +.card-deck .card { + margin-bottom: 15px; +} + +@media (min-width: 576px) { + .card-deck { + -ms-flex-flow: row wrap; + flex-flow: row wrap; + margin-right: -15px; + margin-left: -15px; + } + .card-deck .card { + display: -ms-flexbox; + display: flex; + -ms-flex: 1 0 0%; + flex: 1 0 0%; + -ms-flex-direction: column; + flex-direction: column; + margin-right: 15px; + margin-bottom: 0; + margin-left: 15px; + } +} + +.card-group { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; +} + +.card-group > .card { + margin-bottom: 15px; +} + +@media (min-width: 576px) { + .card-group { + -ms-flex-flow: row wrap; + flex-flow: row wrap; + } + .card-group > .card { + -ms-flex: 1 0 0%; + flex: 1 0 0%; + margin-bottom: 0; + } + .card-group > .card + .card { + margin-left: 0; + border-left: 0; + } + .card-group > .card:first-child { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + .card-group > .card:first-child .card-img-top, + .card-group > .card:first-child .card-header { + border-top-right-radius: 0; + } + .card-group > .card:first-child .card-img-bottom, + .card-group > .card:first-child .card-footer { + border-bottom-right-radius: 0; + } + .card-group > .card:last-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + .card-group > .card:last-child .card-img-top, + .card-group > .card:last-child .card-header { + border-top-left-radius: 0; + } + .card-group > .card:last-child .card-img-bottom, + .card-group > .card:last-child .card-footer { + border-bottom-left-radius: 0; + } + .card-group > .card:only-child { + border-radius: 0.25rem; + } + .card-group > .card:only-child .card-img-top, + .card-group > .card:only-child .card-header { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; + } + .card-group > .card:only-child .card-img-bottom, + .card-group > .card:only-child .card-footer { + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + } + .card-group > .card:not(:first-child):not(:last-child):not(:only-child) { + border-radius: 0; + } + .card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-img-top, + .card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom, + .card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-header, + .card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-footer { + border-radius: 0; + } +} + +.card-columns .card { + margin-bottom: 0.75rem; +} + +@media (min-width: 576px) { + .card-columns { + -webkit-column-count: 3; + -moz-column-count: 3; + column-count: 3; + -webkit-column-gap: 1.25rem; + -moz-column-gap: 1.25rem; + column-gap: 1.25rem; + orphans: 1; + widows: 1; + } + .card-columns .card { + display: inline-block; + width: 100%; + } +} + +.accordion .card { + overflow: hidden; +} + +.accordion .card:not(:first-of-type) .card-header:first-child { + border-radius: 0; +} + +.accordion .card:not(:first-of-type):not(:last-of-type) { + border-bottom: 0; + border-radius: 0; +} + +.accordion .card:first-of-type { + border-bottom: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.accordion .card:last-of-type { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.accordion .card .card-header { + margin-bottom: -1px; +} + +.breadcrumb { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + padding: 0.75rem 1rem; + margin-bottom: 1rem; + list-style: none; + background-color: #e9ecef; + border-radius: 0.25rem; +} + +.breadcrumb-item + .breadcrumb-item { + padding-left: 0.5rem; +} + +.breadcrumb-item + .breadcrumb-item::before { + display: inline-block; + padding-right: 0.5rem; + color: #6c757d; + content: "/"; +} + +.breadcrumb-item + .breadcrumb-item:hover::before { + text-decoration: underline; +} + +.breadcrumb-item + .breadcrumb-item:hover::before { + text-decoration: none; +} + +.breadcrumb-item.active { + color: #6c757d; +} + +.pagination { + display: -ms-flexbox; + display: flex; + padding-left: 0; + list-style: none; + border-radius: 0.25rem; +} + +.page-link { + position: relative; + display: block; + padding: 0.5rem 0.75rem; + margin-left: -1px; + line-height: 1.25; + color: #007bff; + background-color: #fff; + border: 1px solid #dee2e6; +} + +.page-link:hover { + z-index: 2; + color: #0056b3; + text-decoration: none; + background-color: #e9ecef; + border-color: #dee2e6; +} + +.page-link:focus { + z-index: 2; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.page-link:not(:disabled):not(.disabled) { + cursor: pointer; +} + +.page-item:first-child .page-link { + margin-left: 0; + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.page-item:last-child .page-link { + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + +.page-item.active .page-link { + z-index: 1; + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.page-item.disabled .page-link { + color: #6c757d; + pointer-events: none; + cursor: auto; + background-color: #fff; + border-color: #dee2e6; +} + +.pagination-lg .page-link { + padding: 0.75rem 1.5rem; + font-size: 1.25rem; + line-height: 1.5; +} + +.pagination-lg .page-item:first-child .page-link { + border-top-left-radius: 0.3rem; + border-bottom-left-radius: 0.3rem; +} + +.pagination-lg .page-item:last-child .page-link { + border-top-right-radius: 0.3rem; + border-bottom-right-radius: 0.3rem; +} + +.pagination-sm .page-link { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; +} + +.pagination-sm .page-item:first-child .page-link { + border-top-left-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; +} + +.pagination-sm .page-item:last-child .page-link { + border-top-right-radius: 0.2rem; + border-bottom-right-radius: 0.2rem; +} + +.badge { + display: inline-block; + padding: 0.25em 0.4em; + font-size: 75%; + font-weight: 700; + line-height: 1; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: 0.25rem; +} + +a.badge:hover, a.badge:focus { + text-decoration: none; +} + +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +.badge-pill { + padding-right: 0.6em; + padding-left: 0.6em; + border-radius: 10rem; +} + +.badge-primary { + color: #fff; + background-color: #007bff; +} + +a.badge-primary:hover, a.badge-primary:focus { + color: #fff; + background-color: #0062cc; +} + +.badge-secondary { + color: #fff; + background-color: #6c757d; +} + +a.badge-secondary:hover, a.badge-secondary:focus { + color: #fff; + background-color: #545b62; +} + +.badge-success { + color: #fff; + background-color: #28a745; +} + +a.badge-success:hover, a.badge-success:focus { + color: #fff; + background-color: #1e7e34; +} + +.badge-info { + color: #fff; + background-color: #17a2b8; +} + +a.badge-info:hover, a.badge-info:focus { + color: #fff; + background-color: #117a8b; +} + +.badge-warning { + color: #212529; + background-color: #ffc107; +} + +a.badge-warning:hover, a.badge-warning:focus { + color: #212529; + background-color: #d39e00; +} + +.badge-danger { + color: #fff; + background-color: #dc3545; +} + +a.badge-danger:hover, a.badge-danger:focus { + color: #fff; + background-color: #bd2130; +} + +.badge-light { + color: #212529; + background-color: #f8f9fa; +} + +a.badge-light:hover, a.badge-light:focus { + color: #212529; + background-color: #dae0e5; +} + +.badge-dark { + color: #fff; + background-color: #343a40; +} + +a.badge-dark:hover, a.badge-dark:focus { + color: #fff; + background-color: #1d2124; +} + +.jumbotron { + padding: 2rem 1rem; + margin-bottom: 2rem; + background-color: #e9ecef; + border-radius: 0.3rem; +} + +@media (min-width: 576px) { + .jumbotron { + padding: 4rem 2rem; + } +} + +.jumbotron-fluid { + padding-right: 0; + padding-left: 0; + border-radius: 0; +} + +.alert { + position: relative; + padding: 0.75rem 1.25rem; + margin-bottom: 1rem; + border: 1px solid transparent; + border-radius: 0.25rem; +} + +.alert-heading { + color: inherit; +} + +.alert-link { + font-weight: 700; +} + +.alert-dismissible { + padding-right: 4rem; +} + +.alert-dismissible .close { + position: absolute; + top: 0; + right: 0; + padding: 0.75rem 1.25rem; + color: inherit; +} + +.alert-primary { + color: #004085; + background-color: #cce5ff; + border-color: #b8daff; +} + +.alert-primary hr { + border-top-color: #9fcdff; +} + +.alert-primary .alert-link { + color: #002752; +} + +.alert-secondary { + color: #383d41; + background-color: #e2e3e5; + border-color: #d6d8db; +} + +.alert-secondary hr { + border-top-color: #c8cbcf; +} + +.alert-secondary .alert-link { + color: #202326; +} + +.alert-success { + color: #155724; + background-color: #d4edda; + border-color: #c3e6cb; +} + +.alert-success hr { + border-top-color: #b1dfbb; +} + +.alert-success .alert-link { + color: #0b2e13; +} + +.alert-info { + color: #0c5460; + background-color: #d1ecf1; + border-color: #bee5eb; +} + +.alert-info hr { + border-top-color: #abdde5; +} + +.alert-info .alert-link { + color: #062c33; +} + +.alert-warning { + color: #856404; + background-color: #fff3cd; + border-color: #ffeeba; +} + +.alert-warning hr { + border-top-color: #ffe8a1; +} + +.alert-warning .alert-link { + color: #533f03; +} + +.alert-danger { + color: #721c24; + background-color: #f8d7da; + border-color: #f5c6cb; +} + +.alert-danger hr { + border-top-color: #f1b0b7; +} + +.alert-danger .alert-link { + color: #491217; +} + +.alert-light { + color: #818182; + background-color: #fefefe; + border-color: #fdfdfe; +} + +.alert-light hr { + border-top-color: #ececf6; +} + +.alert-light .alert-link { + color: #686868; +} + +.alert-dark { + color: #1b1e21; + background-color: #d6d8d9; + border-color: #c6c8ca; +} + +.alert-dark hr { + border-top-color: #b9bbbe; +} + +.alert-dark .alert-link { + color: #040505; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 1rem 0; + } + to { + background-position: 0 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 1rem 0; + } + to { + background-position: 0 0; + } +} + +.progress { + display: -ms-flexbox; + display: flex; + height: 1rem; + overflow: hidden; + font-size: 0.75rem; + background-color: #e9ecef; + border-radius: 0.25rem; +} + +.progress-bar { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-pack: center; + justify-content: center; + color: #fff; + text-align: center; + white-space: nowrap; + background-color: #007bff; + transition: width 0.6s ease; +} + +@media screen and (prefers-reduced-motion: reduce) { + .progress-bar { + transition: none; + } +} + +.progress-bar-striped { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 1rem 1rem; +} + +.progress-bar-animated { + -webkit-animation: progress-bar-stripes 1s linear infinite; + animation: progress-bar-stripes 1s linear infinite; +} + +.media { + display: -ms-flexbox; + display: flex; + -ms-flex-align: start; + align-items: flex-start; +} + +.media-body { + -ms-flex: 1; + flex: 1; +} + +.list-group { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; +} + +.list-group-item-action { + width: 100%; + color: #495057; + text-align: inherit; +} + +.list-group-item-action:hover, .list-group-item-action:focus { + color: #495057; + text-decoration: none; + background-color: #f8f9fa; +} + +.list-group-item-action:active { + color: #212529; + background-color: #e9ecef; +} + +.list-group-item { + position: relative; + display: block; + padding: 0.75rem 1.25rem; + margin-bottom: -1px; + background-color: #fff; + border: 1px solid rgba(0, 0, 0, 0.125); +} + +.list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.list-group-item:hover, .list-group-item:focus { + z-index: 1; + text-decoration: none; +} + +.list-group-item.disabled, .list-group-item:disabled { + color: #6c757d; + pointer-events: none; + background-color: #fff; +} + +.list-group-item.active { + z-index: 2; + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.list-group-flush .list-group-item { + border-right: 0; + border-left: 0; + border-radius: 0; +} + +.list-group-flush .list-group-item:last-child { + margin-bottom: -1px; +} + +.list-group-flush:first-child .list-group-item:first-child { + border-top: 0; +} + +.list-group-flush:last-child .list-group-item:last-child { + margin-bottom: 0; + border-bottom: 0; +} + +.list-group-item-primary { + color: #004085; + background-color: #b8daff; +} + +.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus { + color: #004085; + background-color: #9fcdff; +} + +.list-group-item-primary.list-group-item-action.active { + color: #fff; + background-color: #004085; + border-color: #004085; +} + +.list-group-item-secondary { + color: #383d41; + background-color: #d6d8db; +} + +.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus { + color: #383d41; + background-color: #c8cbcf; +} + +.list-group-item-secondary.list-group-item-action.active { + color: #fff; + background-color: #383d41; + border-color: #383d41; +} + +.list-group-item-success { + color: #155724; + background-color: #c3e6cb; +} + +.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus { + color: #155724; + background-color: #b1dfbb; +} + +.list-group-item-success.list-group-item-action.active { + color: #fff; + background-color: #155724; + border-color: #155724; +} + +.list-group-item-info { + color: #0c5460; + background-color: #bee5eb; +} + +.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus { + color: #0c5460; + background-color: #abdde5; +} + +.list-group-item-info.list-group-item-action.active { + color: #fff; + background-color: #0c5460; + border-color: #0c5460; +} + +.list-group-item-warning { + color: #856404; + background-color: #ffeeba; +} + +.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus { + color: #856404; + background-color: #ffe8a1; +} + +.list-group-item-warning.list-group-item-action.active { + color: #fff; + background-color: #856404; + border-color: #856404; +} + +.list-group-item-danger { + color: #721c24; + background-color: #f5c6cb; +} + +.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus { + color: #721c24; + background-color: #f1b0b7; +} + +.list-group-item-danger.list-group-item-action.active { + color: #fff; + background-color: #721c24; + border-color: #721c24; +} + +.list-group-item-light { + color: #818182; + background-color: #fdfdfe; +} + +.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus { + color: #818182; + background-color: #ececf6; +} + +.list-group-item-light.list-group-item-action.active { + color: #fff; + background-color: #818182; + border-color: #818182; +} + +.list-group-item-dark { + color: #1b1e21; + background-color: #c6c8ca; +} + +.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus { + color: #1b1e21; + background-color: #b9bbbe; +} + +.list-group-item-dark.list-group-item-action.active { + color: #fff; + background-color: #1b1e21; + border-color: #1b1e21; +} + +.close { + float: right; + font-size: 1.5rem; + font-weight: 700; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; + opacity: .5; +} + +.close:hover { + color: #000; + text-decoration: none; +} + +.close:not(:disabled):not(.disabled) { + cursor: pointer; +} + +.close:not(:disabled):not(.disabled):hover, .close:not(:disabled):not(.disabled):focus { + opacity: .75; +} + +button.close { + padding: 0; + background-color: transparent; + border: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +a.close.disabled { + pointer-events: none; +} + +.toast { + max-width: 350px; + overflow: hidden; + font-size: 0.875rem; + background-color: rgba(255, 255, 255, 0.85); + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 0.25rem; + box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1); + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); + opacity: 0; +} + +.toast:not(:last-child) { + margin-bottom: 0.75rem; +} + +.toast.showing { + opacity: 1; +} + +.toast.show { + display: block; + opacity: 1; +} + +.toast.hide { + display: none; +} + +.toast-header { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + padding: 0.25rem 0.75rem; + color: #6c757d; + background-color: rgba(255, 255, 255, 0.85); + background-clip: padding-box; + border-bottom: 1px solid rgba(0, 0, 0, 0.05); +} + +.toast-body { + padding: 0.75rem; +} + +.modal-open { + overflow: hidden; +} + +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} + +.modal { + position: fixed; + top: 0; + left: 0; + z-index: 1050; + display: none; + width: 100%; + height: 100%; + overflow: hidden; + outline: 0; +} + +.modal-dialog { + position: relative; + width: auto; + margin: 0.5rem; + pointer-events: none; +} + +.modal.fade .modal-dialog { + transition: -webkit-transform 0.3s ease-out; + transition: transform 0.3s ease-out; + transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out; + -webkit-transform: translate(0, -50px); + transform: translate(0, -50px); +} + +@media screen and (prefers-reduced-motion: reduce) { + .modal.fade .modal-dialog { + transition: none; + } +} + +.modal.show .modal-dialog { + -webkit-transform: none; + transform: none; +} + +.modal-dialog-centered { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + min-height: calc(100% - (0.5rem * 2)); +} + +.modal-dialog-centered::before { + display: block; + height: calc(100vh - (0.5rem * 2)); + content: ""; +} + +.modal-content { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; + pointer-events: auto; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 0.3rem; + outline: 0; +} + +.modal-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1040; + width: 100vw; + height: 100vh; + background-color: #000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop.show { + opacity: 0.5; +} + +.modal-header { + display: -ms-flexbox; + display: flex; + -ms-flex-align: start; + align-items: flex-start; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 1rem 1rem; + border-bottom: 1px solid #e9ecef; + border-top-left-radius: 0.3rem; + border-top-right-radius: 0.3rem; +} + +.modal-header .close { + padding: 1rem 1rem; + margin: -1rem -1rem -1rem auto; +} + +.modal-title { + margin-bottom: 0; + line-height: 1.5; +} + +.modal-body { + position: relative; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + padding: 1rem; +} + +.modal-footer { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: end; + justify-content: flex-end; + padding: 1rem; + border-top: 1px solid #e9ecef; + border-bottom-right-radius: 0.3rem; + border-bottom-left-radius: 0.3rem; +} + +.modal-footer > :not(:first-child) { + margin-left: .25rem; +} + +.modal-footer > :not(:last-child) { + margin-right: .25rem; +} + +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} + +@media (min-width: 576px) { + .modal-dialog { + max-width: 500px; + margin: 1.75rem auto; + } + .modal-dialog-centered { + min-height: calc(100% - (1.75rem * 2)); + } + .modal-dialog-centered::before { + height: calc(100vh - (1.75rem * 2)); + } + .modal-sm { + max-width: 300px; + } +} + +@media (min-width: 992px) { + .modal-lg, + .modal-xl { + max-width: 800px; + } +} + +@media (min-width: 1200px) { + .modal-xl { + max-width: 1140px; + } +} + +.tooltip { + position: absolute; + z-index: 1070; + display: block; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: 0.875rem; + word-wrap: break-word; + opacity: 0; +} + +.tooltip.show { + opacity: 0.9; +} + +.tooltip .arrow { + position: absolute; + display: block; + width: 0.8rem; + height: 0.4rem; +} + +.tooltip .arrow::before { + position: absolute; + content: ""; + border-color: transparent; + border-style: solid; +} + +.bs-tooltip-top, .bs-tooltip-auto[x-placement^="top"] { + padding: 0.4rem 0; +} + +.bs-tooltip-top .arrow, .bs-tooltip-auto[x-placement^="top"] .arrow { + bottom: 0; +} + +.bs-tooltip-top .arrow::before, .bs-tooltip-auto[x-placement^="top"] .arrow::before { + top: 0; + border-width: 0.4rem 0.4rem 0; + border-top-color: #000; +} + +.bs-tooltip-right, .bs-tooltip-auto[x-placement^="right"] { + padding: 0 0.4rem; +} + +.bs-tooltip-right .arrow, .bs-tooltip-auto[x-placement^="right"] .arrow { + left: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-right .arrow::before, .bs-tooltip-auto[x-placement^="right"] .arrow::before { + right: 0; + border-width: 0.4rem 0.4rem 0.4rem 0; + border-right-color: #000; +} + +.bs-tooltip-bottom, .bs-tooltip-auto[x-placement^="bottom"] { + padding: 0.4rem 0; +} + +.bs-tooltip-bottom .arrow, .bs-tooltip-auto[x-placement^="bottom"] .arrow { + top: 0; +} + +.bs-tooltip-bottom .arrow::before, .bs-tooltip-auto[x-placement^="bottom"] .arrow::before { + bottom: 0; + border-width: 0 0.4rem 0.4rem; + border-bottom-color: #000; +} + +.bs-tooltip-left, .bs-tooltip-auto[x-placement^="left"] { + padding: 0 0.4rem; +} + +.bs-tooltip-left .arrow, .bs-tooltip-auto[x-placement^="left"] .arrow { + right: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-left .arrow::before, .bs-tooltip-auto[x-placement^="left"] .arrow::before { + left: 0; + border-width: 0.4rem 0 0.4rem 0.4rem; + border-left-color: #000; +} + +.tooltip-inner { + max-width: 200px; + padding: 0.25rem 0.5rem; + color: #fff; + text-align: center; + background-color: #000; + border-radius: 0.25rem; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1060; + display: block; + max-width: 276px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: 0.875rem; + word-wrap: break-word; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 0.3rem; +} + +.popover .arrow { + position: absolute; + display: block; + width: 1rem; + height: 0.5rem; + margin: 0 0.3rem; +} + +.popover .arrow::before, .popover .arrow::after { + position: absolute; + display: block; + content: ""; + border-color: transparent; + border-style: solid; +} + +.bs-popover-top, .bs-popover-auto[x-placement^="top"] { + margin-bottom: 0.5rem; +} + +.bs-popover-top .arrow, .bs-popover-auto[x-placement^="top"] .arrow { + bottom: calc((0.5rem + 1px) * -1); +} + +.bs-popover-top .arrow::before, .bs-popover-auto[x-placement^="top"] .arrow::before, +.bs-popover-top .arrow::after, +.bs-popover-auto[x-placement^="top"] .arrow::after { + border-width: 0.5rem 0.5rem 0; +} + +.bs-popover-top .arrow::before, .bs-popover-auto[x-placement^="top"] .arrow::before { + bottom: 0; + border-top-color: rgba(0, 0, 0, 0.25); +} + + +.bs-popover-top .arrow::after, +.bs-popover-auto[x-placement^="top"] .arrow::after { + bottom: 1px; + border-top-color: #fff; +} + +.bs-popover-right, .bs-popover-auto[x-placement^="right"] { + margin-left: 0.5rem; +} + +.bs-popover-right .arrow, .bs-popover-auto[x-placement^="right"] .arrow { + left: calc((0.5rem + 1px) * -1); + width: 0.5rem; + height: 1rem; + margin: 0.3rem 0; +} + +.bs-popover-right .arrow::before, .bs-popover-auto[x-placement^="right"] .arrow::before, +.bs-popover-right .arrow::after, +.bs-popover-auto[x-placement^="right"] .arrow::after { + border-width: 0.5rem 0.5rem 0.5rem 0; +} + +.bs-popover-right .arrow::before, .bs-popover-auto[x-placement^="right"] .arrow::before { + left: 0; + border-right-color: rgba(0, 0, 0, 0.25); +} + + +.bs-popover-right .arrow::after, +.bs-popover-auto[x-placement^="right"] .arrow::after { + left: 1px; + border-right-color: #fff; +} + +.bs-popover-bottom, .bs-popover-auto[x-placement^="bottom"] { + margin-top: 0.5rem; +} + +.bs-popover-bottom .arrow, .bs-popover-auto[x-placement^="bottom"] .arrow { + top: calc((0.5rem + 1px) * -1); +} + +.bs-popover-bottom .arrow::before, .bs-popover-auto[x-placement^="bottom"] .arrow::before, +.bs-popover-bottom .arrow::after, +.bs-popover-auto[x-placement^="bottom"] .arrow::after { + border-width: 0 0.5rem 0.5rem 0.5rem; +} + +.bs-popover-bottom .arrow::before, .bs-popover-auto[x-placement^="bottom"] .arrow::before { + top: 0; + border-bottom-color: rgba(0, 0, 0, 0.25); +} + + +.bs-popover-bottom .arrow::after, +.bs-popover-auto[x-placement^="bottom"] .arrow::after { + top: 1px; + border-bottom-color: #fff; +} + +.bs-popover-bottom .popover-header::before, .bs-popover-auto[x-placement^="bottom"] .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: 1rem; + margin-left: -0.5rem; + content: ""; + border-bottom: 1px solid #f7f7f7; +} + +.bs-popover-left, .bs-popover-auto[x-placement^="left"] { + margin-right: 0.5rem; +} + +.bs-popover-left .arrow, .bs-popover-auto[x-placement^="left"] .arrow { + right: calc((0.5rem + 1px) * -1); + width: 0.5rem; + height: 1rem; + margin: 0.3rem 0; +} + +.bs-popover-left .arrow::before, .bs-popover-auto[x-placement^="left"] .arrow::before, +.bs-popover-left .arrow::after, +.bs-popover-auto[x-placement^="left"] .arrow::after { + border-width: 0.5rem 0 0.5rem 0.5rem; +} + +.bs-popover-left .arrow::before, .bs-popover-auto[x-placement^="left"] .arrow::before { + right: 0; + border-left-color: rgba(0, 0, 0, 0.25); +} + + +.bs-popover-left .arrow::after, +.bs-popover-auto[x-placement^="left"] .arrow::after { + right: 1px; + border-left-color: #fff; +} + +.popover-header { + padding: 0.5rem 0.75rem; + margin-bottom: 0; + font-size: 1rem; + color: inherit; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-top-left-radius: calc(0.3rem - 1px); + border-top-right-radius: calc(0.3rem - 1px); +} + +.popover-header:empty { + display: none; +} + +.popover-body { + padding: 0.5rem 0.75rem; + color: #212529; +} + +.carousel { + position: relative; +} + +.carousel.pointer-event { + -ms-touch-action: pan-y; + touch-action: pan-y; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner::after { + display: block; + clear: both; + content: ""; +} + +.carousel-item { + position: relative; + display: none; + float: left; + width: 100%; + margin-right: -100%; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transition: -webkit-transform 0.6s ease-in-out; + transition: transform 0.6s ease-in-out; + transition: transform 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out; +} + +@media screen and (prefers-reduced-motion: reduce) { + .carousel-item { + transition: none; + } +} + +.carousel-item.active, +.carousel-item-next, +.carousel-item-prev { + display: block; +} + +.carousel-item-next:not(.carousel-item-left), +.active.carousel-item-right { + -webkit-transform: translateX(100%); + transform: translateX(100%); +} + +.carousel-item-prev:not(.carousel-item-right), +.active.carousel-item-left { + -webkit-transform: translateX(-100%); + transform: translateX(-100%); +} + +.carousel-fade .carousel-item { + opacity: 0; + transition-property: opacity; + -webkit-transform: none; + transform: none; +} + +.carousel-fade .carousel-item.active, +.carousel-fade .carousel-item-next.carousel-item-left, +.carousel-fade .carousel-item-prev.carousel-item-right { + z-index: 1; + opacity: 1; +} + +.carousel-fade .active.carousel-item-left, +.carousel-fade .active.carousel-item-right { + z-index: 0; + opacity: 0; + transition: 0s 0.6s opacity; +} + +@media screen and (prefers-reduced-motion: reduce) { + .carousel-fade .active.carousel-item-left, + .carousel-fade .active.carousel-item-right { + transition: none; + } +} + +.carousel-control-prev, +.carousel-control-next { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + width: 15%; + color: #fff; + text-align: center; + opacity: 0.5; + transition: opacity 0.15s ease; +} + +@media screen and (prefers-reduced-motion: reduce) { + .carousel-control-prev, + .carousel-control-next { + transition: none; + } +} + +.carousel-control-prev:hover, .carousel-control-prev:focus, +.carousel-control-next:hover, +.carousel-control-next:focus { + color: #fff; + text-decoration: none; + outline: 0; + opacity: 0.9; +} + +.carousel-control-prev { + left: 0; +} + +.carousel-control-next { + right: 0; +} + +.carousel-control-prev-icon, +.carousel-control-next-icon { + display: inline-block; + width: 20px; + height: 20px; + background: transparent no-repeat center center; + background-size: 100% 100%; +} + +.carousel-control-prev-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e"); +} + +.carousel-control-next-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e"); +} + +.carousel-indicators { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 15; + display: -ms-flexbox; + display: flex; + -ms-flex-pack: center; + justify-content: center; + padding-left: 0; + margin-right: 15%; + margin-left: 15%; + list-style: none; +} + +.carousel-indicators li { + box-sizing: content-box; + -ms-flex: 0 1 auto; + flex: 0 1 auto; + width: 30px; + height: 3px; + margin-right: 3px; + margin-left: 3px; + text-indent: -999px; + cursor: pointer; + background-color: #fff; + background-clip: padding-box; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + opacity: .5; + transition: opacity 0.6s ease; +} + +@media screen and (prefers-reduced-motion: reduce) { + .carousel-indicators li { + transition: none; + } +} + +.carousel-indicators .active { + opacity: 1; +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #fff; + text-align: center; +} + +@-webkit-keyframes spinner-border { + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes spinner-border { + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +.spinner-border { + display: inline-block; + width: 2rem; + height: 2rem; + vertical-align: text-bottom; + border: 0.25em solid currentColor; + border-right-color: transparent; + border-radius: 50%; + -webkit-animation: spinner-border .75s linear infinite; + animation: spinner-border .75s linear infinite; +} + +.spinner-border-sm { + width: 1rem; + height: 1rem; + border-width: 0.2em; +} + +@-webkit-keyframes spinner-grow { + 0% { + -webkit-transform: scale(0); + transform: scale(0); + } + 50% { + opacity: 1; + } +} + +@keyframes spinner-grow { + 0% { + -webkit-transform: scale(0); + transform: scale(0); + } + 50% { + opacity: 1; + } +} + +.spinner-grow { + display: inline-block; + width: 2rem; + height: 2rem; + vertical-align: text-bottom; + background-color: currentColor; + border-radius: 50%; + opacity: 0; + -webkit-animation: spinner-grow .75s linear infinite; + animation: spinner-grow .75s linear infinite; +} + +.spinner-grow-sm { + width: 1rem; + height: 1rem; +} + +.align-baseline { + vertical-align: baseline !important; +} + +.align-top { + vertical-align: top !important; +} + +.align-middle { + vertical-align: middle !important; +} + +.align-bottom { + vertical-align: bottom !important; +} + +.align-text-bottom { + vertical-align: text-bottom !important; +} + +.align-text-top { + vertical-align: text-top !important; +} + +.bg-primary { + background-color: #007bff !important; +} + +a.bg-primary:hover, a.bg-primary:focus, +button.bg-primary:hover, +button.bg-primary:focus { + background-color: #0062cc !important; +} + +.bg-secondary { + background-color: #6c757d !important; +} + +a.bg-secondary:hover, a.bg-secondary:focus, +button.bg-secondary:hover, +button.bg-secondary:focus { + background-color: #545b62 !important; +} + +.bg-success { + background-color: #28a745 !important; +} + +a.bg-success:hover, a.bg-success:focus, +button.bg-success:hover, +button.bg-success:focus { + background-color: #1e7e34 !important; +} + +.bg-info { + background-color: #17a2b8 !important; +} + +a.bg-info:hover, a.bg-info:focus, +button.bg-info:hover, +button.bg-info:focus { + background-color: #117a8b !important; +} + +.bg-warning { + background-color: #ffc107 !important; +} + +a.bg-warning:hover, a.bg-warning:focus, +button.bg-warning:hover, +button.bg-warning:focus { + background-color: #d39e00 !important; +} + +.bg-danger { + background-color: #dc3545 !important; +} + +a.bg-danger:hover, a.bg-danger:focus, +button.bg-danger:hover, +button.bg-danger:focus { + background-color: #bd2130 !important; +} + +.bg-light { + background-color: #f8f9fa !important; +} + +a.bg-light:hover, a.bg-light:focus, +button.bg-light:hover, +button.bg-light:focus { + background-color: #dae0e5 !important; +} + +.bg-dark { + background-color: #343a40 !important; +} + +a.bg-dark:hover, a.bg-dark:focus, +button.bg-dark:hover, +button.bg-dark:focus { + background-color: #1d2124 !important; +} + +.bg-white { + background-color: #fff !important; +} + +.bg-transparent { + background-color: transparent !important; +} + +.border { + border: 1px solid #dee2e6 !important; +} + +.border-top { + border-top: 1px solid #dee2e6 !important; +} + +.border-right { + border-right: 1px solid #dee2e6 !important; +} + +.border-bottom { + border-bottom: 1px solid #dee2e6 !important; +} + +.border-left { + border-left: 1px solid #dee2e6 !important; +} + +.border-0 { + border: 0 !important; +} + +.border-top-0 { + border-top: 0 !important; +} + +.border-right-0 { + border-right: 0 !important; +} + +.border-bottom-0 { + border-bottom: 0 !important; +} + +.border-left-0 { + border-left: 0 !important; +} + +.border-primary { + border-color: #007bff !important; +} + +.border-secondary { + border-color: #6c757d !important; +} + +.border-success { + border-color: #28a745 !important; +} + +.border-info { + border-color: #17a2b8 !important; +} + +.border-warning { + border-color: #ffc107 !important; +} + +.border-danger { + border-color: #dc3545 !important; +} + +.border-light { + border-color: #f8f9fa !important; +} + +.border-dark { + border-color: #343a40 !important; +} + +.border-white { + border-color: #fff !important; +} + +.rounded { + border-radius: 0.25rem !important; +} + +.rounded-top { + border-top-left-radius: 0.25rem !important; + border-top-right-radius: 0.25rem !important; +} + +.rounded-right { + border-top-right-radius: 0.25rem !important; + border-bottom-right-radius: 0.25rem !important; +} + +.rounded-bottom { + border-bottom-right-radius: 0.25rem !important; + border-bottom-left-radius: 0.25rem !important; +} + +.rounded-left { + border-top-left-radius: 0.25rem !important; + border-bottom-left-radius: 0.25rem !important; +} + +.rounded-circle { + border-radius: 50% !important; +} + +.rounded-pill { + border-radius: 50rem !important; +} + +.rounded-0 { + border-radius: 0 !important; +} + +.clearfix::after { + display: block; + clear: both; + content: ""; +} + +.d-none { + display: none !important; +} + +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: -ms-flexbox !important; + display: flex !important; +} + +.d-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; +} + +@media (min-width: 576px) { + .d-sm-none { + display: none !important; + } + .d-sm-inline { + display: inline !important; + } + .d-sm-inline-block { + display: inline-block !important; + } + .d-sm-block { + display: block !important; + } + .d-sm-table { + display: table !important; + } + .d-sm-table-row { + display: table-row !important; + } + .d-sm-table-cell { + display: table-cell !important; + } + .d-sm-flex { + display: -ms-flexbox !important; + display: flex !important; + } + .d-sm-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 768px) { + .d-md-none { + display: none !important; + } + .d-md-inline { + display: inline !important; + } + .d-md-inline-block { + display: inline-block !important; + } + .d-md-block { + display: block !important; + } + .d-md-table { + display: table !important; + } + .d-md-table-row { + display: table-row !important; + } + .d-md-table-cell { + display: table-cell !important; + } + .d-md-flex { + display: -ms-flexbox !important; + display: flex !important; + } + .d-md-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 992px) { + .d-lg-none { + display: none !important; + } + .d-lg-inline { + display: inline !important; + } + .d-lg-inline-block { + display: inline-block !important; + } + .d-lg-block { + display: block !important; + } + .d-lg-table { + display: table !important; + } + .d-lg-table-row { + display: table-row !important; + } + .d-lg-table-cell { + display: table-cell !important; + } + .d-lg-flex { + display: -ms-flexbox !important; + display: flex !important; + } + .d-lg-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 1200px) { + .d-xl-none { + display: none !important; + } + .d-xl-inline { + display: inline !important; + } + .d-xl-inline-block { + display: inline-block !important; + } + .d-xl-block { + display: block !important; + } + .d-xl-table { + display: table !important; + } + .d-xl-table-row { + display: table-row !important; + } + .d-xl-table-cell { + display: table-cell !important; + } + .d-xl-flex { + display: -ms-flexbox !important; + display: flex !important; + } + .d-xl-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media print { + .d-print-none { + display: none !important; + } + .d-print-inline { + display: inline !important; + } + .d-print-inline-block { + display: inline-block !important; + } + .d-print-block { + display: block !important; + } + .d-print-table { + display: table !important; + } + .d-print-table-row { + display: table-row !important; + } + .d-print-table-cell { + display: table-cell !important; + } + .d-print-flex { + display: -ms-flexbox !important; + display: flex !important; + } + .d-print-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +.embed-responsive { + position: relative; + display: block; + width: 100%; + padding: 0; + overflow: hidden; +} + +.embed-responsive::before { + display: block; + content: ""; +} + +.embed-responsive .embed-responsive-item, +.embed-responsive iframe, +.embed-responsive embed, +.embed-responsive object, +.embed-responsive video { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; +} + +.embed-responsive-21by9::before { + padding-top: 42.857143%; +} + +.embed-responsive-16by9::before { + padding-top: 56.25%; +} + +.embed-responsive-3by4::before { + padding-top: 133.333333%; +} + +.embed-responsive-1by1::before { + padding-top: 100%; +} + +.flex-row { + -ms-flex-direction: row !important; + flex-direction: row !important; +} + +.flex-column { + -ms-flex-direction: column !important; + flex-direction: column !important; +} + +.flex-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; +} + +.flex-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; +} + +.flex-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; +} + +.flex-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; +} + +.flex-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; +} + +.flex-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; +} + +.flex-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; +} + +.justify-content-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; +} + +.justify-content-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; +} + +.justify-content-center { + -ms-flex-pack: center !important; + justify-content: center !important; +} + +.justify-content-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; +} + +.justify-content-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; +} + +.align-items-start { + -ms-flex-align: start !important; + align-items: flex-start !important; +} + +.align-items-end { + -ms-flex-align: end !important; + align-items: flex-end !important; +} + +.align-items-center { + -ms-flex-align: center !important; + align-items: center !important; +} + +.align-items-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; +} + +.align-items-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; +} + +.align-content-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; +} + +.align-content-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; +} + +.align-content-center { + -ms-flex-line-pack: center !important; + align-content: center !important; +} + +.align-content-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; +} + +.align-content-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; +} + +.align-content-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; +} + +.align-self-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; +} + +.align-self-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; +} + +.align-self-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; +} + +.align-self-center { + -ms-flex-item-align: center !important; + align-self: center !important; +} + +.align-self-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; +} + +.align-self-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; +} + +@media (min-width: 576px) { + .flex-sm-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-sm-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-sm-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-sm-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-sm-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-sm-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-sm-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-sm-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-sm-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-sm-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-sm-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-sm-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-sm-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-sm-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-sm-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-sm-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-sm-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-sm-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-sm-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-sm-center { + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-sm-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-sm-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-sm-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-sm-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-sm-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-sm-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-sm-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-sm-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-sm-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-sm-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-sm-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-sm-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-sm-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-sm-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 768px) { + .flex-md-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-md-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-md-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-md-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-md-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-md-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-md-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-md-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-md-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-md-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-md-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-md-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-md-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-md-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-md-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-md-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-md-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-md-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-md-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-md-center { + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-md-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-md-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-md-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-md-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-md-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-md-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-md-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-md-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-md-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-md-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-md-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-md-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-md-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-md-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 992px) { + .flex-lg-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-lg-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-lg-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-lg-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-lg-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-lg-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-lg-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-lg-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-lg-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-lg-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-lg-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-lg-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-lg-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-lg-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-lg-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-lg-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-lg-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-lg-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-lg-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-lg-center { + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-lg-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-lg-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-lg-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-lg-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-lg-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-lg-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-lg-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-lg-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-lg-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-lg-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-lg-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-lg-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-lg-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-lg-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 1200px) { + .flex-xl-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-xl-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-xl-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-xl-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-xl-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-xl-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-xl-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-xl-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-xl-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-xl-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-xl-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-xl-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-xl-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-xl-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-xl-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-xl-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-xl-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-xl-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-xl-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-xl-center { + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-xl-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-xl-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-xl-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-xl-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-xl-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-xl-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-xl-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-xl-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-xl-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-xl-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-xl-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-xl-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-xl-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-xl-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +.float-left { + float: left !important; +} + +.float-right { + float: right !important; +} + +.float-none { + float: none !important; +} + +@media (min-width: 576px) { + .float-sm-left { + float: left !important; + } + .float-sm-right { + float: right !important; + } + .float-sm-none { + float: none !important; + } +} + +@media (min-width: 768px) { + .float-md-left { + float: left !important; + } + .float-md-right { + float: right !important; + } + .float-md-none { + float: none !important; + } +} + +@media (min-width: 992px) { + .float-lg-left { + float: left !important; + } + .float-lg-right { + float: right !important; + } + .float-lg-none { + float: none !important; + } +} + +@media (min-width: 1200px) { + .float-xl-left { + float: left !important; + } + .float-xl-right { + float: right !important; + } + .float-xl-none { + float: none !important; + } +} + +.overflow-auto { + overflow: auto !important; +} + +.overflow-hidden { + overflow: hidden !important; +} + +.position-static { + position: static !important; +} + +.position-relative { + position: relative !important; +} + +.position-absolute { + position: absolute !important; +} + +.position-fixed { + position: fixed !important; +} + +.position-sticky { + position: -webkit-sticky !important; + position: sticky !important; +} + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; +} + +@supports ((position: -webkit-sticky) or (position: sticky)) { + .sticky-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +.sr-only-focusable:active, .sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + overflow: visible; + clip: auto; + white-space: normal; +} + +.shadow-sm { + box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; +} + +.shadow { + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; +} + +.shadow-lg { + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; +} + +.shadow-none { + box-shadow: none !important; +} + +.w-25 { + width: 25% !important; +} + +.w-50 { + width: 50% !important; +} + +.w-75 { + width: 75% !important; +} + +.w-100 { + width: 100% !important; +} + +.w-auto { + width: auto !important; +} + +.h-25 { + height: 25% !important; +} + +.h-50 { + height: 50% !important; +} + +.h-75 { + height: 75% !important; +} + +.h-100 { + height: 100% !important; +} + +.h-auto { + height: auto !important; +} + +.mw-100 { + max-width: 100% !important; +} + +.mh-100 { + max-height: 100% !important; +} + +.min-vw-100 { + min-width: 100vw !important; +} + +.min-vh-100 { + min-height: 100vh !important; +} + +.vw-100 { + width: 100vw !important; +} + +.vh-100 { + height: 100vh !important; +} + +.m-0 { + margin: 0 !important; +} + +.mt-0, +.my-0 { + margin-top: 0 !important; +} + +.mr-0, +.mx-0 { + margin-right: 0 !important; +} + +.mb-0, +.my-0 { + margin-bottom: 0 !important; +} + +.ml-0, +.mx-0 { + margin-left: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.mt-1, +.my-1 { + margin-top: 0.25rem !important; +} + +.mr-1, +.mx-1 { + margin-right: 0.25rem !important; +} + +.mb-1, +.my-1 { + margin-bottom: 0.25rem !important; +} + +.ml-1, +.mx-1 { + margin-left: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.mt-2, +.my-2 { + margin-top: 0.5rem !important; +} + +.mr-2, +.mx-2 { + margin-right: 0.5rem !important; +} + +.mb-2, +.my-2 { + margin-bottom: 0.5rem !important; +} + +.ml-2, +.mx-2 { + margin-left: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.mt-3, +.my-3 { + margin-top: 1rem !important; +} + +.mr-3, +.mx-3 { + margin-right: 1rem !important; +} + +.mb-3, +.my-3 { + margin-bottom: 1rem !important; +} + +.ml-3, +.mx-3 { + margin-left: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.mt-4, +.my-4 { + margin-top: 1.5rem !important; +} + +.mr-4, +.mx-4 { + margin-right: 1.5rem !important; +} + +.mb-4, +.my-4 { + margin-bottom: 1.5rem !important; +} + +.ml-4, +.mx-4 { + margin-left: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.mt-5, +.my-5 { + margin-top: 3rem !important; +} + +.mr-5, +.mx-5 { + margin-right: 3rem !important; +} + +.mb-5, +.my-5 { + margin-bottom: 3rem !important; +} + +.ml-5, +.mx-5 { + margin-left: 3rem !important; +} + +.p-0 { + padding: 0 !important; +} + +.pt-0, +.py-0 { + padding-top: 0 !important; +} + +.pr-0, +.px-0 { + padding-right: 0 !important; +} + +.pb-0, +.py-0 { + padding-bottom: 0 !important; +} + +.pl-0, +.px-0 { + padding-left: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.pt-1, +.py-1 { + padding-top: 0.25rem !important; +} + +.pr-1, +.px-1 { + padding-right: 0.25rem !important; +} + +.pb-1, +.py-1 { + padding-bottom: 0.25rem !important; +} + +.pl-1, +.px-1 { + padding-left: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.pt-2, +.py-2 { + padding-top: 0.5rem !important; +} + +.pr-2, +.px-2 { + padding-right: 0.5rem !important; +} + +.pb-2, +.py-2 { + padding-bottom: 0.5rem !important; +} + +.pl-2, +.px-2 { + padding-left: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.pt-3, +.py-3 { + padding-top: 1rem !important; +} + +.pr-3, +.px-3 { + padding-right: 1rem !important; +} + +.pb-3, +.py-3 { + padding-bottom: 1rem !important; +} + +.pl-3, +.px-3 { + padding-left: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.pt-4, +.py-4 { + padding-top: 1.5rem !important; +} + +.pr-4, +.px-4 { + padding-right: 1.5rem !important; +} + +.pb-4, +.py-4 { + padding-bottom: 1.5rem !important; +} + +.pl-4, +.px-4 { + padding-left: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.pt-5, +.py-5 { + padding-top: 3rem !important; +} + +.pr-5, +.px-5 { + padding-right: 3rem !important; +} + +.pb-5, +.py-5 { + padding-bottom: 3rem !important; +} + +.pl-5, +.px-5 { + padding-left: 3rem !important; +} + +.m-n1 { + margin: -0.25rem !important; +} + +.mt-n1, +.my-n1 { + margin-top: -0.25rem !important; +} + +.mr-n1, +.mx-n1 { + margin-right: -0.25rem !important; +} + +.mb-n1, +.my-n1 { + margin-bottom: -0.25rem !important; +} + +.ml-n1, +.mx-n1 { + margin-left: -0.25rem !important; +} + +.m-n2 { + margin: -0.5rem !important; +} + +.mt-n2, +.my-n2 { + margin-top: -0.5rem !important; +} + +.mr-n2, +.mx-n2 { + margin-right: -0.5rem !important; +} + +.mb-n2, +.my-n2 { + margin-bottom: -0.5rem !important; +} + +.ml-n2, +.mx-n2 { + margin-left: -0.5rem !important; +} + +.m-n3 { + margin: -1rem !important; +} + +.mt-n3, +.my-n3 { + margin-top: -1rem !important; +} + +.mr-n3, +.mx-n3 { + margin-right: -1rem !important; +} + +.mb-n3, +.my-n3 { + margin-bottom: -1rem !important; +} + +.ml-n3, +.mx-n3 { + margin-left: -1rem !important; +} + +.m-n4 { + margin: -1.5rem !important; +} + +.mt-n4, +.my-n4 { + margin-top: -1.5rem !important; +} + +.mr-n4, +.mx-n4 { + margin-right: -1.5rem !important; +} + +.mb-n4, +.my-n4 { + margin-bottom: -1.5rem !important; +} + +.ml-n4, +.mx-n4 { + margin-left: -1.5rem !important; +} + +.m-n5 { + margin: -3rem !important; +} + +.mt-n5, +.my-n5 { + margin-top: -3rem !important; +} + +.mr-n5, +.mx-n5 { + margin-right: -3rem !important; +} + +.mb-n5, +.my-n5 { + margin-bottom: -3rem !important; +} + +.ml-n5, +.mx-n5 { + margin-left: -3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mt-auto, +.my-auto { + margin-top: auto !important; +} + +.mr-auto, +.mx-auto { + margin-right: auto !important; +} + +.mb-auto, +.my-auto { + margin-bottom: auto !important; +} + +.ml-auto, +.mx-auto { + margin-left: auto !important; +} + +@media (min-width: 576px) { + .m-sm-0 { + margin: 0 !important; + } + .mt-sm-0, + .my-sm-0 { + margin-top: 0 !important; + } + .mr-sm-0, + .mx-sm-0 { + margin-right: 0 !important; + } + .mb-sm-0, + .my-sm-0 { + margin-bottom: 0 !important; + } + .ml-sm-0, + .mx-sm-0 { + margin-left: 0 !important; + } + .m-sm-1 { + margin: 0.25rem !important; + } + .mt-sm-1, + .my-sm-1 { + margin-top: 0.25rem !important; + } + .mr-sm-1, + .mx-sm-1 { + margin-right: 0.25rem !important; + } + .mb-sm-1, + .my-sm-1 { + margin-bottom: 0.25rem !important; + } + .ml-sm-1, + .mx-sm-1 { + margin-left: 0.25rem !important; + } + .m-sm-2 { + margin: 0.5rem !important; + } + .mt-sm-2, + .my-sm-2 { + margin-top: 0.5rem !important; + } + .mr-sm-2, + .mx-sm-2 { + margin-right: 0.5rem !important; + } + .mb-sm-2, + .my-sm-2 { + margin-bottom: 0.5rem !important; + } + .ml-sm-2, + .mx-sm-2 { + margin-left: 0.5rem !important; + } + .m-sm-3 { + margin: 1rem !important; + } + .mt-sm-3, + .my-sm-3 { + margin-top: 1rem !important; + } + .mr-sm-3, + .mx-sm-3 { + margin-right: 1rem !important; + } + .mb-sm-3, + .my-sm-3 { + margin-bottom: 1rem !important; + } + .ml-sm-3, + .mx-sm-3 { + margin-left: 1rem !important; + } + .m-sm-4 { + margin: 1.5rem !important; + } + .mt-sm-4, + .my-sm-4 { + margin-top: 1.5rem !important; + } + .mr-sm-4, + .mx-sm-4 { + margin-right: 1.5rem !important; + } + .mb-sm-4, + .my-sm-4 { + margin-bottom: 1.5rem !important; + } + .ml-sm-4, + .mx-sm-4 { + margin-left: 1.5rem !important; + } + .m-sm-5 { + margin: 3rem !important; + } + .mt-sm-5, + .my-sm-5 { + margin-top: 3rem !important; + } + .mr-sm-5, + .mx-sm-5 { + margin-right: 3rem !important; + } + .mb-sm-5, + .my-sm-5 { + margin-bottom: 3rem !important; + } + .ml-sm-5, + .mx-sm-5 { + margin-left: 3rem !important; + } + .p-sm-0 { + padding: 0 !important; + } + .pt-sm-0, + .py-sm-0 { + padding-top: 0 !important; + } + .pr-sm-0, + .px-sm-0 { + padding-right: 0 !important; + } + .pb-sm-0, + .py-sm-0 { + padding-bottom: 0 !important; + } + .pl-sm-0, + .px-sm-0 { + padding-left: 0 !important; + } + .p-sm-1 { + padding: 0.25rem !important; + } + .pt-sm-1, + .py-sm-1 { + padding-top: 0.25rem !important; + } + .pr-sm-1, + .px-sm-1 { + padding-right: 0.25rem !important; + } + .pb-sm-1, + .py-sm-1 { + padding-bottom: 0.25rem !important; + } + .pl-sm-1, + .px-sm-1 { + padding-left: 0.25rem !important; + } + .p-sm-2 { + padding: 0.5rem !important; + } + .pt-sm-2, + .py-sm-2 { + padding-top: 0.5rem !important; + } + .pr-sm-2, + .px-sm-2 { + padding-right: 0.5rem !important; + } + .pb-sm-2, + .py-sm-2 { + padding-bottom: 0.5rem !important; + } + .pl-sm-2, + .px-sm-2 { + padding-left: 0.5rem !important; + } + .p-sm-3 { + padding: 1rem !important; + } + .pt-sm-3, + .py-sm-3 { + padding-top: 1rem !important; + } + .pr-sm-3, + .px-sm-3 { + padding-right: 1rem !important; + } + .pb-sm-3, + .py-sm-3 { + padding-bottom: 1rem !important; + } + .pl-sm-3, + .px-sm-3 { + padding-left: 1rem !important; + } + .p-sm-4 { + padding: 1.5rem !important; + } + .pt-sm-4, + .py-sm-4 { + padding-top: 1.5rem !important; + } + .pr-sm-4, + .px-sm-4 { + padding-right: 1.5rem !important; + } + .pb-sm-4, + .py-sm-4 { + padding-bottom: 1.5rem !important; + } + .pl-sm-4, + .px-sm-4 { + padding-left: 1.5rem !important; + } + .p-sm-5 { + padding: 3rem !important; + } + .pt-sm-5, + .py-sm-5 { + padding-top: 3rem !important; + } + .pr-sm-5, + .px-sm-5 { + padding-right: 3rem !important; + } + .pb-sm-5, + .py-sm-5 { + padding-bottom: 3rem !important; + } + .pl-sm-5, + .px-sm-5 { + padding-left: 3rem !important; + } + .m-sm-n1 { + margin: -0.25rem !important; + } + .mt-sm-n1, + .my-sm-n1 { + margin-top: -0.25rem !important; + } + .mr-sm-n1, + .mx-sm-n1 { + margin-right: -0.25rem !important; + } + .mb-sm-n1, + .my-sm-n1 { + margin-bottom: -0.25rem !important; + } + .ml-sm-n1, + .mx-sm-n1 { + margin-left: -0.25rem !important; + } + .m-sm-n2 { + margin: -0.5rem !important; + } + .mt-sm-n2, + .my-sm-n2 { + margin-top: -0.5rem !important; + } + .mr-sm-n2, + .mx-sm-n2 { + margin-right: -0.5rem !important; + } + .mb-sm-n2, + .my-sm-n2 { + margin-bottom: -0.5rem !important; + } + .ml-sm-n2, + .mx-sm-n2 { + margin-left: -0.5rem !important; + } + .m-sm-n3 { + margin: -1rem !important; + } + .mt-sm-n3, + .my-sm-n3 { + margin-top: -1rem !important; + } + .mr-sm-n3, + .mx-sm-n3 { + margin-right: -1rem !important; + } + .mb-sm-n3, + .my-sm-n3 { + margin-bottom: -1rem !important; + } + .ml-sm-n3, + .mx-sm-n3 { + margin-left: -1rem !important; + } + .m-sm-n4 { + margin: -1.5rem !important; + } + .mt-sm-n4, + .my-sm-n4 { + margin-top: -1.5rem !important; + } + .mr-sm-n4, + .mx-sm-n4 { + margin-right: -1.5rem !important; + } + .mb-sm-n4, + .my-sm-n4 { + margin-bottom: -1.5rem !important; + } + .ml-sm-n4, + .mx-sm-n4 { + margin-left: -1.5rem !important; + } + .m-sm-n5 { + margin: -3rem !important; + } + .mt-sm-n5, + .my-sm-n5 { + margin-top: -3rem !important; + } + .mr-sm-n5, + .mx-sm-n5 { + margin-right: -3rem !important; + } + .mb-sm-n5, + .my-sm-n5 { + margin-bottom: -3rem !important; + } + .ml-sm-n5, + .mx-sm-n5 { + margin-left: -3rem !important; + } + .m-sm-auto { + margin: auto !important; + } + .mt-sm-auto, + .my-sm-auto { + margin-top: auto !important; + } + .mr-sm-auto, + .mx-sm-auto { + margin-right: auto !important; + } + .mb-sm-auto, + .my-sm-auto { + margin-bottom: auto !important; + } + .ml-sm-auto, + .mx-sm-auto { + margin-left: auto !important; + } +} + +@media (min-width: 768px) { + .m-md-0 { + margin: 0 !important; + } + .mt-md-0, + .my-md-0 { + margin-top: 0 !important; + } + .mr-md-0, + .mx-md-0 { + margin-right: 0 !important; + } + .mb-md-0, + .my-md-0 { + margin-bottom: 0 !important; + } + .ml-md-0, + .mx-md-0 { + margin-left: 0 !important; + } + .m-md-1 { + margin: 0.25rem !important; + } + .mt-md-1, + .my-md-1 { + margin-top: 0.25rem !important; + } + .mr-md-1, + .mx-md-1 { + margin-right: 0.25rem !important; + } + .mb-md-1, + .my-md-1 { + margin-bottom: 0.25rem !important; + } + .ml-md-1, + .mx-md-1 { + margin-left: 0.25rem !important; + } + .m-md-2 { + margin: 0.5rem !important; + } + .mt-md-2, + .my-md-2 { + margin-top: 0.5rem !important; + } + .mr-md-2, + .mx-md-2 { + margin-right: 0.5rem !important; + } + .mb-md-2, + .my-md-2 { + margin-bottom: 0.5rem !important; + } + .ml-md-2, + .mx-md-2 { + margin-left: 0.5rem !important; + } + .m-md-3 { + margin: 1rem !important; + } + .mt-md-3, + .my-md-3 { + margin-top: 1rem !important; + } + .mr-md-3, + .mx-md-3 { + margin-right: 1rem !important; + } + .mb-md-3, + .my-md-3 { + margin-bottom: 1rem !important; + } + .ml-md-3, + .mx-md-3 { + margin-left: 1rem !important; + } + .m-md-4 { + margin: 1.5rem !important; + } + .mt-md-4, + .my-md-4 { + margin-top: 1.5rem !important; + } + .mr-md-4, + .mx-md-4 { + margin-right: 1.5rem !important; + } + .mb-md-4, + .my-md-4 { + margin-bottom: 1.5rem !important; + } + .ml-md-4, + .mx-md-4 { + margin-left: 1.5rem !important; + } + .m-md-5 { + margin: 3rem !important; + } + .mt-md-5, + .my-md-5 { + margin-top: 3rem !important; + } + .mr-md-5, + .mx-md-5 { + margin-right: 3rem !important; + } + .mb-md-5, + .my-md-5 { + margin-bottom: 3rem !important; + } + .ml-md-5, + .mx-md-5 { + margin-left: 3rem !important; + } + .p-md-0 { + padding: 0 !important; + } + .pt-md-0, + .py-md-0 { + padding-top: 0 !important; + } + .pr-md-0, + .px-md-0 { + padding-right: 0 !important; + } + .pb-md-0, + .py-md-0 { + padding-bottom: 0 !important; + } + .pl-md-0, + .px-md-0 { + padding-left: 0 !important; + } + .p-md-1 { + padding: 0.25rem !important; + } + .pt-md-1, + .py-md-1 { + padding-top: 0.25rem !important; + } + .pr-md-1, + .px-md-1 { + padding-right: 0.25rem !important; + } + .pb-md-1, + .py-md-1 { + padding-bottom: 0.25rem !important; + } + .pl-md-1, + .px-md-1 { + padding-left: 0.25rem !important; + } + .p-md-2 { + padding: 0.5rem !important; + } + .pt-md-2, + .py-md-2 { + padding-top: 0.5rem !important; + } + .pr-md-2, + .px-md-2 { + padding-right: 0.5rem !important; + } + .pb-md-2, + .py-md-2 { + padding-bottom: 0.5rem !important; + } + .pl-md-2, + .px-md-2 { + padding-left: 0.5rem !important; + } + .p-md-3 { + padding: 1rem !important; + } + .pt-md-3, + .py-md-3 { + padding-top: 1rem !important; + } + .pr-md-3, + .px-md-3 { + padding-right: 1rem !important; + } + .pb-md-3, + .py-md-3 { + padding-bottom: 1rem !important; + } + .pl-md-3, + .px-md-3 { + padding-left: 1rem !important; + } + .p-md-4 { + padding: 1.5rem !important; + } + .pt-md-4, + .py-md-4 { + padding-top: 1.5rem !important; + } + .pr-md-4, + .px-md-4 { + padding-right: 1.5rem !important; + } + .pb-md-4, + .py-md-4 { + padding-bottom: 1.5rem !important; + } + .pl-md-4, + .px-md-4 { + padding-left: 1.5rem !important; + } + .p-md-5 { + padding: 3rem !important; + } + .pt-md-5, + .py-md-5 { + padding-top: 3rem !important; + } + .pr-md-5, + .px-md-5 { + padding-right: 3rem !important; + } + .pb-md-5, + .py-md-5 { + padding-bottom: 3rem !important; + } + .pl-md-5, + .px-md-5 { + padding-left: 3rem !important; + } + .m-md-n1 { + margin: -0.25rem !important; + } + .mt-md-n1, + .my-md-n1 { + margin-top: -0.25rem !important; + } + .mr-md-n1, + .mx-md-n1 { + margin-right: -0.25rem !important; + } + .mb-md-n1, + .my-md-n1 { + margin-bottom: -0.25rem !important; + } + .ml-md-n1, + .mx-md-n1 { + margin-left: -0.25rem !important; + } + .m-md-n2 { + margin: -0.5rem !important; + } + .mt-md-n2, + .my-md-n2 { + margin-top: -0.5rem !important; + } + .mr-md-n2, + .mx-md-n2 { + margin-right: -0.5rem !important; + } + .mb-md-n2, + .my-md-n2 { + margin-bottom: -0.5rem !important; + } + .ml-md-n2, + .mx-md-n2 { + margin-left: -0.5rem !important; + } + .m-md-n3 { + margin: -1rem !important; + } + .mt-md-n3, + .my-md-n3 { + margin-top: -1rem !important; + } + .mr-md-n3, + .mx-md-n3 { + margin-right: -1rem !important; + } + .mb-md-n3, + .my-md-n3 { + margin-bottom: -1rem !important; + } + .ml-md-n3, + .mx-md-n3 { + margin-left: -1rem !important; + } + .m-md-n4 { + margin: -1.5rem !important; + } + .mt-md-n4, + .my-md-n4 { + margin-top: -1.5rem !important; + } + .mr-md-n4, + .mx-md-n4 { + margin-right: -1.5rem !important; + } + .mb-md-n4, + .my-md-n4 { + margin-bottom: -1.5rem !important; + } + .ml-md-n4, + .mx-md-n4 { + margin-left: -1.5rem !important; + } + .m-md-n5 { + margin: -3rem !important; + } + .mt-md-n5, + .my-md-n5 { + margin-top: -3rem !important; + } + .mr-md-n5, + .mx-md-n5 { + margin-right: -3rem !important; + } + .mb-md-n5, + .my-md-n5 { + margin-bottom: -3rem !important; + } + .ml-md-n5, + .mx-md-n5 { + margin-left: -3rem !important; + } + .m-md-auto { + margin: auto !important; + } + .mt-md-auto, + .my-md-auto { + margin-top: auto !important; + } + .mr-md-auto, + .mx-md-auto { + margin-right: auto !important; + } + .mb-md-auto, + .my-md-auto { + margin-bottom: auto !important; + } + .ml-md-auto, + .mx-md-auto { + margin-left: auto !important; + } +} + +@media (min-width: 992px) { + .m-lg-0 { + margin: 0 !important; + } + .mt-lg-0, + .my-lg-0 { + margin-top: 0 !important; + } + .mr-lg-0, + .mx-lg-0 { + margin-right: 0 !important; + } + .mb-lg-0, + .my-lg-0 { + margin-bottom: 0 !important; + } + .ml-lg-0, + .mx-lg-0 { + margin-left: 0 !important; + } + .m-lg-1 { + margin: 0.25rem !important; + } + .mt-lg-1, + .my-lg-1 { + margin-top: 0.25rem !important; + } + .mr-lg-1, + .mx-lg-1 { + margin-right: 0.25rem !important; + } + .mb-lg-1, + .my-lg-1 { + margin-bottom: 0.25rem !important; + } + .ml-lg-1, + .mx-lg-1 { + margin-left: 0.25rem !important; + } + .m-lg-2 { + margin: 0.5rem !important; + } + .mt-lg-2, + .my-lg-2 { + margin-top: 0.5rem !important; + } + .mr-lg-2, + .mx-lg-2 { + margin-right: 0.5rem !important; + } + .mb-lg-2, + .my-lg-2 { + margin-bottom: 0.5rem !important; + } + .ml-lg-2, + .mx-lg-2 { + margin-left: 0.5rem !important; + } + .m-lg-3 { + margin: 1rem !important; + } + .mt-lg-3, + .my-lg-3 { + margin-top: 1rem !important; + } + .mr-lg-3, + .mx-lg-3 { + margin-right: 1rem !important; + } + .mb-lg-3, + .my-lg-3 { + margin-bottom: 1rem !important; + } + .ml-lg-3, + .mx-lg-3 { + margin-left: 1rem !important; + } + .m-lg-4 { + margin: 1.5rem !important; + } + .mt-lg-4, + .my-lg-4 { + margin-top: 1.5rem !important; + } + .mr-lg-4, + .mx-lg-4 { + margin-right: 1.5rem !important; + } + .mb-lg-4, + .my-lg-4 { + margin-bottom: 1.5rem !important; + } + .ml-lg-4, + .mx-lg-4 { + margin-left: 1.5rem !important; + } + .m-lg-5 { + margin: 3rem !important; + } + .mt-lg-5, + .my-lg-5 { + margin-top: 3rem !important; + } + .mr-lg-5, + .mx-lg-5 { + margin-right: 3rem !important; + } + .mb-lg-5, + .my-lg-5 { + margin-bottom: 3rem !important; + } + .ml-lg-5, + .mx-lg-5 { + margin-left: 3rem !important; + } + .p-lg-0 { + padding: 0 !important; + } + .pt-lg-0, + .py-lg-0 { + padding-top: 0 !important; + } + .pr-lg-0, + .px-lg-0 { + padding-right: 0 !important; + } + .pb-lg-0, + .py-lg-0 { + padding-bottom: 0 !important; + } + .pl-lg-0, + .px-lg-0 { + padding-left: 0 !important; + } + .p-lg-1 { + padding: 0.25rem !important; + } + .pt-lg-1, + .py-lg-1 { + padding-top: 0.25rem !important; + } + .pr-lg-1, + .px-lg-1 { + padding-right: 0.25rem !important; + } + .pb-lg-1, + .py-lg-1 { + padding-bottom: 0.25rem !important; + } + .pl-lg-1, + .px-lg-1 { + padding-left: 0.25rem !important; + } + .p-lg-2 { + padding: 0.5rem !important; + } + .pt-lg-2, + .py-lg-2 { + padding-top: 0.5rem !important; + } + .pr-lg-2, + .px-lg-2 { + padding-right: 0.5rem !important; + } + .pb-lg-2, + .py-lg-2 { + padding-bottom: 0.5rem !important; + } + .pl-lg-2, + .px-lg-2 { + padding-left: 0.5rem !important; + } + .p-lg-3 { + padding: 1rem !important; + } + .pt-lg-3, + .py-lg-3 { + padding-top: 1rem !important; + } + .pr-lg-3, + .px-lg-3 { + padding-right: 1rem !important; + } + .pb-lg-3, + .py-lg-3 { + padding-bottom: 1rem !important; + } + .pl-lg-3, + .px-lg-3 { + padding-left: 1rem !important; + } + .p-lg-4 { + padding: 1.5rem !important; + } + .pt-lg-4, + .py-lg-4 { + padding-top: 1.5rem !important; + } + .pr-lg-4, + .px-lg-4 { + padding-right: 1.5rem !important; + } + .pb-lg-4, + .py-lg-4 { + padding-bottom: 1.5rem !important; + } + .pl-lg-4, + .px-lg-4 { + padding-left: 1.5rem !important; + } + .p-lg-5 { + padding: 3rem !important; + } + .pt-lg-5, + .py-lg-5 { + padding-top: 3rem !important; + } + .pr-lg-5, + .px-lg-5 { + padding-right: 3rem !important; + } + .pb-lg-5, + .py-lg-5 { + padding-bottom: 3rem !important; + } + .pl-lg-5, + .px-lg-5 { + padding-left: 3rem !important; + } + .m-lg-n1 { + margin: -0.25rem !important; + } + .mt-lg-n1, + .my-lg-n1 { + margin-top: -0.25rem !important; + } + .mr-lg-n1, + .mx-lg-n1 { + margin-right: -0.25rem !important; + } + .mb-lg-n1, + .my-lg-n1 { + margin-bottom: -0.25rem !important; + } + .ml-lg-n1, + .mx-lg-n1 { + margin-left: -0.25rem !important; + } + .m-lg-n2 { + margin: -0.5rem !important; + } + .mt-lg-n2, + .my-lg-n2 { + margin-top: -0.5rem !important; + } + .mr-lg-n2, + .mx-lg-n2 { + margin-right: -0.5rem !important; + } + .mb-lg-n2, + .my-lg-n2 { + margin-bottom: -0.5rem !important; + } + .ml-lg-n2, + .mx-lg-n2 { + margin-left: -0.5rem !important; + } + .m-lg-n3 { + margin: -1rem !important; + } + .mt-lg-n3, + .my-lg-n3 { + margin-top: -1rem !important; + } + .mr-lg-n3, + .mx-lg-n3 { + margin-right: -1rem !important; + } + .mb-lg-n3, + .my-lg-n3 { + margin-bottom: -1rem !important; + } + .ml-lg-n3, + .mx-lg-n3 { + margin-left: -1rem !important; + } + .m-lg-n4 { + margin: -1.5rem !important; + } + .mt-lg-n4, + .my-lg-n4 { + margin-top: -1.5rem !important; + } + .mr-lg-n4, + .mx-lg-n4 { + margin-right: -1.5rem !important; + } + .mb-lg-n4, + .my-lg-n4 { + margin-bottom: -1.5rem !important; + } + .ml-lg-n4, + .mx-lg-n4 { + margin-left: -1.5rem !important; + } + .m-lg-n5 { + margin: -3rem !important; + } + .mt-lg-n5, + .my-lg-n5 { + margin-top: -3rem !important; + } + .mr-lg-n5, + .mx-lg-n5 { + margin-right: -3rem !important; + } + .mb-lg-n5, + .my-lg-n5 { + margin-bottom: -3rem !important; + } + .ml-lg-n5, + .mx-lg-n5 { + margin-left: -3rem !important; + } + .m-lg-auto { + margin: auto !important; + } + .mt-lg-auto, + .my-lg-auto { + margin-top: auto !important; + } + .mr-lg-auto, + .mx-lg-auto { + margin-right: auto !important; + } + .mb-lg-auto, + .my-lg-auto { + margin-bottom: auto !important; + } + .ml-lg-auto, + .mx-lg-auto { + margin-left: auto !important; + } +} + +@media (min-width: 1200px) { + .m-xl-0 { + margin: 0 !important; + } + .mt-xl-0, + .my-xl-0 { + margin-top: 0 !important; + } + .mr-xl-0, + .mx-xl-0 { + margin-right: 0 !important; + } + .mb-xl-0, + .my-xl-0 { + margin-bottom: 0 !important; + } + .ml-xl-0, + .mx-xl-0 { + margin-left: 0 !important; + } + .m-xl-1 { + margin: 0.25rem !important; + } + .mt-xl-1, + .my-xl-1 { + margin-top: 0.25rem !important; + } + .mr-xl-1, + .mx-xl-1 { + margin-right: 0.25rem !important; + } + .mb-xl-1, + .my-xl-1 { + margin-bottom: 0.25rem !important; + } + .ml-xl-1, + .mx-xl-1 { + margin-left: 0.25rem !important; + } + .m-xl-2 { + margin: 0.5rem !important; + } + .mt-xl-2, + .my-xl-2 { + margin-top: 0.5rem !important; + } + .mr-xl-2, + .mx-xl-2 { + margin-right: 0.5rem !important; + } + .mb-xl-2, + .my-xl-2 { + margin-bottom: 0.5rem !important; + } + .ml-xl-2, + .mx-xl-2 { + margin-left: 0.5rem !important; + } + .m-xl-3 { + margin: 1rem !important; + } + .mt-xl-3, + .my-xl-3 { + margin-top: 1rem !important; + } + .mr-xl-3, + .mx-xl-3 { + margin-right: 1rem !important; + } + .mb-xl-3, + .my-xl-3 { + margin-bottom: 1rem !important; + } + .ml-xl-3, + .mx-xl-3 { + margin-left: 1rem !important; + } + .m-xl-4 { + margin: 1.5rem !important; + } + .mt-xl-4, + .my-xl-4 { + margin-top: 1.5rem !important; + } + .mr-xl-4, + .mx-xl-4 { + margin-right: 1.5rem !important; + } + .mb-xl-4, + .my-xl-4 { + margin-bottom: 1.5rem !important; + } + .ml-xl-4, + .mx-xl-4 { + margin-left: 1.5rem !important; + } + .m-xl-5 { + margin: 3rem !important; + } + .mt-xl-5, + .my-xl-5 { + margin-top: 3rem !important; + } + .mr-xl-5, + .mx-xl-5 { + margin-right: 3rem !important; + } + .mb-xl-5, + .my-xl-5 { + margin-bottom: 3rem !important; + } + .ml-xl-5, + .mx-xl-5 { + margin-left: 3rem !important; + } + .p-xl-0 { + padding: 0 !important; + } + .pt-xl-0, + .py-xl-0 { + padding-top: 0 !important; + } + .pr-xl-0, + .px-xl-0 { + padding-right: 0 !important; + } + .pb-xl-0, + .py-xl-0 { + padding-bottom: 0 !important; + } + .pl-xl-0, + .px-xl-0 { + padding-left: 0 !important; + } + .p-xl-1 { + padding: 0.25rem !important; + } + .pt-xl-1, + .py-xl-1 { + padding-top: 0.25rem !important; + } + .pr-xl-1, + .px-xl-1 { + padding-right: 0.25rem !important; + } + .pb-xl-1, + .py-xl-1 { + padding-bottom: 0.25rem !important; + } + .pl-xl-1, + .px-xl-1 { + padding-left: 0.25rem !important; + } + .p-xl-2 { + padding: 0.5rem !important; + } + .pt-xl-2, + .py-xl-2 { + padding-top: 0.5rem !important; + } + .pr-xl-2, + .px-xl-2 { + padding-right: 0.5rem !important; + } + .pb-xl-2, + .py-xl-2 { + padding-bottom: 0.5rem !important; + } + .pl-xl-2, + .px-xl-2 { + padding-left: 0.5rem !important; + } + .p-xl-3 { + padding: 1rem !important; + } + .pt-xl-3, + .py-xl-3 { + padding-top: 1rem !important; + } + .pr-xl-3, + .px-xl-3 { + padding-right: 1rem !important; + } + .pb-xl-3, + .py-xl-3 { + padding-bottom: 1rem !important; + } + .pl-xl-3, + .px-xl-3 { + padding-left: 1rem !important; + } + .p-xl-4 { + padding: 1.5rem !important; + } + .pt-xl-4, + .py-xl-4 { + padding-top: 1.5rem !important; + } + .pr-xl-4, + .px-xl-4 { + padding-right: 1.5rem !important; + } + .pb-xl-4, + .py-xl-4 { + padding-bottom: 1.5rem !important; + } + .pl-xl-4, + .px-xl-4 { + padding-left: 1.5rem !important; + } + .p-xl-5 { + padding: 3rem !important; + } + .pt-xl-5, + .py-xl-5 { + padding-top: 3rem !important; + } + .pr-xl-5, + .px-xl-5 { + padding-right: 3rem !important; + } + .pb-xl-5, + .py-xl-5 { + padding-bottom: 3rem !important; + } + .pl-xl-5, + .px-xl-5 { + padding-left: 3rem !important; + } + .m-xl-n1 { + margin: -0.25rem !important; + } + .mt-xl-n1, + .my-xl-n1 { + margin-top: -0.25rem !important; + } + .mr-xl-n1, + .mx-xl-n1 { + margin-right: -0.25rem !important; + } + .mb-xl-n1, + .my-xl-n1 { + margin-bottom: -0.25rem !important; + } + .ml-xl-n1, + .mx-xl-n1 { + margin-left: -0.25rem !important; + } + .m-xl-n2 { + margin: -0.5rem !important; + } + .mt-xl-n2, + .my-xl-n2 { + margin-top: -0.5rem !important; + } + .mr-xl-n2, + .mx-xl-n2 { + margin-right: -0.5rem !important; + } + .mb-xl-n2, + .my-xl-n2 { + margin-bottom: -0.5rem !important; + } + .ml-xl-n2, + .mx-xl-n2 { + margin-left: -0.5rem !important; + } + .m-xl-n3 { + margin: -1rem !important; + } + .mt-xl-n3, + .my-xl-n3 { + margin-top: -1rem !important; + } + .mr-xl-n3, + .mx-xl-n3 { + margin-right: -1rem !important; + } + .mb-xl-n3, + .my-xl-n3 { + margin-bottom: -1rem !important; + } + .ml-xl-n3, + .mx-xl-n3 { + margin-left: -1rem !important; + } + .m-xl-n4 { + margin: -1.5rem !important; + } + .mt-xl-n4, + .my-xl-n4 { + margin-top: -1.5rem !important; + } + .mr-xl-n4, + .mx-xl-n4 { + margin-right: -1.5rem !important; + } + .mb-xl-n4, + .my-xl-n4 { + margin-bottom: -1.5rem !important; + } + .ml-xl-n4, + .mx-xl-n4 { + margin-left: -1.5rem !important; + } + .m-xl-n5 { + margin: -3rem !important; + } + .mt-xl-n5, + .my-xl-n5 { + margin-top: -3rem !important; + } + .mr-xl-n5, + .mx-xl-n5 { + margin-right: -3rem !important; + } + .mb-xl-n5, + .my-xl-n5 { + margin-bottom: -3rem !important; + } + .ml-xl-n5, + .mx-xl-n5 { + margin-left: -3rem !important; + } + .m-xl-auto { + margin: auto !important; + } + .mt-xl-auto, + .my-xl-auto { + margin-top: auto !important; + } + .mr-xl-auto, + .mx-xl-auto { + margin-right: auto !important; + } + .mb-xl-auto, + .my-xl-auto { + margin-bottom: auto !important; + } + .ml-xl-auto, + .mx-xl-auto { + margin-left: auto !important; + } +} + +.text-monospace { + font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +.text-justify { + text-align: justify !important; +} + +.text-wrap { + white-space: normal !important; +} + +.text-nowrap { + white-space: nowrap !important; +} + +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.text-left { + text-align: left !important; +} + +.text-right { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +@media (min-width: 576px) { + .text-sm-left { + text-align: left !important; + } + .text-sm-right { + text-align: right !important; + } + .text-sm-center { + text-align: center !important; + } +} + +@media (min-width: 768px) { + .text-md-left { + text-align: left !important; + } + .text-md-right { + text-align: right !important; + } + .text-md-center { + text-align: center !important; + } +} + +@media (min-width: 992px) { + .text-lg-left { + text-align: left !important; + } + .text-lg-right { + text-align: right !important; + } + .text-lg-center { + text-align: center !important; + } +} + +@media (min-width: 1200px) { + .text-xl-left { + text-align: left !important; + } + .text-xl-right { + text-align: right !important; + } + .text-xl-center { + text-align: center !important; + } +} + +.text-lowercase { + text-transform: lowercase !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +.text-capitalize { + text-transform: capitalize !important; +} + +.font-weight-light { + font-weight: 300 !important; +} + +.font-weight-lighter { + font-weight: lighter !important; +} + +.font-weight-normal { + font-weight: 400 !important; +} + +.font-weight-bold { + font-weight: 700 !important; +} + +.font-weight-bolder { + font-weight: bolder !important; +} + +.font-italic { + font-style: italic !important; +} + +.text-white { + color: #fff !important; +} + +.text-primary { + color: #007bff !important; +} + +a.text-primary:hover, a.text-primary:focus { + color: #0056b3 !important; +} + +.text-secondary { + color: #6c757d !important; +} + +a.text-secondary:hover, a.text-secondary:focus { + color: #494f54 !important; +} + +.text-success { + color: #28a745 !important; +} + +a.text-success:hover, a.text-success:focus { + color: #19692c !important; +} + +.text-info { + color: #17a2b8 !important; +} + +a.text-info:hover, a.text-info:focus { + color: #0f6674 !important; +} + +.text-warning { + color: #ffc107 !important; +} + +a.text-warning:hover, a.text-warning:focus { + color: #ba8b00 !important; +} + +.text-danger { + color: #dc3545 !important; +} + +a.text-danger:hover, a.text-danger:focus { + color: #a71d2a !important; +} + +.text-light { + color: #f8f9fa !important; +} + +a.text-light:hover, a.text-light:focus { + color: #cbd3da !important; +} + +.text-dark { + color: #343a40 !important; +} + +a.text-dark:hover, a.text-dark:focus { + color: #121416 !important; +} + +.text-body { + color: #212529 !important; +} + +.text-muted { + color: #6c757d !important; +} + +.text-black-50 { + color: rgba(0, 0, 0, 0.5) !important; +} + +.text-white-50 { + color: rgba(255, 255, 255, 0.5) !important; +} + +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.text-decoration-none { + text-decoration: none !important; +} + +.text-reset { + color: inherit !important; +} + +.visible { + visibility: visible !important; +} + +.invisible { + visibility: hidden !important; +} + +@media print { + *, + *::before, + *::after { + text-shadow: none !important; + box-shadow: none !important; + } + a:not(.btn) { + text-decoration: underline; + } + abbr[title]::after { + content: " (" attr(title) ")"; + } + pre { + white-space: pre-wrap !important; + } + pre, + blockquote { + border: 1px solid #adb5bd; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + @page { + size: a3; + } + body { + min-width: 992px !important; + } + .container { + min-width: 992px !important; + } + .navbar { + display: none; + } + .badge { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table td, + .table th { + background-color: #fff !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #dee2e6 !important; + } + .table-dark { + color: inherit; + } + .table-dark th, + .table-dark td, + .table-dark thead th, + .table-dark tbody + tbody { + border-color: #dee2e6; + } + .table .thead-dark th { + color: inherit; + border-color: #dee2e6; + } +} +/*# sourceMappingURL=bootstrap.css.map */ \ No newline at end of file diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/bootstrap/js/bootstrap.bundle.js b/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/bootstrap/js/bootstrap.bundle.js new file mode 100644 index 0000000000..6fd1000b70 --- /dev/null +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/wwwroot/libs/bootstrap/js/bootstrap.bundle.js @@ -0,0 +1,6818 @@ +/*! + * Bootstrap v4.2.1 (https://getbootstrap.com/) + * Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery')) : + typeof define === 'function' && define.amd ? define(['exports', 'jquery'], factory) : + (factory((global.bootstrap = {}),global.jQuery)); +}(this, (function (exports,$) { 'use strict'; + + $ = $ && $.hasOwnProperty('default') ? $['default'] : $; + + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; + } + + function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; + } + + function _objectSpread(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] != null ? arguments[i] : {}; + var ownKeys = Object.keys(source); + + if (typeof Object.getOwnPropertySymbols === 'function') { + ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { + return Object.getOwnPropertyDescriptor(source, sym).enumerable; + })); + } + + ownKeys.forEach(function (key) { + _defineProperty(target, key, source[key]); + }); + } + + return target; + } + + function _inheritsLoose(subClass, superClass) { + subClass.prototype = Object.create(superClass.prototype); + subClass.prototype.constructor = subClass; + subClass.__proto__ = superClass; + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.2.1): util.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Private TransitionEnd Helpers + * ------------------------------------------------------------------------ + */ + + var TRANSITION_END = 'transitionend'; + var MAX_UID = 1000000; + var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp) + + function toType(obj) { + return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase(); + } + + function getSpecialTransitionEndEvent() { + return { + bindType: TRANSITION_END, + delegateType: TRANSITION_END, + handle: function handle(event) { + if ($(event.target).is(this)) { + return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params + } + + return undefined; // eslint-disable-line no-undefined + } + }; + } + + function transitionEndEmulator(duration) { + var _this = this; + + var called = false; + $(this).one(Util.TRANSITION_END, function () { + called = true; + }); + setTimeout(function () { + if (!called) { + Util.triggerTransitionEnd(_this); + } + }, duration); + return this; + } + + function setTransitionEndSupport() { + $.fn.emulateTransitionEnd = transitionEndEmulator; + $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent(); + } + /** + * -------------------------------------------------------------------------- + * Public Util Api + * -------------------------------------------------------------------------- + */ + + + var Util = { + TRANSITION_END: 'bsTransitionEnd', + getUID: function getUID(prefix) { + do { + // eslint-disable-next-line no-bitwise + prefix += ~~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here + } while (document.getElementById(prefix)); + + return prefix; + }, + getSelectorFromElement: function getSelectorFromElement(element) { + var selector = element.getAttribute('data-target'); + + if (!selector || selector === '#') { + var hrefAttr = element.getAttribute('href'); + selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : ''; + } + + return selector && document.querySelector(selector) ? selector : null; + }, + getTransitionDurationFromElement: function getTransitionDurationFromElement(element) { + if (!element) { + return 0; + } // Get transition-duration of the element + + + var transitionDuration = $(element).css('transition-duration'); + var transitionDelay = $(element).css('transition-delay'); + var floatTransitionDuration = parseFloat(transitionDuration); + var floatTransitionDelay = parseFloat(transitionDelay); // Return 0 if element or transition duration is not found + + if (!floatTransitionDuration && !floatTransitionDelay) { + return 0; + } // If multiple durations are defined, take the first + + + transitionDuration = transitionDuration.split(',')[0]; + transitionDelay = transitionDelay.split(',')[0]; + return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER; + }, + reflow: function reflow(element) { + return element.offsetHeight; + }, + triggerTransitionEnd: function triggerTransitionEnd(element) { + $(element).trigger(TRANSITION_END); + }, + // TODO: Remove in v5 + supportsTransitionEnd: function supportsTransitionEnd() { + return Boolean(TRANSITION_END); + }, + isElement: function isElement(obj) { + return (obj[0] || obj).nodeType; + }, + typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) { + for (var property in configTypes) { + if (Object.prototype.hasOwnProperty.call(configTypes, property)) { + var expectedTypes = configTypes[property]; + var value = config[property]; + var valueType = value && Util.isElement(value) ? 'element' : toType(value); + + if (!new RegExp(expectedTypes).test(valueType)) { + throw new Error(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\".")); + } + } + } + }, + findShadowRoot: function findShadowRoot(element) { + if (!document.documentElement.attachShadow) { + return null; + } // Can find the shadow root otherwise it'll return the document + + + if (typeof element.getRootNode === 'function') { + var root = element.getRootNode(); + return root instanceof ShadowRoot ? root : null; + } + + if (element instanceof ShadowRoot) { + return element; + } // when we don't find a shadow root + + + if (!element.parentNode) { + return null; + } + + return Util.findShadowRoot(element.parentNode); + } + }; + setTransitionEndSupport(); + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME = 'alert'; + var VERSION = '4.2.1'; + var DATA_KEY = 'bs.alert'; + var EVENT_KEY = "." + DATA_KEY; + var DATA_API_KEY = '.data-api'; + var JQUERY_NO_CONFLICT = $.fn[NAME]; + var Selector = { + DISMISS: '[data-dismiss="alert"]' + }; + var Event = { + CLOSE: "close" + EVENT_KEY, + CLOSED: "closed" + EVENT_KEY, + CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY + }; + var ClassName = { + ALERT: 'alert', + FADE: 'fade', + SHOW: 'show' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Alert = + /*#__PURE__*/ + function () { + function Alert(element) { + this._element = element; + } // Getters + + + var _proto = Alert.prototype; + + // Public + _proto.close = function close(element) { + var rootElement = this._element; + + if (element) { + rootElement = this._getRootElement(element); + } + + var customEvent = this._triggerCloseEvent(rootElement); + + if (customEvent.isDefaultPrevented()) { + return; + } + + this._removeElement(rootElement); + }; + + _proto.dispose = function dispose() { + $.removeData(this._element, DATA_KEY); + this._element = null; + }; // Private + + + _proto._getRootElement = function _getRootElement(element) { + var selector = Util.getSelectorFromElement(element); + var parent = false; + + if (selector) { + parent = document.querySelector(selector); + } + + if (!parent) { + parent = $(element).closest("." + ClassName.ALERT)[0]; + } + + return parent; + }; + + _proto._triggerCloseEvent = function _triggerCloseEvent(element) { + var closeEvent = $.Event(Event.CLOSE); + $(element).trigger(closeEvent); + return closeEvent; + }; + + _proto._removeElement = function _removeElement(element) { + var _this = this; + + $(element).removeClass(ClassName.SHOW); + + if (!$(element).hasClass(ClassName.FADE)) { + this._destroyElement(element); + + return; + } + + var transitionDuration = Util.getTransitionDurationFromElement(element); + $(element).one(Util.TRANSITION_END, function (event) { + return _this._destroyElement(element, event); + }).emulateTransitionEnd(transitionDuration); + }; + + _proto._destroyElement = function _destroyElement(element) { + $(element).detach().trigger(Event.CLOSED).remove(); + }; // Static + + + Alert._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var $element = $(this); + var data = $element.data(DATA_KEY); + + if (!data) { + data = new Alert(this); + $element.data(DATA_KEY, data); + } + + if (config === 'close') { + data[config](this); + } + }); + }; + + Alert._handleDismiss = function _handleDismiss(alertInstance) { + return function (event) { + if (event) { + event.preventDefault(); + } + + alertInstance.close(this); + }; + }; + + _createClass(Alert, null, [{ + key: "VERSION", + get: function get() { + return VERSION; + } + }]); + + return Alert; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert())); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME] = Alert._jQueryInterface; + $.fn[NAME].Constructor = Alert; + + $.fn[NAME].noConflict = function () { + $.fn[NAME] = JQUERY_NO_CONFLICT; + return Alert._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$1 = 'button'; + var VERSION$1 = '4.2.1'; + var DATA_KEY$1 = 'bs.button'; + var EVENT_KEY$1 = "." + DATA_KEY$1; + var DATA_API_KEY$1 = '.data-api'; + var JQUERY_NO_CONFLICT$1 = $.fn[NAME$1]; + var ClassName$1 = { + ACTIVE: 'active', + BUTTON: 'btn', + FOCUS: 'focus' + }; + var Selector$1 = { + DATA_TOGGLE_CARROT: '[data-toggle^="button"]', + DATA_TOGGLE: '[data-toggle="buttons"]', + INPUT: 'input:not([type="hidden"])', + ACTIVE: '.active', + BUTTON: '.btn' + }; + var Event$1 = { + CLICK_DATA_API: "click" + EVENT_KEY$1 + DATA_API_KEY$1, + FOCUS_BLUR_DATA_API: "focus" + EVENT_KEY$1 + DATA_API_KEY$1 + " " + ("blur" + EVENT_KEY$1 + DATA_API_KEY$1) + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Button = + /*#__PURE__*/ + function () { + function Button(element) { + this._element = element; + } // Getters + + + var _proto = Button.prototype; + + // Public + _proto.toggle = function toggle() { + var triggerChangeEvent = true; + var addAriaPressed = true; + var rootElement = $(this._element).closest(Selector$1.DATA_TOGGLE)[0]; + + if (rootElement) { + var input = this._element.querySelector(Selector$1.INPUT); + + if (input) { + if (input.type === 'radio') { + if (input.checked && this._element.classList.contains(ClassName$1.ACTIVE)) { + triggerChangeEvent = false; + } else { + var activeElement = rootElement.querySelector(Selector$1.ACTIVE); + + if (activeElement) { + $(activeElement).removeClass(ClassName$1.ACTIVE); + } + } + } + + if (triggerChangeEvent) { + if (input.hasAttribute('disabled') || rootElement.hasAttribute('disabled') || input.classList.contains('disabled') || rootElement.classList.contains('disabled')) { + return; + } + + input.checked = !this._element.classList.contains(ClassName$1.ACTIVE); + $(input).trigger('change'); + } + + input.focus(); + addAriaPressed = false; + } + } + + if (addAriaPressed) { + this._element.setAttribute('aria-pressed', !this._element.classList.contains(ClassName$1.ACTIVE)); + } + + if (triggerChangeEvent) { + $(this._element).toggleClass(ClassName$1.ACTIVE); + } + }; + + _proto.dispose = function dispose() { + $.removeData(this._element, DATA_KEY$1); + this._element = null; + }; // Static + + + Button._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $(this).data(DATA_KEY$1); + + if (!data) { + data = new Button(this); + $(this).data(DATA_KEY$1, data); + } + + if (config === 'toggle') { + data[config](); + } + }); + }; + + _createClass(Button, null, [{ + key: "VERSION", + get: function get() { + return VERSION$1; + } + }]); + + return Button; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event$1.CLICK_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) { + event.preventDefault(); + var button = event.target; + + if (!$(button).hasClass(ClassName$1.BUTTON)) { + button = $(button).closest(Selector$1.BUTTON); + } + + Button._jQueryInterface.call($(button), 'toggle'); + }).on(Event$1.FOCUS_BLUR_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) { + var button = $(event.target).closest(Selector$1.BUTTON)[0]; + $(button).toggleClass(ClassName$1.FOCUS, /^focus(in)?$/.test(event.type)); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME$1] = Button._jQueryInterface; + $.fn[NAME$1].Constructor = Button; + + $.fn[NAME$1].noConflict = function () { + $.fn[NAME$1] = JQUERY_NO_CONFLICT$1; + return Button._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$2 = 'carousel'; + var VERSION$2 = '4.2.1'; + var DATA_KEY$2 = 'bs.carousel'; + var EVENT_KEY$2 = "." + DATA_KEY$2; + var DATA_API_KEY$2 = '.data-api'; + var JQUERY_NO_CONFLICT$2 = $.fn[NAME$2]; + var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key + + var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key + + var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch + + var SWIPE_THRESHOLD = 40; + var Default = { + interval: 5000, + keyboard: true, + slide: false, + pause: 'hover', + wrap: true, + touch: true + }; + var DefaultType = { + interval: '(number|boolean)', + keyboard: 'boolean', + slide: '(boolean|string)', + pause: '(string|boolean)', + wrap: 'boolean', + touch: 'boolean' + }; + var Direction = { + NEXT: 'next', + PREV: 'prev', + LEFT: 'left', + RIGHT: 'right' + }; + var Event$2 = { + SLIDE: "slide" + EVENT_KEY$2, + SLID: "slid" + EVENT_KEY$2, + KEYDOWN: "keydown" + EVENT_KEY$2, + MOUSEENTER: "mouseenter" + EVENT_KEY$2, + MOUSELEAVE: "mouseleave" + EVENT_KEY$2, + TOUCHSTART: "touchstart" + EVENT_KEY$2, + TOUCHMOVE: "touchmove" + EVENT_KEY$2, + TOUCHEND: "touchend" + EVENT_KEY$2, + POINTERDOWN: "pointerdown" + EVENT_KEY$2, + POINTERUP: "pointerup" + EVENT_KEY$2, + DRAG_START: "dragstart" + EVENT_KEY$2, + LOAD_DATA_API: "load" + EVENT_KEY$2 + DATA_API_KEY$2, + CLICK_DATA_API: "click" + EVENT_KEY$2 + DATA_API_KEY$2 + }; + var ClassName$2 = { + CAROUSEL: 'carousel', + ACTIVE: 'active', + SLIDE: 'slide', + RIGHT: 'carousel-item-right', + LEFT: 'carousel-item-left', + NEXT: 'carousel-item-next', + PREV: 'carousel-item-prev', + ITEM: 'carousel-item', + POINTER_EVENT: 'pointer-event' + }; + var Selector$2 = { + ACTIVE: '.active', + ACTIVE_ITEM: '.active.carousel-item', + ITEM: '.carousel-item', + ITEM_IMG: '.carousel-item img', + NEXT_PREV: '.carousel-item-next, .carousel-item-prev', + INDICATORS: '.carousel-indicators', + DATA_SLIDE: '[data-slide], [data-slide-to]', + DATA_RIDE: '[data-ride="carousel"]' + }; + var PointerType = { + TOUCH: 'touch', + PEN: 'pen' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Carousel = + /*#__PURE__*/ + function () { + function Carousel(element, config) { + this._items = null; + this._interval = null; + this._activeElement = null; + this._isPaused = false; + this._isSliding = false; + this.touchTimeout = null; + this.touchStartX = 0; + this.touchDeltaX = 0; + this._config = this._getConfig(config); + this._element = element; + this._indicatorsElement = this._element.querySelector(Selector$2.INDICATORS); + this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0; + this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent); + + this._addEventListeners(); + } // Getters + + + var _proto = Carousel.prototype; + + // Public + _proto.next = function next() { + if (!this._isSliding) { + this._slide(Direction.NEXT); + } + }; + + _proto.nextWhenVisible = function nextWhenVisible() { + // Don't call next when the page isn't visible + // or the carousel or its parent isn't visible + if (!document.hidden && $(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden') { + this.next(); + } + }; + + _proto.prev = function prev() { + if (!this._isSliding) { + this._slide(Direction.PREV); + } + }; + + _proto.pause = function pause(event) { + if (!event) { + this._isPaused = true; + } + + if (this._element.querySelector(Selector$2.NEXT_PREV)) { + Util.triggerTransitionEnd(this._element); + this.cycle(true); + } + + clearInterval(this._interval); + this._interval = null; + }; + + _proto.cycle = function cycle(event) { + if (!event) { + this._isPaused = false; + } + + if (this._interval) { + clearInterval(this._interval); + this._interval = null; + } + + if (this._config.interval && !this._isPaused) { + this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval); + } + }; + + _proto.to = function to(index) { + var _this = this; + + this._activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM); + + var activeIndex = this._getItemIndex(this._activeElement); + + if (index > this._items.length - 1 || index < 0) { + return; + } + + if (this._isSliding) { + $(this._element).one(Event$2.SLID, function () { + return _this.to(index); + }); + return; + } + + if (activeIndex === index) { + this.pause(); + this.cycle(); + return; + } + + var direction = index > activeIndex ? Direction.NEXT : Direction.PREV; + + this._slide(direction, this._items[index]); + }; + + _proto.dispose = function dispose() { + $(this._element).off(EVENT_KEY$2); + $.removeData(this._element, DATA_KEY$2); + this._items = null; + this._config = null; + this._element = null; + this._interval = null; + this._isPaused = null; + this._isSliding = null; + this._activeElement = null; + this._indicatorsElement = null; + }; // Private + + + _proto._getConfig = function _getConfig(config) { + config = _objectSpread({}, Default, config); + Util.typeCheckConfig(NAME$2, config, DefaultType); + return config; + }; + + _proto._handleSwipe = function _handleSwipe() { + var absDeltax = Math.abs(this.touchDeltaX); + + if (absDeltax <= SWIPE_THRESHOLD) { + return; + } + + var direction = absDeltax / this.touchDeltaX; // swipe left + + if (direction > 0) { + this.prev(); + } // swipe right + + + if (direction < 0) { + this.next(); + } + }; + + _proto._addEventListeners = function _addEventListeners() { + var _this2 = this; + + if (this._config.keyboard) { + $(this._element).on(Event$2.KEYDOWN, function (event) { + return _this2._keydown(event); + }); + } + + if (this._config.pause === 'hover') { + $(this._element).on(Event$2.MOUSEENTER, function (event) { + return _this2.pause(event); + }).on(Event$2.MOUSELEAVE, function (event) { + return _this2.cycle(event); + }); + } + + this._addTouchEventListeners(); + }; + + _proto._addTouchEventListeners = function _addTouchEventListeners() { + var _this3 = this; + + if (!this._touchSupported) { + return; + } + + var start = function start(event) { + if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { + _this3.touchStartX = event.originalEvent.clientX; + } else if (!_this3._pointerEvent) { + _this3.touchStartX = event.originalEvent.touches[0].clientX; + } + }; + + var move = function move(event) { + // ensure swiping with one touch and not pinching + if (event.originalEvent.touches && event.originalEvent.touches.length > 1) { + _this3.touchDeltaX = 0; + } else { + _this3.touchDeltaX = event.originalEvent.touches[0].clientX - _this3.touchStartX; + } + }; + + var end = function end(event) { + if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { + _this3.touchDeltaX = event.originalEvent.clientX - _this3.touchStartX; + } + + _this3._handleSwipe(); + + if (_this3._config.pause === 'hover') { + // If it's a touch-enabled device, mouseenter/leave are fired as + // part of the mouse compatibility events on first tap - the carousel + // would stop cycling until user tapped out of it; + // here, we listen for touchend, explicitly pause the carousel + // (as if it's the second time we tap on it, mouseenter compat event + // is NOT fired) and after a timeout (to allow for mouse compatibility + // events to fire) we explicitly restart cycling + _this3.pause(); + + if (_this3.touchTimeout) { + clearTimeout(_this3.touchTimeout); + } + + _this3.touchTimeout = setTimeout(function (event) { + return _this3.cycle(event); + }, TOUCHEVENT_COMPAT_WAIT + _this3._config.interval); + } + }; + + $(this._element.querySelectorAll(Selector$2.ITEM_IMG)).on(Event$2.DRAG_START, function (e) { + return e.preventDefault(); + }); + + if (this._pointerEvent) { + $(this._element).on(Event$2.POINTERDOWN, function (event) { + return start(event); + }); + $(this._element).on(Event$2.POINTERUP, function (event) { + return end(event); + }); + + this._element.classList.add(ClassName$2.POINTER_EVENT); + } else { + $(this._element).on(Event$2.TOUCHSTART, function (event) { + return start(event); + }); + $(this._element).on(Event$2.TOUCHMOVE, function (event) { + return move(event); + }); + $(this._element).on(Event$2.TOUCHEND, function (event) { + return end(event); + }); + } + }; + + _proto._keydown = function _keydown(event) { + if (/input|textarea/i.test(event.target.tagName)) { + return; + } + + switch (event.which) { + case ARROW_LEFT_KEYCODE: + event.preventDefault(); + this.prev(); + break; + + case ARROW_RIGHT_KEYCODE: + event.preventDefault(); + this.next(); + break; + + default: + } + }; + + _proto._getItemIndex = function _getItemIndex(element) { + this._items = element && element.parentNode ? [].slice.call(element.parentNode.querySelectorAll(Selector$2.ITEM)) : []; + return this._items.indexOf(element); + }; + + _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) { + var isNextDirection = direction === Direction.NEXT; + var isPrevDirection = direction === Direction.PREV; + + var activeIndex = this._getItemIndex(activeElement); + + var lastItemIndex = this._items.length - 1; + var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex; + + if (isGoingToWrap && !this._config.wrap) { + return activeElement; + } + + var delta = direction === Direction.PREV ? -1 : 1; + var itemIndex = (activeIndex + delta) % this._items.length; + return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex]; + }; + + _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) { + var targetIndex = this._getItemIndex(relatedTarget); + + var fromIndex = this._getItemIndex(this._element.querySelector(Selector$2.ACTIVE_ITEM)); + + var slideEvent = $.Event(Event$2.SLIDE, { + relatedTarget: relatedTarget, + direction: eventDirectionName, + from: fromIndex, + to: targetIndex + }); + $(this._element).trigger(slideEvent); + return slideEvent; + }; + + _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) { + if (this._indicatorsElement) { + var indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector$2.ACTIVE)); + $(indicators).removeClass(ClassName$2.ACTIVE); + + var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)]; + + if (nextIndicator) { + $(nextIndicator).addClass(ClassName$2.ACTIVE); + } + } + }; + + _proto._slide = function _slide(direction, element) { + var _this4 = this; + + var activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM); + + var activeElementIndex = this._getItemIndex(activeElement); + + var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement); + + var nextElementIndex = this._getItemIndex(nextElement); + + var isCycling = Boolean(this._interval); + var directionalClassName; + var orderClassName; + var eventDirectionName; + + if (direction === Direction.NEXT) { + directionalClassName = ClassName$2.LEFT; + orderClassName = ClassName$2.NEXT; + eventDirectionName = Direction.LEFT; + } else { + directionalClassName = ClassName$2.RIGHT; + orderClassName = ClassName$2.PREV; + eventDirectionName = Direction.RIGHT; + } + + if (nextElement && $(nextElement).hasClass(ClassName$2.ACTIVE)) { + this._isSliding = false; + return; + } + + var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName); + + if (slideEvent.isDefaultPrevented()) { + return; + } + + if (!activeElement || !nextElement) { + // Some weirdness is happening, so we bail + return; + } + + this._isSliding = true; + + if (isCycling) { + this.pause(); + } + + this._setActiveIndicatorElement(nextElement); + + var slidEvent = $.Event(Event$2.SLID, { + relatedTarget: nextElement, + direction: eventDirectionName, + from: activeElementIndex, + to: nextElementIndex + }); + + if ($(this._element).hasClass(ClassName$2.SLIDE)) { + $(nextElement).addClass(orderClassName); + Util.reflow(nextElement); + $(activeElement).addClass(directionalClassName); + $(nextElement).addClass(directionalClassName); + var nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10); + + if (nextElementInterval) { + this._config.defaultInterval = this._config.defaultInterval || this._config.interval; + this._config.interval = nextElementInterval; + } else { + this._config.interval = this._config.defaultInterval || this._config.interval; + } + + var transitionDuration = Util.getTransitionDurationFromElement(activeElement); + $(activeElement).one(Util.TRANSITION_END, function () { + $(nextElement).removeClass(directionalClassName + " " + orderClassName).addClass(ClassName$2.ACTIVE); + $(activeElement).removeClass(ClassName$2.ACTIVE + " " + orderClassName + " " + directionalClassName); + _this4._isSliding = false; + setTimeout(function () { + return $(_this4._element).trigger(slidEvent); + }, 0); + }).emulateTransitionEnd(transitionDuration); + } else { + $(activeElement).removeClass(ClassName$2.ACTIVE); + $(nextElement).addClass(ClassName$2.ACTIVE); + this._isSliding = false; + $(this._element).trigger(slidEvent); + } + + if (isCycling) { + this.cycle(); + } + }; // Static + + + Carousel._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $(this).data(DATA_KEY$2); + + var _config = _objectSpread({}, Default, $(this).data()); + + if (typeof config === 'object') { + _config = _objectSpread({}, _config, config); + } + + var action = typeof config === 'string' ? config : _config.slide; + + if (!data) { + data = new Carousel(this, _config); + $(this).data(DATA_KEY$2, data); + } + + if (typeof config === 'number') { + data.to(config); + } else if (typeof action === 'string') { + if (typeof data[action] === 'undefined') { + throw new TypeError("No method named \"" + action + "\""); + } + + data[action](); + } else if (_config.interval) { + data.pause(); + data.cycle(); + } + }); + }; + + Carousel._dataApiClickHandler = function _dataApiClickHandler(event) { + var selector = Util.getSelectorFromElement(this); + + if (!selector) { + return; + } + + var target = $(selector)[0]; + + if (!target || !$(target).hasClass(ClassName$2.CAROUSEL)) { + return; + } + + var config = _objectSpread({}, $(target).data(), $(this).data()); + + var slideIndex = this.getAttribute('data-slide-to'); + + if (slideIndex) { + config.interval = false; + } + + Carousel._jQueryInterface.call($(target), config); + + if (slideIndex) { + $(target).data(DATA_KEY$2).to(slideIndex); + } + + event.preventDefault(); + }; + + _createClass(Carousel, null, [{ + key: "VERSION", + get: function get() { + return VERSION$2; + } + }, { + key: "Default", + get: function get() { + return Default; + } + }]); + + return Carousel; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event$2.CLICK_DATA_API, Selector$2.DATA_SLIDE, Carousel._dataApiClickHandler); + $(window).on(Event$2.LOAD_DATA_API, function () { + var carousels = [].slice.call(document.querySelectorAll(Selector$2.DATA_RIDE)); + + for (var i = 0, len = carousels.length; i < len; i++) { + var $carousel = $(carousels[i]); + + Carousel._jQueryInterface.call($carousel, $carousel.data()); + } + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME$2] = Carousel._jQueryInterface; + $.fn[NAME$2].Constructor = Carousel; + + $.fn[NAME$2].noConflict = function () { + $.fn[NAME$2] = JQUERY_NO_CONFLICT$2; + return Carousel._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$3 = 'collapse'; + var VERSION$3 = '4.2.1'; + var DATA_KEY$3 = 'bs.collapse'; + var EVENT_KEY$3 = "." + DATA_KEY$3; + var DATA_API_KEY$3 = '.data-api'; + var JQUERY_NO_CONFLICT$3 = $.fn[NAME$3]; + var Default$1 = { + toggle: true, + parent: '' + }; + var DefaultType$1 = { + toggle: 'boolean', + parent: '(string|element)' + }; + var Event$3 = { + SHOW: "show" + EVENT_KEY$3, + SHOWN: "shown" + EVENT_KEY$3, + HIDE: "hide" + EVENT_KEY$3, + HIDDEN: "hidden" + EVENT_KEY$3, + CLICK_DATA_API: "click" + EVENT_KEY$3 + DATA_API_KEY$3 + }; + var ClassName$3 = { + SHOW: 'show', + COLLAPSE: 'collapse', + COLLAPSING: 'collapsing', + COLLAPSED: 'collapsed' + }; + var Dimension = { + WIDTH: 'width', + HEIGHT: 'height' + }; + var Selector$3 = { + ACTIVES: '.show, .collapsing', + DATA_TOGGLE: '[data-toggle="collapse"]' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Collapse = + /*#__PURE__*/ + function () { + function Collapse(element, config) { + this._isTransitioning = false; + this._element = element; + this._config = this._getConfig(config); + this._triggerArray = [].slice.call(document.querySelectorAll("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]"))); + var toggleList = [].slice.call(document.querySelectorAll(Selector$3.DATA_TOGGLE)); + + for (var i = 0, len = toggleList.length; i < len; i++) { + var elem = toggleList[i]; + var selector = Util.getSelectorFromElement(elem); + var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) { + return foundElem === element; + }); + + if (selector !== null && filterElement.length > 0) { + this._selector = selector; + + this._triggerArray.push(elem); + } + } + + this._parent = this._config.parent ? this._getParent() : null; + + if (!this._config.parent) { + this._addAriaAndCollapsedClass(this._element, this._triggerArray); + } + + if (this._config.toggle) { + this.toggle(); + } + } // Getters + + + var _proto = Collapse.prototype; + + // Public + _proto.toggle = function toggle() { + if ($(this._element).hasClass(ClassName$3.SHOW)) { + this.hide(); + } else { + this.show(); + } + }; + + _proto.show = function show() { + var _this = this; + + if (this._isTransitioning || $(this._element).hasClass(ClassName$3.SHOW)) { + return; + } + + var actives; + var activesData; + + if (this._parent) { + actives = [].slice.call(this._parent.querySelectorAll(Selector$3.ACTIVES)).filter(function (elem) { + if (typeof _this._config.parent === 'string') { + return elem.getAttribute('data-parent') === _this._config.parent; + } + + return elem.classList.contains(ClassName$3.COLLAPSE); + }); + + if (actives.length === 0) { + actives = null; + } + } + + if (actives) { + activesData = $(actives).not(this._selector).data(DATA_KEY$3); + + if (activesData && activesData._isTransitioning) { + return; + } + } + + var startEvent = $.Event(Event$3.SHOW); + $(this._element).trigger(startEvent); + + if (startEvent.isDefaultPrevented()) { + return; + } + + if (actives) { + Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide'); + + if (!activesData) { + $(actives).data(DATA_KEY$3, null); + } + } + + var dimension = this._getDimension(); + + $(this._element).removeClass(ClassName$3.COLLAPSE).addClass(ClassName$3.COLLAPSING); + this._element.style[dimension] = 0; + + if (this._triggerArray.length) { + $(this._triggerArray).removeClass(ClassName$3.COLLAPSED).attr('aria-expanded', true); + } + + this.setTransitioning(true); + + var complete = function complete() { + $(_this._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).addClass(ClassName$3.SHOW); + _this._element.style[dimension] = ''; + + _this.setTransitioning(false); + + $(_this._element).trigger(Event$3.SHOWN); + }; + + var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); + var scrollSize = "scroll" + capitalizedDimension; + var transitionDuration = Util.getTransitionDurationFromElement(this._element); + $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); + this._element.style[dimension] = this._element[scrollSize] + "px"; + }; + + _proto.hide = function hide() { + var _this2 = this; + + if (this._isTransitioning || !$(this._element).hasClass(ClassName$3.SHOW)) { + return; + } + + var startEvent = $.Event(Event$3.HIDE); + $(this._element).trigger(startEvent); + + if (startEvent.isDefaultPrevented()) { + return; + } + + var dimension = this._getDimension(); + + this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px"; + Util.reflow(this._element); + $(this._element).addClass(ClassName$3.COLLAPSING).removeClass(ClassName$3.COLLAPSE).removeClass(ClassName$3.SHOW); + var triggerArrayLength = this._triggerArray.length; + + if (triggerArrayLength > 0) { + for (var i = 0; i < triggerArrayLength; i++) { + var trigger = this._triggerArray[i]; + var selector = Util.getSelectorFromElement(trigger); + + if (selector !== null) { + var $elem = $([].slice.call(document.querySelectorAll(selector))); + + if (!$elem.hasClass(ClassName$3.SHOW)) { + $(trigger).addClass(ClassName$3.COLLAPSED).attr('aria-expanded', false); + } + } + } + } + + this.setTransitioning(true); + + var complete = function complete() { + _this2.setTransitioning(false); + + $(_this2._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).trigger(Event$3.HIDDEN); + }; + + this._element.style[dimension] = ''; + var transitionDuration = Util.getTransitionDurationFromElement(this._element); + $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); + }; + + _proto.setTransitioning = function setTransitioning(isTransitioning) { + this._isTransitioning = isTransitioning; + }; + + _proto.dispose = function dispose() { + $.removeData(this._element, DATA_KEY$3); + this._config = null; + this._parent = null; + this._element = null; + this._triggerArray = null; + this._isTransitioning = null; + }; // Private + + + _proto._getConfig = function _getConfig(config) { + config = _objectSpread({}, Default$1, config); + config.toggle = Boolean(config.toggle); // Coerce string values + + Util.typeCheckConfig(NAME$3, config, DefaultType$1); + return config; + }; + + _proto._getDimension = function _getDimension() { + var hasWidth = $(this._element).hasClass(Dimension.WIDTH); + return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT; + }; + + _proto._getParent = function _getParent() { + var _this3 = this; + + var parent; + + if (Util.isElement(this._config.parent)) { + parent = this._config.parent; // It's a jQuery object + + if (typeof this._config.parent.jquery !== 'undefined') { + parent = this._config.parent[0]; + } + } else { + parent = document.querySelector(this._config.parent); + } + + var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]"; + var children = [].slice.call(parent.querySelectorAll(selector)); + $(children).each(function (i, element) { + _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]); + }); + return parent; + }; + + _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) { + var isOpen = $(element).hasClass(ClassName$3.SHOW); + + if (triggerArray.length) { + $(triggerArray).toggleClass(ClassName$3.COLLAPSED, !isOpen).attr('aria-expanded', isOpen); + } + }; // Static + + + Collapse._getTargetFromElement = function _getTargetFromElement(element) { + var selector = Util.getSelectorFromElement(element); + return selector ? document.querySelector(selector) : null; + }; + + Collapse._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DATA_KEY$3); + + var _config = _objectSpread({}, Default$1, $this.data(), typeof config === 'object' && config ? config : {}); + + if (!data && _config.toggle && /show|hide/.test(config)) { + _config.toggle = false; + } + + if (!data) { + data = new Collapse(this, _config); + $this.data(DATA_KEY$3, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](); + } + }); + }; + + _createClass(Collapse, null, [{ + key: "VERSION", + get: function get() { + return VERSION$3; + } + }, { + key: "Default", + get: function get() { + return Default$1; + } + }]); + + return Collapse; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event$3.CLICK_DATA_API, Selector$3.DATA_TOGGLE, function (event) { + // preventDefault only for elements (which change the URL) not inside the collapsible element + if (event.currentTarget.tagName === 'A') { + event.preventDefault(); + } + + var $trigger = $(this); + var selector = Util.getSelectorFromElement(this); + var selectors = [].slice.call(document.querySelectorAll(selector)); + $(selectors).each(function () { + var $target = $(this); + var data = $target.data(DATA_KEY$3); + var config = data ? 'toggle' : $trigger.data(); + + Collapse._jQueryInterface.call($target, config); + }); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME$3] = Collapse._jQueryInterface; + $.fn[NAME$3].Constructor = Collapse; + + $.fn[NAME$3].noConflict = function () { + $.fn[NAME$3] = JQUERY_NO_CONFLICT$3; + return Collapse._jQueryInterface; + }; + + /**! + * @fileOverview Kickass library to create and place poppers near their reference elements. + * @version 1.14.6 + * @license + * Copyright (c) 2016 Federico Zivolo and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined'; + + var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox']; + var timeoutDuration = 0; + for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) { + if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) { + timeoutDuration = 1; + break; + } + } + + function microtaskDebounce(fn) { + var called = false; + return function () { + if (called) { + return; + } + called = true; + window.Promise.resolve().then(function () { + called = false; + fn(); + }); + }; + } + + function taskDebounce(fn) { + var scheduled = false; + return function () { + if (!scheduled) { + scheduled = true; + setTimeout(function () { + scheduled = false; + fn(); + }, timeoutDuration); + } + }; + } + + var supportsMicroTasks = isBrowser && window.Promise; + + /** + * Create a debounced version of a method, that's asynchronously deferred + * but called in the minimum time possible. + * + * @method + * @memberof Popper.Utils + * @argument {Function} fn + * @returns {Function} + */ + var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce; + + /** + * Check if the given variable is a function + * @method + * @memberof Popper.Utils + * @argument {Any} functionToCheck - variable to check + * @returns {Boolean} answer to: is a function? + */ + function isFunction(functionToCheck) { + var getType = {}; + return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; + } + + /** + * Get CSS computed property of the given element + * @method + * @memberof Popper.Utils + * @argument {Eement} element + * @argument {String} property + */ + function getStyleComputedProperty(element, property) { + if (element.nodeType !== 1) { + return []; + } + // NOTE: 1 DOM access here + var window = element.ownerDocument.defaultView; + var css = window.getComputedStyle(element, null); + return property ? css[property] : css; + } + + /** + * Returns the parentNode or the host of the element + * @method + * @memberof Popper.Utils + * @argument {Element} element + * @returns {Element} parent + */ + function getParentNode(element) { + if (element.nodeName === 'HTML') { + return element; + } + return element.parentNode || element.host; + } + + /** + * Returns the scrolling parent of the given element + * @method + * @memberof Popper.Utils + * @argument {Element} element + * @returns {Element} scroll parent + */ + function getScrollParent(element) { + // Return body, `getScroll` will take care to get the correct `scrollTop` from it + if (!element) { + return document.body; + } + + switch (element.nodeName) { + case 'HTML': + case 'BODY': + return element.ownerDocument.body; + case '#document': + return element.body; + } + + // Firefox want us to check `-x` and `-y` variations as well + + var _getStyleComputedProp = getStyleComputedProperty(element), + overflow = _getStyleComputedProp.overflow, + overflowX = _getStyleComputedProp.overflowX, + overflowY = _getStyleComputedProp.overflowY; + + if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) { + return element; + } + + return getScrollParent(getParentNode(element)); + } + + var isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode); + var isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent); + + /** + * Determines if the browser is Internet Explorer + * @method + * @memberof Popper.Utils + * @param {Number} version to check + * @returns {Boolean} isIE + */ + function isIE(version) { + if (version === 11) { + return isIE11; + } + if (version === 10) { + return isIE10; + } + return isIE11 || isIE10; + } + + /** + * Returns the offset parent of the given element + * @method + * @memberof Popper.Utils + * @argument {Element} element + * @returns {Element} offset parent + */ + function getOffsetParent(element) { + if (!element) { + return document.documentElement; + } + + var noOffsetParent = isIE(10) ? document.body : null; + + // NOTE: 1 DOM access here + var offsetParent = element.offsetParent || null; + // Skip hidden elements which don't have an offsetParent + while (offsetParent === noOffsetParent && element.nextElementSibling) { + offsetParent = (element = element.nextElementSibling).offsetParent; + } + + var nodeName = offsetParent && offsetParent.nodeName; + + if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') { + return element ? element.ownerDocument.documentElement : document.documentElement; + } + + // .offsetParent will return the closest TH, TD or TABLE in case + // no offsetParent is present, I hate this job... + if (['TH', 'TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') { + return getOffsetParent(offsetParent); + } + + return offsetParent; + } + + function isOffsetContainer(element) { + var nodeName = element.nodeName; + + if (nodeName === 'BODY') { + return false; + } + return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element; + } + + /** + * Finds the root node (document, shadowDOM root) of the given element + * @method + * @memberof Popper.Utils + * @argument {Element} node + * @returns {Element} root node + */ + function getRoot(node) { + if (node.parentNode !== null) { + return getRoot(node.parentNode); + } + + return node; + } + + /** + * Finds the offset parent common to the two provided nodes + * @method + * @memberof Popper.Utils + * @argument {Element} element1 + * @argument {Element} element2 + * @returns {Element} common offset parent + */ + function findCommonOffsetParent(element1, element2) { + // This check is needed to avoid errors in case one of the elements isn't defined for any reason + if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) { + return document.documentElement; + } + + // Here we make sure to give as "start" the element that comes first in the DOM + var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING; + var start = order ? element1 : element2; + var end = order ? element2 : element1; + + // Get common ancestor container + var range = document.createRange(); + range.setStart(start, 0); + range.setEnd(end, 0); + var commonAncestorContainer = range.commonAncestorContainer; + + // Both nodes are inside #document + + if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) { + if (isOffsetContainer(commonAncestorContainer)) { + return commonAncestorContainer; + } + + return getOffsetParent(commonAncestorContainer); + } + + // one of the nodes is inside shadowDOM, find which one + var element1root = getRoot(element1); + if (element1root.host) { + return findCommonOffsetParent(element1root.host, element2); + } else { + return findCommonOffsetParent(element1, getRoot(element2).host); + } + } + + /** + * Gets the scroll value of the given element in the given side (top and left) + * @method + * @memberof Popper.Utils + * @argument {Element} element + * @argument {String} side `top` or `left` + * @returns {number} amount of scrolled pixels + */ + function getScroll(element) { + var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top'; + + var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft'; + var nodeName = element.nodeName; + + if (nodeName === 'BODY' || nodeName === 'HTML') { + var html = element.ownerDocument.documentElement; + var scrollingElement = element.ownerDocument.scrollingElement || html; + return scrollingElement[upperSide]; + } + + return element[upperSide]; + } + + /* + * Sum or subtract the element scroll values (left and top) from a given rect object + * @method + * @memberof Popper.Utils + * @param {Object} rect - Rect object you want to change + * @param {HTMLElement} element - The element from the function reads the scroll values + * @param {Boolean} subtract - set to true if you want to subtract the scroll values + * @return {Object} rect - The modifier rect object + */ + function includeScroll(rect, element) { + var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + var scrollTop = getScroll(element, 'top'); + var scrollLeft = getScroll(element, 'left'); + var modifier = subtract ? -1 : 1; + rect.top += scrollTop * modifier; + rect.bottom += scrollTop * modifier; + rect.left += scrollLeft * modifier; + rect.right += scrollLeft * modifier; + return rect; + } + + /* + * Helper to detect borders of a given element + * @method + * @memberof Popper.Utils + * @param {CSSStyleDeclaration} styles + * Result of `getStyleComputedProperty` on the given element + * @param {String} axis - `x` or `y` + * @return {number} borders - The borders size of the given axis + */ + + function getBordersSize(styles, axis) { + var sideA = axis === 'x' ? 'Left' : 'Top'; + var sideB = sideA === 'Left' ? 'Right' : 'Bottom'; + + return parseFloat(styles['border' + sideA + 'Width'], 10) + parseFloat(styles['border' + sideB + 'Width'], 10); + } + + function getSize(axis, body, html, computedStyle) { + return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE(10) ? parseInt(html['offset' + axis]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')]) : 0); + } + + function getWindowSizes(document) { + var body = document.body; + var html = document.documentElement; + var computedStyle = isIE(10) && getComputedStyle(html); + + return { + height: getSize('Height', body, html, computedStyle), + width: getSize('Width', body, html, computedStyle) + }; + } + + var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + }; + + var createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + + + + + var defineProperty = function (obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; + }; + + var _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + /** + * Given element offsets, generate an output similar to getBoundingClientRect + * @method + * @memberof Popper.Utils + * @argument {Object} offsets + * @returns {Object} ClientRect like output + */ + function getClientRect(offsets) { + return _extends({}, offsets, { + right: offsets.left + offsets.width, + bottom: offsets.top + offsets.height + }); + } + + /** + * Get bounding client rect of given element + * @method + * @memberof Popper.Utils + * @param {HTMLElement} element + * @return {Object} client rect + */ + function getBoundingClientRect(element) { + var rect = {}; + + // IE10 10 FIX: Please, don't ask, the element isn't + // considered in DOM in some circumstances... + // This isn't reproducible in IE10 compatibility mode of IE11 + try { + if (isIE(10)) { + rect = element.getBoundingClientRect(); + var scrollTop = getScroll(element, 'top'); + var scrollLeft = getScroll(element, 'left'); + rect.top += scrollTop; + rect.left += scrollLeft; + rect.bottom += scrollTop; + rect.right += scrollLeft; + } else { + rect = element.getBoundingClientRect(); + } + } catch (e) {} + + var result = { + left: rect.left, + top: rect.top, + width: rect.right - rect.left, + height: rect.bottom - rect.top + }; + + // subtract scrollbar size from sizes + var sizes = element.nodeName === 'HTML' ? getWindowSizes(element.ownerDocument) : {}; + var width = sizes.width || element.clientWidth || result.right - result.left; + var height = sizes.height || element.clientHeight || result.bottom - result.top; + + var horizScrollbar = element.offsetWidth - width; + var vertScrollbar = element.offsetHeight - height; + + // if an hypothetical scrollbar is detected, we must be sure it's not a `border` + // we make this check conditional for performance reasons + if (horizScrollbar || vertScrollbar) { + var styles = getStyleComputedProperty(element); + horizScrollbar -= getBordersSize(styles, 'x'); + vertScrollbar -= getBordersSize(styles, 'y'); + + result.width -= horizScrollbar; + result.height -= vertScrollbar; + } + + return getClientRect(result); + } + + function getOffsetRectRelativeToArbitraryNode(children, parent) { + var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + var isIE10 = isIE(10); + var isHTML = parent.nodeName === 'HTML'; + var childrenRect = getBoundingClientRect(children); + var parentRect = getBoundingClientRect(parent); + var scrollParent = getScrollParent(children); + + var styles = getStyleComputedProperty(parent); + var borderTopWidth = parseFloat(styles.borderTopWidth, 10); + var borderLeftWidth = parseFloat(styles.borderLeftWidth, 10); + + // In cases where the parent is fixed, we must ignore negative scroll in offset calc + if (fixedPosition && isHTML) { + parentRect.top = Math.max(parentRect.top, 0); + parentRect.left = Math.max(parentRect.left, 0); + } + var offsets = getClientRect({ + top: childrenRect.top - parentRect.top - borderTopWidth, + left: childrenRect.left - parentRect.left - borderLeftWidth, + width: childrenRect.width, + height: childrenRect.height + }); + offsets.marginTop = 0; + offsets.marginLeft = 0; + + // Subtract margins of documentElement in case it's being used as parent + // we do this only on HTML because it's the only element that behaves + // differently when margins are applied to it. The margins are included in + // the box of the documentElement, in the other cases not. + if (!isIE10 && isHTML) { + var marginTop = parseFloat(styles.marginTop, 10); + var marginLeft = parseFloat(styles.marginLeft, 10); + + offsets.top -= borderTopWidth - marginTop; + offsets.bottom -= borderTopWidth - marginTop; + offsets.left -= borderLeftWidth - marginLeft; + offsets.right -= borderLeftWidth - marginLeft; + + // Attach marginTop and marginLeft because in some circumstances we may need them + offsets.marginTop = marginTop; + offsets.marginLeft = marginLeft; + } + + if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') { + offsets = includeScroll(offsets, parent); + } + + return offsets; + } + + function getViewportOffsetRectRelativeToArtbitraryNode(element) { + var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + var html = element.ownerDocument.documentElement; + var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html); + var width = Math.max(html.clientWidth, window.innerWidth || 0); + var height = Math.max(html.clientHeight, window.innerHeight || 0); + + var scrollTop = !excludeScroll ? getScroll(html) : 0; + var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0; + + var offset = { + top: scrollTop - relativeOffset.top + relativeOffset.marginTop, + left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft, + width: width, + height: height + }; + + return getClientRect(offset); + } + + /** + * Check if the given element is fixed or is inside a fixed parent + * @method + * @memberof Popper.Utils + * @argument {Element} element + * @argument {Element} customContainer + * @returns {Boolean} answer to "isFixed?" + */ + function isFixed(element) { + var nodeName = element.nodeName; + if (nodeName === 'BODY' || nodeName === 'HTML') { + return false; + } + if (getStyleComputedProperty(element, 'position') === 'fixed') { + return true; + } + return isFixed(getParentNode(element)); + } + + /** + * Finds the first parent of an element that has a transformed property defined + * @method + * @memberof Popper.Utils + * @argument {Element} element + * @returns {Element} first transformed parent or documentElement + */ + + function getFixedPositionOffsetParent(element) { + // This check is needed to avoid errors in case one of the elements isn't defined for any reason + if (!element || !element.parentElement || isIE()) { + return document.documentElement; + } + var el = element.parentElement; + while (el && getStyleComputedProperty(el, 'transform') === 'none') { + el = el.parentElement; + } + return el || document.documentElement; + } + + /** + * Computed the boundaries limits and return them + * @method + * @memberof Popper.Utils + * @param {HTMLElement} popper + * @param {HTMLElement} reference + * @param {number} padding + * @param {HTMLElement} boundariesElement - Element used to define the boundaries + * @param {Boolean} fixedPosition - Is in fixed position mode + * @returns {Object} Coordinates of the boundaries + */ + function getBoundaries(popper, reference, padding, boundariesElement) { + var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; + + // NOTE: 1 DOM access here + + var boundaries = { top: 0, left: 0 }; + var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference); + + // Handle viewport case + if (boundariesElement === 'viewport') { + boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition); + } else { + // Handle other cases based on DOM element used as boundaries + var boundariesNode = void 0; + if (boundariesElement === 'scrollParent') { + boundariesNode = getScrollParent(getParentNode(reference)); + if (boundariesNode.nodeName === 'BODY') { + boundariesNode = popper.ownerDocument.documentElement; + } + } else if (boundariesElement === 'window') { + boundariesNode = popper.ownerDocument.documentElement; + } else { + boundariesNode = boundariesElement; + } + + var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition); + + // In case of HTML, we need a different computation + if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) { + var _getWindowSizes = getWindowSizes(popper.ownerDocument), + height = _getWindowSizes.height, + width = _getWindowSizes.width; + + boundaries.top += offsets.top - offsets.marginTop; + boundaries.bottom = height + offsets.top; + boundaries.left += offsets.left - offsets.marginLeft; + boundaries.right = width + offsets.left; + } else { + // for all the other DOM elements, this one is good + boundaries = offsets; + } + } + + // Add paddings + padding = padding || 0; + var isPaddingNumber = typeof padding === 'number'; + boundaries.left += isPaddingNumber ? padding : padding.left || 0; + boundaries.top += isPaddingNumber ? padding : padding.top || 0; + boundaries.right -= isPaddingNumber ? padding : padding.right || 0; + boundaries.bottom -= isPaddingNumber ? padding : padding.bottom || 0; + + return boundaries; + } + + function getArea(_ref) { + var width = _ref.width, + height = _ref.height; + + return width * height; + } + + /** + * Utility used to transform the `auto` placement to the placement with more + * available space. + * @method + * @memberof Popper.Utils + * @argument {Object} data - The data object generated by update method + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The data object, properly modified + */ + function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) { + var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0; + + if (placement.indexOf('auto') === -1) { + return placement; + } + + var boundaries = getBoundaries(popper, reference, padding, boundariesElement); + + var rects = { + top: { + width: boundaries.width, + height: refRect.top - boundaries.top + }, + right: { + width: boundaries.right - refRect.right, + height: boundaries.height + }, + bottom: { + width: boundaries.width, + height: boundaries.bottom - refRect.bottom + }, + left: { + width: refRect.left - boundaries.left, + height: boundaries.height + } + }; + + var sortedAreas = Object.keys(rects).map(function (key) { + return _extends({ + key: key + }, rects[key], { + area: getArea(rects[key]) + }); + }).sort(function (a, b) { + return b.area - a.area; + }); + + var filteredAreas = sortedAreas.filter(function (_ref2) { + var width = _ref2.width, + height = _ref2.height; + return width >= popper.clientWidth && height >= popper.clientHeight; + }); + + var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key; + + var variation = placement.split('-')[1]; + + return computedPlacement + (variation ? '-' + variation : ''); + } + + /** + * Get offsets to the reference element + * @method + * @memberof Popper.Utils + * @param {Object} state + * @param {Element} popper - the popper element + * @param {Element} reference - the reference element (the popper will be relative to this) + * @param {Element} fixedPosition - is in fixed position mode + * @returns {Object} An object containing the offsets which will be applied to the popper + */ + function getReferenceOffsets(state, popper, reference) { + var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + + var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference); + return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition); + } + + /** + * Get the outer sizes of the given element (offset size + margins) + * @method + * @memberof Popper.Utils + * @argument {Element} element + * @returns {Object} object containing width and height properties + */ + function getOuterSizes(element) { + var window = element.ownerDocument.defaultView; + var styles = window.getComputedStyle(element); + var x = parseFloat(styles.marginTop || 0) + parseFloat(styles.marginBottom || 0); + var y = parseFloat(styles.marginLeft || 0) + parseFloat(styles.marginRight || 0); + var result = { + width: element.offsetWidth + y, + height: element.offsetHeight + x + }; + return result; + } + + /** + * Get the opposite placement of the given one + * @method + * @memberof Popper.Utils + * @argument {String} placement + * @returns {String} flipped placement + */ + function getOppositePlacement(placement) { + var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' }; + return placement.replace(/left|right|bottom|top/g, function (matched) { + return hash[matched]; + }); + } + + /** + * Get offsets to the popper + * @method + * @memberof Popper.Utils + * @param {Object} position - CSS position the Popper will get applied + * @param {HTMLElement} popper - the popper element + * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this) + * @param {String} placement - one of the valid placement options + * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper + */ + function getPopperOffsets(popper, referenceOffsets, placement) { + placement = placement.split('-')[0]; + + // Get popper node sizes + var popperRect = getOuterSizes(popper); + + // Add position, width and height to our offsets object + var popperOffsets = { + width: popperRect.width, + height: popperRect.height + }; + + // depending by the popper placement we have to compute its offsets slightly differently + var isHoriz = ['right', 'left'].indexOf(placement) !== -1; + var mainSide = isHoriz ? 'top' : 'left'; + var secondarySide = isHoriz ? 'left' : 'top'; + var measurement = isHoriz ? 'height' : 'width'; + var secondaryMeasurement = !isHoriz ? 'height' : 'width'; + + popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2; + if (placement === secondarySide) { + popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement]; + } else { + popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)]; + } + + return popperOffsets; + } + + /** + * Mimics the `find` method of Array + * @method + * @memberof Popper.Utils + * @argument {Array} arr + * @argument prop + * @argument value + * @returns index or -1 + */ + function find(arr, check) { + // use native find if supported + if (Array.prototype.find) { + return arr.find(check); + } + + // use `filter` to obtain the same behavior of `find` + return arr.filter(check)[0]; + } + + /** + * Return the index of the matching object + * @method + * @memberof Popper.Utils + * @argument {Array} arr + * @argument prop + * @argument value + * @returns index or -1 + */ + function findIndex(arr, prop, value) { + // use native findIndex if supported + if (Array.prototype.findIndex) { + return arr.findIndex(function (cur) { + return cur[prop] === value; + }); + } + + // use `find` + `indexOf` if `findIndex` isn't supported + var match = find(arr, function (obj) { + return obj[prop] === value; + }); + return arr.indexOf(match); + } + + /** + * Loop trough the list of modifiers and run them in order, + * each of them will then edit the data object. + * @method + * @memberof Popper.Utils + * @param {dataObject} data + * @param {Array} modifiers + * @param {String} ends - Optional modifier name used as stopper + * @returns {dataObject} + */ + function runModifiers(modifiers, data, ends) { + var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends)); + + modifiersToRun.forEach(function (modifier) { + if (modifier['function']) { + // eslint-disable-line dot-notation + console.warn('`modifier.function` is deprecated, use `modifier.fn`!'); + } + var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation + if (modifier.enabled && isFunction(fn)) { + // Add properties to offsets to make them a complete clientRect object + // we do this before each modifier to make sure the previous one doesn't + // mess with these values + data.offsets.popper = getClientRect(data.offsets.popper); + data.offsets.reference = getClientRect(data.offsets.reference); + + data = fn(data, modifier); + } + }); + + return data; + } + + /** + * Updates the position of the popper, computing the new offsets and applying + * the new style.
    + * Prefer `scheduleUpdate` over `update` because of performance reasons. + * @method + * @memberof Popper + */ + function update() { + // if popper is destroyed, don't perform any further update + if (this.state.isDestroyed) { + return; + } + + var data = { + instance: this, + styles: {}, + arrowStyles: {}, + attributes: {}, + flipped: false, + offsets: {} + }; + + // compute reference element offsets + data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed); + + // compute auto placement, store placement inside the data object, + // modifiers will be able to edit `placement` if needed + // and refer to originalPlacement to know the original value + data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding); + + // store the computed placement inside `originalPlacement` + data.originalPlacement = data.placement; + + data.positionFixed = this.options.positionFixed; + + // compute the popper offsets + data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement); + + data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute'; + + // run the modifiers + data = runModifiers(this.modifiers, data); + + // the first `update` will call `onCreate` callback + // the other ones will call `onUpdate` callback + if (!this.state.isCreated) { + this.state.isCreated = true; + this.options.onCreate(data); + } else { + this.options.onUpdate(data); + } + } + + /** + * Helper used to know if the given modifier is enabled. + * @method + * @memberof Popper.Utils + * @returns {Boolean} + */ + function isModifierEnabled(modifiers, modifierName) { + return modifiers.some(function (_ref) { + var name = _ref.name, + enabled = _ref.enabled; + return enabled && name === modifierName; + }); + } + + /** + * Get the prefixed supported property name + * @method + * @memberof Popper.Utils + * @argument {String} property (camelCase) + * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix) + */ + function getSupportedPropertyName(property) { + var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O']; + var upperProp = property.charAt(0).toUpperCase() + property.slice(1); + + for (var i = 0; i < prefixes.length; i++) { + var prefix = prefixes[i]; + var toCheck = prefix ? '' + prefix + upperProp : property; + if (typeof document.body.style[toCheck] !== 'undefined') { + return toCheck; + } + } + return null; + } + + /** + * Destroys the popper. + * @method + * @memberof Popper + */ + function destroy() { + this.state.isDestroyed = true; + + // touch DOM only if `applyStyle` modifier is enabled + if (isModifierEnabled(this.modifiers, 'applyStyle')) { + this.popper.removeAttribute('x-placement'); + this.popper.style.position = ''; + this.popper.style.top = ''; + this.popper.style.left = ''; + this.popper.style.right = ''; + this.popper.style.bottom = ''; + this.popper.style.willChange = ''; + this.popper.style[getSupportedPropertyName('transform')] = ''; + } + + this.disableEventListeners(); + + // remove the popper if user explicity asked for the deletion on destroy + // do not use `remove` because IE11 doesn't support it + if (this.options.removeOnDestroy) { + this.popper.parentNode.removeChild(this.popper); + } + return this; + } + + /** + * Get the window associated with the element + * @argument {Element} element + * @returns {Window} + */ + function getWindow(element) { + var ownerDocument = element.ownerDocument; + return ownerDocument ? ownerDocument.defaultView : window; + } + + function attachToScrollParents(scrollParent, event, callback, scrollParents) { + var isBody = scrollParent.nodeName === 'BODY'; + var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent; + target.addEventListener(event, callback, { passive: true }); + + if (!isBody) { + attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents); + } + scrollParents.push(target); + } + + /** + * Setup needed event listeners used to update the popper position + * @method + * @memberof Popper.Utils + * @private + */ + function setupEventListeners(reference, options, state, updateBound) { + // Resize event listener on window + state.updateBound = updateBound; + getWindow(reference).addEventListener('resize', state.updateBound, { passive: true }); + + // Scroll event listener on scroll parents + var scrollElement = getScrollParent(reference); + attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents); + state.scrollElement = scrollElement; + state.eventsEnabled = true; + + return state; + } + + /** + * It will add resize/scroll events and start recalculating + * position of the popper element when they are triggered. + * @method + * @memberof Popper + */ + function enableEventListeners() { + if (!this.state.eventsEnabled) { + this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate); + } + } + + /** + * Remove event listeners used to update the popper position + * @method + * @memberof Popper.Utils + * @private + */ + function removeEventListeners(reference, state) { + // Remove resize event listener on window + getWindow(reference).removeEventListener('resize', state.updateBound); + + // Remove scroll event listener on scroll parents + state.scrollParents.forEach(function (target) { + target.removeEventListener('scroll', state.updateBound); + }); + + // Reset state + state.updateBound = null; + state.scrollParents = []; + state.scrollElement = null; + state.eventsEnabled = false; + return state; + } + + /** + * It will remove resize/scroll events and won't recalculate popper position + * when they are triggered. It also won't trigger `onUpdate` callback anymore, + * unless you call `update` method manually. + * @method + * @memberof Popper + */ + function disableEventListeners() { + if (this.state.eventsEnabled) { + cancelAnimationFrame(this.scheduleUpdate); + this.state = removeEventListeners(this.reference, this.state); + } + } + + /** + * Tells if a given input is a number + * @method + * @memberof Popper.Utils + * @param {*} input to check + * @return {Boolean} + */ + function isNumeric(n) { + return n !== '' && !isNaN(parseFloat(n)) && isFinite(n); + } + + /** + * Set the style to the given popper + * @method + * @memberof Popper.Utils + * @argument {Element} element - Element to apply the style to + * @argument {Object} styles + * Object with a list of properties and values which will be applied to the element + */ + function setStyles(element, styles) { + Object.keys(styles).forEach(function (prop) { + var unit = ''; + // add unit if the value is numeric and is one of the following + if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) { + unit = 'px'; + } + element.style[prop] = styles[prop] + unit; + }); + } + + /** + * Set the attributes to the given popper + * @method + * @memberof Popper.Utils + * @argument {Element} element - Element to apply the attributes to + * @argument {Object} styles + * Object with a list of properties and values which will be applied to the element + */ + function setAttributes(element, attributes) { + Object.keys(attributes).forEach(function (prop) { + var value = attributes[prop]; + if (value !== false) { + element.setAttribute(prop, attributes[prop]); + } else { + element.removeAttribute(prop); + } + }); + } + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by `update` method + * @argument {Object} data.styles - List of style properties - values to apply to popper element + * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The same data object + */ + function applyStyle(data) { + // any property present in `data.styles` will be applied to the popper, + // in this way we can make the 3rd party modifiers add custom styles to it + // Be aware, modifiers could override the properties defined in the previous + // lines of this modifier! + setStyles(data.instance.popper, data.styles); + + // any property present in `data.attributes` will be applied to the popper, + // they will be set as HTML attributes of the element + setAttributes(data.instance.popper, data.attributes); + + // if arrowElement is defined and arrowStyles has some properties + if (data.arrowElement && Object.keys(data.arrowStyles).length) { + setStyles(data.arrowElement, data.arrowStyles); + } + + return data; + } + + /** + * Set the x-placement attribute before everything else because it could be used + * to add margins to the popper margins needs to be calculated to get the + * correct popper offsets. + * @method + * @memberof Popper.modifiers + * @param {HTMLElement} reference - The reference element used to position the popper + * @param {HTMLElement} popper - The HTML element used as popper + * @param {Object} options - Popper.js options + */ + function applyStyleOnLoad(reference, popper, options, modifierOptions, state) { + // compute reference element offsets + var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed); + + // compute auto placement, store placement inside the data object, + // modifiers will be able to edit `placement` if needed + // and refer to originalPlacement to know the original value + var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding); + + popper.setAttribute('x-placement', placement); + + // Apply `position` to popper before anything else because + // without the position applied we can't guarantee correct computations + setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' }); + + return options; + } + + /** + * @function + * @memberof Popper.Utils + * @argument {Object} data - The data object generated by `update` method + * @argument {Boolean} shouldRound - If the offsets should be rounded at all + * @returns {Object} The popper's position offsets rounded + * + * The tale of pixel-perfect positioning. It's still not 100% perfect, but as + * good as it can be within reason. + * Discussion here: https://github.com/FezVrasta/popper.js/pull/715 + * + * Low DPI screens cause a popper to be blurry if not using full pixels (Safari + * as well on High DPI screens). + * + * Firefox prefers no rounding for positioning and does not have blurriness on + * high DPI screens. + * + * Only horizontal placement and left/right values need to be considered. + */ + function getRoundedOffsets(data, shouldRound) { + var _data$offsets = data.offsets, + popper = _data$offsets.popper, + reference = _data$offsets.reference; + + + var isVertical = ['left', 'right'].indexOf(data.placement) !== -1; + var isVariation = data.placement.indexOf('-') !== -1; + var sameWidthOddness = reference.width % 2 === popper.width % 2; + var bothOddWidth = reference.width % 2 === 1 && popper.width % 2 === 1; + var noRound = function noRound(v) { + return v; + }; + + var horizontalToInteger = !shouldRound ? noRound : isVertical || isVariation || sameWidthOddness ? Math.round : Math.floor; + var verticalToInteger = !shouldRound ? noRound : Math.round; + + return { + left: horizontalToInteger(bothOddWidth && !isVariation && shouldRound ? popper.left - 1 : popper.left), + top: verticalToInteger(popper.top), + bottom: verticalToInteger(popper.bottom), + right: horizontalToInteger(popper.right) + }; + } + + var isFirefox = isBrowser && /Firefox/i.test(navigator.userAgent); + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by `update` method + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The data object, properly modified + */ + function computeStyle(data, options) { + var x = options.x, + y = options.y; + var popper = data.offsets.popper; + + // Remove this legacy support in Popper.js v2 + + var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) { + return modifier.name === 'applyStyle'; + }).gpuAcceleration; + if (legacyGpuAccelerationOption !== undefined) { + console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!'); + } + var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration; + + var offsetParent = getOffsetParent(data.instance.popper); + var offsetParentRect = getBoundingClientRect(offsetParent); + + // Styles + var styles = { + position: popper.position + }; + + var offsets = getRoundedOffsets(data, window.devicePixelRatio < 2 || !isFirefox); + + var sideA = x === 'bottom' ? 'top' : 'bottom'; + var sideB = y === 'right' ? 'left' : 'right'; + + // if gpuAcceleration is set to `true` and transform is supported, + // we use `translate3d` to apply the position to the popper we + // automatically use the supported prefixed version if needed + var prefixedProperty = getSupportedPropertyName('transform'); + + // now, let's make a step back and look at this code closely (wtf?) + // If the content of the popper grows once it's been positioned, it + // may happen that the popper gets misplaced because of the new content + // overflowing its reference element + // To avoid this problem, we provide two options (x and y), which allow + // the consumer to define the offset origin. + // If we position a popper on top of a reference element, we can set + // `x` to `top` to make the popper grow towards its top instead of + // its bottom. + var left = void 0, + top = void 0; + if (sideA === 'bottom') { + // when offsetParent is the positioning is relative to the bottom of the screen (excluding the scrollbar) + // and not the bottom of the html element + if (offsetParent.nodeName === 'HTML') { + top = -offsetParent.clientHeight + offsets.bottom; + } else { + top = -offsetParentRect.height + offsets.bottom; + } + } else { + top = offsets.top; + } + if (sideB === 'right') { + if (offsetParent.nodeName === 'HTML') { + left = -offsetParent.clientWidth + offsets.right; + } else { + left = -offsetParentRect.width + offsets.right; + } + } else { + left = offsets.left; + } + if (gpuAcceleration && prefixedProperty) { + styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)'; + styles[sideA] = 0; + styles[sideB] = 0; + styles.willChange = 'transform'; + } else { + // othwerise, we use the standard `top`, `left`, `bottom` and `right` properties + var invertTop = sideA === 'bottom' ? -1 : 1; + var invertLeft = sideB === 'right' ? -1 : 1; + styles[sideA] = top * invertTop; + styles[sideB] = left * invertLeft; + styles.willChange = sideA + ', ' + sideB; + } + + // Attributes + var attributes = { + 'x-placement': data.placement + }; + + // Update `data` attributes, styles and arrowStyles + data.attributes = _extends({}, attributes, data.attributes); + data.styles = _extends({}, styles, data.styles); + data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles); + + return data; + } + + /** + * Helper used to know if the given modifier depends from another one.
    + * It checks if the needed modifier is listed and enabled. + * @method + * @memberof Popper.Utils + * @param {Array} modifiers - list of modifiers + * @param {String} requestingName - name of requesting modifier + * @param {String} requestedName - name of requested modifier + * @returns {Boolean} + */ + function isModifierRequired(modifiers, requestingName, requestedName) { + var requesting = find(modifiers, function (_ref) { + var name = _ref.name; + return name === requestingName; + }); + + var isRequired = !!requesting && modifiers.some(function (modifier) { + return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order; + }); + + if (!isRequired) { + var _requesting = '`' + requestingName + '`'; + var requested = '`' + requestedName + '`'; + console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!'); + } + return isRequired; + } + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by update method + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The data object, properly modified + */ + function arrow(data, options) { + var _data$offsets$arrow; + + // arrow depends on keepTogether in order to work + if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) { + return data; + } + + var arrowElement = options.element; + + // if arrowElement is a string, suppose it's a CSS selector + if (typeof arrowElement === 'string') { + arrowElement = data.instance.popper.querySelector(arrowElement); + + // if arrowElement is not found, don't run the modifier + if (!arrowElement) { + return data; + } + } else { + // if the arrowElement isn't a query selector we must check that the + // provided DOM node is child of its popper node + if (!data.instance.popper.contains(arrowElement)) { + console.warn('WARNING: `arrow.element` must be child of its popper element!'); + return data; + } + } + + var placement = data.placement.split('-')[0]; + var _data$offsets = data.offsets, + popper = _data$offsets.popper, + reference = _data$offsets.reference; + + var isVertical = ['left', 'right'].indexOf(placement) !== -1; + + var len = isVertical ? 'height' : 'width'; + var sideCapitalized = isVertical ? 'Top' : 'Left'; + var side = sideCapitalized.toLowerCase(); + var altSide = isVertical ? 'left' : 'top'; + var opSide = isVertical ? 'bottom' : 'right'; + var arrowElementSize = getOuterSizes(arrowElement)[len]; + + // + // extends keepTogether behavior making sure the popper and its + // reference have enough pixels in conjunction + // + + // top/left side + if (reference[opSide] - arrowElementSize < popper[side]) { + data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize); + } + // bottom/right side + if (reference[side] + arrowElementSize > popper[opSide]) { + data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide]; + } + data.offsets.popper = getClientRect(data.offsets.popper); + + // compute center of the popper + var center = reference[side] + reference[len] / 2 - arrowElementSize / 2; + + // Compute the sideValue using the updated popper offsets + // take popper margin in account because we don't have this info available + var css = getStyleComputedProperty(data.instance.popper); + var popperMarginSide = parseFloat(css['margin' + sideCapitalized], 10); + var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width'], 10); + var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide; + + // prevent arrowElement from being placed not contiguously to its popper + sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0); + + data.arrowElement = arrowElement; + data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty(_data$offsets$arrow, altSide, ''), _data$offsets$arrow); + + return data; + } + + /** + * Get the opposite placement variation of the given one + * @method + * @memberof Popper.Utils + * @argument {String} placement variation + * @returns {String} flipped placement variation + */ + function getOppositeVariation(variation) { + if (variation === 'end') { + return 'start'; + } else if (variation === 'start') { + return 'end'; + } + return variation; + } + + /** + * List of accepted placements to use as values of the `placement` option.
    + * Valid placements are: + * - `auto` + * - `top` + * - `right` + * - `bottom` + * - `left` + * + * Each placement can have a variation from this list: + * - `-start` + * - `-end` + * + * Variations are interpreted easily if you think of them as the left to right + * written languages. Horizontally (`top` and `bottom`), `start` is left and `end` + * is right.
    + * Vertically (`left` and `right`), `start` is top and `end` is bottom. + * + * Some valid examples are: + * - `top-end` (on top of reference, right aligned) + * - `right-start` (on right of reference, top aligned) + * - `bottom` (on bottom, centered) + * - `auto-end` (on the side with more space available, alignment depends by placement) + * + * @static + * @type {Array} + * @enum {String} + * @readonly + * @method placements + * @memberof Popper + */ + var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start']; + + // Get rid of `auto` `auto-start` and `auto-end` + var validPlacements = placements.slice(3); + + /** + * Given an initial placement, returns all the subsequent placements + * clockwise (or counter-clockwise). + * + * @method + * @memberof Popper.Utils + * @argument {String} placement - A valid placement (it accepts variations) + * @argument {Boolean} counter - Set to true to walk the placements counterclockwise + * @returns {Array} placements including their variations + */ + function clockwise(placement) { + var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + var index = validPlacements.indexOf(placement); + var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index)); + return counter ? arr.reverse() : arr; + } + + var BEHAVIORS = { + FLIP: 'flip', + CLOCKWISE: 'clockwise', + COUNTERCLOCKWISE: 'counterclockwise' + }; + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by update method + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The data object, properly modified + */ + function flip(data, options) { + // if `inner` modifier is enabled, we can't use the `flip` modifier + if (isModifierEnabled(data.instance.modifiers, 'inner')) { + return data; + } + + if (data.flipped && data.placement === data.originalPlacement) { + // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides + return data; + } + + var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed); + + var placement = data.placement.split('-')[0]; + var placementOpposite = getOppositePlacement(placement); + var variation = data.placement.split('-')[1] || ''; + + var flipOrder = []; + + switch (options.behavior) { + case BEHAVIORS.FLIP: + flipOrder = [placement, placementOpposite]; + break; + case BEHAVIORS.CLOCKWISE: + flipOrder = clockwise(placement); + break; + case BEHAVIORS.COUNTERCLOCKWISE: + flipOrder = clockwise(placement, true); + break; + default: + flipOrder = options.behavior; + } + + flipOrder.forEach(function (step, index) { + if (placement !== step || flipOrder.length === index + 1) { + return data; + } + + placement = data.placement.split('-')[0]; + placementOpposite = getOppositePlacement(placement); + + var popperOffsets = data.offsets.popper; + var refOffsets = data.offsets.reference; + + // using floor because the reference offsets may contain decimals we are not going to consider here + var floor = Math.floor; + var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom); + + var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left); + var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right); + var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top); + var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom); + + var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom; + + // flip the variation if required + var isVertical = ['top', 'bottom'].indexOf(placement) !== -1; + var flippedVariation = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom); + + if (overlapsRef || overflowsBoundaries || flippedVariation) { + // this boolean to detect any flip loop + data.flipped = true; + + if (overlapsRef || overflowsBoundaries) { + placement = flipOrder[index + 1]; + } + + if (flippedVariation) { + variation = getOppositeVariation(variation); + } + + data.placement = placement + (variation ? '-' + variation : ''); + + // this object contains `position`, we want to preserve it along with + // any additional property we may add in the future + data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement)); + + data = runModifiers(data.instance.modifiers, data, 'flip'); + } + }); + return data; + } + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by update method + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The data object, properly modified + */ + function keepTogether(data) { + var _data$offsets = data.offsets, + popper = _data$offsets.popper, + reference = _data$offsets.reference; + + var placement = data.placement.split('-')[0]; + var floor = Math.floor; + var isVertical = ['top', 'bottom'].indexOf(placement) !== -1; + var side = isVertical ? 'right' : 'bottom'; + var opSide = isVertical ? 'left' : 'top'; + var measurement = isVertical ? 'width' : 'height'; + + if (popper[side] < floor(reference[opSide])) { + data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement]; + } + if (popper[opSide] > floor(reference[side])) { + data.offsets.popper[opSide] = floor(reference[side]); + } + + return data; + } + + /** + * Converts a string containing value + unit into a px value number + * @function + * @memberof {modifiers~offset} + * @private + * @argument {String} str - Value + unit string + * @argument {String} measurement - `height` or `width` + * @argument {Object} popperOffsets + * @argument {Object} referenceOffsets + * @returns {Number|String} + * Value in pixels, or original string if no values were extracted + */ + function toValue(str, measurement, popperOffsets, referenceOffsets) { + // separate value from unit + var split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/); + var value = +split[1]; + var unit = split[2]; + + // If it's not a number it's an operator, I guess + if (!value) { + return str; + } + + if (unit.indexOf('%') === 0) { + var element = void 0; + switch (unit) { + case '%p': + element = popperOffsets; + break; + case '%': + case '%r': + default: + element = referenceOffsets; + } + + var rect = getClientRect(element); + return rect[measurement] / 100 * value; + } else if (unit === 'vh' || unit === 'vw') { + // if is a vh or vw, we calculate the size based on the viewport + var size = void 0; + if (unit === 'vh') { + size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); + } else { + size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); + } + return size / 100 * value; + } else { + // if is an explicit pixel unit, we get rid of the unit and keep the value + // if is an implicit unit, it's px, and we return just the value + return value; + } + } + + /** + * Parse an `offset` string to extrapolate `x` and `y` numeric offsets. + * @function + * @memberof {modifiers~offset} + * @private + * @argument {String} offset + * @argument {Object} popperOffsets + * @argument {Object} referenceOffsets + * @argument {String} basePlacement + * @returns {Array} a two cells array with x and y offsets in numbers + */ + function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) { + var offsets = [0, 0]; + + // Use height if placement is left or right and index is 0 otherwise use width + // in this way the first offset will use an axis and the second one + // will use the other one + var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1; + + // Split the offset string to obtain a list of values and operands + // The regex addresses values with the plus or minus sign in front (+10, -20, etc) + var fragments = offset.split(/(\+|\-)/).map(function (frag) { + return frag.trim(); + }); + + // Detect if the offset string contains a pair of values or a single one + // they could be separated by comma or space + var divider = fragments.indexOf(find(fragments, function (frag) { + return frag.search(/,|\s/) !== -1; + })); + + if (fragments[divider] && fragments[divider].indexOf(',') === -1) { + console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.'); + } + + // If divider is found, we divide the list of values and operands to divide + // them by ofset X and Y. + var splitRegex = /\s*,\s*|\s+/; + var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments]; + + // Convert the values with units to absolute pixels to allow our computations + ops = ops.map(function (op, index) { + // Most of the units rely on the orientation of the popper + var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width'; + var mergeWithPrevious = false; + return op + // This aggregates any `+` or `-` sign that aren't considered operators + // e.g.: 10 + +5 => [10, +, +5] + .reduce(function (a, b) { + if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) { + a[a.length - 1] = b; + mergeWithPrevious = true; + return a; + } else if (mergeWithPrevious) { + a[a.length - 1] += b; + mergeWithPrevious = false; + return a; + } else { + return a.concat(b); + } + }, []) + // Here we convert the string values into number values (in px) + .map(function (str) { + return toValue(str, measurement, popperOffsets, referenceOffsets); + }); + }); + + // Loop trough the offsets arrays and execute the operations + ops.forEach(function (op, index) { + op.forEach(function (frag, index2) { + if (isNumeric(frag)) { + offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1); + } + }); + }); + return offsets; + } + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by update method + * @argument {Object} options - Modifiers configuration and options + * @argument {Number|String} options.offset=0 + * The offset value as described in the modifier description + * @returns {Object} The data object, properly modified + */ + function offset(data, _ref) { + var offset = _ref.offset; + var placement = data.placement, + _data$offsets = data.offsets, + popper = _data$offsets.popper, + reference = _data$offsets.reference; + + var basePlacement = placement.split('-')[0]; + + var offsets = void 0; + if (isNumeric(+offset)) { + offsets = [+offset, 0]; + } else { + offsets = parseOffset(offset, popper, reference, basePlacement); + } + + if (basePlacement === 'left') { + popper.top += offsets[0]; + popper.left -= offsets[1]; + } else if (basePlacement === 'right') { + popper.top += offsets[0]; + popper.left += offsets[1]; + } else if (basePlacement === 'top') { + popper.left += offsets[0]; + popper.top -= offsets[1]; + } else if (basePlacement === 'bottom') { + popper.left += offsets[0]; + popper.top += offsets[1]; + } + + data.popper = popper; + return data; + } + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by `update` method + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The data object, properly modified + */ + function preventOverflow(data, options) { + var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper); + + // If offsetParent is the reference element, we really want to + // go one step up and use the next offsetParent as reference to + // avoid to make this modifier completely useless and look like broken + if (data.instance.reference === boundariesElement) { + boundariesElement = getOffsetParent(boundariesElement); + } + + // NOTE: DOM access here + // resets the popper's position so that the document size can be calculated excluding + // the size of the popper element itself + var transformProp = getSupportedPropertyName('transform'); + var popperStyles = data.instance.popper.style; // assignment to help minification + var top = popperStyles.top, + left = popperStyles.left, + transform = popperStyles[transformProp]; + + popperStyles.top = ''; + popperStyles.left = ''; + popperStyles[transformProp] = ''; + + var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed); + + // NOTE: DOM access here + // restores the original style properties after the offsets have been computed + popperStyles.top = top; + popperStyles.left = left; + popperStyles[transformProp] = transform; + + options.boundaries = boundaries; + + var order = options.priority; + var popper = data.offsets.popper; + + var check = { + primary: function primary(placement) { + var value = popper[placement]; + if (popper[placement] < boundaries[placement] && !options.escapeWithReference) { + value = Math.max(popper[placement], boundaries[placement]); + } + return defineProperty({}, placement, value); + }, + secondary: function secondary(placement) { + var mainSide = placement === 'right' ? 'left' : 'top'; + var value = popper[mainSide]; + if (popper[placement] > boundaries[placement] && !options.escapeWithReference) { + value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height)); + } + return defineProperty({}, mainSide, value); + } + }; + + order.forEach(function (placement) { + var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary'; + popper = _extends({}, popper, check[side](placement)); + }); + + data.offsets.popper = popper; + + return data; + } + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by `update` method + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The data object, properly modified + */ + function shift(data) { + var placement = data.placement; + var basePlacement = placement.split('-')[0]; + var shiftvariation = placement.split('-')[1]; + + // if shift shiftvariation is specified, run the modifier + if (shiftvariation) { + var _data$offsets = data.offsets, + reference = _data$offsets.reference, + popper = _data$offsets.popper; + + var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1; + var side = isVertical ? 'left' : 'top'; + var measurement = isVertical ? 'width' : 'height'; + + var shiftOffsets = { + start: defineProperty({}, side, reference[side]), + end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement]) + }; + + data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]); + } + + return data; + } + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by update method + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The data object, properly modified + */ + function hide(data) { + if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) { + return data; + } + + var refRect = data.offsets.reference; + var bound = find(data.instance.modifiers, function (modifier) { + return modifier.name === 'preventOverflow'; + }).boundaries; + + if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) { + // Avoid unnecessary DOM access if visibility hasn't changed + if (data.hide === true) { + return data; + } + + data.hide = true; + data.attributes['x-out-of-boundaries'] = ''; + } else { + // Avoid unnecessary DOM access if visibility hasn't changed + if (data.hide === false) { + return data; + } + + data.hide = false; + data.attributes['x-out-of-boundaries'] = false; + } + + return data; + } + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by `update` method + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The data object, properly modified + */ + function inner(data) { + var placement = data.placement; + var basePlacement = placement.split('-')[0]; + var _data$offsets = data.offsets, + popper = _data$offsets.popper, + reference = _data$offsets.reference; + + var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1; + + var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1; + + popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0); + + data.placement = getOppositePlacement(placement); + data.offsets.popper = getClientRect(popper); + + return data; + } + + /** + * Modifier function, each modifier can have a function of this type assigned + * to its `fn` property.
    + * These functions will be called on each update, this means that you must + * make sure they are performant enough to avoid performance bottlenecks. + * + * @function ModifierFn + * @argument {dataObject} data - The data object generated by `update` method + * @argument {Object} options - Modifiers configuration and options + * @returns {dataObject} The data object, properly modified + */ + + /** + * Modifiers are plugins used to alter the behavior of your poppers.
    + * Popper.js uses a set of 9 modifiers to provide all the basic functionalities + * needed by the library. + * + * Usually you don't want to override the `order`, `fn` and `onLoad` props. + * All the other properties are configurations that could be tweaked. + * @namespace modifiers + */ + var modifiers = { + /** + * Modifier used to shift the popper on the start or end of its reference + * element.
    + * It will read the variation of the `placement` property.
    + * It can be one either `-end` or `-start`. + * @memberof modifiers + * @inner + */ + shift: { + /** @prop {number} order=100 - Index used to define the order of execution */ + order: 100, + /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ + enabled: true, + /** @prop {ModifierFn} */ + fn: shift + }, + + /** + * The `offset` modifier can shift your popper on both its axis. + * + * It accepts the following units: + * - `px` or unit-less, interpreted as pixels + * - `%` or `%r`, percentage relative to the length of the reference element + * - `%p`, percentage relative to the length of the popper element + * - `vw`, CSS viewport width unit + * - `vh`, CSS viewport height unit + * + * For length is intended the main axis relative to the placement of the popper.
    + * This means that if the placement is `top` or `bottom`, the length will be the + * `width`. In case of `left` or `right`, it will be the `height`. + * + * You can provide a single value (as `Number` or `String`), or a pair of values + * as `String` divided by a comma or one (or more) white spaces.
    + * The latter is a deprecated method because it leads to confusion and will be + * removed in v2.
    + * Additionally, it accepts additions and subtractions between different units. + * Note that multiplications and divisions aren't supported. + * + * Valid examples are: + * ``` + * 10 + * '10%' + * '10, 10' + * '10%, 10' + * '10 + 10%' + * '10 - 5vh + 3%' + * '-10px + 5vh, 5px - 6%' + * ``` + * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap + * > with their reference element, unfortunately, you will have to disable the `flip` modifier. + * > You can read more on this at this [issue](https://github.com/FezVrasta/popper.js/issues/373). + * + * @memberof modifiers + * @inner + */ + offset: { + /** @prop {number} order=200 - Index used to define the order of execution */ + order: 200, + /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ + enabled: true, + /** @prop {ModifierFn} */ + fn: offset, + /** @prop {Number|String} offset=0 + * The offset value as described in the modifier description + */ + offset: 0 + }, + + /** + * Modifier used to prevent the popper from being positioned outside the boundary. + * + * A scenario exists where the reference itself is not within the boundaries.
    + * We can say it has "escaped the boundaries" — or just "escaped".
    + * In this case we need to decide whether the popper should either: + * + * - detach from the reference and remain "trapped" in the boundaries, or + * - if it should ignore the boundary and "escape with its reference" + * + * When `escapeWithReference` is set to`true` and reference is completely + * outside its boundaries, the popper will overflow (or completely leave) + * the boundaries in order to remain attached to the edge of the reference. + * + * @memberof modifiers + * @inner + */ + preventOverflow: { + /** @prop {number} order=300 - Index used to define the order of execution */ + order: 300, + /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ + enabled: true, + /** @prop {ModifierFn} */ + fn: preventOverflow, + /** + * @prop {Array} [priority=['left','right','top','bottom']] + * Popper will try to prevent overflow following these priorities by default, + * then, it could overflow on the left and on top of the `boundariesElement` + */ + priority: ['left', 'right', 'top', 'bottom'], + /** + * @prop {number} padding=5 + * Amount of pixel used to define a minimum distance between the boundaries + * and the popper. This makes sure the popper always has a little padding + * between the edges of its container + */ + padding: 5, + /** + * @prop {String|HTMLElement} boundariesElement='scrollParent' + * Boundaries used by the modifier. Can be `scrollParent`, `window`, + * `viewport` or any DOM element. + */ + boundariesElement: 'scrollParent' + }, + + /** + * Modifier used to make sure the reference and its popper stay near each other + * without leaving any gap between the two. Especially useful when the arrow is + * enabled and you want to ensure that it points to its reference element. + * It cares only about the first axis. You can still have poppers with margin + * between the popper and its reference element. + * @memberof modifiers + * @inner + */ + keepTogether: { + /** @prop {number} order=400 - Index used to define the order of execution */ + order: 400, + /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ + enabled: true, + /** @prop {ModifierFn} */ + fn: keepTogether + }, + + /** + * This modifier is used to move the `arrowElement` of the popper to make + * sure it is positioned between the reference element and its popper element. + * It will read the outer size of the `arrowElement` node to detect how many + * pixels of conjunction are needed. + * + * It has no effect if no `arrowElement` is provided. + * @memberof modifiers + * @inner + */ + arrow: { + /** @prop {number} order=500 - Index used to define the order of execution */ + order: 500, + /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ + enabled: true, + /** @prop {ModifierFn} */ + fn: arrow, + /** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */ + element: '[x-arrow]' + }, + + /** + * Modifier used to flip the popper's placement when it starts to overlap its + * reference element. + * + * Requires the `preventOverflow` modifier before it in order to work. + * + * **NOTE:** this modifier will interrupt the current update cycle and will + * restart it if it detects the need to flip the placement. + * @memberof modifiers + * @inner + */ + flip: { + /** @prop {number} order=600 - Index used to define the order of execution */ + order: 600, + /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ + enabled: true, + /** @prop {ModifierFn} */ + fn: flip, + /** + * @prop {String|Array} behavior='flip' + * The behavior used to change the popper's placement. It can be one of + * `flip`, `clockwise`, `counterclockwise` or an array with a list of valid + * placements (with optional variations) + */ + behavior: 'flip', + /** + * @prop {number} padding=5 + * The popper will flip if it hits the edges of the `boundariesElement` + */ + padding: 5, + /** + * @prop {String|HTMLElement} boundariesElement='viewport' + * The element which will define the boundaries of the popper position. + * The popper will never be placed outside of the defined boundaries + * (except if `keepTogether` is enabled) + */ + boundariesElement: 'viewport' + }, + + /** + * Modifier used to make the popper flow toward the inner of the reference element. + * By default, when this modifier is disabled, the popper will be placed outside + * the reference element. + * @memberof modifiers + * @inner + */ + inner: { + /** @prop {number} order=700 - Index used to define the order of execution */ + order: 700, + /** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */ + enabled: false, + /** @prop {ModifierFn} */ + fn: inner + }, + + /** + * Modifier used to hide the popper when its reference element is outside of the + * popper boundaries. It will set a `x-out-of-boundaries` attribute which can + * be used to hide with a CSS selector the popper when its reference is + * out of boundaries. + * + * Requires the `preventOverflow` modifier before it in order to work. + * @memberof modifiers + * @inner + */ + hide: { + /** @prop {number} order=800 - Index used to define the order of execution */ + order: 800, + /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ + enabled: true, + /** @prop {ModifierFn} */ + fn: hide + }, + + /** + * Computes the style that will be applied to the popper element to gets + * properly positioned. + * + * Note that this modifier will not touch the DOM, it just prepares the styles + * so that `applyStyle` modifier can apply it. This separation is useful + * in case you need to replace `applyStyle` with a custom implementation. + * + * This modifier has `850` as `order` value to maintain backward compatibility + * with previous versions of Popper.js. Expect the modifiers ordering method + * to change in future major versions of the library. + * + * @memberof modifiers + * @inner + */ + computeStyle: { + /** @prop {number} order=850 - Index used to define the order of execution */ + order: 850, + /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ + enabled: true, + /** @prop {ModifierFn} */ + fn: computeStyle, + /** + * @prop {Boolean} gpuAcceleration=true + * If true, it uses the CSS 3D transformation to position the popper. + * Otherwise, it will use the `top` and `left` properties + */ + gpuAcceleration: true, + /** + * @prop {string} [x='bottom'] + * Where to anchor the X axis (`bottom` or `top`). AKA X offset origin. + * Change this if your popper should grow in a direction different from `bottom` + */ + x: 'bottom', + /** + * @prop {string} [x='left'] + * Where to anchor the Y axis (`left` or `right`). AKA Y offset origin. + * Change this if your popper should grow in a direction different from `right` + */ + y: 'right' + }, + + /** + * Applies the computed styles to the popper element. + * + * All the DOM manipulations are limited to this modifier. This is useful in case + * you want to integrate Popper.js inside a framework or view library and you + * want to delegate all the DOM manipulations to it. + * + * Note that if you disable this modifier, you must make sure the popper element + * has its position set to `absolute` before Popper.js can do its work! + * + * Just disable this modifier and define your own to achieve the desired effect. + * + * @memberof modifiers + * @inner + */ + applyStyle: { + /** @prop {number} order=900 - Index used to define the order of execution */ + order: 900, + /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ + enabled: true, + /** @prop {ModifierFn} */ + fn: applyStyle, + /** @prop {Function} */ + onLoad: applyStyleOnLoad, + /** + * @deprecated since version 1.10.0, the property moved to `computeStyle` modifier + * @prop {Boolean} gpuAcceleration=true + * If true, it uses the CSS 3D transformation to position the popper. + * Otherwise, it will use the `top` and `left` properties + */ + gpuAcceleration: undefined + } + }; + + /** + * The `dataObject` is an object containing all the information used by Popper.js. + * This object is passed to modifiers and to the `onCreate` and `onUpdate` callbacks. + * @name dataObject + * @property {Object} data.instance The Popper.js instance + * @property {String} data.placement Placement applied to popper + * @property {String} data.originalPlacement Placement originally defined on init + * @property {Boolean} data.flipped True if popper has been flipped by flip modifier + * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper + * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier + * @property {Object} data.styles Any CSS property defined here will be applied to the popper. It expects the JavaScript nomenclature (eg. `marginBottom`) + * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow. It expects the JavaScript nomenclature (eg. `marginBottom`) + * @property {Object} data.boundaries Offsets of the popper boundaries + * @property {Object} data.offsets The measurements of popper, reference and arrow elements + * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values + * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values + * @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0 + */ + + /** + * Default options provided to Popper.js constructor.
    + * These can be overridden using the `options` argument of Popper.js.
    + * To override an option, simply pass an object with the same + * structure of the `options` object, as the 3rd argument. For example: + * ``` + * new Popper(ref, pop, { + * modifiers: { + * preventOverflow: { enabled: false } + * } + * }) + * ``` + * @type {Object} + * @static + * @memberof Popper + */ + var Defaults = { + /** + * Popper's placement. + * @prop {Popper.placements} placement='bottom' + */ + placement: 'bottom', + + /** + * Set this to true if you want popper to position it self in 'fixed' mode + * @prop {Boolean} positionFixed=false + */ + positionFixed: false, + + /** + * Whether events (resize, scroll) are initially enabled. + * @prop {Boolean} eventsEnabled=true + */ + eventsEnabled: true, + + /** + * Set to true if you want to automatically remove the popper when + * you call the `destroy` method. + * @prop {Boolean} removeOnDestroy=false + */ + removeOnDestroy: false, + + /** + * Callback called when the popper is created.
    + * By default, it is set to no-op.
    + * Access Popper.js instance with `data.instance`. + * @prop {onCreate} + */ + onCreate: function onCreate() {}, + + /** + * Callback called when the popper is updated. This callback is not called + * on the initialization/creation of the popper, but only on subsequent + * updates.
    + * By default, it is set to no-op.
    + * Access Popper.js instance with `data.instance`. + * @prop {onUpdate} + */ + onUpdate: function onUpdate() {}, + + /** + * List of modifiers used to modify the offsets before they are applied to the popper. + * They provide most of the functionalities of Popper.js. + * @prop {modifiers} + */ + modifiers: modifiers + }; + + /** + * @callback onCreate + * @param {dataObject} data + */ + + /** + * @callback onUpdate + * @param {dataObject} data + */ + + // Utils + // Methods + var Popper = function () { + /** + * Creates a new Popper.js instance. + * @class Popper + * @param {HTMLElement|referenceObject} reference - The reference element used to position the popper + * @param {HTMLElement} popper - The HTML element used as the popper + * @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults) + * @return {Object} instance - The generated Popper.js instance + */ + function Popper(reference, popper) { + var _this = this; + + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + classCallCheck(this, Popper); + + this.scheduleUpdate = function () { + return requestAnimationFrame(_this.update); + }; + + // make update() debounced, so that it only runs at most once-per-tick + this.update = debounce(this.update.bind(this)); + + // with {} we create a new object with the options inside it + this.options = _extends({}, Popper.Defaults, options); + + // init state + this.state = { + isDestroyed: false, + isCreated: false, + scrollParents: [] + }; + + // get reference and popper elements (allow jQuery wrappers) + this.reference = reference && reference.jquery ? reference[0] : reference; + this.popper = popper && popper.jquery ? popper[0] : popper; + + // Deep merge modifiers options + this.options.modifiers = {}; + Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) { + _this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {}); + }); + + // Refactoring modifiers' list (Object => Array) + this.modifiers = Object.keys(this.options.modifiers).map(function (name) { + return _extends({ + name: name + }, _this.options.modifiers[name]); + }) + // sort the modifiers by order + .sort(function (a, b) { + return a.order - b.order; + }); + + // modifiers have the ability to execute arbitrary code when Popper.js get inited + // such code is executed in the same order of its modifier + // they could add new properties to their options configuration + // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`! + this.modifiers.forEach(function (modifierOptions) { + if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) { + modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state); + } + }); + + // fire the first update to position the popper in the right place + this.update(); + + var eventsEnabled = this.options.eventsEnabled; + if (eventsEnabled) { + // setup event listeners, they will take care of update the position in specific situations + this.enableEventListeners(); + } + + this.state.eventsEnabled = eventsEnabled; + } + + // We can't use class properties because they don't get listed in the + // class prototype and break stuff like Sinon stubs + + + createClass(Popper, [{ + key: 'update', + value: function update$$1() { + return update.call(this); + } + }, { + key: 'destroy', + value: function destroy$$1() { + return destroy.call(this); + } + }, { + key: 'enableEventListeners', + value: function enableEventListeners$$1() { + return enableEventListeners.call(this); + } + }, { + key: 'disableEventListeners', + value: function disableEventListeners$$1() { + return disableEventListeners.call(this); + } + + /** + * Schedules an update. It will run on the next UI update available. + * @method scheduleUpdate + * @memberof Popper + */ + + + /** + * Collection of utilities useful when writing custom modifiers. + * Starting from version 1.7, this method is available only if you + * include `popper-utils.js` before `popper.js`. + * + * **DEPRECATION**: This way to access PopperUtils is deprecated + * and will be removed in v2! Use the PopperUtils module directly instead. + * Due to the high instability of the methods contained in Utils, we can't + * guarantee them to follow semver. Use them at your own risk! + * @static + * @private + * @type {Object} + * @deprecated since version 1.8 + * @member Utils + * @memberof Popper + */ + + }]); + return Popper; + }(); + + /** + * The `referenceObject` is an object that provides an interface compatible with Popper.js + * and lets you use it as replacement of a real DOM node.
    + * You can use this method to position a popper relatively to a set of coordinates + * in case you don't have a DOM node to use as reference. + * + * ``` + * new Popper(referenceObject, popperNode); + * ``` + * + * NB: This feature isn't supported in Internet Explorer 10. + * @name referenceObject + * @property {Function} data.getBoundingClientRect + * A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method. + * @property {number} data.clientWidth + * An ES6 getter that will return the width of the virtual reference element. + * @property {number} data.clientHeight + * An ES6 getter that will return the height of the virtual reference element. + */ + + + Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils; + Popper.placements = placements; + Popper.Defaults = Defaults; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$4 = 'dropdown'; + var VERSION$4 = '4.2.1'; + var DATA_KEY$4 = 'bs.dropdown'; + var EVENT_KEY$4 = "." + DATA_KEY$4; + var DATA_API_KEY$4 = '.data-api'; + var JQUERY_NO_CONFLICT$4 = $.fn[NAME$4]; + var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key + + var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key + + var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key + + var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key + + var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key + + var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse) + + var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + "|" + ARROW_DOWN_KEYCODE + "|" + ESCAPE_KEYCODE); + var Event$4 = { + HIDE: "hide" + EVENT_KEY$4, + HIDDEN: "hidden" + EVENT_KEY$4, + SHOW: "show" + EVENT_KEY$4, + SHOWN: "shown" + EVENT_KEY$4, + CLICK: "click" + EVENT_KEY$4, + CLICK_DATA_API: "click" + EVENT_KEY$4 + DATA_API_KEY$4, + KEYDOWN_DATA_API: "keydown" + EVENT_KEY$4 + DATA_API_KEY$4, + KEYUP_DATA_API: "keyup" + EVENT_KEY$4 + DATA_API_KEY$4 + }; + var ClassName$4 = { + DISABLED: 'disabled', + SHOW: 'show', + DROPUP: 'dropup', + DROPRIGHT: 'dropright', + DROPLEFT: 'dropleft', + MENURIGHT: 'dropdown-menu-right', + MENULEFT: 'dropdown-menu-left', + POSITION_STATIC: 'position-static' + }; + var Selector$4 = { + DATA_TOGGLE: '[data-toggle="dropdown"]', + FORM_CHILD: '.dropdown form', + MENU: '.dropdown-menu', + NAVBAR_NAV: '.navbar-nav', + VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' + }; + var AttachmentMap = { + TOP: 'top-start', + TOPEND: 'top-end', + BOTTOM: 'bottom-start', + BOTTOMEND: 'bottom-end', + RIGHT: 'right-start', + RIGHTEND: 'right-end', + LEFT: 'left-start', + LEFTEND: 'left-end' + }; + var Default$2 = { + offset: 0, + flip: true, + boundary: 'scrollParent', + reference: 'toggle', + display: 'dynamic' + }; + var DefaultType$2 = { + offset: '(number|string|function)', + flip: 'boolean', + boundary: '(string|element)', + reference: '(string|element)', + display: 'string' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Dropdown = + /*#__PURE__*/ + function () { + function Dropdown(element, config) { + this._element = element; + this._popper = null; + this._config = this._getConfig(config); + this._menu = this._getMenuElement(); + this._inNavbar = this._detectNavbar(); + + this._addEventListeners(); + } // Getters + + + var _proto = Dropdown.prototype; + + // Public + _proto.toggle = function toggle() { + if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED)) { + return; + } + + var parent = Dropdown._getParentFromElement(this._element); + + var isActive = $(this._menu).hasClass(ClassName$4.SHOW); + + Dropdown._clearMenus(); + + if (isActive) { + return; + } + + var relatedTarget = { + relatedTarget: this._element + }; + var showEvent = $.Event(Event$4.SHOW, relatedTarget); + $(parent).trigger(showEvent); + + if (showEvent.isDefaultPrevented()) { + return; + } // Disable totally Popper.js for Dropdown in Navbar + + + if (!this._inNavbar) { + /** + * Check for Popper dependency + * Popper - https://popper.js.org + */ + if (typeof Popper === 'undefined') { + throw new TypeError('Bootstrap\'s dropdowns require Popper.js (https://popper.js.org/)'); + } + + var referenceElement = this._element; + + if (this._config.reference === 'parent') { + referenceElement = parent; + } else if (Util.isElement(this._config.reference)) { + referenceElement = this._config.reference; // Check if it's jQuery element + + if (typeof this._config.reference.jquery !== 'undefined') { + referenceElement = this._config.reference[0]; + } + } // If boundary is not `scrollParent`, then set position to `static` + // to allow the menu to "escape" the scroll parent's boundaries + // https://github.com/twbs/bootstrap/issues/24251 + + + if (this._config.boundary !== 'scrollParent') { + $(parent).addClass(ClassName$4.POSITION_STATIC); + } + + this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig()); + } // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + + + if ('ontouchstart' in document.documentElement && $(parent).closest(Selector$4.NAVBAR_NAV).length === 0) { + $(document.body).children().on('mouseover', null, $.noop); + } + + this._element.focus(); + + this._element.setAttribute('aria-expanded', true); + + $(this._menu).toggleClass(ClassName$4.SHOW); + $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.SHOWN, relatedTarget)); + }; + + _proto.show = function show() { + if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || $(this._menu).hasClass(ClassName$4.SHOW)) { + return; + } + + var relatedTarget = { + relatedTarget: this._element + }; + var showEvent = $.Event(Event$4.SHOW, relatedTarget); + + var parent = Dropdown._getParentFromElement(this._element); + + $(parent).trigger(showEvent); + + if (showEvent.isDefaultPrevented()) { + return; + } + + $(this._menu).toggleClass(ClassName$4.SHOW); + $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.SHOWN, relatedTarget)); + }; + + _proto.hide = function hide() { + if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || !$(this._menu).hasClass(ClassName$4.SHOW)) { + return; + } + + var relatedTarget = { + relatedTarget: this._element + }; + var hideEvent = $.Event(Event$4.HIDE, relatedTarget); + + var parent = Dropdown._getParentFromElement(this._element); + + $(parent).trigger(hideEvent); + + if (hideEvent.isDefaultPrevented()) { + return; + } + + $(this._menu).toggleClass(ClassName$4.SHOW); + $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget)); + }; + + _proto.dispose = function dispose() { + $.removeData(this._element, DATA_KEY$4); + $(this._element).off(EVENT_KEY$4); + this._element = null; + this._menu = null; + + if (this._popper !== null) { + this._popper.destroy(); + + this._popper = null; + } + }; + + _proto.update = function update() { + this._inNavbar = this._detectNavbar(); + + if (this._popper !== null) { + this._popper.scheduleUpdate(); + } + }; // Private + + + _proto._addEventListeners = function _addEventListeners() { + var _this = this; + + $(this._element).on(Event$4.CLICK, function (event) { + event.preventDefault(); + event.stopPropagation(); + + _this.toggle(); + }); + }; + + _proto._getConfig = function _getConfig(config) { + config = _objectSpread({}, this.constructor.Default, $(this._element).data(), config); + Util.typeCheckConfig(NAME$4, config, this.constructor.DefaultType); + return config; + }; + + _proto._getMenuElement = function _getMenuElement() { + if (!this._menu) { + var parent = Dropdown._getParentFromElement(this._element); + + if (parent) { + this._menu = parent.querySelector(Selector$4.MENU); + } + } + + return this._menu; + }; + + _proto._getPlacement = function _getPlacement() { + var $parentDropdown = $(this._element.parentNode); + var placement = AttachmentMap.BOTTOM; // Handle dropup + + if ($parentDropdown.hasClass(ClassName$4.DROPUP)) { + placement = AttachmentMap.TOP; + + if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) { + placement = AttachmentMap.TOPEND; + } + } else if ($parentDropdown.hasClass(ClassName$4.DROPRIGHT)) { + placement = AttachmentMap.RIGHT; + } else if ($parentDropdown.hasClass(ClassName$4.DROPLEFT)) { + placement = AttachmentMap.LEFT; + } else if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) { + placement = AttachmentMap.BOTTOMEND; + } + + return placement; + }; + + _proto._detectNavbar = function _detectNavbar() { + return $(this._element).closest('.navbar').length > 0; + }; + + _proto._getPopperConfig = function _getPopperConfig() { + var _this2 = this; + + var offsetConf = {}; + + if (typeof this._config.offset === 'function') { + offsetConf.fn = function (data) { + data.offsets = _objectSpread({}, data.offsets, _this2._config.offset(data.offsets) || {}); + return data; + }; + } else { + offsetConf.offset = this._config.offset; + } + + var popperConfig = { + placement: this._getPlacement(), + modifiers: { + offset: offsetConf, + flip: { + enabled: this._config.flip + }, + preventOverflow: { + boundariesElement: this._config.boundary + } + } // Disable Popper.js if we have a static display + + }; + + if (this._config.display === 'static') { + popperConfig.modifiers.applyStyle = { + enabled: false + }; + } + + return popperConfig; + }; // Static + + + Dropdown._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $(this).data(DATA_KEY$4); + + var _config = typeof config === 'object' ? config : null; + + if (!data) { + data = new Dropdown(this, _config); + $(this).data(DATA_KEY$4, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](); + } + }); + }; + + Dropdown._clearMenus = function _clearMenus(event) { + if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) { + return; + } + + var toggles = [].slice.call(document.querySelectorAll(Selector$4.DATA_TOGGLE)); + + for (var i = 0, len = toggles.length; i < len; i++) { + var parent = Dropdown._getParentFromElement(toggles[i]); + + var context = $(toggles[i]).data(DATA_KEY$4); + var relatedTarget = { + relatedTarget: toggles[i] + }; + + if (event && event.type === 'click') { + relatedTarget.clickEvent = event; + } + + if (!context) { + continue; + } + + var dropdownMenu = context._menu; + + if (!$(parent).hasClass(ClassName$4.SHOW)) { + continue; + } + + if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $.contains(parent, event.target)) { + continue; + } + + var hideEvent = $.Event(Event$4.HIDE, relatedTarget); + $(parent).trigger(hideEvent); + + if (hideEvent.isDefaultPrevented()) { + continue; + } // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + + + if ('ontouchstart' in document.documentElement) { + $(document.body).children().off('mouseover', null, $.noop); + } + + toggles[i].setAttribute('aria-expanded', 'false'); + $(dropdownMenu).removeClass(ClassName$4.SHOW); + $(parent).removeClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget)); + } + }; + + Dropdown._getParentFromElement = function _getParentFromElement(element) { + var parent; + var selector = Util.getSelectorFromElement(element); + + if (selector) { + parent = document.querySelector(selector); + } + + return parent || element.parentNode; + }; // eslint-disable-next-line complexity + + + Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) { + // If not input/textarea: + // - And not a key in REGEXP_KEYDOWN => not a dropdown command + // If input/textarea: + // - If space key => not a dropdown command + // - If key is other than escape + // - If key is not up or down => not a dropdown command + // - If trigger inside the menu => not a dropdown command + if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $(event.target).closest(Selector$4.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) { + return; + } + + event.preventDefault(); + event.stopPropagation(); + + if (this.disabled || $(this).hasClass(ClassName$4.DISABLED)) { + return; + } + + var parent = Dropdown._getParentFromElement(this); + + var isActive = $(parent).hasClass(ClassName$4.SHOW); + + if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) { + if (event.which === ESCAPE_KEYCODE) { + var toggle = parent.querySelector(Selector$4.DATA_TOGGLE); + $(toggle).trigger('focus'); + } + + $(this).trigger('click'); + return; + } + + var items = [].slice.call(parent.querySelectorAll(Selector$4.VISIBLE_ITEMS)); + + if (items.length === 0) { + return; + } + + var index = items.indexOf(event.target); + + if (event.which === ARROW_UP_KEYCODE && index > 0) { + // Up + index--; + } + + if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { + // Down + index++; + } + + if (index < 0) { + index = 0; + } + + items[index].focus(); + }; + + _createClass(Dropdown, null, [{ + key: "VERSION", + get: function get() { + return VERSION$4; + } + }, { + key: "Default", + get: function get() { + return Default$2; + } + }, { + key: "DefaultType", + get: function get() { + return DefaultType$2; + } + }]); + + return Dropdown; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event$4.KEYDOWN_DATA_API, Selector$4.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event$4.KEYDOWN_DATA_API, Selector$4.MENU, Dropdown._dataApiKeydownHandler).on(Event$4.CLICK_DATA_API + " " + Event$4.KEYUP_DATA_API, Dropdown._clearMenus).on(Event$4.CLICK_DATA_API, Selector$4.DATA_TOGGLE, function (event) { + event.preventDefault(); + event.stopPropagation(); + + Dropdown._jQueryInterface.call($(this), 'toggle'); + }).on(Event$4.CLICK_DATA_API, Selector$4.FORM_CHILD, function (e) { + e.stopPropagation(); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME$4] = Dropdown._jQueryInterface; + $.fn[NAME$4].Constructor = Dropdown; + + $.fn[NAME$4].noConflict = function () { + $.fn[NAME$4] = JQUERY_NO_CONFLICT$4; + return Dropdown._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$5 = 'modal'; + var VERSION$5 = '4.2.1'; + var DATA_KEY$5 = 'bs.modal'; + var EVENT_KEY$5 = "." + DATA_KEY$5; + var DATA_API_KEY$5 = '.data-api'; + var JQUERY_NO_CONFLICT$5 = $.fn[NAME$5]; + var ESCAPE_KEYCODE$1 = 27; // KeyboardEvent.which value for Escape (Esc) key + + var Default$3 = { + backdrop: true, + keyboard: true, + focus: true, + show: true + }; + var DefaultType$3 = { + backdrop: '(boolean|string)', + keyboard: 'boolean', + focus: 'boolean', + show: 'boolean' + }; + var Event$5 = { + HIDE: "hide" + EVENT_KEY$5, + HIDDEN: "hidden" + EVENT_KEY$5, + SHOW: "show" + EVENT_KEY$5, + SHOWN: "shown" + EVENT_KEY$5, + FOCUSIN: "focusin" + EVENT_KEY$5, + RESIZE: "resize" + EVENT_KEY$5, + CLICK_DISMISS: "click.dismiss" + EVENT_KEY$5, + KEYDOWN_DISMISS: "keydown.dismiss" + EVENT_KEY$5, + MOUSEUP_DISMISS: "mouseup.dismiss" + EVENT_KEY$5, + MOUSEDOWN_DISMISS: "mousedown.dismiss" + EVENT_KEY$5, + CLICK_DATA_API: "click" + EVENT_KEY$5 + DATA_API_KEY$5 + }; + var ClassName$5 = { + SCROLLBAR_MEASURER: 'modal-scrollbar-measure', + BACKDROP: 'modal-backdrop', + OPEN: 'modal-open', + FADE: 'fade', + SHOW: 'show' + }; + var Selector$5 = { + DIALOG: '.modal-dialog', + DATA_TOGGLE: '[data-toggle="modal"]', + DATA_DISMISS: '[data-dismiss="modal"]', + FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top', + STICKY_CONTENT: '.sticky-top' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Modal = + /*#__PURE__*/ + function () { + function Modal(element, config) { + this._config = this._getConfig(config); + this._element = element; + this._dialog = element.querySelector(Selector$5.DIALOG); + this._backdrop = null; + this._isShown = false; + this._isBodyOverflowing = false; + this._ignoreBackdropClick = false; + this._isTransitioning = false; + this._scrollbarWidth = 0; + } // Getters + + + var _proto = Modal.prototype; + + // Public + _proto.toggle = function toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget); + }; + + _proto.show = function show(relatedTarget) { + var _this = this; + + if (this._isShown || this._isTransitioning) { + return; + } + + if ($(this._element).hasClass(ClassName$5.FADE)) { + this._isTransitioning = true; + } + + var showEvent = $.Event(Event$5.SHOW, { + relatedTarget: relatedTarget + }); + $(this._element).trigger(showEvent); + + if (this._isShown || showEvent.isDefaultPrevented()) { + return; + } + + this._isShown = true; + + this._checkScrollbar(); + + this._setScrollbar(); + + this._adjustDialog(); + + this._setEscapeEvent(); + + this._setResizeEvent(); + + $(this._element).on(Event$5.CLICK_DISMISS, Selector$5.DATA_DISMISS, function (event) { + return _this.hide(event); + }); + $(this._dialog).on(Event$5.MOUSEDOWN_DISMISS, function () { + $(_this._element).one(Event$5.MOUSEUP_DISMISS, function (event) { + if ($(event.target).is(_this._element)) { + _this._ignoreBackdropClick = true; + } + }); + }); + + this._showBackdrop(function () { + return _this._showElement(relatedTarget); + }); + }; + + _proto.hide = function hide(event) { + var _this2 = this; + + if (event) { + event.preventDefault(); + } + + if (!this._isShown || this._isTransitioning) { + return; + } + + var hideEvent = $.Event(Event$5.HIDE); + $(this._element).trigger(hideEvent); + + if (!this._isShown || hideEvent.isDefaultPrevented()) { + return; + } + + this._isShown = false; + var transition = $(this._element).hasClass(ClassName$5.FADE); + + if (transition) { + this._isTransitioning = true; + } + + this._setEscapeEvent(); + + this._setResizeEvent(); + + $(document).off(Event$5.FOCUSIN); + $(this._element).removeClass(ClassName$5.SHOW); + $(this._element).off(Event$5.CLICK_DISMISS); + $(this._dialog).off(Event$5.MOUSEDOWN_DISMISS); + + if (transition) { + var transitionDuration = Util.getTransitionDurationFromElement(this._element); + $(this._element).one(Util.TRANSITION_END, function (event) { + return _this2._hideModal(event); + }).emulateTransitionEnd(transitionDuration); + } else { + this._hideModal(); + } + }; + + _proto.dispose = function dispose() { + [window, this._element, this._dialog].forEach(function (htmlElement) { + return $(htmlElement).off(EVENT_KEY$5); + }); + /** + * `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API` + * Do not move `document` in `htmlElements` array + * It will remove `Event.CLICK_DATA_API` event that should remain + */ + + $(document).off(Event$5.FOCUSIN); + $.removeData(this._element, DATA_KEY$5); + this._config = null; + this._element = null; + this._dialog = null; + this._backdrop = null; + this._isShown = null; + this._isBodyOverflowing = null; + this._ignoreBackdropClick = null; + this._isTransitioning = null; + this._scrollbarWidth = null; + }; + + _proto.handleUpdate = function handleUpdate() { + this._adjustDialog(); + }; // Private + + + _proto._getConfig = function _getConfig(config) { + config = _objectSpread({}, Default$3, config); + Util.typeCheckConfig(NAME$5, config, DefaultType$3); + return config; + }; + + _proto._showElement = function _showElement(relatedTarget) { + var _this3 = this; + + var transition = $(this._element).hasClass(ClassName$5.FADE); + + if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { + // Don't move modal's DOM position + document.body.appendChild(this._element); + } + + this._element.style.display = 'block'; + + this._element.removeAttribute('aria-hidden'); + + this._element.setAttribute('aria-modal', true); + + this._element.scrollTop = 0; + + if (transition) { + Util.reflow(this._element); + } + + $(this._element).addClass(ClassName$5.SHOW); + + if (this._config.focus) { + this._enforceFocus(); + } + + var shownEvent = $.Event(Event$5.SHOWN, { + relatedTarget: relatedTarget + }); + + var transitionComplete = function transitionComplete() { + if (_this3._config.focus) { + _this3._element.focus(); + } + + _this3._isTransitioning = false; + $(_this3._element).trigger(shownEvent); + }; + + if (transition) { + var transitionDuration = Util.getTransitionDurationFromElement(this._dialog); + $(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration); + } else { + transitionComplete(); + } + }; + + _proto._enforceFocus = function _enforceFocus() { + var _this4 = this; + + $(document).off(Event$5.FOCUSIN) // Guard against infinite focus loop + .on(Event$5.FOCUSIN, function (event) { + if (document !== event.target && _this4._element !== event.target && $(_this4._element).has(event.target).length === 0) { + _this4._element.focus(); + } + }); + }; + + _proto._setEscapeEvent = function _setEscapeEvent() { + var _this5 = this; + + if (this._isShown && this._config.keyboard) { + $(this._element).on(Event$5.KEYDOWN_DISMISS, function (event) { + if (event.which === ESCAPE_KEYCODE$1) { + event.preventDefault(); + + _this5.hide(); + } + }); + } else if (!this._isShown) { + $(this._element).off(Event$5.KEYDOWN_DISMISS); + } + }; + + _proto._setResizeEvent = function _setResizeEvent() { + var _this6 = this; + + if (this._isShown) { + $(window).on(Event$5.RESIZE, function (event) { + return _this6.handleUpdate(event); + }); + } else { + $(window).off(Event$5.RESIZE); + } + }; + + _proto._hideModal = function _hideModal() { + var _this7 = this; + + this._element.style.display = 'none'; + + this._element.setAttribute('aria-hidden', true); + + this._element.removeAttribute('aria-modal'); + + this._isTransitioning = false; + + this._showBackdrop(function () { + $(document.body).removeClass(ClassName$5.OPEN); + + _this7._resetAdjustments(); + + _this7._resetScrollbar(); + + $(_this7._element).trigger(Event$5.HIDDEN); + }); + }; + + _proto._removeBackdrop = function _removeBackdrop() { + if (this._backdrop) { + $(this._backdrop).remove(); + this._backdrop = null; + } + }; + + _proto._showBackdrop = function _showBackdrop(callback) { + var _this8 = this; + + var animate = $(this._element).hasClass(ClassName$5.FADE) ? ClassName$5.FADE : ''; + + if (this._isShown && this._config.backdrop) { + this._backdrop = document.createElement('div'); + this._backdrop.className = ClassName$5.BACKDROP; + + if (animate) { + this._backdrop.classList.add(animate); + } + + $(this._backdrop).appendTo(document.body); + $(this._element).on(Event$5.CLICK_DISMISS, function (event) { + if (_this8._ignoreBackdropClick) { + _this8._ignoreBackdropClick = false; + return; + } + + if (event.target !== event.currentTarget) { + return; + } + + if (_this8._config.backdrop === 'static') { + _this8._element.focus(); + } else { + _this8.hide(); + } + }); + + if (animate) { + Util.reflow(this._backdrop); + } + + $(this._backdrop).addClass(ClassName$5.SHOW); + + if (!callback) { + return; + } + + if (!animate) { + callback(); + return; + } + + var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop); + $(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration); + } else if (!this._isShown && this._backdrop) { + $(this._backdrop).removeClass(ClassName$5.SHOW); + + var callbackRemove = function callbackRemove() { + _this8._removeBackdrop(); + + if (callback) { + callback(); + } + }; + + if ($(this._element).hasClass(ClassName$5.FADE)) { + var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop); + + $(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration); + } else { + callbackRemove(); + } + } else if (callback) { + callback(); + } + }; // ---------------------------------------------------------------------- + // the following methods are used to handle overflowing modals + // todo (fat): these should probably be refactored out of modal.js + // ---------------------------------------------------------------------- + + + _proto._adjustDialog = function _adjustDialog() { + var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; + + if (!this._isBodyOverflowing && isModalOverflowing) { + this._element.style.paddingLeft = this._scrollbarWidth + "px"; + } + + if (this._isBodyOverflowing && !isModalOverflowing) { + this._element.style.paddingRight = this._scrollbarWidth + "px"; + } + }; + + _proto._resetAdjustments = function _resetAdjustments() { + this._element.style.paddingLeft = ''; + this._element.style.paddingRight = ''; + }; + + _proto._checkScrollbar = function _checkScrollbar() { + var rect = document.body.getBoundingClientRect(); + this._isBodyOverflowing = rect.left + rect.right < window.innerWidth; + this._scrollbarWidth = this._getScrollbarWidth(); + }; + + _proto._setScrollbar = function _setScrollbar() { + var _this9 = this; + + if (this._isBodyOverflowing) { + // Note: DOMNode.style.paddingRight returns the actual value or '' if not set + // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set + var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT)); + var stickyContent = [].slice.call(document.querySelectorAll(Selector$5.STICKY_CONTENT)); // Adjust fixed content padding + + $(fixedContent).each(function (index, element) { + var actualPadding = element.style.paddingRight; + var calculatedPadding = $(element).css('padding-right'); + $(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this9._scrollbarWidth + "px"); + }); // Adjust sticky content margin + + $(stickyContent).each(function (index, element) { + var actualMargin = element.style.marginRight; + var calculatedMargin = $(element).css('margin-right'); + $(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this9._scrollbarWidth + "px"); + }); // Adjust body padding + + var actualPadding = document.body.style.paddingRight; + var calculatedPadding = $(document.body).css('padding-right'); + $(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + "px"); + } + + $(document.body).addClass(ClassName$5.OPEN); + }; + + _proto._resetScrollbar = function _resetScrollbar() { + // Restore fixed content padding + var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT)); + $(fixedContent).each(function (index, element) { + var padding = $(element).data('padding-right'); + $(element).removeData('padding-right'); + element.style.paddingRight = padding ? padding : ''; + }); // Restore sticky content + + var elements = [].slice.call(document.querySelectorAll("" + Selector$5.STICKY_CONTENT)); + $(elements).each(function (index, element) { + var margin = $(element).data('margin-right'); + + if (typeof margin !== 'undefined') { + $(element).css('margin-right', margin).removeData('margin-right'); + } + }); // Restore body padding + + var padding = $(document.body).data('padding-right'); + $(document.body).removeData('padding-right'); + document.body.style.paddingRight = padding ? padding : ''; + }; + + _proto._getScrollbarWidth = function _getScrollbarWidth() { + // thx d.walsh + var scrollDiv = document.createElement('div'); + scrollDiv.className = ClassName$5.SCROLLBAR_MEASURER; + document.body.appendChild(scrollDiv); + var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth; + document.body.removeChild(scrollDiv); + return scrollbarWidth; + }; // Static + + + Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) { + return this.each(function () { + var data = $(this).data(DATA_KEY$5); + + var _config = _objectSpread({}, Default$3, $(this).data(), typeof config === 'object' && config ? config : {}); + + if (!data) { + data = new Modal(this, _config); + $(this).data(DATA_KEY$5, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](relatedTarget); + } else if (_config.show) { + data.show(relatedTarget); + } + }); + }; + + _createClass(Modal, null, [{ + key: "VERSION", + get: function get() { + return VERSION$5; + } + }, { + key: "Default", + get: function get() { + return Default$3; + } + }]); + + return Modal; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event$5.CLICK_DATA_API, Selector$5.DATA_TOGGLE, function (event) { + var _this10 = this; + + var target; + var selector = Util.getSelectorFromElement(this); + + if (selector) { + target = document.querySelector(selector); + } + + var config = $(target).data(DATA_KEY$5) ? 'toggle' : _objectSpread({}, $(target).data(), $(this).data()); + + if (this.tagName === 'A' || this.tagName === 'AREA') { + event.preventDefault(); + } + + var $target = $(target).one(Event$5.SHOW, function (showEvent) { + if (showEvent.isDefaultPrevented()) { + // Only register focus restorer if modal will actually get shown + return; + } + + $target.one(Event$5.HIDDEN, function () { + if ($(_this10).is(':visible')) { + _this10.focus(); + } + }); + }); + + Modal._jQueryInterface.call($(target), config, this); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME$5] = Modal._jQueryInterface; + $.fn[NAME$5].Constructor = Modal; + + $.fn[NAME$5].noConflict = function () { + $.fn[NAME$5] = JQUERY_NO_CONFLICT$5; + return Modal._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$6 = 'tooltip'; + var VERSION$6 = '4.2.1'; + var DATA_KEY$6 = 'bs.tooltip'; + var EVENT_KEY$6 = "." + DATA_KEY$6; + var JQUERY_NO_CONFLICT$6 = $.fn[NAME$6]; + var CLASS_PREFIX = 'bs-tooltip'; + var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g'); + var DefaultType$4 = { + animation: 'boolean', + template: 'string', + title: '(string|element|function)', + trigger: 'string', + delay: '(number|object)', + html: 'boolean', + selector: '(string|boolean)', + placement: '(string|function)', + offset: '(number|string)', + container: '(string|element|boolean)', + fallbackPlacement: '(string|array)', + boundary: '(string|element)' + }; + var AttachmentMap$1 = { + AUTO: 'auto', + TOP: 'top', + RIGHT: 'right', + BOTTOM: 'bottom', + LEFT: 'left' + }; + var Default$4 = { + animation: true, + template: '', + trigger: 'hover focus', + title: '', + delay: 0, + html: false, + selector: false, + placement: 'top', + offset: 0, + container: false, + fallbackPlacement: 'flip', + boundary: 'scrollParent' + }; + var HoverState = { + SHOW: 'show', + OUT: 'out' + }; + var Event$6 = { + HIDE: "hide" + EVENT_KEY$6, + HIDDEN: "hidden" + EVENT_KEY$6, + SHOW: "show" + EVENT_KEY$6, + SHOWN: "shown" + EVENT_KEY$6, + INSERTED: "inserted" + EVENT_KEY$6, + CLICK: "click" + EVENT_KEY$6, + FOCUSIN: "focusin" + EVENT_KEY$6, + FOCUSOUT: "focusout" + EVENT_KEY$6, + MOUSEENTER: "mouseenter" + EVENT_KEY$6, + MOUSELEAVE: "mouseleave" + EVENT_KEY$6 + }; + var ClassName$6 = { + FADE: 'fade', + SHOW: 'show' + }; + var Selector$6 = { + TOOLTIP: '.tooltip', + TOOLTIP_INNER: '.tooltip-inner', + ARROW: '.arrow' + }; + var Trigger = { + HOVER: 'hover', + FOCUS: 'focus', + CLICK: 'click', + MANUAL: 'manual' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Tooltip = + /*#__PURE__*/ + function () { + function Tooltip(element, config) { + /** + * Check for Popper dependency + * Popper - https://popper.js.org + */ + if (typeof Popper === 'undefined') { + throw new TypeError('Bootstrap\'s tooltips require Popper.js (https://popper.js.org/)'); + } // private + + + this._isEnabled = true; + this._timeout = 0; + this._hoverState = ''; + this._activeTrigger = {}; + this._popper = null; // Protected + + this.element = element; + this.config = this._getConfig(config); + this.tip = null; + + this._setListeners(); + } // Getters + + + var _proto = Tooltip.prototype; + + // Public + _proto.enable = function enable() { + this._isEnabled = true; + }; + + _proto.disable = function disable() { + this._isEnabled = false; + }; + + _proto.toggleEnabled = function toggleEnabled() { + this._isEnabled = !this._isEnabled; + }; + + _proto.toggle = function toggle(event) { + if (!this._isEnabled) { + return; + } + + if (event) { + var dataKey = this.constructor.DATA_KEY; + var context = $(event.currentTarget).data(dataKey); + + if (!context) { + context = new this.constructor(event.currentTarget, this._getDelegateConfig()); + $(event.currentTarget).data(dataKey, context); + } + + context._activeTrigger.click = !context._activeTrigger.click; + + if (context._isWithActiveTrigger()) { + context._enter(null, context); + } else { + context._leave(null, context); + } + } else { + if ($(this.getTipElement()).hasClass(ClassName$6.SHOW)) { + this._leave(null, this); + + return; + } + + this._enter(null, this); + } + }; + + _proto.dispose = function dispose() { + clearTimeout(this._timeout); + $.removeData(this.element, this.constructor.DATA_KEY); + $(this.element).off(this.constructor.EVENT_KEY); + $(this.element).closest('.modal').off('hide.bs.modal'); + + if (this.tip) { + $(this.tip).remove(); + } + + this._isEnabled = null; + this._timeout = null; + this._hoverState = null; + this._activeTrigger = null; + + if (this._popper !== null) { + this._popper.destroy(); + } + + this._popper = null; + this.element = null; + this.config = null; + this.tip = null; + }; + + _proto.show = function show() { + var _this = this; + + if ($(this.element).css('display') === 'none') { + throw new Error('Please use show on visible elements'); + } + + var showEvent = $.Event(this.constructor.Event.SHOW); + + if (this.isWithContent() && this._isEnabled) { + $(this.element).trigger(showEvent); + var shadowRoot = Util.findShadowRoot(this.element); + var isInTheDom = $.contains(shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, this.element); + + if (showEvent.isDefaultPrevented() || !isInTheDom) { + return; + } + + var tip = this.getTipElement(); + var tipId = Util.getUID(this.constructor.NAME); + tip.setAttribute('id', tipId); + this.element.setAttribute('aria-describedby', tipId); + this.setContent(); + + if (this.config.animation) { + $(tip).addClass(ClassName$6.FADE); + } + + var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement; + + var attachment = this._getAttachment(placement); + + this.addAttachmentClass(attachment); + + var container = this._getContainer(); + + $(tip).data(this.constructor.DATA_KEY, this); + + if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) { + $(tip).appendTo(container); + } + + $(this.element).trigger(this.constructor.Event.INSERTED); + this._popper = new Popper(this.element, tip, { + placement: attachment, + modifiers: { + offset: { + offset: this.config.offset + }, + flip: { + behavior: this.config.fallbackPlacement + }, + arrow: { + element: Selector$6.ARROW + }, + preventOverflow: { + boundariesElement: this.config.boundary + } + }, + onCreate: function onCreate(data) { + if (data.originalPlacement !== data.placement) { + _this._handlePopperPlacementChange(data); + } + }, + onUpdate: function onUpdate(data) { + return _this._handlePopperPlacementChange(data); + } + }); + $(tip).addClass(ClassName$6.SHOW); // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + + if ('ontouchstart' in document.documentElement) { + $(document.body).children().on('mouseover', null, $.noop); + } + + var complete = function complete() { + if (_this.config.animation) { + _this._fixTransition(); + } + + var prevHoverState = _this._hoverState; + _this._hoverState = null; + $(_this.element).trigger(_this.constructor.Event.SHOWN); + + if (prevHoverState === HoverState.OUT) { + _this._leave(null, _this); + } + }; + + if ($(this.tip).hasClass(ClassName$6.FADE)) { + var transitionDuration = Util.getTransitionDurationFromElement(this.tip); + $(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); + } else { + complete(); + } + } + }; + + _proto.hide = function hide(callback) { + var _this2 = this; + + var tip = this.getTipElement(); + var hideEvent = $.Event(this.constructor.Event.HIDE); + + var complete = function complete() { + if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) { + tip.parentNode.removeChild(tip); + } + + _this2._cleanTipClass(); + + _this2.element.removeAttribute('aria-describedby'); + + $(_this2.element).trigger(_this2.constructor.Event.HIDDEN); + + if (_this2._popper !== null) { + _this2._popper.destroy(); + } + + if (callback) { + callback(); + } + }; + + $(this.element).trigger(hideEvent); + + if (hideEvent.isDefaultPrevented()) { + return; + } + + $(tip).removeClass(ClassName$6.SHOW); // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + + if ('ontouchstart' in document.documentElement) { + $(document.body).children().off('mouseover', null, $.noop); + } + + this._activeTrigger[Trigger.CLICK] = false; + this._activeTrigger[Trigger.FOCUS] = false; + this._activeTrigger[Trigger.HOVER] = false; + + if ($(this.tip).hasClass(ClassName$6.FADE)) { + var transitionDuration = Util.getTransitionDurationFromElement(tip); + $(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); + } else { + complete(); + } + + this._hoverState = ''; + }; + + _proto.update = function update() { + if (this._popper !== null) { + this._popper.scheduleUpdate(); + } + }; // Protected + + + _proto.isWithContent = function isWithContent() { + return Boolean(this.getTitle()); + }; + + _proto.addAttachmentClass = function addAttachmentClass(attachment) { + $(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment); + }; + + _proto.getTipElement = function getTipElement() { + this.tip = this.tip || $(this.config.template)[0]; + return this.tip; + }; + + _proto.setContent = function setContent() { + var tip = this.getTipElement(); + this.setElementContent($(tip.querySelectorAll(Selector$6.TOOLTIP_INNER)), this.getTitle()); + $(tip).removeClass(ClassName$6.FADE + " " + ClassName$6.SHOW); + }; + + _proto.setElementContent = function setElementContent($element, content) { + var html = this.config.html; + + if (typeof content === 'object' && (content.nodeType || content.jquery)) { + // Content is a DOM node or a jQuery + if (html) { + if (!$(content).parent().is($element)) { + $element.empty().append(content); + } + } else { + $element.text($(content).text()); + } + } else { + $element[html ? 'html' : 'text'](content); + } + }; + + _proto.getTitle = function getTitle() { + var title = this.element.getAttribute('data-original-title'); + + if (!title) { + title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title; + } + + return title; + }; // Private + + + _proto._getContainer = function _getContainer() { + if (this.config.container === false) { + return document.body; + } + + if (Util.isElement(this.config.container)) { + return $(this.config.container); + } + + return $(document).find(this.config.container); + }; + + _proto._getAttachment = function _getAttachment(placement) { + return AttachmentMap$1[placement.toUpperCase()]; + }; + + _proto._setListeners = function _setListeners() { + var _this3 = this; + + var triggers = this.config.trigger.split(' '); + triggers.forEach(function (trigger) { + if (trigger === 'click') { + $(_this3.element).on(_this3.constructor.Event.CLICK, _this3.config.selector, function (event) { + return _this3.toggle(event); + }); + } else if (trigger !== Trigger.MANUAL) { + var eventIn = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSEENTER : _this3.constructor.Event.FOCUSIN; + var eventOut = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSELEAVE : _this3.constructor.Event.FOCUSOUT; + $(_this3.element).on(eventIn, _this3.config.selector, function (event) { + return _this3._enter(event); + }).on(eventOut, _this3.config.selector, function (event) { + return _this3._leave(event); + }); + } + }); + $(this.element).closest('.modal').on('hide.bs.modal', function () { + if (_this3.element) { + _this3.hide(); + } + }); + + if (this.config.selector) { + this.config = _objectSpread({}, this.config, { + trigger: 'manual', + selector: '' + }); + } else { + this._fixTitle(); + } + }; + + _proto._fixTitle = function _fixTitle() { + var titleType = typeof this.element.getAttribute('data-original-title'); + + if (this.element.getAttribute('title') || titleType !== 'string') { + this.element.setAttribute('data-original-title', this.element.getAttribute('title') || ''); + this.element.setAttribute('title', ''); + } + }; + + _proto._enter = function _enter(event, context) { + var dataKey = this.constructor.DATA_KEY; + context = context || $(event.currentTarget).data(dataKey); + + if (!context) { + context = new this.constructor(event.currentTarget, this._getDelegateConfig()); + $(event.currentTarget).data(dataKey, context); + } + + if (event) { + context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true; + } + + if ($(context.getTipElement()).hasClass(ClassName$6.SHOW) || context._hoverState === HoverState.SHOW) { + context._hoverState = HoverState.SHOW; + return; + } + + clearTimeout(context._timeout); + context._hoverState = HoverState.SHOW; + + if (!context.config.delay || !context.config.delay.show) { + context.show(); + return; + } + + context._timeout = setTimeout(function () { + if (context._hoverState === HoverState.SHOW) { + context.show(); + } + }, context.config.delay.show); + }; + + _proto._leave = function _leave(event, context) { + var dataKey = this.constructor.DATA_KEY; + context = context || $(event.currentTarget).data(dataKey); + + if (!context) { + context = new this.constructor(event.currentTarget, this._getDelegateConfig()); + $(event.currentTarget).data(dataKey, context); + } + + if (event) { + context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false; + } + + if (context._isWithActiveTrigger()) { + return; + } + + clearTimeout(context._timeout); + context._hoverState = HoverState.OUT; + + if (!context.config.delay || !context.config.delay.hide) { + context.hide(); + return; + } + + context._timeout = setTimeout(function () { + if (context._hoverState === HoverState.OUT) { + context.hide(); + } + }, context.config.delay.hide); + }; + + _proto._isWithActiveTrigger = function _isWithActiveTrigger() { + for (var trigger in this._activeTrigger) { + if (this._activeTrigger[trigger]) { + return true; + } + } + + return false; + }; + + _proto._getConfig = function _getConfig(config) { + config = _objectSpread({}, this.constructor.Default, $(this.element).data(), typeof config === 'object' && config ? config : {}); + + if (typeof config.delay === 'number') { + config.delay = { + show: config.delay, + hide: config.delay + }; + } + + if (typeof config.title === 'number') { + config.title = config.title.toString(); + } + + if (typeof config.content === 'number') { + config.content = config.content.toString(); + } + + Util.typeCheckConfig(NAME$6, config, this.constructor.DefaultType); + return config; + }; + + _proto._getDelegateConfig = function _getDelegateConfig() { + var config = {}; + + if (this.config) { + for (var key in this.config) { + if (this.constructor.Default[key] !== this.config[key]) { + config[key] = this.config[key]; + } + } + } + + return config; + }; + + _proto._cleanTipClass = function _cleanTipClass() { + var $tip = $(this.getTipElement()); + var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX); + + if (tabClass !== null && tabClass.length) { + $tip.removeClass(tabClass.join('')); + } + }; + + _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) { + var popperInstance = popperData.instance; + this.tip = popperInstance.popper; + + this._cleanTipClass(); + + this.addAttachmentClass(this._getAttachment(popperData.placement)); + }; + + _proto._fixTransition = function _fixTransition() { + var tip = this.getTipElement(); + var initConfigAnimation = this.config.animation; + + if (tip.getAttribute('x-placement') !== null) { + return; + } + + $(tip).removeClass(ClassName$6.FADE); + this.config.animation = false; + this.hide(); + this.show(); + this.config.animation = initConfigAnimation; + }; // Static + + + Tooltip._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $(this).data(DATA_KEY$6); + + var _config = typeof config === 'object' && config; + + if (!data && /dispose|hide/.test(config)) { + return; + } + + if (!data) { + data = new Tooltip(this, _config); + $(this).data(DATA_KEY$6, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](); + } + }); + }; + + _createClass(Tooltip, null, [{ + key: "VERSION", + get: function get() { + return VERSION$6; + } + }, { + key: "Default", + get: function get() { + return Default$4; + } + }, { + key: "NAME", + get: function get() { + return NAME$6; + } + }, { + key: "DATA_KEY", + get: function get() { + return DATA_KEY$6; + } + }, { + key: "Event", + get: function get() { + return Event$6; + } + }, { + key: "EVENT_KEY", + get: function get() { + return EVENT_KEY$6; + } + }, { + key: "DefaultType", + get: function get() { + return DefaultType$4; + } + }]); + + return Tooltip; + }(); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + + $.fn[NAME$6] = Tooltip._jQueryInterface; + $.fn[NAME$6].Constructor = Tooltip; + + $.fn[NAME$6].noConflict = function () { + $.fn[NAME$6] = JQUERY_NO_CONFLICT$6; + return Tooltip._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$7 = 'popover'; + var VERSION$7 = '4.2.1'; + var DATA_KEY$7 = 'bs.popover'; + var EVENT_KEY$7 = "." + DATA_KEY$7; + var JQUERY_NO_CONFLICT$7 = $.fn[NAME$7]; + var CLASS_PREFIX$1 = 'bs-popover'; + var BSCLS_PREFIX_REGEX$1 = new RegExp("(^|\\s)" + CLASS_PREFIX$1 + "\\S+", 'g'); + + var Default$5 = _objectSpread({}, Tooltip.Default, { + placement: 'right', + trigger: 'click', + content: '', + template: '' + }); + + var DefaultType$5 = _objectSpread({}, Tooltip.DefaultType, { + content: '(string|element|function)' + }); + + var ClassName$7 = { + FADE: 'fade', + SHOW: 'show' + }; + var Selector$7 = { + TITLE: '.popover-header', + CONTENT: '.popover-body' + }; + var Event$7 = { + HIDE: "hide" + EVENT_KEY$7, + HIDDEN: "hidden" + EVENT_KEY$7, + SHOW: "show" + EVENT_KEY$7, + SHOWN: "shown" + EVENT_KEY$7, + INSERTED: "inserted" + EVENT_KEY$7, + CLICK: "click" + EVENT_KEY$7, + FOCUSIN: "focusin" + EVENT_KEY$7, + FOCUSOUT: "focusout" + EVENT_KEY$7, + MOUSEENTER: "mouseenter" + EVENT_KEY$7, + MOUSELEAVE: "mouseleave" + EVENT_KEY$7 + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var Popover = + /*#__PURE__*/ + function (_Tooltip) { + _inheritsLoose(Popover, _Tooltip); + + function Popover() { + return _Tooltip.apply(this, arguments) || this; + } + + var _proto = Popover.prototype; + + // Overrides + _proto.isWithContent = function isWithContent() { + return this.getTitle() || this._getContent(); + }; + + _proto.addAttachmentClass = function addAttachmentClass(attachment) { + $(this.getTipElement()).addClass(CLASS_PREFIX$1 + "-" + attachment); + }; + + _proto.getTipElement = function getTipElement() { + this.tip = this.tip || $(this.config.template)[0]; + return this.tip; + }; + + _proto.setContent = function setContent() { + var $tip = $(this.getTipElement()); // We use append for html objects to maintain js events + + this.setElementContent($tip.find(Selector$7.TITLE), this.getTitle()); + + var content = this._getContent(); + + if (typeof content === 'function') { + content = content.call(this.element); + } + + this.setElementContent($tip.find(Selector$7.CONTENT), content); + $tip.removeClass(ClassName$7.FADE + " " + ClassName$7.SHOW); + }; // Private + + + _proto._getContent = function _getContent() { + return this.element.getAttribute('data-content') || this.config.content; + }; + + _proto._cleanTipClass = function _cleanTipClass() { + var $tip = $(this.getTipElement()); + var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX$1); + + if (tabClass !== null && tabClass.length > 0) { + $tip.removeClass(tabClass.join('')); + } + }; // Static + + + Popover._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $(this).data(DATA_KEY$7); + + var _config = typeof config === 'object' ? config : null; + + if (!data && /dispose|hide/.test(config)) { + return; + } + + if (!data) { + data = new Popover(this, _config); + $(this).data(DATA_KEY$7, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](); + } + }); + }; + + _createClass(Popover, null, [{ + key: "VERSION", + // Getters + get: function get() { + return VERSION$7; + } + }, { + key: "Default", + get: function get() { + return Default$5; + } + }, { + key: "NAME", + get: function get() { + return NAME$7; + } + }, { + key: "DATA_KEY", + get: function get() { + return DATA_KEY$7; + } + }, { + key: "Event", + get: function get() { + return Event$7; + } + }, { + key: "EVENT_KEY", + get: function get() { + return EVENT_KEY$7; + } + }, { + key: "DefaultType", + get: function get() { + return DefaultType$5; + } + }]); + + return Popover; + }(Tooltip); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + + $.fn[NAME$7] = Popover._jQueryInterface; + $.fn[NAME$7].Constructor = Popover; + + $.fn[NAME$7].noConflict = function () { + $.fn[NAME$7] = JQUERY_NO_CONFLICT$7; + return Popover._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$8 = 'scrollspy'; + var VERSION$8 = '4.2.1'; + var DATA_KEY$8 = 'bs.scrollspy'; + var EVENT_KEY$8 = "." + DATA_KEY$8; + var DATA_API_KEY$6 = '.data-api'; + var JQUERY_NO_CONFLICT$8 = $.fn[NAME$8]; + var Default$6 = { + offset: 10, + method: 'auto', + target: '' + }; + var DefaultType$6 = { + offset: 'number', + method: 'string', + target: '(string|element)' + }; + var Event$8 = { + ACTIVATE: "activate" + EVENT_KEY$8, + SCROLL: "scroll" + EVENT_KEY$8, + LOAD_DATA_API: "load" + EVENT_KEY$8 + DATA_API_KEY$6 + }; + var ClassName$8 = { + DROPDOWN_ITEM: 'dropdown-item', + DROPDOWN_MENU: 'dropdown-menu', + ACTIVE: 'active' + }; + var Selector$8 = { + DATA_SPY: '[data-spy="scroll"]', + ACTIVE: '.active', + NAV_LIST_GROUP: '.nav, .list-group', + NAV_LINKS: '.nav-link', + NAV_ITEMS: '.nav-item', + LIST_ITEMS: '.list-group-item', + DROPDOWN: '.dropdown', + DROPDOWN_ITEMS: '.dropdown-item', + DROPDOWN_TOGGLE: '.dropdown-toggle' + }; + var OffsetMethod = { + OFFSET: 'offset', + POSITION: 'position' + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + }; + + var ScrollSpy = + /*#__PURE__*/ + function () { + function ScrollSpy(element, config) { + var _this = this; + + this._element = element; + this._scrollElement = element.tagName === 'BODY' ? window : element; + this._config = this._getConfig(config); + this._selector = this._config.target + " " + Selector$8.NAV_LINKS + "," + (this._config.target + " " + Selector$8.LIST_ITEMS + ",") + (this._config.target + " " + Selector$8.DROPDOWN_ITEMS); + this._offsets = []; + this._targets = []; + this._activeTarget = null; + this._scrollHeight = 0; + $(this._scrollElement).on(Event$8.SCROLL, function (event) { + return _this._process(event); + }); + this.refresh(); + + this._process(); + } // Getters + + + var _proto = ScrollSpy.prototype; + + // Public + _proto.refresh = function refresh() { + var _this2 = this; + + var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION; + var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method; + var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0; + this._offsets = []; + this._targets = []; + this._scrollHeight = this._getScrollHeight(); + var targets = [].slice.call(document.querySelectorAll(this._selector)); + targets.map(function (element) { + var target; + var targetSelector = Util.getSelectorFromElement(element); + + if (targetSelector) { + target = document.querySelector(targetSelector); + } + + if (target) { + var targetBCR = target.getBoundingClientRect(); + + if (targetBCR.width || targetBCR.height) { + // TODO (fat): remove sketch reliance on jQuery position/offset + return [$(target)[offsetMethod]().top + offsetBase, targetSelector]; + } + } + + return null; + }).filter(function (item) { + return item; + }).sort(function (a, b) { + return a[0] - b[0]; + }).forEach(function (item) { + _this2._offsets.push(item[0]); + + _this2._targets.push(item[1]); + }); + }; + + _proto.dispose = function dispose() { + $.removeData(this._element, DATA_KEY$8); + $(this._scrollElement).off(EVENT_KEY$8); + this._element = null; + this._scrollElement = null; + this._config = null; + this._selector = null; + this._offsets = null; + this._targets = null; + this._activeTarget = null; + this._scrollHeight = null; + }; // Private + + + _proto._getConfig = function _getConfig(config) { + config = _objectSpread({}, Default$6, typeof config === 'object' && config ? config : {}); + + if (typeof config.target !== 'string') { + var id = $(config.target).attr('id'); + + if (!id) { + id = Util.getUID(NAME$8); + $(config.target).attr('id', id); + } + + config.target = "#" + id; + } + + Util.typeCheckConfig(NAME$8, config, DefaultType$6); + return config; + }; + + _proto._getScrollTop = function _getScrollTop() { + return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop; + }; + + _proto._getScrollHeight = function _getScrollHeight() { + return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); + }; + + _proto._getOffsetHeight = function _getOffsetHeight() { + return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height; + }; + + _proto._process = function _process() { + var scrollTop = this._getScrollTop() + this._config.offset; + + var scrollHeight = this._getScrollHeight(); + + var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight(); + + if (this._scrollHeight !== scrollHeight) { + this.refresh(); + } + + if (scrollTop >= maxScroll) { + var target = this._targets[this._targets.length - 1]; + + if (this._activeTarget !== target) { + this._activate(target); + } + + return; + } + + if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { + this._activeTarget = null; + + this._clear(); + + return; + } + + var offsetLength = this._offsets.length; + + for (var i = offsetLength; i--;) { + var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]); + + if (isActiveTarget) { + this._activate(this._targets[i]); + } + } + }; + + _proto._activate = function _activate(target) { + this._activeTarget = target; + + this._clear(); + + var queries = this._selector.split(',').map(function (selector) { + return selector + "[data-target=\"" + target + "\"]," + selector + "[href=\"" + target + "\"]"; + }); + + var $link = $([].slice.call(document.querySelectorAll(queries.join(',')))); + + if ($link.hasClass(ClassName$8.DROPDOWN_ITEM)) { + $link.closest(Selector$8.DROPDOWN).find(Selector$8.DROPDOWN_TOGGLE).addClass(ClassName$8.ACTIVE); + $link.addClass(ClassName$8.ACTIVE); + } else { + // Set triggered link as active + $link.addClass(ClassName$8.ACTIVE); // Set triggered links parents as active + // With both