Compare commits

...

5 Commits

7 changed files with 204 additions and 178 deletions

View File

@@ -48,20 +48,33 @@ Public Class frmFinalizePDF
End Function End Function
Private Function ReadEnvelope(ByVal pEnvID As Integer) As Byte()
Dim strSql As String = "Select [BYTE_DATA] from [TBSIG_ENVELOPE_DOCUMENT] WHERE ENVELOPE_ID = " & pEnvID
Dim obyteDB = Database.GetScalarValue(strSql)
If Not IsDBNull(obyteDB) Then
Dim fileData As Byte() = DirectCast(Database.GetScalarValue(strSql), Byte())
If fileData IsNot Nothing Then
Return fileData
End If
End If
Throw New InvalidOperationException($"Byte data is null. Envelope ID: {pEnvID}")
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try Try
Dim oDocumentPath = LoadEnvelopeDocument()
Dim oFileInfo = New FileInfo(oDocumentPath)
Dim oTable = LoadAnnotationDataForEnvelope() Dim oTable = LoadAnnotationDataForEnvelope()
Dim oJsonList = oTable.Rows. Dim oJsonList = oTable.Rows.
Cast(Of DataRow). Cast(Of DataRow).
Select(Function(r As DataRow) r.Item("VALUE").ToString()). Select(Function(r As DataRow) r.Item("VALUE").ToString()).
ToList() ToList()
Dim oBuffer As Byte() = File.ReadAllBytes(oDocumentPath) Dim oBuffer As Byte() = ReadEnvelope(CInt(txtEnvelope.Text))
Dim oNewBuffer = PDFBurner.BurnInstantJSONAnnotationsToPDF(oBuffer, oJsonList) Dim oNewBuffer = PDFBurner.BurnInstantJSONAnnotationsToPDF(oBuffer, oJsonList)
Dim oNewPath = Path.Combine(oFileInfo.Directory.FullName, $"{oFileInfo.Name}.burned.pdf") Dim desktopPath As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
Dim oNewPath = Path.Combine(desktopPath, $"E{txtEnvelope.Text}R{txtReceiver.Text}.burned.pdf")
File.WriteAllBytes(oNewPath, oNewBuffer) File.WriteAllBytes(oNewPath, oNewBuffer)
Catch ex As Exception Catch ex As Exception

View File

@@ -1,5 +1,4 @@
using AngleSharp.Common; using EnvelopeGenerator.Web.Models;
using EnvelopeGenerator.Web.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@@ -19,6 +18,6 @@ public class ConfigController : ControllerBase
[HttpGet("Annotations")] [HttpGet("Annotations")]
public IActionResult GetAnnotationParams() public IActionResult GetAnnotationParams()
{ {
return Ok(_annotParams.Annotations.ToDictionary(a => a.Name.ToLower(), a => a)); return Ok(_annotParams.AnnotationDictionary);
} }
} }

View File

@@ -48,6 +48,10 @@ public class AnnotationParams
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);
} }
} }
public Dictionary<string, Annotation> AnnotationDictionary { get; private init; } = new();
} }

View File

@@ -162,32 +162,46 @@
"MarginTop": 0 "MarginTop": 0
}, },
{ {
"Name": "CityLabel", "Name": "PositionLabel",
"VerBoundAnnotName": "Signature", "VerBoundAnnotName": "Signature",
"WidthRatio": 1.2, "WidthRatio": 1.2,
"HeightRatio": 0.5, "HeightRatio": 0.5,
"MarginTopRatio": 0.25 "MarginTopRatio": 0.22
},
{
"Name": "Position",
"VerBoundAnnotName": "PositionLabel",
"WidthRatio": 1.2,
"HeightRatio": 0.5,
"MarginTopRatio": -0.05
},
{
"Name": "CityLabel",
"VerBoundAnnotName": "Position",
"WidthRatio": 1.2,
"HeightRatio": 0.5,
"MarginTopRatio": 0.05
}, },
{ {
"Name": "City", "Name": "City",
"VerBoundAnnotName": "CityLabel", "VerBoundAnnotName": "CityLabel",
"WidthRatio": 1.2, "WidthRatio": 1.2,
"HeightRatio": 0.5, "HeightRatio": 0.5,
"MarginTopRatio": 0 "MarginTopRatio": -0.05
}, },
{ {
"Name": "DateLabel", "Name": "DateLabel",
"VerBoundAnnotName": "City", "VerBoundAnnotName": "City",
"WidthRatio": 1.55, "WidthRatio": 1.55,
"HeightRatio": 0.5, "HeightRatio": 0.5,
"MarginTopRatio": 0.10 "MarginTopRatio": 0.05
}, },
{ {
"Name": "Date", "Name": "Date",
"VerBoundAnnotName": "DateLabel", "VerBoundAnnotName": "DateLabel",
"WidthRatio": 1.55, "WidthRatio": 1.55,
"HeightRatio": 0.5, "HeightRatio": 0.5,
"MarginTopRatio": 0 "MarginTopRatio": -0.1
} }
] ]
} }

