This commit is contained in:
Developer01
2025-04-24 11:45:38 +02:00
16 changed files with 267 additions and 56 deletions

View File

@@ -166,7 +166,7 @@ Public Class EnvelopeEditorController
DocumentRotationChanged() DocumentRotationChanged()
Logger.Info("PageRotation has been reseted to 0.") Logger.Info("PageRotation has been reseted to 0.")
End If End If
oFixedPath = FlattenFormFields.FlattenFormFields(oFixedPath)
Dim oFileInfo = New FileInfo(oFixedPath) Dim oFileInfo = New FileInfo(oFixedPath)
Dim oTempFiles As New TempFiles(State.LogConfig) Dim oTempFiles As New TempFiles(State.LogConfig)
Dim oTempFilePath = Path.Combine(oTempFiles._TempPath, Guid.NewGuid().ToString + oFileInfo.Extension) Dim oTempFilePath = Path.Combine(oTempFiles._TempPath, Guid.NewGuid().ToString + oFileInfo.Extension)

View File

@@ -369,6 +369,7 @@
</Compile> </Compile>
<Compile Include="Helper\Encryption.vb" /> <Compile Include="Helper\Encryption.vb" />
<Compile Include="Helper\FixPageRotation.vb" /> <Compile Include="Helper\FixPageRotation.vb" />
<Compile Include="Helper\FlattenFormFields.vb" />
<Compile Include="Helper\RefreshHelper.vb" /> <Compile Include="Helper\RefreshHelper.vb" />
<Compile Include="Helper\TempFiles.vb" /> <Compile Include="Helper\TempFiles.vb" />
<Compile Include="Helper\Thumbnail.vb" /> <Compile Include="Helper\Thumbnail.vb" />

View File

@@ -0,0 +1,32 @@
Imports System.IO
Imports GdPicture14
Public Class FlattenFormFields
Public Shared Function FlattenFormFields(pFilePath As String) As String
Dim oFolder As String = Path.GetDirectoryName(pFilePath)
Dim gdpicturePdf As GdPicturePDF = New GdPicturePDF()
Dim status As GdPictureStatus = gdpicturePdf.LoadFromFile(pFilePath, True)
If status = GdPictureStatus.OK Then
Dim oFormFieldsCount = gdpicturePdf.GetFormFieldsCount()
If oFormFieldsCount > 0 Then
gdpicturePdf.FlattenFormFields()
Dim newFilesPath As String = Path.Combine(oFolder, "InputFieldsFlattend_" & Path.GetFileName(pFilePath))
If gdpicturePdf.SaveToFile(newFilesPath) = GdPictureStatus.OK Then
Return newFilesPath
End If
End If
End If
Return pFilePath
End Function
End Class

View File

@@ -1,4 +1,5 @@
using EnvelopeGenerator.Web.Models; using EnvelopeGenerator.Web.Models.Annotation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@@ -6,6 +7,7 @@ namespace EnvelopeGenerator.Web.Controllers;
[Route("api/[controller]")] [Route("api/[controller]")]
[ApiController] [ApiController]
[Authorize]
public class ConfigController : ControllerBase public class ConfigController : ControllerBase
{ {
private readonly AnnotationParams _annotParams; private readonly AnnotationParams _annotParams;
@@ -18,6 +20,6 @@ public class ConfigController : ControllerBase
[HttpGet("Annotations")] [HttpGet("Annotations")]
public IActionResult GetAnnotationParams() public IActionResult GetAnnotationParams()
{ {
return Ok(_annotParams.AnnotationDictionary); return Ok(_annotParams.AnnotationJSObject);
} }
} }

View File

@@ -5,7 +5,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<PackageId>EnvelopeGenerator.Web</PackageId> <PackageId>EnvelopeGenerator.Web</PackageId>
<Version>3.1.1</Version> <Version>3.1.2</Version>
<Authors>Digital Data GmbH</Authors> <Authors>Digital Data GmbH</Authors>
<Company>Digital Data GmbH</Company> <Company>Digital Data GmbH</Company>
<Product>EnvelopeGenerator.Web</Product> <Product>EnvelopeGenerator.Web</Product>
@@ -13,8 +13,8 @@
<PackageTags>digital data envelope generator web</PackageTags> <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> <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> <ApplicationIcon>Assets\icon.ico</ApplicationIcon>
<AssemblyVersion>3.1.1</AssemblyVersion> <AssemblyVersion>3.1.2</AssemblyVersion>
<FileVersion>3.1.1</FileVersion> <FileVersion>3.1.2</FileVersion>
<Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright> <Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright>
</PropertyGroup> </PropertyGroup>

