Merge branch 'dev' of https://github.com/abpframework/abp into dev
@ -0,0 +1,28 @@
|
||||
name: "Main"
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "framework/**"
|
||||
- "modules/**"
|
||||
- "templates/**"
|
||||
push:
|
||||
paths:
|
||||
- "framework/**"
|
||||
- "modules/**"
|
||||
- "templates/**"
|
||||
jobs:
|
||||
build-test:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-dotnet@master
|
||||
with:
|
||||
dotnet-version: "3.1.100"
|
||||
|
||||
- name: Build All
|
||||
run: .\build\build-all.ps1
|
||||
shell: pwsh
|
||||
|
||||
- name: Test All
|
||||
run: .\build\test-all.ps1
|
||||
shell: pwsh
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"culture": "ru",
|
||||
"texts": {
|
||||
"Account": "Аккаунт",
|
||||
"Welcome": "Добро пожаловать",
|
||||
"UseOneOfTheFollowingLinksToContinue": "Для продолжения используйте одну из следующих ссылок",
|
||||
"FrameworkHomePage": "Главная страница фреймворка",
|
||||
"FrameworkDocumentation": "Документация фреймворка",
|
||||
"OfficialBlog": "Официальный блог",
|
||||
"CommercialHomePage": "Главная страница коммерческой версии",
|
||||
"CommercialSupportWebSite": "Сайт коммерческой поддержки"
|
||||
}
|
||||
}
|
||||
@ -1,126 +1,8 @@
|
||||
## Getting Started With the Angular Application Template
|
||||
# Getting Started with the Startup Templates
|
||||
|
||||
This tutorial explains how to create a new Angular application using the startup template, configure and run it.
|
||||
See the following tutorials to learn how to get started with the ABP Framework using the pre-built application startup templates:
|
||||
|
||||
### Creating a New Project
|
||||
* [Getting Started With the ASP.NET Core MVC / Razor Pages UI](Getting-Started?UI=MVC&DB=EF&Tiered=No)
|
||||
* [Getting Started with the Angular UI](Getting-Started?UI=NG&DB=EF&Tiered=No)
|
||||
|
||||
This tutorial uses **ABP CLI** to create a new project. See the [Get Started](https://abp.io/get-started) page for other options.
|
||||
|
||||
Install the ABP CLI using a command line window, if you've not installed before:
|
||||
|
||||
````bash
|
||||
dotnet tool install -g Volo.Abp.Cli
|
||||
````
|
||||
|
||||
Use `abp new` command in an empty folder to create your project:
|
||||
|
||||
````bash
|
||||
abp new Acme.BookStore -u angular
|
||||
````
|
||||
|
||||
> You can use different level of namespaces; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore.
|
||||
|
||||
`-u angular` option specifies the UI framework to be Angular. Default database provider is EF Core. See the [CLI documentation](CLI.md) for all available options.
|
||||
|
||||
#### Pre Requirements
|
||||
|
||||
The created solution requires;
|
||||
|
||||
* [Visual Studio 2019 (v16.4+)](https://visualstudio.microsoft.com/vs/)
|
||||
* [.NET Core 3.0+](https://www.microsoft.com/net/download/dotnet-core/)
|
||||
* [Node v12+](https://nodejs.org)
|
||||
* [Yarn v1.19+](https://classic.yarnpkg.com/)
|
||||
|
||||
### The Solution Structure
|
||||
|
||||
Open the solution in **Visual Studio**:
|
||||
|
||||

|
||||
|
||||
The solution has a layered structure (based on [Domain Driven Design](Domain-Driven-Design.md)) and contains unit & integration test projects properly configured to work with **EF Core** & **SQLite in-memory** database.
|
||||
|
||||
> See the [Application Template Document](Startup-Templates/Application.md) to understand the solution structure in details.
|
||||
|
||||
### Database Connection String
|
||||
|
||||
Check the **connection string** in the `appsettings.json` file under the `.HttpApi.Host` project:
|
||||
|
||||
````json
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True"
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
The solution is configured to use **Entity Framework Core** with **MS SQL Server**. EF Core supports [various](https://docs.microsoft.com/en-us/ef/core/providers/) database providers, so you can use another DBMS if you want. Change the connection string if you need.
|
||||
|
||||
### Create Database & Apply Database Migrations
|
||||
|
||||
You have two options to create the database.
|
||||
|
||||
#### Using the DbMigrator Application
|
||||
|
||||
The solution contains a console application (named `Acme.BookStore.DbMigrator` in this sample) that can create database, apply migrations and seed initial data. It is useful on development as well as on production environment.
|
||||
|
||||
> `.DbMigrator` project has its own `appsettings.json`. So, if you have changed the connection string above, you should also change this one.
|
||||
|
||||
Right click to the `.DbMigrator` project and select **Set as StartUp Project**:
|
||||
|
||||

|
||||
|
||||
Hit F5 (or Ctrl+F5) to run the application. It will have an output like shown below:
|
||||
|
||||

|
||||
|
||||
#### Using EF Core Update-Database Command
|
||||
|
||||
Ef Core has `Update-Database` command which creates database if necessary and applies pending migrations. Right click to the `.HttpApi.Host` project and select **Set as StartUp Project**:
|
||||
|
||||

|
||||
|
||||
Open the **Package Manager Console**, select `.EntityFrameworkCore.DbMigrations` project as the **Default Project** and run the `Update-Database` command:
|
||||
|
||||

|
||||
|
||||
This will create a new database based on the configured connection string.
|
||||
|
||||
> Using the `.DbMigrator` tool is the suggested way, because it also seeds the initial data to be able to properly run the web application.
|
||||
|
||||
### Running the Application
|
||||
|
||||
#### Run the API Host (Server Side)
|
||||
|
||||
Ensure that the `.HttpApi.Host` project is the startup project and run the application which will open a Swagger UI:
|
||||
|
||||

|
||||
|
||||
You can see the application APIs and test them here. Get [more info](https://swagger.io/tools/swagger-ui/) about the Swagger UI.
|
||||
|
||||
##### Authorization for the Swagger UI
|
||||
|
||||
Most of the application APIs require authentication & authorization. If you want to test authorized APIs, manually go to the `/Account/Login` page, enter `admin` as the username and `1q2w3E*` as the password to login to the application. Then you will be able to execute authorized APIs too.
|
||||
|
||||
#### Run the Angular Application (Client Side)
|
||||
|
||||
Go to the `angular` folder, open a command line terminal, type the `yarn` command (we suggest the [yarn](https://yarnpkg.com) package manager while `npm install` will also work in most cases)
|
||||
|
||||
````bash
|
||||
yarn
|
||||
````
|
||||
|
||||
Once all node modules are loaded, execute `yarn start` or `npm start` command:
|
||||
|
||||
````bash
|
||||
yarn start
|
||||
````
|
||||
|
||||
Open your favorite browser and go to `localhost:4200` URL. Initial username is `admin` and password is `1q2w3E*`.
|
||||
|
||||
The startup template includes the **identity management** and **tenant management** modules. Once you login, the Administration menu will be available where you can manage **tenants**, **roles**, **users** and their **permissions**.
|
||||
|
||||
> We recommend [Visual Studio Code](https://code.visualstudio.com/) as the editor for the Angular project, but you are free to use your favorite editor.
|
||||
|
||||
### What's Next?
|
||||
|
||||
* [Application development tutorial](Tutorials/Part-1)
|
||||
<!-- TODO: this document has been moved, it should be deleted in the future. -->
|
||||
@ -1,104 +1,8 @@
|
||||
## Getting Started With the ASP.NET Core MVC Template
|
||||
# Getting Started with the Startup Templates
|
||||
|
||||
This tutorial explains how to create a new ASP.NET Core MVC web application using the startup template, configure and run it.
|
||||
See the following tutorials to learn how to get started with the ABP Framework using the pre-built application startup templates:
|
||||
|
||||
### Creating a New Project
|
||||
* [Getting Started With the ASP.NET Core MVC / Razor Pages UI](Getting-Started?UI=MVC&DB=EF&Tiered=No)
|
||||
* [Getting Started with the Angular UI](Getting-Started?UI=NG&DB=EF&Tiered=No)
|
||||
|
||||
This tutorial uses **ABP CLI** to create a new project. See the [Get Started](https://abp.io/get-started) page for other options.
|
||||
|
||||
Install the ABP CLI using a command line window, if you've not installed before:
|
||||
|
||||
````bash
|
||||
dotnet tool install -g Volo.Abp.Cli
|
||||
````
|
||||
|
||||
Use `abp new` command in an empty folder to create your project:
|
||||
|
||||
````bash
|
||||
abp new Acme.BookStore
|
||||
````
|
||||
|
||||
> You can use different level of namespaces; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore.
|
||||
|
||||
`new` command creates a **layered MVC application** with **Entity Framework Core** as the database provider. However, it has additional options. See the [CLI documentation](CLI.md) for all available options.
|
||||
|
||||
#### Pre Requirements
|
||||
|
||||
The created solution requires;
|
||||
|
||||
* [Visual Studio 2019 (v16.4+)](https://visualstudio.microsoft.com/vs/)
|
||||
* [.NET Core 3.0+](https://www.microsoft.com/net/download/dotnet-core/)
|
||||
* [Node v12+](https://nodejs.org)
|
||||
* [Yarn v1.19+](https://classic.yarnpkg.com/)
|
||||
|
||||
### The Solution Structure
|
||||
|
||||
Open the solution in **Visual Studio**:
|
||||
|
||||

|
||||
|
||||
The solution has a layered structure (based on [Domain Driven Design](Domain-Driven-Design.md)) and contains unit & integration test projects properly configured to work with **EF Core** & **SQLite in-memory** database.
|
||||
|
||||
> See [Application template document](Startup-Templates/Application.md) to understand the solution structure in details.
|
||||
|
||||
### Database Connection String
|
||||
|
||||
Check the **connection string** in the `appsettings.json` file under the `.Web` project:
|
||||
|
||||
````json
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True"
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
The solution is configured to use **Entity Framework Core** with **MS SQL Server**. EF Core supports [various](https://docs.microsoft.com/en-us/ef/core/providers/) database providers, so you can use another DBMS if you want. Change the connection string if you need.
|
||||
|
||||
### Create Database & Apply Database Migrations
|
||||
|
||||
You have two options to create the database.
|
||||
|
||||
#### Using the DbMigrator Application
|
||||
|
||||
The solution contains a console application (named `Acme.BookStore.DbMigrator` in this sample) that can create database, apply migrations and seed initial data. It is useful on development as well as on production environment.
|
||||
|
||||
> `.DbMigrator` project has its own `appsettings.json`. So, if you have changed the connection string above, you should also change this one.
|
||||
|
||||
Right click to the `.DbMigrator` project and select **Set as StartUp Project**:
|
||||
|
||||

|
||||
|
||||
Hit F5 (or Ctrl+F5) to run the application. It will have an output like shown below:
|
||||
|
||||

|
||||
|
||||
#### Using EF Core Update-Database Command
|
||||
|
||||
Ef Core has `Update-Database` command which creates database if necessary and applies pending migrations. Right click to the `.Web` project and select **Set as StartUp Project**:
|
||||
|
||||

|
||||
|
||||
Open the **Package Manager Console**, select `.EntityFrameworkCore.DbMigrations` project as the **Default Project** and run the `Update-Database` command:
|
||||
|
||||

|
||||
|
||||
This will create a new database based on the configured connection string.
|
||||
|
||||
> Using the `.Migrator` tool is the suggested way, because it also seeds the initial data to be able to properly run the web application.
|
||||
|
||||
### Running the Application
|
||||
|
||||
Ensure that the `.Web` project is the startup project. Run the application which will open the **home** page in your browser:
|
||||
|
||||

|
||||
|
||||
Click the **Login** button, enter `admin` as the username and `1q2w3E*` as the password to login to the application.
|
||||
|
||||
The startup template includes the **identity management** and **tenant management** modules. Once you login, the Administration menu will be available where you can manage **tenants**, **roles**, **users** and their **permissions**. User management page is shown below:
|
||||
|
||||

|
||||
|
||||
### What's Next?
|
||||
|
||||
* [Application development tutorial](Tutorials/Part-1.md)
|
||||
<!-- TODO: this document has been moved, it should be deleted in the future. -->
|
||||
@ -1,3 +1,277 @@
|
||||
## Dynamic Forms
|
||||
# Dynamic Forms
|
||||
|
||||
`Warning:` Before getting into this document, be sure that you have clearly understood [abp form elements](Form-elements.md) document.
|
||||
|
||||
## Introduction
|
||||
|
||||
`abp-dynamic-form` creates a bootstrap form for a given c# model.
|
||||
|
||||
Basic usage:
|
||||
|
||||
````xml
|
||||
<abp-dynamic-form abp-model="@Model.MyDetailedModel"/>
|
||||
````
|
||||
Model:
|
||||
````csharp
|
||||
public class DynamicFormsModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public DetailedModel MyDetailedModel { get; set; }
|
||||
|
||||
public List<SelectListItem> CountryList { get; set; } = new List<SelectListItem>
|
||||
{
|
||||
new SelectListItem { Value = "CA", Text = "Canada"},
|
||||
new SelectListItem { Value = "US", Text = "USA"},
|
||||
new SelectListItem { Value = "UK", Text = "United Kingdom"},
|
||||
new SelectListItem { Value = "RU", Text = "Russia"}
|
||||
};
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
MyDetailedModel = new DetailedModel
|
||||
{
|
||||
Name = "",
|
||||
Description = "Lorem ipsum dolor sit amet.",
|
||||
IsActive = true,
|
||||
Age = 65,
|
||||
Day = DateTime.Now,
|
||||
MyCarType = CarType.Coupe,
|
||||
YourCarType = CarType.Sedan,
|
||||
Country = "RU",
|
||||
NeighborCountries = new List<string>() { "UK", "CA" }
|
||||
};
|
||||
}
|
||||
|
||||
public class DetailedModel
|
||||
{
|
||||
[Required]
|
||||
[Placeholder("Enter your name...")]
|
||||
[Display(Name = "Name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[TextArea(Rows = 4)]
|
||||
[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]
|
||||
[Display(Name = "Age")]
|
||||
public int Age { get; set; }
|
||||
|
||||
[Required]
|
||||
[Display(Name = "My Car Type")]
|
||||
public CarType MyCarType { get; set; }
|
||||
|
||||
[Required]
|
||||
[AbpRadioButton(Inline = true)]
|
||||
[Display(Name = "Your Car Type")]
|
||||
public CarType YourCarType { get; set; }
|
||||
|
||||
[DataType(DataType.Date)]
|
||||
[Display(Name = "Day")]
|
||||
public DateTime Day { get; set; }
|
||||
|
||||
[SelectItems(nameof(CountryList))]
|
||||
[Display(Name = "Country")]
|
||||
public string Country { get; set; }
|
||||
|
||||
[SelectItems(nameof(CountryList))]
|
||||
[Display(Name = "Neighbor Countries")]
|
||||
public List<string> NeighborCountries { get; set; }
|
||||
}
|
||||
|
||||
public enum CarType
|
||||
{
|
||||
Sedan,
|
||||
Hatchback,
|
||||
StationWagon,
|
||||
Coupe
|
||||
}
|
||||
}
|
||||
````
|
||||
## Demo
|
||||
|
||||
See the [dynamic forms demo page](https://bootstrap-taghelpers.abp.io/Components/DynamicForms) to see it in action.
|
||||
|
||||
## Attributes
|
||||
|
||||
### abp-model
|
||||
|
||||
Sets the c# model for dynamic form. Properties of this modal are turned into inputs in the form.
|
||||
|
||||
### submit-button
|
||||
|
||||
Can be `True` or `False`.
|
||||
|
||||
If `True`, a submit button will be generated at the bottom of the form.
|
||||
|
||||
Default value is `False`.
|
||||
|
||||
### required-symbols
|
||||
|
||||
Can be `True` or `False`.
|
||||
|
||||
If `True`, required inputs will have a symbol (*) that indicates they are required.
|
||||
|
||||
Default value is `True`.
|
||||
|
||||
## Form Content Placement
|
||||
|
||||
By default, `abp-dynamicform` clears the inner html and places the inputs into itself. If you want to add additional content to dynamic form or place the inputs to some specific area, you can use ` <abp-form-content />` tag. This tag will be replaced by form content and rest of the inner html of `abp-dynamic-form` tag will be unchanged.
|
||||
|
||||
Usage:
|
||||
|
||||
````xml
|
||||
<abp-dynamic-form abp-model="@Model.MyExampleModel">
|
||||
<div>
|
||||
Some content....
|
||||
</div>
|
||||
<div class="input-area">
|
||||
<abp-form-content />
|
||||
</div>
|
||||
<div>
|
||||
Some more content....
|
||||
</div>
|
||||
</abp-dynamic-form>
|
||||
````
|
||||
|
||||
## Input Order
|
||||
|
||||
`abp-dynamic-form` orders the properties by their `DisplayOrder` attribute and then their property order in model class.
|
||||
|
||||
Default `DisplayOrder` attribute number is 10000 for every property.
|
||||
|
||||
See example below:
|
||||
|
||||
````csharp
|
||||
public class OrderExampleModel
|
||||
{
|
||||
[DisplayOrder(10004)]
|
||||
public string Name{ get; set; }
|
||||
|
||||
[DisplayOrder(10005)]
|
||||
public string Surname{ get; set; }
|
||||
|
||||
//Default 10000
|
||||
public string EmailAddress { get; set; }
|
||||
|
||||
[DisplayOrder(10003)]
|
||||
public string PhoneNumber { get; set; }
|
||||
|
||||
[DisplayOrder(9999)]
|
||||
public string City { get; set; }
|
||||
}
|
||||
````
|
||||
|
||||
In this example, input fields will be displayed with this order: `City` > `EmailAddress` > `PhoneNumber` > `Name` > `Surname`.
|
||||
|
||||
## Ignoring a property
|
||||
|
||||
By default, `abp-dynamic-form` generates input for every property in model class. If you want to ignore a property, use `DynamicFormIgnore` attribute.
|
||||
|
||||
See example below:
|
||||
|
||||
````csharp
|
||||
public class MyModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
[DynamicFormIgnore]
|
||||
public string Surname { get; set; }
|
||||
}
|
||||
````
|
||||
|
||||
In this example, no input will be generated for `Surname` property.
|
||||
|
||||
## Indicating Text box, Radio Group and Combobox
|
||||
|
||||
If you have read the [Form elements document](Form-elements.md), you noticed that `abp-radio` and `abp-select` tags are very similar on c# model. So we have to use `[AbpRadioButton()]` attribute to tell `abp-dynamic-form` which of your properties will be radio group and which will be combobox. See example below:
|
||||
|
||||
````xml
|
||||
<abp-dynamic-form abp-model="@Model.MyDetailedModel"/>
|
||||
````
|
||||
Model:
|
||||
````csharp
|
||||
public class DynamicFormsModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public DetailedModel MyDetailedModel { get; set; }
|
||||
|
||||
public List<SelectListItem> CountryList { get; set; } = new List<SelectListItem>
|
||||
{
|
||||
new SelectListItem { Value = "CA", Text = "Canada"},
|
||||
new SelectListItem { Value = "US", Text = "USA"},
|
||||
new SelectListItem { Value = "UK", Text = "United Kingdom"},
|
||||
new SelectListItem { Value = "RU", Text = "Russia"}
|
||||
};
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
MyDetailedModel = new DetailedModel
|
||||
{
|
||||
ComboCarType = CarType.Coupe,
|
||||
RadioCarType = CarType.Sedan,
|
||||
ComboCountry = "RU",
|
||||
RadioCountry = "UK"
|
||||
};
|
||||
}
|
||||
|
||||
public class DetailedModel
|
||||
{
|
||||
public CarType ComboCarType { get; set; }
|
||||
|
||||
[AbpRadioButton(Inline = true)]
|
||||
public CarType RadioCarType { get; set; }
|
||||
|
||||
[SelectItems(nameof(CountryList))]
|
||||
public string ComboCountry { get; set; }
|
||||
|
||||
[AbpRadioButton()]
|
||||
[SelectItems(nameof(CountryList))]
|
||||
public string RadioCountry { get; set; }
|
||||
}
|
||||
|
||||
public enum CarType
|
||||
{
|
||||
Sedan,
|
||||
Hatchback,
|
||||
StationWagon,
|
||||
Coupe
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
As you see in example above:
|
||||
|
||||
* If `[AbpRadioButton()]` are used on a **Enum** property, it will be a radio group. Otherwise, combobox.
|
||||
* If `[SelectItems()]` and `[AbpRadioButton()]` are used on a property, it will be a radio group.
|
||||
* If just `[SelectItems()]` is used on a property, it will be a combobox.
|
||||
* If none of these attributes are used on a property, it will be a text box.
|
||||
|
||||
## Localization
|
||||
|
||||
`abp-dynamic-form` handles localization as well.
|
||||
|
||||
By default, it will try to find "DisplayName:{PropertyName}" or "{PropertyName}" localization keys and set the localization value as input label.
|
||||
|
||||
You can set it yourself by using `[Display()]` attribute of Asp.Net Core. You can use a localization key in this attribute. See example below:
|
||||
|
||||
````csharp
|
||||
[Display(Name = "Name")]
|
||||
public string Name { get; set; }
|
||||
````
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
This is not documented yet. You can see a [demo](http://bootstrap-taghelpers.abp.io/Components/DynamicForms) for now.
|
||||
@ -0,0 +1,261 @@
|
||||
# Form Elements
|
||||
|
||||
## Introduction
|
||||
|
||||
Abp provides form input tag helpers to make building forms easier.
|
||||
|
||||
## Demo
|
||||
|
||||
See the [form elements demo page](https://bootstrap-taghelpers.abp.io/Components/FormElements) to see it in action.
|
||||
|
||||
## abp-input
|
||||
|
||||
`abp-input` tag creates a Bootstrap form input for a given c# property. It uses [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-input-tag-helper) in background, so every data annotation attribute of `input` tag helper of Asp.Net Core is also valid for `abp-input`.
|
||||
|
||||
Usage:
|
||||
|
||||
````xml
|
||||
<abp-input asp-for="@Model.MyModel.Name"/>
|
||||
<abp-input asp-for="@Model.MyModel.Description"/>
|
||||
<abp-input asp-for="@Model.MyModel.Password"/>
|
||||
<abp-input asp-for="@Model.MyModel.IsActive"/>
|
||||
````
|
||||
|
||||
Model:
|
||||
|
||||
````csharp
|
||||
public class FormElementsModel : PageModel
|
||||
{
|
||||
public SampleModel MyModel { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
MyModel = new SampleModel();
|
||||
}
|
||||
|
||||
public class SampleModel
|
||||
{
|
||||
[Required]
|
||||
[Placeholder("Enter your name...")]
|
||||
[InputInfoText("What is your name?")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required]
|
||||
[FormControlSize(AbpFormControlSize.Large)]
|
||||
public string SurName { get; set; }
|
||||
|
||||
[TextArea(Rows = 4)]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
### Attributes
|
||||
|
||||
You can set some of the attributes on your c# property, or directly on html tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes.
|
||||
|
||||
#### Property Attributes
|
||||
|
||||
- `[TextArea()]`: Converts the input into a text area.
|
||||
|
||||
* `[Placeholder()]`: Sets placeholder for input. You can use a localization key directly.
|
||||
* `[InputInfoText()]`: Sets a small info text for input. You can use a localization key directly.
|
||||
* `[FormControlSize()]`: Sets size of form-control wrapper element. Available values are
|
||||
- `AbpFormControlSize.Default`
|
||||
- `AbpFormControlSize.Small`
|
||||
- `AbpFormControlSize.Medium`
|
||||
- `AbpFormControlSize.Large`
|
||||
* `[DisabledInput]` : Input is disabled.
|
||||
* `[ReadOnlyInput]`: Input is read-only.
|
||||
|
||||
#### Tag Attributes
|
||||
|
||||
* `info`: Sets a small info text for input. You can use a localization key directly.
|
||||
* `auto-focus`: If true, browser auto focuses on the element.
|
||||
* `size`: Sets size of form-control wrapper element. Available values are
|
||||
- `AbpFormControlSize.Default`
|
||||
- `AbpFormControlSize.Small`
|
||||
- `AbpFormControlSize.Medium`
|
||||
- `AbpFormControlSize.Large`
|
||||
* `disabled`: Input is disabled.
|
||||
* `readonly`: Input is read-only.
|
||||
* `label`: Sets the label for input.
|
||||
* `display-required-symbol`: Adds the required symbol (*) to label if input is required. Default `True`.
|
||||
|
||||
### Label & Localization
|
||||
|
||||
You can set label of your input in different ways:
|
||||
|
||||
- You can use `Label` attribute and directly set the label. But it doesn't auto localize your localization key. So use it as `label="@L["{LocalizationKey}"].Value"`.
|
||||
- You can set it using `[Display(name="{LocalizationKey}")]` attribute of Asp.Net Core.
|
||||
- You can just let **abp** find the localization key for the property. It will try to find "DisplayName:{PropertyName}" or "{PropertyName}" localization keys, if `label` or `[DisplayName]` attributes are not set.
|
||||
|
||||
## abp-select
|
||||
|
||||
`abp-select` tag creates a Bootstrap form select for a given c# property. It uses [Asp.Net Core Select Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-select-tag-helper) in background, so every data annotation attribute of `select` tag helper of Asp.Net Core is also valid for `abp-select`.
|
||||
|
||||
`abp-select` tag needs a list of `Microsoft.AspNetCore.Mvc.Rendering.SelectListItem ` to work. It can be provided by `asp-items` attriube on the tag or `[SelectItems()]` attribute on c# property. (if you are using [abp-dynamic-form](Dynamic-forms.md), c# attribute is the only way.)
|
||||
|
||||
`abp-select` supports multiple selection.
|
||||
|
||||
`abp-select` auto-creates a select list for **Enum** properties. No extra data is needed. If property is nullable, an empty key and value is added to top of the auto-generated list.
|
||||
|
||||
Usage:
|
||||
|
||||
````xml
|
||||
<abp-select asp-for="@Model.MyModel.City" asp-items="@Model.CityList"/>
|
||||
|
||||
<abp-select asp-for="@Model.MyModel.AnotherCity"/>
|
||||
|
||||
<abp-select asp-for="@Model.MyModel.MultipleCities" asp-items="@Model.CityList"/>
|
||||
|
||||
<abp-select asp-for="@Model.MyModel.MyCarType"/>
|
||||
|
||||
<abp-select asp-for="@Model.MyModel.MyNullableCarType"/>
|
||||
````
|
||||
|
||||
Model:
|
||||
|
||||
````csharp
|
||||
public class FormElementsModel : PageModel
|
||||
{
|
||||
public SampleModel MyModel { get; set; }
|
||||
|
||||
public List<SelectListItem> CityList { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
MyModel = new SampleModel();
|
||||
|
||||
CityList = 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 class SampleModel
|
||||
{
|
||||
public string City { get; set; }
|
||||
|
||||
[SelectItems(nameof(CityList))]
|
||||
public string AnotherCity { get; set; }
|
||||
|
||||
public List<string> MultipleCities { get; set; }
|
||||
|
||||
public CarType MyCarType { get; set; }
|
||||
|
||||
public CarType? MyNullableCarType { get; set; }
|
||||
}
|
||||
|
||||
public enum CarType
|
||||
{
|
||||
Sedan,
|
||||
Hatchback,
|
||||
StationWagon,
|
||||
Coupe
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
### Attributes
|
||||
|
||||
You can set some of the attributes on your c# property, or directly on html tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes.
|
||||
|
||||
#### Property Attributes
|
||||
|
||||
* `[SelectItems()]`: Sets the select data. Parameter should be the name of the data list. (see example above)
|
||||
|
||||
- `[InputInfoText()]`: Sets a small info text for input. You can use a localization key directly.
|
||||
- `[FormControlSize()]`: Sets size of form-control wrapper element. Available values are
|
||||
- `AbpFormControlSize.Default`
|
||||
- `AbpFormControlSize.Small`
|
||||
- `AbpFormControlSize.Medium`
|
||||
- `AbpFormControlSize.Large`
|
||||
|
||||
#### Tag Attributes
|
||||
|
||||
- `asp-items`: Sets the select data. This Should be a list of SelectListItem.
|
||||
- `info`: Sets a small info text for input. You can use a localization key directly.
|
||||
- `size`: Sets size of form-control wrapper element. Available values are
|
||||
- `AbpFormControlSize.Default`
|
||||
- `AbpFormControlSize.Small`
|
||||
- `AbpFormControlSize.Medium`
|
||||
- `AbpFormControlSize.Large`
|
||||
- `label`: Sets the label for input.
|
||||
- `display-required-symbol`: Adds the required symbol (*) to label if input is required. Default `True`.
|
||||
|
||||
### Label & Localization
|
||||
|
||||
You can set label of your input in different ways:
|
||||
|
||||
- You can use `Label` attribute and directly set the label. But it doesn't auto localize your localization key. So use it as `label="@L["{LocalizationKey}"].Value".`
|
||||
- You can set it using `[Display(name="{LocalizationKey}")]` attribute of Asp.Net Core.
|
||||
- You can just let **abp** find the localization key for the property. It will try to find "DisplayName:{PropertyName}" or "{PropertyName}" localization keys.
|
||||
|
||||
Localizations of combobox values are set by `abp-select` for **Enum** property. It searches for "{EnumTypeName}.{EnumPropertyName}" or "{EnumPropertyName}" localization keys. For instance, in the example above, it will use "CarType.StationWagon" or "StationWagon" keys for localization when it localizes combobox values.
|
||||
|
||||
## abp-radio
|
||||
|
||||
`abp-radio` tag creates a Bootstrap form radio group for a given c# property. Usage is very similar to `abp-select` tag.
|
||||
|
||||
Usage:
|
||||
|
||||
````xml
|
||||
<abp-radio asp-for="@Model.MyModel.CityRadio" asp-items="@Model.CityList" inline="true"/>
|
||||
|
||||
<abp-radio asp-for="@Model.MyModel.CityRadio2"/>
|
||||
````
|
||||
|
||||
Model:
|
||||
|
||||
````csharp
|
||||
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();
|
||||
MyModel.CityRadio = "IST";
|
||||
MyModel.CityRadio2 = "MOS";
|
||||
}
|
||||
|
||||
public class SampleModel
|
||||
{
|
||||
public string CityRadio { get; set; }
|
||||
|
||||
[SelectItems(nameof(CityList))]
|
||||
public string CityRadio2 { get; set; }
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
### Attributes
|
||||
|
||||
You can set some of the attributes on your c# property, or directly on html tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes.
|
||||
|
||||
#### Property Attributes
|
||||
|
||||
- `[SelectItems()]`: Sets the select data. Parameter should be the name of the data list. (see example above)
|
||||
|
||||
#### Tag Attributes
|
||||
|
||||
- `asp-items`: Sets the select data. This Should be a list of SelectListItem.
|
||||
- `Inline`: If true, radio buttons will be in single line, next to each other. If false, they will be under each other.
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 171 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 218 KiB |
|
After Width: | Height: | Size: 181 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 357 KiB |
|
After Width: | Height: | Size: 424 KiB |
|
After Width: | Height: | Size: 401 KiB |
|
After Width: | Height: | Size: 336 KiB |
|
After Width: | Height: | Size: 389 KiB |
@ -0,0 +1,87 @@
|
||||
# ContainerStrategy
|
||||
|
||||
`ContainerStrategy` 是 @abp/ng.core 包暴露出的抽象类. 有两种扩展容器扩展策略: `ClearContainerStrategy` 和 `InsertIntoContainerStrategy`. 它们实现了相同的方法和属性,这两种策略都可以帮助你定义容器的准备方式和内容的投影位置.
|
||||
|
||||
## API
|
||||
|
||||
`ClearContainerStrategy` 是一个扩展了 `ContainerStrategy` 的类. 它允许你**将内容投影之前清除容器**.
|
||||
|
||||
### 构造函数
|
||||
|
||||
```js
|
||||
constructor(
|
||||
public containerRef: ViewContainerRef,
|
||||
private index?: number, // works only in InsertIntoContainerStrategy
|
||||
)
|
||||
```
|
||||
|
||||
- `containerRef` 是在投影内容时使用的 `ViewContainerRef`.
|
||||
|
||||
### getIndex
|
||||
|
||||
```js
|
||||
getIndex(): number
|
||||
```
|
||||
|
||||
该方法返回被 `0` 和 `containerRef` `length` 限制的给定索引. 对于没有索引的策略,它返回`0`.
|
||||
|
||||
### prepare
|
||||
|
||||
```js
|
||||
prepare(): void
|
||||
```
|
||||
|
||||
此方法在内容投影之前调用. 基于使用的容器策略,它要么清除容器,要么什么都不做(空操作).
|
||||
|
||||
## ClearContainerStrategy
|
||||
|
||||
`ClearContainerStrategy` 是一个扩展了 `ContainerStrategy` 的类. 它允许你**将内容投影之前清除容器**.
|
||||
|
||||
## InsertIntoContainerStrategy
|
||||
|
||||
`InsertIntoContainerStrategy` 是一个扩展了 `ContainerStrategy` 的类. 它允许你**将内容投影到容器中的特定节点索引上**.
|
||||
|
||||
## 预定义的容器策略
|
||||
|
||||
可以通过 `CONTAINER_STRATEGY` 常量访问预定义的容器策略.
|
||||
|
||||
### Clear
|
||||
|
||||
```js
|
||||
CONTAINER_STRATEGY.Clear(containerRef: ViewContainerRef)
|
||||
```
|
||||
|
||||
在内容投影之前清除给定的容器.
|
||||
|
||||
|
||||
### Append
|
||||
|
||||
```js
|
||||
CONTAINER_STRATEGY.Append(containerRef: ViewContainerRef)
|
||||
```
|
||||
|
||||
将投影内容附加到容器中.
|
||||
|
||||
|
||||
### Prepend
|
||||
|
||||
```js
|
||||
CONTAINER_STRATEGY.Prepend(containerRef: ViewContainerRef)
|
||||
```
|
||||
|
||||
将投影的内容预先写入容器中.
|
||||
|
||||
### Insert
|
||||
|
||||
```js
|
||||
CONTAINER_STRATEGY.Insert(
|
||||
containerRef: ViewContainerRef,
|
||||
index: number,
|
||||
)
|
||||
```
|
||||
|
||||
将投影内容按照给定的索引(在`0` 到 `containerRef`的长度之间)插入到容器中.
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- [ProjectionStrategy](./Projection-Strategy.md)
|
||||
@ -0,0 +1,55 @@
|
||||
# ContentSecurityStrategy
|
||||
|
||||
`ContentSecurityStrategy` 是@abp/ng.core包暴露出的抽象类. 它可以根据[内容安全策略](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)帮助你将内联脚本或样式标记为安全.
|
||||
|
||||
## API
|
||||
|
||||
### 构造函数
|
||||
|
||||
```js
|
||||
constructor(public nonce?: string)
|
||||
```
|
||||
|
||||
- `nonce` 启用将内联脚本或样式列入白名单,避免在[script-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#Unsafe_inline_script)和[style-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src#Unsafe_inline_styles)指令中使用 `unsafe-inline`.
|
||||
|
||||
### applyCSP
|
||||
|
||||
```js
|
||||
applyCSP(element: HTMLScriptElement | HTMLStyleElement): void
|
||||
```
|
||||
|
||||
该方法将上述属性映射到给定`element`.
|
||||
|
||||
## LooseContentSecurityPolicy
|
||||
|
||||
`LooseContentSecurityPolicy` 是扩展了 `ContentSecurityStrategy` 的类. 它需要 `nonce` 和带有给定 `<script>` 或 `<style>` 标记的标签.
|
||||
|
||||
## NoContentSecurityPolicy
|
||||
|
||||
`NoContentSecurityPolicy` 是扩展了 `ContentSecurityStrategy` 的类. 它不会将内联脚本和样式标记为安全. 你可以将其视为空操作的替代方案.
|
||||
s
|
||||
|
||||
## 预定义内容安全策略
|
||||
|
||||
可以通过 `CONTENT_SECURITY_STRATEGY` 常量访问预定义的内容安全策略.
|
||||
|
||||
### Loose
|
||||
|
||||
```js
|
||||
CONTENT_SECURITY_STRATEGY.Loose(nonce: string)
|
||||
```
|
||||
|
||||
`nonce` 会被设置.
|
||||
|
||||
### None
|
||||
|
||||
```js
|
||||
CONTENT_SECURITY_STRATEGY.None()
|
||||
```
|
||||
|
||||
什么都不会做.
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- [DomInsertionService](./Dom-Insertion-Service.md)
|
||||
- [ContentStrategy](./Content-Strategy.md)
|
||||
@ -0,0 +1,85 @@
|
||||
# ContentStrategy
|
||||
|
||||
`ContentStrategy` 是@abp/ng.core包暴露出的抽象类. 它可以帮助您创建内联脚本或样式.
|
||||
|
||||
## API
|
||||
|
||||
### 构造函数
|
||||
|
||||
```js
|
||||
constructor(
|
||||
public content: string,
|
||||
protected domStrategy?: DomStrategy,
|
||||
protected contentSecurityStrategy?: ContentSecurityStrategy
|
||||
)
|
||||
```
|
||||
|
||||
- `content` 是被设置为 `<script>` 和 `<style>` 元素的 `textContent` 属性.
|
||||
- `domStrategy` 是在插入创建的元素时将使用的 `DomStrategy` . (默认值: AppendToHead_)
|
||||
- `contentSecurityStrategy` 是 `ContentSecurityStrategy`, 在创建的元素插入使用它它. (默认值: None_)
|
||||
|
||||
请参考[DomStrategy](./Dom-Strategy.md)和[ContentSecurityStrategy](./Content-Security-Strategy.md)文档了解它们的用法.
|
||||
|
||||
### createElement
|
||||
|
||||
```js
|
||||
createElement(): HTMLScriptElement | HTMLStyleElement
|
||||
```
|
||||
|
||||
该方法创建并且返回 `<script>` 或 `<style>` 元素, 将 `content` 设置为 `textContent`.
|
||||
|
||||
### insertElement
|
||||
|
||||
```js
|
||||
insertElement(): void
|
||||
```
|
||||
|
||||
该方法创建并且插入一个 `<script>` 或 `<style>` 元素.
|
||||
|
||||
## ScriptContentStrategy
|
||||
|
||||
`ScriptContentStrategy` 是扩展了 `ContentStrategy` 的类. 你可以使用它将 **`<script>`元素插入DOM**.
|
||||
|
||||
## StyleContentStrategy
|
||||
|
||||
`StyleContentStrategy` 是扩展了 `ContentStrategy` 的类. 你可以使用它将 **`<style>`元素插入DOM**.
|
||||
|
||||
## 预定义内容策略
|
||||
|
||||
预定义的内容策略可以通过 `CONTENT_STRATEGY` 常量访问.
|
||||
|
||||
### AppendScriptToBody
|
||||
|
||||
```js
|
||||
CONTENT_STRATEGY.AppendScriptToBody(content: string)
|
||||
```
|
||||
|
||||
创建具有给定内容的 `<script>` 元素, 并放置在文档中`<body>`标记的**末尾**.
|
||||
|
||||
### AppendScriptToHead
|
||||
|
||||
```js
|
||||
CONTENT_STRATEGY.AppendScriptToHead(content: string)
|
||||
```
|
||||
|
||||
创建具有给定内容的 `<script>` 元素, 并放置在文档中`<head>`标签的**末尾**.
|
||||
|
||||
### AppendStyleToHead
|
||||
|
||||
```js
|
||||
CONTENT_STRATEGY.AppendStyleToHead(content: string)
|
||||
```
|
||||
|
||||
创建具有给定内容的 `<style>` 元素, 并放置在文档中`<head>`标签的**末尾**.
|
||||
|
||||
### PrependStyleToHead
|
||||
|
||||
```js
|
||||
CONTENT_STRATEGY.PrependStyleToHead(content: string)
|
||||
```
|
||||
|
||||
创建具有给定内容的 `<style>` 元素, 并放置在文档中`<head>`标签的**头部**.
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- [DomInsertionService](./Dom-Insertion-Service.md)
|
||||
@ -0,0 +1,100 @@
|
||||
# ContextStrategy
|
||||
|
||||
`ContextStrategy` 是@abp/ng.core包暴露出的抽象类. 有三种扩展容器扩展策略: `ComponentContextStrategy` , `TemplateContextStrategy` 和 `NoContextStrategy`. 它们实现了相同的方法和属性,这三种策略都可以帮助你获得定义投影内容上下文
|
||||
|
||||
## ComponentContextStrategy
|
||||
|
||||
`ComponentContextStrategy` 是扩展了 `ContextStrategy` 的类, 它允许你**将上下文传递给一个投影组件**.
|
||||
|
||||
### 构造函数
|
||||
|
||||
```js
|
||||
constructor(public context: Partial<InferredInstanceOf<T>>) {}
|
||||
```
|
||||
|
||||
- `T` 在这里引用组件类型, 例. `Type<C>`.
|
||||
- `InferredInstanceOf` 是 @abp/ng.core 包暴露的实用类型. 它可以推断组件.
|
||||
- `context` 是将映射到投影组件的属性.
|
||||
|
||||
### setContext
|
||||
|
||||
```js
|
||||
setContext(componentRef: ComponentRef<InferredInstanceOf<T>>): Partial<InferredInstanceOf<T>>
|
||||
```
|
||||
|
||||
该方法将上下文的每个属性映射到具有相同名称的组件属性,并调用更改检测.映射后返回上下文.
|
||||
|
||||
## TemplateContextStrategy
|
||||
|
||||
`TemplateContextStrategy` 是扩展了 `ContextStrategy` 的类. 它允许你**将上下文传递到投影模板**.
|
||||
|
||||
### 构造函数
|
||||
|
||||
```js
|
||||
constructor(public context: Partial<InferredContextOf<T>>) {}
|
||||
```
|
||||
|
||||
- `T` 在这里引用组件类型, 例. `Type<C>`.
|
||||
- `InferredInstanceOf` 是 @abp/ng.core 包暴露的实用类型. 它可以推断组件.
|
||||
- `context` 是将映射到投影组件的属性.
|
||||
|
||||
### setContext
|
||||
|
||||
```js
|
||||
setContext(): Partial<InferredContextOf<T>>
|
||||
```
|
||||
|
||||
此方法不执行任何操作它仅返回上下文,因为模板上下文没有被映射. 而是作为参数传递给 `createEmbeddedView` 方法.
|
||||
|
||||
## NoContextStrategy
|
||||
|
||||
`NoContextStrategy` 是扩展了 `ContextStrategy` 的类. 它允许你**跳过将任何上下文传递到投影内容**.
|
||||
|
||||
### 构造函数
|
||||
|
||||
```js
|
||||
constructor()
|
||||
```
|
||||
|
||||
不像其它的策略, `NoContextStrategy` 构造函数没有参数.
|
||||
|
||||
### setContext
|
||||
|
||||
```js
|
||||
setContext(): undefined
|
||||
```
|
||||
|
||||
由于没有上下文,方法没有参数并且返回`undefined`.
|
||||
|
||||
## 预定义上下文策略
|
||||
|
||||
可以通过 `CONTEXT_STRATEGY` 常量访问预定义的上下文策略.
|
||||
|
||||
### None
|
||||
|
||||
```js
|
||||
CONTEXT_STRATEGY.None()
|
||||
```
|
||||
|
||||
该策略不会将任何上下文传递到投影内容。
|
||||
|
||||
### Component
|
||||
|
||||
```js
|
||||
CONTEXT_STRATEGY.Component(context: Partial<InferredContextOf<T>>)
|
||||
```
|
||||
|
||||
该策略将帮助你将给定的上下文传递到投影组件.
|
||||
|
||||
|
||||
### Template
|
||||
|
||||
```js
|
||||
CONTEXT_STRATEGY.Template(context: Partial<InferredContextOf<T>>)
|
||||
```
|
||||
|
||||
该策略将帮助你将给定的上下文传递到投影模板.
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- [ProjectionStrategy](./Projection-Strategy.md)
|
||||
@ -0,0 +1,80 @@
|
||||
# DomStrategy
|
||||
|
||||
`DomStrategy` 是@abp/ng.core包暴露出的抽象类. 它的实例定义了如何将元素附加到DOM以及如何被其它类(如`LoadingStrategy`)使用.
|
||||
|
||||
## API
|
||||
|
||||
### 构造函数
|
||||
|
||||
```js
|
||||
constructor(
|
||||
public target?: HTMLElement,
|
||||
public position?: InsertPosition
|
||||
)
|
||||
```
|
||||
|
||||
- `target` 是一个 HTMLElement (默认值: document.head_).
|
||||
- `position` 定义将创建的元素放置在何处. 可以在[此处](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentElement)找到所有可能的 `position` 值(默认值: 'beforeend'_).
|
||||
|
||||
### insertElement
|
||||
|
||||
```js
|
||||
insertElement(element: HTMLElement): void
|
||||
```
|
||||
|
||||
该方法根据 `postion` 将给定 `元素` 插入到目标中.
|
||||
|
||||
## 预定义DOM策略
|
||||
|
||||
可以通过 `DOM_STRATEGY` 常量访问预定义的dom策略.
|
||||
|
||||
|
||||
### AppendToBody
|
||||
|
||||
```js
|
||||
DOM_STRATEGY.AppendToBody()
|
||||
```
|
||||
|
||||
`insertElement` 将给定 `元素` 放在 `<body>` 的末尾.
|
||||
|
||||
|
||||
### AppendToHead
|
||||
|
||||
```js
|
||||
DOM_STRATEGY.AppendToHead()
|
||||
```
|
||||
|
||||
`insertElement` 将给定 `元素` 放在 `<head>` 的末尾.
|
||||
|
||||
### PrependToHead
|
||||
|
||||
```js
|
||||
DOM_STRATEGY.PrependToHead()
|
||||
```
|
||||
|
||||
`insertElement` 将给定 `元素` 放在 `<head>` 的头部.
|
||||
|
||||
|
||||
### AfterElement
|
||||
|
||||
```js
|
||||
DOM_STRATEGY.AfterElement(target: HTMLElement)
|
||||
```
|
||||
|
||||
`insertElement` 将给定 `元素` 放在 `target` 之后 (做为同级元素).
|
||||
|
||||
### BeforeElement
|
||||
|
||||
```js
|
||||
DOM_STRATEGY.BeforeElement(target: HTMLElement)
|
||||
```
|
||||
|
||||
`insertElement` 将给定 `元素` 放在 `target` 之前 (做为同级元素).
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- [DomInsertionService](./Dom-Insertion-Service.md)
|
||||
- [LazyLoadService](./Lazy-Load-Service.md)
|
||||
- [LoadingStrategy](./Loading-Strategy.md)
|
||||
- [ContentStrategy](./Content-Strategy.md)
|
||||
- [ProjectionStrategy](./Projection-Strategy.md)
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"culture": "ru",
|
||||
"texts": {
|
||||
"MaxResultCountExceededExceptionMessage": "{0} не может быть больше {1}! Увеличьте {2}.{3} на стороне сервера, чтобы получить больше результатов."
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
{
|
||||
"culture": "ru",
|
||||
"texts": {
|
||||
"DisplayName:Abp.Mailing.DefaultFromAddress": "Адрес отправления по умолчанию",
|
||||
"DisplayName:Abp.Mailing.DefaultFromDisplayName": "Имя отправителя по умолчанию",
|
||||
"DisplayName:Abp.Mailing.Smtp.Host": "Сервер",
|
||||
"DisplayName:Abp.Mailing.Smtp.Port": "Порт",
|
||||
"DisplayName:Abp.Mailing.Smtp.UserName": "Имя пользователя",
|
||||
"DisplayName:Abp.Mailing.Smtp.Password": "Пароль",
|
||||
"DisplayName:Abp.Mailing.Smtp.Domain": "Домен",
|
||||
"DisplayName:Abp.Mailing.Smtp.EnableSsl": "Включить SSL",
|
||||
"DisplayName:Abp.Mailing.Smtp.UseDefaultCredentials": "Использовать учетные данные по умолчанию",
|
||||
"Description:Abp.Mailing.DefaultFromAddress": "Отправление по умолчанию от адреса.",
|
||||
"Description:Abp.Mailing.DefaultFromDisplayName": "Имя отправителя по умолчанию.",
|
||||
"Description:Abp.Mailing.Smtp.Host": "Имя или IP- адрес сервера, используемого для отправки по протоколу SMTP.",
|
||||
"Description:Abp.Mailing.Smtp.Port": "Порт, используемый для отправки по протоколу SMTP.",
|
||||
"Description:Abp.Mailing.Smtp.UserName": "Имя пользователя для SMTP-сервера.",
|
||||
"Description:Abp.Mailing.Smtp.Password": "Пароль для SMTP-сервера.",
|
||||
"Description:Abp.Mailing.Smtp.Domain": "Домен или имя компьютера, от которого производится SMTP-запрос.",
|
||||
"Description:Abp.Mailing.Smtp.EnableSsl": "Использовать SSL для подключения к SMTP-серверу.",
|
||||
"Description:Abp.Mailing.Smtp.UseDefaultCredentials": "Использовать учетные данные для SMTP по умолчанию."
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
{
|
||||
"culture": "ru",
|
||||
"texts": {
|
||||
"DisplayName:Abp.Localization.DefaultLanguage": "Язык по умолчанию",
|
||||
"Description:Abp.Localization.DefaultLanguage": "Язык приложения по умолчанию."
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"culture": "ru",
|
||||
"texts": {
|
||||
"Menu:Administration": "Администрирование"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
{
|
||||
"culture": "ru",
|
||||
"texts": {
|
||||
"Menu:Blogs": "Блоги",
|
||||
"Menu:BlogManagement": "Управление блогом",
|
||||
"Title": "Заголовок",
|
||||
"Delete": "Удалить",
|
||||
"Reply": "Ответить",
|
||||
"ReplyTo": "Ответить {0}",
|
||||
"ContinueReading": "Продолжить чтение",
|
||||
"DaysAgo": "{0} дней назад",
|
||||
"YearsAgo": "{0} лет назад",
|
||||
"MonthsAgo": "{0} месяцев назад",
|
||||
"WeeksAgo": "{0} недель назад",
|
||||
"MinutesAgo": "{0} минут назад",
|
||||
"SecondsAgo": "{0} секунд назад",
|
||||
"HoursAgo": "{0} часов назад",
|
||||
"Now": "сейчас",
|
||||
"Content": "Содержание",
|
||||
"SeeAll": "Увидеть все",
|
||||
"PopularTags": "Популярные тэги",
|
||||
"WiewsWithCount": "{0} просмотров",
|
||||
"LastPosts": "Последние записи",
|
||||
"LeaveComment": "Оставить комментарий",
|
||||
"TagsInThisArticle": "Теги в этой статье",
|
||||
"Posts": "Записи",
|
||||
"Edit": "Редактировать",
|
||||
"BLOG": "БЛОГ",
|
||||
"CommentDeletionWarningMessage": "Комментарий будет удален.",
|
||||
"PostDeletionWarningMessage": "Запись будет удалена.",
|
||||
"BlogDeletionWarningMessage": "Блог будет удален.",
|
||||
"AreYouSure": "Вы уверены?",
|
||||
"CommentWithCount": "{0} комментариев",
|
||||
"Comment": "Комментарий",
|
||||
"ShareOnTwitter": "Поделиться в Twitter",
|
||||
"CoverImage": "Обложка",
|
||||
"CreateANewPost": "Создать новый пост",
|
||||
"CreateANewBlog": "Создать новый блог",
|
||||
"WhatIsNew": "Что нового?",
|
||||
"Name": "Имя",
|
||||
"ShortName": "Фамилия",
|
||||
"CreationTime": "Время создания",
|
||||
"Description": "Описание",
|
||||
"Blogs": "Блоги",
|
||||
"Tags": "Теги"
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,14 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace Volo.ClientSimulation.Pages.ClientSimulation
|
||||
{
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
public async Task OnGetAsync()
|
||||
public virtual Task<IActionResult> OnGetAsync()
|
||||
{
|
||||
|
||||
return Task.FromResult<IActionResult>(Page());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
{
|
||||
"culture": "ru",
|
||||
"texts": {
|
||||
"DocsTitle": "VoloDocs",
|
||||
"WelcomeVoloDocs": "Добро пожаловать в VoloDocs!",
|
||||
"NoProjectWarning": "Отсутствует определение проекта!",
|
||||
"CreateYourFirstProject": "Нажмите здесь, чтобы добавить свой первый проект",
|
||||
"NoProject": "Нет проекта!"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,600 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('just-compare')) :
|
||||
typeof define === 'function' && define.amd ? define('@abp/utils', ['exports', 'just-compare'], factory) :
|
||||
(global = global || self, factory((global.abp = global.abp || {}, global.abp.utils = global.abp.utils || {}, global.abp.utils.common = {}), global.compare));
|
||||
}(this, (function (exports, compare) { 'use strict';
|
||||
|
||||
compare = compare && Object.prototype.hasOwnProperty.call(compare, 'default') ? compare['default'] : compare;
|
||||
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
/* global Reflect, Promise */
|
||||
|
||||
var extendStatics = function(d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
|
||||
function __extends(d, b) {
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
}
|
||||
|
||||
var __assign = function() {
|
||||
__assign = Object.assign || function __assign(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
|
||||
function __rest(s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
function __decorate(decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
}
|
||||
|
||||
function __param(paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
}
|
||||
|
||||
function __metadata(metadataKey, metadataValue) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
|
||||
}
|
||||
|
||||
function __awaiter(thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
}
|
||||
|
||||
function __generator(thisArg, body) {
|
||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||
function step(op) {
|
||||
if (f) throw new TypeError("Generator is already executing.");
|
||||
while (_) try {
|
||||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||
switch (op[0]) {
|
||||
case 0: case 1: t = op; break;
|
||||
case 4: _.label++; return { value: op[1], done: false };
|
||||
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||
default:
|
||||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||
if (t[2]) _.ops.pop();
|
||||
_.trys.pop(); continue;
|
||||
}
|
||||
op = body.call(thisArg, _);
|
||||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||
}
|
||||
}
|
||||
|
||||
function __exportStar(m, exports) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
|
||||
function __values(o) {
|
||||
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
||||
if (m) return m.call(o);
|
||||
if (o && typeof o.length === "number") return {
|
||||
next: function () {
|
||||
if (o && i >= o.length) o = void 0;
|
||||
return { value: o && o[i++], done: !o };
|
||||
}
|
||||
};
|
||||
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
||||
}
|
||||
|
||||
function __read(o, n) {
|
||||
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
||||
if (!m) return o;
|
||||
var i = m.call(o), r, ar = [], e;
|
||||
try {
|
||||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
||||
}
|
||||
catch (error) { e = { error: error }; }
|
||||
finally {
|
||||
try {
|
||||
if (r && !r.done && (m = i["return"])) m.call(i);
|
||||
}
|
||||
finally { if (e) throw e.error; }
|
||||
}
|
||||
return ar;
|
||||
}
|
||||
|
||||
function __spread() {
|
||||
for (var ar = [], i = 0; i < arguments.length; i++)
|
||||
ar = ar.concat(__read(arguments[i]));
|
||||
return ar;
|
||||
}
|
||||
|
||||
function __spreadArrays() {
|
||||
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
|
||||
for (var r = Array(s), k = 0, i = 0; i < il; i++)
|
||||
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
|
||||
r[k] = a[j];
|
||||
return r;
|
||||
};
|
||||
|
||||
function __await(v) {
|
||||
return this instanceof __await ? (this.v = v, this) : new __await(v);
|
||||
}
|
||||
|
||||
function __asyncGenerator(thisArg, _arguments, generator) {
|
||||
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
||||
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
||||
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
||||
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
||||
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
||||
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
||||
function fulfill(value) { resume("next", value); }
|
||||
function reject(value) { resume("throw", value); }
|
||||
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
||||
}
|
||||
|
||||
function __asyncDelegator(o) {
|
||||
var i, p;
|
||||
return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
|
||||
function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; }
|
||||
}
|
||||
|
||||
function __asyncValues(o) {
|
||||
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
||||
var m = o[Symbol.asyncIterator], i;
|
||||
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
||||
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
||||
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
||||
}
|
||||
|
||||
function __makeTemplateObject(cooked, raw) {
|
||||
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
|
||||
return cooked;
|
||||
};
|
||||
|
||||
function __importStar(mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result.default = mod;
|
||||
return result;
|
||||
}
|
||||
|
||||
function __importDefault(mod) {
|
||||
return (mod && mod.__esModule) ? mod : { default: mod };
|
||||
}
|
||||
|
||||
function __classPrivateFieldGet(receiver, privateMap) {
|
||||
if (!privateMap.has(receiver)) {
|
||||
throw new TypeError("attempted to get private field on non-instance");
|
||||
}
|
||||
return privateMap.get(receiver);
|
||||
}
|
||||
|
||||
function __classPrivateFieldSet(receiver, privateMap, value) {
|
||||
if (!privateMap.has(receiver)) {
|
||||
throw new TypeError("attempted to set private field on non-instance");
|
||||
}
|
||||
privateMap.set(receiver, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/* tslint:disable:no-non-null-assertion */
|
||||
var ListNode = /** @class */ (function () {
|
||||
function ListNode(value) {
|
||||
this.value = value;
|
||||
}
|
||||
return ListNode;
|
||||
}());
|
||||
var LinkedList = /** @class */ (function () {
|
||||
function LinkedList() {
|
||||
this.size = 0;
|
||||
}
|
||||
Object.defineProperty(LinkedList.prototype, "head", {
|
||||
get: function () {
|
||||
return this.first;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(LinkedList.prototype, "tail", {
|
||||
get: function () {
|
||||
return this.last;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(LinkedList.prototype, "length", {
|
||||
get: function () {
|
||||
return this.size;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
LinkedList.prototype.attach = function (value, previousNode, nextNode) {
|
||||
if (!previousNode)
|
||||
return this.addHead(value);
|
||||
if (!nextNode)
|
||||
return this.addTail(value);
|
||||
var node = new ListNode(value);
|
||||
node.previous = previousNode;
|
||||
previousNode.next = node;
|
||||
node.next = nextNode;
|
||||
nextNode.previous = node;
|
||||
this.size++;
|
||||
return node;
|
||||
};
|
||||
LinkedList.prototype.attachMany = function (values, previousNode, nextNode) {
|
||||
if (!values.length)
|
||||
return [];
|
||||
if (!previousNode)
|
||||
return this.addManyHead(values);
|
||||
if (!nextNode)
|
||||
return this.addManyTail(values);
|
||||
var list = new LinkedList();
|
||||
list.addManyTail(values);
|
||||
list.first.previous = previousNode;
|
||||
previousNode.next = list.first;
|
||||
list.last.next = nextNode;
|
||||
nextNode.previous = list.last;
|
||||
this.size += values.length;
|
||||
return list.toNodeArray();
|
||||
};
|
||||
LinkedList.prototype.detach = function (node) {
|
||||
if (!node.previous)
|
||||
return this.dropHead();
|
||||
if (!node.next)
|
||||
return this.dropTail();
|
||||
node.previous.next = node.next;
|
||||
node.next.previous = node.previous;
|
||||
this.size--;
|
||||
return node;
|
||||
};
|
||||
LinkedList.prototype.add = function (value) {
|
||||
var _this = this;
|
||||
return {
|
||||
after: function () {
|
||||
var _a;
|
||||
var params = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
params[_i] = arguments[_i];
|
||||
}
|
||||
return (_a = _this.addAfter).call.apply(_a, __spread([_this, value], params));
|
||||
},
|
||||
before: function () {
|
||||
var _a;
|
||||
var params = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
params[_i] = arguments[_i];
|
||||
}
|
||||
return (_a = _this.addBefore).call.apply(_a, __spread([_this, value], params));
|
||||
},
|
||||
byIndex: function (position) { return _this.addByIndex(value, position); },
|
||||
head: function () { return _this.addHead(value); },
|
||||
tail: function () { return _this.addTail(value); },
|
||||
};
|
||||
};
|
||||
LinkedList.prototype.addMany = function (values) {
|
||||
var _this = this;
|
||||
return {
|
||||
after: function () {
|
||||
var _a;
|
||||
var params = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
params[_i] = arguments[_i];
|
||||
}
|
||||
return (_a = _this.addManyAfter).call.apply(_a, __spread([_this, values], params));
|
||||
},
|
||||
before: function () {
|
||||
var _a;
|
||||
var params = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
params[_i] = arguments[_i];
|
||||
}
|
||||
return (_a = _this.addManyBefore).call.apply(_a, __spread([_this, values], params));
|
||||
},
|
||||
byIndex: function (position) { return _this.addManyByIndex(values, position); },
|
||||
head: function () { return _this.addManyHead(values); },
|
||||
tail: function () { return _this.addManyTail(values); },
|
||||
};
|
||||
};
|
||||
LinkedList.prototype.addAfter = function (value, previousValue, compareFn) {
|
||||
if (compareFn === void 0) { compareFn = compare; }
|
||||
var previous = this.find(function (node) { return compareFn(node.value, previousValue); });
|
||||
return previous ? this.attach(value, previous, previous.next) : this.addTail(value);
|
||||
};
|
||||
LinkedList.prototype.addBefore = function (value, nextValue, compareFn) {
|
||||
if (compareFn === void 0) { compareFn = compare; }
|
||||
var next = this.find(function (node) { return compareFn(node.value, nextValue); });
|
||||
return next ? this.attach(value, next.previous, next) : this.addHead(value);
|
||||
};
|
||||
LinkedList.prototype.addByIndex = function (value, position) {
|
||||
if (position < 0)
|
||||
position += this.size;
|
||||
else if (position >= this.size)
|
||||
return this.addTail(value);
|
||||
if (position <= 0)
|
||||
return this.addHead(value);
|
||||
var next = this.get(position);
|
||||
return this.attach(value, next.previous, next);
|
||||
};
|
||||
LinkedList.prototype.addHead = function (value) {
|
||||
var node = new ListNode(value);
|
||||
node.next = this.first;
|
||||
if (this.first)
|
||||
this.first.previous = node;
|
||||
else
|
||||
this.last = node;
|
||||
this.first = node;
|
||||
this.size++;
|
||||
return node;
|
||||
};
|
||||
LinkedList.prototype.addTail = function (value) {
|
||||
var node = new ListNode(value);
|
||||
if (this.first) {
|
||||
node.previous = this.last;
|
||||
this.last.next = node;
|
||||
this.last = node;
|
||||
}
|
||||
else {
|
||||
this.first = node;
|
||||
this.last = node;
|
||||
}
|
||||
this.size++;
|
||||
return node;
|
||||
};
|
||||
LinkedList.prototype.addManyAfter = function (values, previousValue, compareFn) {
|
||||
if (compareFn === void 0) { compareFn = compare; }
|
||||
var previous = this.find(function (node) { return compareFn(node.value, previousValue); });
|
||||
return previous ? this.attachMany(values, previous, previous.next) : this.addManyTail(values);
|
||||
};
|
||||
LinkedList.prototype.addManyBefore = function (values, nextValue, compareFn) {
|
||||
if (compareFn === void 0) { compareFn = compare; }
|
||||
var next = this.find(function (node) { return compareFn(node.value, nextValue); });
|
||||
return next ? this.attachMany(values, next.previous, next) : this.addManyHead(values);
|
||||
};
|
||||
LinkedList.prototype.addManyByIndex = function (values, position) {
|
||||
if (position < 0)
|
||||
position += this.size;
|
||||
if (position <= 0)
|
||||
return this.addManyHead(values);
|
||||
if (position >= this.size)
|
||||
return this.addManyTail(values);
|
||||
var next = this.get(position);
|
||||
return this.attachMany(values, next.previous, next);
|
||||
};
|
||||
LinkedList.prototype.addManyHead = function (values) {
|
||||
var _this = this;
|
||||
return values.reduceRight(function (nodes, value) {
|
||||
nodes.unshift(_this.addHead(value));
|
||||
return nodes;
|
||||
}, []);
|
||||
};
|
||||
LinkedList.prototype.addManyTail = function (values) {
|
||||
var _this = this;
|
||||
return values.map(function (value) { return _this.addTail(value); });
|
||||
};
|
||||
LinkedList.prototype.drop = function () {
|
||||
var _this = this;
|
||||
return {
|
||||
byIndex: function (position) { return _this.dropByIndex(position); },
|
||||
byValue: function () {
|
||||
var params = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
params[_i] = arguments[_i];
|
||||
}
|
||||
return _this.dropByValue.apply(_this, params);
|
||||
},
|
||||
byValueAll: function () {
|
||||
var params = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
params[_i] = arguments[_i];
|
||||
}
|
||||
return _this.dropByValueAll.apply(_this, params);
|
||||
},
|
||||
head: function () { return _this.dropHead(); },
|
||||
tail: function () { return _this.dropTail(); },
|
||||
};
|
||||
};
|
||||
LinkedList.prototype.dropMany = function (count) {
|
||||
var _this = this;
|
||||
return {
|
||||
byIndex: function (position) { return _this.dropManyByIndex(count, position); },
|
||||
head: function () { return _this.dropManyHead(count); },
|
||||
tail: function () { return _this.dropManyTail(count); },
|
||||
};
|
||||
};
|
||||
LinkedList.prototype.dropByIndex = function (position) {
|
||||
if (position < 0)
|
||||
position += this.size;
|
||||
var current = this.get(position);
|
||||
return current ? this.detach(current) : undefined;
|
||||
};
|
||||
LinkedList.prototype.dropByValue = function (value, compareFn) {
|
||||
if (compareFn === void 0) { compareFn = compare; }
|
||||
var position = this.findIndex(function (node) { return compareFn(node.value, value); });
|
||||
return position < 0 ? undefined : this.dropByIndex(position);
|
||||
};
|
||||
LinkedList.prototype.dropByValueAll = function (value, compareFn) {
|
||||
if (compareFn === void 0) { compareFn = compare; }
|
||||
var dropped = [];
|
||||
for (var current = this.first, position = 0; current; position++, current = current.next) {
|
||||
if (compareFn(current.value, value)) {
|
||||
dropped.push(this.dropByIndex(position - dropped.length));
|
||||
}
|
||||
}
|
||||
return dropped;
|
||||
};
|
||||
LinkedList.prototype.dropHead = function () {
|
||||
var head = this.first;
|
||||
if (head) {
|
||||
this.first = head.next;
|
||||
if (this.first)
|
||||
this.first.previous = undefined;
|
||||
else
|
||||
this.last = undefined;
|
||||
this.size--;
|
||||
return head;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
LinkedList.prototype.dropTail = function () {
|
||||
var tail = this.last;
|
||||
if (tail) {
|
||||
this.last = tail.previous;
|
||||
if (this.last)
|
||||
this.last.next = undefined;
|
||||
else
|
||||
this.first = undefined;
|
||||
this.size--;
|
||||
return tail;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
LinkedList.prototype.dropManyByIndex = function (count, position) {
|
||||
if (count <= 0)
|
||||
return [];
|
||||
if (position < 0)
|
||||
position = Math.max(position + this.size, 0);
|
||||
else if (position >= this.size)
|
||||
return [];
|
||||
count = Math.min(count, this.size - position);
|
||||
var dropped = [];
|
||||
while (count--) {
|
||||
var current = this.get(position);
|
||||
dropped.push(this.detach(current));
|
||||
}
|
||||
return dropped;
|
||||
};
|
||||
LinkedList.prototype.dropManyHead = function (count) {
|
||||
if (count <= 0)
|
||||
return [];
|
||||
count = Math.min(count, this.size);
|
||||
var dropped = [];
|
||||
while (count--)
|
||||
dropped.unshift(this.dropHead());
|
||||
return dropped;
|
||||
};
|
||||
LinkedList.prototype.dropManyTail = function (count) {
|
||||
if (count <= 0)
|
||||
return [];
|
||||
count = Math.min(count, this.size);
|
||||
var dropped = [];
|
||||
while (count--)
|
||||
dropped.push(this.dropTail());
|
||||
return dropped;
|
||||
};
|
||||
LinkedList.prototype.find = function (predicate) {
|
||||
for (var current = this.first, position = 0; current; position++, current = current.next) {
|
||||
if (predicate(current, position, this))
|
||||
return current;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
LinkedList.prototype.findIndex = function (predicate) {
|
||||
for (var current = this.first, position = 0; current; position++, current = current.next) {
|
||||
if (predicate(current, position, this))
|
||||
return position;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
LinkedList.prototype.forEach = function (callback) {
|
||||
for (var node = this.first, position = 0; node; position++, node = node.next) {
|
||||
callback(node, position, this);
|
||||
}
|
||||
};
|
||||
LinkedList.prototype.get = function (position) {
|
||||
return this.find(function (_, index) { return position === index; });
|
||||
};
|
||||
LinkedList.prototype.indexOf = function (value, compareFn) {
|
||||
if (compareFn === void 0) { compareFn = compare; }
|
||||
return this.findIndex(function (node) { return compareFn(node.value, value); });
|
||||
};
|
||||
LinkedList.prototype.toArray = function () {
|
||||
var array = new Array(this.size);
|
||||
this.forEach(function (node, index) { return (array[index] = node.value); });
|
||||
return array;
|
||||
};
|
||||
LinkedList.prototype.toNodeArray = function () {
|
||||
var array = new Array(this.size);
|
||||
this.forEach(function (node, index) { return (array[index] = node); });
|
||||
return array;
|
||||
};
|
||||
LinkedList.prototype.toString = function (mapperFn) {
|
||||
if (mapperFn === void 0) { mapperFn = JSON.stringify; }
|
||||
return this.toArray()
|
||||
.map(function (value) { return mapperFn(value); })
|
||||
.join(' <-> ');
|
||||
};
|
||||
// Cannot use Generator type because of ng-packagr
|
||||
LinkedList.prototype[Symbol.iterator] = function () {
|
||||
var node, position;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
node = this.first, position = 0;
|
||||
_a.label = 1;
|
||||
case 1:
|
||||
if (!node) return [3 /*break*/, 4];
|
||||
return [4 /*yield*/, node.value];
|
||||
case 2:
|
||||
_a.sent();
|
||||
_a.label = 3;
|
||||
case 3:
|
||||
position++, node = node.next;
|
||||
return [3 /*break*/, 1];
|
||||
case 4: return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
};
|
||||
return LinkedList;
|
||||
}());
|
||||
|
||||
exports.LinkedList = LinkedList;
|
||||
exports.ListNode = ListNode;
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
})));
|
||||
//# sourceMappingURL=abp-utils.umd.js.map
|
||||
@ -0,0 +1,37 @@
|
||||
{
|
||||
"culture": "ru",
|
||||
"texts": {
|
||||
"Permission:DocumentManagement": "Управление документацией",
|
||||
"Permission:Projects": "Проекты",
|
||||
"Permission:Edit": "Редактировать",
|
||||
"Permission:Delete": "Удалить",
|
||||
"Permission:Create": "Создать",
|
||||
"Permission:Documents": "Документы",
|
||||
"Menu:DocumentManagement": "Документы",
|
||||
"Menu:ProjectManagement": "Проекты",
|
||||
"CreateANewProject": "Создать проекты",
|
||||
"Edit": "Редактировать",
|
||||
"Create": "Создать",
|
||||
"Pull": "Получить",
|
||||
"Projects": "Проекты",
|
||||
"Name": "Название",
|
||||
"ShortName": "Сокращенное название",
|
||||
"DocumentStoreType": "Тип системы хранения",
|
||||
"Format": "Формат",
|
||||
"ShortNameInfoText": "Будет использоваться для уникального URL.",
|
||||
"DisplayName:Name": "Название",
|
||||
"DisplayName:ShortName": "Сокращенное название",
|
||||
"DisplayName:Format": "Формат",
|
||||
"DisplayName:DefaultDocumentName": "Имя документа по умолчанию",
|
||||
"DisplayName:NavigationDocumentName": "Имя документа для навигации",
|
||||
"DisplayName:MinimumVersion": "Минимальная версия",
|
||||
"DisplayName:MainWebsiteUrl": "URL основного веб-сайта",
|
||||
"DisplayName:LatestVersionBranchName": "Название ветки последней версии",
|
||||
"DisplayName:GitHubRootUrl": "Корневой URL-адрес GitHub",
|
||||
"DisplayName:GitHubAccessToken": "Маркер доступа для GitHub",
|
||||
"DisplayName:GitHubUserAgent": "Заголовок User-Agent для GitHub",
|
||||
"DisplayName:All": "Получить все",
|
||||
"DisplayName:LanguageCode": "Код языка",
|
||||
"DisplayName:Version": "Версия"
|
||||
}
|
||||
}
|
||||