From 9d8af1f6da79604f23bfc7e16f493f44638cec0e Mon Sep 17 00:00:00 2001 From: Lukas Phillip Haase <lukas.haase@mni.thm.de> Date: Fri, 18 Oct 2019 15:17:53 +0200 Subject: [PATCH] Resolve "Scrolling-to-top FAB missing on moderation board" --- src/app/app.component.scss | 2 +- .../moderator-comment-list.component.html | 2 +- .../moderator-comment-list.component.scss | 13 +- .../moderator-comment-list.component.ts | 93 +++++++- .../moderator-comment-list.component.ts.orig | 200 ++++++++++++++++++ .../comment-list/comment-list.component.html | 2 +- .../comment-list/comment-list.component.ts | 5 +- src/styles.scss | 8 +- 8 files changed, 300 insertions(+), 25 deletions(-) create mode 100644 src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.ts.orig diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 0825e8bbc..6dd0d9b86 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -56,7 +56,7 @@ main { top:15px; z-index:2; display:none; - box-shadow:0px 2px 4px rgba(0,0,0,0.5); + box-shadow:0px 2px 2px rgba(0,0,0,0.4); transition:all 0.2s ease-in-out; } diff --git a/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.html b/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.html index f9f0a7365..abb4ad252 100644 --- a/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.html +++ b/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.html @@ -58,7 +58,7 @@ </div> -<button mat-icon-button class="scrollTop" [ngClass]="{'visible': scrollExtended}" (click)="scrollToTop()" tabIndex="-1"> +<button mat-icon-button class="scrollTop" [ngClass]="{'visible': isScrollButtonVisible()}" (click)="AppComponent.scrollTop()" tabIndex="-1"> <mat-icon>arrow_upward</mat-icon> </button> diff --git a/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.scss b/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.scss index a418df968..fcf910f16 100644 --- a/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.scss +++ b/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.scss @@ -116,16 +116,15 @@ h3 { .scrollTop { position: fixed; - bottom: 3%; - left: -40px; + left: 25px; + bottom: 65px; + transform: scale(0); z-index: 1; background-color: var(--primary); - color: white; - transition: 0.5s; + color: var(--on-primary); + transition: 0.1s; } .visible { - left: 5%; - transition: 0.5s; - background-color: var(--primary); + transform: scale(1); } diff --git a/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.ts b/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.ts index f5f2e0811..308e9c787 100644 --- a/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.ts +++ b/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.ts @@ -11,8 +11,11 @@ import { Vote } from '../../../models/vote'; import { UserRole } from '../../../models/user-roles.enum'; import { Room } from '../../../models/room'; import { RoomService } from '../../../services/http/room.service'; +import { VoteService } from '../../../services/http/vote.service'; +import { CorrectWrong } from '../../../models/correct-wrong.enum'; import { EventService } from '../../../services/util/event.service'; import { Router } from '@angular/router'; +import { AppComponent } from '../../../app.component'; @Component({ selector: 'app-moderator-comment-list', @@ -23,6 +26,7 @@ export class ModeratorCommentListComponent implements OnInit { @ViewChild('searchBox') searchField: ElementRef; @Input() user: User; @Input() roomId: string; + AppComponent = AppComponent; comments: Comment[] = []; room: Room; hideCommentsList = false; @@ -34,7 +38,13 @@ export class ModeratorCommentListComponent implements OnInit { votedesc = 'votedesc'; time = 'time'; currentSort: string; + read = 'read'; + unread = 'unread'; + favorite = 'favorite'; + correct = 'correct'; + wrong = 'wrong'; ack = 'ack'; + currentFilter = ''; commentVoteMap = new Map<string, Vote>(); scroll = false; scrollExtended = false; @@ -57,6 +67,7 @@ export class ModeratorCommentListComponent implements OnInit { ngOnInit() { this.roomId = localStorage.getItem(`roomId`); + const userId = this.user.id; this.userRole = this.user.role; this.roomService.getRoom(this.roomId).subscribe(room => this.room = room); this.hideCommentsList = false; @@ -86,8 +97,8 @@ export class ModeratorCommentListComponent implements OnInit { this.scrollExtended = currentScroll >= 300; } - scrollToTop(): void { - document.documentElement.scrollTo({ top: 0, behavior: 'smooth' }); + isScrollButtonVisible(): boolean { + return !AppComponent.isScrolledTop() && this.comments.length > 5; } searchComments(): void { @@ -105,6 +116,20 @@ export class ModeratorCommentListComponent implements OnInit { this.searchField.nativeElement.focus(); } + getComments(): void { + this.isLoading = false; + let commentThreshold = -10; + if (this.room && this.room.extensions && this.room.extensions['comments']) { + commentThreshold = this.room.extensions['comments'].commentThreshold; + if (this.hideCommentsList) { + this.filteredComments = this.filteredComments.filter(x => x.score >= commentThreshold); + } else { + this.comments = this.comments.filter(x => x.score >= commentThreshold); + } + } + this.sortComments(this.currentSort); + } + getVote(comment: Comment): Vote { if (this.userRole === 0) { return this.commentVoteMap.get(comment.id); @@ -127,6 +152,28 @@ export class ModeratorCommentListComponent implements OnInit { return el.id !== payload.id; }); } + switch (key) { + case this.read: + this.comments[i].read = <boolean>value; + break; + case this.correct: + this.comments[i].correct = <CorrectWrong>value; + break; + case this.favorite: + this.comments[i].favorite = <boolean>value; + break; + case 'score': + this.comments[i].score = <number>value; + break; + case this.ack: + // tslint:disable-next-line:no-shadowed-variable + const isNowAck = <boolean>value; + if (isNowAck) { + this.comments = this.comments.filter(function (el) { + return el.id !== payload.id; + }); + } + } } } } @@ -141,6 +188,7 @@ export class ModeratorCommentListComponent implements OnInit { break; } + this.filterComments(this.currentFilter); this.sortComments(this.currentSort); this.searchComments(); } @@ -148,18 +196,45 @@ export class ModeratorCommentListComponent implements OnInit { parseIncomingModeratorMessage(message: Message) { const msg = JSON.parse(message.body); const payload = msg.payload; - if (msg.type === 'CommentCreated') { - const c = new Comment(); - c.roomId = this.roomId; - c.body = payload.body; - c.id = payload.id; - c.timestamp = payload.timestamp; - this.comments = this.comments.concat(c); + switch (msg.type) { + case 'CommentCreated': + const c = new Comment(); + c.roomId = this.roomId; + c.body = payload.body; + c.id = payload.id; + c.timestamp = payload.timestamp; + this.comments = this.comments.concat(c); + break; } + console.log(msg); + this.filterComments(this.currentFilter); this.sortComments(this.currentSort); this.searchComments(); } + filterComments(type: string): void { + this.currentFilter = type; + if (type === '') { + this.filteredComments = this.comments; + return; + } + this.filteredComments = this.comments.filter(c => { + switch (type) { + case this.correct: + return c.correct === CorrectWrong.CORRECT ? 1 : 0; + case this.wrong: + return c.correct === CorrectWrong.WRONG ? 1 : 0; + case this.favorite: + return c.favorite; + case this.read: + return c.read; + case this.unread: + return !c.read; + } + }); + this.sortComments(this.currentSort); + } + sort(array: any[], type: string): void { array.sort((a, b) => { if (type === this.voteasc) { diff --git a/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.ts.orig b/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.ts.orig new file mode 100644 index 000000000..608a95ef8 --- /dev/null +++ b/src/app/components/moderator/moderator-comment-list/moderator-comment-list.component.ts.orig @@ -0,0 +1,200 @@ +import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; +import { Comment } from '../../../models/comment'; +import { CommentService } from '../../../services/http/comment.service'; +import { TranslateService } from '@ngx-translate/core'; +import { LanguageService } from '../../../services/util/language.service'; +import { Message } from '@stomp/stompjs'; +import { MatDialog } from '@angular/material'; +import { WsCommentServiceService } from '../../../services/websockets/ws-comment-service.service'; +import { User } from '../../../models/user'; +import { Vote } from '../../../models/vote'; +import { UserRole } from '../../../models/user-roles.enum'; +import { Room } from '../../../models/room'; +import { RoomService } from '../../../services/http/room.service'; +import { EventService } from '../../../services/util/event.service'; +<<<<<<< HEAD +import { Router } from '@angular/router'; +======= +import { AppComponent } from '../../../app.component'; +>>>>>>> 231fd12c... Scroll-To-Top Button for Moderator-Comment-List, Fix for Firefox Body-Scroll-Bug + +@Component({ + selector: 'app-moderator-comment-list', + templateUrl: './moderator-comment-list.component.html', + styleUrls: ['./moderator-comment-list.component.scss'] +}) +export class ModeratorCommentListComponent implements OnInit { + @ViewChild('searchBox') searchField: ElementRef; + @Input() user: User; + @Input() roomId: string; + AppComponent = AppComponent; + comments: Comment[] = []; + room: Room; + hideCommentsList = false; + filteredComments: Comment[]; + userRole: UserRole; + deviceType: string; + isLoading = true; + voteasc = 'voteasc'; + votedesc = 'votedesc'; + time = 'time'; + currentSort: string; + ack = 'ack'; + commentVoteMap = new Map<string, Vote>(); + scroll = false; + scrollExtended = false; + searchInput = ''; + search = false; + searchPlaceholder = ''; + + constructor( + private commentService: CommentService, + private translateService: TranslateService, + public dialog: MatDialog, + protected langService: LanguageService, + private wsCommentService: WsCommentServiceService, + protected roomService: RoomService, + public eventService: EventService, + private router: Router + ) { + langService.langEmitter.subscribe(lang => translateService.use(lang)); + } + + ngOnInit() { + this.roomId = localStorage.getItem(`roomId`); + this.userRole = this.user.role; + this.roomService.getRoom(this.roomId).subscribe(room => this.room = room); + this.hideCommentsList = false; + this.wsCommentService.getModeratorCommentStream(this.roomId).subscribe((message: Message) => { + this.parseIncomingModeratorMessage(message); + }); + this.wsCommentService.getCommentStream(this.roomId).subscribe((message: Message) => { + this.parseIncomingMessage(message); + }); + this.translateService.use(localStorage.getItem('currentLang')); + this.deviceType = localStorage.getItem('deviceType'); + this.currentSort = this.votedesc; + this.commentService.getRejectedComments(this.roomId) + .subscribe(comments => { + this.comments = comments; + this.isLoading = false; + this.sortComments(this.currentSort); + }); + this.translateService.get('comment-list.search').subscribe(msg => { + this.searchPlaceholder = msg; + }); + } + + checkScroll(): void { + const currentScroll = document.documentElement.scrollTop; + this.scroll = currentScroll >= 65; + this.scrollExtended = currentScroll >= 300; + } + + isScrollButtonVisible(): boolean { + return !AppComponent.isScrolledTop() && this.comments.length > 5; + } + + searchComments(): void { + if (this.searchInput && this.searchInput.length > 2) { + this.hideCommentsList = true; + this.filteredComments = this.comments.filter(c => c.body.toLowerCase().includes(this.searchInput.toLowerCase())); + } + } + + activateSearch() { + this.translateService.get('comment-list.search').subscribe(msg => { + this.searchPlaceholder = msg; + }); + this.search = true; + this.searchField.nativeElement.focus(); + } + + getVote(comment: Comment): Vote { + if (this.userRole === 0) { + return this.commentVoteMap.get(comment.id); + } + } + + parseIncomingMessage(message: Message) { + const msg = JSON.parse(message.body); + const payload = msg.payload; + switch (msg.type) { + case 'CommentPatched': + // ToDo: Use a map for comments w/ key = commentId + for (let i = 0; i < this.comments.length; i++) { + if (payload.id === this.comments[i].id) { + for (const [key, value] of Object.entries(payload.changes)) { + if (key === this.ack) { + const isNowAck = <boolean>value; + if (isNowAck) { + this.comments = this.comments.filter(function (el) { + return el.id !== payload.id; + }); + } + } + } + } + } + break; + case 'CommentDeleted': + for (let i = 0; i < this.comments.length; i++) { + this.comments = this.comments.filter(function (el) { + return el.id !== payload.id; + }); + } + break; + } + + this.sortComments(this.currentSort); + this.searchComments(); + } + + parseIncomingModeratorMessage(message: Message) { + const msg = JSON.parse(message.body); + const payload = msg.payload; + if (msg.type === 'CommentCreated') { + const c = new Comment(); + c.roomId = this.roomId; + c.body = payload.body; + c.id = payload.id; + c.timestamp = payload.timestamp; + this.comments = this.comments.concat(c); + } + this.sortComments(this.currentSort); + this.searchComments(); + } + + sort(array: any[], type: string): void { + array.sort((a, b) => { + if (type === this.voteasc) { + return (a.score > b.score) ? 1 : (b.score > a.score) ? -1 : 0; + } else if (type === this.votedesc) { + return (b.score > a.score) ? 1 : (a.score > b.score) ? -1 : 0; + } + const dateA = new Date(a.timestamp), dateB = new Date(b.timestamp); + if (type === this.time) { + return (+dateB > +dateA) ? 1 : (+dateA > +dateB) ? -1 : 0; + } + }); + } + + sortComments(type: string): void { + if (this.hideCommentsList === true) { + this.sort(this.filteredComments, type); + } else { + this.sort(this.comments, type); + } + this.currentSort = type; + } + + switchToCommentList(): void { + let role; + if (this.userRole === UserRole.CREATOR.valueOf()) { + role = 'creator'; + } else if (this.userRole === UserRole.EXECUTIVE_MODERATOR) { + role = 'moderator'; + } + this.router.navigate([`/${role}/room/${this.room.shortId}/comments`]); + } +} 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 0f8cd978e..d19ba7331 100644 --- a/src/app/components/shared/comment-list/comment-list.component.html +++ b/src/app/components/shared/comment-list/comment-list.component.html @@ -119,7 +119,7 @@ </mat-menu> </div> -<button mat-icon-button class="scrollTop" [ngClass]="{'visible': isScrollButtonVisible()}" (click)="scrollToTop()"> +<button mat-icon-button class="scrollTop" [ngClass]="{'visible': isScrollButtonVisible()}" (click)="AppComponent.scrollTop()"> <mat-icon>arrow_upward</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 f84010cc6..04399c86b 100644 --- a/src/app/components/shared/comment-list/comment-list.component.ts +++ b/src/app/components/shared/comment-list/comment-list.component.ts @@ -30,6 +30,7 @@ export class CommentListComponent implements OnInit { @ViewChild('searchBox') searchField: ElementRef; @Input() user: User; @Input() roomId: string; + AppComponent = AppComponent; comments: Comment[] = []; room: Room; hideCommentsList = false; @@ -118,10 +119,6 @@ export class CommentListComponent implements OnInit { this.scrollExtended = currentScroll >= 300; } - scrollToTop(): void { - AppComponent.scrollTop(); - } - isScrollButtonVisible(): boolean { return !AppComponent.isScrolledTop() && this.comments.length > 5; } diff --git a/src/styles.scss b/src/styles.scss index 350780ad9..9680a8981 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -14,6 +14,12 @@ // that you are using. @include angular-material-theme($arsnova-theme); +body{ + width:100%; + height:100%; + overflow:hidden; +} + ::-webkit-scrollbar{ width:2px; background-color:var(--on-secondary); @@ -60,5 +66,3 @@ } - - -- GitLab