update dependencies, migrate subscribe, add submit type to buttons

This commit is contained in:
_Bastler 2024-02-26 15:11:48 +01:00
parent 43da1441d9
commit 31dc5e5c25
31 changed files with 4388 additions and 5047 deletions

View File

@ -39,7 +39,10 @@
"buildOptimizer": false, "buildOptimizer": false,
"sourceMap": true, "sourceMap": true,
"optimization": false, "optimization": false,
"namedChunks": true "namedChunks": true,
"allowedCommonJsDependencies": [
"moment"
]
}, },
"configurations": { "configurations": {
"production": { "production": {
@ -121,8 +124,9 @@
} }
} }
} }
}}, }
},
"cli": { "cli": {
"analytics": false "analytics": false
} }
} }

8046
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "bstlboard", "name": "bstlboard",
"version": "2.0.1", "version": "2.1.0",
"license": "AGPL3", "license": "AGPL3",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
@ -12,35 +12,35 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^17.0.9", "@angular/animations": "^17.2.2",
"@angular/cdk": "^17.0.5", "@angular/cdk": "^17.2.1",
"@angular/common": "^17.0.9", "@angular/common": "^17.2.2",
"@angular/compiler": "^17.0.9", "@angular/compiler": "^17.2.2",
"@angular/core": "^17.0.9", "@angular/core": "^17.2.2",
"@angular/forms": "^17.0.9", "@angular/forms": "^17.2.2",
"@angular/material": "^17.0.5", "@angular/material": "^17.2.1",
"@angular/material-moment-adapter": "^17.0.5", "@angular/material-moment-adapter": "^17.2.1",
"@angular/platform-browser": "^17.0.9", "@angular/platform-browser": "^17.2.2",
"@angular/platform-browser-dynamic": "^17.0.9", "@angular/platform-browser-dynamic": "^17.2.2",
"@angular/router": "^17.0.9", "@angular/router": "^17.2.2",
"@angular/service-worker": "^17.0.9", "@angular/service-worker": "^17.2.2",
"moment": "^2.30.1", "moment": "^2.30.1",
"rxjs": "~7.8.1", "rxjs": "~7.8.1",
"tslib": "^2.6.2", "tslib": "^2.6.2",
"zone.js": "~0.14.3" "zone.js": "~0.14.4"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^17.0.10", "@angular-devkit/build-angular": "^17.2.1",
"@angular/cli": "^17.0.10", "@angular/cli": "^17.2.1",
"@angular/compiler-cli": "^17.0.9", "@angular/compiler-cli": "^17.2.2",
"@angular/localize": "^17.0.9", "@angular/localize": "^17.2.2",
"@types/jasmine": "^5.1.4", "@types/jasmine": "^5.1.4",
"jasmine-core": "~5.1.1", "jasmine-core": "~5.1.2",
"karma": "^6.4.2", "karma": "^6.4.3",
"karma-chrome-launcher": "~3.2.0", "karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.1", "karma-coverage": "~2.2.1",
"karma-jasmine": "~5.1.0", "karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "^2.1.0", "karma-jasmine-html-reporter": "^2.1.0",
"typescript": "~5.2.2" "typescript": "~5.3.3"
} }
} }

View File

@ -48,28 +48,30 @@ export class AuthenticatedGuard implements CanActivate {
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) { canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const that = this; const that = this;
return this.authService.getAuth().then((data: any) => { return this.authService.getAuth().then((data: any) => {
this.userService.get().subscribe((user: any) => { this.userService.get().subscribe({
let updateLocale = false; next: (user: any) => {
let updateTheme = false; let updateLocale = false;
let darktheme = 'false'; let updateTheme = false;
let darktheme = 'false';
if (user.darkTheme) { if (user.darkTheme) {
darktheme = 'true'; darktheme = 'true';
} }
if (darktheme != localStorage.getItem("bstlboard.darkTheme")) { if (darktheme != localStorage.getItem("bstlboard.darkTheme")) {
localStorage.setItem("bstlboard.darkTheme", darktheme); localStorage.setItem("bstlboard.darkTheme", darktheme);
updateTheme = true; updateTheme = true;
} }
if (this.i18nService.locales.indexOf(user.locale) != -1 && localStorage.getItem("bstlboard.locale") != user.locale) { if (this.i18nService.locales.indexOf(user.locale) != -1 && localStorage.getItem("bstlboard.locale") != user.locale) {
if (this.i18nService.locale != user.locale) { if (this.i18nService.locale != user.locale) {
localStorage.setItem("bstlboard.locale", user.locale); localStorage.setItem("bstlboard.locale", user.locale);
updateLocale = true; updateLocale = true;
}
}
if (updateLocale || updateTheme) {
window.location.reload();
} }
}
if (updateLocale || updateTheme) {
window.location.reload();
} }
}); });

View File

@ -7,14 +7,14 @@ import { CommentService } from '../../services/comment.service';
@Component({ @Component({
selector: 'page-comment', selector: 'page-comment',
templateUrl: './comment.page.html', templateUrl: './comment.page.html',
styleUrls: [ './comment.page.scss' ] styleUrls: ['./comment.page.scss']
}) })
export class PageComment implements OnInit { export class PageComment implements OnInit {
id: number; id: number;
comment: any; comment: any;
notfound: boolean = false; notfound: boolean = false;
ignoreSubcomments: string[] = [ 'entry' ]; ignoreSubcomments: string[] = ['entry'];
constructor(private commentService: CommentService, constructor(private commentService: CommentService,
private route: ActivatedRoute) { } private route: ActivatedRoute) { }
@ -22,11 +22,14 @@ export class PageComment implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.id = +this.route.snapshot.paramMap.get('id'); this.id = +this.route.snapshot.paramMap.get('id');
this.commentService.getComment(this.id).subscribe((data) => { this.commentService.getComment(this.id).subscribe({
this.comment = data; next: (data) => {
}, (error) => { this.comment = data;
if (error.status == 404) { },
this.notfound = true; error: (error) => {
if (error.status == 404) {
this.notfound = true;
}
} }
}) })
} }

View File

@ -31,35 +31,39 @@ export class PageEntries implements OnInit, OnDestroy {
ngOnInit(): void { ngOnInit(): void {
this.boundRefresh = this.refresh.bind(this); this.boundRefresh = this.refresh.bind(this);
this.boundUpdate = this.update.bind(this); this.boundUpdate = this.update.bind(this);
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe({
if (this.init) { next: (params) => {
this.entries = { filter: {} }; if (this.init) {
if (params[ 'p' ]) { this.entries = { filter: {} };
this.entries.number = +params[ 'p' ] - 1; if (params['p']) {
if (this.entries.number < 0) { this.entries.number = +params['p'] - 1;
this.entries.number = 0; if (this.entries.number < 0) {
this.entries.number = 0;
}
} }
}
if (params[ 's' ]) { if (params['s']) {
this.entries.size = +params[ 's' ]; this.entries.size = +params['s'];
}
if (params[ 'asc' ]) {
this.asc = true;
}
for (const param in params) {
if (param != 's' && param != 'p' && param != 'asc') {
this.entries.filter[ param ] = params[ param ];
} }
}
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => { if (params['asc']) {
this.settings = settings; this.asc = true;
this.refresh(); }
this.init = false;
}) for (const param in params) {
if (param != 's' && param != 'p' && param != 'asc') {
this.entries.filter[param] = params[param];
}
}
this.settingsSubscription = this.settingsService.settings.subscribe({
next: (settings) => {
this.settings = settings;
this.refresh();
this.init = false;
}
})
}
} }
}); });
} }
@ -75,11 +79,14 @@ export class PageEntries implements OnInit, OnDestroy {
const filter = JSON.parse(JSON.stringify(this.entries.filter || {})) const filter = JSON.parse(JSON.stringify(this.entries.filter || {}))
this.entries.content = null; this.entries.content = null;
this.fetch(this.entries.number || 0, this.entries.size || this.settings.pageSize, this.asc, this.entries.filter).subscribe((data: any) => { this.fetch(this.entries.number || 0, this.entries.size || this.settings.pageSize, this.asc, this.entries.filter).subscribe({
this.entries = data; next: (data: any) => {
this.entries.filter = filter; this.entries = data;
}, (error) => { this.entries.filter = filter;
this.entries = { error: error }; },
error: (error) => {
this.entries = { error: error };
}
}) })
} }
@ -98,7 +105,7 @@ export class PageEntries implements OnInit, OnDestroy {
if (this.entries.filter) { if (this.entries.filter) {
for (const param in this.entries.filter) { for (const param in this.entries.filter) {
params[ param ] = this.entries.filter[ param ]; params[param] = this.entries.filter[param];
} }
} }
@ -111,11 +118,13 @@ export class PageEntries implements OnInit, OnDestroy {
}); });
const filter = JSON.parse(JSON.stringify(this.entries.filter || {})) const filter = JSON.parse(JSON.stringify(this.entries.filter || {}))
this.fetch(event.pageIndex, event.pageSize, this.asc, this.entries.filter).subscribe((data: any) => { this.fetch(event.pageIndex, event.pageSize, this.asc, this.entries.filter).subscribe({
this.entries = data; next: (data: any) => {
this.entries.filter = filter; this.entries = data;
}, (error) => { this.entries.filter = filter;
this.entries = { error: error }; }, error: (error) => {
this.entries = { error: error };
}
}) })
} }

