Compare commits
15 Commits
a6ddc72df3
...
1bf1c37296
| Author | SHA1 | Date | |
|---|---|---|---|
| 1bf1c37296 | |||
| ea6f3e61be | |||
| 0c446bba56 | |||
| e74c777687 | |||
| d678111f25 | |||
| 469e335fc3 | |||
| 8d9dbbea19 | |||
| d1088798e5 | |||
| b4353cd9ff | |||
| 0ea7386cb6 | |||
| 161ec6491d | |||
| 6d254281f8 | |||
| 5dc32a02a9 | |||
| ba468c3f99 | |||
| bca0b09cf4 |
@@ -62,25 +62,16 @@ public class DocumentController(IMediator mediator, IAuthorizationService authSe
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Gets the document for the specified envelope key.
|
||||
/// </summary>
|
||||
/// <param name="envelopeKey"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
[Authorize(Policy = AuthPolicy.Receiver)]
|
||||
[HttpGet("{envelopeKey}")]
|
||||
public async Task<IActionResult> GetDocumentOfReceiver(string envelopeKey, CancellationToken cancel)
|
||||
{
|
||||
var envelopeIdStr = User.FindFirst(EnvelopeClaimNames.EnvelopeId)?.Value;
|
||||
|
||||
if (!int.TryParse(envelopeIdStr, out int envelopeId))
|
||||
{
|
||||
logger.LogError(
|
||||
"Inner service error: Failed to parse Envelope ID from claims. Claim '{ClaimName}' had an invalid or missing value: '{ClaimValue}'.",
|
||||
EnvelopeClaimNames.EnvelopeId,
|
||||
envelopeIdStr ?? "null");
|
||||
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "Inner service error: Invalid envelope claim.");
|
||||
}
|
||||
int envelopeId = User.GetEnvelopeIdOfReceiver();
|
||||
|
||||
var senderDoc = await mediator.Send(new ReadDocumentQuery() { EnvelopeId = envelopeId }, cancel);
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
<Authors>Digital Data GmbH</Authors>
|
||||
<Company>Digital Data GmbH</Company>
|
||||
<Product>EnvelopeGenerator.GeneratorAPI</Product>
|
||||
<Version>1.3.0</Version>
|
||||
<FileVersion>1.3.0</FileVersion>
|
||||
<AssemblyVersion>1.3.0</AssemblyVersion>
|
||||
<Version>1.3.1</Version>
|
||||
<FileVersion>1.3.1</FileVersion>
|
||||
<AssemblyVersion>1.3.1</AssemblyVersion>
|
||||
<PackageOutputPath>Copyright © 2025 Digital Data GmbH. All rights reserved.</PackageOutputPath>
|
||||
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -11,6 +11,10 @@ namespace EnvelopeGenerator.API.Extensions;
|
||||
/// </summary>
|
||||
public static class ReceiverClaimExtensions
|
||||
{
|
||||
private static readonly string[] EnvelopeIdClaimTypes = [EnvelopeClaimTypes.Id, "envelope_id", "EnvelopeId"];
|
||||
private static readonly string[] EnvelopeUuidClaimTypes = [ClaimTypes.NameIdentifier, "envelope_uuid", "EnvelopeUuid"];
|
||||
private static readonly string[] ReceiverSignatureClaimTypes = [ClaimTypes.Hash, "receiver_sig", "ReceiverSignature"];
|
||||
|
||||
private static string GetRequiredClaimOfReceiver(this ClaimsPrincipal user, string claimType)
|
||||
{
|
||||
var value = user.FindFirstValue(claimType);
|
||||
@@ -27,15 +31,32 @@ public static class ReceiverClaimExtensions
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
private static string GetRequiredClaimOfReceiver(this ClaimsPrincipal user, params string[] claimTypes)
|
||||
{
|
||||
foreach (var claimType in claimTypes.Where(t => !string.IsNullOrWhiteSpace(t)).Distinct())
|
||||
{
|
||||
var value = user.FindFirstValue(claimType);
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
return value;
|
||||
}
|
||||
|
||||
var identity = user.Identity;
|
||||
var principalName = identity?.Name ?? "(anonymous)";
|
||||
var authType = identity?.AuthenticationType ?? "(none)";
|
||||
var availableClaims = string.Join(", ", user.Claims.Select(c => $"{c.Type}={c.Value}"));
|
||||
var message = $"Required claim(s) '{string.Join("', '", claimTypes)}' are missing for user '{principalName}' (auth: {authType}). Available claims: [{availableClaims}].";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authenticated envelope UUID from the claims.
|
||||
/// </summary>
|
||||
public static string GetEnvelopeUuidOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.NameIdentifier);
|
||||
public static string GetEnvelopeUuidOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(EnvelopeUuidClaimTypes);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authenticated receiver signature from the claims.
|
||||
/// </summary>
|
||||
public static string GetReceiverSignatureOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.Hash);
|
||||
public static string GetReceiverSignatureOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ReceiverSignatureClaimTypes);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authenticated receiver display name from the claims.
|
||||
@@ -57,7 +78,7 @@ public static class ReceiverClaimExtensions
|
||||
/// </summary>
|
||||
public static int GetEnvelopeIdOfReceiver(this ClaimsPrincipal user)
|
||||
{
|
||||
var envIdStr = user.GetRequiredClaimOfReceiver(EnvelopeClaimTypes.Id);
|
||||
var envIdStr = user.GetRequiredClaimOfReceiver(EnvelopeIdClaimTypes);
|
||||
if (!int.TryParse(envIdStr, out var envId))
|
||||
{
|
||||
throw new InvalidOperationException($"Claim '{EnvelopeClaimTypes.Id}' is not a valid integer.");
|
||||
|
||||
@@ -329,15 +329,7 @@ try
|
||||
app.MapControllers();
|
||||
|
||||
// Catch-all YARP proxy — only forward requests that are not swagger/scalar/openapi paths.
|
||||
app.MapWhen(
|
||||
ctx =>
|
||||
{
|
||||
var path = ctx.Request.Path.Value ?? string.Empty;
|
||||
return !path.StartsWith("/swagger", StringComparison.OrdinalIgnoreCase) &&
|
||||
!path.StartsWith("/scalar", StringComparison.OrdinalIgnoreCase) &&
|
||||
!path.StartsWith("/openapi", StringComparison.OrdinalIgnoreCase);
|
||||
},
|
||||
branch => branch.UseRouting().UseEndpoints(e => e.MapReverseProxy()));
|
||||
app.MapReverseProxy();
|
||||
|
||||
app.Run();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<WebPublishMethod>Package</WebPublishMethod>
|
||||
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
||||
<SiteUrlToLaunchAfterPublish />
|
||||
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||
<ProjectGuid>5e0e17c0-ff5a-4246-bf87-1add85376a27</ProjectGuid>
|
||||
<DesktopBuildPackageLocation>M:\App&Service\0 DD - Smart UP\signFLOW\API\net8\$(Version)\EnvelopeGenerator.API.zip</DesktopBuildPackageLocation>
|
||||
<PackageAsSingleFile>true</PackageAsSingleFile>
|
||||
<DeployIisAppPath>EnvelopeGenerator</DeployIisAppPath>
|
||||
<_TargetId>IISWebDeployPackage</_TargetId>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,10 +1,21 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"ReverseProxy": {
|
||||
"Clusters": {
|
||||
"receiver-ui": {
|
||||
"Destinations": {
|
||||
"primary": {
|
||||
"Address": "https://localhost:52936"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"AuthClientParams": {
|
||||
"Url": "http://172.24.12.39:9090/auth-hub",
|
||||
"PublicKeys": [
|
||||
|
||||
@@ -29,9 +29,12 @@
|
||||
"ClusterId": "receiver-ui",
|
||||
"Order": 100,
|
||||
"Match": {
|
||||
"Path": "/envelope/{**catch-all}",
|
||||
"Path": "/envelope/{EnvelopeKey}",
|
||||
"Methods": [ "GET", "HEAD" ]
|
||||
}
|
||||
},
|
||||
"Transforms": [
|
||||
{ "PathSet": "/index.html" }
|
||||
]
|
||||
},
|
||||
"receiver-ui-static-assets": {
|
||||
"ClusterId": "receiver-ui",
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
<PackageIcon>Assets\icon.ico</PackageIcon>
|
||||
<PackageTags>digital data envelope generator web</PackageTags>
|
||||
<Description>EnvelopeGenerator.ReceiverUI is a Blazor WebAssembly application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly.</Description>
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<!-- NuGet package version -->
|
||||
<AssemblyVersion>1.2.0.0</AssemblyVersion>
|
||||
<AssemblyVersion>1.3.0.0</AssemblyVersion>
|
||||
<!-- Assembly version for API compatibility -->
|
||||
<FileVersion>1.2.0.0</FileVersion>
|
||||
<FileVersion>1.3.0.0</FileVersion>
|
||||
<!-- Windows file version -->
|
||||
<Copyright>Copyright © 2026 Digital Data GmbH. All rights reserved.</Copyright>
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<PackageReference Include="DevExpress.Blazor.Reporting.Viewer" Version="25.2.3" />
|
||||
<PackageReference Include="DevExpress.Drawing.Skia" Version="25.2.3" />
|
||||
<PackageReference Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="8.3.1.2" />
|
||||
<PackageReference Include="itext" Version="8.0.5" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.WebAssembly" Version="3.119.1" />
|
||||
<PackageReference Include="SkiaSharp.Views.Blazor" Version="3.119.1" />
|
||||
<NativeFileReference Include="$(HarfBuzzSharpStaticLibraryPath)\2.0.23\*.a" />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@page "/"
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<link href="_content/DevExpress.Blazor.Themes/blazing-berry.bs5.min.css" rel="stylesheet" />
|
||||
|
||||
@@ -18,12 +19,10 @@
|
||||
|
||||
<div class="home-content">
|
||||
<div class="home-card card shadow border-0">
|
||||
<div class="card-body p-4 p-md-5 text-center">
|
||||
<div class="card-body p-4 p-md-5">
|
||||
|
||||
<p class="text-muted mb-4" style="font-size: 0.92rem; line-height: 1.7;">
|
||||
Das digitale Unterschriftenportal ist eine Plattform, die entwickelt wurde, um Ihre Dokumente sicher zu unterschreiben und zu verwalten.
|
||||
Mit seiner benutzerfreundlichen Oberfläche können Sie Ihre Dokumente schnell hochladen, die Unterschriftsprozesse verfolgen und Ihre digitalen Unterschriftenanwendungen einfach durchführen.
|
||||
Dieses Portal beschleunigt Ihren Arbeitsablauf mit rechtlich gültigen Unterschriften und erhöht gleichzeitig die Sicherheit Ihrer Dokumente.
|
||||
<p class="text-muted mb-4" style="font-size: 0.92rem; line-height: 1.7; text-align: justify; text-align-last: left; min-height: calc(0.92rem * 1.7 * 9);">
|
||||
<span id="home-description"></span>
|
||||
</p>
|
||||
|
||||
<div class="mt-4 pt-3 border-top">
|
||||
@@ -57,4 +56,16 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private const string HomePageDescription =
|
||||
"Das digitale Unterschriftenportal ist eine Plattform, die entwickelt wurde, um Ihre Dokumente sicher zu unterschreiben und zu verwalten. " +
|
||||
"Mit seiner benutzerfreundlichen Oberfläche können Sie Ihre Dokumente schnell hochladen, die Unterschriftsprozesse verfolgen und Ihre digitalen Unterschriftenanwendungen einfach durchführen. " +
|
||||
"Dieses Portal beschleunigt Ihren Arbeitsablauf mit rechtlich gültigen Unterschriften und erhöht gleichzeitig die Sicherheit Ihrer Dokumente.";
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await JS.InvokeVoidAsync("receiverSignature.startTyped", "home-description", HomePageDescription, 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,66 +654,71 @@ Shown="OnPopupShownAsync">
|
||||
var imageBytes = Convert.FromBase64String(signatureDataUrl[(signatureDataUrl.IndexOf(',') + 1)..]);
|
||||
using var imageStream = new MemoryStream(imageBytes);
|
||||
var imageSource = new ImageSource(DXImage.FromStream(imageStream));
|
||||
var bottomMargin = report.Bands.OfType<BottomMarginBand>().FirstOrDefault();
|
||||
|
||||
if (bottomMargin is null) {
|
||||
bottomMargin = new BottomMarginBand();
|
||||
report.Bands.Add(bottomMargin);
|
||||
}
|
||||
var detail = report.Bands.OfType<DevExpress.XtraReports.UI.DetailBand>().FirstOrDefault();
|
||||
if (detail is null) return;
|
||||
|
||||
var annotId = annotation?.Id.ToString() ?? "0";
|
||||
RemoveExistingSignatureById(bottomMargin, annotId);
|
||||
RemoveExistingSignatureById(detail, annotId);
|
||||
|
||||
const float sigWidth = 230F;
|
||||
const float sigImgHeight = 70F;
|
||||
const float infoHeight = 48.75F;
|
||||
const float innerGap = 5F;
|
||||
const float bottomPad = 6F;
|
||||
const float defaultTopPad = 8F;
|
||||
const float maxBandHeight = 210F;
|
||||
const float sigWidth = 230F;
|
||||
const float sigImgHeight = 70F;
|
||||
const float infoHeight = 48.75F;
|
||||
const float innerGap = 5F;
|
||||
|
||||
float sigX = (float)(annotation?.X ?? 390.0);
|
||||
float requiredHeight = defaultTopPad + sigImgHeight + innerGap + infoHeight + bottomPad;
|
||||
bottomMargin.HeightF = Math.Min(maxBandHeight, Math.Max(bottomMargin.HeightF, requiredHeight));
|
||||
float topPad = Math.Max(0F, bottomMargin.HeightF - bottomPad - infoHeight - innerGap - sigImgHeight);
|
||||
float imageY = topPad;
|
||||
float sigX = (float)(annotation?.X ?? 390.0);
|
||||
float imageY = (float)(annotation?.Y ?? 900.0);
|
||||
float labelY = imageY + sigImgHeight + innerGap;
|
||||
int targetPage = annotation?.Page ?? 1;
|
||||
|
||||
var signatureInformation = string.IsNullOrWhiteSpace(signerPosition)
|
||||
? $"{signerFullName}\n{signaturePlace}, {DateTime.Now:d}"
|
||||
: $"{signerFullName}\n{signerPosition}\n{signaturePlace}, {DateTime.Now:d}";
|
||||
|
||||
var signature = new XRPictureBox {
|
||||
Name = $"receiverSignatureImage_{annotId}",
|
||||
Name = $"receiverSignatureImage_{annotId}",
|
||||
ImageSource = imageSource,
|
||||
BoundsF = new RectangleF(sigX, imageY, sigWidth, sigImgHeight),
|
||||
Sizing = ImageSizeMode.ZoomImage,
|
||||
Borders = BorderSide.Bottom,
|
||||
BoundsF = new RectangleF(sigX, imageY, sigWidth, sigImgHeight),
|
||||
Sizing = ImageSizeMode.ZoomImage,
|
||||
Borders = BorderSide.Bottom,
|
||||
BorderColor = System.Drawing.Color.FromArgb(73, 80, 87),
|
||||
BackColor = Color.FromArgb(219, 219, 219),
|
||||
BackColor = Color.FromArgb(219, 219, 219)
|
||||
};
|
||||
|
||||
var signatureLabel = new XRLabel {
|
||||
Name = $"receiverSignatureLabel_{annotId}",
|
||||
Text = signatureInformation,
|
||||
Multiline = true,
|
||||
BoundsF = new RectangleF(sigX, labelY - 5, sigWidth, infoHeight),
|
||||
Font = new DXFont("Open Sans", 8F, DXFontStyle.Regular),
|
||||
ForeColor = System.Drawing.Color.FromArgb(73, 80, 87),
|
||||
Name = $"receiverSignatureLabel_{annotId}",
|
||||
Text = signatureInformation,
|
||||
Multiline = true,
|
||||
BoundsF = new RectangleF(sigX, labelY - 5, sigWidth, infoHeight),
|
||||
Font = new DXFont("Open Sans", 8F, DXFontStyle.Regular),
|
||||
ForeColor = System.Drawing.Color.FromArgb(73, 80, 87),
|
||||
TextAlignment = TextAlignment.TopCenter,
|
||||
BackColor = Color.FromArgb(219, 219, 219)
|
||||
};
|
||||
|
||||
bottomMargin.Controls.AddRange(new XRControl[] { signature, signatureLabel });
|
||||
// Show each control only on the target page using an independent print counter
|
||||
int sigPrintCount = 0;
|
||||
signature.BeforePrint += (_, e) => {
|
||||
sigPrintCount++;
|
||||
e.Cancel = sigPrintCount != targetPage;
|
||||
};
|
||||
|
||||
int lblPrintCount = 0;
|
||||
signatureLabel.BeforePrint += (_, e) => {
|
||||
lblPrintCount++;
|
||||
e.Cancel = lblPrintCount != targetPage;
|
||||
};
|
||||
|
||||
detail.Controls.AddRange(new XRControl[] { signature, signatureLabel });
|
||||
}
|
||||
|
||||
static void RemoveExistingSignatureById(BottomMarginBand bottomMargin, string annotId) {
|
||||
var controls = bottomMargin.Controls
|
||||
static void RemoveExistingSignatureById(DevExpress.XtraReports.UI.DetailBand detail, string annotId) {
|
||||
var controls = detail.Controls
|
||||
.Cast<XRControl>()
|
||||
.Where(c => c.Name == $"receiverSignatureImage_{annotId}" || c.Name == $"receiverSignatureLabel_{annotId}")
|
||||
.ToArray();
|
||||
foreach (var c in controls)
|
||||
bottomMargin.Controls.Remove(c);
|
||||
detail.Controls.Remove(c);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
|
||||
41
EnvelopeGenerator.ReceiverUI/wwwroot/css/privacy-policy.css
Normal file
41
EnvelopeGenerator.ReceiverUI/wwwroot/css/privacy-policy.css
Normal file
@@ -0,0 +1,41 @@
|
||||
body {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 1.25rem;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
margin: 0rem 10rem 3rem 10rem;
|
||||
box-shadow: 0 .25rem .5rem rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #0056b3;
|
||||
}
|
||||
|
||||
section {
|
||||
background-color: white;
|
||||
padding: 1.25rem;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 .25rem .5rem rgba(0, 0, 0, 0.1);
|
||||
margin: 0rem 10rem 3rem 10rem
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc inside;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0056b3;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
1
EnvelopeGenerator.ReceiverUI/wwwroot/css/privacy-policy.min.css
vendored
Normal file
1
EnvelopeGenerator.ReceiverUI/wwwroot/css/privacy-policy.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
body{font-family:system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.6;margin:1.25rem;background-color:#f4f4f4}header{text-align:center;margin:0 10rem 3rem 10rem;box-shadow:0 .25rem .5rem rgba(0,0,0,.1)}h1{color:#333}h2{color:#0056b3}section{background-color:#fff;padding:1.25rem;border-radius:.5rem;box-shadow:0 .25rem .5rem rgba(0,0,0,.1);margin:0 10rem 3rem 10rem}ul{list-style:disc inside}a{color:#0056b3;text-decoration:none}a:hover{text-decoration:underline}
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Datenschutzinformation für das Fernsignatursystem: signFLOW</title>
|
||||
<link rel="stylesheet" href="css/privacy-policy.min.css">
|
||||
<link rel="stylesheet" href="../css/privacy-policy.min.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
"id": 1,
|
||||
"page": 1,
|
||||
"x": 390.0,
|
||||
"y": 980.0
|
||||
"y": 380.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"page": 2,
|
||||
"x": 390.0,
|
||||
"y": 980.0
|
||||
"y": 680.0
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
<a class="dismiss">X</a>
|
||||
</div>
|
||||
<script src="_content/DevExpress.Blazor.Resources/js/preload-script.js"></script>
|
||||
<script src="js/typed.umd.js"></script>
|
||||
<script src="js/receiver-signature.js?v=9"></script>
|
||||
<script src="_framework/blazor.webassembly.js"></script>
|
||||
</body>
|
||||
|
||||
@@ -315,12 +315,22 @@ window.receiverSignature = (() => {
|
||||
state.hasSignature = true;
|
||||
}
|
||||
|
||||
function startTyped(elementId, text, typeSpeed) {
|
||||
if (typeof Typed === 'undefined') return;
|
||||
new Typed('#' + elementId, {
|
||||
strings: [text],
|
||||
typeSpeed: typeSpeed || 15,
|
||||
showCursor: false
|
||||
});
|
||||
}
|
||||
|
||||
function getDataUrl(id) { const c = document.getElementById(id); const s = pads.get(id); return (c && s && s.hasSignature) ? c.toDataURL('image/png') : null; }
|
||||
function getTypedDataUrl(id) { const c = document.getElementById(id); const s = typedSignatures.get(id); return (c && s && s.hasSignature) ? c.toDataURL('image/png') : null; }
|
||||
function getImageDataUrl(id) { const c = document.getElementById(id); const s = imageSignatures.get(id); return (c && s && s.hasSignature) ? c.toDataURL('image/png') : null; }
|
||||
|
||||
// ?? Public API ??????????????????????????????????????????????????????????
|
||||
return {
|
||||
startTyped: startTyped,
|
||||
installAnnotationCheckboxes: installAnnotationCheckboxes,
|
||||
debugDumpViewerDom: debugDumpViewerDom,
|
||||
initialize: initialize,
|
||||
|
||||
3
EnvelopeGenerator.ReceiverUI/wwwroot/js/typed.umd.js
Normal file
3
EnvelopeGenerator.ReceiverUI/wwwroot/js/typed.umd.js
Normal file
@@ -0,0 +1,3 @@
|
||||
!function(t,s){"object"==typeof exports&&"undefined"!=typeof module?module.exports=s():"function"==typeof define&&define.amd?define(s):(t||self).Typed=s()}(this,function(){function t(){return t=Object.assign?Object.assign.bind():function(t){for(var s=1;s<arguments.length;s++){var e=arguments[s];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])}return t},t.apply(this,arguments)}var s={strings:["These are the default values...","You know what you should do?","Use your own!","Have a great day!"],stringsElement:null,typeSpeed:0,startDelay:0,backSpeed:0,smartBackspace:!0,shuffle:!1,backDelay:700,fadeOut:!1,fadeOutClass:"typed-fade-out",fadeOutDelay:500,loop:!1,loopCount:Infinity,showCursor:!0,cursorChar:"|",autoInsertCss:!0,attr:null,bindInputFocusEvents:!1,contentType:"html",onBegin:function(t){},onComplete:function(t){},preStringTyped:function(t,s){},onStringTyped:function(t,s){},onLastStringBackspaced:function(t){},onTypingPaused:function(t,s){},onTypingResumed:function(t,s){},onReset:function(t){},onStop:function(t,s){},onStart:function(t,s){},onDestroy:function(t){}},e=new(/*#__PURE__*/function(){function e(){}var n=e.prototype;return n.load=function(e,n,i){if(e.el="string"==typeof i?document.querySelector(i):i,e.options=t({},s,n),e.isInput="input"===e.el.tagName.toLowerCase(),e.attr=e.options.attr,e.bindInputFocusEvents=e.options.bindInputFocusEvents,e.showCursor=!e.isInput&&e.options.showCursor,e.cursorChar=e.options.cursorChar,e.cursorBlinking=!0,e.elContent=e.attr?e.el.getAttribute(e.attr):e.el.textContent,e.contentType=e.options.contentType,e.typeSpeed=e.options.typeSpeed,e.startDelay=e.options.startDelay,e.backSpeed=e.options.backSpeed,e.smartBackspace=e.options.smartBackspace,e.backDelay=e.options.backDelay,e.fadeOut=e.options.fadeOut,e.fadeOutClass=e.options.fadeOutClass,e.fadeOutDelay=e.options.fadeOutDelay,e.isPaused=!1,e.strings=e.options.strings.map(function(t){return t.trim()}),e.stringsElement="string"==typeof e.options.stringsElement?document.querySelector(e.options.stringsElement):e.options.stringsElement,e.stringsElement){e.strings=[],e.stringsElement.style.cssText="clip: rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px;";var r=Array.prototype.slice.apply(e.stringsElement.children),o=r.length;if(o)for(var a=0;a<o;a+=1)e.strings.push(r[a].innerHTML.trim())}for(var u in e.strPos=0,e.currentElContent=this.getCurrentElContent(e),e.currentElContent&&e.currentElContent.length>0&&(e.strPos=e.currentElContent.length-1,e.strings.unshift(e.currentElContent)),e.sequence=[],e.strings)e.sequence[u]=u;e.arrayPos=0,e.stopNum=0,e.loop=e.options.loop,e.loopCount=e.options.loopCount,e.curLoop=0,e.shuffle=e.options.shuffle,e.pause={status:!1,typewrite:!0,curString:"",curStrPos:0},e.typingComplete=!1,e.autoInsertCss=e.options.autoInsertCss,e.autoInsertCss&&(this.appendCursorAnimationCss(e),this.appendFadeOutAnimationCss(e))},n.getCurrentElContent=function(t){return t.attr?t.el.getAttribute(t.attr):t.isInput?t.el.value:"html"===t.contentType?t.el.innerHTML:t.el.textContent},n.appendCursorAnimationCss=function(t){var s="data-typed-js-cursor-css";if(t.showCursor&&!document.querySelector("["+s+"]")){var e=document.createElement("style");e.setAttribute(s,"true"),e.innerHTML="\n .typed-cursor{\n opacity: 1;\n }\n .typed-cursor.typed-cursor--blink{\n animation: typedjsBlink 0.7s infinite;\n -webkit-animation: typedjsBlink 0.7s infinite;\n animation: typedjsBlink 0.7s infinite;\n }\n @keyframes typedjsBlink{\n 50% { opacity: 0.0; }\n }\n @-webkit-keyframes typedjsBlink{\n 0% { opacity: 1; }\n 50% { opacity: 0.0; }\n 100% { opacity: 1; }\n }\n ",document.body.appendChild(e)}},n.appendFadeOutAnimationCss=function(t){var s="data-typed-fadeout-js-css";if(t.fadeOut&&!document.querySelector("["+s+"]")){var e=document.createElement("style");e.setAttribute(s,"true"),e.innerHTML="\n .typed-fade-out{\n opacity: 0;\n transition: opacity .25s;\n }\n .typed-cursor.typed-cursor--blink.typed-fade-out{\n -webkit-animation: 0;\n animation: 0;\n }\n ",document.body.appendChild(e)}},e}()),n=new(/*#__PURE__*/function(){function t(){}var s=t.prototype;return s.typeHtmlChars=function(t,s,e){if("html"!==e.contentType)return s;var n=t.substring(s).charAt(0);if("<"===n||"&"===n){var i;for(i="<"===n?">":";";t.substring(s+1).charAt(0)!==i&&!(1+ ++s>t.length););s++}return s},s.backSpaceHtmlChars=function(t,s,e){if("html"!==e.contentType)return s;var n=t.substring(s).charAt(0);if(">"===n||";"===n){var i;for(i=">"===n?"<":"&";t.substring(s-1).charAt(0)!==i&&!(--s<0););s--}return s},t}());/*#__PURE__*/
|
||||
return function(){function t(t,s){e.load(this,s,t),this.begin()}var s=t.prototype;return s.toggle=function(){this.pause.status?this.start():this.stop()},s.stop=function(){this.typingComplete||this.pause.status||(this.toggleBlinking(!0),this.pause.status=!0,this.options.onStop(this.arrayPos,this))},s.start=function(){this.typingComplete||this.pause.status&&(this.pause.status=!1,this.pause.typewrite?this.typewrite(this.pause.curString,this.pause.curStrPos):this.backspace(this.pause.curString,this.pause.curStrPos),this.options.onStart(this.arrayPos,this))},s.destroy=function(){this.reset(!1),this.options.onDestroy(this)},s.reset=function(t){void 0===t&&(t=!0),clearInterval(this.timeout),this.replaceText(""),this.cursor&&this.cursor.parentNode&&(this.cursor.parentNode.removeChild(this.cursor),this.cursor=null),this.strPos=0,this.arrayPos=0,this.curLoop=0,t&&(this.insertCursor(),this.options.onReset(this),this.begin())},s.begin=function(){var t=this;this.options.onBegin(this),this.typingComplete=!1,this.shuffleStringsIfNeeded(this),this.insertCursor(),this.bindInputFocusEvents&&this.bindFocusEvents(),this.timeout=setTimeout(function(){0===t.strPos?t.typewrite(t.strings[t.sequence[t.arrayPos]],t.strPos):t.backspace(t.strings[t.sequence[t.arrayPos]],t.strPos)},this.startDelay)},s.typewrite=function(t,s){var e=this;this.fadeOut&&this.el.classList.contains(this.fadeOutClass)&&(this.el.classList.remove(this.fadeOutClass),this.cursor&&this.cursor.classList.remove(this.fadeOutClass));var i=this.humanizer(this.typeSpeed),r=1;!0!==this.pause.status?this.timeout=setTimeout(function(){s=n.typeHtmlChars(t,s,e);var i=0,o=t.substring(s);if("^"===o.charAt(0)&&/^\^\d+/.test(o)){var a=1;a+=(o=/\d+/.exec(o)[0]).length,i=parseInt(o),e.temporaryPause=!0,e.options.onTypingPaused(e.arrayPos,e),t=t.substring(0,s)+t.substring(s+a),e.toggleBlinking(!0)}if("`"===o.charAt(0)){for(;"`"!==t.substring(s+r).charAt(0)&&(r++,!(s+r>t.length)););var u=t.substring(0,s),p=t.substring(u.length+1,s+r),c=t.substring(s+r+1);t=u+p+c,r--}e.timeout=setTimeout(function(){e.toggleBlinking(!1),s>=t.length?e.doneTyping(t,s):e.keepTyping(t,s,r),e.temporaryPause&&(e.temporaryPause=!1,e.options.onTypingResumed(e.arrayPos,e))},i)},i):this.setPauseStatus(t,s,!0)},s.keepTyping=function(t,s,e){0===s&&(this.toggleBlinking(!1),this.options.preStringTyped(this.arrayPos,this));var n=t.substring(0,s+=e);this.replaceText(n),this.typewrite(t,s)},s.doneTyping=function(t,s){var e=this;this.options.onStringTyped(this.arrayPos,this),this.toggleBlinking(!0),this.arrayPos===this.strings.length-1&&(this.complete(),!1===this.loop||this.curLoop===this.loopCount)||(this.timeout=setTimeout(function(){e.backspace(t,s)},this.backDelay))},s.backspace=function(t,s){var e=this;if(!0!==this.pause.status){if(this.fadeOut)return this.initFadeOut();this.toggleBlinking(!1);var i=this.humanizer(this.backSpeed);this.timeout=setTimeout(function(){s=n.backSpaceHtmlChars(t,s,e);var i=t.substring(0,s);if(e.replaceText(i),e.smartBackspace){var r=e.strings[e.arrayPos+1];e.stopNum=r&&i===r.substring(0,s)?s:0}s>e.stopNum?(s--,e.backspace(t,s)):s<=e.stopNum&&(e.arrayPos++,e.arrayPos===e.strings.length?(e.arrayPos=0,e.options.onLastStringBackspaced(),e.shuffleStringsIfNeeded(),e.begin()):e.typewrite(e.strings[e.sequence[e.arrayPos]],s))},i)}else this.setPauseStatus(t,s,!1)},s.complete=function(){this.options.onComplete(this),this.loop?this.curLoop++:this.typingComplete=!0},s.setPauseStatus=function(t,s,e){this.pause.typewrite=e,this.pause.curString=t,this.pause.curStrPos=s},s.toggleBlinking=function(t){this.cursor&&(this.pause.status||this.cursorBlinking!==t&&(this.cursorBlinking=t,t?this.cursor.classList.add("typed-cursor--blink"):this.cursor.classList.remove("typed-cursor--blink")))},s.humanizer=function(t){return Math.round(Math.random()*t/2)+t},s.shuffleStringsIfNeeded=function(){this.shuffle&&(this.sequence=this.sequence.sort(function(){return Math.random()-.5}))},s.initFadeOut=function(){var t=this;return this.el.className+=" "+this.fadeOutClass,this.cursor&&(this.cursor.className+=" "+this.fadeOutClass),setTimeout(function(){t.arrayPos++,t.replaceText(""),t.strings.length>t.arrayPos?t.typewrite(t.strings[t.sequence[t.arrayPos]],0):(t.typewrite(t.strings[0],0),t.arrayPos=0)},this.fadeOutDelay)},s.replaceText=function(t){this.attr?this.el.setAttribute(this.attr,t):this.isInput?this.el.value=t:"html"===this.contentType?this.el.innerHTML=t:this.el.textContent=t},s.bindFocusEvents=function(){var t=this;this.isInput&&(this.el.addEventListener("focus",function(s){t.stop()}),this.el.addEventListener("blur",function(s){t.el.value&&0!==t.el.value.length||t.start()}))},s.insertCursor=function(){this.showCursor&&(this.cursor||(this.cursor=document.createElement("span"),this.cursor.className="typed-cursor",this.cursor.setAttribute("aria-hidden",!0),this.cursor.innerHTML=this.cursorChar,this.el.parentNode&&this.el.parentNode.insertBefore(this.cursor,this.el.nextSibling)))},t}()});
|
||||
//# sourceMappingURL=typed.umd.js.map
|
||||
@@ -20,6 +20,9 @@ EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "core", "core", "{9943209E-1744-4944-B1BA-4F87FC1A0EEB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{134D4164-B291-4E19-99B9-E4FA3AFAB62C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
COPILOT_CONTEXT_EN.md = COPILOT_CONTEXT_EN.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0CBC2432-A561-4440-89BC-671B66A24146}"
|
||||
EndProject
|
||||
|
||||
Reference in New Issue
Block a user