From 741857e57cc36f6bf6e416971388781b1f4b77cd Mon Sep 17 00:00:00 2001
From: Ruben Bimberg <ruben.bimberg@mni.thm.de>
Date: Mon, 14 Jun 2021 23:44:34 +0200
Subject: [PATCH] Fixes UI bugs

---
 .../worker-dialog.component.html              | 26 ++++-----
 .../worker-dialog.component.scss              | 14 ++---
 .../worker-dialog/worker-dialog.component.ts  | 39 +++++++-------
 .../shared/header/header.component.ts         |  3 +-
 .../tag-cloud-pop-up.component.html           |  5 +-
 .../tag-cloud-pop-up.component.scss           | 28 +++++++---
 .../tag-cloud-pop-up.component.ts             | 53 ++++++++++++++-----
 .../shared/tag-cloud/tag-cloud.component.ts   |  5 +-
 .../services/util/tag-cloud-data.service.ts   |  8 +++
 9 files changed, 115 insertions(+), 66 deletions(-)

diff --git a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.html b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.html
index e5f8aa371..97722af6e 100644
--- a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.html
+++ b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.html
@@ -1,20 +1,14 @@
-
 <div id="worker-content">
-
-
-<div id="header">
-  <span>Laufend # {{getNumberInQueue()}}</span>
-  <button id="btn_hide" (click)="close()">X</button>
-</div>
-
-
-
-
-  <div mat-dialog-content>
-    <div *ngFor="let task of taskQueue">
-      <span>{{ task.room.name }}, # {{ task.comments.length }}</span>
-    </div>
+  <div id="header">
+    <button id="btn_hide" (click)="close()">X</button>
+    <details>
+      <summary>Laufend # {{getNumberInQueue()}}</summary>
+      <div mat-dialog-content>
+        <div *ngFor="let task of taskQueue">
+          <span>{{ task.room.name }}, # {{ task.comments.length }}</span>
+        </div>
+      </div>
+    </details>
   </div>
-
 </div>
 
diff --git a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.scss b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.scss
index 7c09c71f0..d91e72491 100644
--- a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.scss
+++ b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.scss
@@ -1,14 +1,14 @@
 button {
-  position: absolute!important;
-  right: 0;
-  top: 0;
+  position: absolute !important;
+  right: 5px;
+  top: 5px;
 }
 