View File

@ -46,10 +46,10 @@
</mat-card-content> </mat-card-content>
<mat-card-actions> <mat-card-actions>
<button *ngIf="!working && !entry.id" mat-raised-button color="primary" [disabled]="form.invalid"> <button type="submit" *ngIf="!working && !entry.id" mat-raised-button color="primary" [disabled]="form.invalid">
{{'submission.create' | i18n}} {{'submission.create' | i18n}}
</button> </button>
<button *ngIf="!working && entry.id" mat-raised-button color="primary" [disabled]="form.invalid"> <button type="submit" *ngIf="!working && entry.id" mat-raised-button color="primary" [disabled]="form.invalid">
{{'submission.update' | i18n}} {{'submission.update' | i18n}}
</button> </button>
<a *ngIf="success" mat-button color="primary" routerLink="/e/{{entry.id}}">{{'submission.success' | i18n}}</a> <a *ngIf="success" mat-button color="primary" routerLink="/e/{{entry.id}}">{{'submission.success' | i18n}}</a>

View File

@ -11,14 +11,14 @@ import { Subscription } from 'rxjs';
@Component({ @Component({
selector: 'page-entry-edit', selector: 'page-entry-edit',
templateUrl: './edit.page.html', templateUrl: './edit.page.html',
styleUrls: [ './edit.page.scss' ] styleUrls: ['./edit.page.scss']
}) })
export class PageEntryEdit implements OnInit, OnDestroy { export class PageEntryEdit implements OnInit, OnDestroy {
id: number; id: number;
entry: any; entry: any;
entryTypes: string[] = [ 'LINK', 'DISCUSSION', 'QUESTION', 'INTERN' ]; entryTypes: string[] = ['LINK', 'DISCUSSION', 'QUESTION', 'INTERN'];
entryType: string = this.entryTypes[ 0 ]; entryType: string = this.entryTypes[0];
notfound: boolean = false; notfound: boolean = false;
working: boolean = false; working: boolean = false;
success: boolean = false; success: boolean = false;
@ -37,40 +37,48 @@ export class PageEntryEdit implements OnInit, OnDestroy {
ngOnInit(): void { ngOnInit(): void {
this.form = this.formBuilder.group({ this.form = this.formBuilder.group({
entryType: [ '', Validators.required ], entryType: ['', Validators.required],
url: [ '', Validators.required ], url: ['', Validators.required],
title: [ '', Validators.required ], title: ['', Validators.required],
text: [ '', Validators.nullValidator ], text: ['', Validators.nullValidator],
}); });
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => { this.settingsSubscription = this.settingsService.settings.subscribe({
this.settings = settings; next: (settings) => {
this.settings = settings;
}
}); });
this.form.get('entryType').setValue(this.entryType); this.form.get('entryType').setValue(this.entryType);
this.form.get('entryType').valueChanges.subscribe((value) => { this.form.get('entryType').valueChanges.subscribe({
this.entryType = value; next: (value) => {
switch (value) { this.entryType = value;
case 'LINK': switch (value) {
this.form.get('url').setValidators([ Validators.required ]); case 'LINK':
this.form.get('text').setValidators([ Validators.nullValidator ]); this.form.get('url').setValidators([Validators.required]);
break; this.form.get('text').setValidators([Validators.nullValidator]);
default: break;
this.form.get('url').setValidators([ Validators.nullValidator ]); default:
this.form.get('text').setValidators([ Validators.required ]); this.form.get('url').setValidators([Validators.nullValidator]);
break; this.form.get('text').setValidators([Validators.required]);
break;
}
} }
}); });
this.form.get('url').valueChanges.pipe( this.form.get('url').valueChanges.pipe(
debounceTime(800), debounceTime(800),
distinctUntilChanged()).subscribe((value) => { distinctUntilChanged()).subscribe({
if (value && !this.form.get('title').value) { next: (value) => {
this.entriesService.titleHelper(value).subscribe((title: string) => { if (value && !this.form.get('title').value) {
this.form.get('title').setValue(title); this.entriesService.titleHelper(value).subscribe({
}) next: (title: string) => {
this.form.get('title').setValue(title);
}
})
}
} }
}) })
@ -85,21 +93,24 @@ export class PageEntryEdit implements OnInit, OnDestroy {
refresh() { refresh() {
if (this.id) { if (this.id) {
this.form.get('entryType').disable(); this.form.get('entryType').disable();
this.entriesService.getEntry(this.id).subscribe((data) => { this.entriesService.getEntry(this.id).subscribe({
this.entry = data; next: (data) => {
this.entryType = this.entry.entryType; this.entry = data;
this.form.get("entryType").setValue(this.entry.entryType); this.entryType = this.entry.entryType;
this.form.get("url").setValue(this.entry.url); this.form.get("entryType").setValue(this.entry.entryType);
this.form.get("title").setValue(this.entry.title); this.form.get("url").setValue(this.entry.url);
this.form.get("text").setValue(this.entry.text); this.form.get("title").setValue(this.entry.title);
if (!this.entry.metadata.edit) { this.form.get("text").setValue(this.entry.text);
this.form.get("url").disable(); if (!this.entry.metadata.edit) {
this.form.get("title").disable(); this.form.get("url").disable();
this.form.get("text").disable(); this.form.get("title").disable();
} this.form.get("text").disable();
}, (error) => { }
if (error.status == 404) { },
this.notfound = true; error: (error) => {
if (error.status == 404) {
this.notfound = true;
}
} }
}) })
} else { } else {
@ -110,7 +121,7 @@ export class PageEntryEdit implements OnInit, OnDestroy {
} }
hasError(controlName: string): boolean { hasError(controlName: string): boolean {
return this.form.controls[ controlName ].errors != null; return this.form.controls[controlName].errors != null;
} }
onTitleFocus(event): void { onTitleFocus(event): void {
@ -129,19 +140,22 @@ export class PageEntryEdit implements OnInit, OnDestroy {
this.entry.title = this.form.get("title").value; this.entry.title = this.form.get("title").value;
this.entry.text = this.form.get("text").value; this.entry.text = this.form.get("text").value;
this.entriesService.create(this.entry).subscribe((data) => { this.entriesService.create(this.entry).subscribe({
this.router.navigateByUrl('/'); next: (data) => {
}, (error) => { this.router.navigateByUrl('/');
this.working = false; },
if (error.status == 422) { error: (error) => {
let errors = {}; this.working = false;
for (let code of error.error) { if (error.status == 422) {
errors[ code.field ] = errors[ code.field ] || {}; let errors = {};
errors[ code.field ][ code.code ] = true; for (let code of error.error) {
} errors[code.field] = errors[code.field] || {};
errors[code.field][code.code] = true;
}
for (let code in errors) { for (let code in errors) {
this.form.get(code).setErrors(errors[ code ]); this.form.get(code).setErrors(errors[code]);
}
} }
} }
}) })
@ -159,46 +173,51 @@ export class PageEntryEdit implements OnInit, OnDestroy {
this.entry.title = this.form.get("title").value; this.entry.title = this.form.get("title").value;
this.entry.text = this.form.get("text").value; this.entry.text = this.form.get("text").value;
this.entriesService.update(this.entry).subscribe((data) => { this.entriesService.update(this.entry).subscribe({
this.entry = data; next: (data) => {
this.working = false; this.entry = data;
this.success = true; this.working = false;
}, (error) => { this.success = true;
this.working = false; },
if (error.status == 403) { error: (error) => {
this.snackBar.open("Error"); this.working = false;
} if (error.status == 403) {
if (error.status == 422) { this.snackBar.open("Error");
let errors = {};
for (let code of error.error) {
errors[ code.field ] = errors[ code.field ] || {};
errors[ code.field ][ code.code ] = true;
} }
if (error.status == 422) {
let errors = {};
for (let code of error.error) {
errors[code.field] = errors[code.field] || {};
errors[code.field][code.code] = true;
}
for (let code in errors) { for (let code in errors) {
this.form.get(code).setErrors(errors[ code ]); this.form.get(code).setErrors(errors[code]);
}
} }
} }
}) })
} else { } else {
this.tagsService.setTags(this.entry.id, this.entry.tags).subscribe((data) => { this.tagsService.setTags(this.entry.id, this.entry.tags).subscribe({
this.entry = data; next: (data) => {
this.working = false; this.entry = data;
this.success = true; this.working = false;
}, (error) => { this.success = true;
this.working = false; }, error: (error) => {
if (error.status == 403) { this.working = false;
this.snackBar.open("Error"); if (error.status == 403) {
} this.snackBar.open("Error");
if (error.status == 422) {
let errors = {};
for (let code of error.error) {
errors[ code.field ] = errors[ code.field ] || {};
errors[ code.field ][ code.code ] = true;
} }
if (error.status == 422) {
let errors = {};
for (let code of error.error) {
errors[code.field] = errors[code.field] || {};
errors[code.field][code.code] = true;
}
for (let code in errors) { for (let code in errors) {
this.form.get(code).setErrors(errors[ code ]); this.form.get(code).setErrors(errors[code]);
}
} }
} }
}) })

View File

@ -9,7 +9,7 @@ import { UiComments } from '../../ui/comments/comments.ui';
@Component({ @Component({
selector: 'page-entry', selector: 'page-entry',
templateUrl: './entry.page.html', templateUrl: './entry.page.html',
styleUrls: [ './entry.page.scss' ] styleUrls: ['./entry.page.scss']
}) })
export class PageEntry implements OnInit { export class PageEntry implements OnInit {
@ -29,12 +29,15 @@ export class PageEntry implements OnInit {
} }
refresh() { refresh() {
this.entriesService.getEntry(this.id).subscribe((data) => { this.entriesService.getEntry(this.id).subscribe({
this.entry = data; next: (data) => {
}, (error) => { this.entry = data;
if (error.status == 404) { },
this.entry = false; error: (error) => {
this.notfound = true; if (error.status == 404) {
this.entry = false;
this.notfound = true;
}
} }
}) })
} }

View File

@ -8,7 +8,7 @@ import { AuthService } from '../../services/auth.service';
@Component({ @Component({
selector: 'page-login', selector: 'page-login',
templateUrl: './login.page.html', templateUrl: './login.page.html',
styleUrls: [ './login.page.scss' ] styleUrls: ['./login.page.scss']
}) })
export class PageLogin implements OnInit { export class PageLogin implements OnInit {
@ -27,30 +27,34 @@ export class PageLogin implements OnInit {
private route: ActivatedRoute) { } private route: ActivatedRoute) { }
async ngOnInit() { async ngOnInit() {
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe({
if (params[ 'all' ] || params[ 'all' ] == '') { next: (params) => {
this.internalLogin = true; if (params['all'] || params['all'] == '') {
} this.internalLogin = true;
if (params[ 'target' ]) { }
this.targetRoute = params[ 'target' ]; if (params['target']) {
this.router.navigate([], { queryParams: { target: null }, queryParamsHandling: 'merge', replaceUrl: true }); this.targetRoute = params['target'];
} this.router.navigate([], { queryParams: { target: null }, queryParamsHandling: 'merge', replaceUrl: true });
if (params[ 'error' ] || params[ 'error' ] == '') { }
this.loginInvalid = true; if (params['error'] || params['error'] == '') {
this.router.navigate([], { queryParams: { error: null }, queryParamsHandling: 'merge', replaceUrl: true }); this.loginInvalid = true;
} this.router.navigate([], { queryParams: { error: null }, queryParamsHandling: 'merge', replaceUrl: true });
if (params[ 'externalError' ] || params[ 'externalError' ] == '') { }
this.externalLoginInvalid = true; if (params['externalError'] || params['externalError'] == '') {
this.router.navigate([], { queryParams: { externalError: null }, queryParamsHandling: 'merge', replaceUrl: true }); this.externalLoginInvalid = true;
this.router.navigate([], { queryParams: { externalError: null }, queryParamsHandling: 'merge', replaceUrl: true });
}
} }
}); });
this.authService.getExternal().subscribe((data: any[]) => { this.authService.getExternal().subscribe({
this.externals = data; next: (data: any[]) => {
const autologinClient = localStorage.getItem("bstlboard.autologin"); this.externals = data;
for (let client of this.externals) { const autologinClient = localStorage.getItem("bstlboard.autologin");
if (client.id == autologinClient) { for (let client of this.externals) {
window.location.href = this.apiUrl + "/" + client.loginUrl; if (client.id == autologinClient) {
window.location.href = this.apiUrl + "/" + client.loginUrl;
}
} }
} }
}) })

View File

@ -19,19 +19,23 @@ export class PageModerationComments implements OnInit {
} }
refresh(): void { refresh(): void {
this.moderationService.getFlaggedComments(this.comments.number || 0, this.comments.size || 30).subscribe((data: any) => { this.moderationService.getFlaggedComments(this.comments.number || 0, this.comments.size || 30).subscribe({
this.comments = data; next: (data: any) => {
}, (error) => { }) this.comments = data;
}
})
} }
showMore() { showMore() {
const oldContent: any[] = this.comments.content; const oldContent: any[] = this.comments.content;
this.moderationService.getFlaggedComments(this.comments.number + 1, this.comments.size).subscribe((data) => { this.moderationService.getFlaggedComments(this.comments.number + 1, this.comments.size).subscribe({
this.comments = data; next: (data) => {
for (let comment of this.comments.content) { this.comments = data;
oldContent.push(comment); for (let comment of this.comments.content) {
oldContent.push(comment);
}
this.comments.content = oldContent;
} }
this.comments.content = oldContent;
}) })
} }
} }

View File

@ -44,13 +44,17 @@ export class PageSearch implements OnInit {
}) })
this.searchFormControl.valueChanges.pipe( this.searchFormControl.valueChanges.pipe(
debounceTime(300)).subscribe((value: string) => { debounceTime(300)).subscribe({
this.refresh(); next: (value: string) => {
this.refresh();
}
}) })
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => { this.settingsSubscription = this.settingsService.settings.subscribe({
this.settings = settings; next: (settings) => {
this.refresh(); this.settings = settings;
this.refresh();
}
}) })
} }
@ -79,10 +83,13 @@ export class PageSearch implements OnInit {
}); });
this.results.content = null; this.results.content = null;
this.searchService.search(this.searchFormControl.value || " ", this.searchType, 0, this.results.size || this.settings.pageSize, this.asc, this.byDate).subscribe((data: any) => { this.searchService.search(this.searchFormControl.value || " ", this.searchType, 0, this.results.size || this.settings.pageSize, this.asc, this.byDate).subscribe({
this.results = data; next: (data: any) => {
}, (error) => { this.results = data;
this.results = { error: error }; },
error: (error) => {
this.results = { error: error };
}
}) })
} }
@ -106,10 +113,13 @@ export class PageSearch implements OnInit {
queryParamsHandling: 'merge' queryParamsHandling: 'merge'
}); });
this.searchService.search(this.searchFormControl.value, this.searchType, event.pageIndex, event.pageSize, this.asc, this.byDate).subscribe((data: any) => { this.searchService.search(this.searchFormControl.value, this.searchType, event.pageIndex, event.pageSize, this.asc, this.byDate).subscribe({
this.results = data; next: (data: any) => {
}, (error) => { this.results = data;
this.results = { error: error }; },
error: (error) => {
this.results = { error: error };
}
}) })
} }
} }

