diff --git a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.html b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.html index 793df0cb579797d2969d4c0b1789b8ddc50daff0..433d5e01c39d39bbb7094200d7007d91fbe6aa25 100644 --- a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.html +++ b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.html @@ -18,11 +18,7 @@ <div class="input-row firstElementOfExpansionPanel" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column"> <mat-slide-toggle matTooltip="{{'tag-cloud-config.random-angle-tooltip' | translate}}" (change)="valueChanged()" fxFlex [(ngModel)]="cloudParameters.randomAngles" [ngModelOptions]="{standalone: true}">{{'tag-cloud-config.random-angle' | translate}}</mat-slide-toggle> - </div> - <div class="input-row special-settings automatic-spelling" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column"> - <div class="input-row" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column"> - <mat-slide-toggle matTooltip="{{'tag-cloud-config.automatic-spelling-tooltip' | translate}}" [(ngModel)]="cloudParameters.checkSpelling" [checked]="cloudParameters.checkSpelling" [ngModelOptions]="{standalone: true}" (change)="valueChanged()">{{'tag-cloud-config.automatic-spelling' | translate}}</mat-slide-toggle> - </div> + <mat-icon matTooltip="{{'tag-cloud-config.random-angle-note' | translate}}">help</mat-icon> </div> <div class="input-row special-settings automatic-spelling" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column"> <mat-radio-group matTooltip="{{'tag-cloud-config.notation-tooltip' | translate}}" aria-label="Notation:"> {{'tag-cloud-config.notation' | translate}} @@ -71,7 +67,7 @@ <div class="input-row" fxLayout="column" fxLayoutGap="5px"> <mat-form-field appearance="fill"> <mat-label>{{'tag-cloud-config.font-family' | translate}}</mat-label> - <mat-select (selectionChange)="valueChanged()" [(ngModel)]="cloudParameters.fontFamily"> + <mat-select (selectionChange)="valueChanged()" matTooltip="{{'tag-cloud-config.font-family-tooltip' | translate}}" [(ngModel)]="cloudParameters.fontFamily"> <mat-option value="sans-serif">Normal</mat-option> <mat-option value="Abril Fatface">Abril Fatface</mat-option> <mat-option value="Dancing Script">Dancing Script</mat-option> @@ -81,24 +77,23 @@ </mat-form-field> </div> <div class="input-row special-settings automatic-spelling" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column"> - <mat-radio-group matTooltip="{{'tag-cloud-config.notation-tooltip' | translate}}" aria-label="Notation:"> - <div><mat-slide-toggle [checked]="checkItalic()" (change)="italicChecked($event)"[ngModelOptions]="{standalone: true}">{{'tag-cloud-config.font-style-italic' | translate}}</mat-slide-toggle> </div> + <mat-radio-group matTooltip="{{'tag-cloud-config.bold-notation-tooltip' | translate}}" aria-label="Notation:"> <div><mat-slide-toggle [checked]="checkBold()" (change)="boldChecked($event)" [ngModelOptions]="{standalone: true}">{{'tag-cloud-config.font-style-bold' | translate}}</mat-slide-toggle> </div> </mat-radio-group> </div> <div class="input-row" fxLayout="column" fxLayoutGap="5px"> <mat-form-field fxFlex fxLayout.xs="column"> <mat-label>{{'tag-cloud-config.font-size-min' | translate}}</mat-label> - <input #minFont [value]="cloudParameters.fontSizeMin" matInput type="number" + <input #minFont [value]="cloudParameters.fontSizeMin.toString()" matInput type="number" [(ngModel)]="cloudParameters.fontSizeMin" [ngModelOptions]="{standalone: true}" (change)="valueChanged()" - min="10" max="300" step="10" matTooltip="{{'tag-cloud-config.font-size-min-tooltip' | translate}}" /> + min="280" max="300" step="10" matTooltip="{{'tag-cloud-config.font-size-min-tooltip' | translate}}" /> </mat-form-field> </div> <div class="input-row" fxLayout="column" fxLayoutGap="5px"> <mat-form-field fxFlex fxLayout.xs="column"> <mat-label>{{'tag-cloud-config.font-size-max' | translate}}</mat-label> <input #maxFont matInput type="number" [(ngModel)]="cloudParameters.fontSizeMax" - [ngModelOptions]="{standalone: true}" (change)="valueChanged()" min="10" max="1000" step="10" + [ngModelOptions]="{standalone: true}" (change)="valueChanged()" min="280" max="1000" step="10" matTooltip="{{'tag-cloud-config.font-size-max-tooltip' | translate}}" /> </mat-form-field> </div> @@ -176,12 +171,12 @@ <div class="input-row" fxLayout="column" fxLayoutGap="5px" *ngIf="weightClass.actualTagNumber > 0 && !parent.dataManager.demoActive"> <div class="input-row" fxLayout="column" fxLayoutGap="5px"> <mat-label class="label-text" >{{'tag-cloud-config.weight-number' | translate}}</mat-label> - <mat-slider [value]="weightClass.maxTagNumber" min="0" [max]="weightClass.actualTagNumber" step="1" + <mat-slider [value]="weightClass.maxTagNumber" min="1" [max]="weightClass.actualTagNumber" step="1" [(ngModel)]="weightClass.maxTagNumber" [ngModelOptions]="{standalone: true}" (change)="valueChanged()" [thumbLabel]="true" matTooltip="{{'tag-cloud-config.weight-number-tooltip' | translate}}"></mat-slider> </div> </div> - <div class="input-row" fxLayout="column" fxLayoutGap="5px"> + <div class="input-row" fxLayout="column" fxLayoutGap="5px" *ngIf="!cloudParameters.randomAngles"> <mat-label class="label-text">{{'tag-cloud-config.rotate-weight' | translate}}</mat-label> <mat-slider [value]="weightClass.rotationAngle" min="-180" max="180" step="1" [(ngModel)]="weightClass.rotationAngle" [ngModelOptions]="{standalone: true}" (change)="valueChanged()" diff --git a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.scss b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.scss index ad76e0495520f53011b6c5e723a1afdae8804824..316554c43c41f8a50bf3dc935d5f750de04c0977 100644 --- a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.scss +++ b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.scss @@ -121,7 +121,7 @@ mat-divider { ::ng-deep .mat-accent .mat-slider-track-fill, ::ng-deep .mat-accent .mat-slider-thumb, ::ng-deep .mat-accent .mat-slider-thumb-label{ - color: var(--on-primary);; + color: var(--on-primary); background-color: var(--primary); } @@ -130,12 +130,12 @@ mat-divider { } ::ng-deep .primary{ - color: var(--on-primary);; + color: var(--on-primary); background-color: var(--primary); } ::ng-deep .secondary{ - color: var(--on-cancel);; + color: var(--on-cancel); background-color: var(--cancel); margin-right: 20px; @@ -143,11 +143,11 @@ mat-divider { .button-row{ width: 100%; - margin: auto auto 20px auto ; + margin: auto auto 20px auto; } .reset { margin: 25px auto auto auto; - background-color: var(--white); + background-color: var(--secondary); color: black; width: 100%; } diff --git a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.ts b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.ts index bea6981ce553143c96f3da414be062887799b2de..967d2ec047c2d61c518879936031d481707c72fb 100644 --- a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.ts +++ b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.ts @@ -100,6 +100,9 @@ export class CloudConfigurationComponent implements OnInit { this.cloudParameters = this.parent.currentCloudParameters; this.defaultCloudParameters = this.parent.currentCloudParameters; this.parent.dataManager.getMetaData().subscribe((value)=>{ + if (!value) { + return; + } this.countPerWeight = value.countPerWeight; this.parseArrayToJsonWeightClasses(); }); @@ -129,6 +132,7 @@ export class CloudConfigurationComponent implements OnInit { this.weightClasses[i].tagColor = element.color; this.weightClasses[i].actualTagNumber = this.countPerWeight[i]; this.weightClasses[i].rotationAngle = element.rotation; + this.weightClasses[i].maxTagNumber = element.maxVisibleElements == -1 ? this.weightClasses[i].actualTagNumber : element.maxVisibleElements; }); } diff --git a/src/app/components/shared/_dialogs/create-comment/create-comment.component.html b/src/app/components/shared/_dialogs/create-comment/create-comment.component.html index e4897582b82f7c8fbb0936d3ab9ae1f2f2c0a25f..978d076a300d08cc545bd77890cacefcca1cc8b1 100644 --- a/src/app/components/shared/_dialogs/create-comment/create-comment.component.html +++ b/src/app/components/shared/_dialogs/create-comment/create-comment.component.html @@ -98,7 +98,10 @@ </ars-row> <ars-row ars-flex-box class="spellcheck"> <ars-col> - <button mat-button class="spell-button" (click)="grammarCheck(commentBody)"> + <button + [disabled]="this.commentBody.innerHTML.length === 0" + mat-flat-button class="spell-button" + (click)="grammarCheck(commentBody)"> {{ 'comment-page.grammar-check' | translate}} <mat-icon *ngIf="isSpellchecking" style="margin: 0;"> <mat-spinner diameter="20"></mat-spinner> diff --git a/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts b/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts index c15d7ff60117434f05260fcc4a6b9844606a521e..5ca59b3528a5543b164bdd09a603854fb9d0d20f 100644 --- a/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts +++ b/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts @@ -1,5 +1,5 @@ import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { Comment } from '../../../../models/comment'; +import { Comment, Language as CommentLanguage } from '../../../../models/comment'; import { NotificationService } from '../../../../services/util/notification.service'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; import { TranslateService } from '@ngx-translate/core'; @@ -121,9 +121,12 @@ export class CreateCommentComponent implements OnInit, OnDestroy { .subscribe((result) => { if (result.isAcceptable) { const commentLang = this.languagetoolService.mapLanguageToSpacyModel(result.result.language.code as Language); + const selectedLangExtend = this.selectedLang[2] === '-' ? this.selectedLang.substr(0, 2) : this.selectedLang; // Store language if it was auto-detected - if(this.selectedLang === 'auto') { + if (this.selectedLang === 'auto') { comment.language = Comment.mapModelToLanguage(commentLang); + } else if (CommentLanguage[selectedLangExtend]) { + comment.language = CommentLanguage[selectedLangExtend]; } const dialogRef = this.dialog.open(SpacyDialogComponent, { data: { @@ -138,6 +141,7 @@ export class CreateCommentComponent implements OnInit, OnDestroy { } }); } else { + comment.language = CommentLanguage.auto; this.dialogRef.close(comment); } this.isSendingToSpacy = false; diff --git a/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.html b/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.html index aebb707b53bdc0b78d2addd685d9820fc061bf5d..aadff087cfc38dcbd323e9067faa3f68484aba41 100644 --- a/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.html +++ b/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.html @@ -1,6 +1,7 @@ <ars-row> <div class="anchor-wrp"> <span *ngIf="keywords.length > 0"> + <span>{{ 'spacy-dialog.select-keywords' | translate }}</span> <ars-row class="select-all-section"> <mat-checkbox class="select-all-checkbox" id="checkAll" @@ -42,14 +43,14 @@ matTooltipShowDelay="750"> </mat-checkbox> <button *ngIf="!keyword.editing" - (click)="onEdit(keyword)" mat-icon-button + (click)="onEdit(keyword); onEditChange(1)" mat-icon-button [ngClass]="{'keywords-actions-selected': keyword.selected}" matTooltip="{{ 'spacy-dialog.edit-keyword-hint' | translate }}" matTooltipShowDelay="750"> <mat-icon>edit</mat-icon> </button> <button *ngIf="keyword.editing" - (click)="onEndEditing(keyword)" mat-icon-button + (click)="onEndEditing(keyword); onEditChange(-1)" mat-icon-button class = "edit-accept" matTooltip="{{ 'spacy-dialog.editing-done-hint' | translate }}" matTooltipShowDelay="750"> @@ -75,6 +76,7 @@ <ars-fill></ars-fill> <ars-col> <app-dialog-action-buttons + #appDialogActionButtons buttonsLabelSection="comment-page" confirmButtonLabel="send" [showDivider]="false" diff --git a/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.ts b/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.ts index 4b4b53a65d1de434fd0c70086d08d532886a7af8..45166229b358cbcc4c6a3c2c4765931d45931961 100644 --- a/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.ts +++ b/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.ts @@ -1,4 +1,4 @@ -import { AfterContentInit, Component, Inject, OnInit } from '@angular/core'; +import { AfterContentInit, Component, Inject, OnInit, ViewChild } from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { CreateCommentComponent } from '../create-comment/create-comment.component'; @@ -6,6 +6,7 @@ import { SpacyService, Model } from '../../../../services/http/spacy.service'; import { LanguagetoolService } from '../../../../services/http/languagetool.service'; import { Comment } from '../../../../models/comment'; import { map } from 'rxjs/operators'; +import { DialogActionButtonsComponent } from '../../dialog/dialog-action-buttons/dialog-action-buttons.component'; export interface Keyword { word: string; @@ -21,6 +22,8 @@ export interface Keyword { }) export class SpacyDialogComponent implements OnInit, AfterContentInit { + @ViewChild('appDialogActionButtons') appDialogActionButtons: DialogActionButtonsComponent; + comment: Comment; commentLang: Model; commentBodyChecked: string; @@ -29,6 +32,7 @@ export class SpacyDialogComponent implements OnInit, AfterContentInit { isLoading = false; langSupported: boolean; manualKeywords = ''; + _concurrentEdits = 0 constructor( protected langService: LanguagetoolService, @@ -143,4 +147,9 @@ export class SpacyDialogComponent implements OnInit, AfterContentInit { this.keywords = []; } } + + onEditChange(change: number) { + this._concurrentEdits += change; + this.appDialogActionButtons.confirmButtonDisabled = (this._concurrentEdits > 0) + } } diff --git a/src/app/components/shared/_dialogs/topic-cloud-filter/topic-cloud-filter.component.html b/src/app/components/shared/_dialogs/topic-cloud-filter/topic-cloud-filter.component.html index 8838a59c151580b2f44d30605c35a1a93f4b7c81..3b1911cb570fcfb476624a32042e1763ed9859f8 100644 --- a/src/app/components/shared/_dialogs/topic-cloud-filter/topic-cloud-filter.component.html +++ b/src/app/components/shared/_dialogs/topic-cloud-filter/topic-cloud-filter.component.html @@ -1,30 +1,32 @@ -<div mat-dialog-content> - <p>{{'content.topic-cloud-content' | translate}}</p> -</div> - <mat-divider></mat-divider> <mat-radio-group [(ngModel)]="continueFilter" aria-label="Select an option"> - <mat-radio-button value="continueWithAll"> + <mat-radio-button checked="true" value="continueWithAll"> <div class="elementRow"> <div class="elementText"> {{'content.continue-with-all-questions' | translate}} </div> <div class="elementIcons"> - <mat-icon [inline]="true">comment</mat-icon> {{allComments.comments}} - <mat-icon [inline]="true">person</mat-icon> {{allComments.users}} - <mat-icon svgIcon="hashtag" class="comment_tag-icon"></mat-icon> {{allComments.keywords}} + <mat-icon [inline]="true" + matTooltip="{{'header.overview-question-tooltip' | translate}}">comment</mat-icon> {{allComments.comments}} + <mat-icon [inline]="true" + matTooltip="{{'header.overview-questioners-tooltip' | translate}}">person</mat-icon> {{allComments.users}} + <mat-icon svgIcon="hashtag" class="comment_tag-icon" + matTooltip="{{'header.overview-keywords-tooltip' | translate}}"></mat-icon> {{allComments.keywords}} </div> </div> </mat-radio-button> - <mat-radio-button checked="true" value="continueWithCurr" *ngIf="!disableCurrentFiltersOptions"> + <mat-radio-button value="continueWithCurr" *ngIf="!disableCurrentFiltersOptions"> <div class="elementRow"> <div class="elementText"> {{'content.continue-with-current-questions' | translate}} </div> <div class="elementIcons"> - <mat-icon [inline]="true">comment</mat-icon> {{filteredComments.comments}} - <mat-icon [inline]="true">person</mat-icon> {{filteredComments.users}} - <mat-icon svgIcon="hashtag" class="comment_tag-icon"></mat-icon> {{filteredComments.keywords}} + <mat-icon [inline]="true" + matTooltip="{{'header.overview-question-tooltip' | translate}}">comment</mat-icon> {{filteredComments.comments}} + <mat-icon [inline]="true" + matTooltip="{{'header.overview-questioners-tooltip' | translate}}">person</mat-icon> {{filteredComments.users}} + <mat-icon svgIcon="hashtag" class="comment_tag-icon" + matTooltip="{{'header.overview-keywords-tooltip' | translate}}"></mat-icon> {{filteredComments.keywords}} </div> </div> </mat-radio-button> diff --git a/src/app/components/shared/_dialogs/topic-cloud-filter/topic-cloud-filter.component.ts b/src/app/components/shared/_dialogs/topic-cloud-filter/topic-cloud-filter.component.ts index a26ac48facb1bc8d0c5f6b10d1ef23fc87fd51c5..2cce403e9e7d0e084aaff4bfb6af3ed7de2ab23f 100644 --- a/src/app/components/shared/_dialogs/topic-cloud-filter/topic-cloud-filter.component.ts +++ b/src/app/components/shared/_dialogs/topic-cloud-filter/topic-cloud-filter.component.ts @@ -1,15 +1,17 @@ -import { Component, Inject, OnInit, Input } from '@angular/core'; +import { Component, Inject, Input, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; import { NotificationService } from '../../../../services/util/notification.service'; import { TranslateService } from '@ngx-translate/core'; import { RoomCreatorPageComponent } from '../../../creator/room-creator-page/room-creator-page.component'; import { LanguageService } from '../../../../services/util/language.service'; import { EventService } from '../../../../services/util/event.service'; -import { ActivatedRoute, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { CommentFilter } from '../../../../utils/filter-options'; import { RoomService } from '../../../../services/http/room.service'; import { Comment } from '../../../../models/comment'; import { CommentListData } from '../../comment-list/comment-list.component'; +import { TopicCloudAdminService } from '../../../../services/util/topic-cloud-admin.service'; +import { KeywordOrFulltext } from '../topic-cloud-administration/TopicCloudAdminData'; class CommentsCount { comments: number; @@ -25,12 +27,14 @@ class CommentsCount { export class TopicCloudFilterComponent implements OnInit { @Input() target: string; - continueFilter = 'continueWithCurr'; + continueFilter = 'continueWithAll'; comments: Comment[]; tmpFilter: CommentFilter; allComments: CommentsCount; filteredComments: CommentsCount; disableCurrentFiltersOptions = false; + private readonly _filter: KeywordOrFulltext; + private readonly _blacklist: string[]; constructor(public dialogRef: MatDialogRef<RoomCreatorPageComponent>, public dialog: MatDialog, @@ -42,6 +46,9 @@ export class TopicCloudFilterComponent implements OnInit { @Inject(MAT_DIALOG_DATA) public data: any, public eventService: EventService) { langService.langEmitter.subscribe(lang => translationService.use(lang)); + const adminData = TopicCloudAdminService.getDefaultAdminData; + this._filter = adminData.keywordORfulltext; + this._blacklist = adminData.blacklist; } ngOnInit() { @@ -76,9 +83,25 @@ export class TopicCloudFilterComponent implements OnInit { if (c.userNumber) { userSet.add(c.userNumber); } - if (c.keywordsFromQuestioner) { - c.keywordsFromQuestioner.forEach(k => { - keywordSet.add(k); + let source = c.keywordsFromQuestioner; + if (this._filter === KeywordOrFulltext.both) { + source = !source || !source.length ? c.keywordsFromSpacy : source; + } else if (this._filter === KeywordOrFulltext.fulltext) { + source = c.keywordsFromSpacy; + } + if (source) { + source.forEach(k => { + let isProfanity = false; + const lowerCasedKeyword = k.toLowerCase(); + for (const word of this._blacklist) { + if (lowerCasedKeyword.includes(word)) { + isProfanity = true; + break; + } + } + if (!isProfanity) { + keywordSet.add(k); + } }); } }); diff --git a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog-task.ts b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog-task.ts index a95509994bb41363ebfd56c16a1f2fa8d160c622..5bfdb4b459ff80efb336bd8635a6daed705b248d 100644 --- a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog-task.ts +++ b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog-task.ts @@ -51,7 +51,6 @@ export class WorkerDialogTask { } return; } - const fallbackmodel = (localStorage.getItem('currentLang') || 'de') as Model; const currentComment = this._comments[currentIndex]; CreateCommentKeywords.isSpellingAcceptable(this.languagetoolService, currentComment.body) .subscribe(result => { @@ -60,9 +59,15 @@ export class WorkerDialogTask { this.callSpacy(currentIndex + concurrentCallsPerTask); return; } - const model = this.languagetoolService - .mapLanguageToSpacyModel(result.result.language.detectedLanguage.code as Language); - this.spacyService.getKeywords(result.text, model === 'auto' ? fallbackmodel : model) + const commentModel = currentComment.language.toLowerCase(); + const model = commentModel !== 'auto' ? commentModel.toLowerCase() as Model : + this.languagetoolService.mapLanguageToSpacyModel(result.result.language.detectedLanguage.code as Language); + if (model === 'auto') { + this.statistics.badSpelled++; + this.callSpacy(currentIndex + concurrentCallsPerTask); + return; + } + this.spacyService.getKeywords(result.text, model) .subscribe(newKeywords => { const changes = new TSMap<string, string>(); changes.set('keywordsFromSpacy', JSON.stringify(newKeywords)); @@ -74,19 +79,16 @@ export class WorkerDialogTask { if (patchError instanceof HttpErrorResponse && patchError.status === 403) { this.error = 'forbidden'; } - console.log(patchError); }, () => { this.callSpacy(currentIndex + concurrentCallsPerTask); }); }, - keywordError => { + __ => { this.statistics.failed++; - console.log(keywordError); this.callSpacy(currentIndex + concurrentCallsPerTask); }); - }, error => { + }, _ => { this.statistics.failed++; - console.log(error); this.callSpacy(currentIndex + concurrentCallsPerTask); }); } diff --git a/src/app/components/shared/comment-list/comment-list.component.html b/src/app/components/shared/comment-list/comment-list.component.html index a346dd2a1784d11facede53cc5973348a954592b..5edfdf4716cec1f1fe40eed822c598995f1d7808 100644 --- a/src/app/components/shared/comment-list/comment-list.component.html +++ b/src/app/components/shared/comment-list/comment-list.component.html @@ -30,7 +30,7 @@ mat-icon-button class="searchBarButton close red" *ngIf="searchInput !== '' || search" - (click)="hideCommentsList=false; searchInput = ''; search = false; searchPlaceholder = '';" + (click)="hideCommentsList=false; searchInput = ''; search = false;" aria-labelledby="close_search"> <mat-icon>close</mat-icon> </button> diff --git a/src/app/components/shared/comment-list/comment-list.component.ts b/src/app/components/shared/comment-list/comment-list.component.ts index 4ce3d90459d4788fbea4885b5a6820f617b45a3b..967ff70fc74be02627932e551c1e63d8c00816db 100644 --- a/src/app/components/shared/comment-list/comment-list.component.ts +++ b/src/app/components/shared/comment-list/comment-list.component.ts @@ -96,6 +96,7 @@ export class CommentListComponent implements OnInit, OnDestroy { fromNow: number; moderatorIds: string[]; commentsEnabled: boolean; + userNumberSelection: number = 0; createCommentWrapper: CreateCommentWrapper = null; private _subscriptionEventServiceTagConfig = null; private _subscriptionEventServiceRoomData = null; @@ -122,11 +123,17 @@ export class CommentListComponent implements OnInit, OnDestroy { private roomDataService: RoomDataService, private wsRoomService: WsRoomService ) { - langService.langEmitter.subscribe(lang => translateService.use(lang)); + langService.langEmitter.subscribe(lang => { + translateService.use(lang); + this.translateService.get('comment-list.search').subscribe(msg => { + this.searchPlaceholder = msg; + }); + }); } initNavigation() { this._subscriptionEventServiceTagConfig = this.eventService.on<string>('setTagConfig').subscribe(tag => { + this.setTimePeriod(Period.all); this.clickedOnKeyword(tag); }); this._subscriptionEventServiceRoomData = this.eventService.on<string>('pushCurrentRoomData').subscribe(_ => { @@ -324,9 +331,6 @@ export class CommentListComponent implements OnInit, OnDestroy { } activateSearch() { - this.translateService.get('comment-list.search').subscribe(msg => { - this.searchPlaceholder = msg; - }); this.search = true; this.searchField.nativeElement.focus(); } @@ -392,7 +396,9 @@ export class CommentListComponent implements OnInit, OnDestroy { return c.userNumber === compare; case this.keyword: this.selectedKeyword = compare; - return c.keywordsFromQuestioner ? c.keywordsFromQuestioner.includes(compare) : false; + const isInQuestioner = c.keywordsFromQuestioner ? c.keywordsFromQuestioner.includes(compare) : false; + const isInSpacy = c.keywordsFromSpacy ? c.keywordsFromSpacy.includes(compare) : false; + return isInQuestioner || isInSpacy; case this.answer: return c.answer; case this.unanswered: @@ -446,6 +452,7 @@ export class CommentListComponent implements OnInit, OnDestroy { } clickedUserNumber(usrNumber: number): void { + this.userNumberSelection = usrNumber; this.filterComments(this.userNumber, usrNumber); } @@ -585,6 +592,7 @@ export class CommentListComponent implements OnInit, OnDestroy { filter.periodSet = this.period; filter.keywordSelected = this.selectedKeyword; filter.tagSelected = this.selectedTag; + filter.userNumberSelected = this.userNumberSelection; if (filter.periodSet === Period.fromNow) { filter.timeStampNow = new Date().getTime(); diff --git a/src/app/components/shared/comment/comment.component.scss b/src/app/components/shared/comment/comment.component.scss index b4f6c773b849c1b862afc4a41aba2f0dc61ad03b..88dce68e1e06883ec93e92dfb106709b564953f9 100644 --- a/src/app/components/shared/comment/comment.component.scss +++ b/src/app/components/shared/comment/comment.component.scss @@ -206,6 +206,10 @@ mat-card-content > :first-child { height: 18px !important; } +.mat-badge-content { + background: #fb9a1c; +} + .user-number { cursor: pointer; color: var(--on-surface); diff --git a/src/app/components/shared/dialog/dialog-action-buttons/dialog-action-buttons.component.html b/src/app/components/shared/dialog/dialog-action-buttons/dialog-action-buttons.component.html index 9ae1ae502f68b18599444df4143b78f61c33e031..8dab567c3e7da153906678740f074605b9cb93a4 100644 --- a/src/app/components/shared/dialog/dialog-action-buttons/dialog-action-buttons.component.html +++ b/src/app/components/shared/dialog/dialog-action-buttons/dialog-action-buttons.component.html @@ -6,6 +6,7 @@ <div fxLayoutAlign="end"> <div fxLayout="row-reverse" fxLayoutGap="10px" class="buttons"> <button + [disabled]="confirmButtonDisabled" *ngIf="confirmButtonClickAction !== undefined" type="button" mat-flat-button @@ -18,6 +19,7 @@ </mat-icon> </button> <button + [disabled]="cancelButtonDisabled" *ngIf="cancelButtonClickAction !== undefined" type="button" mat-flat-button diff --git a/src/app/components/shared/dialog/dialog-action-buttons/dialog-action-buttons.component.ts b/src/app/components/shared/dialog/dialog-action-buttons/dialog-action-buttons.component.ts index 6b4af6f658edb828d083568cfc3d33fc6786b48b..56c12bac7b2c8e2a2135e7bec99ef26213677ee7 100644 --- a/src/app/components/shared/dialog/dialog-action-buttons/dialog-action-buttons.component.ts +++ b/src/app/components/shared/dialog/dialog-action-buttons/dialog-action-buttons.component.ts @@ -16,6 +16,16 @@ export enum DialogConfirmActionButtonType { }) export class DialogActionButtonsComponent implements OnInit { + /** + * gray out confirm button + */ + @Input() confirmButtonDisabled: boolean = false + + /** + * gray out cancel button + */ + @Input() cancelButtonDisabled: boolean = false + @Input() showDivider = true; /** diff --git a/src/app/components/shared/footer/footer.component.html b/src/app/components/shared/footer/footer.component.html index dd8f018bdbd26b6e04430044ba0739cc74a0eac5..07c4ac5f8a91a7d2a7a01bf5385d8ca3e1a46e55 100644 --- a/src/app/components/shared/footer/footer.component.html +++ b/src/app/components/shared/footer/footer.component.html @@ -27,6 +27,7 @@ <span class="fill-remaining-space"></span> <button [matMenuTriggerFor]="langMenu" + (menuOpened)="openMenu()" aria-labelledby="language-label" class="focus_button" id="language-menu" diff --git a/src/app/components/shared/footer/footer.component.ts b/src/app/components/shared/footer/footer.component.ts index 2af9c97542e300c39ccd7da357725bd7790811b2..6cba039d5c54209b096782eb9ae1d556d9de4149 100644 --- a/src/app/components/shared/footer/footer.component.ts +++ b/src/app/components/shared/footer/footer.component.ts @@ -1,5 +1,5 @@ -import { LanguageService } from './../../../services/util/language.service'; -import { Component, OnInit } from '@angular/core'; +import { LanguageService } from '../../../services/util/language.service'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { NotificationService } from '../../../services/util/notification.service'; import { Router } from '@angular/router'; import { MatDialog } from '@angular/material/dialog'; @@ -18,6 +18,7 @@ import { AppComponent } from '../../../app.component'; import { StyleService } from '../../../../../projects/ars/src/lib/style/style.service'; import { MotdService } from '../../../services/http/motd.service'; import { MotdDialogComponent } from '../_dialogs/motd-dialog/motd-dialog.component'; +import { MatMenu } from '@angular/material/menu'; @Component({ selector: 'app-footer', @@ -26,6 +27,8 @@ import { MotdDialogComponent } from '../_dialogs/motd-dialog/motd-dialog.compone }) export class FooterComponent implements OnInit { + @ViewChild('langMenu') langaugeMenu: MatMenu; + public demoId = 'Feedback'; public room: Room; @@ -177,4 +180,12 @@ export class FooterComponent implements OnInit { getLanguage(): string { return localStorage.getItem('currentLang'); } + + openMenu() { + if (this.getLanguage() === 'de') { + this.langaugeMenu._allItems.get(0).focus(); + } else if (this.getLanguage() === 'en') { + this.langaugeMenu._allItems.get(1).focus(); + } + } } diff --git a/src/app/components/shared/header/header.component.html b/src/app/components/shared/header/header.component.html index a896aa9a99812982272d9f0fc0dcb56886ecd897..6477bdd39727ee736b92541bd617f028eb6f371c 100644 --- a/src/app/components/shared/header/header.component.html +++ b/src/app/components/shared/header/header.component.html @@ -17,7 +17,7 @@ </h2> - <ng-container *ngIf="room && room.closed && !router.url.includes('/room-list/')"> + <ng-container *ngIf="room && room.questionsBlocked"> <mat-icon>block</mat-icon><h1>{{'header.questions-blocked'|translate}}</h1> </ng-container> @@ -125,7 +125,7 @@ <ng-container *ngIf="router.url.endsWith('/comments')"> <button mat-menu-item - *ngIf="user && !router.url.endsWith('moderator/comments') && ((user.role > 0) || ((user.role == 0) && room && !room.closed))" + *ngIf="user && !router.url.endsWith('moderator/comments') && ((user.role > 0) || ((user.role == 0) && room && !room.questionsBlocked))" tabindex="0" (click)="navigateCreateQuestion();"> <mat-icon> @@ -360,13 +360,14 @@ <span>{{'header.delete-account' | translate}}</span> </button> - <ng-container *ngIf="router.url.includes('/creator') || router.url.includes('/moderator')"> + <ng-container *ngIf="room && user && user.role > 0"> <button mat-menu-item (click)="blockQuestions()" - [ngClass]="{'color-warn': room && room.closed}" + [ngClass]="{'color-warn': room && room.questionsBlocked}" tabindex="0"> <mat-icon class="color-warn">block</mat-icon> - <span>{{'header.block' | translate}}</span> + <span *ngIf="!room.questionsBlocked">{{'header.block' | translate}}</span> + <span *ngIf="room.questionsBlocked">{{'header.unlock' | translate}}</span> </button> </ng-container> diff --git a/src/app/components/shared/header/header.component.ts b/src/app/components/shared/header/header.component.ts index cff27dafb5e044c9499a616e70be86c34bf64f83..55a70f0b2d9b054854dcb4199885cccd043da212 100644 --- a/src/app/components/shared/header/header.component.ts +++ b/src/app/components/shared/header/header.component.ts @@ -25,6 +25,7 @@ import { RoomService } from '../../../services/http/room.service'; import { Room } from '../../../models/room'; import { TagCloudMetaData } from '../../../services/util/tag-cloud-data.service'; import { WorkerDialogComponent } from '../_dialogs/worker-dialog/worker-dialog.component'; +import { WsRoomService } from '../../../services/websockets/ws-room.service'; @Component({ selector: 'app-header', @@ -43,6 +44,7 @@ export class HeaderComponent implements OnInit { commentsCountQuestions = 0; commentsCountUsers = 0; commentsCountKeywords = 0; + private _subscriptionRoomService = null; constructor(public location: Location, private authenticationService: AuthenticationService, @@ -56,7 +58,8 @@ export class HeaderComponent implements OnInit { private _r: Renderer2, private motdService: MotdService, private confirmDialog: MatDialog, - private roomService: RoomService + private roomService: RoomService, + private wsRoomService: WsRoomService ) { } @@ -118,12 +121,25 @@ export class HeaderComponent implements OnInit { const segments = this.router.parseUrl(this.router.url).root.children.primary.segments; this.shortId = ''; this.room = null; + if (this._subscriptionRoomService) { + this._subscriptionRoomService.unsubscribe(); + this._subscriptionRoomService = null; + } if (segments && segments.length > 2) { if (!segments[2].path.includes('%')) { this.shortId = segments[2].path; localStorage.setItem('shortId', this.shortId); - this.roomService.getRoomByShortId(this.shortId).subscribe(room => this.room = room); + this.roomService.getRoomByShortId(this.shortId).subscribe(room => { + this.room = room; + this._subscriptionRoomService = this.wsRoomService.getRoomStream(this.room.id).subscribe(msg => { + const message = JSON.parse(msg.body); + if (message.type === 'RoomPatched') { + this.room.questionsBlocked = message.payload.changes.questionsBlocked; + this.moderationEnabled = message.payload.changes.moderated; + } + }); + }); } } } @@ -150,6 +166,12 @@ export class HeaderComponent implements OnInit { }); } + ngOnDestroy() { + if (this._subscriptionRoomService) { + this._subscriptionRoomService.unsubscribe(); + } + } + showMotdDialog() { this.motdService.requestDialog(); } @@ -319,11 +341,10 @@ export class HeaderComponent implements OnInit { public blockQuestions() { // flip state if clicked this.room.questionsBlocked = !this.room.questionsBlocked; - this.roomService.updateRoom(this.room).subscribe(r => this.room = r); + this.roomService.updateRoom(this.room).subscribe(); } public startWorkerDialog() { WorkerDialogComponent.addWorkTask(this.dialog, this.room); } - } diff --git a/src/app/components/shared/room-join/room-join.component.ts b/src/app/components/shared/room-join/room-join.component.ts index 6a4cd17481cccb71667f21352b2a4cbe82628431..cc6a6ea8e23488cf3626cbab9095f34f5a2d9916 100644 --- a/src/app/components/shared/room-join/room-join.component.ts +++ b/src/app/components/shared/room-join/room-join.component.ts @@ -93,6 +93,7 @@ export class RoomJoinComponent implements OnInit { addAndNavigate() { if (this.user.id === this.room.ownerId) { + this.authenticationService.setAccess(this.room.shortId, UserRole.CREATOR); this.router.navigate([`/creator/room/${this.room.shortId}/comments`]); } else { this.roomService.addToHistory(this.room.id); 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 c79c3e2823960818fdf21898ae076a1f2ad97e60..77632d2beca37497f11686c5500481ebd61944b5 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,7 +42,7 @@ </p> </span> </div> - <div class="replacementContainer" *ngIf="checkLanguage && user && user.role >= 1"> + <div class="replacementContainer" *ngIf="user && user.role >= 1"> <mat-form-field> <mat-label>{{'tag-cloud-popup.tag-correction-placeholder' | translate}}</mat-label> <input type="text" 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 0c25bfda2a286c6c3f77110629964be649708243..0ad09a4ccbc6945c625d236e41cbc45e3138b552 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 @@ -10,6 +10,7 @@ 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'; +import { UserRole } from '../../../../models/user-roles.enum'; const CLOSE_TIME = 1500; @@ -30,7 +31,6 @@ export class TagCloudPopUpComponent implements OnInit, AfterViewInit { user: User; selectedLang: Language = 'en-US'; spellingData: string[] = []; - checkLanguage = false; private _popupHoverTimer: number; private _popupCloseTimer: number; private _hasLeft = true; @@ -77,10 +77,9 @@ export class TagCloudPopUpComponent implements OnInit, AfterViewInit { this.close(); } - enter(elem: HTMLElement, tag: string, tagData: TagCloudDataTagEntry, hoverDelayInMs: number, checkLanguage: boolean): void { - this.checkLanguage = checkLanguage; - if (checkLanguage) { - this.spellingData = []; + enter(elem: HTMLElement, tag: string, tagData: TagCloudDataTagEntry, hoverDelayInMs: number): void { + this.spellingData = []; + if (this.user && this.user.role > UserRole.PARTICIPANT) { this.languagetoolService.checkSpellings(tag, 'auto').subscribe(correction => { const langKey = correction.language.code.split('-')[0].toUpperCase(); if (['DE', 'FR', 'EN'].indexOf(langKey) < 0) { 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 92b98129d35165eb5a91059851dbf27cd3f6d0b9..37c401a931362c0a318d7b32b23fb187b34e1a0e 100644 --- a/src/app/components/shared/tag-cloud/tag-cloud.component.ts +++ b/src/app/components/shared/tag-cloud/tag-cloud.component.ts @@ -77,16 +77,16 @@ type DefaultColors = [ ]; const defaultColors: DefaultColors = [ 'var(--secondary, greenyellow)', - 'var(--moderator, lightblue)', - 'var(--blue, green)', - 'var(--grey, yellow)', - 'var(--red, orange)', - 'var(--primary, pink)', - 'var(--yellow, gray)', - 'var(--on-background, lightgreen)', - 'var(--purple, tomato)', - 'var(--magenta, white)', - 'var(--light-green, brown)', + '#f1f1f1', + '#d98e49', + '#ccca3c', + '#83e761', + '#3accd4', + '#54a1e9', + '#3a44ee', + '#9725eb', + '#e436c7', + '#ff0000', 'var(--background, black)' ]; @@ -111,32 +111,31 @@ const getResolvedDefaultColors = (): string[] => { const getDefaultCloudParameters = (): CloudParameters => { const resDefaultColors = getResolvedDefaultColors(); const weightSettings: CloudWeightSettings = [ - {maxVisibleElements: -1, color: resDefaultColors[1], rotation: 0}, - {maxVisibleElements: -1, color: resDefaultColors[2], rotation: 0}, - {maxVisibleElements: -1, color: resDefaultColors[3], rotation: 0}, - {maxVisibleElements: -1, color: resDefaultColors[4], rotation: 0}, - {maxVisibleElements: -1, color: resDefaultColors[5], rotation: 0}, - {maxVisibleElements: -1, color: resDefaultColors[6], rotation: 0}, - {maxVisibleElements: -1, color: resDefaultColors[7], rotation: 0}, - {maxVisibleElements: -1, color: resDefaultColors[8], rotation: 0}, - {maxVisibleElements: -1, color: resDefaultColors[9], rotation: 0}, - {maxVisibleElements: -1, color: resDefaultColors[10], rotation: 0}, + {maxVisibleElements: 5, color: resDefaultColors[1], rotation: 0}, + {maxVisibleElements: 6, color: resDefaultColors[2], rotation: 0}, + {maxVisibleElements: 5, color: resDefaultColors[3], rotation: 0}, + {maxVisibleElements: 6, color: resDefaultColors[4], rotation: 0}, + {maxVisibleElements: 5, color: resDefaultColors[5], rotation: 0}, + {maxVisibleElements: 6, color: resDefaultColors[6], rotation: 0}, + {maxVisibleElements: 5, color: resDefaultColors[7], rotation: 0}, + {maxVisibleElements: 6, color: resDefaultColors[8], rotation: 0}, + {maxVisibleElements: 5, color: resDefaultColors[9], rotation: 0}, + {maxVisibleElements: 6, color: resDefaultColors[10], rotation: 0}, ]; return { fontFamily: 'Dancing Script', - fontWeight: 'normal', + fontWeight: 'bold', fontStyle: 'normal', - fontSize: '10px', + fontSize: '280px', backgroundColor: resDefaultColors[11], fontColor: resDefaultColors[0], - fontSizeMin: 100, + fontSizeMin: 280, fontSizeMax: 380, hoverScale: 1.3, hoverTime: 0.6, hoverDelay: 0.4, delayWord: 0, randomAngles: true, - checkSpelling: true, sortAlphabetically: false, textTransform: CloudTextStyle.normal, cloudWeightSettings: weightSettings @@ -238,10 +237,16 @@ export class TagCloudComponent implements OnInit, OnDestroy, AfterContentInit, A }); } }); - this.dataManager.getData().subscribe(_ => { + this.dataManager.getData().subscribe(data => { + if (!data) { + return; + } this.rebuildData(); }); this.dataManager.getMetaData().subscribe(data => { + if (!data) { + return; + } this.eventService.broadcast('tagCloudHeaderDataOverview', data); }); this.authenticationService.watchUser.subscribe(newUser => { @@ -439,8 +444,7 @@ export class TagCloudComponent implements OnInit, OnDestroy, AfterContentInit, A }); elem.addEventListener('mouseenter', () => { this.popup.enter(elem, dataElement.text, dataElement.tagData, - (this._currentSettings.hoverTime + this._currentSettings.hoverDelay) * 1_000, - this._currentSettings.checkSpelling); + (this._currentSettings.hoverTime + this._currentSettings.hoverDelay) * 1_000); }); }); } @@ -477,7 +481,7 @@ export class TagCloudComponent implements OnInit, OnDestroy, AfterContentInit, A 'font-size: ' + (this._currentSettings.fontSizeMin + fontRange * i).toFixed(0) + '%; }'); } customTagCloudStyles.sheet.insertRule('.spacyTagCloud > span:hover, .spacyTagCloud > span:hover > a { ' + - 'color: ' + this._currentSettings.fontColor + '; ' + + 'color: ' + this._currentSettings.fontColor + ' !important; ' + 'background-color: ' + this._currentSettings.backgroundColor + '; }'); customTagCloudStyles.sheet.insertRule('.spacyTagCloudContainer { ' + 'background-color: ' + this._currentSettings.backgroundColor + '; }'); diff --git a/src/app/components/shared/tag-cloud/tag-cloud.interface.ts b/src/app/components/shared/tag-cloud/tag-cloud.interface.ts index b6f0edf187bf9b80fc536327d88e54c876e8b7c5..240eb3b0b6eade4a3b802b0b482c091fec322e10 100644 --- a/src/app/components/shared/tag-cloud/tag-cloud.interface.ts +++ b/src/app/components/shared/tag-cloud/tag-cloud.interface.ts @@ -94,10 +94,6 @@ export interface CloudParameters { * Sorts the cloud alphabetical. */ sortAlphabetically: boolean; - /** - * Checks if the word is spelled correctly, if not, do not display it. - */ - checkSpelling: boolean; /** * Custom CSS text transform setting */ diff --git a/src/app/models/comment.ts b/src/app/models/comment.ts index 0e146b36f901c6840cd7284d718f3ec5d2e80401..8de26629ffa7d82ce9c47e34634dbe0b82b87de7 100644 --- a/src/app/models/comment.ts +++ b/src/app/models/comment.ts @@ -1,4 +1,3 @@ -import { dashCaseToCamelCase } from '@angular/compiler/src/util'; import { Model } from '../services/http/spacy.service'; import { CorrectWrong } from './correct-wrong.enum'; diff --git a/src/app/models/room.ts b/src/app/models/room.ts index be6409f31f70758fa396ac0a0ca59a9766c7fde4..abd4a42965183ac5dcf0adc0381067e857996cd1 100644 --- a/src/app/models/room.ts +++ b/src/app/models/room.ts @@ -15,7 +15,6 @@ export class Room { questionsBlocked: boolean; profanityFilter: ProfanityFilter; - constructor( ownerId: string = '', shortId: string = '', @@ -48,7 +47,7 @@ export class Room { } } -export enum ProfanityFilter{ +export enum ProfanityFilter { all = 'ALL', languageSpecific = 'LANGUAGE_SPECIFIC', partialWords = 'PARTIAL_WORDS', diff --git a/src/app/services/util/room-data.service.ts b/src/app/services/util/room-data.service.ts index 5e24a138d622ecd14c7f646d08a0def56f58dbc3..498e8c262c4ed96183595d7107d29987cf827212 100644 --- a/src/app/services/util/room-data.service.ts +++ b/src/app/services/util/room-data.service.ts @@ -8,7 +8,7 @@ import { CorrectWrong } from '../../models/correct-wrong.enum'; import { RoomService } from '../http/room.service'; import { ProfanityFilterService } from './profanity-filter.service'; import { ProfanityFilter, Room } from '../../models/room'; -import { WsRoomService } from '..//websockets/ws-room.service'; +import { WsRoomService } from '../websockets/ws-room.service'; export interface UpdateInformation { type: 'CommentCreated' | 'CommentPatched' | 'CommentHighlighted' | 'CommentDeleted'; @@ -130,7 +130,7 @@ export class RoomDataService { return tempSubject.asObservable(); } - public checkProfanity(comment: Comment){ + public checkProfanity(comment: Comment) { const finish = new Subject<boolean>(); const subscription = finish.asObservable().subscribe(_ => { if (this.room.profanityFilter !== ProfanityFilter.deactivated) { @@ -162,7 +162,7 @@ export class RoomDataService { this._savedCommentsAfterFilter.set(comment.id, this.filterCommentOfProfanity(this.room, comment)); } - private filterAllCommentsBodies(){ + private filterAllCommentsBodies() { this._currentComments.forEach(comment => { comment.body = this._savedCommentsBeforeFilter.get(comment.id); this.setCommentBody(comment); @@ -192,10 +192,10 @@ export class RoomDataService { if (this._wsCommentServiceSubscription) { this._wsCommentServiceSubscription.unsubscribe(); } - this._wsCommentServiceSubscription = this.wsCommentService.getCommentStream(roomId) - .subscribe(msg => this.onMessageReceive(msg)); this.roomService.getRoom(roomId).subscribe(room => { this.room = room; + this._wsCommentServiceSubscription = this.wsCommentService.getCommentStream(roomId) + .subscribe(msg => this.onMessageReceive(msg)); this.commentService.getAckComments(roomId).subscribe(comments => { this._currentComments = comments; for (const comment of comments) { @@ -252,19 +252,23 @@ export class RoomDataService { c.tag = payload.tag; c.creatorId = payload.creatorId; c.userNumber = this.commentService.hashCode(c.creatorId); + c.keywordsFromQuestioner = JSON.parse(payload.keywordsFromQuestioner); + this._fastCommentAccess[c.id] = c; + this._currentComments.push(c); this.triggerUpdate(UpdateType.commentStream, { type: 'CommentCreated', finished: false, comment: c }); this.commentService.getComment(c.id).subscribe(comment => { - this._fastCommentAccess[comment.id] = comment; - this._currentComments.push(comment); - this.setCommentBody(comment); + for (const key of Object.keys(comment)) { + c[key] = comment[key]; + } + this.setCommentBody(c); this.triggerUpdate(UpdateType.commentStream, { type: 'CommentCreated', finished: true, - comment + comment: c }); }); } diff --git a/src/app/services/util/tag-cloud-data.service.ts b/src/app/services/util/tag-cloud-data.service.ts index 07fb647467c658e3ed2dc3dbec70508a26c8e83a..8509c510737cb4a2c2f5a462346bdc371a2b07e7 100644 --- a/src/app/services/util/tag-cloud-data.service.ts +++ b/src/app/services/util/tag-cloud-data.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { TopicCloudAdminData } from '../../components/shared/_dialogs/topic-cloud-administration/TopicCloudAdminData'; -import { Observable, Subject, Subscription } from 'rxjs'; +import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs'; import { TopicCloudAdminService } from './topic-cloud-admin.service'; import { CommentFilter } from '../../utils/filter-options'; import { TranslateService } from '@ngx-translate/core'; @@ -65,8 +65,8 @@ export enum TagCloudCalcWeightType { export class TagCloudDataService { private _isDemoActive: boolean; private _isAlphabeticallySorted: boolean; - private _dataBus: Subject<TagCloudData>; - private _metaDataBus: Subject<TagCloudMetaData>; + private _dataBus: BehaviorSubject<TagCloudData>; + private _metaDataBus: BehaviorSubject<TagCloudMetaData>; private _cachedData: TagCloudData; private _commentSubscription = null; private _roomId = null; @@ -85,7 +85,7 @@ export class TagCloudDataService { private _roomDataService: RoomDataService) { this._isDemoActive = false; this._isAlphabeticallySorted = false; - this._dataBus = new Subject<TagCloudData>(); + this._dataBus = new BehaviorSubject<TagCloudData>(null); this._currentMetaData = { tagCount: 0, commentCount: 0, @@ -94,7 +94,7 @@ export class TagCloudDataService { maxWeight: 0, countPerWeight: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }; - this._metaDataBus = new Subject<TagCloudMetaData>(); + this._metaDataBus = new BehaviorSubject<TagCloudMetaData>(null); this._cachedData = null; // Subscribe to own 'service' for caching this._dataBus.asObservable().subscribe(data => { diff --git a/src/app/services/util/topic-cloud-admin.service.ts b/src/app/services/util/topic-cloud-admin.service.ts index 1c923f11084b1eacc4b629e54e135110af177fac..8b787e474077972eb676bde33272e5b8d33943a1 100644 --- a/src/app/services/util/topic-cloud-admin.service.ts +++ b/src/app/services/util/topic-cloud-admin.service.ts @@ -89,6 +89,7 @@ export class TopicCloudAdminService { if (_adminData.profanityFilter !== ProfanityFilter.deactivated) { _adminData.blacklist = _adminData.blacklist.concat(this.profanityFilterService.getProfanityList); } + localStorage.setItem(TopicCloudAdminService.adminKey, JSON.stringify(_adminData)); this.adminData.next(_adminData); }); } diff --git a/src/app/utils/create-comment-keywords.ts b/src/app/utils/create-comment-keywords.ts index 5b8c2d691419b4ba95a4fd290f820bf2c49abd3c..1e9d595b5a48fddf1b7f26a077deb39986d4bb3d 100644 --- a/src/app/utils/create-comment-keywords.ts +++ b/src/app/utils/create-comment-keywords.ts @@ -2,6 +2,7 @@ import { Language, LanguagetoolService } from '../services/http/languagetool.ser import { map } from 'rxjs/operators'; export class CreateCommentKeywords { + static isSpellingAcceptable(languagetoolService: LanguagetoolService, text: string, language: Language = 'auto') { text = this.cleaningFunction(text); return languagetoolService.checkSpellings(text, language).pipe( diff --git a/src/app/utils/filter-options.ts b/src/app/utils/filter-options.ts index 7669a7d697a59d6d442d135815612e893562e45a..9268cbcf7cdb9cfab1ba03bc72c50e772f977386 100644 --- a/src/app/utils/filter-options.ts +++ b/src/app/utils/filter-options.ts @@ -26,12 +26,13 @@ export class CommentFilter { filterSelected = ''; keywordSelected = ''; tagSelected = ''; + userNumberSelected = 0; paused = false; timeStampUntil = 0; periodSet: Period = Period.twoWeeks; - timeStampNow = 0; + timeStampNow = 0; constructor(obj?: any) { if (obj) { @@ -42,6 +43,7 @@ export class CommentFilter { this.timeStampUntil = obj.timeStampUntil; this.periodSet = obj.periodSet; this.timeStampNow = obj.timeStampNow; + this.userNumberSelected = obj.userNumberSelected; } } @@ -56,6 +58,7 @@ export class CommentFilter { public static generateFilterNow(filterSelected: string): CommentFilter { const filter = new CommentFilter(); + filter.userNumberSelected = 0; filter.filterSelected = filterSelected; filter.paused = false; @@ -72,6 +75,8 @@ export class CommentFilter { tagSelected: string, keywordSelected: string): CommentFilter { const filter = new CommentFilter(); + + filter.userNumberSelected = 0; filter.filterSelected = filterSelected; filter.paused = true; @@ -154,6 +159,10 @@ export class CommentFilter { } } + if (this.userNumberSelected !== 0) { + return com.userNumber === this.userNumberSelected; + } + if (this.keywordSelected !== '') { return com.keywordsFromQuestioner.includes(this.keywordSelected); } diff --git a/src/assets/i18n/creator/de.json b/src/assets/i18n/creator/de.json index ff969e902e4493d58f1a2de32166b6c7b0e63049..787822a15bf209f45cf983e1a60820d725246989 100644 --- a/src/assets/i18n/creator/de.json +++ b/src/assets/i18n/creator/de.json @@ -417,6 +417,15 @@ "read-more": "Mehr lesen", "read-less": "Weniger lesen" }, + "tag-cloud": { + "demo-data-topic": "Thema %d", + "overview-question-topic-tooltip": "Anzahl gestellter Fragen mit diesem Thema", + "overview-questioners-topic-tooltip": "Anzahl Fragensteller*innen mit diesem Thema", + "period-since-first-comment":"Zeitraum seit erstem Kommentar", + "upvote-topic": "Upvotes für dieses Thema", + "downvote-topic": "Downvotes für dieses Thema", + "blacklist-topic": "Thema zur Blacklist hinzufügen" + }, "tag-cloud-config":{ "general":"Allgemein", "overflow":"Überlauf", @@ -436,6 +445,7 @@ "font-size-max":"Schriftgröße max", "select-color": "Farbauswahl", "random-angle-tooltip": "Anordnung der Winkel zufällig generieren", + "random-angle-note": "Wenn Aktiviert, wird die Rotierung der einzelnen Relevanz-Gruppen deaktiviert", "background-tooltip": "Auswahl der Hintergrundfarbe", "word-delay-tooltip": "Animationsverzögerung der Wörter", "font-size-min-tooltip": "Auswahl der minimalen Schriftgrösse", @@ -444,14 +454,13 @@ "hover-scale-tooltip": "Skallierung der Wörter beim Erscheinen", "hover-time-tooltip": "Festlegen der Erscheinungszeit der Wörter", "hover-delay-tooltip": "Hover-Verzögerung der Wörter", - "weight-class-settings": "Relevanz-Gruppen", + "weight-class-settings": "Relevanz", "weight-class": "Relevanz-Gruppe", "back-btn": "Zurück", "weight-color": "Schriftfarbe", "weight-number": "max. Anzahl Schlüsselwörter", "weight-color-tooltip": "Auswahl der Schriftfarbe", "weight-number-tooltip": "maximale Anzahl der Schlüsselwörter festlegen", - "automatic-spelling": "Rechtschreibüberprüfung", "notation": "Notation:", "lowerCase": "Kleinschreibung", "capitalization": "Kapitälchen", @@ -461,7 +470,6 @@ "cleanUpView": "Tag-Cleanup Einstellungen", "rotation": "Drehgrad zufälliger Einträge", "highestWeight": "Anzahl Tags mit max. Gewichtung", - "automatic-spelling-tooltip": "automatische Überprüfung der Rechtschreibung", "notation-tooltip": "Einstellung der Schreibweise: klein, groß, standard", "alphabetical-sorting-tooltip": "Alphabetische Sortierung", "highestWeight-tooltip": "x Tags mit der höchsten Gewichtung anzeigen", @@ -469,8 +477,10 @@ "rotate-weight-tooltip": "einige Einträge dieser Wichtigkeitsklassen zufällig um x Grad drehen", "font":"Schrift", "reset-btn": "Zurücksetzten", + "font-family-tooltip": "Schriftart auswählen", + "bold-notation-tooltip": "Schriftdicke fett auswählen", "font-style-bold" : "Fett", "font-style-italic": "Kursiv", - "font-family":"Schrift Art" + "font-family":"Schriftart" } } diff --git a/src/assets/i18n/creator/en.json b/src/assets/i18n/creator/en.json index e40833745e900ccfca5c31895c6d4934919cedd1..36f43b1101e200392d087d6575a756dbb254b33d 100644 --- a/src/assets/i18n/creator/en.json +++ b/src/assets/i18n/creator/en.json @@ -348,6 +348,15 @@ "session-name": "Session name", "preview": "Preview" }, + "tag-cloud": { + "demo-data-topic": "Topic %d", + "overview-question-topic-tooltip": "Number of questions with this topic", + "overview-questioners-topic-tooltip": "Number of questioners with this topic", + "period-since-first-comment":"Period since first comment", + "upvote-topic": "Upvotes for this topic", + "downvote-topic": "Downvotes for this topic", + "blacklist-topic": "Add topic to blacklist" + }, "tag-cloud-popup": { "few-seconds": "few seconds", "few-minutes": "few minutes", @@ -435,6 +444,7 @@ "font-size-max":"Font size max", "select-color": "Selected color", "random-angle-tooltip": "Generate angle randomly", + "random-angle-note": "If Enabled, the rotation of the individual weight-class is disabled", "background-tooltip": "Select background-color", "word-delay-tooltip": "Select word-delay", "font-size-min-tooltip": "Select minimum font-size", @@ -450,7 +460,6 @@ "weight-number": "max. number of keywords", "weight-color-tooltip": "Select font-color", "weight-number-tooltip": "Select maximal number of keywords", - "automatic-spelling": "Spell check", "notation": "Notation:", "lowerCase": "Lower case", "capitalization": "Capitalization", @@ -460,14 +469,15 @@ "cleanUpView": "Tag-Cleanup Settings", "rotation": "rotation of random entries", "highestWeight": "Number of tags with highest weight", - "automatic-spelling-tooltip": "spell check", "notation-tooltip": "Notation-Settings: small, large, standard", "alphabetical-sorting-tooltip": "Alphabetical sorting", "rotate-weight-tooltip": "Rotate some entries randomly by x degrees", "highestWeight-tooltip": "show x tags with the highest weight", "rotate-weight": "Rotate some entries of this weight class randomly by x degrees", "font":"Font", - "reset-btn": "Reset", + "reset-btn": "Reset", + "font-family-tooltip": "Select font", + "bold-notation-tooltip": "Select font-thickness bold", "font-style-bold" : "Bold", "font-style-italic": "Italic", "font-family":"Font Family" diff --git a/src/assets/i18n/home/de.json b/src/assets/i18n/home/de.json index ae37748f62aa3ff545d77333707dc34d2daac700..2d60f5976339e0bc05d73ce1818cc54b90bc4bb3 100644 --- a/src/assets/i18n/home/de.json +++ b/src/assets/i18n/home/de.json @@ -50,9 +50,9 @@ "cancel": "Abbrechen", "continue": "Weiter", "reset": "Zurücksetzen", - "continue-with-all-questions" : "Weiter mit kompletter Fragenliste", - "continue-with-current-questions": "Weiter mit aktuellen Filtern", - "continue-with-all-questions-from-now": "Weiter mit allen Fragen ab jetzt" + "continue-with-all-questions" : "Weiter mit allen Fragen der Sitzung", + "continue-with-current-questions": "Weiter mit aktueller Fragenliste", + "continue-with-all-questions-from-now": "Weiter mit Fragen, die ab jetzt gestellt werden" }, "header": { "abort": "Abbrechen", @@ -70,6 +70,7 @@ "login": "Anmelden", "logout": "Abmelden", "block": "Fragen sperren", + "unlock": "Fragen entsperen", "moderation-enabled": "Die Sitzung wird moderiert.", "QR": "QR-Code der Sitzung in Vollansicht", "my-account": "Optionen", diff --git a/src/assets/i18n/home/en.json b/src/assets/i18n/home/en.json index c9b76af9ee3b284c64c2ec257d66ad07dd1bd97e..c55219181bb5f52aaf58cfb7e80eba8cb9745fec 100644 --- a/src/assets/i18n/home/en.json +++ b/src/assets/i18n/home/en.json @@ -56,6 +56,7 @@ "cancel": "Cancel", "delete": "Delete", "block" : "Block questions", + "unlock": "Unlock questions", "delete-account": "Delete account", "home-header": "Collect and rate questions", "id": "Key", @@ -130,9 +131,9 @@ "cancel": "Cancel", "continue": "Continue", "reset": "Reset", - "continue-with-all-questions" : "Continue with complete list of questions", - "continue-with-current-questions": "Continue with current filters", - "continue-with-all-questions-from-now": "Continue with all questions from now" + "continue-with-all-questions" : "Continue with all questions of the session", + "continue-with-current-questions": "Continue with current question list", + "continue-with-all-questions-from-now": "Continue with questions that will be asked form now on" }, "imprint": { diff --git a/src/assets/i18n/participant/de.json b/src/assets/i18n/participant/de.json index 6df5a1d3970733668d9b049430ccbf228968cdee..221bbd0ff236a3870944b6f646cb48e32a172de0 100644 --- a/src/assets/i18n/participant/de.json +++ b/src/assets/i18n/participant/de.json @@ -100,7 +100,8 @@ "edit-keyword-hint": "Stichwort editieren", "editing-done-hint": "Editierung abschliessen", "force-language-selection": "Automatische Spracherkennung unpräzise, bitte gewählte Sprache prüfen!", - "add-manually": "Geben Sie bitte die Stichwörter unten mit separatem Komma ein" + "add-manually": "Geben Sie bitte die Stichwörter unten mit separatem Komma ein", + "select-keywords": "Wählen Sie die Stichwörter für Ihre Frage aus" }, "comment-page": { "a11y-comment_input": "Gib deine Frage ein", @@ -232,8 +233,6 @@ "questions-blocked": "Fragen sind deaktiviert!" }, "tag-cloud": { - "config": "Wolkenansicht ändern", - "administration": "Wolkenthemen editieren", "demo-data-topic": "Thema %d", "overview-question-topic-tooltip": "Anzahl gestellter Fragen mit diesem Thema", "overview-questioners-topic-tooltip": "Anzahl Fragensteller*innen mit diesem Thema", @@ -332,6 +331,7 @@ "font-size-max": "Schriftgröße max", "select-color": "Farbauswahl", "random-angle-tooltip": "Anordnung der Winkel zufällig generieren", + "random-angle-note": "Wenn Aktiviert, wird die Rotierung der einzelnen Relevanz-Gruppen deaktiviert", "background-tooltip": "Auswahl der Hintergrundfarbe", "word-delay-tooltip": "Animationsverzögerung der Wörter", "font-size-min-tooltip": "Auswahl der minimalen Schriftgrösse", @@ -342,13 +342,12 @@ "hover-delay-tooltip": "Hover-Verzögerung der Wörter", "extended-btn": "Wichtigkeitsklasse", "back-btn": "Zurück", - "weight-class-settings": "Relevanz-Gruppen", + "weight-class-settings": "Relevanz", "weight-class": "Relevanz-Gruppe", "weight-color": "Schriftfarbe", "weight-number": "max. Anzahl Schlüsselwörter", "weight-color-tooltip": "Auswahl der Schriftfarbe", "weight-number-tooltip": "maximale Anzahl der Schlüsselwörter festlegen", - "automatic-spelling": "Rechtschreibüberprüfung", "notation": "Notation:", "lowerCase": "Kleinschreibung", "capitalization": "Kapitälchen", @@ -358,16 +357,17 @@ "cleanUpView": "Tag-Cleanup Einstellungen", "rotation": "Drehgrad zufälliger Einträge", "highestWeight": "Anzahl Tags mit max. Gewichtung", - "automatic-spelling-tooltip": "automatische Überprüfung der Rechtschreibung", "notation-tooltip": "Einstellung der Schreibweise: klein, groß, standard", "alphabetical-sorting-tooltip": "Alphabetische Sortierung", "highestWeight-tooltip": "x Tags mit der höchsten Gewichtung anzeigen", "rotate-weight": "Einige Einträge dieser Klasse zufällig um x Grad drehen", "rotate-weight-tooltip": "einige Einträge dieser Wichtigkeitsklasse zufällig um x Grad drehen", "font":"Schrift", - "reset-btn": "Zurücksetzten", + "reset-btn": "Zurücksetzten", + "font-family-tooltip": "Schriftart auswählen", + "bold-notation-tooltip": "Schriftdicke fett auswählen", "font-style-bold" : "Fett", "font-style-italic": "Kursiv", - "font-family":"Schrift Art" + "font-family":"Schriftart" } } diff --git a/src/assets/i18n/participant/en.json b/src/assets/i18n/participant/en.json index c738162dca5405a6c99ff07bd0a6c6b4bd83aa9a..d32eb74547d79e7f9877df076c0986ad1f086d48 100644 --- a/src/assets/i18n/participant/en.json +++ b/src/assets/i18n/participant/en.json @@ -110,7 +110,8 @@ "edit-keyword-hint": "Edit keyword", "editing-done-hint": "Finish editing", "force-language-selection": "Language detection inaccurate, please check language settings!", - "add-manually": "You can manually enter the keywords separated with a comma " + "add-manually": "You can manually enter the keywords separated with a comma", + "select-keywords": "Choose the keywords for your question" }, "comment-page": { "a11y-comment_input": "Enter your question", @@ -238,8 +239,6 @@ "questions-blocked": "No further questions!" }, "tag-cloud": { - "config": "Modify cloud view", - "administration": "Edit cloud topics", "demo-data-topic": "Topic %d", "overview-question-topic-tooltip": "Number of questions with this topic", "overview-questioners-topic-tooltip": "Number of questioners with this topic", @@ -338,6 +337,7 @@ "font-size-max":"Font size max", "select-color": "Selected color", "random-angle-tooltip": "Generate angle randomly", + "random-angle-note": "If Enabled, the rotation of the individual weight-class is disabled", "background-tooltip": "Select background-color", "word-delay-tooltip": "Select word-delay", "font-size-min-tooltip": "Select minimum font-size", @@ -354,7 +354,6 @@ "weight-number": "max. number of keywords", "weight-color-tooltip": "Select font-color", "weight-number-tooltip": "Select maximal number of keywords", - "automatic-spelling": "Spell check", "notation": "Notation:", "lowerCase": "Lower case", "capitalization": "Capitalization", @@ -364,7 +363,6 @@ "cleanUpView": "Tag-Cleanup Settings", "rotation": "rotation of random entries", "highestWeight": "Number of tags with highest weight", - "automatic-spelling-tooltip": "automatic spelling check", "notation-tooltip": "Notation-Settings: small, large, standard", "alphabetical-sorting-tooltip": "Alphabetical sorting", "rotate-weight-tooltip": "Rotate some entries randomly by x degrees", @@ -372,6 +370,8 @@ "rotate-weight": "Rotate some entries of this weight class randomly by x degrees", "font":"Font", "reset-btn": "Reset", + "font-family-tooltip": "Select font", + "bold-notation-tooltip": "Select font-thickness bold", "font-style-bold" : "Bold", "font-style-italic": "Italic", "font-family":"Font Family"