@ -0,0 +1,240 @@ |
|||
# ABP Framework & ABP Commercial 3.2 RC With The New Blazor UI |
|||
|
|||
We are extremely excited today to release the [ABP Framework](https://abp.io/) (and the [ABP Commercial](https://commercial.abp.io/), as always) version `3.2.0-rc.1` (Release Candidate). This release includes an early preview version of the **Blazor UI** for the ABP.IO Platform. |
|||
|
|||
## The Blazor UI |
|||
|
|||
While the Blazor UI **should be considered as experimental** for now, it is possible to start to develop your application today. |
|||
|
|||
### Fundamental Services |
|||
|
|||
Currently, implemented some important framework features; |
|||
|
|||
* **Authentication** through the MVC backend using the OpenId Connect authorization code flow. So, all the current login options (login, register, forgot password, external/social logins...) are supported. |
|||
* **Authorization**, using the ABP Framework **permissions** as well as the standard authorization system. |
|||
* **Localization** just works like the MVC UI. |
|||
* **Basic Theme** with top main menu. |
|||
* **Dynamic C# HTTP API proxies**, so you can directly consume your backend API by injecting the application service interfaces. |
|||
* Some other **fundamental services** like `ISettingProvider`, `IFeatureChecker`, `ICurrentUser`... |
|||
|
|||
Also, the standard .net services are already available, like caching, logging, validation and much more. Since the ABP Framework is layered itself, all the non MVC UI related features are already usable for the Blazor UI. |
|||
|
|||
### Pre-Built Modules |
|||
|
|||
Some modules have been implemented; |
|||
|
|||
* **Identity** module is pre-installed and provides **user, role and permission management**. |
|||
* **Profile management** page is implemented to allow to change password and personal settings. |
|||
|
|||
### About the Blazorise Library |
|||
|
|||
We've selected the [Blazorise](https://blazorise.com/) as a fundamental UI library for the Blazor UI. It already supports different HTML/CSS frameworks (like Bootstrap, Bulma, Ant Design...) and significantly increases the developer productivity. |
|||
|
|||
 |
|||
|
|||
We also have a good news: **[Mladen Macanović](https://github.com/stsrki)**, the creator of the Blazorise, is **joining to the core ABP Framework team** in the next weeks. We are excited to work with him to bring the power of these two successful projects together. |
|||
|
|||
### The Tutorial |
|||
|
|||
We are currently in progress of updating the [web application development tutorial](https://docs.abp.io/en/abp/3.2/Tutorials/Part-1) for the Blazor UI. Follow the [@abpframework](https://twitter.com/abpframework) Twitter account to get informed once it's ready. |
|||
|
|||
### Get started with the Blazor UI |
|||
|
|||
If you want to try the Blazor UI today, follow the instructions below. |
|||
|
|||
#### Upgrade the ABP CLI |
|||
|
|||
> **Known issue**: When you upgrade the ABP CLI to `3.2.0-rc.1`, you won't be able to create new solutions with a stable version ([#5453](https://github.com/abpframework/abp/issues/5453)). Downgrade to `3.1.0` back after trying the preview version, if you want to create solutions with a stable version later. |
|||
|
|||
Install the latest [ABP CLI](https://docs.abp.io/en/abp/3.2/CLI) preview version: |
|||
|
|||
````bash |
|||
dotnet tool update Volo.Abp.Cli -g --version 3.2.0-rc.1 |
|||
```` |
|||
|
|||
#### Create a new Solution |
|||
|
|||
Then you can create a new solution using the *abp new* command: |
|||
|
|||
````bash |
|||
abp new AbpBlazorDemo -u blazor --preview |
|||
```` |
|||
|
|||
Also specify the `-t app-pro` parameter if you are an ABP Commercial user. |
|||
|
|||
> See the ABP CLI documentation for the additional options, like MongoDB database or separated authentication server. |
|||
|
|||
#### Open the Solution |
|||
|
|||
Open the generated solution using the latest Visual Studio 2019. You will see a solution structure like the picture below: |
|||
|
|||
 |
|||
|
|||
> **A fix for the 3.2.0-rc.1** |
|||
> |
|||
> There is a bug in the `3.2.0-rc.1` that prevents `HttpApi.Host` project run properly, when you try to login to the application. **Follow the steps explained in the [#5457](https://github.com/abpframework/abp/issues/5457) for the `HttpApi.Host` project** to fix it for your solution, before running it. It will be resolved with the `3.2.0-rc.2`. |
|||
|
|||
#### Run the Application |
|||
|
|||
* Run the `DbMigrator` project to create the database and seed the initial data. |
|||
* Run the `HttpApi.Host` project for the server side. |
|||
* Run the `Blazor` project to start the Blazor UI. |
|||
|
|||
Use `admin` as the username and `1q2w3E*` as the password to login to the application. |
|||
|
|||
Here, a screenshot from the role management page of the Blazor UI: |
|||
|
|||
 |
|||
|
|||
## What's New with the ABP Framework 3.2 |
|||
|
|||
Beside the Blazor UI, there are a lot of issues have been closed with [the milestone 3.2](https://github.com/abpframework/abp/milestone/39?closed=1). I will highlight some of the major features and changes released with this version. |
|||
|
|||
### MongoDB ACID Transactions |
|||
|
|||
[MongoDB integration](https://docs.abp.io/en/abp/3.2/MongoDB) now supports multi-document transactions that comes with the MongoDB 4.x. |
|||
|
|||
> Transactions are disabled for automated integration tests coming with the application startup template, since the Mongo2Go library (we use in the test projects) has a problem with the transactions. We've sent a [Pull Request](https://github.com/Mongo2Go/Mongo2Go/pull/101) to fix it and will enable the transactions again when they merge & release it. |
|||
> |
|||
> If you are upgrading an existing solution and using MongoDB, please disable transactions for the test projects by following the [Unit Of Work](https://docs.abp.io/en/abp/3.2/Unit-Of-Work) documentation. |
|||
|
|||
### Kafka Integration for the Distributed Event Bus |
|||
|
|||
ABP Framework's [distributed event system](https://docs.abp.io/en/abp/3.2/Distributed-Event-Bus) has been [integrated to RabbitMQ](https://docs.abp.io/en/abp/3.2/Distributed-Event-Bus-RabbitMQ-Integration) before. By the version 3.2, it has a Kafka integration package, named [Volo.Abp.EventBus.Kafka](https://www.nuget.org/packages/Volo.Abp.EventBus.Kafka). |
|||
|
|||
See the [Kafka integration documentation](https://docs.abp.io/en/abp/3.2/Distributed-Event-Bus-Kafka-Integration) to learn how to install and configure it. |
|||
|
|||
### Host Features |
|||
|
|||
[ABP Feature System](https://docs.abp.io/en/abp/3.2/Features) allows you to define features in your application. Then you can enable/disable a feature dynamically on the runtime. It is generally used in a [multi-tenant](https://docs.abp.io/en/abp/3.2/Multi-Tenancy) system to restrict features for tenants, so you can charge extra money for some features in a SaaS application. |
|||
|
|||
In some cases, you may want to use the same features in the host side (host is you as you are managing the tenants). For this case, we've added a "**Manage Host Features**" button to the Tenant Management page so you can open a modal dialog to select the features for the host side. |
|||
|
|||
 |
|||
|
|||
### AbpHttpClientBuilderOptions |
|||
|
|||
ABP Framework provides a system to dynamically create C# proxies to consume HTTP APIs from your client applications. `AbpHttpClientBuilderOptions` is a new option class to configure the `HttpClient`s used by the proxy system. |
|||
|
|||
**Example: Use the [Polly](https://github.com/App-vNext/Polly) library to retry up to 3 times for a failed HTTP request** |
|||
|
|||
````csharp |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<AbpHttpClientBuilderOptions>(options => |
|||
{ |
|||
options.ProxyClientBuildActions.Add((remoteServiceName, clientBuilder) => |
|||
{ |
|||
clientBuilder.AddTransientHttpErrorPolicy(policyBuilder => |
|||
policyBuilder.WaitAndRetryAsync( |
|||
3, |
|||
i => TimeSpan.FromSeconds(Math.Pow(2, i)) |
|||
) |
|||
); |
|||
}); |
|||
}); |
|||
} |
|||
```` |
|||
|
|||
See the issue [#5304](https://github.com/abpframework/abp/issues/5304) for the details. |
|||
|
|||
### ABP Build Command |
|||
|
|||
We are using **mono repository** approach and the [abp repository](https://github.com/abpframework/abp) has tens of solutions and hundreds of projects (the framework, modules, tooling, templates...) with all of them are referencing to each other. |
|||
|
|||
It gets a significant time to build the whole repository for every Git push. To **optimize** this process, we've created the **abp build** command in the [ABP CLI](https://docs.abp.io/en/abp/3.2/CLI): |
|||
|
|||
````bash |
|||
abp build |
|||
```` |
|||
|
|||
We will use this command to build the abp repository or a solution inside it. However it is available to everyone in case of need. |
|||
|
|||
> **Most of the people will not need it**. If you need it, see the [ABP CLI](https://docs.abp.io/en/abp/3.2/CLI) document to learn all the details and options. |
|||
|
|||
### Other Features, Improvements and Changes |
|||
|
|||
* Introduced the `DynamicRangeAttribute` that can be used to determine the range values on runtime, just like the `DynamicStringLengthAttribute` was introduced before. |
|||
* Improved the feature management modal for multi-tenant applications to group features on the UI and show hierarchically. |
|||
* Added `--skip-cli-version-check` option to ABP CLI to improve the performance by bypassing the online version check. |
|||
* Angular UI now redirect to MVC UI (the authentication server side) for profile management page, if the authorization code flow is used (which is the default). |
|||
* Account module profile management page is now extensible. You can implement the `IProfileManagementPageContributor` interface and register it using the `ProfileManagementPageOptions` class. |
|||
* Improvements and optimizations for the [Angular service proxy generation](https://blog.abp.io/abp/Introducing-the-Angular-Service-Proxy-Generation). |
|||
|
|||
And a lot of minor improvements and bug fixes. You can see [the milestone 3.2](https://github.com/abpframework/abp/milestone/39?closed=1) for all issues & PRs closed with this version. |
|||
|
|||
## What's New with the ABP Commercial 3.2 |
|||
|
|||
### Breaking Changes |
|||
|
|||
The new *profile picture management* feature uses the [BLOB storing](https://docs.abp.io/en/abp/3.2/Blob-Storing) system, so it needs a Storage Provider. The new **startup template comes with the [Database BLOB Provider](https://docs.abp.io/en/abp/3.2/Blob-Storing-Database) pre-installed**. You can change it if you want to use another BLOB provider (like Azure, AWS or a simple file system). |
|||
|
|||
**Existing solutions must configure a BLOB provider** after upgrading to the version 3.2. Follow the [BLOB Storing document](https://docs.abp.io/en/abp/3.2/Blob-Storing#blob-storage-providers) to configure the provider yourself. |
|||
|
|||
### The Blazor UI |
|||
|
|||
The **experimental** Blazor UI is also available for the ABP Commercial. The [Lepton Theme](https://commercial.abp.io/themes) hasn't been implemented with this initial preview, however we are working on it with the highest priority. |
|||
|
|||
You can use the [ABP Suite](https://docs.abp.io/en/commercial/latest/abp-suite/index) or the following ABP CLI command to create a new solution with the Blazor UI: |
|||
|
|||
````bash |
|||
abp new AbpBlazorDemo -u blazor -t app-pro --preview |
|||
```` |
|||
|
|||
Please try it and provide feedback to us. Thanks in advance. |
|||
|
|||
> See the instructions in the *Get started with the Blazor UI* section above to properly create and run your application. |
|||
|
|||
### File Management Angular UI |
|||
|
|||
Angular UI for the [File Management](https://commercial.abp.io/modules/Volo.FileManagement) module is available with the version 3.2. You can add it to your solution using the ABP Suite. |
|||
|
|||
 |
|||
|
|||
### Profile Picture Management |
|||
|
|||
We've added profile picture management for the account module, so a user can select one of the options below for her profile picture; |
|||
|
|||
* Use the default placeholder as the avatar. |
|||
* Use [Gravatar](https://gravatar.com/) service to get the picture matching the email address of the user. |
|||
* Upload a file as the profile picture. |
|||
|
|||
 |
|||
|
|||
### Two Factor Authentication Features |
|||
|
|||
Created [features](https://docs.abp.io/en/abp/3.2/Features) and [settings](https://docs.abp.io/en/abp/3.2/Settings) to disable, enable or force to use 2FA on login for the tenants and users. |
|||
|
|||
### Upgrading the ABP Suite |
|||
|
|||
You can use the following command to upgrade the ABP Suite to the latest preview version: |
|||
|
|||
```` |
|||
abp suite update --preview |
|||
```` |
|||
|
|||
## Other News |
|||
|
|||
### The ABP Community |
|||
|
|||
**ABP Community** web site is constantly being improved and new articles are added. We will add "**commenting**" and "**rating**" features to the articles soon to increase the interactivity between the people. |
|||
|
|||
 |
|||
|
|||
If you have something to share with the ABP community or want to follow the project progress, please check the **[community.abp.io](https://community.abp.io/)**! |
|||
|
|||
### CMS Kit Project |
|||
|
|||
We are silently working on a project, named [CMS Kit](https://github.com/abpframework/abp/tree/dev/modules/cms-kit), for a few months. CMS Kit is a set of reusable CMS (Content Management System) components based on the ABP Framework. Some of the components currently being developed: |
|||
|
|||
* **Comments**; Allows users to comment under something (a blog post, a document, an image... etc). |
|||
* **Reactions**; Allows users to give reactions to something (a comment, a picture... etc.) using simple emoji icons. |
|||
* **Rating**; Allows users to rate some content from 1 to 5. |
|||
* **Newsletter**; Allows you to put a newsletter box to your web site to collect emails from users. |
|||
* **Contact**; Put a form to get message from the web site visitors. |
|||
|
|||
There are more planned components like articles, tags, votes, favorites, portfolio, image gallery, FAQ... etc. We will document and deploy these components when they get matured and ready to use. Some of them will be open source & free while some of them are paid (included in the [ABP Commercial](https://commercial.abp.io/) license). |
|||
|
|||
## Feedback |
|||
|
|||
Please try the ABP Framework 3.2.0 RC and [provide feedback](https://github.com/abpframework/abp/issues/new) to help us to release a more stable version. The planned release date for the [3.2.0 final](https://github.com/abpframework/abp/milestone/43) version is October 01. |
|||
|
After Width: | Height: | Size: 551 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 216 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 55 KiB |
@ -0,0 +1,122 @@ |
|||
# How to Setup Azure Active Directory and Integrate Abp Angular Application |
|||
|
|||
This guide demonstrates how to register an application to Azure Active Directory and integrate AzureAD to an ABP angular application that enables users to sign in using OAuth 2.0 with credentials from **Azure Active Directory**. |
|||
|
|||
## Authentication Flow |
|||
|
|||
Abp angular applications use **Authentication Code with PKCE** (specs [here](https://tools.ietf.org/html/rfc7636)) which is the most suitable flow for spa applications by the time this article is written since implicit flow is deprecated. |
|||
|
|||
The most common question is; |
|||
|
|||
> Where to put OpenId connection code in angular project? |
|||
|
|||
The answer is, **you don't**. Abp angular application is integrated with backend code (HttpApi.Host project) where it loads the configurations, **permissions** etc. For none-tiered angular applications, **HttpApi.Host** project also has IdentityServer4 embedded; also serving as **Authorization Server**. Angular application authentication flow is shown below. |
|||
|
|||
<img src="auth-diagram.jpeg" alt="auth-diagram" style="zoom:50%;" /> |
|||
|
|||
> What if I want Azure AD as my authorization server and not IdentityServer? |
|||
|
|||
This means your application will be using AzureAD user store for authentication. By registering both angular app and HttpApi to AzureAD, authentication might work but **authorization won't**. Users need to be registered to Abp identity system for auditing, permissions etc. So the flow should be 3rd party registration. |
|||
|
|||
## Setting up OpenId Connection |
|||
|
|||
Lets start with adding OpenId connection. Open the **HttpApiHostModule.cs** and update the **ConfigureAuthentication** method as below: |
|||
|
|||
```csharp |
|||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); |
|||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier); |
|||
|
|||
context.Services.AddAuthentication() |
|||
.AddIdentityServerAuthentication(options => |
|||
{ |
|||
options.Authority = configuration["AuthServer:Authority"]; |
|||
options.RequireHttpsMetadata = false; |
|||
options.ApiName = "NonTieredAngular"; |
|||
options.JwtBackChannelHandler = new HttpClientHandler() |
|||
{ |
|||
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator |
|||
}; |
|||
}) |
|||
.AddOpenIdConnect("AzureOpenId", "Azure AD OpenId", options => |
|||
{ |
|||
options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"] + "/v2.0/"; |
|||
options.ClientId = configuration["AzureAd:ClientId"]; |
|||
options.ResponseType = OpenIdConnectResponseType.CodeIdToken; |
|||
options.CallbackPath = configuration["AzureAd:CallbackPath"]; |
|||
options.ClientSecret = configuration["AzureAd:ClientSecret"]; |
|||
options.RequireHttpsMetadata = false; |
|||
options.SaveTokens = true; |
|||
options.GetClaimsFromUserInfoEndpoint = true; |
|||
options.Scope.Add("email"); |
|||
}); |
|||
``` |
|||
|
|||
> If you are using tiered (separate identity server) application, open **IdentityServerModule.cs** and add the OpenIdConnection manually to **ConfigureServices** method as following: |
|||
|
|||
```csharp |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); |
|||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier); |
|||
|
|||
context.Services.AddAuthentication() |
|||
.AddOpenIdConnect("AzureOpenId", "Azure AD OpenId", options => |
|||
{ |
|||
... // Same configuration above |
|||
}); |
|||
``` |
|||
|
|||
Now we can add AzureAD settings. Open the **appsettings.json** located in **HttpApi.Host** project (or **IdentityServer** project if you are using tiered application). Add the following; |
|||
|
|||
```csharp |
|||
"AzureAd": { |
|||
"Instance": "https://login.microsoftonline.com/", |
|||
"TenantId": "<azureAd-tenant-id>", |
|||
"ClientId": "<azureAd-client-id>", |
|||
"Domain": "domain.onmicrosoft.com", |
|||
"CallbackPath": "/signin-azuread-oidc", |
|||
"ClientSecret": "<azureAd-client-secret>" |
|||
}, |
|||
``` |
|||
|
|||
Keep on mind that **App.SelfUrl** + **AzureAd.CallbackPath** will be used in AzureAD app registration. We'll update the AzureAd settings after registering the application in Azure Portal. |
|||
|
|||
## Setting up Azure Active Directory |
|||
|
|||
Navigate to Manage Azure Active Directory in [azure portal](https://portal.azure.com/). Go to **App registrations** on left side menu and hit New registration. |
|||
|
|||
 |
|||
|
|||
Enter a name for your application and **App.SelfUrl** + **AzureAd.CallbackPath** as redirect uri then register. |
|||
|
|||
<img src="azure-app-register.JPG" alt="azure-app-register" style="zoom:75%;" /> |
|||
|
|||
Now navigate to **Authentication** on the left menu and enable **ID tokens**. |
|||
|
|||
 |
|||
|
|||
We also need to set a client secret. Navigate to **Certificates & secrets** menu on the left and create a new client secret. |
|||
|
|||
 |
|||
|
|||
**Copy** the secret and update your appsettings.json **AzureAd.ClientSecret** field. |
|||
|
|||
 |
|||
|
|||
Also update your **AzureAd.TenantId** and **AzureAd.ClientId** fields with the information located under **Overview** menu. And that's all. |
|||
|
|||
Next time you hit login, you should be seeing login screen enabled Azure AD like below. |
|||
|
|||
 |
|||
|
|||
# FAQ |
|||
|
|||
* I am getting errors when trying to login to AzureAD. |
|||
* You can check [this article FAQ](https://community.abp.io/articles/how-to-use-the-azure-active-directory-authentication-for-mvc-razor-page-applications-4603b9cf) which covers many errors. |
|||
|
|||
|
|||
* But I don't want my users to see default login screen. I want my users to login **only** from AzureAD. |
|||
* You can **mimic** this behaviour by customizing the login page and instantly trigger Azure AD provider click. For more info, you can check [this article](https://community.abp.io/articles/how-to-customize-the-login-page-for-mvc-razor-page-applications-9a40f3cd). |
|||
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 32 KiB |
@ -0,0 +1,441 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq.Expressions; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp.Domain.Entities; |
|||
|
|||
namespace Volo.Abp.Domain.Repositories |
|||
{ |
|||
public static class RepositoryAsyncExtensions |
|||
{ |
|||
#region Contains
|
|||
|
|||
public static Task<bool> ContainsAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] T item, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.ContainsAsync(repository, item, cancellationToken); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Any/All
|
|||
|
|||
public static Task<bool> AnyAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, bool>> predicate, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.AnyAsync(repository, predicate, cancellationToken); |
|||
} |
|||
|
|||
public static Task<bool> AllAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, bool>> predicate, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.AllAsync(repository, predicate, cancellationToken); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Count/LongCount
|
|||
|
|||
public static Task<int> CountAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.CountAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
public static Task<int> CountAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, bool>> predicate, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.CountAsync(repository, predicate, cancellationToken); |
|||
} |
|||
|
|||
public static Task<long> LongCountAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.LongCountAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
public static Task<long> LongCountAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, bool>> predicate, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.LongCountAsync(repository, predicate, cancellationToken); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region First/FirstOrDefault
|
|||
|
|||
public static Task<T> FirstAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.FirstAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
public static Task<T> FirstAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, bool>> predicate, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.FirstAsync(repository, predicate, cancellationToken); |
|||
} |
|||
|
|||
public static Task<T> FirstOrDefaultAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.FirstOrDefaultAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
public static Task<T> FirstOrDefaultAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, bool>> predicate, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.FirstOrDefaultAsync(repository, predicate, cancellationToken); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Last/LastOrDefault
|
|||
|
|||
public static Task<T> LastAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.LastAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
public static Task<T> LastAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, bool>> predicate, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.LastAsync(repository, predicate, cancellationToken); |
|||
} |
|||
|
|||
public static Task<T> LastOrDefaultAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.LastOrDefaultAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
public static Task<T> LastOrDefaultAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, bool>> predicate, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.LastOrDefaultAsync(repository, predicate, cancellationToken); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Single/SingleOrDefault
|
|||
|
|||
public static Task<T> SingleAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SingleAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
public static Task<T> SingleAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, bool>> predicate, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SingleAsync(repository, predicate, cancellationToken); |
|||
} |
|||
|
|||
public static Task<T> SingleOrDefaultAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SingleOrDefaultAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
public static Task<T> SingleOrDefaultAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, bool>> predicate, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SingleOrDefaultAsync(repository, predicate, cancellationToken); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Min
|
|||
|
|||
public static Task<T> MinAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.MinAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
public static Task<TResult> MinAsync<T, TResult>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, TResult>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.MinAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Max
|
|||
|
|||
public static Task<T> MaxAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.MaxAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
public static Task<TResult> MaxAsync<T, TResult>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, TResult>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.MaxAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Sum
|
|||
|
|||
public static Task<decimal> SumAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, decimal>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SumAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<decimal?> SumAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, decimal?>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SumAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<int> SumAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, int>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SumAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<int?> SumAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, int?>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SumAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<long> SumAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, long>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SumAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<long?> SumAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, long?>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SumAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<double> SumAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, double>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SumAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<double?> SumAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, double?>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SumAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<float> SumAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, float>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SumAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<float?> SumAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, float?>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.SumAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Average
|
|||
|
|||
public static Task<decimal> AverageAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, decimal>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.AverageAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<decimal?> AverageAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, decimal?>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.AverageAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<double> AverageAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, int>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.AverageAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<double?> AverageAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, int?>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.AverageAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<double> AverageAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, long>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.AverageAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<double?> AverageAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, long?>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.AverageAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<double> AverageAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, double>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.AverageAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<double?> AverageAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, double?>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.AverageAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
public static Task<float?> AverageAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
[NotNull] Expression<Func<T, float?>> selector, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.AverageAsync(repository, selector, cancellationToken); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ToList/Array
|
|||
|
|||
public static Task<List<T>> ToListAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.ToListAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
public static Task<T[]> ToArrayAsync<T>( |
|||
[NotNull] this IReadOnlyRepository<T> repository, |
|||
CancellationToken cancellationToken = default) |
|||
where T : class, IEntity |
|||
{ |
|||
return repository.AsyncExecuter.ToArrayAsync(repository, cancellationToken); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -1,46 +0,0 @@ |
|||
var abp = abp || {}; |
|||
(function () { |
|||
|
|||
if (!luxon) { |
|||
throw "abp/luxon library requires the luxon library included to the page!"; |
|||
} |
|||
|
|||
/* TIMING *************************************************/ |
|||
|
|||
abp.timing = abp.timing || {}; |
|||
|
|||
var setObjectValue = function (obj, property, value) { |
|||
if (typeof property === "string") { |
|||
property = property.split('.'); |
|||
} |
|||
|
|||
if (property.length > 1) { |
|||
var p = property.shift(); |
|||
setObjectValue(obj[p], property, value); |
|||
} else { |
|||
obj[property[0]] = value; |
|||
} |
|||
} |
|||
|
|||
var getObjectValue = function (obj, property) { |
|||
return property.split('.').reduce((a, v) => a[v], obj) |
|||
} |
|||
|
|||
abp.timing.convertFieldsToIsoDate = function (form, fields) { |
|||
for (var field of fields) { |
|||
var dateTime = luxon.DateTime |
|||
.fromFormat( |
|||
getObjectValue(form, field), |
|||
abp.localization.currentCulture.dateTimeFormat.shortDatePattern, |
|||
{locale: abp.localization.currentCulture.cultureName} |
|||
); |
|||
|
|||
if (!dateTime.invalid) { |
|||
setObjectValue(form, field, dateTime.toFormat("yyyy-MM-dd HH:mm:ss")) |
|||
} |
|||
} |
|||
|
|||
return form; |
|||
} |
|||
|
|||
})(jQuery); |
|||
@ -1,46 +0,0 @@ |
|||
var abp = abp || {}; |
|||
(function () { |
|||
|
|||
if (!luxon) { |
|||
throw "abp/luxon library requires the luxon library included to the page!"; |
|||
} |
|||
|
|||
/* TIMING *************************************************/ |
|||
|
|||
abp.timing = abp.timing || {}; |
|||
|
|||
var setObjectValue = function (obj, property, value) { |
|||
if (typeof property === "string") { |
|||
property = property.split('.'); |
|||
} |
|||
|
|||
if (property.length > 1) { |
|||
var p = property.shift(); |
|||
setObjectValue(obj[p], property, value); |
|||
} else { |
|||
obj[property[0]] = value; |
|||
} |
|||
} |
|||
|
|||
var getObjectValue = function (obj, property) { |
|||
return property.split('.').reduce((a, v) => a[v], obj) |
|||
} |
|||
|
|||
abp.timing.convertFieldsToIsoDate = function (form, fields) { |
|||
for (var field of fields) { |
|||
var dateTime = luxon.DateTime |
|||
.fromFormat( |
|||
getObjectValue(form, field), |
|||
abp.localization.currentCulture.dateTimeFormat.shortDatePattern, |
|||
{locale: abp.localization.currentCulture.cultureName} |
|||
); |
|||
|
|||
if (!dateTime.invalid) { |
|||
setObjectValue(form, field, dateTime.toFormat("yyyy-MM-dd HH:mm:ss")) |
|||
} |
|||
} |
|||
|
|||
return form; |
|||
} |
|||
|
|||
})(jQuery); |
|||
@ -0,0 +1,973 @@ |
|||
/*! |
|||
* clipboard.js v2.0.6 |
|||
* https://clipboardjs.com/
|
|||
* |
|||
* Licensed MIT © Zeno Rocha |
|||
*/ |
|||
(function webpackUniversalModuleDefinition(root, factory) { |
|||
if(typeof exports === 'object' && typeof module === 'object') |
|||
module.exports = factory(); |
|||
else if(typeof define === 'function' && define.amd) |
|||
define([], factory); |
|||
else if(typeof exports === 'object') |
|||
exports["ClipboardJS"] = factory(); |
|||
else |
|||
root["ClipboardJS"] = factory(); |
|||
})(this, function() { |
|||
return /******/ (function(modules) { // webpackBootstrap
|
|||
/******/ // The module cache
|
|||
/******/ var installedModules = {}; |
|||
/******/ |
|||
/******/ // The require function
|
|||
/******/ function __webpack_require__(moduleId) { |
|||
/******/ |
|||
/******/ // Check if module is in cache
|
|||
/******/ if(installedModules[moduleId]) { |
|||
/******/ return installedModules[moduleId].exports; |
|||
/******/ } |
|||
/******/ // Create a new module (and put it into the cache)
|
|||
/******/ var module = installedModules[moduleId] = { |
|||
/******/ i: moduleId, |
|||
/******/ l: false, |
|||
/******/ exports: {} |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // Execute the module function
|
|||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); |
|||
/******/ |
|||
/******/ // Flag the module as loaded
|
|||
/******/ module.l = true; |
|||
/******/ |
|||
/******/ // Return the exports of the module
|
|||
/******/ return module.exports; |
|||
/******/ } |
|||
/******/ |
|||
/******/ |
|||
/******/ // expose the modules object (__webpack_modules__)
|
|||
/******/ __webpack_require__.m = modules; |
|||
/******/ |
|||
/******/ // expose the module cache
|
|||
/******/ __webpack_require__.c = installedModules; |
|||
/******/ |
|||
/******/ // define getter function for harmony exports
|
|||
/******/ __webpack_require__.d = function(exports, name, getter) { |
|||
/******/ if(!__webpack_require__.o(exports, name)) { |
|||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); |
|||
/******/ } |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // define __esModule on exports
|
|||
/******/ __webpack_require__.r = function(exports) { |
|||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { |
|||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); |
|||
/******/ } |
|||
/******/ Object.defineProperty(exports, '__esModule', { value: true }); |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // create a fake namespace object
|
|||
/******/ // mode & 1: value is a module id, require it
|
|||
/******/ // mode & 2: merge all properties of value into the ns
|
|||
/******/ // mode & 4: return value when already ns object
|
|||
/******/ // mode & 8|1: behave like require
|
|||
/******/ __webpack_require__.t = function(value, mode) { |
|||
/******/ if(mode & 1) value = __webpack_require__(value); |
|||
/******/ if(mode & 8) return value; |
|||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; |
|||
/******/ var ns = Object.create(null); |
|||
/******/ __webpack_require__.r(ns); |
|||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); |
|||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); |
|||
/******/ return ns; |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|||
/******/ __webpack_require__.n = function(module) { |
|||
/******/ var getter = module && module.__esModule ? |
|||
/******/ function getDefault() { return module['default']; } : |
|||
/******/ function getModuleExports() { return module; }; |
|||
/******/ __webpack_require__.d(getter, 'a', getter); |
|||
/******/ return getter; |
|||
/******/ }; |
|||
/******/ |
|||
/******/ // Object.prototype.hasOwnProperty.call
|
|||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; |
|||
/******/ |
|||
/******/ // __webpack_public_path__
|
|||
/******/ __webpack_require__.p = ""; |
|||
/******/ |
|||
/******/ |
|||
/******/ // Load entry module and return exports
|
|||
/******/ return __webpack_require__(__webpack_require__.s = 6); |
|||
/******/ }) |
|||
/************************************************************************/ |
|||
/******/ ([ |
|||
/* 0 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
function select(element) { |
|||
var selectedText; |
|||
|
|||
if (element.nodeName === 'SELECT') { |
|||
element.focus(); |
|||
|
|||
selectedText = element.value; |
|||
} |
|||
else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { |
|||
var isReadOnly = element.hasAttribute('readonly'); |
|||
|
|||
if (!isReadOnly) { |
|||
element.setAttribute('readonly', ''); |
|||
} |
|||
|
|||
element.select(); |
|||
element.setSelectionRange(0, element.value.length); |
|||
|
|||
if (!isReadOnly) { |
|||
element.removeAttribute('readonly'); |
|||
} |
|||
|
|||
selectedText = element.value; |
|||
} |
|||
else { |
|||
if (element.hasAttribute('contenteditable')) { |
|||
element.focus(); |
|||
} |
|||
|
|||
var selection = window.getSelection(); |
|||
var range = document.createRange(); |
|||
|
|||
range.selectNodeContents(element); |
|||
selection.removeAllRanges(); |
|||
selection.addRange(range); |
|||
|
|||
selectedText = selection.toString(); |
|||
} |
|||
|
|||
return selectedText; |
|||
} |
|||
|
|||
module.exports = select; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 1 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
function E () { |
|||
// Keep this empty so it's easier to inherit from
|
|||
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
|
|||
} |
|||
|
|||
E.prototype = { |
|||
on: function (name, callback, ctx) { |
|||
var e = this.e || (this.e = {}); |
|||
|
|||
(e[name] || (e[name] = [])).push({ |
|||
fn: callback, |
|||
ctx: ctx |
|||
}); |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
once: function (name, callback, ctx) { |
|||
var self = this; |
|||
function listener () { |
|||
self.off(name, listener); |
|||
callback.apply(ctx, arguments); |
|||
}; |
|||
|
|||
listener._ = callback |
|||
return this.on(name, listener, ctx); |
|||
}, |
|||
|
|||
emit: function (name) { |
|||
var data = [].slice.call(arguments, 1); |
|||
var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); |
|||
var i = 0; |
|||
var len = evtArr.length; |
|||
|
|||
for (i; i < len; i++) { |
|||
evtArr[i].fn.apply(evtArr[i].ctx, data); |
|||
} |
|||
|
|||
return this; |
|||
}, |
|||
|
|||
off: function (name, callback) { |
|||
var e = this.e || (this.e = {}); |
|||
var evts = e[name]; |
|||
var liveEvents = []; |
|||
|
|||
if (evts && callback) { |
|||
for (var i = 0, len = evts.length; i < len; i++) { |
|||
if (evts[i].fn !== callback && evts[i].fn._ !== callback) |
|||
liveEvents.push(evts[i]); |
|||
} |
|||
} |
|||
|
|||
// Remove event from queue to prevent memory leak
|
|||
// Suggested by https://github.com/lazd
|
|||
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
|
|||
|
|||
(liveEvents.length) |
|||
? e[name] = liveEvents |
|||
: delete e[name]; |
|||
|
|||
return this; |
|||
} |
|||
}; |
|||
|
|||
module.exports = E; |
|||
module.exports.TinyEmitter = E; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 2 */ |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
var is = __webpack_require__(3); |
|||
var delegate = __webpack_require__(4); |
|||
|
|||
/** |
|||
* Validates all params and calls the right |
|||
* listener function based on its target type. |
|||
* |
|||
* @param {String|HTMLElement|HTMLCollection|NodeList} target |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listen(target, type, callback) { |
|||
if (!target && !type && !callback) { |
|||
throw new Error('Missing required arguments'); |
|||
} |
|||
|
|||
if (!is.string(type)) { |
|||
throw new TypeError('Second argument must be a String'); |
|||
} |
|||
|
|||
if (!is.fn(callback)) { |
|||
throw new TypeError('Third argument must be a Function'); |
|||
} |
|||
|
|||
if (is.node(target)) { |
|||
return listenNode(target, type, callback); |
|||
} |
|||
else if (is.nodeList(target)) { |
|||
return listenNodeList(target, type, callback); |
|||
} |
|||
else if (is.string(target)) { |
|||
return listenSelector(target, type, callback); |
|||
} |
|||
else { |
|||
throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList'); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Adds an event listener to a HTML element |
|||
* and returns a remove listener function. |
|||
* |
|||
* @param {HTMLElement} node |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listenNode(node, type, callback) { |
|||
node.addEventListener(type, callback); |
|||
|
|||
return { |
|||
destroy: function() { |
|||
node.removeEventListener(type, callback); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Add an event listener to a list of HTML elements |
|||
* and returns a remove listener function. |
|||
* |
|||
* @param {NodeList|HTMLCollection} nodeList |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listenNodeList(nodeList, type, callback) { |
|||
Array.prototype.forEach.call(nodeList, function(node) { |
|||
node.addEventListener(type, callback); |
|||
}); |
|||
|
|||
return { |
|||
destroy: function() { |
|||
Array.prototype.forEach.call(nodeList, function(node) { |
|||
node.removeEventListener(type, callback); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Add an event listener to a selector |
|||
* and returns a remove listener function. |
|||
* |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Object} |
|||
*/ |
|||
function listenSelector(selector, type, callback) { |
|||
return delegate(document.body, selector, type, callback); |
|||
} |
|||
|
|||
module.exports = listen; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 3 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
/** |
|||
* Check if argument is a HTML element. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.node = function(value) { |
|||
return value !== undefined |
|||
&& value instanceof HTMLElement |
|||
&& value.nodeType === 1; |
|||
}; |
|||
|
|||
/** |
|||
* Check if argument is a list of HTML elements. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.nodeList = function(value) { |
|||
var type = Object.prototype.toString.call(value); |
|||
|
|||
return value !== undefined |
|||
&& (type === '[object NodeList]' || type === '[object HTMLCollection]') |
|||
&& ('length' in value) |
|||
&& (value.length === 0 || exports.node(value[0])); |
|||
}; |
|||
|
|||
/** |
|||
* Check if argument is a string. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.string = function(value) { |
|||
return typeof value === 'string' |
|||
|| value instanceof String; |
|||
}; |
|||
|
|||
/** |
|||
* Check if argument is a function. |
|||
* |
|||
* @param {Object} value |
|||
* @return {Boolean} |
|||
*/ |
|||
exports.fn = function(value) { |
|||
var type = Object.prototype.toString.call(value); |
|||
|
|||
return type === '[object Function]'; |
|||
}; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 4 */ |
|||
/***/ (function(module, exports, __webpack_require__) { |
|||
|
|||
var closest = __webpack_require__(5); |
|||
|
|||
/** |
|||
* Delegates event to a selector. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @param {Boolean} useCapture |
|||
* @return {Object} |
|||
*/ |
|||
function _delegate(element, selector, type, callback, useCapture) { |
|||
var listenerFn = listener.apply(this, arguments); |
|||
|
|||
element.addEventListener(type, listenerFn, useCapture); |
|||
|
|||
return { |
|||
destroy: function() { |
|||
element.removeEventListener(type, listenerFn, useCapture); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Delegates event to a selector. |
|||
* |
|||
* @param {Element|String|Array} [elements] |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @param {Boolean} useCapture |
|||
* @return {Object} |
|||
*/ |
|||
function delegate(elements, selector, type, callback, useCapture) { |
|||
// Handle the regular Element usage
|
|||
if (typeof elements.addEventListener === 'function') { |
|||
return _delegate.apply(null, arguments); |
|||
} |
|||
|
|||
// Handle Element-less usage, it defaults to global delegation
|
|||
if (typeof type === 'function') { |
|||
// Use `document` as the first parameter, then apply arguments
|
|||
// This is a short way to .unshift `arguments` without running into deoptimizations
|
|||
return _delegate.bind(null, document).apply(null, arguments); |
|||
} |
|||
|
|||
// Handle Selector-based usage
|
|||
if (typeof elements === 'string') { |
|||
elements = document.querySelectorAll(elements); |
|||
} |
|||
|
|||
// Handle Array-like based usage
|
|||
return Array.prototype.map.call(elements, function (element) { |
|||
return _delegate(element, selector, type, callback, useCapture); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Finds closest match and invokes callback. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @param {String} type |
|||
* @param {Function} callback |
|||
* @return {Function} |
|||
*/ |
|||
function listener(element, selector, type, callback) { |
|||
return function(e) { |
|||
e.delegateTarget = closest(e.target, selector); |
|||
|
|||
if (e.delegateTarget) { |
|||
callback.call(element, e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
module.exports = delegate; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 5 */ |
|||
/***/ (function(module, exports) { |
|||
|
|||
var DOCUMENT_NODE_TYPE = 9; |
|||
|
|||
/** |
|||
* A polyfill for Element.matches() |
|||
*/ |
|||
if (typeof Element !== 'undefined' && !Element.prototype.matches) { |
|||
var proto = Element.prototype; |
|||
|
|||
proto.matches = proto.matchesSelector || |
|||
proto.mozMatchesSelector || |
|||
proto.msMatchesSelector || |
|||
proto.oMatchesSelector || |
|||
proto.webkitMatchesSelector; |
|||
} |
|||
|
|||
/** |
|||
* Finds the closest parent that matches a selector. |
|||
* |
|||
* @param {Element} element |
|||
* @param {String} selector |
|||
* @return {Function} |
|||
*/ |
|||
function closest (element, selector) { |
|||
while (element && element.nodeType !== DOCUMENT_NODE_TYPE) { |
|||
if (typeof element.matches === 'function' && |
|||
element.matches(selector)) { |
|||
return element; |
|||
} |
|||
element = element.parentNode; |
|||
} |
|||
} |
|||
|
|||
module.exports = closest; |
|||
|
|||
|
|||
/***/ }), |
|||
/* 6 */ |
|||
/***/ (function(module, __webpack_exports__, __webpack_require__) { |
|||
|
|||
"use strict"; |
|||
__webpack_require__.r(__webpack_exports__); |
|||
|
|||
// EXTERNAL MODULE: ./node_modules/select/src/select.js
|
|||
var src_select = __webpack_require__(0); |
|||
var select_default = /*#__PURE__*/__webpack_require__.n(src_select); |
|||
|
|||
// CONCATENATED MODULE: ./src/clipboard-action.js
|
|||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; |
|||
|
|||
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; }; }(); |
|||
|
|||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } |
|||
|
|||
|
|||
|
|||
/** |
|||
* Inner class which performs selection from either `text` or `target` |
|||
* properties and then executes copy or cut operations. |
|||
*/ |
|||
|
|||
var clipboard_action_ClipboardAction = function () { |
|||
/** |
|||
* @param {Object} options |
|||
*/ |
|||
function ClipboardAction(options) { |
|||
_classCallCheck(this, ClipboardAction); |
|||
|
|||
this.resolveOptions(options); |
|||
this.initSelection(); |
|||
} |
|||
|
|||
/** |
|||
* Defines base properties passed from constructor. |
|||
* @param {Object} options |
|||
*/ |
|||
|
|||
|
|||
_createClass(ClipboardAction, [{ |
|||
key: 'resolveOptions', |
|||
value: function resolveOptions() { |
|||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; |
|||
|
|||
this.action = options.action; |
|||
this.container = options.container; |
|||
this.emitter = options.emitter; |
|||
this.target = options.target; |
|||
this.text = options.text; |
|||
this.trigger = options.trigger; |
|||
|
|||
this.selectedText = ''; |
|||
} |
|||
|
|||
/** |
|||
* Decides which selection strategy is going to be applied based |
|||
* on the existence of `text` and `target` properties. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'initSelection', |
|||
value: function initSelection() { |
|||
if (this.text) { |
|||
this.selectFake(); |
|||
} else if (this.target) { |
|||
this.selectTarget(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Creates a fake textarea element, sets its value from `text` property, |
|||
* and makes a selection on it. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'selectFake', |
|||
value: function selectFake() { |
|||
var _this = this; |
|||
|
|||
var isRTL = document.documentElement.getAttribute('dir') == 'rtl'; |
|||
|
|||
this.removeFake(); |
|||
|
|||
this.fakeHandlerCallback = function () { |
|||
return _this.removeFake(); |
|||
}; |
|||
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true; |
|||
|
|||
this.fakeElem = document.createElement('textarea'); |
|||
// Prevent zooming on iOS
|
|||
this.fakeElem.style.fontSize = '12pt'; |
|||
// Reset box model
|
|||
this.fakeElem.style.border = '0'; |
|||
this.fakeElem.style.padding = '0'; |
|||
this.fakeElem.style.margin = '0'; |
|||
// Move element out of screen horizontally
|
|||
this.fakeElem.style.position = 'absolute'; |
|||
this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px'; |
|||
// Move element to the same position vertically
|
|||
var yPosition = window.pageYOffset || document.documentElement.scrollTop; |
|||
this.fakeElem.style.top = yPosition + 'px'; |
|||
|
|||
this.fakeElem.setAttribute('readonly', ''); |
|||
this.fakeElem.value = this.text; |
|||
|
|||
this.container.appendChild(this.fakeElem); |
|||
|
|||
this.selectedText = select_default()(this.fakeElem); |
|||
this.copyText(); |
|||
} |
|||
|
|||
/** |
|||
* Only removes the fake element after another click event, that way |
|||
* a user can hit `Ctrl+C` to copy because selection still exists. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'removeFake', |
|||
value: function removeFake() { |
|||
if (this.fakeHandler) { |
|||
this.container.removeEventListener('click', this.fakeHandlerCallback); |
|||
this.fakeHandler = null; |
|||
this.fakeHandlerCallback = null; |
|||
} |
|||
|
|||
if (this.fakeElem) { |
|||
this.container.removeChild(this.fakeElem); |
|||
this.fakeElem = null; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Selects the content from element passed on `target` property. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'selectTarget', |
|||
value: function selectTarget() { |
|||
this.selectedText = select_default()(this.target); |
|||
this.copyText(); |
|||
} |
|||
|
|||
/** |
|||
* Executes the copy operation based on the current selection. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'copyText', |
|||
value: function copyText() { |
|||
var succeeded = void 0; |
|||
|
|||
try { |
|||
succeeded = document.execCommand(this.action); |
|||
} catch (err) { |
|||
succeeded = false; |
|||
} |
|||
|
|||
this.handleResult(succeeded); |
|||
} |
|||
|
|||
/** |
|||
* Fires an event based on the copy operation result. |
|||
* @param {Boolean} succeeded |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'handleResult', |
|||
value: function handleResult(succeeded) { |
|||
this.emitter.emit(succeeded ? 'success' : 'error', { |
|||
action: this.action, |
|||
text: this.selectedText, |
|||
trigger: this.trigger, |
|||
clearSelection: this.clearSelection.bind(this) |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Moves focus away from `target` and back to the trigger, removes current selection. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'clearSelection', |
|||
value: function clearSelection() { |
|||
if (this.trigger) { |
|||
this.trigger.focus(); |
|||
} |
|||
document.activeElement.blur(); |
|||
window.getSelection().removeAllRanges(); |
|||
} |
|||
|
|||
/** |
|||
* Sets the `action` to be performed which can be either 'copy' or 'cut'. |
|||
* @param {String} action |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'destroy', |
|||
|
|||
|
|||
/** |
|||
* Destroy lifecycle. |
|||
*/ |
|||
value: function destroy() { |
|||
this.removeFake(); |
|||
} |
|||
}, { |
|||
key: 'action', |
|||
set: function set() { |
|||
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy'; |
|||
|
|||
this._action = action; |
|||
|
|||
if (this._action !== 'copy' && this._action !== 'cut') { |
|||
throw new Error('Invalid "action" value, use either "copy" or "cut"'); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Gets the `action` property. |
|||
* @return {String} |
|||
*/ |
|||
, |
|||
get: function get() { |
|||
return this._action; |
|||
} |
|||
|
|||
/** |
|||
* Sets the `target` property using an element |
|||
* that will be have its content copied. |
|||
* @param {Element} target |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'target', |
|||
set: function set(target) { |
|||
if (target !== undefined) { |
|||
if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) { |
|||
if (this.action === 'copy' && target.hasAttribute('disabled')) { |
|||
throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); |
|||
} |
|||
|
|||
if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) { |
|||
throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); |
|||
} |
|||
|
|||
this._target = target; |
|||
} else { |
|||
throw new Error('Invalid "target" value, use a valid Element'); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Gets the `target` property. |
|||
* @return {String|HTMLElement} |
|||
*/ |
|||
, |
|||
get: function get() { |
|||
return this._target; |
|||
} |
|||
}]); |
|||
|
|||
return ClipboardAction; |
|||
}(); |
|||
|
|||
/* harmony default export */ var clipboard_action = (clipboard_action_ClipboardAction); |
|||
// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js
|
|||
var tiny_emitter = __webpack_require__(1); |
|||
var tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter); |
|||
|
|||
// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js
|
|||
var listen = __webpack_require__(2); |
|||
var listen_default = /*#__PURE__*/__webpack_require__.n(listen); |
|||
|
|||
// CONCATENATED MODULE: ./src/clipboard.js
|
|||
var clipboard_typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; |
|||
|
|||
var clipboard_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; }; }(); |
|||
|
|||
function clipboard_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } |
|||
|
|||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } |
|||
|
|||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
/** |
|||
* Base class which takes one or more elements, adds event listeners to them, |
|||
* and instantiates a new `ClipboardAction` on each click. |
|||
*/ |
|||
|
|||
var clipboard_Clipboard = function (_Emitter) { |
|||
_inherits(Clipboard, _Emitter); |
|||
|
|||
/** |
|||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger |
|||
* @param {Object} options |
|||
*/ |
|||
function Clipboard(trigger, options) { |
|||
clipboard_classCallCheck(this, Clipboard); |
|||
|
|||
var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this)); |
|||
|
|||
_this.resolveOptions(options); |
|||
_this.listenClick(trigger); |
|||
return _this; |
|||
} |
|||
|
|||
/** |
|||
* Defines if attributes would be resolved using internal setter functions |
|||
* or custom functions that were passed in the constructor. |
|||
* @param {Object} options |
|||
*/ |
|||
|
|||
|
|||
clipboard_createClass(Clipboard, [{ |
|||
key: 'resolveOptions', |
|||
value: function resolveOptions() { |
|||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; |
|||
|
|||
this.action = typeof options.action === 'function' ? options.action : this.defaultAction; |
|||
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget; |
|||
this.text = typeof options.text === 'function' ? options.text : this.defaultText; |
|||
this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body; |
|||
} |
|||
|
|||
/** |
|||
* Adds a click event listener to the passed trigger. |
|||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'listenClick', |
|||
value: function listenClick(trigger) { |
|||
var _this2 = this; |
|||
|
|||
this.listener = listen_default()(trigger, 'click', function (e) { |
|||
return _this2.onClick(e); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Defines a new `ClipboardAction` on each click event. |
|||
* @param {Event} e |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'onClick', |
|||
value: function onClick(e) { |
|||
var trigger = e.delegateTarget || e.currentTarget; |
|||
|
|||
if (this.clipboardAction) { |
|||
this.clipboardAction = null; |
|||
} |
|||
|
|||
this.clipboardAction = new clipboard_action({ |
|||
action: this.action(trigger), |
|||
target: this.target(trigger), |
|||
text: this.text(trigger), |
|||
container: this.container, |
|||
trigger: trigger, |
|||
emitter: this |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Default `action` lookup function. |
|||
* @param {Element} trigger |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'defaultAction', |
|||
value: function defaultAction(trigger) { |
|||
return getAttributeValue('action', trigger); |
|||
} |
|||
|
|||
/** |
|||
* Default `target` lookup function. |
|||
* @param {Element} trigger |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'defaultTarget', |
|||
value: function defaultTarget(trigger) { |
|||
var selector = getAttributeValue('target', trigger); |
|||
|
|||
if (selector) { |
|||
return document.querySelector(selector); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Returns the support of the given action, or all actions if no action is |
|||
* given. |
|||
* @param {String} [action] |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'defaultText', |
|||
|
|||
|
|||
/** |
|||
* Default `text` lookup function. |
|||
* @param {Element} trigger |
|||
*/ |
|||
value: function defaultText(trigger) { |
|||
return getAttributeValue('text', trigger); |
|||
} |
|||
|
|||
/** |
|||
* Destroy lifecycle. |
|||
*/ |
|||
|
|||
}, { |
|||
key: 'destroy', |
|||
value: function destroy() { |
|||
this.listener.destroy(); |
|||
|
|||
if (this.clipboardAction) { |
|||
this.clipboardAction.destroy(); |
|||
this.clipboardAction = null; |
|||
} |
|||
} |
|||
}], [{ |
|||
key: 'isSupported', |
|||
value: function isSupported() { |
|||
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut']; |
|||
|
|||
var actions = typeof action === 'string' ? [action] : action; |
|||
var support = !!document.queryCommandSupported; |
|||
|
|||
actions.forEach(function (action) { |
|||
support = support && !!document.queryCommandSupported(action); |
|||
}); |
|||
|
|||
return support; |
|||
} |
|||
}]); |
|||
|
|||
return Clipboard; |
|||
}(tiny_emitter_default.a); |
|||
|
|||
/** |
|||
* Helper function to retrieve attribute value. |
|||
* @param {String} suffix |
|||
* @param {Element} element |
|||
*/ |
|||
|
|||
|
|||
function getAttributeValue(suffix, element) { |
|||
var attribute = 'data-clipboard-' + suffix; |
|||
|
|||
if (!element.hasAttribute(attribute)) { |
|||
return; |
|||
} |
|||
|
|||
return element.getAttribute(attribute); |
|||
} |
|||
|
|||
/* harmony default export */ var clipboard = __webpack_exports__["default"] = (clipboard_Clipboard); |
|||
|
|||
/***/ }) |
|||
/******/ ])["default"]; |
|||
}); |
|||
@ -0,0 +1,32 @@ |
|||
# [Prism](https://prismjs.com/) |
|||
|
|||
[](https://travis-ci.org/PrismJS/prism) |
|||
[](https://www.npmjs.com/package/prismjs) |
|||
|
|||
Prism is a lightweight, robust, elegant syntax highlighting library. It's a spin-off project from [Dabblet](https://dabblet.com/). |
|||
|
|||
You can learn more on [prismjs.com](https://prismjs.com/). |
|||
|
|||
[Why another syntax highlighter?](https://lea.verou.me/2012/07/introducing-prism-an-awesome-new-syntax-highlighter/#more-1841) |
|||
|
|||
[More themes for Prism!](https://github.com/PrismJS/prism-themes) |
|||
|
|||
## Contribute to Prism! |
|||
|
|||
Prism depends on community contributions to expand and cover a wider array of use cases. If you like it, considering giving back by sending a pull request. Here are a few tips: |
|||
|
|||
- Read the [documentation](https://prismjs.com/extending.html). Prism was designed to be extensible. |
|||
- Do not edit `prism.js`, it’s just the version of Prism used by the Prism website and is built automatically. Limit your changes to the unminified files in the `components/` folder. `prism.js` and all minified files are also generated automatically by our build system. |
|||
- The build system uses [gulp](https://github.com/gulpjs/gulp) to minify the files and build `prism.js`. With all of Prism's dependencies installed, you just need to run the command `npm run build`. |
|||
- Please follow the code conventions used in the files already. For example, I use [tabs for indentation and spaces for alignment](http://lea.verou.me/2012/01/why-tabs-are-clearly-superior/). Opening braces are on the same line, closing braces on their own line regardless of construct. There is a space before the opening brace. etc etc. |
|||
- Please try to err towards more smaller PRs rather than few huge PRs. If a PR includes changes I want to merge and changes I don't, handling it becomes difficult. |
|||
- My time is very limited these days, so it might take a long time to review longer PRs (short ones are usually merged very quickly), especially those modifying the Prism Core. This doesn't mean your PR is rejected. |
|||
- If you contribute a new language definition, you will be responsible for handling bug reports about that language definition. |
|||
- If you [add a new language definition](https://prismjs.com/extending.html#creating-a-new-language-definition) or plugin, you need to add it to `components.json` as well and rebuild Prism by running `npm run build`, so that it becomes available to the download build page. For new languages, please also add a few [tests](https://prismjs.com/test-suite.html) and an example in the `examples/` folder. |
|||
- Go to [prism-themes](https://github.com/PrismJS/prism-themes) if you want to add a new theme. |
|||
|
|||
Thank you so much for contributing!! |
|||
|
|||
## Translations |
|||
|
|||
* [](https://www.awesomes.cn/repo/PrismJS/prism) |
|||
@ -0,0 +1,56 @@ |
|||
const components = require('../components.js'); |
|||
const getLoader = require('../dependencies'); |
|||
|
|||
|
|||
/** |
|||
* The set of all languages which have been loaded using the below function. |
|||
* |
|||
* @type {Set<string>} |
|||
*/ |
|||
const loadedLanguages = new Set(); |
|||
|
|||
/** |
|||
* Loads the given languages and adds them to the current Prism instance. |
|||
* |
|||
* If no languages are provided, __all__ Prism languages will be loaded. |
|||
* |
|||
* @param {string|string[]} [languages] |
|||
* @returns {void} |
|||
*/ |
|||
function loadLanguages(languages) { |
|||
if (languages === undefined) { |
|||
languages = Object.keys(components.languages).filter(l => l != 'meta'); |
|||
} else if (!Array.isArray(languages)) { |
|||
languages = [languages]; |
|||
} |
|||
|
|||
// the user might have loaded languages via some other way or used `prism.js` which already includes some
|
|||
// we don't need to validate the ids because `getLoader` will ignore invalid ones
|
|||
const loaded = [...loadedLanguages, ...Object.keys(Prism.languages)]; |
|||
|
|||
getLoader(components, languages, loaded).load(lang => { |
|||
if (!(lang in components.languages)) { |
|||
if (!loadLanguages.silent) { |
|||
console.warn('Language does not exist: ' + lang); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
const pathToLanguage = './prism-' + lang; |
|||
|
|||
// remove from require cache and from Prism
|
|||
delete require.cache[require.resolve(pathToLanguage)]; |
|||
delete Prism.languages[lang]; |
|||
|
|||
require(pathToLanguage); |
|||
|
|||
loadedLanguages.add(lang); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Set this to `true` to prevent all warning messages `loadLanguages` logs. |
|||
*/ |
|||
loadLanguages.silent = false; |
|||
|
|||
module.exports = loadLanguages; |
|||
@ -0,0 +1,54 @@ |
|||
(function (Prism) { |
|||
|
|||
var coreRules = '(?:ALPHA|BIT|CHAR|CR|CRLF|CTL|DIGIT|DQUOTE|HEXDIG|HTAB|LF|LWSP|OCTET|SP|VCHAR|WSP)'; |
|||
|
|||
Prism.languages.abnf = { |
|||
'comment': /;.*/, |
|||
'string': { |
|||
pattern: /(?:%[is])?"[^"\n\r]*"/, |
|||
greedy: true, |
|||
inside: { |
|||
'punctuation': /^%[is]/ |
|||
} |
|||
}, |
|||
'range': { |
|||
pattern: /%(?:b[01]+-[01]+|d\d+-\d+|x[A-F\d]+-[A-F\d]+)/i, |
|||
alias: 'number' |
|||
}, |
|||
'terminal': { |
|||
pattern: /%(?:b[01]+(?:\.[01]+)*|d\d+(?:\.\d+)*|x[A-F\d]+(?:\.[A-F\d]+)*)/i, |
|||
alias: 'number' |
|||
}, |
|||
'repetition': { |
|||
pattern: /(^|[^\w-])(?:\d*\*\d*|\d+)/, |
|||
lookbehind: true, |
|||
alias: 'operator' |
|||
}, |
|||
'definition': { |
|||
pattern: /(^[ \t]*)(?:[a-z][\w-]*|<[^>\r\n]*>)(?=\s*=)/m, |
|||
lookbehind: true, |
|||
alias: 'keyword', |
|||
inside: { |
|||
'punctuation': /<|>/ |
|||
} |
|||
}, |
|||
'core-rule': { |
|||
pattern: RegExp('(?:(^|[^<\\w-])' + coreRules + '|<' + coreRules + '>)(?![\\w-])', 'i'), |
|||
lookbehind: true, |
|||
alias: ['rule', 'constant'], |
|||
inside: { |
|||
'punctuation': /<|>/ |
|||
} |
|||
}, |
|||
'rule': { |
|||
pattern: /(^|[^<\w-])[a-z][\w-]*|<[^>\r\n]*>/i, |
|||
lookbehind: true, |
|||
inside: { |
|||
'punctuation': /<|>/ |
|||
} |
|||
}, |
|||
'operator': /=\/?|\//, |
|||
'punctuation': /[()\[\]]/ |
|||
}; |
|||
|
|||
})(Prism); |
|||
@ -0,0 +1 @@ |
|||
!function(n){var i="(?:ALPHA|BIT|CHAR|CR|CRLF|CTL|DIGIT|DQUOTE|HEXDIG|HTAB|LF|LWSP|OCTET|SP|VCHAR|WSP)";Prism.languages.abnf={comment:/;.*/,string:{pattern:/(?:%[is])?"[^"\n\r]*"/,greedy:!0,inside:{punctuation:/^%[is]/}},range:{pattern:/%(?:b[01]+-[01]+|d\d+-\d+|x[A-F\d]+-[A-F\d]+)/i,alias:"number"},terminal:{pattern:/%(?:b[01]+(?:\.[01]+)*|d\d+(?:\.\d+)*|x[A-F\d]+(?:\.[A-F\d]+)*)/i,alias:"number"},repetition:{pattern:/(^|[^\w-])(?:\d*\*\d*|\d+)/,lookbehind:!0,alias:"operator"},definition:{pattern:/(^[ \t]*)(?:[a-z][\w-]*|<[^>\r\n]*>)(?=\s*=)/m,lookbehind:!0,alias:"keyword",inside:{punctuation:/<|>/}},"core-rule":{pattern:RegExp("(?:(^|[^<\\w-])"+i+"|<"+i+">)(?![\\w-])","i"),lookbehind:!0,alias:["rule","constant"],inside:{punctuation:/<|>/}},rule:{pattern:/(^|[^<\w-])[a-z][\w-]*|<[^>\r\n]*>/i,lookbehind:!0,inside:{punctuation:/<|>/}},operator:/=\/?|\//,punctuation:/[()\[\]]/}}(); |
|||
@ -0,0 +1,15 @@ |
|||
Prism.languages.actionscript = Prism.languages.extend('javascript', { |
|||
'keyword': /\b(?:as|break|case|catch|class|const|default|delete|do|else|extends|finally|for|function|if|implements|import|in|instanceof|interface|internal|is|native|new|null|package|private|protected|public|return|super|switch|this|throw|try|typeof|use|var|void|while|with|dynamic|each|final|get|include|namespace|native|override|set|static)\b/, |
|||
'operator': /\+\+|--|(?:[+\-*\/%^]|&&?|\|\|?|<<?|>>?>?|[!=]=?)=?|[~?@]/ |
|||
}); |
|||
Prism.languages.actionscript['class-name'].alias = 'function'; |
|||
|
|||
if (Prism.languages.markup) { |
|||
Prism.languages.insertBefore('actionscript', 'string', { |
|||
'xml': { |
|||
pattern: /(^|[^.])<\/?\w+(?:\s+[^\s>\/=]+=("|')(?:\\[\s\S]|(?!\2)[^\\])*\2)*\s*\/?>/, |
|||
lookbehind: true, |
|||
inside: Prism.languages.markup |
|||
} |
|||
}); |
|||
} |
|||
@ -0,0 +1 @@ |
|||
Prism.languages.actionscript=Prism.languages.extend("javascript",{keyword:/\b(?:as|break|case|catch|class|const|default|delete|do|else|extends|finally|for|function|if|implements|import|in|instanceof|interface|internal|is|native|new|null|package|private|protected|public|return|super|switch|this|throw|try|typeof|use|var|void|while|with|dynamic|each|final|get|include|namespace|native|override|set|static)\b/,operator:/\+\+|--|(?:[+\-*\/%^]|&&?|\|\|?|<<?|>>?>?|[!=]=?)=?|[~?@]/}),Prism.languages.actionscript["class-name"].alias="function",Prism.languages.markup&&Prism.languages.insertBefore("actionscript","string",{xml:{pattern:/(^|[^.])<\/?\w+(?:\s+[^\s>\/=]+=("|')(?:\\[\s\S]|(?!\2)[^\\])*\2)*\s*\/?>/,lookbehind:!0,inside:Prism.languages.markup}}); |
|||
@ -0,0 +1,19 @@ |
|||
Prism.languages.ada = { |
|||
'comment': /--.*/, |
|||
'string': /"(?:""|[^"\r\f\n])*"/i, |
|||
'number': [ |
|||
{ |
|||
pattern: /\b\d(?:_?\d)*#[\dA-F](?:_?[\dA-F])*(?:\.[\dA-F](?:_?[\dA-F])*)?#(?:E[+-]?\d(?:_?\d)*)?/i |
|||
}, |
|||
{ |
|||
pattern: /\b\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:E[+-]?\d(?:_?\d)*)?\b/i |
|||
} |
|||
], |
|||
'attr-name': /\b'\w+/i, |
|||
'keyword': /\b(?:abort|abs|abstract|accept|access|aliased|all|and|array|at|begin|body|case|constant|declare|delay|delta|digits|do|else|new|return|elsif|end|entry|exception|exit|for|function|generic|goto|if|in|interface|is|limited|loop|mod|not|null|of|others|out|overriding|package|pragma|private|procedure|protected|raise|range|record|rem|renames|requeue|reverse|select|separate|some|subtype|synchronized|tagged|task|terminate|then|type|until|use|when|while|with|xor)\b/i, |
|||
'boolean': /\b(?:true|false)\b/i, |
|||
'operator': /<[=>]?|>=?|=>?|:=|\/=?|\*\*?|[&+-]/, |
|||
'punctuation': /\.\.?|[,;():]/, |
|||
'char': /'.'/, |
|||
'variable': /\b[a-z](?:[_a-z\d])*\b/i |
|||
}; |
|||
@ -0,0 +1 @@ |
|||
Prism.languages.ada={comment:/--.*/,string:/"(?:""|[^"\r\f\n])*"/i,number:[{pattern:/\b\d(?:_?\d)*#[\dA-F](?:_?[\dA-F])*(?:\.[\dA-F](?:_?[\dA-F])*)?#(?:E[+-]?\d(?:_?\d)*)?/i},{pattern:/\b\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:E[+-]?\d(?:_?\d)*)?\b/i}],"attr-name":/\b'\w+/i,keyword:/\b(?:abort|abs|abstract|accept|access|aliased|all|and|array|at|begin|body|case|constant|declare|delay|delta|digits|do|else|new|return|elsif|end|entry|exception|exit|for|function|generic|goto|if|in|interface|is|limited|loop|mod|not|null|of|others|out|overriding|package|pragma|private|procedure|protected|raise|range|record|rem|renames|requeue|reverse|select|separate|some|subtype|synchronized|tagged|task|terminate|then|type|until|use|when|while|with|xor)\b/i,boolean:/\b(?:true|false)\b/i,operator:/<[=>]?|>=?|=>?|:=|\/=?|\*\*?|[&+-]/,punctuation:/\.\.?|[,;():]/,char:/'.'/,variable:/\b[a-z](?:[_a-z\d])*\b/i}; |
|||
@ -0,0 +1,24 @@ |
|||
(function (Prism) { |
|||
|
|||
Prism.languages.agda = { |
|||
'comment': /\{-[\s\S]*?(?:-\}|$)|--.*/, |
|||
'string': { |
|||
pattern: /"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/, |
|||
greedy: true, |
|||
}, |
|||
'punctuation': /[(){}⦃⦄.;@]/, |
|||
'class-name': { |
|||
pattern: /((?:data|record) +)\S+/, |
|||
lookbehind: true, |
|||
}, |
|||
'function': { |
|||
pattern: /(^[ \t]*)[^:\r\n]+?(?=:)/m, |
|||
lookbehind: true, |
|||
}, |
|||
'operator': { |
|||
pattern: /(^\s*|\s)(?:[=|:∀→λ\\?_]|->)(?=\s)/, |
|||
lookbehind: true, |
|||
}, |
|||
'keyword': /\b(?:Set|abstract|constructor|data|eta-equality|field|forall|forall|hiding|import|in|inductive|infix|infixl|infixr|instance|let|macro|module|mutual|no-eta-equality|open|overlap|pattern|postulate|primitive|private|public|quote|quoteContext|quoteGoal|quoteTerm|record|renaming|rewrite|syntax|tactic|unquote|unquoteDecl|unquoteDef|using|variable|where|with)\b/, |
|||
}; |
|||
}(Prism)); |
|||
@ -0,0 +1 @@ |
|||
Prism.languages.agda={comment:/\{-[\s\S]*?(?:-\}|$)|--.*/,string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},punctuation:/[(){}⦃⦄.;@]/,"class-name":{pattern:/((?:data|record) +)\S+/,lookbehind:!0},function:{pattern:/(^[ \t]*)[^:\r\n]+?(?=:)/m,lookbehind:!0},operator:{pattern:/(^\s*|\s)(?:[=|:∀→λ\\?_]|->)(?=\s)/,lookbehind:!0},keyword:/\b(?:Set|abstract|constructor|data|eta-equality|field|forall|forall|hiding|import|in|inductive|infix|infixl|infixr|instance|let|macro|module|mutual|no-eta-equality|open|overlap|pattern|postulate|primitive|private|public|quote|quoteContext|quoteGoal|quoteTerm|record|renaming|rewrite|syntax|tactic|unquote|unquoteDecl|unquoteDef|using|variable|where|with)\b/}; |
|||
@ -0,0 +1,25 @@ |
|||
// based on https://github.com/microsoft/AL/blob/master/grammar/alsyntax.tmlanguage
|
|||
|
|||
Prism.languages.al = { |
|||
'comment': /\/\/.*|\/\*[\s\S]*?\*\//, |
|||
'string': { |
|||
pattern: /'(?:''|[^'\r\n])*'(?!')|"(?:""|[^"\r\n])*"(?!")/, |
|||
greedy: true |
|||
}, |
|||
'function': { |
|||
pattern: /(\b(?:event|procedure|trigger)\s+|(?:^|[^.])\.\s*)[a-z_]\w*(?=\s*\()/i, |
|||
lookbehind: true |
|||
}, |
|||
'keyword': [ |
|||
// keywords
|
|||
/\b(?:array|asserterror|begin|break|case|do|downto|else|end|event|exit|for|foreach|function|if|implements|in|indataset|interface|internal|local|of|procedure|program|protected|repeat|runonclient|securityfiltering|suppressdispose|temporary|then|to|trigger|until|var|while|with|withevents)\b/i, |
|||
// objects and metadata that are used like keywords
|
|||
/\b(?:action|actions|addafter|addbefore|addfirst|addlast|area|assembly|chartpart|codeunit|column|controladdin|cuegroup|customizes|dataitem|dataset|dotnet|elements|enum|enumextension|extends|field|fieldattribute|fieldelement|fieldgroup|fieldgroups|fields|filter|fixed|grid|group|key|keys|label|labels|layout|modify|moveafter|movebefore|movefirst|movelast|page|pagecustomization|pageextension|part|profile|query|repeater|report|requestpage|schema|separator|systempart|table|tableelement|tableextension|textattribute|textelement|type|usercontrol|value|xmlport)\b/i |
|||
], |
|||
'number': /\b(?:0x[\da-f]+|(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)(?:F|U(?:LL?)?|LL?)?\b/i, |
|||
'boolean': /\b(?:false|true)\b/i, |
|||
'variable': /\b(?:Curr(?:FieldNo|Page|Report)|RequestOptionsPage|x?Rec)\b/, |
|||
'class-name': /\b(?:automation|biginteger|bigtext|blob|boolean|byte|char|clienttype|code|completiontriggererrorlevel|connectiontype|database|dataclassification|datascope|date|dateformula|datetime|decimal|defaultlayout|dialog|dictionary|dotnetassembly|dotnettypedeclaration|duration|errorinfo|errortype|executioncontext|executionmode|fieldclass|fieldref|fieldtype|file|filterpagebuilder|guid|httpclient|httpcontent|httpheaders|httprequestmessage|httpresponsemessage|instream|integer|joker|jsonarray|jsonobject|jsontoken|jsonvalue|keyref|list|moduledependencyinfo|moduleinfo|none|notification|notificationscope|objecttype|option|outstream|pageresult|record|recordid|recordref|reportformat|securityfilter|sessionsettings|tableconnectiontype|tablefilter|testaction|testfield|testfilterfield|testpage|testpermissions|testrequestpage|text|textbuilder|textconst|textencoding|time|transactionmodel|transactiontype|variant|verbosity|version|view|views|webserviceactioncontext|webserviceactionresultcode|xmlattribute|xmlattributecollection|xmlcdata|xmlcomment|xmldeclaration|xmldocument|xmldocumenttype|xmlelement|xmlnamespacemanager|xmlnametable|xmlnode|xmlnodelist|xmlprocessinginstruction|xmlreadoptions|xmltext|xmlwriteoptions)\b/i, |
|||
'operator': /\.\.|:[=:]|[-+*/]=?|<>|[<>]=?|=|\b(?:and|div|mod|not|or|xor)\b/i, |
|||
'punctuation': /[()\[\]{}:.;,]/ |
|||
}; |
|||
@ -0,0 +1 @@ |
|||
Prism.languages.al={comment:/\/\/.*|\/\*[\s\S]*?\*\//,string:{pattern:/'(?:''|[^'\r\n])*'(?!')|"(?:""|[^"\r\n])*"(?!")/,greedy:!0},function:{pattern:/(\b(?:event|procedure|trigger)\s+|(?:^|[^.])\.\s*)[a-z_]\w*(?=\s*\()/i,lookbehind:!0},keyword:[/\b(?:array|asserterror|begin|break|case|do|downto|else|end|event|exit|for|foreach|function|if|implements|in|indataset|interface|internal|local|of|procedure|program|protected|repeat|runonclient|securityfiltering|suppressdispose|temporary|then|to|trigger|until|var|while|with|withevents)\b/i,/\b(?:action|actions|addafter|addbefore|addfirst|addlast|area|assembly|chartpart|codeunit|column|controladdin|cuegroup|customizes|dataitem|dataset|dotnet|elements|enum|enumextension|extends|field|fieldattribute|fieldelement|fieldgroup|fieldgroups|fields|filter|fixed|grid|group|key|keys|label|labels|layout|modify|moveafter|movebefore|movefirst|movelast|page|pagecustomization|pageextension|part|profile|query|repeater|report|requestpage|schema|separator|systempart|table|tableelement|tableextension|textattribute|textelement|type|usercontrol|value|xmlport)\b/i],number:/\b(?:0x[\da-f]+|(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)(?:F|U(?:LL?)?|LL?)?\b/i,boolean:/\b(?:false|true)\b/i,variable:/\b(?:Curr(?:FieldNo|Page|Report)|RequestOptionsPage|x?Rec)\b/,"class-name":/\b(?:automation|biginteger|bigtext|blob|boolean|byte|char|clienttype|code|completiontriggererrorlevel|connectiontype|database|dataclassification|datascope|date|dateformula|datetime|decimal|defaultlayout|dialog|dictionary|dotnetassembly|dotnettypedeclaration|duration|errorinfo|errortype|executioncontext|executionmode|fieldclass|fieldref|fieldtype|file|filterpagebuilder|guid|httpclient|httpcontent|httpheaders|httprequestmessage|httpresponsemessage|instream|integer|joker|jsonarray|jsonobject|jsontoken|jsonvalue|keyref|list|moduledependencyinfo|moduleinfo|none|notification|notificationscope|objecttype|option|outstream|pageresult|record|recordid|recordref|reportformat|securityfilter|sessionsettings|tableconnectiontype|tablefilter|testaction|testfield|testfilterfield|testpage|testpermissions|testrequestpage|text|textbuilder|textconst|textencoding|time|transactionmodel|transactiontype|variant|verbosity|version|view|views|webserviceactioncontext|webserviceactionresultcode|xmlattribute|xmlattributecollection|xmlcdata|xmlcomment|xmldeclaration|xmldocument|xmldocumenttype|xmlelement|xmlnamespacemanager|xmlnametable|xmlnode|xmlnodelist|xmlprocessinginstruction|xmlreadoptions|xmltext|xmlwriteoptions)\b/i,operator:/\.\.|:[=:]|[-+*/]=?|<>|[<>]=?|=|\b(?:and|div|mod|not|or|xor)\b/i,punctuation:/[()\[\]{}:.;,]/}; |
|||
@ -0,0 +1,65 @@ |
|||
Prism.languages.antlr4 = { |
|||
'comment': /\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/, |
|||
'string': { |
|||
pattern: /'(?:\\.|[^\\'\r\n])*'/, |
|||
greedy: true |
|||
}, |
|||
'character-class': { |
|||
pattern: /\[(?:\\.|[^\\\]\r\n])*\]/, |
|||
greedy: true, |
|||
alias: 'regex', |
|||
inside: { |
|||
'range': { |
|||
pattern: /([^[]|(?:^|[^\\])(?:\\\\)*\\\[)-(?!\])/, |
|||
lookbehind: true, |
|||
alias: 'punctuation' |
|||
}, |
|||
'escape': /\\(?:u(?:[a-fA-F\d]{4}|\{[a-fA-F\d]+\})|[pP]\{[=\w-]+\}|[^\r\nupP])/, |
|||
'punctuation': /[\[\]]/ |
|||
} |
|||
}, |
|||
'action': { |
|||
pattern: /\{(?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})*\}/, |
|||
greedy: true, |
|||
inside: { |
|||
'content': { |
|||
// this might be C, C++, Python, Java, C#, or any other language ANTLR4 compiles to
|
|||
pattern: /(\{)[\s\S]+(?=\})/, |
|||
lookbehind: true |
|||
}, |
|||
'punctuation': /[{}]/ |
|||
} |
|||
}, |
|||
'command': { |
|||
pattern: /(->\s*)(?:\s*(?:,\s*)?\b[a-z]\w*(?:\s*\([^()\r\n]*\))?)+(?=\s*;)/i, |
|||
lookbehind: true, |
|||
inside: { |
|||
'function': /\b\w+(?=\s*(?:[,(]|$))/, |
|||
'punctuation': /[,()]/ |
|||
} |
|||
}, |
|||
'annotation': { |
|||
pattern: /@\w+(?:::\w+)*/, |
|||
alias: 'keyword' |
|||
}, |
|||
'label': { |
|||
pattern: /#[ \t]*\w+/, |
|||
alias: 'punctuation' |
|||
}, |
|||
'keyword': /\b(?:catch|channels|finally|fragment|grammar|import|lexer|locals|mode|options|parser|returns|throws|tokens)\b/, |
|||
'definition': [ |
|||
{ |
|||
pattern: /\b[a-z]\w*(?=\s*:)/, |
|||
alias: ['rule', 'class-name'] |
|||
}, |
|||
{ |
|||
pattern: /\b[A-Z]\w*(?=\s*:)/, |
|||
alias: ['token', 'constant'] |
|||
}, |
|||
], |
|||
'constant': /\b[A-Z][A-Z_]*\b/, |
|||
'operator': /\.\.|->|[|~]|[*+?]\??/, |
|||
'punctuation': /[;:()=]/ |
|||
}; |
|||
|
|||
Prism.languages.g4 = Prism.languages.antlr4; |
|||
@ -0,0 +1 @@ |
|||
Prism.languages.antlr4={comment:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,string:{pattern:/'(?:\\.|[^\\'\r\n])*'/,greedy:!0},"character-class":{pattern:/\[(?:\\.|[^\\\]\r\n])*\]/,greedy:!0,alias:"regex",inside:{range:{pattern:/([^[]|(?:^|[^\\])(?:\\\\)*\\\[)-(?!\])/,lookbehind:!0,alias:"punctuation"},escape:/\\(?:u(?:[a-fA-F\d]{4}|\{[a-fA-F\d]+\})|[pP]\{[=\w-]+\}|[^\r\nupP])/,punctuation:/[\[\]]/}},action:{pattern:/\{(?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})*\}/,greedy:!0,inside:{content:{pattern:/(\{)[\s\S]+(?=\})/,lookbehind:!0},punctuation:/[{}]/}},command:{pattern:/(->\s*)(?:\s*(?:,\s*)?\b[a-z]\w*(?:\s*\([^()\r\n]*\))?)+(?=\s*;)/i,lookbehind:!0,inside:{function:/\b\w+(?=\s*(?:[,(]|$))/,punctuation:/[,()]/}},annotation:{pattern:/@\w+(?:::\w+)*/,alias:"keyword"},label:{pattern:/#[ \t]*\w+/,alias:"punctuation"},keyword:/\b(?:catch|channels|finally|fragment|grammar|import|lexer|locals|mode|options|parser|returns|throws|tokens)\b/,definition:[{pattern:/\b[a-z]\w*(?=\s*:)/,alias:["rule","class-name"]},{pattern:/\b[A-Z]\w*(?=\s*:)/,alias:["token","constant"]}],constant:/\b[A-Z][A-Z_]*\b/,operator:/\.\.|->|[|~]|[*+?]\??/,punctuation:/[;:()=]/},Prism.languages.g4=Prism.languages.antlr4; |
|||
@ -0,0 +1,32 @@ |
|||
Prism.languages.apl = { |
|||
'comment': /(?:⍝|#[! ]).*$/m, |
|||
'string': { |
|||
pattern: /'(?:[^'\r\n]|'')*'/, |
|||
greedy: true |
|||
}, |
|||
'number': /¯?(?:\d*\.?\b\d+(?:e[+¯]?\d+)?|¯|∞)(?:j¯?(?:\d*\.?\d+(?:e[+¯]?\d+)?|¯|∞))?/i, |
|||
'statement': /:[A-Z][a-z][A-Za-z]*\b/, |
|||
'system-function': { |
|||
pattern: /⎕[A-Z]+/i, |
|||
alias: 'function' |
|||
}, |
|||
'constant': /[⍬⌾#⎕⍞]/, |
|||
'function': /[-+×÷⌈⌊∣|⍳⍸?*⍟○!⌹<≤=>≥≠≡≢∊⍷∪∩~∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⊆⊇⌷⍋⍒⊤⊥⍕⍎⊣⊢⍁⍂≈⍯↗¤→]/, |
|||
'monadic-operator': { |
|||
pattern: /[\\\/⌿⍀¨⍨⌶&∥]/, |
|||
alias: 'operator' |
|||
}, |
|||
'dyadic-operator': { |
|||
pattern: /[.⍣⍠⍤∘⌸@⌺⍥]/, |
|||
alias: 'operator' |
|||
}, |
|||
'assignment': { |
|||
pattern: /←/, |
|||
alias: 'keyword' |
|||
}, |
|||
'punctuation': /[\[;\]()◇⋄]/, |
|||
'dfn': { |
|||
pattern: /[{}⍺⍵⍶⍹∇⍫:]/, |
|||
alias: 'builtin' |
|||
} |
|||
}; |
|||
@ -0,0 +1 @@ |
|||
Prism.languages.apl={comment:/(?:⍝|#[! ]).*$/m,string:{pattern:/'(?:[^'\r\n]|'')*'/,greedy:!0},number:/¯?(?:\d*\.?\b\d+(?:e[+¯]?\d+)?|¯|∞)(?:j¯?(?:\d*\.?\d+(?:e[+¯]?\d+)?|¯|∞))?/i,statement:/:[A-Z][a-z][A-Za-z]*\b/,"system-function":{pattern:/⎕[A-Z]+/i,alias:"function"},constant:/[⍬⌾#⎕⍞]/,function:/[-+×÷⌈⌊∣|⍳⍸?*⍟○!⌹<≤=>≥≠≡≢∊⍷∪∩~∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⊆⊇⌷⍋⍒⊤⊥⍕⍎⊣⊢⍁⍂≈⍯↗¤→]/,"monadic-operator":{pattern:/[\\\/⌿⍀¨⍨⌶&∥]/,alias:"operator"},"dyadic-operator":{pattern:/[.⍣⍠⍤∘⌸@⌺⍥]/,alias:"operator"},assignment:{pattern:/←/,alias:"keyword"},punctuation:/[\[;\]()◇⋄]/,dfn:{pattern:/[{}⍺⍵⍶⍹∇⍫:]/,alias:"builtin"}}; |
|||
@ -0,0 +1,20 @@ |
|||
Prism.languages.applescript = { |
|||
'comment': [ |
|||
// Allow one level of nesting
|
|||
/\(\*(?:\(\*(?:[^*]|\*(?!\)))*\*\)|(?!\(\*)[\s\S])*?\*\)/, |
|||
/--.+/, |
|||
/#.+/ |
|||
], |
|||
'string': /"(?:\\.|[^"\\\r\n])*"/, |
|||
'number': /(?:\b\d+\.?\d*|\B\.\d+)(?:e-?\d+)?\b/i, |
|||
'operator': [ |
|||
/[&=≠≤≥*+\-\/÷^]|[<>]=?/, |
|||
/\b(?:(?:start|begin|end)s? with|(?:(?:does not|doesn't) contain|contains?)|(?:is|isn't|is not) (?:in|contained by)|(?:(?:is|isn't|is not) )?(?:greater|less) than(?: or equal)?(?: to)?|(?:(?:does not|doesn't) come|comes) (?:before|after)|(?:is|isn't|is not) equal(?: to)?|(?:(?:does not|doesn't) equal|equals|equal to|isn't|is not)|(?:a )?(?:ref(?: to)?|reference to)|(?:and|or|div|mod|as|not))\b/ |
|||
], |
|||
'keyword': /\b(?:about|above|after|against|apart from|around|aside from|at|back|before|beginning|behind|below|beneath|beside|between|but|by|considering|continue|copy|does|eighth|else|end|equal|error|every|exit|false|fifth|first|for|fourth|from|front|get|given|global|if|ignoring|in|instead of|into|is|it|its|last|local|me|middle|my|ninth|of|on|onto|out of|over|prop|property|put|repeat|return|returning|second|set|seventh|since|sixth|some|tell|tenth|that|the|then|third|through|thru|timeout|times|to|transaction|true|try|until|where|while|whose|with|without)\b/, |
|||
'class': { |
|||
pattern: /\b(?:alias|application|boolean|class|constant|date|file|integer|list|number|POSIX file|real|record|reference|RGB color|script|text|centimetres|centimeters|feet|inches|kilometres|kilometers|metres|meters|miles|yards|square feet|square kilometres|square kilometers|square metres|square meters|square miles|square yards|cubic centimetres|cubic centimeters|cubic feet|cubic inches|cubic metres|cubic meters|cubic yards|gallons|litres|liters|quarts|grams|kilograms|ounces|pounds|degrees Celsius|degrees Fahrenheit|degrees Kelvin)\b/, |
|||
alias: 'builtin' |
|||
}, |
|||
'punctuation': /[{}():,¬«»《》]/ |
|||
}; |
|||
@ -0,0 +1 @@ |
|||
Prism.languages.applescript={comment:[/\(\*(?:\(\*(?:[^*]|\*(?!\)))*\*\)|(?!\(\*)[\s\S])*?\*\)/,/--.+/,/#.+/],string:/"(?:\\.|[^"\\\r\n])*"/,number:/(?:\b\d+\.?\d*|\B\.\d+)(?:e-?\d+)?\b/i,operator:[/[&=≠≤≥*+\-\/÷^]|[<>]=?/,/\b(?:(?:start|begin|end)s? with|(?:(?:does not|doesn't) contain|contains?)|(?:is|isn't|is not) (?:in|contained by)|(?:(?:is|isn't|is not) )?(?:greater|less) than(?: or equal)?(?: to)?|(?:(?:does not|doesn't) come|comes) (?:before|after)|(?:is|isn't|is not) equal(?: to)?|(?:(?:does not|doesn't) equal|equals|equal to|isn't|is not)|(?:a )?(?:ref(?: to)?|reference to)|(?:and|or|div|mod|as|not))\b/],keyword:/\b(?:about|above|after|against|apart from|around|aside from|at|back|before|beginning|behind|below|beneath|beside|between|but|by|considering|continue|copy|does|eighth|else|end|equal|error|every|exit|false|fifth|first|for|fourth|from|front|get|given|global|if|ignoring|in|instead of|into|is|it|its|last|local|me|middle|my|ninth|of|on|onto|out of|over|prop|property|put|repeat|return|returning|second|set|seventh|since|sixth|some|tell|tenth|that|the|then|third|through|thru|timeout|times|to|transaction|true|try|until|where|while|whose|with|without)\b/,class:{pattern:/\b(?:alias|application|boolean|class|constant|date|file|integer|list|number|POSIX file|real|record|reference|RGB color|script|text|centimetres|centimeters|feet|inches|kilometres|kilometers|metres|meters|miles|yards|square feet|square kilometres|square kilometers|square metres|square meters|square miles|square yards|cubic centimetres|cubic centimeters|cubic feet|cubic inches|cubic metres|cubic meters|cubic yards|gallons|litres|liters|quarts|grams|kilograms|ounces|pounds|degrees Celsius|degrees Fahrenheit|degrees Kelvin)\b/,alias:"builtin"},punctuation:/[{}():,¬«»《》]/}; |
|||