View File

@@ -1,27 +1,8 @@
class Annotation {
static async createAnnotations(document, instance) { async function createAnnotations(document, instance) {
const signatures = [] const signatures = [];
for (var element of document.elements) { for(var element of document.elements) {
const [annotation, formField, annotation_date, formFieldDate, annotation_city, formFieldCity, annotation_date_label, formFieldDateLabel, annotation_city_label, formFieldCityLabel] = await Annotation.createSignature(element)
signatures.push(annotation)
signatures.push(formField)
signatures.push(annotation_date)
signatures.push(formFieldDate)
signatures.push(annotation_city)
signatures.push(formFieldCity)
signatures.push(annotation_date_label)
signatures.push(formFieldDateLabel)
signatures.push(annotation_city_label)
signatures.push(formFieldCityLabel)
}
await instance.create(signatures)
}
static async createSignature(element) {
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
@@ -41,10 +22,24 @@
annotationIds: PSPDFKit.Immutable.List([annotation.id]), annotationIds: PSPDFKit.Immutable.List([annotation.id]),
}) })
/** //position
* Date, post code and place text form part const id_position = PSPDFKit.generateInstantId()
*/ const annotation_position = new PSPDFKit.Annotations.WidgetAnnotation({
const date_place_top_shift = 9.5; id: id_position,
pageIndex: page,
formFieldName: id_position,
backgroundColor: PSPDFKit.Color.DarkBlue,
blendMode: 'multiply',
boundingBox: new PSPDFKit.Geometry.Rect(annotParams.position),
fontSize: 8
})
const formFieldPosition = new PSPDFKit.FormFields.TextFormField({
name: id_position,
annotationIds: PSPDFKit.Immutable.List([annotation_position.id]),
value: "",
readOnly: false
})
//city //city
const id_city = PSPDFKit.generateInstantId() const id_city = PSPDFKit.generateInstantId()
@@ -95,7 +90,6 @@
/** /**
* Date, post code and place label part * Date, post code and place label part
*/ */
const label_top_shift = -15
//date label //date label
const id_date_label = PSPDFKit.generateInstantId() const id_date_label = PSPDFKit.generateInstantId()
@@ -140,167 +134,169 @@
readOnly: true readOnly: true
}) })
return [annotation, formField, annotation_date, formFieldDate, annotation_city, formFieldCity, annotation_date_label, formFieldDateLabel, annotation_city_label, formFieldCityLabel] //position label
} const id_position_label = PSPDFKit.generateInstantId()
const annotation_position_label = new PSPDFKit.Annotations.WidgetAnnotation({
static createTextBox(element) { id: id_position_label,
const id = PSPDFKit.generateInstantId()
const width = Annotation.inchToPoint(element.width)
const height = Annotation.inchToPoint(element.height)
const top = Annotation.inchToPoint(element.top) - height / 2
const left = Annotation.inchToPoint(element.left) - width / 2
const page = element.page - 1
//shift
top += height + 10
const annotation = new PSPDFKit.Annotations.WidgetAnnotation({
id: id,
pageIndex: page, pageIndex: page,
formFieldName: id, formFieldName: id_position_label,
backgroundColor: PSPDFKit.Color.YELLOW,
blendMode: 'multiply', blendMode: 'multiply',
boundingBox: new PSPDFKit.Geometry.Rect({ boundingBox: new PSPDFKit.Geometry.Rect(annotParams.positionlabel),
width, fontSize: 8,
height, backgroundColor: PSPDFKit.Color.TRANSPARENT,
top, fontColor: PSPDFKit.Color.Black,
left, isBold: true,
}),
}) })
const formField = new PSPDFKit.FormFields.SignatureFormField({ const formFieldPositionLabel = new PSPDFKit.FormFields.TextFormField({
name: id, name: id_position_label,
annotationIds: PSPDFKit.Immutable.List([annotation.id]), annotationIds: PSPDFKit.Immutable.List([annotation_position_label.id]),
value: "Position",
readOnly: true
}) })
return [annotation, formField] signatures.push(annotation)
signatures.push(formField)
signatures.push(annotation_date)
signatures.push(formFieldDate)
signatures.push(annotation_city)
signatures.push(formFieldCity)
signatures.push(annotation_position)
signatures.push(formFieldPosition)
signatures.push(annotation_date_label)
signatures.push(formFieldDateLabel)
signatures.push(annotation_city_label)
signatures.push(formFieldCityLabel)
signatures.push(annotation_position_label)
signatures.push(formFieldPositionLabel)
} }
static async getAnnotations(instance) { await instance.create(signatures);
const array = await Promise.all( }
Array.from({ length: instance.totalPageCount }).map((_, pageIndex) =>
instance.getAnnotations(pageIndex) async function getAnnotations(instance) {
) const array = await Promise.all(
) Array.from({ length: instance.totalPageCount }).map((_, pageIndex) =>
instance.getAnnotations(pageIndex)
return array.flatMap((annotations) => )
annotations.reduce((acc, annotation) => acc.concat(annotation), []) )
)
} return array.flatMap((annotations) =>
annotations.reduce((acc, annotation) => acc.concat(annotation), [])
static async deleteAnnotations(instance) { )
const allAnnotations = await Annotation.getAnnotations(instance) }
const pageAnnotations = allAnnotations.filter(Annotation.isSignature)
//deleting all Annotations async function deleteAnnotations(instance) {
return await instance.delete(pageAnnotations) const allAnnotations = await getAnnotations(instance)
} const pageAnnotations = allAnnotations.filter(isSignature)
//deleting all Annotations
static async validateAnnotations(instance) { return await instance.delete(pageAnnotations)
const allAnnotations = await Annotation.getAnnotations(instance) }
const pageAnnotations = allAnnotations
.map((annotation) => { async function validateAnnotations(instance) {
return annotation const allAnnotations = await getAnnotations(instance)
}) const pageAnnotations = allAnnotations
.map((annotation) => {
return true return annotation
} })
static isSignature(annotation) { return true
return !!annotation.isSignature || annotation.description == 'FRAME' }
}
function isSignature(annotation) {
static createImageAnnotation(boundingBox, pageIndex, imageAttachmentId) { return !!annotation.isSignature || annotation.description == 'FRAME'
const frameAnnotation = new PSPDFKit.Annotations.ImageAnnotation({ }
pageIndex: pageIndex,
isSignature: false, function createImageAnnotation(boundingBox, pageIndex, imageAttachmentId) {
readOnly: true, const frameAnnotation = new PSPDFKit.Annotations.ImageAnnotation({
locked: true, pageIndex: pageIndex,
lockedContents: true, isSignature: false,
contentType: 'image/png', readOnly: true,
imageAttachmentId, locked: true,
description: 'FRAME', lockedContents: true,
boundingBox: boundingBox, contentType: 'image/png',
}) imageAttachmentId,
return frameAnnotation description: 'FRAME',
} boundingBox: boundingBox,
})
static async createAnnotationFrameBlob(receiverName, receiverSignature, timestamp, width, height) { return frameAnnotation
Comp.SignatureProgress.SignedCount += 1; }
const canvas = document.createElement('canvas')
const scale = 4 async function createAnnotationFrameBlob(receiverName, receiverSignature, timestamp, width, height) {
const fontSize = 10 Comp.SignatureProgress.SignedCount += 1;
const canvas = document.createElement('canvas')
canvas.width = width * scale const scale = 4
canvas.height = height * scale const fontSize = 10
const ctx = canvas.getContext('2d') canvas.width = width * scale
// This supposedly makes the lines and text less blurry canvas.height = height * scale
// See: https://stackoverflow.com/questions/8696631/canvas-drawings-like-lines-are-blurry
ctx.translate(0.5, 0.5) const ctx = canvas.getContext('2d')
// This supposedly makes the lines and text less blurry
// This also should make the lines and text less blurry // See: https://stackoverflow.com/questions/8696631/canvas-drawings-like-lines-are-blurry
ctx.textRendering = "geometricPrecision" ctx.translate(0.5, 0.5)
const date = timestamp // This also should make the lines and text less blurry
const dateString = date.toLocaleString('de-DE') ctx.textRendering = "geometricPrecision"
const signatureLength = 100 * scale const date = timestamp
const signatureString = receiverSignature.substring(0, 15) + "…" const dateString = date.toLocaleString('de-DE')
ctx.beginPath() const signatureLength = 100 * scale
const signatureString = receiverSignature.substring(0, 15) + "…"
ctx.moveTo(30 * scale, 10 * scale)
ctx.lineTo(signatureLength, 10 * scale) ctx.beginPath()
ctx.moveTo(30 * scale, 10 * scale) ctx.moveTo(30 * scale, 10 * scale)
ctx.arcTo(10 * scale, 10 * scale, 10 * scale, 30 * scale, 20 * scale) ctx.lineTo(signatureLength, 10 * scale)
ctx.moveTo(10 * scale, 30 * scale) ctx.moveTo(30 * scale, 10 * scale)
ctx.arcTo(10 * scale, 50 * scale, 30 * scale, 50 * scale, 20 * scale) ctx.arcTo(10 * scale, 10 * scale, 10 * scale, 30 * scale, 20 * scale)
ctx.moveTo(30 * scale, 50 * scale) ctx.moveTo(10 * scale, 30 * scale)
ctx.lineTo(signatureLength, 50 * scale) ctx.arcTo(10 * scale, 50 * scale, 30 * scale, 50 * scale, 20 * scale)
ctx.strokeStyle = 'darkblue' ctx.moveTo(30 * scale, 50 * scale)
ctx.stroke() ctx.lineTo(signatureLength, 50 * scale)
ctx.fillStyle = 'black' ctx.strokeStyle = 'darkblue'
ctx.font = `${fontSize * scale}px sans-serif` ctx.stroke()
ctx.fillText('Signed by', 15 * scale, 10 * scale)
ctx.fillText(receiverName, 15 * scale, 60 * scale) ctx.fillStyle = 'black'
ctx.fillText(signatureString, 15 * scale, 70 * scale) ctx.font = `${fontSize * scale}px sans-serif`
ctx.fillText('Signed by', 15 * scale, 10 * scale)
return new Promise((resolve) => { ctx.fillText(receiverName, 15 * scale, 60 * scale)
canvas.toBlob((blob) => { ctx.fillText(signatureString, 15 * scale, 70 * scale)
const url = URL.createObjectURL(blob)
resolve(url) return new Promise((resolve) => {
}) canvas.toBlob((blob) => {
}) const url = URL.createObjectURL(blob)
} resolve(url)
})
static inchToPoint(inch) { })
return inch * 72 }
}
//required
//required requiredFieldNames = new Array()
static #requiredFieldNames = new Array()
function markFieldAsRequired(formField) {
static markFieldAsRequired(formField) { requiredFieldNames.push(formField.name)
this.#requiredFieldNames.push(formField.name) }
}
function isFieldRequired(formField) {
static isFieldRequired(formField) { return requiredFieldNames.includes(formField.name)
return this.#requiredFieldNames.includes(formField.name) }
}
//city
//city cityFieldNames = new Array()
static #cityFieldNames = new Array()
function markFieldAsCity(formField) {
static markFieldAsCity(formField) { cityFieldNames.push(formField.name)
this.#cityFieldNames.push(formField.name) }
}
function isCityField(formField) {
static isCityField(formField) { return cityFieldNames.includes(formField.name)
return this.#cityFieldNames.includes(formField.name)
}
} }

View File

@@ -70,7 +70,7 @@ class App {
// Load annotations into PSPDFKit // Load annotations into PSPDFKit
try { try {
this.signatureCount = this.currentDocument.elements.length this.signatureCount = this.currentDocument.elements.length
await Annotation.createAnnotations(this.currentDocument, this.Instance) await createAnnotations(this.currentDocument, this.Instance)
const openResponse = await this.Network.openDocument(this.envelopeKey) const openResponse = await this.Network.openDocument(this.envelopeKey)
@@ -109,7 +109,7 @@ class App {
const height = 75 const height = 75
const timestamp = new Date() const timestamp = new Date()
const imageUrl = await Annotation.createAnnotationFrameBlob( const imageUrl = await createAnnotationFrameBlob(
this.envelopeReceiver.name, this.envelopeReceiver.name,
this.currentReceiver.signature, this.currentReceiver.signature,
timestamp, timestamp,
@@ -121,7 +121,7 @@ class App {
const blob = await request.blob() const blob = await request.blob()
const imageAttachmentId = await this.Instance.createAttachment(blob) const imageAttachmentId = await this.Instance.createAttachment(blob)
const frameAnnotation = Annotation.createImageAnnotation( const frameAnnotation = createImageAnnotation(
new PSPDFKit.Geometry.Rect({ new PSPDFKit.Geometry.Rect({
left: left, left: left,
top: top, top: top,
@@ -222,7 +222,7 @@ class App {
const iFormFieldValues = await iJSON.formFieldValues; const iFormFieldValues = await iJSON.formFieldValues;
//check required //check required
const iReqFields = iFormFieldValues.filter(f => Annotation.isFieldRequired(f)) const iReqFields = iFormFieldValues.filter(f => isFieldRequired(f))
const hasEmptyReq = iReqFields.some(f => (f.value === undefined || f.value === null || f.value === "")) const hasEmptyReq = iReqFields.some(f => (f.value === undefined || f.value === null || f.value === ""))
if (hasEmptyReq) { if (hasEmptyReq) {
@@ -236,7 +236,7 @@ class App {
//check city //check city
const city_regex = new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$") const city_regex = new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$")
const iCityFields = iFormFieldValues.filter(f => Annotation.isCityField(f)) const iCityFields = iFormFieldValues.filter(f => isCityField(f))
for (var f of iCityFields) for (var f of iCityFields)
if (!IS_MOBILE_DEVICE && !city_regex.test(f.value)) { if (!IS_MOBILE_DEVICE && !city_regex.test(f.value)) {
Swal.fire({ Swal.fire({
@@ -322,7 +322,7 @@ class App {
async validateAnnotations(totalSignatures) { async validateAnnotations(totalSignatures) {
const annotations = await Annotation.getAnnotations(this.Instance) const annotations = await getAnnotations(this.Instance)
const filtered = annotations const filtered = annotations
.map(a => a.toJS()) .map(a => a.toJS())
.filter(a => a.isSignature) .filter(a => a.isSignature)
@@ -343,7 +343,7 @@ class App {
}) })
if (result.isConfirmed) { if (result.isConfirmed) {
const result = await Annotation.deleteAnnotations(this.Instance) const result = await deleteAnnotations(this.Instance)
} }
return result return result

View File

@@ -1,3 +1,3 @@
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.addToolbarItems(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")));[...document.getElementsByClassName("btn_reject")].forEach(n=>n.addEventListener("click",()=>this.handleClick("REJECT")))}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);Comp.SignatureProgress.SignedCount=0;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":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(` 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.addToolbarItems(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 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")));[...document.getElementsByClassName("btn_reject")].forEach(n=>n.addEventListener("click",()=>this.handleClick("REJECT")))}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 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=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);Comp.SignatureProgress.SignedCount=0;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":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} Request failed: ${t}
`)}},allowOutsideClick:()=>!Swal.isLoading()}).then(n=>{if(n.isConfirmed){const t=n.value;t.ok?redirRejected():Swal.showValidationMessage(`Request failed: ${t.message}`)}});break;case"COPY_URL":const n=window.location.href.replace(/\/readonly/gi,"");navigator.clipboard.writeText(n).then(function(){bsNotify("Kopiert",{alert_type:"success",delay:4,icon_name:"check_circle"})}).catch(function(){bsNotify("Unerwarteter Fehler",{alert_type:"danger",delay:4,icon_name:"error"})});break;case"SHARE":Comp.ShareBackdrop.show();break;case"LOGOUT":await logout()}}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(!IS_MOBILE_DEVICE&&!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}} `)}},allowOutsideClick:()=>!Swal.isLoading()}).then(n=>{if(n.isConfirmed){const t=n.value;t.ok?redirRejected():Swal.showValidationMessage(`Request failed: ${t.message}`)}});break;case"COPY_URL":const n=window.location.href.replace(/\/readonly/gi,"");navigator.clipboard.writeText(n).then(function(){bsNotify("Kopiert",{alert_type:"success",delay:4,icon_name:"check_circle"})}).catch(function(){bsNotify("Unerwarteter Fehler",{alert_type:"danger",delay:4,icon_name:"error"})});break;case"SHARE":Comp.ShareBackdrop.show();break;case"LOGOUT":await logout()}}async handleFinish(){const n=await this.Instance.exportInstantJSON(),t=await n.formFieldValues,r=t.filter(n=>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=>isCityField(n));for(var i of e)if(!IS_MOBILE_DEVICE&&!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 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 deleteAnnotations(this.Instance)}return n}}