View File

@ -79,7 +79,7 @@
</mat-form-field> </mat-form-field>
</mat-card-content> </mat-card-content>
<mat-card-actions> <mat-card-actions>
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid"> <button type="submit" *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
{{'settings.update' | i18n}} {{'settings.update' | i18n}}
</button> </button>
<a *ngIf="success" mat-button color="primary">{{'settings.success' | i18n}}</a> <a *ngIf="success" mat-button color="primary">{{'settings.success' | i18n}}</a>

View File

@ -8,7 +8,7 @@ import { Subscription } from 'rxjs';
@Component({ @Component({
selector: 'page-settings', selector: 'page-settings',
templateUrl: './settings.page.html', templateUrl: './settings.page.html',
styleUrls: [ './settings.page.scss' ] styleUrls: ['./settings.page.scss']
}) })
export class PageSettings implements OnInit, OnDestroy { export class PageSettings implements OnInit, OnDestroy {
@ -27,33 +27,37 @@ export class PageSettings implements OnInit, OnDestroy {
ngOnInit(): void { ngOnInit(): void {
this.form = this.formBuilder.group({ this.form = this.formBuilder.group({
username: [ { disabled: true }, Validators.nullValidator ], username: [{ disabled: true }, Validators.nullValidator],
email: [ '', Validators.nullValidator ], email: ['', Validators.nullValidator],
about: [ '', Validators.nullValidator ], about: ['', Validators.nullValidator],
gravity: [ '', Validators.nullValidator ], gravity: ['', Validators.nullValidator],
entryDelay: [ '', Validators.nullValidator ], entryDelay: ['', Validators.nullValidator],
commentDelay: [ '', Validators.nullValidator ], commentDelay: ['', Validators.nullValidator],
pageSize: [ '', Validators.nullValidator ], pageSize: ['', Validators.nullValidator],
}); });
this.form.get('username').disable(); this.form.get('username').disable();
this.userService.get().subscribe(user => { this.userService.get().subscribe({
this.user = user; next: (user) => {
if (!this.user.settings) { this.user = user;
this.user.settings = {}; if (!this.user.settings) {
} this.user.settings = {};
this.form.get('username').setValue(this.user.username); }
this.form.get('email').setValue(this.user.email); this.form.get('username').setValue(this.user.username);
this.form.get('about').setValue(this.user.about); this.form.get('email').setValue(this.user.email);
this.form.get('about').setValue(this.user.about);
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => { this.settingsSubscription = this.settingsService.settings.subscribe({
this.settings = settings; next: (settings) => {
this.form.get('gravity').setValue(this.user.settings.gravity || this.settings.defaultGravity); this.settings = settings;
this.form.get('entryDelay').setValue(this.user.settings.entryDelay || this.settings.defaultEntryDelay); this.form.get('gravity').setValue(this.user.settings.gravity || this.settings.defaultGravity);
this.form.get('commentDelay').setValue(this.user.settings.commentDelay || this.settings.defaultCommentDelay); this.form.get('entryDelay').setValue(this.user.settings.entryDelay || this.settings.defaultEntryDelay);
this.form.get('pageSize').setValue(this.user.settings.pageSize || this.settings.defaultPageSize); this.form.get('commentDelay').setValue(this.user.settings.commentDelay || this.settings.defaultCommentDelay);
}); this.form.get('pageSize').setValue(this.user.settings.pageSize || this.settings.defaultPageSize);
}
});
}
}) })
} }
@ -62,7 +66,7 @@ export class PageSettings implements OnInit, OnDestroy {
} }
hasError(controlName: string): boolean { hasError(controlName: string): boolean {
return this.form.controls[ controlName ].errors != null; return this.form.controls[controlName].errors != null;
} }
resetGravity(): void { resetGravity(): void {
@ -124,25 +128,28 @@ export class PageSettings implements OnInit, OnDestroy {
this.user.settings.pageSize = this.form.get('pageSize').value; this.user.settings.pageSize = this.form.get('pageSize').value;
} }
this.userService.update(this.user).subscribe((data) => { this.userService.update(this.user).subscribe({
this.user = data; next: (data) => {
if (!this.user.settings) { this.user = data;
this.user.settings = {}; if (!this.user.settings) {
} this.user.settings = {};
this.working = false;
this.success = true;
this.settingsService.getSettings();
}, (error) => {
this.working = false;
if (error.status == 422) {
let errors = {};
for (let code of error.error) {
errors[ code.field ] = errors[ code.field ] || {};
errors[ code.field ][ code.code ] = true;
} }
this.working = false;
this.success = true;
this.settingsService.getSettings();
},
error: (error) => {
this.working = false;
if (error.status == 422) {
let errors = {};
for (let code of error.error) {
errors[code.field] = errors[code.field] || {};
errors[code.field][code.code] = true;
}
for (let code in errors) { for (let code in errors) {
this.form.get(code).setErrors(errors[ code ]); this.form.get(code).setErrors(errors[code]);
}
} }
} }
}) })

View File

@ -5,7 +5,7 @@ import { Router, ActivatedRoute } from '@angular/router';
@Component({ @Component({
selector: 'page-unavailable', selector: 'page-unavailable',
templateUrl: './unavailable.page.html', templateUrl: './unavailable.page.html',
styleUrls: [ './unavailable.page.scss' ] styleUrls: ['./unavailable.page.scss']
}) })
export class PageUnavailable implements OnInit { export class PageUnavailable implements OnInit {
@ -17,10 +17,12 @@ export class PageUnavailable implements OnInit {
private route: ActivatedRoute) { } private route: ActivatedRoute) { }
ngOnInit(): void { ngOnInit(): void {
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe({
if (params[ 'target' ]) { next: (params) => {
this.targetRoute = params[ 'target' ]; if (params['target']) {
this.router.navigate([], { queryParams: { target: null }, queryParamsHandling: 'merge', skipLocationChange: true }); this.targetRoute = params['target'];
this.router.navigate([], { queryParams: { target: null }, queryParamsHandling: 'merge', skipLocationChange: true });
}
} }
}); });
@ -30,7 +32,7 @@ export class PageUnavailable implements OnInit {
if (!this.targetRoute || this.targetRoute === "unavailable" || this.targetRoute === "/unavailable") { if (!this.targetRoute || this.targetRoute === "unavailable" || this.targetRoute === "/unavailable") {
this.location.back; this.location.back;
} else { } else {
this.router.navigate([ this.targetRoute ]); this.router.navigate([this.targetRoute]);
} }
} }

View File

@ -8,7 +8,7 @@ import { UserService } from '../../services/user.service';
@Component({ @Component({
selector: 'page-user', selector: 'page-user',
templateUrl: './user.page.html', templateUrl: './user.page.html',
styleUrls: [ './user.page.scss' ] styleUrls: ['./user.page.scss']
}) })
export class PageUser implements OnInit { export class PageUser implements OnInit {
@ -21,11 +21,14 @@ export class PageUser implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.username = this.route.snapshot.paramMap.get('username'); this.username = this.route.snapshot.paramMap.get('username');
this.userService.getUser(this.username).subscribe((data) => { this.userService.getUser(this.username).subscribe({
this.user = data; next: (data) => {
}, (error) => { this.user = data;
if (error.status == 422) { },
this.notfound = true; error: (error) => {
if (error.status == 422) {
this.notfound = true;
}
} }
}) })
} }

View File

@ -9,7 +9,7 @@ import { SettingsService } from '../../../services/settings.service';
@Component({ @Component({
selector: 'page-usercomments', selector: 'page-usercomments',
templateUrl: './usercomments.page.html', templateUrl: './usercomments.page.html',
styleUrls: [ './usercomments.page.scss' ] styleUrls: ['./usercomments.page.scss']
}) })
export class PageUserComments implements OnInit, OnDestroy { export class PageUserComments implements OnInit, OnDestroy {
@ -17,18 +17,22 @@ export class PageUserComments implements OnInit, OnDestroy {
username: string; username: string;
comments: any = {}; comments: any = {};
init: boolean = true; init: boolean = true;
ignore: string[] = [ "author" ]; ignore: string[] = ["author"];
settingsSubscription: Subscription; settingsSubscription: Subscription;
constructor(private settingsService: SettingsService, private commentService: CommentService, private router: Router, private route: ActivatedRoute) { } constructor(private settingsService: SettingsService, private commentService: CommentService, private router: Router, private route: ActivatedRoute) { }
ngOnInit(): void { ngOnInit(): void {
this.username = this.route.snapshot.paramMap.get('username'); this.username = this.route.snapshot.paramMap.get('username');
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => { this.settingsSubscription = this.settingsService.settings.subscribe({
this.settings = settings; next: (settings) => {
this.commentService.getByUser(this.username, this.comments.number || 0, this.comments.size || this.settings.pageSize, this.ignore).subscribe((data: any) => { this.settings = settings;
this.comments = data; this.commentService.getByUser(this.username, this.comments.number || 0, this.comments.size || this.settings.pageSize, this.ignore).subscribe({
}, (error) => { }) next: (data: any) => {
this.comments = data;
}
})
}
}) })
} }
@ -38,12 +42,14 @@ export class PageUserComments implements OnInit, OnDestroy {
showMore() { showMore() {
const oldContent: any[] = this.comments.content; const oldContent: any[] = this.comments.content;
this.commentService.getByUser(this.username, this.comments.number + 1, this.comments.size, this.ignore).subscribe((data) => { this.commentService.getByUser(this.username, this.comments.number + 1, this.comments.size, this.ignore).subscribe({
this.comments = data; next: (data) => {
for (let comment of this.comments.content) { this.comments = data;
oldContent.push(comment); for (let comment of this.comments.content) {
oldContent.push(comment);
}
this.comments.content = oldContent;
} }
this.comments.content = oldContent;
}) })
} }
} }

View File

@ -70,7 +70,7 @@
</mat-card-content> </mat-card-content>
<mat-card-actions class="flex wrap fill"> <mat-card-actions class="flex wrap fill">
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid"> <button type="submit" *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
<mat-icon>save</mat-icon> {{ (view.id ? 'views.update' : 'views.create') | i18n}} <mat-icon>save</mat-icon> {{ (view.id ? 'views.update' : 'views.create') | i18n}}
</button> </button>
<a mat-button color="primary" routerLink="/v/{{view.name}}" *ngIf="view.id">{{ 'views.goTo' | <a mat-button color="primary" routerLink="/v/{{view.name}}" *ngIf="view.id">{{ 'views.goTo' |

View File

@ -13,16 +13,16 @@ import { MatDialog } from '@angular/material/dialog';
@Component({ @Component({
selector: 'page-view-edit', selector: 'page-view-edit',
templateUrl: './edit.page.html', templateUrl: './edit.page.html',
styleUrls: [ './edit.page.scss' ] styleUrls: ['./edit.page.scss']
}) })
export class PageViewEdit implements OnInit, OnDestroy { export class PageViewEdit implements OnInit, OnDestroy {
name: string; name: string;
view: any; view: any;
entryTypes: string[] = [ undefined, 'LINK', 'DISCUSSION', 'QUESTION', 'INTERN' ]; entryTypes: string[] = [undefined, 'LINK', 'DISCUSSION', 'QUESTION', 'INTERN'];
entryType: string = this.entryTypes[ 0 ]; entryType: string = this.entryTypes[0];
sortings: string[] = [ 'NEW', 'TOP', 'HOT', 'LAST' ]; sortings: string[] = ['NEW', 'TOP', 'HOT', 'LAST'];
sorting: string = this.sortings[ 0 ]; sorting: string = this.sortings[0];
notfound: boolean = false; notfound: boolean = false;
working: boolean = false; working: boolean = false;
form: FormGroup; form: FormGroup;
@ -44,34 +44,44 @@ export class PageViewEdit implements OnInit, OnDestroy {
ngOnInit(): void { ngOnInit(): void {
this.form = this.formBuilder.group({ this.form = this.formBuilder.group({
name: [ '', Validators.required ], name: ['', Validators.required],
entryType: [ '', Validators.nullValidator ], entryType: ['', Validators.nullValidator],
sorting: [ '', Validators.required ], sorting: ['', Validators.required],
index: [ '', Validators.required ], index: ['', Validators.required],
}); });
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => { this.settingsSubscription = this.settingsService.settings.subscribe({
this.settings = settings; next: (settings) => {
this.settings = settings;
}
}); });
this.route.params.subscribe((params) => { this.route.params.subscribe({
if (params.name) { next: (params) => {
this.form.get('name').setValue(params.name); if (params.name) {
this.form.get('name').setValue(params.name);
this.form.get('entryType').setValue(this.entryType); this.form.get('entryType').setValue(this.entryType);
this.form.get('entryType').valueChanges.subscribe((value) => { this.form.get('entryType').valueChanges.subscribe({
this.entryType = value; next: (value) => {
}); this.entryType = value;
this.form.get('sorting').setValue(this.sorting); }
this.form.get('sorting').valueChanges.subscribe((value) => { });
this.sorting = value; this.form.get('sorting').setValue(this.sorting);
}); this.form.get('sorting').valueChanges.subscribe({
this.form.get('index').valueChanges.subscribe((value) => { next: (value) => {
this.view.index = value; this.sorting = value;
}); }
});
this.form.get('index').valueChanges.subscribe({
next: (value) => {
this.view.index = value;
}
});
this.name = params.name; this.name = params.name;
this.refresh(); this.refresh();
}
} }
}) })
@ -84,17 +94,20 @@ export class PageViewEdit implements OnInit, OnDestroy {
refresh() { refresh() {
if (this.name) { if (this.name) {
this.viewService.getView(this.name, undefined).subscribe((data) => { this.viewService.getView(this.name, undefined).subscribe({
this.view = data; next: (data) => {
this.entryType = this.view.entryType; this.view = data;
this.sorting = this.view.sorting; this.entryType = this.view.entryType;
this.form.get("name").setValue(this.view.name); this.sorting = this.view.sorting;
this.form.get("entryType").setValue(this.view.entryType); this.form.get("name").setValue(this.view.name);
this.form.get("sorting").setValue(this.view.sorting); this.form.get("entryType").setValue(this.view.entryType);
this.form.get("index").setValue(this.view.index); this.form.get("sorting").setValue(this.view.sorting);
}, (error) => { this.form.get("index").setValue(this.view.index);
if (error.status == 404) { },
this.notfound = true; error: (error) => {
if (error.status == 404) {
this.notfound = true;
}
} }
}) })
} else { } else {
@ -111,7 +124,7 @@ export class PageViewEdit implements OnInit, OnDestroy {
} }
hasError(controlName: string): boolean { hasError(controlName: string): boolean {
return this.form.controls[ controlName ].errors != null; return this.form.controls[controlName].errors != null;
} }
@ -127,28 +140,31 @@ export class PageViewEdit implements OnInit, OnDestroy {
this.view.sorting = this.sorting; this.view.sorting = this.sorting;
this.view.index = this.form.get("index").value; this.view.index = this.form.get("index").value;
this.viewService.createOrUpdate(this.view).subscribe((data) => { this.viewService.createOrUpdate(this.view).subscribe({
this.view = data; next: (data) => {
this.working = false; this.view = data;
this.snackBar.open(this.i18n.get('views.success', []), this.i18n.get("close", []), { this.working = false;
duration: 3000 this.snackBar.open(this.i18n.get('views.success', []), this.i18n.get("close", []), {
}); duration: 3000
this.router.navigateByUrl('/v/' + this.view.name); });
this.viewService.getViews(); this.router.navigateByUrl('/v/' + this.view.name);
}, (error) => { this.viewService.getViews();
this.working = false; },
if (error.status == 403) { error: (error) => {
this.snackBar.open("Error"); this.working = false;
} if (error.status == 403) {
if (error.status == 422) { this.snackBar.open("Error");
let errors = {};
for (let code of error.error) {
errors[ code.field ] = errors[ code.field ] || {};
errors[ code.field ][ code.code ] = true;
} }
if (error.status == 422) {
let errors = {};
for (let code of error.error) {
errors[code.field] = errors[code.field] || {};
errors[code.field][code.code] = true;
}
for (let code in errors) { for (let code in errors) {
this.form.get(code).setErrors(errors[ code ]); this.form.get(code).setErrors(errors[code]);
}
} }
} }
}) })
@ -158,18 +174,22 @@ export class PageViewEdit implements OnInit, OnDestroy {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'views.confirmDelete', 'label': 'views.confirmDelete',
'args': [ this.view.name ] 'args': [this.view.name]
} }
}) })
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe({
if (result) { next: (result) => {
this.working = true; if (result) {
this.viewService.deleteView(this.view.name).subscribe(() => { this.working = true;
this.working = false; this.viewService.deleteView(this.view.name).subscribe({
this.router.navigateByUrl('/'); next: () => {
this.viewService.getViews(); this.working = false;
}) this.router.navigateByUrl('/');
this.viewService.getViews();
}
})
}
} }
}); });
} }

View File

@ -9,7 +9,7 @@ import { PageEntries } from '../entries/entries.page';
@Component({ @Component({
selector: 'page-view', selector: 'page-view',
templateUrl: './view.page.html', templateUrl: './view.page.html',
styleUrls: [ './view.page.scss' ] styleUrls: ['./view.page.scss']
}) })
export class PageView implements OnInit, OnDestroy { export class PageView implements OnInit, OnDestroy {
@ -27,27 +27,32 @@ export class PageView implements OnInit, OnDestroy {
} }
ngOnInit(): void { ngOnInit(): void {
this.paramsSub = this.route.params.subscribe((params: Params) => { this.paramsSub = this.route.params.subscribe({
this.name = params[ 'name' ]; next: (params: Params) => {
this.username = params[ 'username' ]; this.name = params['name'];
this.username = params['username'];
if (!this.name) { if (!this.name) {
this.viewService.getViews().then((data: any) => { this.viewService.getViews().then((data: any) => {
const views = data.content; const views = data.content;
if (!views || views.length == 0) { if (!views || views.length == 0) {
this.router.navigate([ '/v' ], { queryParams: { name: this.name }, queryParamsHandling: 'merge' }); this.router.navigate(['/v'], { queryParams: { name: this.name }, queryParamsHandling: 'merge' });
} else { } else {
this.router.navigateByUrl('/v/' + views[ 0 ].name); this.router.navigateByUrl('/v/' + views[0].name);
} }
}) })
} else { } else {
this.viewService.getView(this.name, this.username).subscribe((data) => { this.viewService.getView(this.name, this.username).subscribe({
if (this.entries) { next: (data) => {
this.entries.refresh(); if (this.entries) {
} this.entries.refresh();
}, (error) => { }
this.router.navigate([ '/v' ], { queryParams: { name: this.name }, queryParamsHandling: 'merge' }); },
}) error: (error) => {
this.router.navigate(['/v'], { queryParams: { name: this.name }, queryParamsHandling: 'merge' });
}
})
}
} }
}); });
this.boundFetch = this.fetch.bind(this); this.boundFetch = this.fetch.bind(this);

View File

@ -74,7 +74,7 @@
{{'comment.text.error' | i18n}} {{'comment.text.error' | i18n}}
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid"> <button type="submit" *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
{{'comment.save' | i18n}} {{'comment.save' | i18n}}
</button> </button>
</form> </form>

View File

@ -13,7 +13,7 @@ import { UiComments } from '../comments/comments.ui';
@Component({ @Component({
selector: 'ui-comment', selector: 'ui-comment',
templateUrl: './comment.ui.html', templateUrl: './comment.ui.html',
styleUrls: [ './comment.ui.scss' ] styleUrls: ['./comment.ui.scss']
}) })
export class UiComment implements OnInit { export class UiComment implements OnInit {
@ -29,6 +29,7 @@ export class UiComment implements OnInit {
@Input() actions: boolean = true; @Input() actions: boolean = true;
@ViewChild('subcomments') comments: UiComments; @ViewChild('subcomments') comments: UiComments;
form: FormGroup; form: FormGroup;
working: boolean = false;
constructor( constructor(
private authService: AuthService, private authService: AuthService,
@ -40,45 +41,61 @@ export class UiComment implements OnInit {
public dialog: MatDialog) { } public dialog: MatDialog) { }
ngOnInit(): void { ngOnInit(): void {
this.authService.auth.subscribe((auth: any) => { this.authService.auth.subscribe({
if (auth && auth.authorities) { next: (auth: any) => {
this.author = auth.username == this.comment.author; if (auth && auth.authorities) {
for (let role of auth.authorities) { this.author = auth.username == this.comment.author;
if (role.authority == 'ROLE_ADMIN' || role.authority == 'ROLE_MOD') { for (let role of auth.authorities) {
this.moderator = true; if (role.authority == 'ROLE_ADMIN' || role.authority == 'ROLE_MOD') {
this.moderator = true;
}
} }
} }
} }
}) })
this.form = this.formBuilder.group({ this.form = this.formBuilder.group({
text: [ '', Validators.required ], text: ['', Validators.required],
}); });
this.form.get('text').setValue(this.comment.text); this.form.get('text').setValue(this.comment.text);
} }
voteUp() { voteUp() {
this.voteService.voteCommentUp(this.comment.id).subscribe((result) => { this.voteService.voteCommentUp(this.comment.id).subscribe({
this.commentService.getComment(this.comment.id, this.ignore).subscribe((data) => { next: () => {
this.comment = data; this.commentService.getComment(this.comment.id, this.ignore).subscribe({
}) next: (data) => {
this.comment = data;
}
})
}
}); });
} }
voteDown() { voteDown() {
this.voteService.voteCommentDown(this.comment.id).subscribe((result) => { this.voteService.voteCommentDown(this.comment.id).subscribe({
this.commentService.getComment(this.comment.id, this.ignore).subscribe((data) => { next: () => {
this.comment = data; this.commentService.getComment(this.comment.id, this.ignore).subscribe({
}) next: (data) => {
this.comment = data;
}
})
}
}); });
} }
unvote() { unvote() {
this.voteService.unvoteComment(this.comment.id).subscribe((result) => { this.voteService.unvoteComment(this.comment.id).subscribe({
this.commentService.getComment(this.comment.id, this.ignore).subscribe((data) => { next: (
this.comment = data;
}) ) => {
this.commentService.getComment(this.comment.id, this.ignore).subscribe({
next: (data) => {
this.comment = data;
}
})
}
}); });
} }
@ -86,16 +103,20 @@ export class UiComment implements OnInit {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'comment.confirmFlag', 'label': 'comment.confirmFlag',
'args': [ this.comment.text, this.comment.author ] 'args': [this.comment.text, this.comment.author]
} }
}) })
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe({
if (result) { next: (result) => {
this.flagService.flagComment(this.comment.id).subscribe((result) => { if (result) {
this.comment.metadata.flag = false; this.flagService.flagComment(this.comment.id).subscribe({
this.comment.metadata.unflag = true; next: () => {
}); this.comment.metadata.flag = false;
this.comment.metadata.unflag = true;
}
});
}
} }
}); });
} }
@ -104,16 +125,20 @@ export class UiComment implements OnInit {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'comment.confirmUnflag', 'label': 'comment.confirmUnflag',
'args': [ this.comment.text, this.comment.author ] 'args': [this.comment.text, this.comment.author]
} }
}) })
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe({
if (result) { next: (result) => {
this.flagService.unflagComment(this.comment.id).subscribe((result) => { if (result) {
this.comment.metadata.flag = true; this.flagService.unflagComment(this.comment.id).subscribe({
this.comment.metadata.unflag = false; next: () => {
}); this.comment.metadata.flag = true;
this.comment.metadata.unflag = false;
}
});
}
} }
}); });
} }
@ -142,16 +167,28 @@ export class UiComment implements OnInit {
} }
hasError(controlName: string): boolean { hasError(controlName: string): boolean {
return this.form.controls[ controlName ].errors != null; return this.form.controls[controlName].errors != null;
} }
update(): void { update(): void {
if (this.working) {
return;
}
if (this.canEdit()) { if (this.canEdit()) {
this.working = true;
this.comment.text = this.form.get('text').value; this.comment.text = this.form.get('text').value;
this.form.get('text').disable(); this.form.get('text').disable();
this.commentService.update(this.comment).subscribe((data) => { this.commentService.update(this.comment).subscribe({
this.comment = data; next: (data) => {
this.comment.metadata.edit = false; this.comment = data;
this.comment.metadata.edit = false;
this.working = false;
},
error: () => {
this.working = false;
}
}) })
} }
} }
@ -160,15 +197,19 @@ export class UiComment implements OnInit {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'comment.confirmDelete', 'label': 'comment.confirmDelete',
'args': [ this.comment.text, this.comment.author ] 'args': [this.comment.text, this.comment.author]
} }
}) })
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe({
if (result) { next: (result) => {
this.commentService.delete(this.comment.id).subscribe((result: any) => { if (result) {
this.change && this.change() this.commentService.delete(this.comment.id).subscribe({
}) next: () => {
this.change && this.change()
}
})
}
} }
}); });
} }
@ -177,15 +218,19 @@ export class UiComment implements OnInit {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'moderation.comment.confirmDelete', 'label': 'moderation.comment.confirmDelete',
'args': [ this.comment.text, this.comment.author ] 'args': [this.comment.text, this.comment.author]
} }
}) })
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe({
if (result) { next: (result) => {
this.moderationService.deleteComment(this.comment.id).subscribe((result: any) => { if (result) {
this.change && this.change() this.moderationService.deleteComment(this.comment.id).subscribe({
}) next: () => {
this.change && this.change()
}
})
}
} }
}); });
} }
@ -194,15 +239,19 @@ export class UiComment implements OnInit {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'moderation.comment.confirmUnflag', 'label': 'moderation.comment.confirmUnflag',
'args': [ this.comment.text, this.comment.author ] 'args': [this.comment.text, this.comment.author]
} }
}) })
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe({
if (result) { next: (result) => {
this.moderationService.unflagComment(this.comment.id).subscribe((result: any) => { if (result) {
this.change && this.change(); this.moderationService.unflagComment(this.comment.id).subscribe({
}) next: () => {
this.change && this.change();
}
})
}
} }
}); });
} }