-::ng-deep.mat-dialog-container {
-  padding: 0 !important;
+::ng-deep .workerContainer > .mat-dialog-container {
+  padding: 5px !important;
   box-shadow: 0 2px 1px -1px rgba(0, 0, 0, .2), 0 1px 1px 0 rgba(0, 0, 0, .14), 0 1px 3px 0 rgba(0, 0, 0, .12), -4px 0 0 0 var(--primary);
-  overflow: hidden!important;
-  position: relative!important;
+  overflow: hidden !important;
+  position: relative !important;
 }
 
 #worker-content {
diff --git a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.ts b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.ts
index da60a9bed..82f5b31eb 100644
--- a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.ts
+++ b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.ts
@@ -1,13 +1,13 @@
-import {Component, Inject, OnInit} from '@angular/core';
-import {MAT_DIALOG_DATA} from '@angular/material/dialog';
-import {Room} from "../../../../models/room";
-import {CommentService} from "../../../../services/http/comment.service";
+import { Component, OnInit } from '@angular/core';
+import { Room } from '../../../../models/room';
+import { CommentService } from '../../../../services/http/comment.service';
 import { Comment } from '../../../../models/comment';
-import {SpacyService} from "../../../../services/http/spacy.service";
-import {TSMap} from "typescript-map";
+import { SpacyService } from '../../../../services/http/spacy.service';
+import { TSMap } from 'typescript-map';
+
 export interface WorkTask {
-  room: Room,
-  comments: Comment[]
+  room: Room;
+  comments: Comment[];
 }
 
 @Component({
@@ -17,13 +17,16 @@ export interface WorkTask {
 })
 export class WorkerDialogComponent implements OnInit {
 
-  isRunning: boolean = false;
+  isRunning = false;
   taskQueue: WorkTask[] = [];
   closeCallback: any = null;
+
   constructor(private commentService: CommentService,
-              private spacyService: SpacyService) {}
+              private spacyService: SpacyService) {
+  }
 
-  ngOnInit(): void {}
+  ngOnInit(): void {
+  }
 
   _callNextInQueue(): void {
     if (!this.isQueueEmpty()) {
@@ -32,7 +35,7 @@ export class WorkerDialogComponent implements OnInit {
       this.runWorkTask(task);
     } else {
       this.isRunning = false;
-      setTimeout(()=> this.close(), 2000);
+      setTimeout(() => this.close(), 2000);
     }
   }
 
@@ -42,21 +45,20 @@ export class WorkerDialogComponent implements OnInit {
     }
 
     this.commentService.getAckComments(room.id).subscribe((comments: Comment[]) => {
-      const task: WorkTask = {room: room, comments: comments};
+      const task: WorkTask = {room, comments};
 
       // TEST
       //for (let i = 0 ; i < 5 ; i++) {
-        this.taskQueue.push(task);
+      this.taskQueue.push(task);
       //}
 
       if (!this.isRunning) {
         this._callNextInQueue();
       }
-    })
+    });
   }
 
   runWorkTask(task: WorkTask): void {
-
     task.comments.forEach((c: Comment) => {
       const model = 'de';
       const text = c.body;
@@ -71,9 +73,8 @@ export class WorkerDialogComponent implements OnInit {
           console.log('PATCHED .........................');
           this._callNextInQueue();
         });
-
-      })
-    })
+      });
+    });
   }
 
   getNumberInQueue() {
diff --git a/src/app/components/shared/header/header.component.ts b/src/app/components/shared/header/header.component.ts
index 6a4ec043d..566319123 100644
--- a/src/app/components/shared/header/header.component.ts
+++ b/src/app/components/shared/header/header.component.ts
@@ -335,7 +335,8 @@ export class HeaderComponent implements OnInit {
         position: {left: '50px', bottom: '50px'},
         role: 'dialog',
         hasBackdrop: false,
-        closeOnNavigation: false
+        closeOnNavigation: false,
+        panelClass: 'workerContainer'
       });
 
       const component: WorkerDialogComponent = this.workerDialogRef.componentInstance;
diff --git a/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.html b/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.html
index 9e29f1cac..2fb300699 100644
--- a/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.html
+++ b/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.html
@@ -42,12 +42,13 @@
         </p>
       </span>
     </div>
-    <div *ngIf="spellingData">
+    <div class="replacementContainer" *ngIf="checkLanguage">
       <mat-form-field>
         <mat-label>{{'tag-cloud-popup.tag-correction-placeholder' | translate}}</mat-label>
         <input type="text"
                aria-label="{{'tag-cloud-popup.tag-correction-placeholder' | translate}}"
                matInput
+               (keyup)="checkEnter($event)"
                [formControl]="replacementInput"
                [matAutocomplete]="auto">
         <mat-autocomplete #auto="matAutocomplete">
@@ -57,7 +58,7 @@
         </mat-autocomplete>
       </mat-form-field>
       <br>
-      <button mat-button class ="replace-button" (click)="updateTag()">send</button>
+      <button mat-button class="replace-button" (click)="updateTag()">{{"comment-page.send" | translate}}</button>
     </div>
     <div *ngIf="categories && categories.length">
       <p>Kategorien:</p>
diff --git a/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.scss b/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.scss
index 783473a7a..9ac82a267 100644
--- a/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.scss
+++ b/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.scss
@@ -128,30 +128,46 @@ button {
   padding-left: 10px;
   padding-right: 10px;
 }
