Compare commits
12 Commits
58b13e233c
...
9782503d1d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9782503d1d | ||
|
|
35ced9b9ad | ||
|
|
9b28c0a1d1 | ||
|
|
fd19c5be58 | ||
|
|
7d582d2422 | ||
|
|
fe1d553a8d | ||
|
|
99c05a44f5 | ||
|
|
678360953d | ||
|
|
9867e81220 | ||
|
|
49cfc3c044 | ||
|
|
43ae15b71c | ||
|
|
1c2df71e0f |
@@ -145,10 +145,10 @@
|
||||
<value>Englisch</value>
|
||||
</data>
|
||||
<data name="EnvelopeInfo1" xml:space="preserve">
|
||||
<value>Sie müssen {0} Vorgang unterzeichen. Bitte prüfen Sie die Seite {1}.</value>
|
||||
<value>Sie müssen {0} Vorgang unterzeichen. <span class="highlight highlight-envelope-info-1">Bitte prüfen Sie die Seite {1}</span>.</value>
|
||||
</data>
|
||||
<data name="EnvelopeInfo2" xml:space="preserve">
|
||||
<value>Erstellt am {0} von {1}. Sie können den Absender über <a href="mailto:{2}?subject={3}&body=Sehr%20geehrter%20{4}%20{5},%0A%0A%0A">{6}</a> kontaktieren.</value>
|
||||
<value>Erstellt am {0} von {1}. Sie können den Absender über <span class="highlight highlight-envelope-info-2"><a class="mail-link" href="mailto:{2}?subject={3}&body=Sehr%20geehrter%20{4}%20{5},%0A%0A%0A">{6}</a></span> kontaktieren.</value>
|
||||
</data>
|
||||
<data name="Finalize" xml:space="preserve">
|
||||
<value>Abschließen</value>
|
||||
@@ -204,6 +204,9 @@
|
||||
<data name="SignDoc" xml:space="preserve">
|
||||
<value>Dokument unterschreiben</value>
|
||||
</data>
|
||||
<data name="SigningProcessTitle" xml:space="preserve">
|
||||
<value>Titel des Unterzeichnungs-Vorgangs</value>
|
||||
</data>
|
||||
<data name="UnexpectedError" xml:space="preserve">
|
||||
<value>Ein unerwarteter Fehler ist aufgetreten.</value>
|
||||
</data>
|
||||
|
||||
@@ -145,10 +145,10 @@
|
||||
<value>English</value>
|
||||
</data>
|
||||
<data name="EnvelopeInfo1" xml:space="preserve">
|
||||
<value>You have to sign {0} process. Please check page {1}.</value>
|
||||
<value>You have to sign {0} process. <span class="highlight highlight-envelope-info-1">Please check page {1}</span>.</value>
|
||||
</data>
|
||||
<data name="EnvelopeInfo2" xml:space="preserve">
|
||||
<value>Created on {0} by {1}. You can contact the sender via <a href="mailto:{2}?subject={3}&body=Dear%20{4}%20{5},%0A%0A%0A">{6}</a>.</value>
|
||||
<value>Created on {0} by {1}. You can contact the sender via <span class="highlight highlight-envelope-info-2"><a class="mail-link" href="mailto:{2}?subject={3}&body=Dear%20{4}%20{5},%0A%0A%0A">{6}</a></span>.</value>
|
||||
</data>
|
||||
<data name="Finalize" xml:space="preserve">
|
||||
<value>Finalize</value>
|
||||
@@ -204,6 +204,9 @@
|
||||
<data name="SignDoc" xml:space="preserve">
|
||||
<value>Sign document</value>
|
||||
</data>
|
||||
<data name="SigningProcessTitle" xml:space="preserve">
|
||||
<value>Title of the signing process</value>
|
||||
</data>
|
||||
<data name="UnexpectedError" xml:space="preserve">
|
||||
<value>An unexpected error has occurred.</value>
|
||||
</data>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<PackageId>EnvelopeGenerator.Web</PackageId>
|
||||
<Version>1.0.0.1</Version>
|
||||
<Version>1.0.0.2</Version>
|
||||
<Authors>Digital Data GmbH</Authors>
|
||||
<Company>Digital Data GmbH</Company>
|
||||
<Product>EnvelopeGenerator.Web</Product>
|
||||
@@ -13,10 +13,14 @@
|
||||
<PackageTags>digital data envelope generator web</PackageTags>
|
||||
<Description>EnvelopeGenerator.Web is an ASP.NET MVC 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>
|
||||
<ApplicationIcon>Assets\icon.ico</ApplicationIcon>
|
||||
<AssemblyVersion>1.1.0.1</AssemblyVersion>
|
||||
<FileVersion>1.1.0.1</FileVersion>
|
||||
<AssemblyVersion>1.0.0.2</AssemblyVersion>
|
||||
<FileVersion>1.0.0.2</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="bundleconfig.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Views\Shared\Error.html" />
|
||||
</ItemGroup>
|
||||
@@ -27,8 +31,13 @@
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="bundleconfig.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="BuildBundlerMinifier2022" Version="2.9.9" />
|
||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="1.0.1.1" />
|
||||
<PackageReference Include="DigitalData.Core.API" Version="1.0.2.1" />
|
||||
<PackageReference Include="DigitalData.Core.Application" Version="1.0.0" />
|
||||
|
||||
@@ -16,6 +16,7 @@ using Microsoft.Extensions.Options;
|
||||
using EnvelopeGenerator.Application;
|
||||
using DigitalData.EmailProfilerDispatcher;
|
||||
using EnvelopeGenerator.Infrastructure;
|
||||
using EnvelopeGenerator.Web.Sanitizers;
|
||||
|
||||
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
||||
logger.Info("Logging initialized!");
|
||||
@@ -126,11 +127,15 @@ try
|
||||
|
||||
builder.Services.AddSingleton(HtmlEncoder.Default);
|
||||
builder.Services.AddSingleton(UrlEncoder.Default);
|
||||
builder.Services.AddSingleton(_ =>
|
||||
builder.Services.AddSanitizer<HtmlSanitizer>();
|
||||
builder.Services.AddSanitizer<HighlightHtmlSanitizer>(s =>
|
||||
{
|
||||
var sanitizer = new HtmlSanitizer();
|
||||
//configure sanitzer
|
||||
return sanitizer;
|
||||
s.AllowedTags.Add("a");
|
||||
s.AllowedAttributes.Add("href");
|
||||
s.AllowedAttributes.Add("class");
|
||||
s.AllowedClasses.Add("highlight");
|
||||
s.AllowedClasses.Add("highlight-envelope-info-1");
|
||||
s.AllowedClasses.Add("highlight-envelope-info-2");
|
||||
});
|
||||
|
||||
// Register the FlagIconCssClass instance as a singleton
|
||||
|
||||
17
EnvelopeGenerator.Web/Sanitizers/DIExtensions.cs
Normal file
17
EnvelopeGenerator.Web/Sanitizers/DIExtensions.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Ganss.Xss;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Sanitizers
|
||||
{
|
||||
public static class DIExtensions
|
||||
{
|
||||
public static IServiceCollection AddSanitizer<THtmlSanitizer>(this IServiceCollection services, Action<THtmlSanitizer>? optionActions = null)
|
||||
where THtmlSanitizer : HtmlSanitizer => services
|
||||
.AddSingleton(serviceProvider =>
|
||||
{
|
||||
var sanitizer = ActivatorUtilities.CreateInstance<THtmlSanitizer>(serviceProvider);
|
||||
optionActions?.Invoke(sanitizer);
|
||||
return sanitizer;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Ganss.Xss;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Sanitizers
|
||||
{
|
||||
public class HighlightHtmlSanitizer : HtmlSanitizer
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -37,16 +37,23 @@
|
||||
<div class="row g-0">
|
||||
<div class="col p-0 m-0">
|
||||
<div class="card-body p-0 m-0 ms-4">
|
||||
<h5 class="card-title p-0 m-0">@($"{envelope?.Title.TrySanitize(_sanitizer)}")</h5>
|
||||
<p class="card-text p-0 m-0">@(string.Format(_localizer[WebKey.EnvelopeInfo1], pages.Count(), stPageIndexes.TrySanitize(_sanitizer)))</p>
|
||||
<p class="card-text p-0 m-0"><small class="text-body-secondary">@Html.Raw(string.Format(_localizer[WebKey.EnvelopeInfo2],
|
||||
envelope?.AddedWhen.ToString(userCulture?.Info?.DateTimeFormat),
|
||||
$"{sender?.Prename} {sender?.Name}".TrySanitize(_sanitizer),
|
||||
sender?.Email.TryEncode(_encoder),
|
||||
envelope?.Title.TryEncode(_encoder),
|
||||
sender?.Prename.TryEncode(_encoder),
|
||||
sender?.Name.TryEncode(_encoder),
|
||||
sender?.Email.TryEncode(_encoder)).TrySanitize(_sanitizer))</small></p>
|
||||
<h5 class="card-title p-0 m-0">
|
||||
<span class="signature-process-title">@($"{_localizer[WebKey.SigningProcessTitle]}: ".TrySanitize(_sanitizer))</span>
|
||||
<span class="signature-process-name">@($"{envelope?.Title}".TrySanitize(_sanitizer))</span>
|
||||
</h5>
|
||||
<p class="card-text p-0 m-0">@Html.Raw(string.Format(_localizer[WebKey.EnvelopeInfo1], pages.Count(), stPageIndexes).TrySanitize(_hlSanitizer))</p>
|
||||
<p class="card-text p-0 m-0">
|
||||
<small class="text-body-secondary">
|
||||
@Html.Raw(string.Format(_localizer[WebKey.EnvelopeInfo2], /* sanitize separately but don't sanitize the URI */
|
||||
envelope?.AddedWhen.ToString(userCulture?.Info?.DateTimeFormat).TrySanitize(_sanitizer),
|
||||
$"{sender?.Prename} {sender?.Name}".TrySanitize(_sanitizer),
|
||||
sender?.Email.TrySanitize(_sanitizer),
|
||||
envelope?.Title.TrySanitize(_sanitizer),
|
||||
sender?.Prename.TrySanitize(_sanitizer),
|
||||
sender?.Name.TrySanitize(_sanitizer),
|
||||
sender?.Email.TrySanitize(_sanitizer)))
|
||||
</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<title>@ViewData["Title"]</title>
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="~/lib/sweetalert2/sweetalert2.min.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true"/>
|
||||
<link rel="stylesheet" href="~/EnvelopeGenerator.Web.styles.css" asp-append-version="true"/>
|
||||
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/EnvelopeGenerator.Web.styles.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/lib/flag-icons-main/css/flag-icons.min.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/lib/alertifyjs/css/alertify.min.css" />
|
||||
<link rel="stylesheet" href="~/lib/alertifyjs/css/themes/default.min.css" />
|
||||
@@ -28,14 +28,14 @@
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<script src="~/lib/sweetalert2/sweetalert2.min.js"></script>
|
||||
<script src="~/lib/alertifyjs/alertify.min.js"></script>
|
||||
<script src="~/js/ui.js" asp-append-version="true"></script>
|
||||
<script src="~/js/ui.min.js" asp-append-version="true"></script>
|
||||
<script src="~/js/annotation.js" asp-append-version="true"></script>
|
||||
<script src="~/js/network.js" asp-append-version="true"></script>
|
||||
<script src="~/js/app.js" asp-append-version="true"></script>
|
||||
<script src="~/js/network.min.js" asp-append-version="true"></script>
|
||||
<script src="~/js/app.min.js" asp-append-version="true"></script>
|
||||
<script src="~/lib/pspdfkit/pspdfkit.js" asp-append-version="true"></script>
|
||||
<script src="~/lib/bootstrap-cookie-consent-settings-main/bootstrap-cookie-consent-settings.js" asp-append-version="true"></script>
|
||||
<script src="~/js/util.js" asp-append-version="true"></script>
|
||||
<script src="~/js/api-service.js" asp-append-version="true"></script>
|
||||
<script src="~/js/util.min.js" asp-append-version="true"></script>
|
||||
<script src="~/js/api-service.min.js" asp-append-version="true"></script>
|
||||
@await RenderSectionAsync("Scripts", required: false)
|
||||
@{
|
||||
var settings = new JsonSerializerSettings
|
||||
@@ -51,7 +51,7 @@
|
||||
<partial name="_CookieConsentPartial" />
|
||||
@RenderBody()
|
||||
</main>
|
||||
<script src="~/js/event-binder.js" asp-append-version="true"></script>
|
||||
<script src="~/js/event-binder.min.js" asp-append-version="true"></script>
|
||||
@Html.AntiForgeryToken()
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,10 +1,12 @@
|
||||
@using EnvelopeGenerator.Web
|
||||
@using EnvelopeGenerator.Web.Models
|
||||
@using EnvelopeGenerator.Web.Sanitizers
|
||||
@using Microsoft.Extensions.Localization
|
||||
@using EnvelopeGenerator.Application.Resources
|
||||
@inject IStringLocalizer<Resource> _localizer
|
||||
@inject System.Text.Encodings.Web.UrlEncoder _encoder
|
||||
@inject Ganss.Xss.HtmlSanitizer _sanitizer
|
||||
@inject HighlightHtmlSanitizer _hlSanitizer
|
||||
@inject Microsoft.AspNetCore.Http.IHttpContextAccessor _accessor
|
||||
@inject Cultures _cultures
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@@ -32,5 +32,6 @@
|
||||
public static readonly string RejectionInfo2 = nameof(RejectionInfo2);
|
||||
public static readonly string RejectionInfo1_ext = nameof(RejectionInfo1_ext);
|
||||
public static readonly string RejectionInfo2_ext = nameof(RejectionInfo2_ext);
|
||||
}
|
||||
public static readonly string SigningProcessTitle = nameof(SigningProcessTitle);
|
||||
}
|
||||
}
|
||||
@@ -119,5 +119,17 @@
|
||||
"AddedWho": "DDEnvelopGenerator",
|
||||
"ReminderTypeId": 202377,
|
||||
"EmailAttmt1": ""
|
||||
}
|
||||
},
|
||||
"Regexes": [
|
||||
{
|
||||
"Pattern": "/^\\p{L}+(?:([\\ \\-\\']|(\\.\\ ))\\p{L}+)*$/u",
|
||||
"Name": "City",
|
||||
"Platforms": [ ".NET" ]
|
||||
},
|
||||
{
|
||||
"Pattern": "/^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$/",
|
||||
"Name": "City",
|
||||
"Platforms": [ "javascript" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
62
EnvelopeGenerator.Web/bundleconfig.json
Normal file
62
EnvelopeGenerator.Web/bundleconfig.json
Normal file
@@ -0,0 +1,62 @@
|
||||
[
|
||||
{
|
||||
"outputFileName": "wwwroot/js/app.min.js",
|
||||
"inputFiles": [
|
||||
"wwwroot/js/app.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "wwwroot/js/api-service.min.js",
|
||||
"inputFiles": [
|
||||
"wwwroot/js/api-service.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "wwwroot/js/error-space.min.js",
|
||||
"inputFiles": [
|
||||
"wwwroot/js/error-space.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "wwwroot/js/event-binder.min.js",
|
||||
"inputFiles": [
|
||||
"wwwroot/js/event-binder.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "wwwroot/js/network.min.js",
|
||||
"inputFiles": [
|
||||
"wwwroot/js/network.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "wwwroot/js/ui.min.js",
|
||||
"inputFiles": [
|
||||
"wwwroot/js/ui.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "wwwroot/js/util.min.js",
|
||||
"inputFiles": [
|
||||
"wwwroot/js/util.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "wwwroot/css/error-space.min.css",
|
||||
"inputFiles": [
|
||||
"wwwroot/css/error-space.css"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "wwwroot/css/site.min.css",
|
||||
"inputFiles": [
|
||||
"wwwroot/css/site.css"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "wwwroot/lib/bootstrap-cookie-consent-settings-main/bootstrap-cookie-consent-settings.min.js",
|
||||
"inputFiles": [
|
||||
"wwwroot/lib/bootstrap-cookie-consent-settings-main/bootstrap-cookie-consent-settings.js"
|
||||
]
|
||||
}
|
||||
]
|
||||
1
EnvelopeGenerator.Web/bundleconfig.json.bindings
Normal file
1
EnvelopeGenerator.Web/bundleconfig.json.bindings
Normal file
@@ -0,0 +1 @@
|
||||
///<binding BeforeBuild='Stylesheets, JavaScript, wwwroot/js/app.min.js' />
|
||||
1
EnvelopeGenerator.Web/wwwroot/css/error-space.min.css
vendored
Normal file
1
EnvelopeGenerator.Web/wwwroot/css/error-space.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -201,7 +201,30 @@ footer#page-footer {
|
||||
min-width: 4vw;
|
||||
}
|
||||
|
||||
/* Additional styles for better mobile responsiveness */
|
||||
.highlight {
|
||||
font-weight: 700;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.signature-process-title, .signature-process-name {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.signature-process-name {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.mail-link {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.mail-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* styles for mobile responsiveness */
|
||||
@media (max-width: 767px) {
|
||||
.navbar {
|
||||
flex-direction: column;
|
||||
@@ -256,3 +279,11 @@ footer#page-footer {
|
||||
max-width: 90%;
|
||||
}
|
||||
}
|
||||
@media (max-height: 850px) {
|
||||
.collapse .card-text, .collapsing .card-text {
|
||||
font-size: 0.5rem; /* Font size reduced */
|
||||
margin: 0rem;
|
||||
padding: 0rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
EnvelopeGenerator.Web/wwwroot/css/site.min.css
vendored
Normal file
1
EnvelopeGenerator.Web/wwwroot/css/site.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
#app{background:#808080;width:100vw;height:80vh}.btn-group{margin-right:10vw;margin-bottom:10vh}.btn_refresh,.btn_reject,.btn_complete{height:2.5rem}.btn_complete .icon,.btn_reject .icon,.btn_refresh .icon{width:1.1rem}.btn_complete span,.btn_reject span,.btn_refresh span{vertical-align:middle}.button-finish{transition:background-color linear 300ms;background-color:#059669;color:#fff;border-left:0}.button-finish:hover,.button-finish:focus,.button-finish:active{background-color:#10b981;color:#fff}.button-reject{transition:background-color linear 300ms;background-color:#d97706;color:#fff;border-left:0}.button-reject:hover,.button-reject:focus,.button-reject:active{background-color:#f59e0b;color:#fff}.button-reset{transition:background-color linear 300ms;background-color:#2563eb;color:#fff;border-left:0}.button-reset:hover,.button-reset:focus,.button-reset:active{background-color:#3b82f6;color:#fff}body{background-color:#bbb}.page{margin-top:3rem;background:#fff;border-radius:5px;box-shadow:rgba(9,30,66,.25) 0 4px 8px -2px,rgba(9,30,66,.08) 0 0 0 1px;max-width:40rem}.page section{max-width:30rem;margin:0 auto}.page header .icon{display:inline-block;border-radius:100px;padding:15px;margin-bottom:2rem}.page header .icon.admin{background-color:#331904;color:#fecba1}.page header .icon.locked{background-color:#ffc107;color:#000}.page header .icon.signed{background-color:#146c43;color:#fff}.page header .icon.rejected{background-color:#e4d8d5;color:#fff}.page .form{max-width:30rem;margin:2rem auto;display:flex;gap:1rem}#form-access-code>.input,#form-admin-password>.input{flex-grow:1}#page-admin header .icon{background-color:#331904;color:#fecba1}.envelope{display:block;border:1px solid #eee;margin-bottom:1rem;padding:.5rem}footer#page-footer{color:#333;max-width:40rem;margin-top:1rem;font-size:.85rem}footer#page-footer a,footer#page-footer a:link,footer#page-footer a:hover,footer#page-footer a:visited,footer#page-footer a:focus{color:#444}.sender-card{background-color:transparent;border:0}.sender-card .row{height:7vh}.sender-card img{height:7vh;background-color:#d1cfcf;border-radius:50px}.envelope-message{font-family:'Roboto',sans-serif}.none-display{display:none}.dropdown-flag img,.img-flag{width:30%;height:70%}.dropdown-flag{height:75%;width:75%}.increase-dropdown-height{min-height:400px}.dropdown-flag .select2-container{width:100%!important;max-width:180px}.lang-item{font-size:.85rem}#langDropdownMenuButton{min-width:4vw}.highlight{font-weight:700;font-size:13px}.signature-process-title,.signature-process-name{font-size:18px}.signature-process-name{font-size:15px;font-weight:700}.mail-link{color:#000;text-decoration:none}.mail-link:hover{text-decoration:underline}@media(max-width:767px){.navbar{flex-direction:column;align-items:flex-start}.navbar-brand{font-size:.5rem;text-align:center;width:100%;overflow:hidden;text-overflow:ellipsis}.collapse .card-text,.collapsing .card-text{font-size:.6rem;margin:0;padding:0}.sender-card .card-body{padding:.5rem}.btn_group{position:fixed;flex-direction:row;bottom:.5rem;right:.5rem}.img-fluid{width:1.2rem;height:100%;display:none}img{max-width:4rem}.page{margin-top:1rem;max-width:90%;padding:.5rem}.page section{max-width:90%}}@media(max-height:850px){.collapse .card-text,.collapsing .card-text{font-size:.5rem;margin:0;padding:0}}
|
||||
Binary file not shown.
@@ -62,7 +62,7 @@
|
||||
backgroundColor: PSPDFKit.Color.DarkBlue,
|
||||
blendMode: 'multiply',
|
||||
boundingBox: new PSPDFKit.Geometry.Rect({
|
||||
width: width * 0.75,
|
||||
width: width * 1.55,
|
||||
height: height / 2,
|
||||
top: top + height + 25 + date_place_top_shift,
|
||||
left: left + width * 1.30,
|
||||
@@ -77,7 +77,7 @@
|
||||
const formFieldDate = new PSPDFKit.FormFields.TextFormField({
|
||||
name: id_date,
|
||||
annotationIds: PSPDFKit.Immutable.List([annotation_date.id]),
|
||||
value: locale_date_dd_mm_yyyy(),
|
||||
value: detailedCurrentDate(),
|
||||
readOnly: true
|
||||
})
|
||||
|
||||
@@ -108,6 +108,8 @@
|
||||
|
||||
this.markFieldAsRequired(formFieldCity);
|
||||
|
||||
this.markFieldAsCity(formFieldCity);
|
||||
|
||||
/**
|
||||
* Date, post code and place label part
|
||||
*/
|
||||
@@ -307,6 +309,7 @@
|
||||
return inch * 72
|
||||
}
|
||||
|
||||
//required
|
||||
static #requiredFieldNames = new Array()
|
||||
|
||||
static markFieldAsRequired(formField) {
|
||||
@@ -316,4 +319,15 @@
|
||||
static isFieldRequired(formField) {
|
||||
return this.#requiredFieldNames.includes(formField.name)
|
||||
}
|
||||
|
||||
//city
|
||||
static #cityFieldNames = new Array()
|
||||
|
||||
static markFieldAsCity(formField) {
|
||||
this.#cityFieldNames.push(formField.name)
|
||||
}
|
||||
|
||||
static isCityField(formField){
|
||||
return this.#cityFieldNames.includes(formField.name)
|
||||
}
|
||||
}
|
||||
2
EnvelopeGenerator.Web/wwwroot/js/api-service.min.js
vendored
Normal file
2
EnvelopeGenerator.Web/wwwroot/js/api-service.min.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
class Content{static get JSON(){return"application/json"}}class API{static get REJECT_URL(){return`/api/envelope/reject`}static get REJECT_REDIR_URL(){return`/envelopekey/${API.ENV_KEY}/rejected`}static __XSRF_TOKEN
|
||||
static get XSRF_TOKEN(){return API.__XSRF_TOKEN??=document.getElementsByName("__RequestVerificationToken")[0].value,API.__XSRF_TOKEN}static get ENV_KEY(){return ENV_KEY??document.querySelector('meta[name="env-key"]').getAttribute("content")}}const submitForm=async n=>await fetch(n.action,{method:n.method,body:new FormData(n),headers:{"X-Requested-With":"XMLHttpRequest"}}),createRequest=async(n,t,i,r)=>fetch(t,{credentials:"include",method:n,headers:{"Content-Type":r,"X-XSRF-TOKEN":API.XSRF_TOKEN},body:JSON.stringify(i)}),createPost=(n,t,i)=>createRequest("POST",n,t,i),rejectEnvelope=n=>createPost(API.REJECT_URL,n,Content.JSON),redirect=n=>window.location.href=n,redirRejected=()=>redirect(API.REJECT_REDIR_URL);
|
||||
@@ -170,6 +170,8 @@ class App {
|
||||
async handleFinish(event) {
|
||||
const iJSON = await this.Instance.exportInstantJSON()
|
||||
const iFormFieldValues = await iJSON.formFieldValues;
|
||||
|
||||
//check required
|
||||
const iReqFields = iFormFieldValues.filter(f => Annotation.isFieldRequired(f))
|
||||
const hasEmptyReq = iReqFields.some(f => (f.value === undefined || f.value === null || f.value === ""))
|
||||
|
||||
@@ -182,6 +184,20 @@ class App {
|
||||
return false;
|
||||
}
|
||||
|
||||
//check city
|
||||
const city_regex = new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$")
|
||||
const iCityFields = iFormFieldValues.filter(f => Annotation.isCityField(f))
|
||||
for(var f of iCityFields)
|
||||
if(!city_regex.test(f.value)){
|
||||
Swal.fire({
|
||||
title: 'Warnung',
|
||||
text: `Bitte überprüfen Sie die eingegebene Ortsangabe "${f.value}" auf korrekte Formatierung. Beispiele für richtige Formate sind: München, Île-de-France, Sauðárkrókur, San Francisco, St. Catharines usw.`,
|
||||
icon: 'warning',
|
||||
})
|
||||
return false;
|
||||
}
|
||||
|
||||
//check # of signature
|
||||
const validationResult = await this.validateAnnotations(this.signatureCount)
|
||||
if (validationResult === false) {
|
||||
Swal.fire({
|
||||
|
||||
File diff suppressed because one or more lines are too long
1
EnvelopeGenerator.Web/wwwroot/js/app.min.js
vendored
Normal file
1
EnvelopeGenerator.Web/wwwroot/js/app.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
const ActionType={Created:0,Saved:1,Sent:2,EmailSent:3,Delivered:4,Seen:5,Signed:6,Rejected:7};class App{constructor(n,t,i,r,u,f){this.container=f??`#${this.constructor.name.toLowerCase()}`;this.envelopeKey=n;this.Network=new Network;this.Instance=null;this.currentDocument=null;this.currentReceiver=null;this.signatureCount=0;this.envelopeReceiver=t;this.documentBytes=i;this.licenseKey=r;this.locale=u}async init(){this.currentDocument=this.envelopeReceiver.envelope.documents[0];this.currentReceiver=this.envelopeReceiver.receiver;const n=this.documentBytes;if(n.fatal||n.error)return Swal.fire({title:"Fehler",text:"Dokument konnte nicht geladen werden!",icon:"error"});const t=this.documentBytes;this.Instance=await UI.loadPSPDFKit(t,this.container,this.licenseKey,this.locale);UI.configurePSPDFKit(this.Instance,this.handleClick.bind(this));this.Instance.addEventListener("annotations.load",this.handleAnnotationsLoad.bind(this));this.Instance.addEventListener("annotations.change",this.handleAnnotationsChange.bind(this));this.Instance.addEventListener("annotations.create",this.handleAnnotationsCreate.bind(this));this.Instance.addEventListener("annotations.willChange",()=>{Comp.ActPanel.Toggle()});try{this.signatureCount=this.currentDocument.elements.length;await Annotation.createAnnotations(this.currentDocument,this.Instance);const n=await this.Network.openDocument(this.envelopeKey);if(n.fatal||n.error)return Swal.fire({title:"Fehler",text:"Umschlag konnte nicht geöffnet werden!",icon:"error"})}catch(i){}[...document.getElementsByClassName("btn_refresh")].forEach(n=>n.addEventListener("click",()=>this.handleClick("RESET")));[...document.getElementsByClassName("btn_complete")].forEach(n=>n.addEventListener("click",()=>this.handleClick("FINISH")))}handleAnnotationsLoad(n){n.toJS()}handleAnnotationsChange(){}async handleAnnotationsCreate(n){const t=n.toJS()[0],i=!!t.formFieldName,r=!!t.isSignature;if(i===!1&&r===!0){const r=t.boundingBox.left-20,u=t.boundingBox.top-20,n=150,i=75,f=new Date,e=await Annotation.createAnnotationFrameBlob(this.envelopeReceiver.name,this.currentReceiver.signature,f,n,i),o=await fetch(e),s=await o.blob(),h=await this.Instance.createAttachment(s),c=Annotation.createImageAnnotation(new PSPDFKit.Geometry.Rect({left:r,top:u,width:n,height:i}),t.pageIndex,h);this.Instance.create(c)}}async handleClick(n){let t=!1;switch(n){case"RESET":t=await this.handleReset(null);t.isConfirmed&&Swal.fire({title:"Erfolg",text:"Dokument wurde zurückgesetzt",icon:"info"});break;case"FINISH":t=await this.handleFinish(null);t==!0&&(window.location.href=`/EnvelopeKey/${this.envelopeKey}/Success`);break;case"REJECT":alert("Dokument abgelent!")}}async handleFinish(){const n=await this.Instance.exportInstantJSON(),t=await n.formFieldValues,r=t.filter(n=>Annotation.isFieldRequired(n)),u=r.some(n=>n.value===undefined||n.value===null||n.value==="");if(u)return Swal.fire({title:"Warnung",text:"Bitte füllen Sie alle Standortinformationen vollständig aus!",icon:"warning"}),!1;const f=new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$"),e=t.filter(n=>Annotation.isCityField(n));for(var i of e)if(!f.test(i.value))return Swal.fire({title:"Warnung",text:`Bitte überprüfen Sie die eingegebene Ortsangabe "${i.value}" auf korrekte Formatierung. Beispiele für richtige Formate sind: München, Île-de-France, Sauðárkrókur, San Francisco, St. Catharines usw.`,icon:"warning"}),!1;const o=await this.validateAnnotations(this.signatureCount);return o===!1?(Swal.fire({title:"Warnung",text:"Es wurden nicht alle Signaturfelder ausgefüllt!",icon:"warning"}),!1):Swal.fire({title:localized.confirmation,html:`<div class="text-start fs-6 p-0 m-0">${localized.sigAgree}</div>`,icon:"question",showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.finalize,cancelButtonText:localized.back}).then(async t=>{if(t.isConfirmed){try{await this.Instance.save()}catch(i){return Swal.fire({title:"Fehler",text:"Umschlag konnte nicht signiert werden!",icon:"error"}),!1}try{const i=await n,t=await this.Network.postEnvelope(this.envelopeKey,this.currentDocument.id,i);return t.fatal?(Swal.fire({title:"Fehler",text:"Umschlag konnte nicht signiert werden!",icon:"error"}),!1):t.error?(Swal.fire({title:"Warnung",text:"Umschlag ist nicht mehr verfügbar.",icon:"warning"}),!1):!0}catch(i){return!1}}else return!1})}async validateAnnotations(n){const t=await Annotation.getAnnotations(this.Instance),i=t.map(n=>n.toJS()).filter(n=>n.isSignature);return n>i.length?!1:!0}async handleReset(){const n=await Swal.fire({title:"Sind sie sicher?",text:"Wollen Sie das Dokument und alle erstellten Signaturen zurücksetzen?",icon:"question",showCancelButton:!0});if(n.isConfirmed){const n=await Annotation.deleteAnnotations(this.Instance)}return n}}
|
||||
1
EnvelopeGenerator.Web/wwwroot/js/error-space.min.js
vendored
Normal file
1
EnvelopeGenerator.Web/wwwroot/js/error-space.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
function drawVisor(){const t=document.getElementById("visor"),n=t.getContext("2d");n.beginPath();n.moveTo(5,45);n.bezierCurveTo(15,64,45,64,55,45);n.lineTo(55,20);n.bezierCurveTo(55,15,50,10,45,10);n.lineTo(15,10);n.bezierCurveTo(15,10,5,10,5,20);n.lineTo(5,45);n.fillStyle="#2f3640";n.strokeStyle="#f5f6fa";n.fill();n.stroke()}function animate(){requestAnimationFrame(animate);ctx.clearRect(0,0,innerWidth,innerHeight);ctx.beginPath();ctx.moveTo(130,170);ctx.bezierCurveTo(250,y1,345,y2,400,y3);ctx.strokeStyle="white";ctx.lineWidth=8;ctx.stroke();y1===100&&(y1Forward=!0);y1===300&&(y1Forward=!1);y2===100&&(y2Forward=!0);y2===310&&(y2Forward=!1);y3===100&&(y3Forward=!0);y3===317&&(y3Forward=!1);y1Forward?y1+=1:y1-=1;y2Forward?y2+=1:y2-=1;y3Forward?y3+=1:y3-=1}const cordCanvas=document.getElementById("cord"),ctx=cordCanvas.getContext("2d");let y1=160,y2=100,y3=100,y1Forward=!0,y2Forward=!1,y3Forward=!0;drawVisor();animate();
|
||||
3
EnvelopeGenerator.Web/wwwroot/js/event-binder.min.js
vendored
Normal file
3
EnvelopeGenerator.Web/wwwroot/js/event-binder.min.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
$(".btn_reject").click(()=>Swal.fire({title:localized.rejection,html:`<div class="text-start fs-6 p-0 m-0">${localized.rejectionReasonQ}</div>`,icon:"question",input:"text",inputAttributes:{autocapitalize:"off"},showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.complete,cancelButtonText:localized.back,showLoaderOnConfirm:!0,preConfirm:async n=>{try{return await rejectEnvelope(n)}catch(t){Swal.showValidationMessage(`
|
||||
Request failed: ${t}
|
||||
`)}},allowOutsideClick:()=>!Swal.isLoading()}).then(n=>{if(n.isConfirmed){const t=n.value;t.ok?redirRejected():Swal.showValidationMessage(`Request failed: ${t.message}`)}}));class Comp{static ActPanel=class{static __Root;static get Root(){Comp.ActPanel.__Root??=document.getElementById("flex-actio-panel");return Comp.ActPanel.__Root}static get Elements(){return[...Comp.ActPanel.Root.children]}static get IsHided(){return Comp.ActPanel.Root.style.display=="none"}static set Display(n){Comp.ActPanel.Root.style.display=n;Comp.ActPanel.Elements.forEach(t=>t.style.display=n)}static Toggle(){Comp.ActPanel.Display=Comp.ActPanel.IsHided?"":"none"}};}
|
||||
1
EnvelopeGenerator.Web/wwwroot/js/network.min.js
vendored
Normal file
1
EnvelopeGenerator.Web/wwwroot/js/network.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
async function setLangAsync(n,t){document.getElementById("selectedFlag").className="fi "+t+" me-2";await fetch(`/lang/${n}`,{method:"POST",headers:{"Content-Type":"application/json"}})}async function setLanguage(n){const t=await fetch("/lang",{method:"GET",headers:{"Content-Type":"application/json"}}).then(n=>n.json()).then(t=>t.includes(n)).catch(()=>!1);if(t)return await fetch(`/lang/${n}`,{method:"POST",headers:{"Content-Type":"application/json"}}).then(n=>{if(n.redirected)window.location.href=n.url;else if(!n.ok)return Promise.reject("Failed to set language")})}class Network{async getEnvelope(n){return this.getRequest(`/api/envelope/${n}`).then(this.wrapJsonResponse.bind(this))}async postEnvelope(n,t,i){return this.postRequest(`/api/envelope/${n}?index=${t}`,i).then(this.wrapJsonResponse.bind(this))}async getDocument(n,t){return this.getRequest(`/api/document/${n}?index=${t}`).then(this.wrapBinaryResponse.bind(this))}async openDocument(n){return this.postRequest(`/api/document/${n}`,{}).then(this.wrapJsonResponse.bind(this))}withCSRFToken(n){const t=getCSRFToken;let i=n.headers;return n.headers={...i,...t},n}getCSRFToken(){const n=document.getElementsByName("__RequestVerificationToken")[0].value;return{"X-XSRF-TOKEN":n}}getRequest(n,t){const r=this.getCSRFToken(),i={credentials:"include",method:"GET",headers:{...r}};return t!==undefined&&(i.body=JSON.stringify(t)),fetch(n,i)}postRequest(n,t){const i=this.getCSRFToken(),r={credentials:"include",method:"POST",headers:{...i,"Content-Type":"application/json; charset=utf-8"},body:JSON.stringify(t)};return fetch(n,r)}async wrapJsonResponse(n){return await this.wrapResponse(n,async n=>await n.json())}async wrapBinaryResponse(n){return await this.wrapResponse(n,async n=>await n.arrayBuffer())}async wrapResponse(n,t){let i;if(n.status===200){const r=await t(n);i=new WrappedResponse(r,null)}else if(n.status===403){const t=await n.json();i=new WrappedResponse(null,t)}else i=new WrappedResponse(null,null);return i}}class WrappedResponse{constructor(n,t){this.data=n;this.error=t;this.fatal=n===null&&t===null}}
|
||||
7
EnvelopeGenerator.Web/wwwroot/js/ui.min.js
vendored
Normal file
7
EnvelopeGenerator.Web/wwwroot/js/ui.min.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
class UI{static allowedToolbarItems=["sidebar-thumbnails","sidebar-document-ouline","sidebar-bookmarks","pager","pan","zoom-out","zoom-in","zoom-mode","spacer","search",];static Instance
|
||||
static loadPSPDFKit(n,t,i,r){return UI.Instance=PSPDFKit.load({locale:r,licenseKey:i,styleSheets:["/css/site.css"],container:t,document:n,annotationPresets:UI.getPresets(),electronicSignatures:{creationModes:["DRAW","TYPE","IMAGE"]},initialViewState:new PSPDFKit.ViewState({sidebarMode:PSPDFKit.SidebarMode.THUMBNAILS}),isEditableAnnotation:function(n){return n.isSignature||n.description=="FRAME"?!1:!0},customRenderers:{Annotation:UI.annotationRenderer}}),UI.Instance}static configurePSPDFKit(n,t){const i=UI.getToolbarItems(n,t);n.setToolbarItems(i)}static annotationRenderer(){return null}static getToolbarItems(n,t){const i=UI.getCustomItems(t),r=UI.getDefaultItems(n.toolbarItems);return r.concat(i)}static createElementFromHTML(n){const t=document.createElement("div");return t.innerHTML=n.trim(),t.firstChild}static getCustomItems=function(n){return[];return[{type:"custom",id:"button-reset",className:"button-reset",title:"Zurücksetzen",onPress(){n("RESET")},icon:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z"/>
|
||||
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/>
|
||||
</svg>`},{type:"custom",id:"button-reject",className:"button-reject",title:"Ablehnen",onPress(){n("REJECT")},icon:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-hand-thumbs-down" viewBox="0 0 16 16">
|
||||
<path d="M8.864 15.674c-.956.24-1.843-.484-1.908-1.42-.072-1.05-.23-2.015-.428-2.59-.125-.36-.479-1.012-1.04-1.638-.557-.624-1.282-1.179-2.131-1.41C2.685 8.432 2 7.85 2 7V3c0-.845.682-1.464 1.448-1.546 1.07-.113 1.564-.415 2.068-.723l.048-.029c.272-.166.578-.349.97-.484C6.931.08 7.395 0 8 0h3.5c.937 0 1.599.478 1.934 1.064.164.287.254.607.254.913 0 .152-.023.312-.077.464.201.262.38.577.488.9.11.33.172.762.004 1.15.069.13.12.268.159.403.077.27.113.567.113.856 0 .289-.036.586-.113.856-.035.12-.08.244-.138.363.394.571.418 1.2.234 1.733-.206.592-.682 1.1-1.2 1.272-.847.283-1.803.276-2.516.211a9.877 9.877 0 0 1-.443-.05 9.364 9.364 0 0 1-.062 4.51c-.138.508-.55.848-1.012.964zM11.5 1H8c-.51 0-.863.068-1.14.163-.281.097-.506.229-.776.393l-.04.025c-.555.338-1.198.73-2.49.868-.333.035-.554.29-.554.55V7c0 .255.226.543.62.65 1.095.3 1.977.997 2.614 1.709.635.71 1.064 1.475 1.238 1.977.243.7.407 1.768.482 2.85.025.362.36.595.667.518l.262-.065c.16-.04.258-.144.288-.255a8.34 8.34 0 0 0-.145-4.726.5.5 0 0 1 .595-.643h.003l.014.004.058.013a8.912 8.912 0 0 0 1.036.157c.663.06 1.457.054 2.11-.163.175-.059.45-.301.57-.651.107-.308.087-.67-.266-1.021L12.793 7l.353-.354c.043-.042.105-.14.154-.315.048-.167.075-.37.075-.581 0-.211-.027-.414-.075-.581-.05-.174-.111-.273-.154-.315l-.353-.354.353-.354c.047-.047.109-.176.005-.488a2.224 2.224 0 0 0-.505-.804l-.353-.354.353-.354c.006-.005.041-.05.041-.17a.866.866 0 0 0-.121-.415C12.4 1.272 12.063 1 11.5 1"/>
|
||||
</svg>`},{type:"custom",id:"button-finish",className:"button-finish",title:"Abschließen",onPress(){n("FINISH")}},]};static getDefaultItems(n){return n.filter(n=>UI.allowedToolbarItems.includes(n.type))}static getPresets(){const n=PSPDFKit.defaultAnnotationPresets;return n.ink={lineWidth:10},n.widget={readOnly:!0},n}}
|
||||
@@ -46,13 +46,17 @@ async function getLocation() {
|
||||
}
|
||||
|
||||
const getLocaleDateString = _ => new Date().toLocaleDateString('de-DE')
|
||||
|
||||
function locale_date_dd_mm_yyyy() {
|
||||
const today = new Date();
|
||||
const day = String(today.getDate()).padStart(2, '0');
|
||||
const month = String(today.getMonth() + 1).padStart(2, '0');
|
||||
const year = String(today.getFullYear()).slice(-4);
|
||||
return `${day}/${month}/${year}`;
|
||||
|
||||
function detailedCurrentDate() {
|
||||
return new Intl.DateTimeFormat('de-DE', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
timeZoneName: 'shortOffset'
|
||||
}).format();
|
||||
}
|
||||
|
||||
let __is_mobile = null;
|
||||
|
||||
1
EnvelopeGenerator.Web/wwwroot/js/util.min.js
vendored
Normal file
1
EnvelopeGenerator.Web/wwwroot/js/util.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
function getCoordinates(){return new Promise((n,t)=>{navigator.geolocation?navigator.geolocation.getCurrentPosition(t=>n(t.coords),n=>t(n)):t(new Error("Geolocation is not supported by this browser."))})}async function getCity(){try{const t=await getCoordinates(),i=await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${t.latitude}&lon=${t.longitude}`),n=await i.json();if(n&&n.address){const t=n.address.city||n.address.town||n.address.village||n.address.hamlet,i=n.address.postcode;return i+" "+t||""}}catch{return""}}async function getLocation(){try{const t=await getCoordinates(),i=await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${t.latitude}&lon=${t.longitude}`),n=await i.json();if(n&&n.address){const t=n.address.city||n.address.town||n.address.village||n.address.hamlet,i=n.address.postcode;return{postalCode:i,city:t}}}catch{return{postalCode:"",city:""}}}function detailedCurrentDate(){return new Intl.DateTimeFormat("de-DE",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:"shortOffset"}).format()}function isMobile(){return __is_mobile===null&&(__is_mobile=/Mobi|Android/i.test(window.navigator.userAgent)),__is_mobile}const B64ToBuff=n=>new Uint8Array(Array.from(atob(n),n=>n.charCodeAt(0))).buffer;const getLocaleDateString=()=>(new Date).toLocaleDateString("de-DE");let __is_mobile=null;
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user