View File

@@ -1,8 +1,8 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace EnvelopeGenerator.Web.Models; namespace EnvelopeGenerator.Web.Models.Annotation;
public record Annotation public record Annotation : IAnnotation
{ {
public required string Name { get; init; } public required string Name { get; init; }
@@ -60,6 +60,16 @@ public record Annotation
public Annotation? VerBoundAnnot { get; set; } public Annotation? VerBoundAnnot { get; set; }
#endregion #endregion
public Color? BackgroundColor { get; init; }
#region Border
public Color? BorderColor { get; init; }
public string? BorderStyle { get; init; }
public int? BorderWidth { get; set; }
#endregion
[JsonIgnore] [JsonIgnore]
internal Annotation Default internal Annotation Default
{ {

View File

@@ -1,15 +1,21 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace EnvelopeGenerator.Web.Models; namespace EnvelopeGenerator.Web.Models.Annotation;
public class AnnotationParams public class AnnotationParams
{ {
public AnnotationParams()
{
_AnnotationJSObjectInitor = new(CreateAnnotationJSObject);
}
public Background? Background { get; init; }
#region Annotation
[JsonIgnore] [JsonIgnore]
public Annotation? DefaultAnnotation { get; init; } public Annotation? DefaultAnnotation { get; init; }
private readonly IEnumerable<Annotation> _annots = new List<Annotation>(); private readonly List<Annotation> _annots = new List<Annotation>();
public Annotation this[string name] => _annots.First(a => a.Name == name);
public bool TryGet(string name, out Annotation annotation) public bool TryGet(string name, out Annotation annotation)
{ {
@@ -24,34 +30,50 @@ public class AnnotationParams
get => _annots; get => _annots;
init init
{ {
_annots = value; _annots = value.ToList();
if (DefaultAnnotation is not null) if (DefaultAnnotation is not null)
foreach (var annot in _annots) foreach (var annot in _annots)
annot.Default = DefaultAnnotation; annot.Default = DefaultAnnotation;
foreach (var annot in _annots) for (int i = 0; i < _annots.Count; i++)
{ {
#region set bound annotations #region set bound annotations
// horizontal // horizontal
if (annot.HorBoundAnnotName is string horBoundAnnotName) if (_annots[i].HorBoundAnnotName is string horBoundAnnotName)
if (TryGet(horBoundAnnotName, out var horBoundAnnot)) if (TryGet(horBoundAnnotName, out var horBoundAnnot))
annot.HorBoundAnnot = horBoundAnnot; _annots[i].HorBoundAnnot = horBoundAnnot;
else else
throw new InvalidOperationException($"{horBoundAnnotName} added as bound anotation. However, it is not defined."); throw new InvalidOperationException($"{horBoundAnnotName} added as bound anotation. However, it is not defined.");
// vertical // vertical
if (annot.VerBoundAnnotName is string verBoundAnnotName) if (_annots[i].VerBoundAnnotName is string verBoundAnnotName)
if (TryGet(verBoundAnnotName, out var verBoundAnnot)) if (TryGet(verBoundAnnotName, out var verBoundAnnot))
annot.VerBoundAnnot = verBoundAnnot; _annots[i].VerBoundAnnot = verBoundAnnot;
else else
throw new InvalidOperationException($"{verBoundAnnotName} added as bound anotation. However, it is not defined."); throw new InvalidOperationException($"{verBoundAnnotName} added as bound anotation. However, it is not defined.");
#endregion #endregion
} }
AnnotationDictionary = _annots.ToDictionary(a => a.Name.ToLower(), a => a);
} }
} }
#endregion
public Dictionary<string, Annotation> AnnotationDictionary { get; private init; } = new(); #region AnnotationJSObject
private Dictionary<string, IAnnotation> CreateAnnotationJSObject()
{
var dict = _annots.ToDictionary(a => a.Name.ToLower(), a => a as IAnnotation);
if (Background is not null)
{
Background.Locate(_annots);
dict.Add(Background.Name.ToLower(), Background);
}
return dict;
}
private readonly Lazy<Dictionary<string, IAnnotation>> _AnnotationJSObjectInitor;
public Dictionary<string, IAnnotation> AnnotationJSObject => _AnnotationJSObjectInitor.Value;
#endregion
} }

View File

@@ -0,0 +1,58 @@
using System.Text.Json.Serialization;
namespace EnvelopeGenerator.Web.Models.Annotation;
/// <summary>
/// The Background is an annotation for the PSPDF Kit. However, it has no function.
/// It is only the first annotation as a background for other annotations.
/// </summary>
public record Background : IAnnotation
{
[JsonIgnore]
public double Margin { get; init; }
public string Name { get; } = "Background";
public double? Width { get; set; }
public double? Height { get; set; }
public double Left { get; set; }
public double Top { get; set; }
public Color? BackgroundColor { get; init; }
#region Border
public Color? BorderColor { get; init; }
public string? BorderStyle { get; init; }
public int? BorderWidth { get; set; }
#endregion
public void Locate(IEnumerable<IAnnotation> annotations)
{
// set Top
if (annotations.MinBy(a => a.Top)?.Top is double minTop)
Top = minTop;
// set Left
if (annotations.MinBy(a => a.Left)?.Left is double minLeft)
Left = minLeft;
// set Width
if(annotations.MaxBy(a => a.GetRight())?.GetRight() is double maxRight)
Width = maxRight - Left;
// set Height
if (annotations.MaxBy(a => a.GetBottom())?.GetBottom() is double maxBottom)
Height = maxBottom - Top;
// add margins
Top -= Margin;
Left -= Margin;
Width += Margin * 2;
Height += Margin * 2;
}
}

View File

@@ -0,0 +1,10 @@
namespace EnvelopeGenerator.Web.Models.Annotation;
public record Color
{
public int R { get; init; } = 0;
public int G { get; init; } = 0;
public int B { get; init; } = 0;
}

View File

@@ -0,0 +1,8 @@
namespace EnvelopeGenerator.Web.Models.Annotation;
public static class Extensions
{
public static double GetRight(this IAnnotation annotation) => annotation.Left + annotation?.Width ?? 0;
public static double GetBottom(this IAnnotation annotation) => annotation.Top + annotation?.Height ?? 0;
}

View File

@@ -0,0 +1,22 @@
namespace EnvelopeGenerator.Web.Models.Annotation;
public interface IAnnotation
{
string Name { get; }
double? Width { get; }
double? Height { get; }
double Left { get; }
double Top { get; }
Color? BackgroundColor { get; }
Color? BorderColor { get; }
string? BorderStyle { get; }
int? BorderWidth { get; }
}

View File

@@ -15,6 +15,7 @@ using DigitalData.EmailProfilerDispatcher;
using EnvelopeGenerator.Infrastructure; using EnvelopeGenerator.Infrastructure;
using EnvelopeGenerator.Web.Sanitizers; using EnvelopeGenerator.Web.Sanitizers;
using EnvelopeGenerator.Application.Contracts.Services; using EnvelopeGenerator.Application.Contracts.Services;
using EnvelopeGenerator.Web.Models.Annotation;
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger(); var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
logger.Info("Logging initialized!"); logger.Info("Logging initialized!");

View File

@@ -151,6 +151,21 @@
}, },
"MainPageTitle": null, "MainPageTitle": null,
"AnnotationParams": { "AnnotationParams": {
"Background": {
"Margin": 0.20,
"BackgroundColor": {
"R": 222,
"G": 220,
"B": 215
},
"BorderColor": {
"R": 204,
"G": 202,
"B": 198
},
"BorderStyle": "underline",
"BorderWidth": 4
},
"DefaultAnnotation": { "DefaultAnnotation": {
"Width": 1, "Width": 1,
"Height": 0.5, "Height": 0.5,

View File

@@ -6,14 +6,42 @@ async function createAnnotations(document, instance) {
const annotParams = await getAnnotationParams(element.left, element.top); const annotParams = await getAnnotationParams(element.left, element.top);
const page = element.page - 1 const page = element.page - 1
//background
if(annotParams.background){
let background = annotParams.background;
const id_background = PSPDFKit.generateInstantId();
const annotation_background = new PSPDFKit.Annotations.WidgetAnnotation({
id: id_background,
pageIndex: page,
formFieldName: id_background,
backgroundColor: background?.backgroundColor ? new PSPDFKit.Color(background.backgroundColor) : null,
blendMode: 'normal',
boundingBox: new PSPDFKit.Geometry.Rect(background),
fontSize: 8,
borderStyle: background.borderStyle,
borderWidth: background.borderWidth,
borderColor: background?.borderColor ? new PSPDFKit.Color(background.borderColor) : null
});
const formFieldBackground = new PSPDFKit.FormFields.ButtonFormField({
name: id_background,
annotationIds: PSPDFKit.Immutable.List([annotation_background.id]),
value: "",
readOnly: false
});
signatures.push(annotation_background)
signatures.push(formFieldBackground)
}
//signatures //signatures
const id = PSPDFKit.generateInstantId() const id = PSPDFKit.generateInstantId()
const annotation = new PSPDFKit.Annotations.WidgetAnnotation({ const annotation = new PSPDFKit.Annotations.WidgetAnnotation({
id: id, id: id,
pageIndex: page, pageIndex: page,
formFieldName: id, formFieldName: id,
backgroundColor: PSPDFKit.Color.YELLOW, backgroundColor: PSPDFKit.Color.LIGHT_YELLOW,
blendMode: 'multiply', blendMode: 'normal',
boundingBox: new PSPDFKit.Geometry.Rect(annotParams.signature), boundingBox: new PSPDFKit.Geometry.Rect(annotParams.signature),
}) })
@@ -29,7 +57,7 @@ async function createAnnotations(document, instance) {
pageIndex: page, pageIndex: page,
formFieldName: id_position, formFieldName: id_position,
backgroundColor: PSPDFKit.Color.DarkBlue, backgroundColor: PSPDFKit.Color.DarkBlue,
blendMode: 'multiply', blendMode: 'normal',
boundingBox: new PSPDFKit.Geometry.Rect(annotParams.position), boundingBox: new PSPDFKit.Geometry.Rect(annotParams.position),
fontSize: 8 fontSize: 8
}) })
@@ -48,7 +76,7 @@ async function createAnnotations(document, instance) {
pageIndex: page, pageIndex: page,
formFieldName: id_city, formFieldName: id_city,
backgroundColor: PSPDFKit.Color.DarkBlue, backgroundColor: PSPDFKit.Color.DarkBlue,
blendMode: 'multiply', blendMode: 'normal',
boundingBox: new PSPDFKit.Geometry.Rect(annotParams.city), boundingBox: new PSPDFKit.Geometry.Rect(annotParams.city),
fontSize: 8 fontSize: 8
}) })
@@ -67,7 +95,7 @@ async function createAnnotations(document, instance) {
pageIndex: page, pageIndex: page,
formFieldName: id_date, formFieldName: id_date,
backgroundColor: PSPDFKit.Color.DarkBlue, backgroundColor: PSPDFKit.Color.DarkBlue,
blendMode: 'multiply', blendMode: 'normal',
boundingBox: new PSPDFKit.Geometry.Rect(annotParams.date), boundingBox: new PSPDFKit.Geometry.Rect(annotParams.date),
fontSize: 8, fontSize: 8,
backgroundColor: PSPDFKit.Color.TRANSPARENT, backgroundColor: PSPDFKit.Color.TRANSPARENT,
@@ -97,7 +125,7 @@ async function createAnnotations(document, instance) {
id: id_date_label, id: id_date_label,
pageIndex: page, pageIndex: page,
formFieldName: id_date_label, formFieldName: id_date_label,
blendMode: 'multiply', blendMode: 'normal',
boundingBox: new PSPDFKit.Geometry.Rect(annotParams.datelabel), boundingBox: new PSPDFKit.Geometry.Rect(annotParams.datelabel),
fontSize: 8, fontSize: 8,
backgroundColor: PSPDFKit.Color.TRANSPARENT, backgroundColor: PSPDFKit.Color.TRANSPARENT,
@@ -119,7 +147,7 @@ async function createAnnotations(document, instance) {
id: id_city_label, id: id_city_label,
pageIndex: page, pageIndex: page,
formFieldName: id_city_label, formFieldName: id_city_label,
blendMode: 'multiply', blendMode: 'normal',
boundingBox: new PSPDFKit.Geometry.Rect(annotParams.citylabel), boundingBox: new PSPDFKit.Geometry.Rect(annotParams.citylabel),
fontSize: 8, fontSize: 8,
backgroundColor: PSPDFKit.Color.TRANSPARENT, backgroundColor: PSPDFKit.Color.TRANSPARENT,
@@ -131,7 +159,8 @@ async function createAnnotations(document, instance) {
name: id_city_label, name: id_city_label,
annotationIds: PSPDFKit.Immutable.List([annotation_city_label.id]), annotationIds: PSPDFKit.Immutable.List([annotation_city_label.id]),
value: "Ort", value: "Ort",
readOnly: true readOnly: true,
color: PSPDFKit.Color.BLACK
}) })
//position label //position label
@@ -140,7 +169,7 @@ async function createAnnotations(document, instance) {
id: id_position_label, id: id_position_label,
pageIndex: page, pageIndex: page,
formFieldName: id_position_label, formFieldName: id_position_label,
blendMode: 'multiply', blendMode: 'normal',
boundingBox: new PSPDFKit.Geometry.Rect(annotParams.positionlabel), boundingBox: new PSPDFKit.Geometry.Rect(annotParams.positionlabel),
fontSize: 8, fontSize: 8,
backgroundColor: PSPDFKit.Color.TRANSPARENT, backgroundColor: PSPDFKit.Color.TRANSPARENT,

View File

@@ -175,21 +175,21 @@ async function setLanguage(language) {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}) })
.then(res => res.json()) .then(res => res.json())
.then(langs => langs.includes(language)) .then(langs => langs.includes(language))
.catch(err => false); .catch(err => false);
if(hasLang) if (hasLang)
return await fetch(`/lang/${language}`, { return await fetch(`/lang/${language}`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' } headers: { 'Content-Type': 'application/json' }
}) })
.then(response => { .then(response => {
if (response.redirected) if (response.redirected)
window.location.href = response.url; window.location.href = response.url;
else if (!response.ok) else if (!response.ok)
return Promise.reject('Failed to set language'); return Promise.reject('Failed to set language');
}); });
} }
async function logout() { async function logout() {
@@ -204,22 +204,23 @@ async function logout() {
}); });
} }
function getAnnotationParams(leftInInch = 0, topInInch = 0, inchToPointFactor = 72) {
return fetch(`${window.location.origin}/api/Config/Annotations`, { async function getAnnotationParams(leftInInch = 0, topInInch = 0, inchToPointFactor = 72) {
const annotParams = await fetch(`${window.location.origin}/api/Config/Annotations`, {
credentials: 'include', credentials: 'include',
method: 'GET' method: 'GET'
}) })
.then(res => res.json()) .then(res => res.json());
.then(annotParams => {
for(var key in annotParams){ for (var key in annotParams) {
var annot = annotParams[key]; var annot = annotParams[key];
annot.width *= inchToPointFactor; annot.width *= inchToPointFactor;
annot.height *= inchToPointFactor; annot.height *= inchToPointFactor;
annot.left += leftInInch; annot.left += leftInInch - 0.7;
annot.left *= inchToPointFactor; annot.left *= inchToPointFactor;
annot.top += topInInch; annot.top += topInInch - 0.5;
annot.top *= inchToPointFactor; annot.top *= inchToPointFactor;
} }
return annotParams; return annotParams;
});
} }

