Compare commits

...

10 Commits

5 changed files with 173 additions and 96 deletions

View File

@@ -16,7 +16,7 @@
}, },
"AdminPassword": "dd", "AdminPassword": "dd",
"PSPDFKitLicenseKey_SignFlow": "y8VgCpBgUfNlpKJZC-GwjpPs-S-KFBHv4RywfHbqpBAbO0XxRuWDaMGZtIaMrXBDlndlJLk---Ve93xjI_ZR4sbFymf4Ot97yTYUMeDdL2LYXhspkEnSAtkXf9zqepNL1v_0DMibjpqXFQMkVB1y3D5xdnOg-iJuCCZEMhZ780qg04_H_nmx63uSgxjN0GJxC8YvsbnRcUZ2l_idImMvWL0HMqB5B7oEpNenasA0RK0uapFRTa7NIQok0phpTHZYKB4qvj7od2yxlytGB7qBl4-lwT70DSQ9mrLkCWbuzZ9cV9D8fDzdFXr6WoZdOYpkrUadRbsy2bhPq_ukxszDWN4JGhebo0XKUK_YfgvSlS7lFOxHNblHeC9B7gZ8T-VuQ_z1QA2JYRf1dmhSuclnW00diShIg-N0I79PWGsQE4j40XtVpyWcN9uT9hMuiRpL0LzHV4YgsgBrgKgs_moqL7f0L4-MwaS25Dx4Wcz4ttKaerLavwMM4CJHI3DNqTC5UUEG6EViFxBQtrmuAS7kiw2nWjvXO7kUA24NARtsRCphjWE4l6wSMdh7kpqhfbV7_hdb5xXYGALNPkv8En6zPpFIew8DDcOH9dgxfKMI34LLhkEWqovZW_7fXNJTEIHVpR0DSPbZrmyEwkECnbDcNzjyFk2M1fzstJj_dSotyZvS57XJK2DgojbRgXL9pncs", "PSPDFKitLicenseKey_SignFlow": "y8VgCpBgUfNlpKJZC-GwjpPs-S-KFBHv4RywfHbqpBAbO0XxRuWDaMGZtIaMrXBDlndlJLk---Ve93xjI_ZR4sbFymf4Ot97yTYUMeDdL2LYXhspkEnSAtkXf9zqepNL1v_0DMibjpqXFQMkVB1y3D5xdnOg-iJuCCZEMhZ780qg04_H_nmx63uSgxjN0GJxC8YvsbnRcUZ2l_idImMvWL0HMqB5B7oEpNenasA0RK0uapFRTa7NIQok0phpTHZYKB4qvj7od2yxlytGB7qBl4-lwT70DSQ9mrLkCWbuzZ9cV9D8fDzdFXr6WoZdOYpkrUadRbsy2bhPq_ukxszDWN4JGhebo0XKUK_YfgvSlS7lFOxHNblHeC9B7gZ8T-VuQ_z1QA2JYRf1dmhSuclnW00diShIg-N0I79PWGsQE4j40XtVpyWcN9uT9hMuiRpL0LzHV4YgsgBrgKgs_moqL7f0L4-MwaS25Dx4Wcz4ttKaerLavwMM4CJHI3DNqTC5UUEG6EViFxBQtrmuAS7kiw2nWjvXO7kUA24NARtsRCphjWE4l6wSMdh7kpqhfbV7_hdb5xXYGALNPkv8En6zPpFIew8DDcOH9dgxfKMI34LLhkEWqovZW_7fXNJTEIHVpR0DSPbZrmyEwkECnbDcNzjyFk2M1fzstJj_dSotyZvS57XJK2DgojbRgXL9pncs",
"UseCSPInDev": true, "UseCSPInDev": false,
"Content-Security-Policy": [ // The first format parameter {0} will be replaced by the nonce value. "Content-Security-Policy": [ // The first format parameter {0} will be replaced by the nonce value.
"default-src 'self'", "default-src 'self'",
"script-src 'self' 'nonce-{0}' 'unsafe-inline' 'unsafe-eval' blob: data:", "script-src 'self' 'nonce-{0}' 'unsafe-inline' 'unsafe-eval' blob: data:",

View File

@@ -1,77 +1,30 @@
class Annotation { class Annotation {
createAnnotations(document) { static async createAnnotations(document) {
const annotations = [] const signatures = []
document.elements.forEach((element) => { for(var element of document.elements){
const [annotation, formField] = this.createAnnotationFromElement(element) const [annotation, formField, annotation2, formFieldDate] = await Annotation.createSignature(element)
annotations.push(annotation) signatures.push(annotation)
annotations.push(formField) signatures.push(formField)
}) signatures.push(annotation2)
signatures.push(formFieldDate)
}
return annotations return [...signatures ]
} }
async getAnnotations(instance) { static async createSignature(element) {
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), [])
)
}
async deleteAnnotations(instance) {
const allAnnotations = await this.getAnnotations(instance)
const pageAnnotations = allAnnotations.filter(this.isSignature)
//deleting all Annotations
return await instance.delete(pageAnnotations)
}
async validateAnnotations(instance) {
const allAnnotations = await this.getAnnotations(instance)
const pageAnnotations = allAnnotations
.map((annotation) => {
return annotation
})
return true
}
isSignature(annotation) {
return !!annotation.isSignature || annotation.description == 'FRAME'
}
createAnnotationFromElement(element) {
const id = PSPDFKit.generateInstantId() const id = PSPDFKit.generateInstantId()
const width = this.inchToPoint(element.width) const width = Annotation.inchToPoint(element.width)
const height = this.inchToPoint(element.height) const height = Annotation.inchToPoint(element.height)
const top = this.inchToPoint(element.top) - height / 2 const top = Annotation.inchToPoint(element.top) - height / 2
const left = this.inchToPoint(element.left) - width / 2 const left = Annotation.inchToPoint(element.left) - width / 2
const page = element.page - 1 const page = element.page - 1
const annotation = this.createSignatureAnnotation(
id,
width,
height,
top,
left,
page
)
const formField = new PSPDFKit.FormFields.SignatureFormField({ //signatures
name: id,
annotationIds: PSPDFKit.Immutable.List([annotation.id]),
})
return [annotation, formField]
}
createSignatureAnnotation(id, width, height, top, left, pageIndex) {
const annotation = new PSPDFKit.Annotations.WidgetAnnotation({ const annotation = new PSPDFKit.Annotations.WidgetAnnotation({
id: id, id: id,
pageIndex: pageIndex, pageIndex: page,
formFieldName: id, formFieldName: id,
backgroundColor: PSPDFKit.Color.YELLOW, backgroundColor: PSPDFKit.Color.YELLOW,
blendMode: 'multiply', blendMode: 'multiply',
@@ -83,10 +36,107 @@
}), }),
}) })
return annotation const formField = new PSPDFKit.FormFields.SignatureFormField({
name: id,
annotationIds: PSPDFKit.Immutable.List([annotation.id]),
})
//date
var city = await getCity();
const id_date = PSPDFKit.generateInstantId()
const annotation_date = new PSPDFKit.Annotations.WidgetAnnotation({
id: id_date,
pageIndex: page,
formFieldName: id_date,
backgroundColor: PSPDFKit.Color.DarkBlue,
blendMode: 'multiply',
boundingBox: new PSPDFKit.Geometry.Rect({
width: width * 1.5,
height: height / 2,
top: top + height + 25,
left: left - width * .25,
}),
fontSize:8
})
const formFieldDate = new PSPDFKit.FormFields.TextFormField({
name: id_date,
annotationIds: PSPDFKit.Immutable.List([annotation_date.id]),
value: getLocaleDateString() + ", " + city
})
return [annotation, formField, annotation_date, formFieldDate]
} }
createImageAnnotation(boundingBox, pageIndex, imageAttachmentId) { static createTextBox(element) {
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,
formFieldName: id,
backgroundColor: PSPDFKit.Color.YELLOW,
blendMode: 'multiply',
boundingBox: new PSPDFKit.Geometry.Rect({
width,
height,
top,
left,
}),
})
const formField = new PSPDFKit.FormFields.SignatureFormField({
name: id,
annotationIds: PSPDFKit.Immutable.List([annotation.id]),
})
return [annotation, formField]
}
static createText
static async 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), [])
)
}
static async deleteAnnotations(instance) {
const allAnnotations = await Annotation.getAnnotations(instance)
const pageAnnotations = allAnnotations.filter(Annotation.isSignature)
//deleting all Annotations
return await instance.delete(pageAnnotations)
}
static async validateAnnotations(instance) {
const allAnnotations = await Annotation.getAnnotations(instance)
const pageAnnotations = allAnnotations
.map((annotation) => {
return annotation
})
return true
}
static isSignature(annotation) {
return !!annotation.isSignature || annotation.description == 'FRAME'
}
static createImageAnnotation(boundingBox, pageIndex, imageAttachmentId) {
const frameAnnotation = new PSPDFKit.Annotations.ImageAnnotation({ const frameAnnotation = new PSPDFKit.Annotations.ImageAnnotation({
pageIndex: pageIndex, pageIndex: pageIndex,
isSignature: false, isSignature: false,
@@ -101,7 +151,7 @@
return frameAnnotation return frameAnnotation
} }
async createAnnotationFrameBlob(receiverName, receiverSignature, timestamp, width, height) { static async createAnnotationFrameBlob(receiverName, receiverSignature, timestamp, width, height) {
const canvas = document.createElement('canvas') const canvas = document.createElement('canvas')
const scale = 4 const scale = 4
const fontSize = 10 const fontSize = 10
@@ -154,7 +204,7 @@
}) })
} }
inchToPoint(inch) { static inchToPoint(inch) {
return inch * 72 return inch * 72
} }
} }

