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 744beea27e2131ebac46c0fa000c3a5f410b0f75..3dc3a4528245855d1a48f62e446ef04c7755b6b0 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 @@ -1,7 +1,7 @@ <ars-row ars-flex-box> <app-write-comment [confirmLabel]="'send'" - [onSubmit]="buildCreateCommentActionCallback()" - [onClose]="buildCloseDialogActionCallback()" + [onSubmit]="this.closeDialog.bind(this)" + [onClose]="this.onNoClick.bind(this)" [isSpinning]="isSendingToSpacy" [tags]="tags" [user]="user"> 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 0b16dd17eacfaad79f6d3c6d154b807e0c23714e..00d57e8ff6115ec5d362d3ef3163b564edbd5b06 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 @@ -23,9 +23,7 @@ export class CreateCommentComponent implements OnInit { user: User; roomId: string; tags: string[]; - selectedTag: string; isSendingToSpacy = false; - tempEditView: string; constructor( private notification: NotificationService, @@ -45,32 +43,19 @@ export class CreateCommentComponent implements OnInit { this.dialogRef.close(); } - checkInputData(body: string): boolean { - body = body.trim(); - if (!body) { - this.translateService.get('comment-page.error-comment').subscribe(message => { - this.notification.show(message); - }); - return false; - } - return true; - } - - closeDialog(body: string) { - if (this.checkInputData(body) === true) { - const comment = new Comment(); - comment.roomId = localStorage.getItem(`roomId`); - comment.body = body; - comment.creatorId = this.user.id; - comment.createdFromLecturer = this.user.role === 1; - comment.tag = this.selectedTag; - this.isSendingToSpacy = true; - this.openSpacyDialog(comment); - } + closeDialog(body: string, text: string, tag: string) { + const comment = new Comment(); + comment.roomId = localStorage.getItem(`roomId`); + comment.body = body; + comment.creatorId = this.user.id; + comment.createdFromLecturer = this.user.role > 0; + comment.tag = tag; + this.isSendingToSpacy = true; + this.openSpacyDialog(comment, text); } - openSpacyDialog(comment: Comment): void { - CreateCommentKeywords.isSpellingAcceptable(this.languagetoolService, comment.body, this.commentComponent.selectedLang) + openSpacyDialog(comment: Comment, rawText: string): void { + CreateCommentKeywords.isSpellingAcceptable(this.languagetoolService, rawText, this.commentComponent.selectedLang) .subscribe((result) => { if (result.isAcceptable) { const commentLang = this.languagetoolService.mapLanguageToSpacyModel(result.result.language.code as Language); @@ -105,12 +90,4 @@ export class CreateCommentComponent implements OnInit { this.isSendingToSpacy = false; }); } - - buildCloseDialogActionCallback(): () => void { - return () => this.onNoClick(); - } - - buildCreateCommentActionCallback(): (string) => void { - return (text: string) => this.closeDialog(text); - } } diff --git a/src/app/components/shared/view-comment-data/view-comment-data.component.html b/src/app/components/shared/view-comment-data/view-comment-data.component.html index 7ea97ddacb9c87275859f22124eb20f2d5b527ca..647fe95b42a1a8139aa0555f730318a8fdaef538 100644 --- a/src/app/components/shared/view-comment-data/view-comment-data.component.html +++ b/src/app/components/shared/view-comment-data/view-comment-data.component.html @@ -9,7 +9,10 @@ <div #tooltipContainer></div> <div fxLayout="row" style="justify-content: space-between; padding: 0 5px"> <span aria-hidden="true" style="font-size: 75%"> - {{currentData.length}} / {{user.role === 3 ? 1000 : 500}} + {{ 'comment-page.Markdown-hint' | translate }} + </span> + <span aria-hidden="true" style="font-size: 75%"> + {{currentText.length}} / {{maxTextCharacters}} </span> </div> </ars-row> diff --git a/src/app/components/shared/view-comment-data/view-comment-data.component.ts b/src/app/components/shared/view-comment-data/view-comment-data.component.ts index 814d45e17448e1c3e88510bf219a240c3462ec3c..ac59274cf715e20971985300e0c73cb986b194b4 100644 --- a/src/app/components/shared/view-comment-data/view-comment-data.component.ts +++ b/src/app/components/shared/view-comment-data/view-comment-data.component.ts @@ -33,13 +33,14 @@ export class ViewCommentDataComponent implements OnInit, AfterViewInit { @Input() isEditor = false; @Input() user: User; @Input() currentData = ''; + @Input() maxTextCharacters = 500; @Input() markEvents?: { onCreate: (markContainer: HTMLDivElement, tooltipContainer: HTMLDivElement, editor: QuillEditorComponent) => void; onChange: (delta: any) => void; onEditorChange: () => void; onDocumentClick: (e) => void; }; - currentText = ''; + currentText = '\n'; quillModules: QuillModules = { toolbar: { container: participantToolbar, @@ -125,6 +126,21 @@ export class ViewCommentDataComponent implements OnInit, AfterViewInit { this.markEvents.onEditorChange(); } this.syncErrorLayer(); + const elem: HTMLDivElement = document.querySelector('div.ql-tooltip'); + if (elem) { + setTimeout(() => { + let left = parseFloat(elem.style.left); + const containerWidth = this.editor.editorElem.getBoundingClientRect().width; + if (left < 0) { + elem.style.left = '0'; + left = 0; + } + const right = left + elem.getBoundingClientRect().width; + if (right > containerWidth) { + elem.style.left = (containerWidth - right + left) + 'px'; + } + }); + } }); } else { this.quillView.onEditorCreated.subscribe(_ => { diff --git a/src/app/components/shared/write-comment/write-comment.component.html b/src/app/components/shared/write-comment/write-comment.component.html index e5c52468f01dedbbf4b083e84ffca93718de6fc3..5a2f19a711057f5dcce84df71d9a45443943806f 100644 --- a/src/app/components/shared/write-comment/write-comment.component.html +++ b/src/app/components/shared/write-comment/write-comment.component.html @@ -48,6 +48,7 @@ <app-view-comment-data *ngIf="enabled" [user]="user" [isEditor]="true" + [maxTextCharacters]="maxTextCharacters" [markEvents]="getMarkEvents()"></app-view-comment-data> <ars-row ars-flex-box *ngIf="enabled" class="spellcheck"> <ars-col> diff --git a/src/app/components/shared/write-comment/write-comment.component.ts b/src/app/components/shared/write-comment/write-comment.component.ts index 10352624d695b58fa7762d5961ca21fb2e9fbc10..417ff00ac8ab2710244e24a0853a3ed588cc79b1 100644 --- a/src/app/components/shared/write-comment/write-comment.component.ts +++ b/src/app/components/shared/write-comment/write-comment.component.ts @@ -1,11 +1,10 @@ -import { AfterViewInit, Component, ElementRef, Input, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { Component, ElementRef, Input, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { Language, LanguagetoolService } from '../../../services/http/languagetool.service'; import { Comment } from '../../../models/comment'; import { User } from '../../../models/user'; import { NotificationService } from '../../../services/util/notification.service'; import { EventService } from '../../../services/util/event.service'; -import { CreateCommentKeywords } from '../../../utils/create-comment-keywords'; import { Marks } from './write-comment.marks'; import { LanguageService } from '../../../services/util/language.service'; import { QuillEditorComponent } from 'ngx-quill'; @@ -24,7 +23,7 @@ export class WriteCommentComponent implements OnInit { @Input() user: User; @Input() tags: string[]; @Input() onClose: () => any; - @Input() onSubmit: (commentText: string, selectedTag: string) => any; + @Input() onSubmit: (commentData: string, commentText: string, selectedTag: string) => any; @Input() isSpinning = false; @Input() disableCancelButton = false; @Input() confirmLabel = 'save'; @@ -33,6 +32,8 @@ export class WriteCommentComponent implements OnInit { @Input() enabled = true; comment: Comment; selectedTag: string; + maxTextCharacters = 500; + maxDataCharacters = 2500; // Grammarheck languages: Language[] = ['de-DE', 'en-US', 'fr', 'auto']; selectedLang: Language = 'auto'; @@ -54,6 +55,8 @@ export class WriteCommentComponent implements OnInit { ngOnInit(): void { this.translateService.use(localStorage.getItem('currentLang')); + this.maxTextCharacters = this.user.role > 0 ? 1000 : 500; + this.maxDataCharacters = this.maxTextCharacters * 5; } buildCloseDialogActionCallback(): () => void { @@ -68,8 +71,8 @@ export class WriteCommentComponent implements OnInit { return undefined; } return () => { - if (this.checkInputData(this.commentData.currentData)) { - this.onSubmit(this.commentData.currentData, this.selectedTag); + if (this.checkInputData(this.commentData.currentData, this.commentData.currentText)) { + this.onSubmit(this.commentData.currentData, this.commentData.currentText, this.selectedTag); } }; } @@ -92,8 +95,7 @@ export class WriteCommentComponent implements OnInit { }); this.isSpellchecking = true; this.hasSpellcheckConfidence = true; - const text = CreateCommentKeywords.cleaningFunction(rawText, true); - this.checkSpellings(text).subscribe((wordsCheck) => { + this.checkSpellings(rawText).subscribe((wordsCheck) => { if (!this.checkLanguageConfidence(wordsCheck)) { this.hasSpellcheckConfidence = false; this.isSpellchecking = false; @@ -113,11 +115,7 @@ export class WriteCommentComponent implements OnInit { langSelect.innerHTML = this.newLang; } this.marks.clear(); - const wrongWords = wordsCheck.matches.map(err => text.slice(err.offset, err.offset + err.length)); - if (!wrongWords.length) { - return; - } - this.checkSpellings(rawText).subscribe((res) => this.marks.buildErrors(rawText, wrongWords, res)); + this.marks.buildErrors(rawText, wordsCheck); }, () => { this.isSpellchecking = false; }, () => { @@ -142,32 +140,29 @@ export class WriteCommentComponent implements OnInit { this.marks.onDataChange(delta); }, onEditorChange: () => { - const elem: HTMLDivElement = document.querySelector('div.ql-tooltip'); - if (elem) { // fix tooltip - setTimeout(() => { - const left = parseFloat(elem.style.left); - const right = left + elem.getBoundingClientRect().width; - const containerWidth = this.commentData.editor.editorElem.getBoundingClientRect().width; - if (left < 0) { - elem.style.left = '0'; - } else if (right > containerWidth) { - elem.style.left = (containerWidth - right + left) + 'px'; - } - }); - } this.marks.sync(); }, onDocumentClick: (e) => this.onDocumentClick(e) }; } - private checkInputData(body: string): boolean { - body = body.trim(); - if (!body) { + private checkInputData(data: string, text: string): boolean { + text = text.trim(); + if (!text.length) { this.translateService.get('comment-page.error-comment').subscribe(message => { this.notification.show(message); }); return false; + } else if (text.length > this.maxTextCharacters) { + this.translateService.get('comment-page.error-comment-text').subscribe(message => { + this.notification.show(message); + }); + return false; + } else if (data.length > this.maxDataCharacters) { + this.translateService.get('comment-page.error-comment-data').subscribe(message => { + this.notification.show(message); + }); + return false; } return true; } diff --git a/src/app/components/shared/write-comment/write-comment.marks.ts b/src/app/components/shared/write-comment/write-comment.marks.ts index 58780e812b2a9d728bfcc4696e88482b7b8702d6..d9cef879a1a96ff689181aa49e5eecd11a8f1183 100644 --- a/src/app/components/shared/write-comment/write-comment.marks.ts +++ b/src/app/components/shared/write-comment/write-comment.marks.ts @@ -114,14 +114,10 @@ export class Marks { this.sync(); } - buildErrors(initialText: string, wrongWords: string[], res: LanguagetoolResult): void { + buildErrors(initialText: string, res: LanguagetoolResult): void { const indexFinder = new ContentIndexFinder(this.editor.quillEditor.getContents().ops); for (let i = 0; i < res.matches.length; i++) { const match = res.matches[i]; - const foundWord = initialText.slice(match.offset, match.offset + match.length); - if (!wrongWords.includes(foundWord)) { - continue; - } const [start, len] = indexFinder.adjustTextIndexes(match.offset, match.length); const mark = new Mark(start, len, this.markContainer, this.tooltipContainer, this.editor.quillEditor); mark.setSuggestions(res, i, () => { diff --git a/src/app/utils/create-comment-keywords.ts b/src/app/utils/create-comment-keywords.ts index ab65318b45f072f678cf7b0f8394a19ec9649ded..075431ae214115db830381a8888f030b426fae09 100644 --- a/src/app/utils/create-comment-keywords.ts +++ b/src/app/utils/create-comment-keywords.ts @@ -9,7 +9,6 @@ export class CreateCommentKeywords { } static isSpellingAcceptable(languagetoolService: LanguagetoolService, text: string, language: Language = 'auto') { - text = this.cleaningFunction(text); return languagetoolService.checkSpellings(text, language).pipe( map(result => { const wordCount = text.trim().split(' ').length; @@ -23,19 +22,4 @@ export class CreateCommentKeywords { }) ); } - - static cleaningFunction(text: string, removeAsciiNamedEmojis = false): string { - // eslint-disable-next-line max-len - const regexEmoji = new RegExp('\uD918\uDD28|\ufe0f|\u200D|\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]', 'g'); - const regexKatex = new RegExp('\\$[^$\\n ]+\\$|\\$\\$[^$\\n ]+\\$\\$', 'g'); - const regexMarkdown = new RegExp('(?:__|[*#])|\\[(.+?)]\\((.+?)\\)', 'g'); - const regexBlank = new RegExp('[\\s]{2,}', 'gu'); - const regexAsciiNamedEmojis = new RegExp(':([a-z0-9_]+):', 'g'); - text = text.replace(regexKatex, ''); - text = text.replace(regexEmoji, ''); - text = text.replace(regexMarkdown, ''); - text = text.replace(regexAsciiNamedEmojis, removeAsciiNamedEmojis ? '' : '$1'); - text = text.replace(regexBlank, ' '); - return text; - } } diff --git a/src/assets/i18n/creator/de.json b/src/assets/i18n/creator/de.json index 890bef4763f3996aa67aad6fa0c68605b20e4711..159d74af5edc824365a8342a2317bd4600536130 100644 --- a/src/assets/i18n/creator/de.json +++ b/src/assets/i18n/creator/de.json @@ -141,6 +141,8 @@ "enter-title": "Titel", "error-both-fields": "Bitte fülle alle Felder aus.", "error-comment": "Bitte gib eine Frage ein.", + "error-comment-text": "Dein Text ist zu lang. Bitte kürze ihn.", + "error-comment-data": "Zu viele Formatierungen oder verknüpfte Elemente. Bitte entferne einige.", "error-title": "Bitte gib einen Titel ein.", "exit-description": "Präsentation verlassen", "export": "Exportieren", diff --git a/src/assets/i18n/creator/en.json b/src/assets/i18n/creator/en.json index 61b73d6e0d958d1cf41ce5ec8a39e9bb50692942..c95c108328d843d5243baee9594ca39615ffe50f 100644 --- a/src/assets/i18n/creator/en.json +++ b/src/assets/i18n/creator/en.json @@ -142,6 +142,8 @@ "enter-title": "Title", "error-both-fields": "Please fill in all fields.", "error-comment": "Please ask a question.", + "error-comment-text": "Your text is too long. Please shorten it.", + "error-comment-data": "Too much formatting or linked elements. Please remove some.", "error-title": "Please enter a title.", "exit-description": "Exit Presentation Mode", "export": "Export", diff --git a/src/assets/i18n/participant/de.json b/src/assets/i18n/participant/de.json index c13de69075d2406d24007573ca0ee653fb022be5..4215ee795ff63a06396dd04467d63c74f420b6f9 100644 --- a/src/assets/i18n/participant/de.json +++ b/src/assets/i18n/participant/de.json @@ -128,6 +128,8 @@ "enter-title": "Titel", "error-both-fields": "Bitte fülle alle Felder aus.", "error-comment": "Bitte gib deine Frage ein.", + "error-comment-text": "Dein Text ist zu lang. Bitte kürze ihn.", + "error-comment-data": "Zu viele Formatierungen oder verknüpfte Elemente. Bitte entferne einige.", "error-title": "Bitte gib einen Titel ein.", "has-answer": "Die Frage wurde kommentiert. Klick hier, um den Kommentar zu lesen.", "exit-description": "Präsentationsmodus verlassen", diff --git a/src/assets/i18n/participant/en.json b/src/assets/i18n/participant/en.json index 7a1eb25618b9e59fdd256e5203733652c97ac5b3..9a14a1a67caea608da0a53d310ff5c81c3e55b12 100644 --- a/src/assets/i18n/participant/en.json +++ b/src/assets/i18n/participant/en.json @@ -137,6 +137,8 @@ "enter-title": "Title", "error-both-fields": "Please fill in all fields.", "error-comment": "Please enter a question.", + "error-comment-text": "Your text is too long. Please shorten it.", + "error-comment-data": "Too much formatting or linked elements. Please remove some.", "error-title": "Please enter a title.", "exit-description": "Exit Presentation Mode", "has-answer": "The question was answered. Click for full view.",