View File

@@ -1 +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")})}async function logout(){return await fetch(`/auth/logout`,{method:"POST",headers:{"Content-Type":"application/json"}}).then(n=>{n.ok&&(window.location.href="/")})}function getAnnotationParams(n=0,t=0,i=72){return fetch(`${window.location.origin}/api/Config/Annotations`,{credentials:"include",method:"GET"}).then(n=>n.json()).then(r=>{var f,u;for(f in r)u=r[f],u.width*=i,u.height*=i,u.left+=n,u.left*=i,u.top+=t,u.top*=i;return r})}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){const t=this.getCSRFToken(),i={credentials:"include",method:"GET",headers:{...t}};return 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}} 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")})}async function logout(){return await fetch(`/auth/logout`,{method:"POST",headers:{"Content-Type":"application/json"}}).then(n=>{n.ok&&(window.location.href="/")})}async function getAnnotationParams(n=0,t=0,i=72){var f,r;const u=await fetch(`${window.location.origin}/api/Config/Annotations`,{credentials:"include",method:"GET"}).then(n=>n.json());for(f in u)r=u[f],r.width*=i,r.height*=i,r.left+=n-.7,r.left*=i,r.top+=t-.5,r.top*=i;return u}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){const t=this.getCSRFToken(),i={credentials:"include",method:"GET",headers:{...t}};return 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}}