From a7771e22f9e32d8b005cb93991c674e102815e2f Mon Sep 17 00:00:00 2001
From: Christina Toegl <toegl@tugraz.at>
Date: Mon, 3 May 2021 12:50:20 +0200
Subject: [PATCH] Refactor PDF annotations according to review and fix several
 bugs

---
 src/dbp-official-signature-pdf-upload.js  |  9 ++-
 src/dbp-pdf-annotation-view.js            | 68 ++++++++++++++++++++++-
 src/dbp-qualified-signature-pdf-upload.js |  7 ++-
 src/dbp-signature-lit-element.js          | 34 +++++++++++-
 src/i18n/de/translation.json              | 16 ++++--
 src/i18n/en/translation.json              | 16 ++++--
 6 files changed, 133 insertions(+), 17 deletions(-)

diff --git a/src/dbp-official-signature-pdf-upload.js b/src/dbp-official-signature-pdf-upload.js
index 09b9c46..6c31368 100644
--- a/src/dbp-official-signature-pdf-upload.js
+++ b/src/dbp-official-signature-pdf-upload.js
@@ -52,8 +52,10 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem
         this.currentPreviewQueueKey = '';
         this.allowAnnotating = false;
         this.queuedFilesAnnotations = [];
-        this.queuedFilesEnabledAnnotations = [];
+        this.queuedFilesAnnotationModes = [];
         this.queuedFilesAnnotationsCount = 0;
+        this.queuedFilesAnnotationSaved = [];
+        this.queuedFilesEnabledAnnotations = [];
         this.isAnnotationViewVisible = false;
         this.addAnnotationInProgress = false;
         this.activity = new Activity(metadata);
@@ -105,6 +107,8 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem
             queuedFilesAnnotations: { type: Array, attribute: false },
             queuedFilesAnnotationsCount: { type: Number, attribute: false },
             addAnnotationInProgress: { type: Boolean, attribute: false },
+            queuedFilesAnnotationModes: { type: Array, attribute: false },
+            queuedFilesAnnotationSaved: { type: Array, attribute: false },
             showClipboard: { type: Boolean, attribute: 'show-clipboard' },
         };
     }
@@ -731,6 +735,7 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem
                             <dbp-textswitch id="annotation-switch" 
                                 name1="no-text"
                                 name2="text-selected"
+                                name="${this.queuedFilesAnnotationModes[id] || "no-text"}"
                                 class="${classMap({'switch': true})}"
                                 value1="${i18n.t('official-pdf-upload.annotation-no')}"
                                 value2="${i18n.t('official-pdf-upload.annotation-yes')}"
@@ -980,7 +985,7 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem
                             </div>
                             <dbp-pdf-annotation-view lang="${this.lang}"
                                              @dbp-pdf-annotations-save="${this.processAnnotationEvent}"
-                                             @dbp-pdf-annotations-cancel="${this.hideAnnotationView}"></dbp-pdf-annotation-view>
+                                             @dbp-pdf-annotations-cancel="${this.processAnnotationCancelEvent}"></dbp-pdf-annotation-view>
                         </div>
                         <!-- File upload progress -->
                         <div id="upload-progress" class="field notification is-info ${classMap({hidden: !this.uploadInProgress})}">
diff --git a/src/dbp-pdf-annotation-view.js b/src/dbp-pdf-annotation-view.js
index 46866ad..5d6e19e 100644
--- a/src/dbp-pdf-annotation-view.js
+++ b/src/dbp-pdf-annotation-view.js
@@ -5,6 +5,7 @@ import {ScopedElementsMixin} from '@open-wc/scoped-elements';
 import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
 import {MiniSpinner, Icon} from '@dbp-toolkit/common';
 import {OrganizationSelect} from "@dbp-toolkit/organization-select";
+import { send } from '@dbp-toolkit/common/notification';
 import * as commonStyles from '@dbp-toolkit/common/styles';
 import * as utils from './utils';
 
