userpages + filter improvments
This commit is contained in:
parent
c1ea8948fc
commit
fb6631576e
@ -14,12 +14,14 @@ import { PageModerationEntries } from './pages/moderation/entries/moderation.ent
|
|||||||
import { PageNew } from './pages/new/new.page';
|
import { PageNew } from './pages/new/new.page';
|
||||||
import { PageNotFound } from './pages/notfound/notfound.page';
|
import { PageNotFound } from './pages/notfound/notfound.page';
|
||||||
import { PageSettings } from './pages/settings/settings.page';
|
import { PageSettings } from './pages/settings/settings.page';
|
||||||
import { PageSubmission } from './pages/submission/submission.page';
|
|
||||||
import { PageTop } from './pages/top/top.page';
|
import { PageTop } from './pages/top/top.page';
|
||||||
import { PageUnavailable } from './pages/unavailable/unavailable.page';
|
import { PageUnavailable } from './pages/unavailable/unavailable.page';
|
||||||
import { PageUser } from './pages/user/user.page';
|
import { PageUser } from './pages/user/user.page';
|
||||||
|
|
||||||
import { PageUserComments } from './pages/user/usercomments/usercomments.page';
|
import { PageUserComments } from './pages/user/usercomments/usercomments.page';
|
||||||
import { PageUserEntries } from './pages/user/userentries/userentries.page';
|
import { PageUserEntries } from './pages/user/userentries/userentries.page';
|
||||||
|
import { PageUserPageEdit } from './pages/userpage/edit/edit.page';
|
||||||
|
import { PageUserPage } from './pages/userpage/userpage.page';
|
||||||
import { UiMain } from './ui/main/main.ui';
|
import { UiMain } from './ui/main/main.ui';
|
||||||
|
|
||||||
|
|
||||||
@ -31,12 +33,16 @@ const routes: Routes = [
|
|||||||
{ path: 'top', component: PageTop, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'top', component: PageTop, canActivate: [ AuthenticatedGuard ] },
|
||||||
{ path: 'hot', component: PageHot, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'hot', component: PageHot, canActivate: [ AuthenticatedGuard ] },
|
||||||
{ path: 'last', component: PageLast, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'last', component: PageLast, canActivate: [ AuthenticatedGuard ] },
|
||||||
|
{ path: 'p', component: PageUserPageEdit, canActivate: [ AuthenticatedGuard ] },
|
||||||
|
{ path: 'p/:name', component: PageUserPage, canActivate: [ AuthenticatedGuard ] },
|
||||||
|
{ path: 'p/:name/edit', component: PageUserPageEdit, canActivate: [ AuthenticatedGuard ] },
|
||||||
|
{ path: 'p/:name/:username', component: PageUserPage, canActivate: [ AuthenticatedGuard ] },
|
||||||
{ path: 'moderation/comments', component: PageModerationComments, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'moderation/comments', component: PageModerationComments, canActivate: [ AuthenticatedGuard ] },
|
||||||
{ path: 'moderation/entries', component: PageModerationEntries, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'moderation/entries', component: PageModerationEntries, canActivate: [ AuthenticatedGuard ] },
|
||||||
{ path: 'new', component: PageNew, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'new', component: PageNew, canActivate: [ AuthenticatedGuard ] },
|
||||||
{ path: 'bookmarks', component: PageBookmarks, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'bookmarks', component: PageBookmarks, canActivate: [ AuthenticatedGuard ] },
|
||||||
{ path: 'settings', component: PageSettings, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'settings', component: PageSettings, canActivate: [ AuthenticatedGuard ] },
|
||||||
{ path: 'submit', component: PageSubmission, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'submit', component: PageEntryEdit, canActivate: [ AuthenticatedGuard ] },
|
||||||
{ path: 'e/:id', component: PageEntry, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'e/:id', component: PageEntry, canActivate: [ AuthenticatedGuard ] },
|
||||||
{ path: 'e/:id/edit', component: PageEntryEdit, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'e/:id/edit', component: PageEntryEdit, canActivate: [ AuthenticatedGuard ] },
|
||||||
{ path: 'c/:id', component: PageComment, canActivate: [ AuthenticatedGuard ] },
|
{ path: 'c/:id', component: PageComment, canActivate: [ AuthenticatedGuard ] },
|
||||||
|
@ -30,7 +30,6 @@ import { PageModerationEntries } from './pages/moderation/entries/moderation.ent
|
|||||||
import { PageNew } from './pages/new/new.page';
|
import { PageNew } from './pages/new/new.page';
|
||||||
import { PageNotFound } from './pages/notfound/notfound.page'
|
import { PageNotFound } from './pages/notfound/notfound.page'
|
||||||
import { PageSettings } from './pages/settings/settings.page';
|
import { PageSettings } from './pages/settings/settings.page';
|
||||||
import { PageSubmission } from './pages/submission/submission.page';
|
|
||||||
import { PageTop } from './pages/top/top.page';
|
import { PageTop } from './pages/top/top.page';
|
||||||
import { PageUnavailable } from './pages/unavailable/unavailable.page'
|
import { PageUnavailable } from './pages/unavailable/unavailable.page'
|
||||||
import { PageUser } from './pages/user/user.page';
|
import { PageUser } from './pages/user/user.page';
|
||||||
@ -50,6 +49,9 @@ import { I18nService, I18nPaginatorIntl } from './services/i18n.service';
|
|||||||
import { ServiceWorkerModule } from '@angular/service-worker';
|
import { ServiceWorkerModule } from '@angular/service-worker';
|
||||||
import { environment } from '../environments/environment';
|
import { environment } from '../environments/environment';
|
||||||
import { UiTagsPicker } from './ui/tags/tagspicker.ui';
|
import { UiTagsPicker } from './ui/tags/tagspicker.ui';
|
||||||
|
import { UiUserPageMenu } from './ui/userpagemenu/userpagemenu.ui';
|
||||||
|
import { PageUserPage } from './pages/userpage/userpage.page';
|
||||||
|
import { PageUserPageEdit } from './pages/userpage/edit/edit.page';
|
||||||
|
|
||||||
|
|
||||||
export function fetchI18n(i18n: I18nService) {
|
export function fetchI18n(i18n: I18nService) {
|
||||||
@ -100,10 +102,11 @@ export class XhrInterceptor implements HttpInterceptor {
|
|||||||
PageNew,
|
PageNew,
|
||||||
PageNotFound,
|
PageNotFound,
|
||||||
PageSettings,
|
PageSettings,
|
||||||
PageSubmission,
|
|
||||||
PageTop,
|
PageTop,
|
||||||
PageUnavailable,
|
PageUnavailable,
|
||||||
PageUser, PageUserComments, PageUserEntries,
|
PageUser, PageUserComments, PageUserEntries,
|
||||||
|
PageUserPage,
|
||||||
|
PageUserPageEdit,
|
||||||
UiComment,
|
UiComment,
|
||||||
UiCommentCount,
|
UiCommentCount,
|
||||||
UiCommentForm,
|
UiCommentForm,
|
||||||
@ -112,8 +115,9 @@ export class XhrInterceptor implements HttpInterceptor {
|
|||||||
UiEntry,
|
UiEntry,
|
||||||
UiMain,
|
UiMain,
|
||||||
UiPoints,
|
UiPoints,
|
||||||
ConfirmDialog,
|
UiTagsPicker,
|
||||||
UiTagsPicker
|
UiUserPageMenu,
|
||||||
|
ConfirmDialog
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
@ -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>
|
@ -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 { Router, ActivatedRoute } from '@angular/router';
|
||||||
import { PageEvent } from '@angular/material/paginator';
|
import { PageEvent } from '@angular/material/paginator';
|
||||||
|
|
||||||
import { SettingsService } from '../../services/settings.service';
|
import { SettingsService } from '../../services/settings.service';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'page-entries',
|
selector: 'page-entries',
|
||||||
templateUrl: './entries.page.html'
|
templateUrl: './entries.page.html'
|
||||||
})
|
})
|
||||||
export class PageEntries implements OnInit {
|
export class PageEntries implements OnInit, OnDestroy {
|
||||||
|
|
||||||
settings: any;
|
|
||||||
@Input() fetch: Function;
|
@Input() fetch: Function;
|
||||||
|
@Input() filter: boolean = true;
|
||||||
@Input() gravityFilter: boolean = false;
|
@Input() gravityFilter: boolean = false;
|
||||||
entries: any;
|
entries: any;
|
||||||
asc: boolean = false;
|
asc: boolean = false;
|
||||||
@ -20,6 +21,9 @@ export class PageEntries implements OnInit {
|
|||||||
init: boolean = true;
|
init: boolean = true;
|
||||||
filterOpen: boolean = false;
|
filterOpen: boolean = false;
|
||||||
|
|
||||||
|
settings: any;
|
||||||
|
settingsSubscription: Subscription;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private settingsService: SettingsService, private router: Router, private route: ActivatedRoute) { }
|
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.settings = settings;
|
||||||
this.refresh();
|
this.refresh();
|
||||||
this.init = false;
|
this.init = false;
|
||||||
@ -59,6 +63,10 @@ export class PageEntries implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.settingsSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
refresh(): void {
|
refresh(): void {
|
||||||
if (!this.entries) {
|
if (!this.entries) {
|
||||||
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.fetch(this.entries.number || 0, this.entries.size || this.settings.pageSize, this.asc, this.entries.filter).subscribe((data: any) => {
|
||||||
this.entries = data;
|
this.entries = data;
|
||||||
this.entries.filter = filter;
|
this.entries.filter = filter;
|
||||||
}, (error) => { })
|
}, (error) => {
|
||||||
|
this.entries = { error: error };
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<mat-progress-bar *ngIf="!entry" mode="indeterminate"></mat-progress-bar>
|
<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>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<p>{{'submission.edit' | i18n}}</p>
|
<p>{{ (entry.id ? 'submission.edit' : 'submission.info') | i18n}}</p>
|
||||||
<mat-form-field>
|
<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>
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
@ -36,7 +43,10 @@
|
|||||||
|
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<mat-card-actions>
|
<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}}
|
{{'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>
|
||||||
|
@ -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 { EntriesService } from '../../../services/entries.service';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { FormBuilder, FormGroup, Validators, NgForm } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
|
|
||||||
import { distinctUntilChanged, debounceTime } from 'rxjs/operators';
|
import { distinctUntilChanged, debounceTime } from 'rxjs/operators';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { MatChipInputEvent } from '@angular/material/chips';
|
|
||||||
import { TagsService } from 'src/app/services/tags.service';
|
import { TagsService } from 'src/app/services/tags.service';
|
||||||
import { SettingsService } from 'src/app/services/settings.service';
|
import { SettingsService } from 'src/app/services/settings.service';
|
||||||
|
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 {
|
export class PageEntryEdit implements OnInit, OnDestroy {
|
||||||
|
|
||||||
id: number;
|
id: number;
|
||||||
entry: any;
|
entry: any;
|
||||||
@ -25,13 +24,14 @@ export class PageEntryEdit implements OnInit {
|
|||||||
success: boolean = false;
|
success: boolean = false;
|
||||||
form: FormGroup;
|
form: FormGroup;
|
||||||
settings: any;
|
settings: any;
|
||||||
readonly tagsSeparatorKeysCodes = [ ENTER, COMMA, SPACE ] as const;
|
|
||||||
@ViewChild('formDirective') private formDirective: NgForm;
|
settingsSubscription: Subscription;
|
||||||
|
|
||||||
constructor(private entriesService: EntriesService,
|
constructor(private entriesService: EntriesService,
|
||||||
private tagsService: TagsService,
|
private tagsService: TagsService,
|
||||||
private settingsService: SettingsService,
|
private settingsService: SettingsService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
|
private router: Router,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private snackBar: MatSnackBar) { }
|
private snackBar: MatSnackBar) { }
|
||||||
|
|
||||||
@ -43,11 +43,11 @@ export class PageEntryEdit implements OnInit {
|
|||||||
text: [ '', Validators.nullValidator ],
|
text: [ '', Validators.nullValidator ],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.settingsService.settings.subscribe((settings) => {
|
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.form.get('entryType').disable();
|
this.form.get('entryType').setValue(this.entryType);
|
||||||
|
|
||||||
this.form.get('entryType').valueChanges.subscribe((value) => {
|
this.form.get('entryType').valueChanges.subscribe((value) => {
|
||||||
this.entryType = value;
|
this.entryType = value;
|
||||||
@ -63,6 +63,7 @@ export class PageEntryEdit implements OnInit {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
this.form.get('url').valueChanges.pipe(
|
this.form.get('url').valueChanges.pipe(
|
||||||
debounceTime(800),
|
debounceTime(800),
|
||||||
distinctUntilChanged()).subscribe((value) => {
|
distinctUntilChanged()).subscribe((value) => {
|
||||||
@ -73,11 +74,17 @@ 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();
|
this.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.settingsSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
refresh() {
|
refresh() {
|
||||||
|
if (this.id) {
|
||||||
|
this.form.get('entryType').disable();
|
||||||
this.entriesService.getEntry(this.id).subscribe((data) => {
|
this.entriesService.getEntry(this.id).subscribe((data) => {
|
||||||
this.entry = data;
|
this.entry = data;
|
||||||
this.entryType = this.entry.entryType;
|
this.entryType = this.entry.entryType;
|
||||||
@ -95,6 +102,10 @@ export class PageEntryEdit implements OnInit {
|
|||||||
this.notfound = true;
|
this.notfound = true;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
this.entry = {};
|
||||||
|
this.entry.entryType = this.entryType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasError(controlName: string): boolean {
|
hasError(controlName: string): boolean {
|
||||||
@ -105,33 +116,43 @@ export class PageEntryEdit implements OnInit {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addTag(event: MatChipInputEvent): void {
|
create(): 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 {
|
|
||||||
|
|
||||||
if (this.working) {
|
if (this.working) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.working = true;
|
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) {
|
if (this.entry.metadata.edit) {
|
||||||
this.entry.url = this.form.get("url").value;
|
this.entry.url = this.form.get("url").value;
|
||||||
this.entry.title = this.form.get("title").value;
|
this.entry.title = this.form.get("title").value;
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
<p>{{'settings.pagesettings' | i18n}}</p>
|
<p>{{'settings.pagesettings' | i18n}}</p>
|
||||||
<mat-form-field>
|
<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-button (click)="resetGravity()">
|
||||||
<mat-icon>cancel</mat-icon>
|
<mat-icon>cancel</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
@ -33,9 +34,9 @@
|
|||||||
</mat-hint>
|
</mat-hint>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<button
|
<button matTooltip="{{'settings.entryDelay.reset' | i18n:settings.defaultEntryDelay}}"
|
||||||
*ngIf="user.settings.entryDelay || form.get('entryDelay').value != settings.defaultEntryDelay"
|
*ngIf="user.settings.entryDelay || form.get('entryDelay').value != settings.defaultEntryDelay" matPrefix
|
||||||
matPrefix mat-icon-button (click)="resetEntryDelay()">
|
mat-icon-button (click)="resetEntryDelay()">
|
||||||
<mat-icon>cancel</mat-icon>
|
<mat-icon>cancel</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<input type="number" min="0" max="15" step="1" matInput placeholder="{{'settings.entryDelay' | i18n}}"
|
<input type="number" min="0" max="15" step="1" matInput placeholder="{{'settings.entryDelay' | i18n}}"
|
||||||
@ -48,7 +49,7 @@
|
|||||||
</mat-hint>
|
</mat-hint>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<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"
|
*ngIf="user.settings.commentDelay || form.get('commentDelay').value != settings.defaultCommentDelay"
|
||||||
matPrefix mat-icon-button (click)="resetCommentDelay()">
|
matPrefix mat-icon-button (click)="resetCommentDelay()">
|
||||||
<mat-icon>cancel</mat-icon>
|
<mat-icon>cancel</mat-icon>
|
||||||
@ -62,6 +63,19 @@
|
|||||||
{{'settings.commentDelay.zero' | i18n}}
|
{{'settings.commentDelay.zero' | i18n}}
|
||||||
</mat-hint>
|
</mat-hint>
|
||||||
</mat-form-field>
|
</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-content>
|
||||||
<mat-card-actions>
|
<mat-card-actions>
|
||||||
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
|
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
|
||||||
|
@ -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 { FormBuilder, FormGroup, Validators, NgForm } from '@angular/forms';
|
||||||
|
|
||||||
import { UserService } from '../../services/user.service';
|
import { UserService } from '../../services/user.service';
|
||||||
import { SettingsService } from 'src/app/services/settings.service';
|
import { SettingsService } from 'src/app/services/settings.service';
|
||||||
|
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 {
|
export class PageSettings implements OnInit, OnDestroy {
|
||||||
|
|
||||||
auth: any;
|
auth: any;
|
||||||
user: any;
|
user: any;
|
||||||
@ -18,6 +19,7 @@ export class PageSettings implements OnInit {
|
|||||||
form: FormGroup;
|
form: FormGroup;
|
||||||
settings: any;
|
settings: any;
|
||||||
@ViewChild('formDirective') private formDirective: NgForm;
|
@ViewChild('formDirective') private formDirective: NgForm;
|
||||||
|
settingsSubscription: Subscription;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
@ -32,6 +34,7 @@ export class PageSettings implements OnInit {
|
|||||||
gravity: [ '', Validators.nullValidator ],
|
gravity: [ '', Validators.nullValidator ],
|
||||||
entryDelay: [ '', Validators.nullValidator ],
|
entryDelay: [ '', Validators.nullValidator ],
|
||||||
commentDelay: [ '', Validators.nullValidator ],
|
commentDelay: [ '', Validators.nullValidator ],
|
||||||
|
pageSize: [ '', Validators.nullValidator ],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.form.get('username').disable();
|
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('email').setValue(this.user.email);
|
||||||
this.form.get('about').setValue(this.user.about);
|
this.form.get('about').setValue(this.user.about);
|
||||||
|
|
||||||
this.settingsService.settings.subscribe((settings) => {
|
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.form.get('gravity').setValue(this.user.settings.gravity || this.settings.defaultGravity);
|
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('entryDelay').setValue(this.user.settings.entryDelay || this.settings.defaultEntryDelay);
|
||||||
this.form.get('commentDelay').setValue(this.user.settings.commentDelay || this.settings.defaultCommentDelay);
|
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 {
|
hasError(controlName: string): boolean {
|
||||||
@ -75,6 +81,11 @@ export class PageSettings implements OnInit {
|
|||||||
this.form.get('commentDelay').setValue(this.settings.defaultCommentDelay);
|
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 {
|
save(): void {
|
||||||
if (this.working) {
|
if (this.working) {
|
||||||
return;
|
return;
|
||||||
@ -108,6 +119,12 @@ export class PageSettings implements OnInit {
|
|||||||
this.user.settings.commentDelay = this.form.get('commentDelay').value;
|
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.userService.update(this.user).subscribe((data) => {
|
||||||
this.user = data;
|
this.user = data;
|
||||||
if (!this.user.settings) {
|
if (!this.user.settings) {
|
||||||
@ -115,6 +132,7 @@ export class PageSettings implements OnInit {
|
|||||||
}
|
}
|
||||||
this.working = false;
|
this.working = false;
|
||||||
this.success = true;
|
this.success = true;
|
||||||
|
this.settingsService.getSettings();
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
this.working = false;
|
this.working = false;
|
||||||
if (error.status == 422) {
|
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>
|
|
@ -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 { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
import { CommentService } from '../../../services/comment.service';
|
import { CommentService } from '../../../services/comment.service';
|
||||||
import { SettingsService } from '../../../services/settings.service';
|
import { SettingsService } from '../../../services/settings.service';
|
||||||
@ -10,19 +11,20 @@ import { SettingsService } from '../../../services/settings.service';
|
|||||||
templateUrl: './usercomments.page.html',
|
templateUrl: './usercomments.page.html',
|
||||||
styleUrls: [ './usercomments.page.scss' ]
|
styleUrls: [ './usercomments.page.scss' ]
|
||||||
})
|
})
|
||||||
export class PageUserComments implements OnInit {
|
export class PageUserComments implements OnInit, OnDestroy {
|
||||||
|
|
||||||
settings: any;
|
settings: any;
|
||||||
username: string;
|
username: string;
|
||||||
comments: any = {};
|
comments: any = {};
|
||||||
init: boolean = true;
|
init: boolean = true;
|
||||||
ignore: string[] = [ "author" ];
|
ignore: string[] = [ "author" ];
|
||||||
|
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.settingsService.settings.subscribe((settings) => {
|
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => {
|
||||||
this.settings = 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.commentService.getByUser(this.username, this.comments.number || 0, this.comments.size || this.settings.pageSize, this.ignore).subscribe((data: any) => {
|
||||||
this.comments = data;
|
this.comments = data;
|
||||||
@ -30,6 +32,10 @@ export class PageUserComments implements OnInit {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.settingsSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
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((data) => {
|
||||||
|
67
src/app/pages/userpage/edit/edit.page.html
Normal file
67
src/app/pages/userpage/edit/edit.page.html
Normal file
@ -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;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui-tagspicker {
|
mat-chip mat-icon.mat-icon-inline {
|
||||||
display: block;
|
margin-top: -12px;
|
||||||
width: 100%;
|
margin-right: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
form {
|
form {
|
||||||
@ -23,3 +23,7 @@ form {
|
|||||||
max-width: 50%;
|
max-width: 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mat-card-actions > * {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
156
src/app/pages/userpage/edit/edit.page.ts
Normal file
156
src/app/pages/userpage/edit/edit.page.ts
Normal 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();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
8
src/app/pages/userpage/userpage.page.html
Normal file
8
src/app/pages/userpage/userpage.page.html
Normal file
@ -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
src/app/pages/userpage/userpage.page.ts
Normal file
46
src/app/pages/userpage/userpage.page.ts
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -50,6 +50,10 @@ export class EntriesService {
|
|||||||
return this.fetch("/last", page, size, asc, filter);
|
return this.fetch("/last", page, size, asc, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getByUserPage(name: string, page: number, size: number, asc: boolean, username: string) {
|
||||||
|
return this.fetch("/userpage/" + name, page, size, asc, username ? { username: username } : undefined);
|
||||||
|
}
|
||||||
|
|
||||||
getByUser(username: string, page: number, size: number, asc: boolean, filter: any) {
|
getByUser(username: string, page: number, size: number, asc: boolean, filter: any) {
|
||||||
return this.fetch("/byuser/" + username, page, size, asc, filter);
|
return this.fetch("/byuser/" + username, page, size, asc, filter);
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import { environment } from '../../environments/environment';
|
|||||||
})
|
})
|
||||||
export class SettingsService {
|
export class SettingsService {
|
||||||
|
|
||||||
settings: ReplaySubject<any> = new ReplaySubject(undefined);
|
settings: ReplaySubject<any> = new ReplaySubject(1);
|
||||||
|
|
||||||
constructor(private http: HttpClient) {
|
constructor(private http: HttpClient) {
|
||||||
}
|
}
|
||||||
|
53
src/app/services/userpage.service.ts
Normal file
53
src/app/services/userpage.service.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
|
import { environment } from '../../environments/environment';
|
||||||
|
import { ReplaySubject } from 'rxjs';
|
||||||
|
import { RequestError } from './requesterror';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class UserPageService {
|
||||||
|
|
||||||
|
userPages: ReplaySubject<any> = new ReplaySubject(1);
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) {
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserPages() {
|
||||||
|
return this.http.get(environment.apiUrl + "/userpages").toPromise().then((data: any) => {
|
||||||
|
this.userPages.next(data);
|
||||||
|
return data;
|
||||||
|
}, error => {
|
||||||
|
throw new RequestError(error);
|
||||||
|
});;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPublicUserPages(page: number, size: number, desc: boolean) {
|
||||||
|
let httpParams = new HttpParams();
|
||||||
|
if (page != undefined) {
|
||||||
|
httpParams = httpParams.set("page", "" + page);
|
||||||
|
}
|
||||||
|
if (size != undefined) {
|
||||||
|
httpParams = httpParams.set("size", "" + size);
|
||||||
|
}
|
||||||
|
if (desc) {
|
||||||
|
httpParams = httpParams.set("desc", "" + desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.http.get(environment.apiUrl + "/userpages/public", { params: httpParams });
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserPage(name: string) {
|
||||||
|
return this.http.get(environment.apiUrl + "/userpages/userpage/" + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
createOrUpdate(userPage: any) {
|
||||||
|
return this.http.post(environment.apiUrl + "/userpages/userpage", userPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteUserPage(name: string) {
|
||||||
|
return this.http.delete(environment.apiUrl + "/userpages/userpage/" + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import { Component, OnInit, Input } from '@angular/core';
|
import { Component, OnInit, Input, OnDestroy } from '@angular/core';
|
||||||
import { PageEvent } from '@angular/material/paginator';
|
import { PageEvent } from '@angular/material/paginator';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
import { CommentService } from '../../services/comment.service';
|
import { CommentService } from '../../services/comment.service';
|
||||||
import { SettingsService } from '../../services/settings.service';
|
import { SettingsService } from '../../services/settings.service';
|
||||||
@ -9,7 +10,7 @@ import { SettingsService } from '../../services/settings.service';
|
|||||||
templateUrl: './comments.ui.html',
|
templateUrl: './comments.ui.html',
|
||||||
styleUrls: [ './comments.ui.scss' ]
|
styleUrls: [ './comments.ui.scss' ]
|
||||||
})
|
})
|
||||||
export class UiComments implements OnInit {
|
export class UiComments implements OnInit, OnDestroy {
|
||||||
|
|
||||||
settings: any;
|
settings: any;
|
||||||
comments: any;
|
comments: any;
|
||||||
@ -19,17 +20,22 @@ export class UiComments implements OnInit {
|
|||||||
@Input() subcomments: boolean = false;
|
@Input() subcomments: boolean = false;
|
||||||
@Input() parentLink: boolean = false;
|
@Input() parentLink: boolean = false;
|
||||||
boundRefresh: Function;
|
boundRefresh: Function;
|
||||||
|
settingsSubscription: Subscription;
|
||||||
|
|
||||||
constructor(private settingsService: SettingsService, private commentService: CommentService) { }
|
constructor(private settingsService: SettingsService, private commentService: CommentService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.boundRefresh = this.refresh.bind(this);
|
this.boundRefresh = this.refresh.bind(this);
|
||||||
this.settingsService.settings.subscribe((settings) => {
|
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.refresh();
|
this.refresh();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.settingsSubscription.unsubscribe;
|
||||||
|
}
|
||||||
|
|
||||||
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((data) => {
|
||||||
|
@ -1,4 +1,19 @@
|
|||||||
<mat-progress-bar *ngIf="!entries || !entries.content" mode="indeterminate"></mat-progress-bar>
|
<mat-progress-bar *ngIf="!entries || !entries.content && !entries.error" mode="indeterminate"></mat-progress-bar>
|
||||||
|
|
||||||
|
|
||||||
|
<div *ngIf="entries && entries.error" fxLayout="column" fxFlexFill>
|
||||||
|
<mat-card class="accent box">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>{{ 'entries.error.' + entries.error.status | i18n}}</mat-card-title>
|
||||||
|
<mat-card-subtitle>{{'entries.error' | i18n}}</mat-card-subtitle>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<p>
|
||||||
|
{{ 'entries.error.' + entries.error.status + '.text' | i18n}}
|
||||||
|
</p>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div *ngIf="entries" fxLayout="column" fxFlexFill>
|
<div *ngIf="entries" fxLayout="column" fxFlexFill>
|
||||||
<mat-list *ngIf="entries.content">
|
<mat-list *ngIf="entries.content">
|
||||||
@ -20,12 +35,13 @@
|
|||||||
<span fxFlexOffset="auto"></span>
|
<span fxFlexOffset="auto"></span>
|
||||||
|
|
||||||
<div class="mat-paginator" fxLayout="row" fxLayout.xs="column" fxLayoutAlign.xs="start start">
|
<div class="mat-paginator" fxLayout="row" fxLayout.xs="column" fxLayoutAlign.xs="start start">
|
||||||
<div class="filter-container">
|
<div *ngIf="filter" class="filter-container">
|
||||||
<a mat-icon-button mat-button (click)="filterOpen=!filterOpen" title="{{'entries.filter' | i18n}}">
|
<a mat-icon-button mat-button (click)="filterOpen=!filterOpen" title="{{'entries.filter' | i18n}}" [color]="filterOpen ? 'accent' : 'primary'">
|
||||||
<mat-icon>filter_alt</mat-icon>
|
<mat-icon>filter_alt</mat-icon>
|
||||||
</a>
|
</a>
|
||||||
<div *ngIf="filterOpen">
|
<div *ngIf="filterOpen" fxLayout="row wrap">
|
||||||
<ui-tagspicker [(model)]="entries.filter.tag" max="1" placeholder="{{'entries.filter.tag' | i18n}}" [change]="boundTagspickerChange"></ui-tagspicker>
|
<ui-tagspicker [(model)]="tags" placeholder="{{'entries.filter.tags' | i18n}}" [change]="boundTagsPickerChange">
|
||||||
|
</ui-tagspicker>
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input matInput [matDatepicker]="picker" [value]="entries && entries.filter && entries.filter.date"
|
<input matInput [matDatepicker]="picker" [value]="entries && entries.filter && entries.filter.date"
|
||||||
@ -35,8 +51,33 @@
|
|||||||
<mat-datepicker #picker touchUi></mat-datepicker>
|
<mat-datepicker #picker touchUi></mat-datepicker>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-select placeholder="{{'entries.filter.entryType' | i18n}}"
|
||||||
|
[value]="entries && entries.filter && entries.filter.type"
|
||||||
|
(selectionChange)="setFilter('type', $event.value || undefined)">
|
||||||
|
<mat-select-trigger>
|
||||||
|
<span *ngIf="entries.filter.type">
|
||||||
|
<mat-icon>{{'entryType.' + entries.filter.type + '.icon' | i18n}}</mat-icon> {{'entryType.' +
|
||||||
|
entries.filter.type | 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>
|
||||||
|
|
||||||
|
|
||||||
|
<ui-tagspicker [(model)]="excludedTags" placeholder="{{'entries.filter.excludedTags' | i18n}}" [change]="boundExcludedTagsPickerChange">
|
||||||
|
</ui-tagspicker>
|
||||||
|
|
||||||
<mat-form-field *ngIf="gravityFilter">
|
<mat-form-field *ngIf="gravityFilter">
|
||||||
<input matInput type="number" step="0.01" min="0"
|
<input matInput type="number" step="0.01" min="0" max="2.0"
|
||||||
[value]="entries && entries.filter && entries.filter.gravity"
|
[value]="entries && entries.filter && entries.filter.gravity"
|
||||||
(change)="setFilter('gravity', $event.target && $event.target.value || undefined)"
|
(change)="setFilter('gravity', $event.target && $event.target.value || undefined)"
|
||||||
placeholder="{{'entries.filter.gravity' | i18n}}">
|
placeholder="{{'entries.filter.gravity' | i18n}}">
|
||||||
|
@ -31,4 +31,22 @@ mat-chip mat-icon.mat-icon-inline {
|
|||||||
|
|
||||||
ui-tagspicker {
|
ui-tagspicker {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
margin: 5px;
|
||||||
|
|
||||||
|
@media screen and (min-width: 576px) {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 768px) {
|
||||||
|
max-width: 80%;
|
||||||
|
margin: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 992px) {
|
||||||
|
max-width: 50%;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,10 +1,6 @@
|
|||||||
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
|
|
||||||
import { Component, OnInit, Input, ViewChild } from '@angular/core';
|
import { Component, OnInit, Input, ViewChild } from '@angular/core';
|
||||||
import { FormControl } from '@angular/forms';
|
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { debounceTime, switchMap } from 'rxjs/operators';
|
|
||||||
import { TagsService } from 'src/app/services/tags.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ui-entries',
|
selector: 'ui-entries',
|
||||||
@ -17,19 +13,23 @@ export class UiEntries implements OnInit {
|
|||||||
@Input() update: Function;
|
@Input() update: Function;
|
||||||
@Input() refresh: Function;
|
@Input() refresh: Function;
|
||||||
@Input() gravityFilter: boolean = false;
|
@Input() gravityFilter: boolean = false;
|
||||||
|
@Input() filter: boolean = true;
|
||||||
@ViewChild(MatPaginator) matPaginator;
|
@ViewChild(MatPaginator) matPaginator;
|
||||||
pageSizeOptions: number[] = [ 1, 2, 3, 4, 5, 10, 30, 50, 100 ];
|
pageSizeOptions: number[] = [ 1, 2, 3, 4, 5, 10, 15, 30, 50, 100 ];
|
||||||
filterOpen: boolean = false;
|
filterOpen: boolean = false;
|
||||||
searchTags: Observable<Object>;
|
searchTags: Observable<Object>;
|
||||||
boundTagspickerChange: Function;
|
boundTagsPickerChange: Function;
|
||||||
|
boundExcludedTagsPickerChange: Function;
|
||||||
|
entryTypes: string[] = [ undefined, 'LINK', 'DISCUSSION', 'QUESTION', 'INTERN' ];
|
||||||
|
tags: string[] = [];
|
||||||
|
excludedTags: string[] = [];
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
constructor(private tagsService: TagsService) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.checkFilterOpen();
|
this.checkFilterOpen();
|
||||||
this.boundTagspickerChange = this.tagspickerChange.bind(this);
|
this.boundTagsPickerChange = this.tagsPickerChange.bind(this);
|
||||||
|
this.boundExcludedTagsPickerChange = this.excludedTagsPickerChange.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFilterOpen() {
|
checkFilterOpen() {
|
||||||
@ -38,15 +38,32 @@ export class UiEntries implements OnInit {
|
|||||||
for (const param in this.entries.filter) {
|
for (const param in this.entries.filter) {
|
||||||
if (this.entries.filter[ param ]) {
|
if (this.entries.filter[ param ]) {
|
||||||
this.filterOpen = true;
|
this.filterOpen = true;
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
if (param == 'tags' && this.entries.filter[ param ]) {
|
||||||
|
this.tags = this.entries.filter[ param ].split(',');
|
||||||
|
}
|
||||||
|
if (param == 'excludedTags' && this.entries.filter[ param ]) {
|
||||||
|
this.excludedTags = this.entries.filter[ param ].split(',');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tagspickerChange(value: any) {
|
tagsPickerChange(value: string[]) {
|
||||||
console.log("change", value);
|
if (value && value.length > 0) {
|
||||||
this.setFilter('tag', value[0]);
|
this.setFilter('tags', value.join(','));
|
||||||
|
} else {
|
||||||
|
this.setFilter('tags', undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
excludedTagsPickerChange(value: string[]) {
|
||||||
|
if (value && value.length > 0) {
|
||||||
|
this.setFilter('excludedTags', value.join(','));
|
||||||
|
} else {
|
||||||
|
this.setFilter('excludedTags', undefined);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setFilter(key: string, value) {
|
setFilter(key: string, value) {
|
||||||
|
@ -45,7 +45,7 @@ export class UiEntry implements OnInit {
|
|||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
relativeTo: this.route,
|
relativeTo: this.route,
|
||||||
queryParams: { 'tag': tag },
|
queryParams: { 'tags': tag },
|
||||||
queryParamsHandling: 'merge'
|
queryParamsHandling: 'merge'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -43,18 +43,19 @@
|
|||||||
(click)="!isBiggerScreen() && opened=false">
|
(click)="!isBiggerScreen() && opened=false">
|
||||||
<mat-nav-list>
|
<mat-nav-list>
|
||||||
<a *ngIf="authenticated" routerLink="/top" routerLinkActive="active" mat-list-item>
|
<a *ngIf="authenticated" routerLink="/top" routerLinkActive="active" mat-list-item>
|
||||||
<mat-icon>trending_up</mat-icon> {{'page.top' | i18n}}
|
<mat-icon>{{'sorting.TOP.icon' | i18n}}</mat-icon> {{'sorting.TOP' | i18n}}
|
||||||
</a>
|
</a>
|
||||||
<a *ngIf="authenticated" routerLink="/new" routerLinkActive="active" mat-list-item>
|
<a *ngIf="authenticated" routerLink="/new" routerLinkActive="active" mat-list-item>
|
||||||
<mat-icon>today</mat-icon> {{'page.new' | i18n}}
|
<mat-icon>{{'sorting.NEW.icon' | i18n}}</mat-icon> {{'sorting.NEW' | i18n}}
|
||||||
</a>
|
</a>
|
||||||
<mat-divider *ngIf="authenticated"></mat-divider>
|
<mat-divider *ngIf="authenticated"></mat-divider>
|
||||||
<a *ngIf="authenticated" routerLink="/hot" routerLinkActive="active" mat-list-item>
|
<a *ngIf="authenticated" routerLink="/hot" routerLinkActive="active" mat-list-item>
|
||||||
<mat-icon>whatshot</mat-icon> {{'page.hot' | i18n}}
|
<mat-icon>{{'sorting.HOT.icon' | i18n}}</mat-icon> {{'sorting.HOT' | i18n}}
|
||||||
</a>
|
</a>
|
||||||
<a *ngIf="authenticated" routerLink="/last" routerLinkActive="active" mat-list-item>
|
<a *ngIf="authenticated" routerLink="/last" routerLinkActive="active" mat-list-item>
|
||||||
<mat-icon>history</mat-icon> {{'page.last' | i18n}}
|
<mat-icon>{{'sorting.LAST.icon' | i18n}}</mat-icon> {{'sorting.LAST' | i18n}}
|
||||||
</a>
|
</a>
|
||||||
|
<ui-userpagemenu *ngIf="authenticated"></ui-userpagemenu>
|
||||||
<mat-divider *ngIf="moderator"></mat-divider>
|
<mat-divider *ngIf="moderator"></mat-divider>
|
||||||
<a *ngIf="moderator" routerLink="/moderation/entries" routerLinkActive="active" mat-list-item>
|
<a *ngIf="moderator" routerLink="/moderation/entries" routerLinkActive="active" mat-list-item>
|
||||||
<mat-icon>report</mat-icon> {{'moderation.entries' | i18n}}
|
<mat-icon>report</mat-icon> {{'moderation.entries' | i18n}}
|
||||||
|
10
src/app/ui/userpagemenu/userpagemenu.ui.html
Normal file
10
src/app/ui/userpagemenu/userpagemenu.ui.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<ng-container *ngIf="settings">
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<a *ngFor="let userpage of userpages" routerLink="/p/{{userpage.name}}" routerLinkActive="active" mat-list-item>
|
||||||
|
<mat-icon>star</mat-icon> {{userpage.name}}
|
||||||
|
</a>
|
||||||
|
<a *ngIf="userpages.length < settings.maxUserPages" routerLink="/p" routerLinkActive="active" mat-list-item
|
||||||
|
title="{{'userpages.add' | i18n}}">
|
||||||
|
<mat-icon style="margin: 0 auto;">add</mat-icon>
|
||||||
|
</a>
|
||||||
|
</ng-container>
|
3
src/app/ui/userpagemenu/userpagemenu.ui.scss
Normal file
3
src/app/ui/userpagemenu/userpagemenu.ui.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
mat-form-field {
|
||||||
|
display: block;
|
||||||
|
}
|
32
src/app/ui/userpagemenu/userpagemenu.ui.ts
Normal file
32
src/app/ui/userpagemenu/userpagemenu.ui.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
import { SettingsService } from 'src/app/services/settings.service';
|
||||||
|
import { UserPageService } from 'src/app/services/userpage.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ui-userpagemenu',
|
||||||
|
templateUrl: 'userpagemenu.ui.html',
|
||||||
|
styleUrls: [ './userpagemenu.ui.scss' ]
|
||||||
|
})
|
||||||
|
export class UiUserPageMenu implements OnInit {
|
||||||
|
|
||||||
|
|
||||||
|
userpages: any[] = [];
|
||||||
|
settings: any;
|
||||||
|
settingsSubscription: Subscription;
|
||||||
|
|
||||||
|
constructor(private userPageService: UserPageService, private settingsService: SettingsService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => {
|
||||||
|
this.settings = settings;
|
||||||
|
this.userPageService.userPages.subscribe((data: any) => {
|
||||||
|
this.userpages = data.content;
|
||||||
|
})
|
||||||
|
this.userPageService.getUserPages();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user