-.replace-button{
+
+.replace-button {
   background-color: var(--primary);
   color: var(--on-primary);
-  margin-top: 1rem;
   min-width: 30px !important;
   min-height: 10px !important;
+  width: 100%;
+  z-index: 3;
 }
-mat-form-field{
+
+::ng-deep .replacementContainer {
+  align-self: center;
+
+  .mat-form-field-infix {
+    min-width: 150px;
+    width: min-content;
+  }
+
+  .mat-form-field-wrapper {
+    margin-bottom: -0.8em;
+  }
+}
+
+mat-form-field {
   border-radius: 5px;
   line-height: 80%;
   caret-color: var(--on-surface);
   -webkit-appearance: textarea;
   min-height: 30px;
-  min-width: 100px;
+  min-width: 140px;
   cursor: text;
-  margin-right: 5px;
   color: var(--on-dialog);
   background-color: var(--dialog);
-  margin-top: 5px;
+  margin-top: 0.2em;
 
   &:focus {
     outline: none;
   }
 }
+
 #replacement {
   color: var(--on-dialog);
   background-color: var(--dialog);
diff --git a/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.ts b/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.ts
index 9310b86cd..c4fed49e8 100644
--- a/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.ts
+++ b/src/app/components/shared/tag-cloud/tag-cloud-pop-up/tag-cloud-pop-up.component.ts
@@ -8,6 +8,8 @@ import { Language, LanguagetoolService } from '../../../../services/http/languag
 import { FormControl } from '@angular/forms';
 import { TSMap } from 'typescript-map';
 import { CommentService } from '../../../../services/http/comment.service';
+import { NotificationService } from '../../../../services/util/notification.service';
+import { MatAutocompleteTrigger } from '@angular/material/autocomplete';
 
 const CLOSE_TIME = 1500;
 
@@ -19,6 +21,7 @@ const CLOSE_TIME = 1500;
 export class TagCloudPopUpComponent implements OnInit, AfterViewInit {
 
   @ViewChild('popupContainer') popupContainer: ElementRef;
+  @ViewChild(MatAutocompleteTrigger) trigger: MatAutocompleteTrigger;
   replacementInput = new FormControl();
   tag: string;
   tagData: TagCloudDataTagEntry;
@@ -26,16 +29,19 @@ export class TagCloudPopUpComponent implements OnInit, AfterViewInit {
   timePeriodText: string;
   user: User;
   selectedLang: Language = 'en-US';
-  spellingData: string[] = undefined;
+  spellingData: string[] = [];
+  checkLanguage = false;
   private _popupHoverTimer: number;
   private _popupCloseTimer: number;
+  private _hasLeft = true;
 
   constructor(private langService: LanguageService,
               private translateService: TranslateService,
               private authenticationService: AuthenticationService,
               private tagCloudDataService: TagCloudDataService,
               private languagetoolService: LanguagetoolService,
-              private commentService: CommentService) {
+              private commentService: CommentService,
+              private notificationService: NotificationService) {
     this.langService.langEmitter.subscribe(lang => {
       this.translateService.use(lang);
     });
@@ -54,8 +60,10 @@ export class TagCloudPopUpComponent implements OnInit, AfterViewInit {
     const html = this.popupContainer.nativeElement as HTMLDivElement;
     html.addEventListener('mouseenter', () => {
       clearTimeout(this._popupCloseTimer);
+      this._hasLeft = false;
     });
     html.addEventListener('mouseleave', () => {
+      this._hasLeft = true;
       this.close();
     });
   }
@@ -69,20 +77,23 @@ export class TagCloudPopUpComponent implements OnInit, AfterViewInit {
     this.close();
   }
 
-  enter(elem: HTMLElement, tag: string, tagData: TagCloudDataTagEntry, hoverDelayInMs: number): void {
-    this.spellingData = undefined;
-    this.languagetoolService.checkSpellings(tag, this.selectedLang).subscribe(correction => {
+  enter(elem: HTMLElement, tag: string, tagData: TagCloudDataTagEntry, hoverDelayInMs: number, checkLanguage: boolean): void {
+    this.checkLanguage = checkLanguage;
+    if (checkLanguage) {
       this.spellingData = [];
-      for (const match of correction.matches) {
-        if (match.replacements != null && match.replacements.length > 0) {
-          for (const replacement of match.replacements) {
-            this.spellingData.push(replacement.value);
+      this.languagetoolService.checkSpellings(tag, this.selectedLang).subscribe(correction => {
+        for (const match of correction.matches) {
+          if (match.replacements != null && match.replacements.length > 0) {
+            for (const replacement of match.replacements) {
+              this.spellingData.push(replacement.value);
+            }
           }
         }
-      }
-    });
+      });
+    }
     clearTimeout(this._popupCloseTimer);
     clearTimeout(this._popupHoverTimer);
+    this._hasLeft = true;
     this._popupHoverTimer = setTimeout(() => {
       this.tag = tag;
       this.tagData = tagData;
@@ -102,7 +113,7 @@ export class TagCloudPopUpComponent implements OnInit, AfterViewInit {
     const html = this.popupContainer.nativeElement as HTMLDivElement;
     clearTimeout(this._popupCloseTimer);
     if (addDelay) {
-      if (html.contains(document.activeElement) && html !== document.activeElement) {
+      if (!this._hasLeft || (html.contains(document.activeElement) && html !== document.activeElement)) {
         return;
       }
       this._popupCloseTimer = setTimeout(() => {
@@ -132,9 +143,25 @@ export class TagCloudPopUpComponent implements OnInit, AfterViewInit {
       changes.set('keywordsFromQuestioner', JSON.stringify(comment.keywordsFromQuestioner));
       comment.keywordsFromSpacy.forEach(renameKeyword);
       changes.set('keywordsFromSpacy', JSON.stringify(comment.keywordsFromSpacy));
-      this.commentService.patchComment(comment, changes).subscribe();
+      this.commentService.patchComment(comment, changes).subscribe(_ => {
+        this.translateService.get('topic-cloud-dialog.keyword-edit').subscribe(msg => {
+          this.notificationService.show(msg);
+        });
+      }, _ => {
+        this.translateService.get('topic-cloud-dialog.changes-gone-wrong').subscribe(msg => {
+          this.notificationService.show(msg);
+        });
+      });
     });
     this.close(false);
+    this.replacementInput.reset();
+    this.trigger.closePanel();
+  }
+
+  checkEnter(e: KeyboardEvent) {
+    if (e.key === 'Enter') {
+      this.updateTag();
+    }
   }
 
   private position(elem: HTMLElement) {
diff --git a/src/app/components/shared/tag-cloud/tag-cloud.component.ts b/src/app/components/shared/tag-cloud/tag-cloud.component.ts
index a663cbd54..b0d32a0a2 100644
--- a/src/app/components/shared/tag-cloud/tag-cloud.component.ts
+++ b/src/app/components/shared/tag-cloud/tag-cloud.component.ts
@@ -424,7 +424,8 @@ export class TagCloudComponent implements OnInit, AfterViewInit, OnDestroy {
       });
       elem.addEventListener('mouseenter', () => {
         this.popup.enter(elem, dataElement.text, dataElement.tagData,
-          (this._currentSettings.hoverTime + this._currentSettings.hoverDelay) * 1_000);
+          (this._currentSettings.hoverTime + this._currentSettings.hoverDelay) * 1_000,
+          this._currentSettings.checkSpelling);
       });
     });
   }
@@ -446,7 +447,7 @@ export class TagCloudComponent implements OnInit, AfterViewInit, OnDestroy {
       textTransform = 'text-transform: capitalize;';
     } else if (this._currentSettings.textTransform === CloudTextStyle.lowercase) {
       textTransform = 'text-transform: lowercase;';
-    }else if (this._currentSettings.textTransform === CloudTextStyle.uppercase) {
+    } else if (this._currentSettings.textTransform === CloudTextStyle.uppercase) {
       textTransform = 'text-transform: uppercase;';
     }
     customTagCloudStyles.sheet.insertRule('.spacyTagCloud > span, .spacyTagCloud > span > a { ' +
diff --git a/src/app/services/util/tag-cloud-data.service.ts b/src/app/services/util/tag-cloud-data.service.ts
index c380f0e56..8d9ec90e3 100644
--- a/src/app/services/util/tag-cloud-data.service.ts
+++ b/src/app/services/util/tag-cloud-data.service.ts
@@ -400,6 +400,14 @@ export class TagCloudDataService {
                   comment.downvotes = value as number;
                   needRebuild = true;
                   break;
+                case 'keywordsFromSpacy':
+                  comment.keywordsFromSpacy = JSON.parse(value as string);
+                  needRebuild = true;
+                  break;
+                case 'keywordsFromQuestioner':
+                  comment.keywordsFromQuestioner = JSON.parse(value as string);
+                  needRebuild = true;
+                  break;
                 case 'ack':
                   const isNowAck = value as boolean;
                   if (!isNowAck) {
-- 
GitLab