View File

@ -4,7 +4,7 @@ import { CommentService } from '../../services/comment.service';
@Component({ @Component({
selector: 'ui-commentcount', selector: 'ui-commentcount',
templateUrl: './commentcount.ui.html', templateUrl: './commentcount.ui.html',
styleUrls: [ './commentcount.ui.scss' ] styleUrls: ['./commentcount.ui.scss']
}) })
export class UiCommentCount implements OnInit { export class UiCommentCount implements OnInit {
@ -16,12 +16,16 @@ export class UiCommentCount implements OnInit {
ngOnInit(): void { ngOnInit(): void {
if (this.target && this.parent) { if (this.target && this.parent) {
this.commentService.countParent(this.target, this.parent).subscribe((data) => { this.commentService.countParent(this.target, this.parent).subscribe({
this.count = +data; next: (data) => {
this.count = +data;
}
}); });
} else if (this.target) { } else if (this.target) {
this.commentService.count(this.target).subscribe((data) => { this.commentService.count(this.target).subscribe({
this.count = +data; next: (data) => {
this.count = +data;
}
}); });
} }
} }

View File

@ -8,7 +8,7 @@
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid"> <button type="submit" *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
{{'comment.create' | i18n}} {{'comment.create' | i18n}}
</button> </button>

View File

@ -6,7 +6,7 @@ import { Output, EventEmitter } from '@angular/core';
@Component({ @Component({
selector: 'ui-commentform', selector: 'ui-commentform',
templateUrl: './commentform.ui.html', templateUrl: './commentform.ui.html',
styleUrls: [ './commentform.ui.scss' ] styleUrls: ['./commentform.ui.scss']
}) })
export class UiCommentForm implements OnInit { export class UiCommentForm implements OnInit {
@ -22,23 +22,32 @@ export class UiCommentForm implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.form = this.formBuilder.group({ this.form = this.formBuilder.group({
text: [ '', Validators.required ], text: ['', Validators.required],
}); });
} }
hasError(controlName: string): boolean { hasError(controlName: string): boolean {
return this.form.controls[ controlName ].errors != null; return this.form.controls[controlName].errors != null;
} }
create(): void { create(): void {
if (this.working) {
return;
}
const comment: any = {}; const comment: any = {};
comment.target = this.target; comment.target = this.target;
comment.parent = this.parent; comment.parent = this.parent;
comment.text = this.form.get("text").value; comment.text = this.form.get("text").value;
this.working = true;
this.commentService.create(comment).subscribe((data) => { this.commentService.create(comment).subscribe({
this.formDirective.resetForm(); next: (data) => {
this.replyCommentEvent.emit(data); this.formDirective.resetForm();
this.replyCommentEvent.emit(data);
this.working = false;
},
error: () => {
this.working = false;
}
}); });
} }
} }

View File

@ -7,7 +7,7 @@ import { SettingsService } from '../../services/settings.service';
@Component({ @Component({
selector: 'ui-comments', selector: 'ui-comments',
templateUrl: './comments.ui.html', templateUrl: './comments.ui.html',
styleUrls: [ './comments.ui.scss' ] styleUrls: ['./comments.ui.scss']
}) })
export class UiComments implements OnInit, OnDestroy { export class UiComments implements OnInit, OnDestroy {
@ -25,9 +25,11 @@ export class UiComments implements OnInit, OnDestroy {
ngOnInit(): void { ngOnInit(): void {
this.boundRefresh = this.refresh.bind(this); this.boundRefresh = this.refresh.bind(this);
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => { this.settingsSubscription = this.settingsService.settings.subscribe({
this.settings = settings; next: (settings) => {
this.refresh(); this.settings = settings;
this.refresh();
}
}) })
} }
@ -37,12 +39,16 @@ export class UiComments implements OnInit, OnDestroy {
refresh(): void { refresh(): void {
if (this.parent) { if (this.parent) {
this.commentService.getNewByParent(this.target, this.parent, 0, this.settings.pageSize, this.ignore).subscribe((data) => { this.commentService.getNewByParent(this.target, this.parent, 0, this.settings.pageSize, this.ignore).subscribe({
this.comments = data; next: (data) => {
this.comments = data;
}
}) })
} else { } else {
this.commentService.getNew(this.target, 0, this.settings.pageSize, this.ignore).subscribe((data) => { this.commentService.getNew(this.target, 0, this.settings.pageSize, this.ignore).subscribe({
this.comments = data; next: (data) => {
this.comments = data;
}
}) })
} }
} }
@ -63,20 +69,24 @@ export class UiComments implements OnInit, OnDestroy {
showMore() { showMore() {
const oldContent: any[] = this.comments.content; const oldContent: any[] = this.comments.content;
if (this.parent) { if (this.parent) {
this.commentService.getNewByParent(this.target, this.parent, this.comments.number + 1, this.comments.size, this.ignore).subscribe((data) => { this.commentService.getNewByParent(this.target, this.parent, this.comments.number + 1, this.comments.size, this.ignore).subscribe({
this.comments = data; next: (data) => {
for (let comment of this.comments.content) { this.comments = data;
oldContent.push(comment); for (let comment of this.comments.content) {
oldContent.push(comment);
}
this.comments.content = oldContent;
} }
this.comments.content = oldContent;
}) })
} else { } else {
this.commentService.getNew(this.target, this.comments.number + 1, this.comments.size, this.ignore).subscribe((data) => { this.commentService.getNew(this.target, this.comments.number + 1, this.comments.size, this.ignore).subscribe({
this.comments = data; next: (data) => {
for (let comment of this.comments.content) { this.comments = data;
oldContent.push(comment); for (let comment of this.comments.content) {
oldContent.push(comment);
}
this.comments.content = oldContent;
} }
this.comments.content = oldContent;
}) })
} }
} }

View File

@ -13,7 +13,7 @@ import { ActivatedRoute, Router } from '@angular/router';
@Component({ @Component({
selector: 'ui-entry', selector: 'ui-entry',
templateUrl: './entry.ui.html', templateUrl: './entry.ui.html',
styleUrls: [ './entry.ui.scss' ] styleUrls: ['./entry.ui.scss']
}) })
export class UiEntry implements OnInit { export class UiEntry implements OnInit {
@ -37,11 +37,13 @@ export class UiEntry implements OnInit {
private route: ActivatedRoute) { } private route: ActivatedRoute) { }
ngOnInit(): void { ngOnInit(): void {
this.authService.auth.subscribe((auth: any) => { this.authService.auth.subscribe({
if (auth && auth.authorities) { next: (auth: any) => {
for (let role of auth.authorities) { if (auth && auth.authorities) {
if (role.authority == 'ROLE_ADMIN' || role.authority == 'ROLE_MOD') { for (let role of auth.authorities) {
this.moderator = true; if (role.authority == 'ROLE_ADMIN' || role.authority == 'ROLE_MOD') {
this.moderator = true;
}
} }
} }
} }
@ -62,34 +64,44 @@ export class UiEntry implements OnInit {
} }
voteUp() { voteUp() {
this.voteService.voteEntryUp(this.entry.id).subscribe((result) => { this.voteService.voteEntryUp(this.entry.id).subscribe({
this.change && this.change(); next: () => {
this.change && this.change();
}
}); });
} }
voteDown() { voteDown() {
this.voteService.voteEntryDown(this.entry.id).subscribe((result) => { this.voteService.voteEntryDown(this.entry.id).subscribe({
this.change && this.change(); next: () => {
this.change && this.change();
}
}); });
} }
addBookmark() { addBookmark() {
this.bookmarksService.addEntry(this.entry.id).subscribe((result) => { this.bookmarksService.addEntry(this.entry.id).subscribe({
this.entry.metadata.bookmark = false; next: () => {
this.entry.metadata.removeBookmark = true; this.entry.metadata.bookmark = false;
this.entry.metadata.removeBookmark = true;
}
}); });
} }
removeBookmark() { removeBookmark() {
this.bookmarksService.removeEntry(this.entry.id).subscribe((result) => { this.bookmarksService.removeEntry(this.entry.id).subscribe({
this.entry.metadata.bookmark = true; next: () => {
this.entry.metadata.removeBookmark = false; this.entry.metadata.bookmark = true;
this.entry.metadata.removeBookmark = false;
}
}); });
} }
unvote() { unvote() {
this.voteService.unvoteEntry(this.entry.id).subscribe((result) => { this.voteService.unvoteEntry(this.entry.id).subscribe({
this.change && this.change(); next: () => {
this.change && this.change();
}
}); });
} }
@ -97,16 +109,20 @@ export class UiEntry implements OnInit {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'entry.confirmFlag', 'label': 'entry.confirmFlag',
'args': [ this.entry.title, this.entry.author ] 'args': [this.entry.title, this.entry.author]
} }
}) })
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe({
if (result) { next: (result) => {
this.flagService.flagEntry(this.entry.id).subscribe((result) => { if (result) {
this.entry.metadata.flag = false; this.flagService.flagEntry(this.entry.id).subscribe({
this.entry.metadata.unflag = true; next: () => {
}); this.entry.metadata.flag = false;
this.entry.metadata.unflag = true;
}
});
}
} }
}); });
} }
@ -115,16 +131,20 @@ export class UiEntry implements OnInit {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'entry.confirmUnflag', 'label': 'entry.confirmUnflag',
'args': [ this.entry.title, this.entry.author ] 'args': [this.entry.title, this.entry.author]
} }
}) })
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe({
if (result) { next: (result) => {
this.flagService.unflagEntry(this.entry.id).subscribe((result) => { if (result) {
this.entry.metadata.unflag = false; this.flagService.unflagEntry(this.entry.id).subscribe({
this.entry.metadata.flag = true; next: () => {
}); this.entry.metadata.unflag = false;
this.entry.metadata.flag = true;
}
});
}
} }
}); });
} }
@ -133,16 +153,20 @@ export class UiEntry implements OnInit {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'entry.confirmDelete', 'label': 'entry.confirmDelete',
'args': [ this.entry.title, this.entry.author ] 'args': [this.entry.title, this.entry.author]
} }
}) })
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe({
if (result) { next: (result) => {
this.entriesService.delete(this.entry.id).subscribe((result: any) => { if (result) {
this.entry = null; this.entriesService.delete(this.entry.id).subscribe({
this.change && this.change(); next: () => {
}) this.entry = null;
this.change && this.change();
}
})
}
} }
}); });
} }
@ -151,16 +175,20 @@ export class UiEntry implements OnInit {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'moderation.entry.confirmDelete', 'label': 'moderation.entry.confirmDelete',
'args': [ this.entry.title, this.entry.author ] 'args': [this.entry.title, this.entry.author]
} }
}) })
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe({
if (result) { next: (result) => {
this.moderationService.deleteEntry(this.entry.id).subscribe((result: any) => { if (result) {
this.entry = null; this.moderationService.deleteEntry(this.entry.id).subscribe({
this.change && this.change(); next: () => {
}) this.entry = null;
this.change && this.change();
}
})
}
} }
}); });
} }
@ -169,15 +197,19 @@ export class UiEntry implements OnInit {
const dialogRef = this.dialog.open(ConfirmDialog, { const dialogRef = this.dialog.open(ConfirmDialog, {
data: { data: {
'label': 'moderation.entry.confirmUnflag', 'label': 'moderation.entry.confirmUnflag',
'args': [ this.entry.title, this.entry.author ] 'args': [this.entry.title, this.entry.author]
} }
}) })
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe({
if (result) { next: (result) => {
this.moderationService.unflagEntry(this.entry.id).subscribe((result: any) => { if (result) {
this.change && this.change(); this.moderationService.unflagEntry(this.entry.id).subscribe({
}) next: () => {
this.change && this.change();
}
})
}
} }
}); });
} }

