add prettier & format

This commit is contained in:
Jonathan Jenne 2023-11-20 10:59:28 +01:00
parent ea35ed0e29
commit 624266a971
6 changed files with 253 additions and 191 deletions

View File

@ -4,7 +4,7 @@
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"format": "npx prettier wwwroot/js --write"
},
"keywords": [],
"author": "",

View File

@ -1,58 +1,84 @@
class Annotation {
createAnnotations(document) {
const annotations = [];
const annotations = []
document.elements.forEach((element) => {
console.log("Creating annotation for element", element.id)
console.log('Creating annotation for element', element.id)
const [annotation, formField] = this.createAnnotationFromElement(element)
annotations.push(annotation);
annotations.push(formField);
const [annotation, formField] =
this.createAnnotationFromElement(element)
annotations.push(annotation)
annotations.push(formField)
})
return annotations;
return annotations
}
async deleteAnnotations(instance) {
let pageAnnotations = (
await Promise.all(Array.from({ length: instance.totalPageCount }).map((_, pageIndex) =>
instance.getAnnotations(pageIndex)
))
).flatMap((annotations) =>
annotations.reduce((acc, annotation) => acc.concat(annotation), [])
).filter((annotation) => !!annotation.isSignature || annotation.description == "FRAME");
await Promise.all(
Array.from({ length: instance.totalPageCount }).map(
(_, pageIndex) => instance.getAnnotations(pageIndex)
)
)
)
.flatMap((annotations) =>
annotations.reduce(
(acc, annotation) => acc.concat(annotation),
[]
)
)
.filter(
(annotation) =>
!!annotation.isSignature ||
annotation.description == 'FRAME'
)
//deleting all Annotations
return await instance.delete(pageAnnotations);
return await instance.delete(pageAnnotations)
}
async validateAnnotations(instance) {
let pageAnnotations = (
await Promise.all(Array.from({ length: instance.totalPageCount }).map((_, pageIndex) =>
instance.getAnnotations(pageIndex)
))
).flatMap((annotations) =>
annotations.reduce((acc, annotation) => acc.concat(annotation), [])
).map((annotation) => {
console.log(annotation.toJS());
return annotation;
});
await Promise.all(
Array.from({ length: instance.totalPageCount }).map(
(_, pageIndex) => instance.getAnnotations(pageIndex)
)
)
)
.flatMap((annotations) =>
annotations.reduce(
(acc, annotation) => acc.concat(annotation),
[]
)
)
.map((annotation) => {
console.log(annotation.toJS())
return annotation
})
return true;
return true
}
createAnnotationFromElement(element) {
const id = PSPDFKit.generateInstantId()
const width = this.inchToPoint(element.width)
const height = this.inchToPoint(element.height)
const top = this.inchToPoint(element.top) - (height / 2)
const left = this.inchToPoint(element.left) - (width / 2)
const top = this.inchToPoint(element.top) - height / 2
const left = this.inchToPoint(element.left) - width / 2
const page = element.page - 1
const annotation = this.createSignatureAnnotation(id, width, height, top, left, page)
const annotation = this.createSignatureAnnotation(
id,
width,
height,
top,
left,
page
)
console.log(annotation)
const formField = new PSPDFKit.FormFields.SignatureFormField({
name: id,
annotationIds: PSPDFKit.Immutable.List([annotation.id])
annotationIds: PSPDFKit.Immutable.List([annotation.id]),
})
console.log(formField)
@ -64,23 +90,32 @@
id: id,
pageIndex: pageIndex,
formFieldName: id,
boundingBox: new PSPDFKit.Geometry.Rect({ width, height, top, left })
boundingBox: new PSPDFKit.Geometry.Rect({
width,
height,
top,
left,
}),
})
return annotation
}
async createFrameAnnotation(annotation, receiver) {
const left = annotation.boundingBox.left - 25;
const top = annotation.boundingBox.top - 25;
const width = 150;
const height = 75;
const left = annotation.boundingBox.left - 25
const top = annotation.boundingBox.top - 25
const width = 150
const height = 75
const imageUrl = await this.Annotation.createAnnotationFrameBlob(receiver.name, width, height);
const request = await fetch(imageUrl);
const blob = await request.blob();
const imageUrl = await this.Annotation.createAnnotationFrameBlob(
receiver.name,
width,
height
)
const request = await fetch(imageUrl)
const blob = await request.blob()
const imageAttachmentId = await this.Instance.createAttachment(blob);
const imageAttachmentId = await this.Instance.createAttachment(blob)
const frameAnnotation = new PSPDFKit.Annotations.ImageAnnotation({
pageIndex: annotation.pageIndex,
isSignature: false,
@ -96,53 +131,52 @@
width: width,
height: height,
}),
});
})
}
async createAnnotationFrameBlob(receiverName, width, height) {
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const canvas = document.createElement('canvas')
canvas.width = width
canvas.height = height
const ctx = canvas.getContext("2d");
const ctx = canvas.getContext('2d')
const date = new Date();
const dateString = date.toLocaleDateString("de-DE");
const date = new Date()
const dateString = date.toLocaleDateString('de-DE')
const signatureLength = 100;
const signatureLength = 100
ctx.beginPath();
ctx.beginPath()
ctx.moveTo(30, 10);
ctx.lineTo(signatureLength, 10);
ctx.moveTo(30, 10)
ctx.lineTo(signatureLength, 10)
ctx.moveTo(30, 10);
ctx.arcTo(10, 10, 10, 30, 20);
ctx.moveTo(30, 10)
ctx.arcTo(10, 10, 10, 30, 20)
ctx.moveTo(10, 30);
ctx.arcTo(10, 50, 30, 50, 20);
ctx.moveTo(10, 30)
ctx.arcTo(10, 50, 30, 50, 20)
ctx.moveTo(30, 50);
ctx.lineTo(signatureLength, 50);
ctx.moveTo(30, 50)
ctx.lineTo(signatureLength, 50)
ctx.strokeStyle = "darkblue";
ctx.stroke();
ctx.strokeStyle = 'darkblue'
ctx.stroke()
ctx.fillStyle = "black";
ctx.font = "10px serif";
ctx.fillText("Signed by", 30, 10)
ctx.fillText(receiverName + ", " + dateString, 15, 60)
ctx.fillStyle = 'black'
ctx.font = '10px serif'
ctx.fillText('Signed by', 30, 10)
ctx.fillText(receiverName + ', ' + dateString, 15, 60)
return new Promise(resolve => {
return new Promise((resolve) => {
canvas.toBlob((blob) => {
const url = URL.createObjectURL(blob);
const url = URL.createObjectURL(blob)
resolve(url)
})
})
}
inchToPoint(inch) {
return inch * 72;
return inch * 72
}
}

View File

@ -6,153 +6,171 @@ const ActionType = {
Delivered: 4,
Seen: 5,
Signed: 6,
Rejected: 7
Rejected: 7,
}
class App {
constructor(container, envelopeKey) {
this.container = container;
this.envelopeKey = envelopeKey;
this.container = container
this.envelopeKey = envelopeKey
// Initialize classes
console.debug("Initializing classes..")
this.UI = new UI();
this.Network = new Network();
this.Annotation = new Annotation();
console.debug('Initializing classes..')
this.UI = new UI()
this.Network = new Network()
this.Annotation = new Annotation()
this.Instance = null;
this.currentDocument = null;
this.currentReceiver = null;
this.Instance = null
this.currentDocument = null
this.currentReceiver = null
}
// This function will be called in the ShowEnvelope.razor page
// and will trigger loading of the Editor Interface
async init() {
// Load the envelope from the database
console.debug("Loading envelope from database..")
const envelopeObject = await this.Network.getEnvelope(this.envelopeKey);
this.currentDocument = envelopeObject.envelope.documents[0];
this.currentReceiver = envelopeObject.receiver;
console.debug('Loading envelope from database..')
const envelopeObject = await this.Network.getEnvelope(this.envelopeKey)
this.currentDocument = envelopeObject.envelope.documents[0]
this.currentReceiver = envelopeObject.receiver
console.log(envelopeObject)
// Load the document from the filestore
console.debug("Loading document from filestore")
console.debug('Loading document from filestore')
let arrayBuffer
try {
arrayBuffer = await this.Network.getDocument(this.envelopeKey, this.currentDocument.id);
arrayBuffer = await this.Network.getDocument(
this.envelopeKey,
this.currentDocument.id
)
} catch (e) {
console.error(e)
}
// Load PSPDFKit
console.debug("Loading PSPDFKit..")
console.debug('Loading PSPDFKit..')
this.Instance = await this.UI.loadPSPDFKit(arrayBuffer, this.container)
this.UI.configurePSPDFKit(this.Instance, this.handleClick.bind(this))
this.Instance.addEventListener("annotations.load", this.handleAnnotationsLoad)
this.Instance.addEventListener("annotations.change", this.handleAnnotationsChange)
this.Instance.addEventListener("annotations.create", this.handleAnnotationsCreate.bind(this))
this.Instance.addEventListener(
'annotations.load',
this.handleAnnotationsLoad
)
this.Instance.addEventListener(
'annotations.change',
this.handleAnnotationsChange
)
this.Instance.addEventListener(
'annotations.create',
this.handleAnnotationsCreate.bind(this)
)
// Load annotations into PSPDFKit
console.debug("Loading annotations..")
console.debug('Loading annotations..')
try {
const annotations = this.Annotation.createAnnotations(this.currentDocument)
const annotations = this.Annotation.createAnnotations(
this.currentDocument
)
const createdAnnotations = await this.Instance.create(annotations)
await this.Network.postHistory(this.envelopeKey, ActionType.Seen)
} catch (e) {
console.error(e)
}
}
handleAnnotationsLoad(loadedAnnotations) {
console.log("annotations loaded", loadedAnnotations.toJS());
console.log('annotations loaded', loadedAnnotations.toJS())
}
handleAnnotationsChange() {}
async handleAnnotationsCreate(createdAnnotations) {
const annotation = createdAnnotations.toJS()[0];
const isFormField = !!annotation.formFieldName;
const isSignature = !!annotation.isSignature;
const annotation = createdAnnotations.toJS()[0]
const isFormField = !!annotation.formFieldName
const isSignature = !!annotation.isSignature
if (isFormField === false && isSignature === true) {
await this.Annotation.createFrameAnnotation(annotation, this.currentReceiver)
await this.Annotation.createFrameAnnotation(
annotation,
this.currentReceiver
)
}
}
async handleClick(eventType) {
let result = false;
let result = false
switch (eventType) {
case "RESET":
case 'RESET':
result = await this.handleReset(null)
if (result == true) {
alert("Dokument zurückgesetzt!");
alert('Dokument zurückgesetzt!')
} else {
alert("Fehler beim Zurücksetzen des Dokuments!")
alert('Fehler beim Zurücksetzen des Dokuments!')
}
break;
break
case "FINISH":
case 'FINISH':
result = await this.handleFinish(null)
if (result == true) {
// TODO: Redirect to success page
alert("Dokument erfolgreich signiert!")
alert('Dokument erfolgreich signiert!')
} else {
alert("Fehler beim Abschließen des Dokuments!")
alert('Fehler beim Abschließen des Dokuments!')
}
break;
break
}
}
async handleFinish(event) {
// Save changes before doing anything
try {
await this.Instance.save();
await this.Instance.save()
} catch (e) {
console.error(e);
return false;
console.error(e)
return false
}
// Export annotation data and save to database
try {
const json = await this.Instance.exportInstantJSON()
const postEnvelopeResult = await this.Network.postEnvelope(this.envelopeKey, this.currentDocument.id, JSON.stringify(json))
const postEnvelopeResult = await this.Network.postEnvelope(
this.envelopeKey,
this.currentDocument.id,
JSON.stringify(json)
)
if (postEnvelopeResult === false) {
return false;
return false
}
// Redirect to success page after saving to database
window.location.href = `/EnvelopeKey/${this.envelopeKey}/Success`
} catch (e) {
console.error(e);
return false;
console.error(e)
return false
}
return true;
return true
}
async handleReset(event) {
if (confirm("Wollen Sie das Dokument und alle erstellten Signaturen zurücksetzen?")) {
if (
confirm(
'Wollen Sie das Dokument und alle erstellten Signaturen zurücksetzen?'
)
) {
const result = this.Annotation.deleteAnnotations(this.Instance)
return true;
return true
} else {
return true;
return true
}
}
}

View File

@ -1,66 +1,72 @@
class Network {
getEnvelope(envelopeKey) {
return fetch(`/api/envelope/${envelopeKey}`, this.withCSRFToken({ credentials: "include" }))
.then(res => res.json());
return fetch(
`/api/envelope/${envelopeKey}`,
this.withCSRFToken({ credentials: 'include' })
).then((res) => res.json())
}
getDocument(envelopeKey, documentId) {
return fetch(`/api/document/${envelopeKey}?index=${documentId}`, this.withCSRFToken({ credentials: "include" }))
.then(res => res.arrayBuffer());
return fetch(
`/api/document/${envelopeKey}?index=${documentId}`,
this.withCSRFToken({ credentials: 'include' })
).then((res) => res.arrayBuffer())
}
postEnvelope(envelopeKey, documentId, jsonString) {
const url = `/api/envelope/${envelopeKey}?index=${documentId}`;
const url = `/api/envelope/${envelopeKey}?index=${documentId}`
const options = {
credentials: "include",
method: "POST",
body: jsonString
credentials: 'include',
method: 'POST',
body: jsonString,
}
console.debug("PostEnvelope/Calling url: " + url)
console.debug('PostEnvelope/Calling url: ' + url)
return fetch(url, this.withCSRFToken(options))
.then(this.handleResponse)
.then((res) => {
if (!res.ok) {
return false;
};
return true;
});
return false
}
return true
})
}
postHistory(envelopeKey, actionType) {
const url = `/api/history/${envelopeKey}`;
const url = `/api/history/${envelopeKey}`
const data = {
actionType: actionType
actionType: actionType,
}
const options = {
credentials: "include",
method: "POST",
credentials: 'include',
method: 'POST',
headers: {
'Content-Type': "application/json; charset=utf-8"
'Content-Type': 'application/json; charset=utf-8',
},
body: JSON.stringify(data)
body: JSON.stringify(data),
}
console.debug("PostHistory/Calling url: " + url)
console.debug('PostHistory/Calling url: ' + url)
return fetch(url, this.withCSRFToken(options))
.then(this.handleResponse)
.then((res) => {
if (!res.ok) {
return false;
};
return true;
});
return false
}
return true
})
}
withCSRFToken(options) {
const token = (document.getElementsByName("__RequestVerificationToken")[0]).value;
let headers = options.headers;
options.headers = { ...headers, 'X-XSRF-TOKEN': token };
const token = document.getElementsByName(
'__RequestVerificationToken'
)[0].value
let headers = options.headers
options.headers = { ...headers, 'X-XSRF-TOKEN': token }
return options;
return options
}
handleResponse(res) {
@ -72,4 +78,3 @@
}
}
}