@@ -61,6 +62,9 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) {
 
     setAnnotationRows(rows) {
         this.annotationRows = rows ? rows : [];
+        if (this.annotationRows.length === 0) {
+            this.isTextHidden = false;
+        }
     }
 
     /**
@@ -69,18 +73,69 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) {
     deleteAll() {
         this.annotationRows = [];
         this.isTextHidden = false;
+        this.sendCancelEvent();
     }
 
     sendCancelEvent() {
+        console.log('cancel event called');
         const event = new CustomEvent("dbp-pdf-annotations-cancel",
             { "detail": {}, bubbles: true, composed: true });
         this.dispatchEvent(event);
     }
 
+    validateValues() {
+        
+        for (let annotation of this.annotationRows) {
+            const annotationTypeData = utils.getAnnotationTypes(annotation['annotationType']);
+
+            if (annotationTypeData['hasOrganization']) {
+                let organization = annotation.organizationValue;
+
+                if (typeof organization === 'undefined' || organization === null || organization === '') {
+                    send({
+                        "summary": i18n.t('annotation-view.empty-organization-title'),
+                        "body": i18n.t('annotation-view.empty-organization-message'),
+                        "type": "danger",
+                        "timeout": 5,
+                    });
+                    return false;
+                }
+            }
+
+            if (annotation['value'] === null || annotation['value'] === '') {
+                send({
+                    "summary": i18n.t('annotation-view.empty-annotation-title', {annotationType: annotationTypeData.name[this.lang]}),
+                    "body": i18n.t('annotation-view.empty-annotation-message'),
+                    "type": "danger",
+                    "timeout": 5,
+                });
+                return false;
+            }
+
+            const pattern = new RegExp('[A-Za-z0-9ÄäÖöÜüß\*\\/?! &@()=+_-]*');
+            let matchResult = annotation['value'].match(pattern);
+
+            if (matchResult[0] === undefined || annotation['value'].length !== matchResult[0].length) {
+                send({
+                    "summary": i18n.t('annotation-view.invalid-annotation-text-title'),
+                    "body": i18n.t('annotation-view.invalid-annotation-text-message'),
+                    "type": "danger",
+                    "timeout": 5,
+                });
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
      * Stores information to document
      */
     saveAll() {
+        if (!this.validateValues()) {
+            return;
+        }
+        
         const data = {
             "key": this.key,
             "annotationRows": this.annotationRows,
@@ -88,6 +143,10 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) {
         const event = new CustomEvent("dbp-pdf-annotations-save",
             { "detail": data, bubbles: true, composed: true });
         this.dispatchEvent(event);
+
+        if (this.annotationRows.length === 0) {
+            this.isTextHidden = false;
+        }
     }
 
     /**
@@ -137,6 +196,7 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) {
 
             if(this.annotationRows.length === 0) {
                 this.isTextHidden = false;
+                this.sendCancelEvent();
             }
 
             // we just need this so the UI will update
@@ -206,6 +266,8 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) {
 
             select:not(.select) {
                 background-size: 13px;
+                background-position-x: calc(100% - 0.4rem);
+                padding-right: 1.3rem;
                 height: 33px;
             }
 
@@ -306,7 +368,7 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) {
                                 this.updateAnnotation(id, 'organizationNumber', JSON.parse(e.target.getAttribute("data-object")).alternateName);
                             }}></dbp-organization-select>
 
-                    <input type="text" .value="${data.value}" class="input" 
+                    <input type="text" .value="${data.value}" class="input" pattern="[A-Za-z0-9ÄäÖöÜüß\*\\/! &@()=+_-]*" 
                             placeholder="${annotationTypeData.hasOrganization ? i18n.t('annotation-view.businessnumber-placeholder') : i18n.t('annotation-view.intended-use-placeholder')}" 
                             @change=${e => { this.updateAnnotation(id, 'value', e.target.value); }}>
                 </div>
@@ -348,13 +410,13 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) {
                 </div>
                 <div id="fields-wrapper">
                     <div id="inside-fields">
-                        <div class="text ${classMap({hidden: this.isTextHidden})}">
+                        <div class="text ${classMap({hidden: this.isTextHidden || this.annotationRows.length > 0})}">
                             <p>${i18n.t('annotation-view.introduction')}</p>
                         </div>
                         ${this.getAnnotationsHtml()}
                     </div>
                     <div class="delete-elements">
-                        <button class="button ${classMap({hidden: !this.isTextHidden})}"
+                        <button class="button ${classMap({hidden: !this.isTextHidden && this.annotationRows.length === 0})}"
                                 title="${i18n.t('annotation-view.delete-all-button-title')}"
                                 @click="${() => { this.deleteAll(); } }"
                                 ?disabled="${ this.annotationRows.length === 0 }">
diff --git a/src/dbp-qualified-signature-pdf-upload.js b/src/dbp-qualified-signature-pdf-upload.js
index 99f6919..e89518d 100644
--- a/src/dbp-qualified-signature-pdf-upload.js
+++ b/src/dbp-qualified-signature-pdf-upload.js
@@ -54,6 +54,8 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle
         this.allowAnnotating = false;
         this.queuedFilesAnnotations = [];
         this.queuedFilesAnnotationsCount = 0;
+        this.queuedFilesAnnotationModes = [];
+        this.queuedFilesAnnotationSaved = [];
         this.queuedFilesEnabledAnnotations = [];
         this.isAnnotationViewVisible = false;
         this.addAnnotationInProgress = false;
@@ -109,6 +111,8 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle
             queuedFilesAnnotations: { type: Array, attribute: false },
             queuedFilesAnnotationsCount: { type: Number, attribute: false },
             addAnnotationInProgress: { type: Boolean, attribute: false },
+            queuedFilesAnnotationModes: { type: Array, attribute: false },
+            queuedFilesAnnotationSaved: { type: Array, attribute: false },
         };
     }
 
@@ -877,6 +881,7 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle
                             <dbp-textswitch id="annotation-switch"
                                 name1="no-text"
                                 name2="text-selected"
+                                name="${this.queuedFilesAnnotationModes[id] || "no-text"}"
                                 class="${classMap({'switch': true})}"
                                 value1="${i18n.t('qualified-pdf-upload.annotation-no')}"
                                 value2="${i18n.t('qualified-pdf-upload.annotation-yes')}"
@@ -1142,7 +1147,7 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle
                             </div>
                             <dbp-pdf-annotation-view lang="${this.lang}"
                                              @dbp-pdf-annotations-save="${this.processAnnotationEvent}"
-                                             @dbp-pdf-annotations-cancel="${this.hideAnnotationView}"></dbp-pdf-annotation-view>
+                                             @dbp-pdf-annotations-cancel="${this.processAnnotationCancelEvent}"></dbp-pdf-annotation-view>
                         </div>
                         <!-- File upload progress -->
                         <div id="upload-progress" class="field notification is-info ${classMap({hidden: !this.uploadInProgress})}">
diff --git a/src/dbp-signature-lit-element.js b/src/dbp-signature-lit-element.js
index db0a3cf..5d16c4f 100644
--- a/src/dbp-signature-lit-element.js
+++ b/src/dbp-signature-lit-element.js
@@ -119,6 +119,10 @@ export default class DBPSignatureLitElement extends DBPSignatureBaseLitElement {
      * @returns shows PdfAnnotationView
      */
     async showAnnotationView(key, name) {
+
+        this.queuedFilesAnnotationModes[key] = name;
+        console.log(name);
+
         if (this.signingProcessEnabled) {
             return;
         }
@@ -135,10 +139,14 @@ export default class DBPSignatureLitElement extends DBPSignatureBaseLitElement {
             this._(viewTag).setAttribute('key', key);
             this._(viewTag).setAnnotationRows(this.queuedFilesAnnotations[key]);
 
+            console.log('in show: ', this.queuedFilesAnnotations[key]);
+            console.log('key: ', key);
+
             this.isAnnotationViewVisible = true;
             this.enableAnnotationsForKey(key);
         } else {
             this.disableAnnotationsForKey(key);
+            this.queuedFilesAnnotationSaved[key] = false;
 
             if (this.currentPreviewQueueKey === key) {
                 this.isAnnotationViewVisible = false;
@@ -158,13 +166,37 @@ export default class DBPSignatureLitElement extends DBPSignatureBaseLitElement {
 
         this.isAnnotationViewVisible = false;
         this.addAnnotationInProgress = false;
+
+        this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = "text-selected";
+        this.queuedFilesAnnotationSaved[this.currentPreviewQueueKey] = true;
+    }
+
+    /**
+     * 
+     * @param {*} event 
+     */
+    processAnnotationCancelEvent(event) {
+        let key = this.currentPreviewQueueKey;
+
+        this.queuedFilesAnnotations[key] = [];
+        this.queuedFilesAnnotations[key] = undefined;
+        this.disableAnnotationsForKey(key);
+
+        this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = "no-text";
+        this.queuedFilesAnnotationSaved[this.currentPreviewQueueKey] = false;
     }
 
     /**
      * Hides the PdfAnnotationView
      */
     hideAnnotationView() {
-        this._("#annotation-switch").name = "no-text";
+        console.log('hide view - x click');
+
+        if (this.queuedFilesAnnotationSaved[this.currentPreviewQueueKey] !== undefined && this.queuedFilesAnnotationSaved[this.currentPreviewQueueKey]) {
+            this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = "text-selected";
+        } else {
+            this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = "no-text";
+        }
         this.isAnnotationViewVisible = false;
         this.addAnnotationInProgress = false;
     }
diff --git a/src/i18n/de/translation.json b/src/i18n/de/translation.json
index 74bd5f8..027e998 100644
--- a/src/i18n/de/translation.json
+++ b/src/i18n/de/translation.json
@@ -30,10 +30,10 @@
     "file-picker-context": "PDF-Dokumente zum Signieren auswählen",
     "add-annotation-title": "Dem PDF eine Kennzahl hinzufügen",
     "annotation-type-please-select": "Bitte wählen Sie einen Typ aus",
-    "annotation": "Text hinzufügen",
+    "annotation": "Anmerkungen",
     "annotation-no": "Nein",
     "annotation-yes": "Ja",
-    "annotation-view-label": "Text zu Dokument hinzufügen"
+    "annotation-view-label": "Anmerkungen zu Dokument hinzufügen"
   },
   "qualified-pdf-upload": {
     "save-field-label": "{{count}} Datei speichern",
@@ -67,10 +67,10 @@
     "positioning": "Positionierung",
     "confirm-page-leave": "Sind Sie sicher, dass Sie die Seite verlassen wollen? Es stehen signierte Dokumente zum Download bereit.",
     "file-picker-context": "PDF-Dokumente zum Signieren auswählen",
-    "annotation": "Text hinzufügen",
+    "annotation": "Anmerkungen",
     "annotation-no": "Nein",
     "annotation-yes": "Ja",
-    "annotation-view-label": "Text zu Dokument hinzufügen"
+    "annotation-view-label": "Anmerkungen zu Dokument hinzufügen"
   },
   "signature-verification": {
     "upload-text": "Sie können in diesem Bereich PDF-Dokumente mit einer Maximalgröße von bis zu 32MB pro Dokument hochladen. Die PDF-Dokumente dürfen sich auch in ZIP-Dateien befinden.",
@@ -128,7 +128,13 @@
     "type-value-2": "Verwendungszweck",
     "businessnumber-placeholder": "Fügen Sie hier die Geschäftszahl ein (z.B. 247/1/2020-S)",
     "intended-use-placeholder": "Fügen Sie hier den gewünschten Text ein",
-    "introduction": "In diesem Bereich können Sie zusätzlichen Text definieren, der in der Signatur enthalten sein soll. Klicken Sie dafür auf \"Neues Feld einfügen\" und wählen Sie das gewünschte Feld aus. Klicken Sie dann auf das \"+\" um das Feld einzufügen und den gewünschten Text einzugeben."
+    "introduction": "In diesem Bereich können Sie zusätzlichen Text definieren, der in der Signatur enthalten sein soll. Klicken Sie dafür auf \"Neues Feld einfügen\" und wählen Sie das gewünschte Feld aus. Klicken Sie dann auf das \"+\" um das Feld einzufügen und den gewünschten Text einzugeben.",
+    "empty-annotation-title": "{{annotationType}} ist leer!",
+    "empty-annotation-message": "Bitte tragen Sie einen Wert für die gewählte Anmerkung ein.",
+    "empty-organization-title": "Organisation wurde nicht ausgewählt!",
+    "empty-organization-message": "Bitte wählen Sie Ihre Organisation aus, bevor Sie die gewählte Anmerkung übernehmen.",
+    "invalid-annotation-text-title": "Ungültiger Eingabewert!",
+    "invalid-annotation-text-message": "Sie haben ein oder mehrere ungültige Zeichen eingegeben. Zulässige Sonderzeichen sind: \\/ !=+-_*&()"
   },
   "error-permission-message": "Sie müssen das Recht auf Amtssignaturen besitzen um diese Funktion nutzen zu können!",
   "error-login-message": "Sie müssen eingeloggt sein um diese Funktion nutzen zu können!",
diff --git a/src/i18n/en/translation.json b/src/i18n/en/translation.json
index 311c57b..0f7c38e 100644
--- a/src/i18n/en/translation.json
+++ b/src/i18n/en/translation.json
@@ -30,10 +30,10 @@
     "file-picker-context": "Upload PDF-documents to sign",
     "add-annotation-title": "Add annotation to PDF",
     "annotation-type-please-select": "Please select a type",
-    "annotation": "Add text",
+    "annotation": "Annotations",
     "annotation-no": "No",
     "annotation-yes": "Yes",
-    "annotation-view-label": "Add text to document"
+    "annotation-view-label": "Add annotations to document"
   },
   "qualified-pdf-upload": {
     "save-field-label": "Save {{count}} file",
@@ -67,10 +67,10 @@
     "positioning": "Positioning",
     "confirm-page-leave": "Are you sure you want to leave this page? There are still signed documents ready to be downloaded.",
     "file-picker-context": "Upload PDF-documents to sign",
-    "annotation": "Add text",
+    "annotation": "Annotations",
     "annotation-no": "No",
     "annotation-yes": "Yes",
-    "annotation-view-label": "Add text to document"
+    "annotation-view-label": "Add annotations to document"
   },
   "signature-verification": {
     "upload-text": "In this area you can upload PDF-documents up to a size of 32MB. The PDF-documents can also be located in a ZIP-file.",
@@ -128,7 +128,13 @@
     "type-value-2": "Intended use",
     "businessnumber-placeholder": "Insert business number here (e.g. 247/1/2020-S)",
     "intended-use-placeholder": "Insert text here",
-    "introduction": "In this area you can define additional text to be included in the signature. To do this, click on \"Insert new field\" and select the desired field. Then click on the \"+\" to insert the field and enter the desired text."
+    "introduction": "In this area you can define additional text to be included in the signature. To do this, click on \"Insert new field\" and select the desired field. Then click on the \"+\" to insert the field and enter the desired text.",
+    "empty-annotation-title": "{{annotationType}} is empty!",
+    "empty-annotation-message": "Please enter a value for the selected annotation.",
+    "empty-organization-title": "Organization was not selected!",
+    "empty-organization-message": "Please select your organization before applying the selected annotation.",
+    "invalid-annotation-text-title": "Invalid Input Value!",
+    "invalid-annotation-text-message": "You have entered one or more invalid characters. Valid special characters are: \\/ !?=+-_*&()"
   },
   "error-permission-message": "You need have permissions to use the official signature to use this function!",
   "error-login-message": "You need to be logged in to use this function!",
-- 
GitLab