userpages + filter improvments

This commit is contained in:
2021-12-02 19:31:38 +01:00
parent c1ea8948fc
commit fb6631576e
28 changed files with 666 additions and 293 deletions
+2 -1
View File
@@ -1 +1,2 @@
<ui-entries [entries]="entries" [refresh]="boundRefresh" [update]="boundUpdate" [gravityFilter]="gravityFilter"></ui-entries>
<ui-entries [entries]="entries" [refresh]="boundRefresh" [update]="boundUpdate" [filter]="filter"
[gravityFilter]="gravityFilter"></ui-entries>
+15 -5
View File
@@ -1,17 +1,18 @@
import { Component, OnInit, Input } from '@angular/core';
import { Component, OnInit, Input, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { PageEvent } from '@angular/material/paginator';
import { SettingsService } from '../../services/settings.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'page-entries',
templateUrl: './entries.page.html'
})
export class PageEntries implements OnInit {
export class PageEntries implements OnInit, OnDestroy {
settings: any;
@Input() fetch: Function;
@Input() filter: boolean = true;
@Input() gravityFilter: boolean = false;
entries: any;
asc: boolean = false;
@@ -20,6 +21,9 @@ export class PageEntries implements OnInit {
init: boolean = true;
filterOpen: boolean = false;
settings: any;
settingsSubscription: Subscription;
constructor(
private settingsService: SettingsService, private router: Router, private route: ActivatedRoute) { }
@@ -50,7 +54,7 @@ export class PageEntries implements OnInit {
}
}
this.settingsService.settings.subscribe((settings) => {
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => {
this.settings = settings;
this.refresh();
this.init = false;
@@ -59,6 +63,10 @@ export class PageEntries implements OnInit {
});
}
ngOnDestroy(): void {
this.settingsSubscription.unsubscribe();
}
refresh(): void {
if (!this.entries) {
this.entries = {};
@@ -69,7 +77,9 @@ export class PageEntries implements OnInit {
this.fetch(this.entries.number || 0, this.entries.size || this.settings.pageSize, this.asc, this.entries.filter).subscribe((data: any) => {
this.entries = data;
this.entries.filter = filter;
}, (error) => { })
}, (error) => {
this.entries = { error: error };
})
}
+14 -4
View File
@@ -1,11 +1,18 @@
<div class="container">
<mat-progress-bar *ngIf="!entry" mode="indeterminate"></mat-progress-bar>
<form [formGroup]="form" (ngSubmit)="update()" #formDirective="ngForm" *ngIf="entry">
<form [formGroup]="form" (ngSubmit)="entry.id ? update() : create()" #formDirective="ngForm" *ngIf="entry && settings">
<mat-card>
<mat-card-content>
<p>{{'submission.edit' | i18n}}</p>
<p>{{ (entry.id ? 'submission.edit' : 'submission.info') | i18n}}</p>
<mat-form-field>
<input matInput placeholder="{{'submission.entryType' | i18n}}" formControlName="entryType" disabled>
<mat-select placeholder="{{'submission.entryType' | i18n}}" formControlName="entryType">
<mat-select-trigger>
<mat-icon>{{'entryType.' + entryType + '.icon' | i18n}}</mat-icon> {{'entryType.' + entryType | i18n}}
</mat-select-trigger>
<mat-option *ngFor="let entryType of entryTypes" [value]="entryType">
<mat-icon>{{'entryType.' + entryType + '.icon' | i18n}}</mat-icon> {{'entryType.' + entryType | i18n}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
@@ -36,7 +43,10 @@
</mat-card-content>
<mat-card-actions>
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
<button *ngIf="!working && !entry.id" mat-raised-button color="primary" [disabled]="form.invalid">
{{'submission.create' | i18n}}
</button>
<button *ngIf="!working && entry.id" mat-raised-button color="primary" [disabled]="form.invalid">
{{'submission.update' | i18n}}
</button>
<a *ngIf="success" mat-button color="primary" routerLink="/e/{{entry.id}}">{{'submission.success' | i18n}}</a>
+70 -49
View File
@@ -1,20 +1,19 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { EntriesService } from '../../../services/entries.service';
import { ActivatedRoute } from '@angular/router';
import { FormBuilder, FormGroup, Validators, NgForm } from '@angular/forms';
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
import { ActivatedRoute, Router } from '@angular/router';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { distinctUntilChanged, debounceTime } from 'rxjs/operators';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatChipInputEvent } from '@angular/material/chips';
import { TagsService } from 'src/app/services/tags.service';
import { SettingsService } from 'src/app/services/settings.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'page-entry-edit',
templateUrl: './edit.page.html',
styleUrls: [ './edit.page.scss' ]
})
export class PageEntryEdit implements OnInit {
export class PageEntryEdit implements OnInit, OnDestroy {
id: number;
entry: any;
@@ -25,13 +24,14 @@ export class PageEntryEdit implements OnInit {
success: boolean = false;
form: FormGroup;
settings: any;
readonly tagsSeparatorKeysCodes = [ ENTER, COMMA, SPACE ] as const;
@ViewChild('formDirective') private formDirective: NgForm;
settingsSubscription: Subscription;
constructor(private entriesService: EntriesService,
private tagsService: TagsService,
private settingsService: SettingsService,
private formBuilder: FormBuilder,
private router: Router,
private route: ActivatedRoute,
private snackBar: MatSnackBar) { }
@@ -43,11 +43,11 @@ export class PageEntryEdit implements OnInit {
text: [ '', Validators.nullValidator ],
});
this.settingsService.settings.subscribe((settings) => {
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => {
this.settings = settings;
});
this.form.get('entryType').disable();
this.form.get('entryType').setValue(this.entryType);
this.form.get('entryType').valueChanges.subscribe((value) => {
this.entryType = value;
@@ -63,6 +63,7 @@ export class PageEntryEdit implements OnInit {
}
});
this.form.get('url').valueChanges.pipe(
debounceTime(800),
distinctUntilChanged()).subscribe((value) => {
@@ -73,28 +74,38 @@ export class PageEntryEdit implements OnInit {
}
})
this.id = +this.route.snapshot.paramMap.get('id');
this.id = this.route.snapshot.paramMap.get('id') && +this.route.snapshot.paramMap.get('id');
this.refresh();
}
ngOnDestroy(): void {
this.settingsSubscription.unsubscribe();
}
refresh() {
this.entriesService.getEntry(this.id).subscribe((data) => {
this.entry = data;
this.entryType = this.entry.entryType;
this.form.get("entryType").setValue(this.entry.entryType);
this.form.get("url").setValue(this.entry.url);
this.form.get("title").setValue(this.entry.title);
this.form.get("text").setValue(this.entry.text);
if (!this.entry.metadata.edit) {
this.form.get("url").disable();
this.form.get("title").disable();
this.form.get("text").disable();
}
}, (error) => {
if (error.status == 404) {
this.notfound = true;
}
})
if (this.id) {
this.form.get('entryType').disable();
this.entriesService.getEntry(this.id).subscribe((data) => {
this.entry = data;
this.entryType = this.entry.entryType;
this.form.get("entryType").setValue(this.entry.entryType);
this.form.get("url").setValue(this.entry.url);
this.form.get("title").setValue(this.entry.title);
this.form.get("text").setValue(this.entry.text);
if (!this.entry.metadata.edit) {
this.form.get("url").disable();
this.form.get("title").disable();
this.form.get("text").disable();
}
}, (error) => {
if (error.status == 404) {
this.notfound = true;
}
})
} else {
this.entry = {};
this.entry.entryType = this.entryType;
}
}
hasError(controlName: string): boolean {
@@ -105,33 +116,43 @@ export class PageEntryEdit implements OnInit {
}
addTag(event: MatChipInputEvent): void {
let value = (event.value || "").trim();
if (value.startsWith('#')) {
value = value.replace('#', '');
}
value = value.split('#').join('-');
if (value) {
this.entry.tags.push(value);
}
event.chipInput!.clear();
}
removeTag(tag: string): void {
const index = this.entry.tags.indexOf(tag);
if (index >= 0) {
this.entry.tags.splice(index, 1);
}
}
update(): void {
create(): void {
if (this.working) {
return;
}
this.working = true;
this.entry.url = this.form.get("url").value;
this.entry.entryType = this.entryType;
this.entry.title = this.form.get("title").value;
this.entry.text = this.form.get("text").value;
this.entriesService.create(this.entry).subscribe((data) => {
this.router.navigateByUrl('/');
}, (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) {
this.form.get(code).setErrors(errors[ code ]);
}
}
})
}
update(): void {
if (this.working) {
return;
}
this.working = true;
if (this.entry.metadata.edit) {
this.entry.url = this.form.get("url").value;
this.entry.title = this.form.get("title").value;
+19 -5
View File
@@ -19,7 +19,8 @@
<mat-divider></mat-divider>
<p>{{'settings.pagesettings' | i18n}}</p>
<mat-form-field>
<button *ngIf="user.settings.gravity || form.get('gravity').value != settings.defaultGravity" matPrefix
<button matTooltip="{{'settings.gravity.reset' | i18n:settings.defaultGravity}}"
*ngIf="user.settings.gravity || form.get('gravity').value != settings.defaultGravity" matPrefix
mat-icon-button (click)="resetGravity()">
<mat-icon>cancel</mat-icon>
</button>
@@ -33,9 +34,9 @@
</mat-hint>
</mat-form-field>
<mat-form-field>
<button
*ngIf="user.settings.entryDelay || form.get('entryDelay').value != settings.defaultEntryDelay"
matPrefix mat-icon-button (click)="resetEntryDelay()">
<button matTooltip="{{'settings.entryDelay.reset' | i18n:settings.defaultEntryDelay}}"
*ngIf="user.settings.entryDelay || form.get('entryDelay').value != settings.defaultEntryDelay" matPrefix
mat-icon-button (click)="resetEntryDelay()">
<mat-icon>cancel</mat-icon>
</button>
<input type="number" min="0" max="15" step="1" matInput placeholder="{{'settings.entryDelay' | i18n}}"
@@ -48,7 +49,7 @@
</mat-hint>
</mat-form-field>
<mat-form-field>
<button
<button matTooltip="{{'settings.commentDelay.reset' | i18n:settings.defaultCommentDelay}}"
*ngIf="user.settings.commentDelay || form.get('commentDelay').value != settings.defaultCommentDelay"
matPrefix mat-icon-button (click)="resetCommentDelay()">
<mat-icon>cancel</mat-icon>
@@ -62,6 +63,19 @@
{{'settings.commentDelay.zero' | i18n}}
</mat-hint>
</mat-form-field>
<mat-form-field>
<button matTooltip="{{'settings.pageSize.reset' | i18n:settings.defaultPageSize}}"
*ngIf="user.settings.pageSize || form.get('pageSize').value != settings.defaultPageSize" matPrefix
mat-icon-button (click)="resetPageSize()">
<mat-icon>cancel</mat-icon>
</button>
<input type="number" min="1" max="100" step="1" matInput placeholder="{{'settings.pageSize' | i18n}}"
formControlName="pageSize">
<mat-hint *ngIf="form.get('pageSize').value != 0">
{{'settings.pageSize.hint' | i18n}}
</mat-hint>
</mat-form-field>
</mat-card-content>
<mat-card-actions>
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
+22 -4
View File
@@ -1,15 +1,16 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators, NgForm } from '@angular/forms';
import { UserService } from '../../services/user.service';
import { SettingsService } from 'src/app/services/settings.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'page-settings',
templateUrl: './settings.page.html',
styleUrls: [ './settings.page.scss' ]
})
export class PageSettings implements OnInit {
export class PageSettings implements OnInit, OnDestroy {
auth: any;
user: any;
@@ -18,6 +19,7 @@ export class PageSettings implements OnInit {
form: FormGroup;
settings: any;
@ViewChild('formDirective') private formDirective: NgForm;
settingsSubscription: Subscription;
constructor(
private userService: UserService,
@@ -32,6 +34,7 @@ export class PageSettings implements OnInit {
gravity: [ '', Validators.nullValidator ],
entryDelay: [ '', Validators.nullValidator ],
commentDelay: [ '', Validators.nullValidator ],
pageSize: [ '', Validators.nullValidator ],
});
this.form.get('username').disable();
@@ -45,15 +48,18 @@ export class PageSettings implements OnInit {
this.form.get('email').setValue(this.user.email);
this.form.get('about').setValue(this.user.about);
this.settingsService.settings.subscribe((settings) => {
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => {
this.settings = settings;
this.form.get('gravity').setValue(this.user.settings.gravity || this.settings.defaultGravity);
this.form.get('entryDelay').setValue(this.user.settings.entryDelay || this.settings.defaultEntryDelay);
this.form.get('commentDelay').setValue(this.user.settings.commentDelay || this.settings.defaultCommentDelay);
this.form.get('pageSize').setValue(this.user.settings.pageSize || this.settings.defaultPageSize);
});
})
}
ngOnDestroy(): void {
this.settingsSubscription.unsubscribe();
}
hasError(controlName: string): boolean {
@@ -75,6 +81,11 @@ export class PageSettings implements OnInit {
this.form.get('commentDelay').setValue(this.settings.defaultCommentDelay);
}
resetPageSize(): void {
this.user.settings.pageSize = null;
this.form.get('pageSize').setValue(this.settings.defaultPageSize);
}
save(): void {
if (this.working) {
return;
@@ -108,6 +119,12 @@ export class PageSettings implements OnInit {
this.user.settings.commentDelay = this.form.get('commentDelay').value;
}
if (this.form.get('pageSize').value != this.settings.defaultPageSize && !this.user.settings.pageSize) {
this.user.settings.pageSize = this.form.get('pageSize').value;
} else if (this.user.settings.pageSize) {
this.user.settings.pageSize = this.form.get('pageSize').value;
}
this.userService.update(this.user).subscribe((data) => {
this.user = data;
if (!this.user.settings) {
@@ -115,6 +132,7 @@ export class PageSettings implements OnInit {
}
this.working = false;
this.success = true;
this.settingsService.getSettings();
}, (error) => {
this.working = false;
if (error.status == 422) {
@@ -1,52 +0,0 @@
<div class="container">
<form [formGroup]="form" (ngSubmit)="create()" #formDirective="ngForm">
<mat-card>
<mat-card-content>
<p>{{'submission.info' | i18n}}</p>
<mat-form-field>
<mat-select placeholder="{{'submission.entryType' | i18n}}" formControlName="entryType">
<mat-select-trigger>
<mat-icon>{{'entryType.' + entryType + '.icon' | i18n}}</mat-icon> {{'entryType.' + entryType | i18n}}
</mat-select-trigger>
<mat-option *ngFor="let entryType of entryTypes" [value]="entryType">
<mat-icon>{{'entryType.' + entryType + '.icon' | i18n}}</mat-icon> {{'entryType.' + entryType | i18n}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<input matInput placeholder="{{'submission.url' | i18n}}" formControlName="url" type="url"
[required]="entryType == 'LINK'" matAutofocus>
<mat-error *ngIf="hasError('url')">
{{'submission.url.error' | i18n}}
</mat-error>
</mat-form-field>
<mat-form-field>
<input matInput placeholder="{{'submission.title' | i18n}}" formControlName="title" type="text" required
(focus)="onTitleFocus($event)">
<mat-error>
{{'submission.title.error' | i18n}}
</mat-error>
</mat-form-field>
<mat-form-field>
<textarea [mat-autosize] [matAutosizeMinRows]="3" matInput placeholder="{{'submission.text' | i18n}}"
[required]="entryType != 'LINK'" formControlName="text"></textarea>
<mat-error>
{{'submission.text.error' | i18n}}
</mat-error>
</mat-form-field>
<ui-tagspicker [(model)]="tags" placeholder="{{'submission.tags' | i18n}}" [max]="settings.maxTags">
</ui-tagspicker>
</mat-card-content>
<mat-card-actions>
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
{{'submission.create' | i18n}}
</button>
</mat-card-actions>
</mat-card>
</form>
</div>
-131
View File
@@ -1,131 +0,0 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { EntriesService } from '../../services/entries.service';
import { Router } from '@angular/router';
import { FormBuilder, FormGroup, Validators, NgForm } from '@angular/forms';
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
import { distinctUntilChanged, debounceTime } from 'rxjs/operators';
import { MatChipInputEvent } from '@angular/material/chips';
import { SettingsService } from 'src/app/services/settings.service';
@Component({
selector: 'page-submission',
templateUrl: './submission.page.html',
styleUrls: [ './submission.page.scss' ]
})
export class PageSubmission implements OnInit {
entryTypes: string[] = [ 'LINK', 'DISCUSSION', 'QUESTION', 'INTERN' ];
entryType: string = this.entryTypes[ 0 ];
working: boolean = false;
form: FormGroup;
readonly tagsSeparatorKeysCodes = [ ENTER, COMMA, SPACE ] as const;
tags: string[] = [];
settings: any;
@ViewChild('formDirective') private formDirective: NgForm;
constructor(private entriesService: EntriesService,
private settingsService: SettingsService,
private router: Router,
private formBuilder: FormBuilder) { }
ngOnInit(): void {
this.form = this.formBuilder.group({
entryType: [ '', Validators.required ],
url: [ '', Validators.required ],
title: [ '', Validators.required ],
text: [ '', Validators.nullValidator ],
});
this.settingsService.settings.subscribe((settings) => {
this.settings = settings;
});
this.form.get('entryType').setValue(this.entryType);
this.form.get('entryType').valueChanges.subscribe((value) => {
this.entryType = value;
switch (value) {
case 'LINK':
this.form.get('url').setValidators([ Validators.required ]);
this.form.get('text').setValidators([ Validators.nullValidator ]);
break;
default:
this.form.get('url').setValidators([ Validators.nullValidator ]);
this.form.get('text').setValidators([ Validators.required ]);
break;
}
});
this.form.get('url').valueChanges.pipe(
debounceTime(800),
distinctUntilChanged()).subscribe((value) => {
if (value && !this.form.get('title').value) {
this.entriesService.titleHelper(value).subscribe((title: string) => {
this.form.get('title').setValue(title);
})
}
})
}
hasError(controlName: string): boolean {
return this.form.controls[ controlName ].errors != null;
}
onTitleFocus(event): void {
}
addTag(event: MatChipInputEvent): void {
let value = (event.value || "").trim();
if (value.startsWith('#')) {
value = value.replace('#', '');
}
value = value.split('#').join('-');
if (value) {
this.tags.push(value);
}
event.chipInput!.clear();
}
removeTag(tag: string): void {
const index = this.tags.indexOf(tag);
if (index >= 0) {
this.tags.splice(index, 1);
}
}
create(): void {
if (this.working) {
return;
}
this.working = true;
const entry: any = {};
entry.url = this.form.get("url").value;
entry.entryType = this.entryType;
entry.title = this.form.get("title").value;
entry.text = this.form.get("text").value;
entry.tags = this.tags;
this.entriesService.create(entry).subscribe((data) => {
this.router.navigateByUrl('/');
}, (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) {
this.form.get(code).setErrors(errors[ code ]);
}
}
})
}
}
@@ -1,6 +1,7 @@
import { Component, OnInit, Input } from '@angular/core';
import { Component, OnInit, Input, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { CommentService } from '../../../services/comment.service';
import { SettingsService } from '../../../services/settings.service';
@@ -10,19 +11,20 @@ import { SettingsService } from '../../../services/settings.service';
templateUrl: './usercomments.page.html',
styleUrls: [ './usercomments.page.scss' ]
})
export class PageUserComments implements OnInit {
export class PageUserComments implements OnInit, OnDestroy {
settings: any;
username: string;
comments: any = {};
init: boolean = true;
ignore: string[] = [ "author" ];
settingsSubscription: Subscription;
constructor(private settingsService: SettingsService, private commentService: CommentService, private router: Router, private route: ActivatedRoute) { }
ngOnInit(): void {
this.username = this.route.snapshot.paramMap.get('username');
this.settingsService.settings.subscribe((settings) => {
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => {
this.settings = settings;
this.commentService.getByUser(this.username, this.comments.number || 0, this.comments.size || this.settings.pageSize, this.ignore).subscribe((data: any) => {
this.comments = data;
@@ -30,6 +32,10 @@ export class PageUserComments implements OnInit {
})
}
ngOnDestroy(): void {
this.settingsSubscription.unsubscribe();
}
showMore() {
const oldContent: any[] = this.comments.content;
this.commentService.getByUser(this.username, this.comments.number + 1, this.comments.size, this.ignore).subscribe((data) => {
@@ -0,0 +1,67 @@
<div class="container">
<mat-progress-bar *ngIf="!userpage" mode="indeterminate"></mat-progress-bar>
<form [formGroup]="form" (ngSubmit)="save()" #formDirective="ngForm" *ngIf="userpage && settings">
<mat-card>
<mat-card-content>
<p>{{ (userpage.id ? 'userpages.edit' : 'userpages.create') | i18n}}</p>
<mat-form-field>
<input matInput placeholder="{{'userpages.name' | i18n}}" formControlName="name" matAutofocus>
<mat-error *ngIf="hasError('name')">
<div *ngFor="let error of form.get('name').errors | keyvalue">
{{'userpages.name.error.' + error.key | i18n}}<br>
</div>
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-select placeholder="{{'userpages.sorting' | i18n}}" formControlName="sorting">
<mat-select-trigger>
<mat-icon>{{'sorting.' + sorting + '.icon' | i18n}}</mat-icon> {{'sorting.' + sorting | i18n}}
</mat-select-trigger>
<mat-option *ngFor="let sorting of sortings" [value]="sorting">
<mat-icon>{{'sorting.' + sorting + '.icon' | i18n}}</mat-icon> {{'sorting.' + sorting | i18n}}
</mat-option>
</mat-select>
</mat-form-field>
<ui-tagspicker [(model)]="userpage.tags" placeholder="{{'userpages.tags' | i18n}}">
</ui-tagspicker>
<ui-tagspicker [(model)]="userpage.excludedTags" placeholder="{{'userpages.excludedTags' | i18n}}">
</ui-tagspicker>
<mat-form-field>
<mat-select placeholder="{{'userpages.entryType' | i18n}}" formControlName="entryType">
<mat-select-trigger>
<span *ngIf="entryType">
<mat-icon>{{'entryType.' + entryType + '.icon' | i18n}}</mat-icon> {{'entryType.' +
entryType | i18n}}
</span>
</mat-select-trigger>
<mat-option *ngFor="let entryType of entryTypes" [value]="entryType">
<span *ngIf="entryType">
<mat-icon>{{'entryType.' + entryType + '.icon' | i18n}}</mat-icon> {{'entryType.' + entryType | i18n}}
</span>
<span *ngIf="!entryType">
{{'entryType.empty' | i18n}}
</span>
</mat-option>
</mat-select>
</mat-form-field>
</mat-card-content>
<mat-card-actions fxLayout="row wrap" fxFlexFill>
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
<mat-icon>save</mat-icon> {{ (userpage.id ? 'userpages.update' : 'userpages.create') | i18n}}
</button>
<a mat-button color="primary" routerLink="/p/{{userpage.name}}" *ngIf="userpage.id">{{ 'userpages.goTo' |
i18n}}</a>
<span fxFlexOffset="auto" fxFlexOffset.xs="none"></span>
<a mat-raised-button color="warn" *ngIf="!working && userpage.id" (click)="deleteUserPage()"><mat-icon>delete</mat-icon> {{
'userpages.delete' |
i18n}}</a>
</mat-card-actions>
</mat-card>
</form>
</div>
@@ -2,9 +2,9 @@ mat-form-field {
display: block;
}
ui-tagspicker {
display: block;
width: 100%;
mat-chip mat-icon.mat-icon-inline {
margin-top: -12px;
margin-right: -2px;
}
form {
@@ -23,3 +23,7 @@ form {
max-width: 50%;
}
}
mat-card-actions > * {
margin-bottom: 10px;
}
+156
View File
@@ -0,0 +1,156 @@
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { FormBuilder, FormGroup, Validators, NgForm } from '@angular/forms';
import { MatSnackBar } from '@angular/material/snack-bar';
import { TagsService } from 'src/app/services/tags.service';
import { SettingsService } from 'src/app/services/settings.service';
import { Subscription } from 'rxjs';
import { UserPageService } from 'src/app/services/userpage.service';
import { I18nService } from 'src/app/services/i18n.service';
import { ConfirmDialog } from 'src/app/ui/confirm/confirm.component';
import { MatDialog } from '@angular/material/dialog';
@Component({
selector: 'page-userpage-edit',
templateUrl: './edit.page.html',
styleUrls: [ './edit.page.scss' ]
})
export class PageUserPageEdit implements OnInit, OnDestroy {
name: string;
userpage: any;
entryTypes: string[] = [ undefined, 'LINK', 'DISCUSSION', 'QUESTION', 'INTERN' ];
entryType: string = this.entryTypes[ 0 ];
sortings: string[] = [ 'NEW', 'TOP', 'HOT', 'LAST' ];
sorting: string = this.sortings[ 0 ];
notfound: boolean = false;
working: boolean = false;
form: FormGroup;
settings: any;
settingsSubscription: Subscription;
constructor(private userPageService: UserPageService,
private tagsService: TagsService,
private settingsService: SettingsService,
private formBuilder: FormBuilder,
private router: Router,
private i18n: I18nService,
private route: ActivatedRoute,
private snackBar: MatSnackBar,
public dialog: MatDialog) { }
ngOnInit(): void {
this.form = this.formBuilder.group({
name: [ '', Validators.required ],
entryType: [ '', Validators.nullValidator ],
sorting: [ '', Validators.required ],
});
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => {
this.settings = settings;
});
this.form.get('entryType').setValue(this.entryType);
this.form.get('entryType').valueChanges.subscribe((value) => {
this.entryType = value;
});
this.form.get('sorting').setValue(this.sorting);
this.form.get('sorting').valueChanges.subscribe((value) => {
this.sorting = value;
});
this.name = this.route.snapshot.paramMap.get('name');
this.refresh();
}
ngOnDestroy(): void {
this.settingsSubscription.unsubscribe();
}
refresh() {
if (this.name) {
this.userPageService.getUserPage(this.name).subscribe((data) => {
this.userpage = data;
this.entryType = this.userpage.entryType;
this.sorting = this.userpage.sorting;
this.form.get("name").setValue(this.userpage.name);
this.form.get("entryType").setValue(this.userpage.entryType);
this.form.get("sorting").setValue(this.userpage.sorting);
}, (error) => {
if (error.status == 404) {
this.notfound = true;
}
})
} else {
this.userpage = {};
this.userpage.entryType = this.entryType;
this.userpage.sorting = this.sorting;
this.userpage.tags = [];
this.userpage.excludedTags = [];
}
}
hasError(controlName: string): boolean {
return this.form.controls[ controlName ].errors != null;
}
save(): void {
if (this.working) {
return;
}
this.working = true;
this.userpage.name = this.form.get("name").value;
this.userpage.entryType = this.entryType;
this.userpage.sorting = this.sorting;
this.userPageService.createOrUpdate(this.userpage).subscribe((data) => {
this.userpage = data;
this.working = false;
this.snackBar.open(this.i18n.get('userpages.success', []), this.i18n.get("close", []), {
duration: 3000
});
this.router.navigateByUrl('/p/' + this.userpage.name);
this.userPageService.getUserPages();
}, (error) => {
this.working = false;
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;
}
for (let code in errors) {
this.form.get(code).setErrors(errors[ code ]);
}
}
})
}
deleteUserPage() {
const dialogRef = this.dialog.open(ConfirmDialog, {
data: {
'label': 'userpages.confirmDelete',
'args': [ this.userpage.name ]
}
})
dialogRef.afterClosed().subscribe(result => {
if (result) {
this.working = true;
this.userPageService.deleteUserPage(this.userpage.name).subscribe(() => {
this.working = false;
this.router.navigateByUrl('/');
this.userPageService.getUserPages();
})
}
});
}
}
@@ -0,0 +1,8 @@
<div fxLayout="column" fxFlexFill>
<div class="container">
<span>{{name}} <small *ngIf="!username"><a routerLink="/p/{{name}}/edit" matTooltip="{{'userpages.edit' | i18n}}">
<mat-icon inline="true">edit</mat-icon>
</a></small></span>
</div>
<page-entries #entries [fetch]="boundFetch" [filter]="false" fxFlex="grow"></page-entries>
</div>
+46
View File
@@ -0,0 +1,46 @@
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { EntriesService } from '../../services/entries.service';
import { PageEntries } from '../entries/entries.page';
@Component({
selector: 'page-userpage',
templateUrl: './userpage.page.html'
})
export class PageUserPage implements OnInit, OnDestroy {
boundFetch: Function;
name: string;
username: string;
paramsSub: Subscription;
@ViewChild('entries') entries: PageEntries;
constructor(
private entriesService: EntriesService,
private router: Router,
private route: ActivatedRoute) {
}
ngOnInit(): void {
this.paramsSub = this.route.params.subscribe((params: Params) => {
this.name = params[ 'name' ];
this.username = params[ 'username' ];
if (this.entries) {
this.entries.refresh();
}
});
this.boundFetch = this.fetch.bind(this);
}
ngOnDestroy(): void {
this.paramsSub.unsubscribe();
}
fetch(page: number, size: number, asc: boolean, filter: any) {
return this.entriesService.getByUserPage(this.name, page, size, asc, this.username);
}
}