View File

@ -1,15 +1,15 @@
class UI {
allowedToolbarItems = [
"sidebar-thumbnails",
"sidebar-document-ouline",
"sidebar-bookmarks",
"pager",
"pan",
"zoom-out",
"zoom-in",
"zoom-mode",
"spacer",
"search"
'sidebar-thumbnails',
'sidebar-document-ouline',
'sidebar-bookmarks',
'pager',
'pan',
'zoom-out',
'zoom-in',
'zoom-mode',
'spacer',
'search',
]
// Load the PSPDFKit UI by setting a target element as the container to render in
@ -19,24 +19,27 @@
styleSheets: ['/css/site.css'],
container: container,
document: arrayBuffer,
autoSaveMode: "DISABLED",
autoSaveMode: 'DISABLED',
annotationPresets: this.getPresets(),
electronicSignatures: {
creationModes: ["DRAW", "TYPE"]
creationModes: ['DRAW', 'TYPE'],
},
isEditableAnnotation: function (annotation) {
// Check if the annotation is a signature
// This will allow new signatures, but not allow edits.
console.log(annotation.isSignature, annotation.description)
if (annotation.isSignature || annotation.description == "FRAME") {
return false;
if (
annotation.isSignature ||
annotation.description == 'FRAME'
) {
return false
}
return true;
return true
//return !annotation.isSignature;
}
},
})
}
@ -44,7 +47,7 @@
const toolbarItems = this.getToolbarItems(instance, handler)
instance.setToolbarItems(toolbarItems)
console.debug("PSPDFKit configured!");
console.debug('PSPDFKit configured!')
}
getToolbarItems(instance, handler) {
@ -63,46 +66,48 @@
getCustomItems = function (callback) {
return [
{
type: "custom",
id: "button-reset",
className: "button-reset",
title: "Zurücksetzen",
type: 'custom',
id: 'button-reset',
className: 'button-reset',
title: 'Zurücksetzen',
onPress() {
console.log("RESET")
callback("RESET")
console.log('RESET')
callback('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>`
</svg>`,
},
{
type: "custom",
id: "button-finish",
className: "button-finish",
title: "Abschließen",
type: 'custom',
id: 'button-finish',
className: 'button-finish',
title: 'Abschließen',
onPress() {
console.log("FINISH")
callback("FINISH")
}
}
console.log('FINISH')
callback('FINISH')
},
},
]
}
getDefaultItems(items) {
return items.filter((item) => this.allowedToolbarItems.includes(item.type))
return items.filter((item) =>
this.allowedToolbarItems.includes(item.type)
)
}
getPresets() {
const annotationPresets = PSPDFKit.defaultAnnotationPresets;
const annotationPresets = PSPDFKit.defaultAnnotationPresets
annotationPresets.ink = {
lineWidth: 10
};
lineWidth: 10,
}
annotationPresets.widget = {
readOnly: true
readOnly: true,
}
return annotationPresets;
return annotationPresets
}
}