View File

@@ -14,9 +14,7 @@ class App {
this.container = container ?? `#${this.constructor.name.toLowerCase()}`; this.container = container ?? `#${this.constructor.name.toLowerCase()}`;
this.envelopeKey = envelopeKey this.envelopeKey = envelopeKey
this.UI = new UI()
this.Network = new Network() this.Network = new Network()
this.Annotation = new Annotation()
this.Instance = null this.Instance = null
this.currentDocument = null this.currentDocument = null
@@ -49,8 +47,8 @@ class App {
const arrayBuffer = this.documentBytes const arrayBuffer = this.documentBytes
// Load PSPDFKit // Load PSPDFKit
this.Instance = await this.UI.loadPSPDFKit(arrayBuffer, this.container, this.licenseKey, this.locale) this.Instance = await UI.loadPSPDFKit(arrayBuffer, this.container, this.licenseKey, this.locale)
this.UI.configurePSPDFKit(this.Instance, this.handleClick.bind(this)) UI.configurePSPDFKit(this.Instance, this.handleClick.bind(this))
this.Instance.addEventListener( this.Instance.addEventListener(
'annotations.load', 'annotations.load',
@@ -72,9 +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
const annotations = this.Annotation.createAnnotations( const annotations = await Annotation.createAnnotations(this.currentDocument)
this.currentDocument
)
await this.Instance.create(annotations) await this.Instance.create(annotations)
const openResponse = await this.Network.openDocument(this.envelopeKey) const openResponse = await this.Network.openDocument(this.envelopeKey)
@@ -113,7 +109,7 @@ class App {
const height = 75 const height = 75
const timestamp = new Date() const timestamp = new Date()
const imageUrl = await this.Annotation.createAnnotationFrameBlob( const imageUrl = await Annotation.createAnnotationFrameBlob(
this.envelopeReceiver.name, this.envelopeReceiver.name,
this.currentReceiver.signature, this.currentReceiver.signature,
timestamp, timestamp,
@@ -125,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 = this.Annotation.createImageAnnotation( const frameAnnotation = Annotation.createImageAnnotation(
new PSPDFKit.Geometry.Rect({ new PSPDFKit.Geometry.Rect({
left: left, left: left,
top: top, top: top,
@@ -247,7 +243,7 @@ class App {
async validateAnnotations(totalSignatures) { async validateAnnotations(totalSignatures) {
const annotations = await this.Annotation.getAnnotations(this.Instance) const annotations = await Annotation.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)
@@ -268,7 +264,7 @@ class App {
}) })
if (result.isConfirmed) { if (result.isConfirmed) {
const result = await this.Annotation.deleteAnnotations(this.Instance) const result = await Annotation.deleteAnnotations(this.Instance)
} }
return result return result

View File

@@ -1,5 +1,5 @@
class UI { class UI {
allowedToolbarItems = [ static allowedToolbarItems = [
'sidebar-thumbnails', 'sidebar-thumbnails',
'sidebar-document-ouline', 'sidebar-document-ouline',
'sidebar-bookmarks', 'sidebar-bookmarks',
@@ -14,14 +14,14 @@
// Load the PSPDFKit UI by setting a target element as the container to render in // Load the PSPDFKit UI by setting a target element as the container to render in
// and a arraybuffer which represents the document that should be displayed. // and a arraybuffer which represents the document that should be displayed.
loadPSPDFKit(arrayBuffer, container, licenseKey, locale) { static loadPSPDFKit(arrayBuffer, container, licenseKey, locale) {
return PSPDFKit.load({ return PSPDFKit.load({
locale: locale, locale: locale,
licenseKey: licenseKey, licenseKey: licenseKey,
styleSheets: ['/css/site.css'], styleSheets: ['/css/site.css'],
container: container, container: container,
document: arrayBuffer, document: arrayBuffer,
annotationPresets: this.getPresets(), annotationPresets: UI.getPresets(),
electronicSignatures: { electronicSignatures: {
creationModes: ['DRAW', 'TYPE', 'IMAGE'], creationModes: ['DRAW', 'TYPE', 'IMAGE'],
}, },
@@ -40,35 +40,35 @@
//return !annotation.isSignature; //return !annotation.isSignature;
}, },
customRenderers: { customRenderers: {
Annotation: this.annotationRenderer, Annotation: UI.annotationRenderer,
}, },
}) })
} }
configurePSPDFKit(instance, handler) { static configurePSPDFKit(instance, handler) {
const toolbarItems = this.getToolbarItems(instance, handler) const toolbarItems = UI.getToolbarItems(instance, handler)
instance.setToolbarItems(toolbarItems) instance.setToolbarItems(toolbarItems)
} }
annotationRenderer(data) { static annotationRenderer(data) {
// leave everything as is // leave everything as is
return null return null
} }
getToolbarItems(instance, handler) { static getToolbarItems(instance, handler) {
const customItems = this.getCustomItems(handler) const customItems = UI.getCustomItems(handler)
const defaultItems = this.getDefaultItems(instance.toolbarItems) const defaultItems = UI.getDefaultItems(instance.toolbarItems)
return defaultItems.concat(customItems) return defaultItems.concat(customItems)
} }
createElementFromHTML(html) { static createElementFromHTML(html) {
const el = document.createElement('div') const el = document.createElement('div')
el.innerHTML = html.trim() el.innerHTML = html.trim()
return el.firstChild return el.firstChild
} }
getCustomItems = function (callback) { static getCustomItems = function (callback) {
return [] return []
return [ return [
{ {
@@ -108,11 +108,11 @@
] ]
} }
getDefaultItems(items) { static getDefaultItems(items) {
return items.filter((item) => this.allowedToolbarItems.includes(item.type)) return items.filter((item) => UI.allowedToolbarItems.includes(item.type))
} }
getPresets() { static getPresets() {
const annotationPresets = PSPDFKit.defaultAnnotationPresets const annotationPresets = PSPDFKit.defaultAnnotationPresets
annotationPresets.ink = { annotationPresets.ink = {
lineWidth: 10, lineWidth: 10,

View File

@@ -1 +1,32 @@
const B64ToBuff = (base64String) => new Uint8Array(Array.from(atob(base64String), char => char.charCodeAt(0))).buffer; const B64ToBuff = (base64String) => new Uint8Array(Array.from(atob(base64String), char => char.charCodeAt(0))).buffer;
function getCoordinates() {
return new Promise((resolve, reject) => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
position => resolve(position.coords),
error => reject(error)
);
} else {
reject(new Error("Geolocation is not supported by this browser."));
}
});
}
async function getCity() {
try {
const coords = await getCoordinates();
const response = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${coords.latitude}&lon=${coords.longitude}`);
const data = await response.json();
if (data && data.address) {
const city = data.address.city || data.address.town || data.address.village || data.address.hamlet;
const postalCode = data.address.postcode;
return postalCode + ' ' + city || '';
}
} catch {
return '';
}
}
const getLocaleDateString = _ => new Date().toLocaleDateString('de-DE')