View File

@ -48,11 +48,13 @@ export class UiMain {
private _adapter: DateAdapter<any>, private swUpdate: SwUpdate) { private _adapter: DateAdapter<any>, private swUpdate: SwUpdate) {
iconRegistry.addSvgIcon('logo', sanitizer.bypassSecurityTrustResourceUrl('assets/icons/logo.svg')); iconRegistry.addSvgIcon('logo', sanitizer.bypassSecurityTrustResourceUrl('assets/icons/logo.svg'));
this.swUpdate.versionUpdates.subscribe(evt => { this.swUpdate.versionUpdates.subscribe({
if (evt.type == 'VERSION_READY') { next: (evt) => {
this.hasUpdate = true; if (evt.type == 'VERSION_READY') {
} else if (evt.type == 'VERSION_INSTALLATION_FAILED') { this.hasUpdate = true;
console.error(`Failed to install version '${evt.version.hash}': ${evt.error}`); } else if (evt.type == 'VERSION_INSTALLATION_FAILED') {
console.error(`Failed to install version '${evt.version.hash}': ${evt.error}`);
}
} }
}) })
@ -68,15 +70,18 @@ export class UiMain {
this.datetimeformat = this.i18n.get('format.datetime', []); this.datetimeformat = this.i18n.get('format.datetime', []);
this.currentLocale = this.i18n.getLocale(); this.currentLocale = this.i18n.getLocale();
this.locales = this.i18n.getLocales(); this.locales = this.i18n.getLocales();
this.authService.auth.subscribe(auth => { this.authService.auth.subscribe({
this.authenticated = true; next: (auth) => {
for (let role of auth.authorities) { this.authenticated = true;
if (role.authority == 'ROLE_ADMIN' || role.authority == 'ROLE_MOD') { for (let role of auth.authorities) {
this.moderator = true; if (role.authority == 'ROLE_ADMIN' || role.authority == 'ROLE_MOD') {
this.moderator = true;
}
} }
},
error: (error) => {
this.authenticated = false;
} }
}, (error) => {
this.authenticated = false;
}) })
this._adapter.setLocale(this.currentLocale); this._adapter.setLocale(this.currentLocale);
@ -102,11 +107,15 @@ export class UiMain {
localStorage.setItem("bstlboard.locale", locale); localStorage.setItem("bstlboard.locale", locale);
if (this.authenticated) { if (this.authenticated) {
this.userService.get().subscribe((user: any) => { this.userService.get().subscribe({
user.locale = locale; next: (user: any) => {
this.userService.update(user).subscribe(() => { user.locale = locale;
window.location.reload(); this.userService.update(user).subscribe({
}) next: () => {
window.location.reload();
}
})
}
}); });
} else { } else {
window.location.reload(); window.location.reload();
@ -140,11 +149,15 @@ export class UiMain {
localStorage.setItem("bstlboard.darkTheme", this.darkTheme ? "true" : "false"); localStorage.setItem("bstlboard.darkTheme", this.darkTheme ? "true" : "false");
if (this.authenticated) { if (this.authenticated) {
this.userService.get().subscribe((user: any) => { this.userService.get().subscribe({
user.darkTheme = this.darkTheme; next: (user: any) => {
this.userService.update(user).subscribe(() => { user.darkTheme = this.darkTheme;
window.location.reload(); this.userService.update(user).subscribe({
}) next: () => {
window.location.reload();
}
})
}
}); });
} else { } else {
window.location.reload(); window.location.reload();
@ -154,10 +167,12 @@ export class UiMain {
logout() { logout() {
localStorage.removeItem("bstlboard.autologin"); localStorage.removeItem("bstlboard.autologin");
this.authService.logout().subscribe(data => { this.authService.logout().subscribe({
this.router.navigate([""]).then(() => { next: () => {
window.location.reload(); this.router.navigate([""]).then(() => {
}); window.location.reload();
});
}
}) })
} }
@ -185,27 +200,33 @@ export class UiMain {
} }
touchEvents(): void { touchEvents(): void {
fromEvent(document, 'touchstart').subscribe((event: TouchEvent) => { fromEvent(document, 'touchstart').subscribe({
if (event.touches[0]) { next: (event: TouchEvent) => {
this.touchStartX = event.touches[0].screenX; if (event.touches[0]) {
this.touchStartX = event.touches[0].screenX;
}
} }
}) })
fromEvent(document, 'touchmove').subscribe((event: TouchEvent) => { fromEvent(document, 'touchmove').subscribe({
if (event.touches[0]) { next: (event: TouchEvent) => {
this.touchX = event.touches[0].screenX; if (event.touches[0]) {
this.touchX = event.touches[0].screenX;
}
} }
}) })
fromEvent(document, 'touchend').subscribe((event: TouchEvent) => { fromEvent(document, 'touchend').subscribe({
if (this.touchX != 0) { next: () => {
const touchDiff = this.touchStartX - this.touchX; if (this.touchX != 0) {
this.touchStartX = 0; const touchDiff = this.touchStartX - this.touchX;
this.touchX = 0; this.touchStartX = 0;
if (touchDiff < 0 && touchDiff < (this.touchThresh * -1) && !this.opened) { this.touchX = 0;
this.opened = true; if (touchDiff < 0 && touchDiff < (this.touchThresh * -1) && !this.opened) {
} else if (touchDiff > 0 && touchDiff > this.touchThresh && this.opened) { this.opened = true;
this.opened = false; } else if (touchDiff > 0 && touchDiff > this.touchThresh && this.opened) {
this.opened = false;
}
} }
} }
}) })

View File

@ -4,7 +4,7 @@ import { VoteService } from '../../services/vote.service';
@Component({ @Component({
selector: 'ui-points', selector: 'ui-points',
templateUrl: './points.ui.html', templateUrl: './points.ui.html',
styleUrls: [ './points.ui.scss' ] styleUrls: ['./points.ui.scss']
}) })
export class UiPoints implements OnInit { export class UiPoints implements OnInit {
@ -16,12 +16,16 @@ export class UiPoints implements OnInit {
ngOnInit(): void { ngOnInit(): void {
if (this.type == 'e') { if (this.type == 'e') {
this.voteService.getEntryPoints(this.target).subscribe((data) => { this.voteService.getEntryPoints(this.target).subscribe({
this.count = +data; next: (data) => {
this.count = +data;
}
}); });
} else if (this.type == 'c') { } else if (this.type == 'c') {
this.voteService.getCommentPoints(this.target).subscribe((data) => { this.voteService.getCommentPoints(this.target).subscribe({
this.count = +data; next: (data) => {
this.count = +data;
}
}); });
} }
} }

View File

@ -20,12 +20,16 @@ export class UiViewMenu implements OnInit {
} }
ngOnInit(): void { ngOnInit(): void {
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => { this.settingsSubscription = this.settingsService.settings.subscribe({
this.settings = settings; next: (settings) => {
this.viewService.views.subscribe((data: any) => { this.settings = settings;
this.views = data.content; this.viewService.views.subscribe({
}) next: (data: any) => {
this.viewService.getViews(); this.views = data.content;
}
})
this.viewService.getViews();
}
}) })
} }

View File

@ -1,15 +1,18 @@
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Pipe({ name: 'urltext' }) @Pipe({ name: 'urltext' })
export class UrlTextPipe implements PipeTransform { export class UrlTextPipe implements PipeTransform {
httpPattern = /(\b(https?:\/\/)([-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]))/ig; httpPattern = /(\b(https?:\/\/)([-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]))/ig;
wwwPattern =/(^|[^\/>])(www\.[\S]+(\b|$))/gim; wwwPattern = /(^|[^\/>])(www\.[\S]+(\b|$))/gim;
transform(value: string): any { constructor(private santisizer: DomSanitizer) { }
transform(value: string): SafeHtml {
value = value.replace(this.httpPattern, '<a href="$1" target="_blank">$3</a>'); value = value.replace(this.httpPattern, '<a href="$1" target="_blank">$3</a>');
value = value.replace(this.wwwPattern, '$1<a target="_blank" href="https://$2">$2</a>'); value = value.replace(this.wwwPattern, '$1<a target="_blank" href="https://$2">$2</a>');
return value; return this.santisizer.bypassSecurityTrustHtml(value);
} }
} }
@ -23,7 +26,7 @@ export class UrlBasePipe implements PipeTransform {
return ''; return '';
} }
const parts = value.split( '/' ) const parts = value.split('/')
if (parts.length < 3) { if (parts.length < 3) {
return ''; return '';