improvements + bookmarks

This commit is contained in:
_Bastler 2021-10-04 13:02:30 +02:00
parent a69a85aeb0
commit 0cabe9b0a5
12 changed files with 169 additions and 15 deletions

View File

@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; import { Routes, RouterModule } from '@angular/router';
import { AuthGuard, AuthUpdateGuard, AuthenticatedGuard, AnonymousGuard } from './auth/auth.guard'; import { AuthGuard, AuthUpdateGuard, AuthenticatedGuard, AnonymousGuard } from './auth/auth.guard';
import { PageBookmarks } from './pages/bookmarks/bookmarks.page';
import { PageEntry } from './pages/entry/entry.page'; import { PageEntry } from './pages/entry/entry.page';
import { PageLogin } from './pages/login/login.page'; import { PageLogin } from './pages/login/login.page';
import { PageNew } from './pages/new/new.page'; import { PageNew } from './pages/new/new.page';
@ -18,6 +19,7 @@ const routes: Routes = [
{ path: '', component: PageTop, canActivate: [ AuthenticatedGuard ] }, { path: '', component: PageTop, canActivate: [ AuthenticatedGuard ] },
{ path: 'e/:id', component: PageEntry, canActivate: [ AuthenticatedGuard ] }, { path: 'e/:id', component: PageEntry, canActivate: [ AuthenticatedGuard ] },
{ path: 'new', component: PageNew, canActivate: [ AuthenticatedGuard ] }, { path: 'new', component: PageNew, canActivate: [ AuthenticatedGuard ] },
{ path: 'bookmarks', component: PageBookmarks, canActivate: [ AuthenticatedGuard ] },
{ path: 'submit', component: PageSubmission, canActivate: [ AuthenticatedGuard ] }, { path: 'submit', component: PageSubmission, canActivate: [ AuthenticatedGuard ] },
{ path: 'login', component: PageLogin, canActivate: [ AnonymousGuard ] }, { path: 'login', component: PageLogin, canActivate: [ AnonymousGuard ] },
{ path: 'settings', component: PageSettings, canActivate: [ AuthenticatedGuard ] }, { path: 'settings', component: PageSettings, canActivate: [ AuthenticatedGuard ] },

View File

@ -17,6 +17,7 @@ import { AutofocusDirective } from './material/autofocus';
import { I18nPipe } from './utils/i18n.pipe'; import { I18nPipe } from './utils/i18n.pipe';
import { MomentPipe } from './utils/moment.pipe'; import { MomentPipe } from './utils/moment.pipe';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { PageBookmarks } from './pages/bookmarks/bookmarks.page';
import { PageEntry } from './pages/entry/entry.page'; import { PageEntry } from './pages/entry/entry.page';
import { PageLogin } from './pages/login/login.page'; import { PageLogin } from './pages/login/login.page';
import { PageNew } from './pages/new/new.page'; import { PageNew } from './pages/new/new.page';
@ -71,6 +72,7 @@ export class XhrInterceptor implements HttpInterceptor {
I18nPipe, I18nPipe,
MomentPipe, MomentPipe,
AppComponent, AppComponent,
PageBookmarks,
PageEntry, PageEntry,
PageLogin, PageLogin,
PageNew, PageNew,

View File

@ -0,0 +1 @@
<ui-entries [entries]="entries" [refresh]="boundRefresh" [update]="boundUpdate"></ui-entries>

View File

@ -0,0 +1,81 @@
import { Component, OnInit, Input } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { PageEvent } from '@angular/material/paginator';
import { BookmarksService } from '../../services/bookmarks.service';
@Component({
selector: 'page-bookmarks',
templateUrl: './bookmarks.page.html'
})
export class PageBookmarks implements OnInit {
@Input() entries: any;
boundRefresh: Function;
boundUpdate: Function;
init: boolean = true;
constructor(private bookmarksService: BookmarksService, private router: Router, private route: ActivatedRoute) { }
ngOnInit(): void {
this.boundRefresh = this.refresh.bind(this);
this.boundUpdate = this.update.bind(this);
this.route.queryParams.subscribe(params => {
if (this.init) {
this.entries = {};
if (params[ 'p' ]) {
this.entries.number = +params[ 'p' ] - 1;
if (this.entries.number < 0) {
this.entries.number = 0;
}
}
if (params[ 's' ]) {
this.entries.size = +params[ 's' ];
}
this.refresh();
this.init = false;
}
});
}
refresh(): void {
if (!this.entries) {
this.entries = {};
}
this.entries.content = null;
this.bookmarksService.getEntriesPages(this.entries.number || 0, this.entries.size || 30).subscribe((data: any) => {
this.entries = data;
this.entries.bookmarks = true;
}, (error) => { })
}
update(event: PageEvent) {
this.entries.content = null;
const params: any = { p: null, s: null };
if (event.pageIndex != 0) {
params.p = event.pageIndex + 1;
}
if (event.pageSize != 30) {
params.s = event.pageSize;
}
this.router.navigate(
[],
{
relativeTo: this.route,
queryParams: params,
queryParamsHandling: 'merge'
});
this.bookmarksService.getEntriesPages(event.pageIndex, event.pageSize).subscribe((data: any) => {
this.entries = data;
}, (error) => { })
}
}

View File

@ -0,0 +1,29 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment';
@Injectable({
providedIn: 'root',
})
export class BookmarksService {
constructor(private http: HttpClient) {
}
getEntries() {
return this.http.get(environment.apiUrl + "/b");
}
getEntriesPages(page: number, size: number) {
return this.http.get(environment.apiUrl + "/b" + "?page=" + page + "&size=" + size);
}
addEntry(id: number) {
return this.http.put(environment.apiUrl + "/b/" + id, {});
}
removeEntry(id: number) {
return this.http.delete(environment.apiUrl + "/b/" + id, {});
}
}

View File

@ -43,19 +43,25 @@ export class UiComment implements OnInit {
voteUp() { voteUp() {
this.voteService.voteCommentUp(this.comment.id).subscribe((result) => { this.voteService.voteCommentUp(this.comment.id).subscribe((result) => {
this.change && this.change() this.commentService.getComment(this.comment.id).subscribe((data) => {
this.comment = data;
})
}); });
} }
voteDown() { voteDown() {
this.voteService.voteCommentDown(this.comment.id).subscribe((result) => { this.voteService.voteCommentDown(this.comment.id).subscribe((result) => {
this.change && this.change() this.commentService.getComment(this.comment.id).subscribe((data) => {
this.comment = data;
})
}); });
} }
unvote() { unvote() {
this.voteService.unvoteComment(this.comment.id).subscribe((result) => { this.voteService.unvoteComment(this.comment.id).subscribe((result) => {
this.change && this.change() this.commentService.getComment(this.comment.id).subscribe((data) => {
this.comment = data;
})
}); });
} }

View File

@ -1,6 +1,6 @@
<div *ngIf="comments" fxLayout="column" fxFlexFill class="comments"> <div *ngIf="comments" fxLayout="column" fxFlexFill class="comments">
<ng-container *ngFor="let comment of comments.content; let i = index"> <ng-container *ngFor="let comment of comments.content; let i = index">
<mat-divider *ngIf="i > 0"></mat-divider> <mat-divider class="divider" *ngIf="i > 0"></mat-divider>
<ui-comment [comment]="comment" [change]="boundRefresh"></ui-comment> <ui-comment [comment]="comment" [change]="boundRefresh"></ui-comment>
</ng-container> </ng-container>
</div> </div>

View File

@ -1,3 +1,7 @@
.comments { .comments {
padding-left: 15px; padding-left: 15px;
} }
.divider {
margin: 10px 0px;
}

View File

@ -11,7 +11,11 @@
</ng-container> </ng-container>
</mat-list> </mat-list>
<p *ngIf="entries.totalElements == 0">{{'entries.nothing' | i18n}}</p> <mat-list *ngIf="entries.totalElements == 0">
<mat-list-item>
<p>{{'entries.nothing' | i18n}}</p>
</mat-list-item>
</mat-list>
<span fxFlexOffset="auto"></span> <span fxFlexOffset="auto"></span>

View File

@ -27,10 +27,20 @@
<a routerLink="/e/{{entry.id}}" matTooltip="{{entry.created | datef:'LLLL'}}">{{entry.created <a routerLink="/e/{{entry.id}}" matTooltip="{{entry.created | datef:'LLLL'}}">{{entry.created
| datef}}</a> | datef}}</a>
{{'entry.author' | i18n}}<a routerLink="/u/{{entry.author}}">{{entry.author}}</a> {{'entry.author' | i18n}}<a routerLink="/u/{{entry.author}}">{{entry.author}}</a>
| <span> | </span>
<a routerLink="/e/{{entry.id}}">{{'entry.comments' | i18n:(entry.metadata && entry.metadata.comments)}}</a> <a routerLink="/e/{{entry.id}}">{{'entry.comments' | i18n:(entry.metadata && entry.metadata.comments)}}</a>
<span> | </span>
<a *ngIf="entry.metadata && !entry.metadata.bookmarked" href="javascript:" (click)="addBookmark()"
matTooltip="{{'bookmarks.add' | i18n}}">
<mat-icon inline="true">bookmark_border</mat-icon>
</a>
<a *ngIf="entry.metadata && entry.metadata.bookmarked" href="javascript:" (click)="removeBookmark()"
matTooltip="{{'bookmarks.remove' | i18n}}">
<mat-icon inline="true">bookmark</mat-icon>
</a>
<span *ngIf="entry.metadata && entry.metadata.unvote"> | </span> <span *ngIf="entry.metadata && entry.metadata.unvote"> | </span>
<a *ngIf="entry.metadata && entry.metadata.unvote" href="javascript:" (click)="unvote(entry.id)">{{'entry.unvote' | i18n}}</a> <a *ngIf="entry.metadata && entry.metadata.unvote" href="javascript:" (click)="unvote(entry.id)">{{'entry.unvote' |
i18n}}</a>
<span *ngIf="moderator"> | </span> <span *ngIf="moderator"> | </span>
<a *ngIf="moderator" href="javascript:" (click)="deleteEntry(entry)">{{'entry.delete' | i18n}}</a> <a *ngIf="moderator" href="javascript:" (click)="deleteEntry(entry)">{{'entry.delete' | i18n}}</a>
</small> </small>

View File

@ -3,7 +3,7 @@ import { MatDialog } from '@angular/material/dialog';
import { AuthService } from '../../services/auth.service'; import { AuthService } from '../../services/auth.service';
import { VoteService } from '../../services/vote.service'; import { VoteService } from '../../services/vote.service';
import { CommentService } from '../../services/comment.service'; import { BookmarksService } from '../../services/bookmarks.service';
import { ModerationService } from '../../services/moderarion.service'; import { ModerationService } from '../../services/moderarion.service';
import { ConfirmDialog } from '../../ui/confirm/confirm.component'; import { ConfirmDialog } from '../../ui/confirm/confirm.component';
@ -20,7 +20,7 @@ export class UiEntry implements OnInit {
@Input() change: Function; @Input() change: Function;
constructor(private authService: AuthService, private voteService: VoteService, constructor(private authService: AuthService, private voteService: VoteService,
private moderationService: ModerationService, public dialog: MatDialog) { } private moderationService: ModerationService, private bookmarksService: BookmarksService, public dialog: MatDialog) { }
ngOnInit(): void { ngOnInit(): void {
this.authService.auth.subscribe((auth: any) => { this.authService.auth.subscribe((auth: any) => {
@ -36,26 +36,38 @@ export class UiEntry implements OnInit {
voteUp() { voteUp() {
this.voteService.voteEntryUp(this.entry.id).subscribe((result) => { this.voteService.voteEntryUp(this.entry.id).subscribe((result) => {
this.change && this.change() this.change && this.change();
}); });
} }
voteDown() { voteDown() {
this.voteService.voteEntryDown(this.entry.id).subscribe((result) => { this.voteService.voteEntryDown(this.entry.id).subscribe((result) => {
this.change && this.change() this.change && this.change();
});
}
addBookmark() {
this.bookmarksService.addEntry(this.entry.id).subscribe((result) => {
this.entry.metadata.bookmarked = true;
});
}
removeBookmark() {
this.bookmarksService.removeEntry(this.entry.id).subscribe((result) => {
this.entry.metadata.bookmarked = false;
}); });
} }
unvote() { unvote() {
this.voteService.unvoteEntry(this.entry.id).subscribe((result) => { this.voteService.unvoteEntry(this.entry.id).subscribe((result) => {
this.change && this.change() this.change && this.change();
}); });
} }
deleteEntry(entry: any) { deleteEntry(entry: any) {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'comment.confirmDelete', 'label': 'entry.confirmDelete',
'args': [ entry.title, entry.author ] 'args': [ entry.title, entry.author ]
} }
}) })

View File

@ -28,6 +28,9 @@
<a *ngIf="auth && auth.authenticated" routerLink="/new" routerLinkActive="active" mat-list-item> <a *ngIf="auth && auth.authenticated" routerLink="/new" routerLinkActive="active" mat-list-item>
<mat-icon>history</mat-icon> {{'new' | i18n}} <mat-icon>history</mat-icon> {{'new' | i18n}}
</a> </a>
<a *ngIf="auth && auth.authenticated" routerLink="/bookmarks" routerLinkActive="active" mat-list-item>
<mat-icon>bookmarks</mat-icon> {{'bookmarks' | i18n}}
</a>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<a *ngIf="auth && auth.authenticated" routerLink="/settings" routerLinkActive="active" mat-list-item> <a *ngIf="auth && auth.authenticated" routerLink="/settings" routerLinkActive="active" mat-list-item>
<mat-icon>tune</mat-icon> {{'settings' | i18n}} <mat-icon>tune</mat-icon> {{'settings' | i18n}}