From 979324ccc8902d6b799bda2ed6e1ac3982afda5c Mon Sep 17 00:00:00 2001 From: _Bastler Date: Wed, 1 Dec 2021 19:01:17 +0100 Subject: [PATCH] added tags + filtering --- src/app/app.module.ts | 2 + src/app/pages/entries/entries.page.html | 2 +- src/app/pages/entries/entries.page.ts | 33 ++++++- src/app/pages/entry/edit/edit.page.html | 12 ++- src/app/pages/entry/edit/edit.page.scss | 7 +- src/app/pages/entry/edit/edit.page.ts | 99 ++++++++++++++----- src/app/pages/entry/entry.page.html | 2 +- src/app/pages/entry/entry.page.ts | 1 + src/app/pages/hot/hot.page.html | 2 +- src/app/pages/hot/hot.page.ts | 4 +- src/app/pages/last/last.page.ts | 4 +- src/app/pages/login/login.page.html | 2 +- src/app/pages/new/new.page.ts | 4 +- src/app/pages/submission/submission.page.html | 7 +- src/app/pages/submission/submission.page.scss | 7 +- src/app/pages/submission/submission.page.ts | 26 ++++- src/app/pages/top/top.page.html | 2 +- src/app/pages/top/top.page.ts | 4 +- .../user/userentries/userentries.page.ts | 4 +- src/app/services/entries.service.ts | 46 ++++++--- src/app/services/tags.service.ts | 22 +++++ src/app/ui/entries/entries.ui.html | 36 ++++++- src/app/ui/entries/entries.ui.scss | 21 ++++ src/app/ui/entries/entries.ui.ts | 52 +++++++++- src/app/ui/entry/entry.ui.html | 11 ++- src/app/ui/entry/entry.ui.scss | 45 +++++++++ src/app/ui/entry/entry.ui.ts | 24 +++-- src/app/ui/tags/tagspicker.ui.html | 18 ++++ src/app/ui/tags/tagspicker.ui.scss | 16 +++ src/app/ui/tags/tagspicker.ui.ts | 95 ++++++++++++++++++ 30 files changed, 526 insertions(+), 84 deletions(-) create mode 100644 src/app/services/tags.service.ts create mode 100644 src/app/ui/tags/tagspicker.ui.html create mode 100644 src/app/ui/tags/tagspicker.ui.scss create mode 100644 src/app/ui/tags/tagspicker.ui.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index c67f05d..aa5f40a 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -49,6 +49,7 @@ import { ConfirmDialog } from './ui/confirm/confirm.component' import { I18nService, I18nPaginatorIntl } from './services/i18n.service'; import { ServiceWorkerModule } from '@angular/service-worker'; import { environment } from '../environments/environment'; +import { UiTagsPicker } from './ui/tags/tagspicker.ui'; export function fetchI18n(i18n: I18nService) { @@ -112,6 +113,7 @@ export class XhrInterceptor implements HttpInterceptor { UiMain, UiPoints, ConfirmDialog, + UiTagsPicker ], imports: [ BrowserModule, diff --git a/src/app/pages/entries/entries.page.html b/src/app/pages/entries/entries.page.html index 24cc006..53111cb 100644 --- a/src/app/pages/entries/entries.page.html +++ b/src/app/pages/entries/entries.page.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/app/pages/entries/entries.page.ts b/src/app/pages/entries/entries.page.ts index d340a0f..97ef8b0 100644 --- a/src/app/pages/entries/entries.page.ts +++ b/src/app/pages/entries/entries.page.ts @@ -12,10 +12,13 @@ export class PageEntries implements OnInit { settings: any; @Input() fetch: Function; + @Input() gravityFilter: boolean = false; entries: any; + asc: boolean = false; boundRefresh: Function; boundUpdate: Function; init: boolean = true; + filterOpen: boolean = false; constructor( private settingsService: SettingsService, private router: Router, private route: ActivatedRoute) { } @@ -25,7 +28,7 @@ export class PageEntries implements OnInit { this.boundUpdate = this.update.bind(this); this.route.queryParams.subscribe(params => { if (this.init) { - this.entries = {}; + this.entries = { filter: {} }; if (params[ 'p' ]) { this.entries.number = +params[ 'p' ] - 1; if (this.entries.number < 0) { @@ -37,6 +40,16 @@ export class PageEntries implements OnInit { this.entries.size = +params[ 's' ]; } + if (params[ 'asc' ]) { + this.asc = true; + } + + for (const param in params) { + if (param != 's' && param != 'p' && param != 'asc') { + this.entries.filter[ param ] = params[ param ]; + } + } + this.settingsService.settings.subscribe((settings) => { this.settings = settings; this.refresh(); @@ -51,9 +64,11 @@ export class PageEntries implements OnInit { this.entries = {}; } + const filter = JSON.parse(JSON.stringify(this.entries.filter || {})) this.entries.content = null; - this.fetch(this.entries.number || 0, this.entries.size || this.settings.pageSize).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.filter = filter; }, (error) => { }) } @@ -70,6 +85,12 @@ export class PageEntries implements OnInit { params.s = event.pageSize; } + if (this.entries.filter) { + for (const param in this.entries.filter) { + params[ param ] = this.entries.filter[ param ]; + } + } + this.router.navigate( [], { @@ -78,9 +99,13 @@ export class PageEntries implements OnInit { queryParamsHandling: 'merge' }); - this.fetch(event.pageIndex, event.pageSize).subscribe((data: any) => { + const filter = JSON.parse(JSON.stringify(this.entries.filter || {})) + this.fetch(event.pageIndex, event.pageSize, this.asc, this.entries.filter).subscribe((data: any) => { this.entries = data; - }, (error) => { }) + this.entries.filter = filter; + }, (error) => { + this.entries = {}; + }) } } diff --git a/src/app/pages/entry/edit/edit.page.html b/src/app/pages/entry/edit/edit.page.html index 3d24d62..de6394d 100644 --- a/src/app/pages/entry/edit/edit.page.html +++ b/src/app/pages/entry/edit/edit.page.html @@ -1,5 +1,6 @@
-
+ +

{{'submission.edit' | i18n}}

@@ -23,18 +24,21 @@ - + {{'submission.text.error' | i18n}} + + +
- {{'submission.success' | i18n}} + {{'submission.success' | i18n}}
diff --git a/src/app/pages/entry/edit/edit.page.scss b/src/app/pages/entry/edit/edit.page.scss index db871a6..d0188ca 100644 --- a/src/app/pages/entry/edit/edit.page.scss +++ b/src/app/pages/entry/edit/edit.page.scss @@ -2,6 +2,11 @@ mat-form-field { display: block; } +mat-chip mat-icon.mat-icon-inline { + margin-top: -12px; + margin-right: -2px; +} + form { margin: 5px; @@ -17,4 +22,4 @@ form { @media screen and (min-width: 992px) { max-width: 50%; } -} \ No newline at end of file +} diff --git a/src/app/pages/entry/edit/edit.page.ts b/src/app/pages/entry/edit/edit.page.ts index 4b6ccb2..257157a 100644 --- a/src/app/pages/entry/edit/edit.page.ts +++ b/src/app/pages/entry/edit/edit.page.ts @@ -1,9 +1,12 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { EntriesService } from '../../../services/entries.service'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { FormBuilder, FormGroup, Validators, NgForm } from '@angular/forms'; -import { distinctUntilChanged, debounceTime } from 'rxjs/operators'; +import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes'; +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'; @Component({ selector: 'page-entry-edit', @@ -20,9 +23,11 @@ export class PageEntryEdit implements OnInit { working: boolean = false; success: boolean = false; form: FormGroup; + readonly tagsSeparatorKeysCodes = [ ENTER, COMMA, SPACE ] as const; @ViewChild('formDirective') private formDirective: NgForm; constructor(private entriesService: EntriesService, + private tagsService: TagsService, private formBuilder: FormBuilder, private route: ActivatedRoute, private snackBar: MatSnackBar) { } @@ -73,6 +78,11 @@ export class PageEntryEdit implements OnInit { 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; @@ -88,6 +98,25 @@ 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 { if (this.working) { @@ -96,31 +125,55 @@ export class PageEntryEdit implements OnInit { this.working = true; - this.entry.url = this.form.get("url").value; - this.entry.title = this.form.get("title").value; - this.entry.text = this.form.get("text").value; + if (this.entry.metadata.edit) { + this.entry.url = this.form.get("url").value; + this.entry.title = this.form.get("title").value; + this.entry.text = this.form.get("text").value; - this.entriesService.update(this.entry).subscribe((data) => { - this.entry = data; - this.working = false; - this.success = true; - }, (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; + this.entriesService.update(this.entry).subscribe((data) => { + this.entry = data; + this.working = false; + this.success = true; + }, (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 ]); + for (let code in errors) { + this.form.get(code).setErrors(errors[ code ]); + } } - } - }) + }) + } else { + this.tagsService.setTags(this.entry.id, this.entry.tags).subscribe((data) => { + this.entry = data; + this.working = false; + this.success = true; + }, (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 ]); + } + } + }) + } } diff --git a/src/app/pages/entry/entry.page.html b/src/app/pages/entry/entry.page.html index 9b77dcb..1598164 100644 --- a/src/app/pages/entry/entry.page.html +++ b/src/app/pages/entry/entry.page.html @@ -1,7 +1,7 @@
- +

diff --git a/src/app/pages/entry/entry.page.ts b/src/app/pages/entry/entry.page.ts index 642fabc..87cb62d 100644 --- a/src/app/pages/entry/entry.page.ts +++ b/src/app/pages/entry/entry.page.ts @@ -33,6 +33,7 @@ export class PageEntry implements OnInit { this.entry = data; }, (error) => { if (error.status == 404) { + this.entry = false; this.notfound = true; } }) diff --git a/src/app/pages/hot/hot.page.html b/src/app/pages/hot/hot.page.html index 9d79ea7..49dce6b 100644 --- a/src/app/pages/hot/hot.page.html +++ b/src/app/pages/hot/hot.page.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/app/pages/hot/hot.page.ts b/src/app/pages/hot/hot.page.ts index 506f9c8..b4eb208 100644 --- a/src/app/pages/hot/hot.page.ts +++ b/src/app/pages/hot/hot.page.ts @@ -19,8 +19,8 @@ export class PageHot implements OnInit { this.boundFetch = this.fetch.bind(this); } - fetch(page: number, size: number) { - return this.entriesService.getComments(page,size); + fetch(page: number, size: number, asc: boolean, filter: any) { + return this.entriesService.getComments(page, size, asc, filter); } } diff --git a/src/app/pages/last/last.page.ts b/src/app/pages/last/last.page.ts index c778a03..813b856 100644 --- a/src/app/pages/last/last.page.ts +++ b/src/app/pages/last/last.page.ts @@ -16,8 +16,8 @@ export class PageLast implements OnInit { this.boundFetch = this.fetch.bind(this); } - fetch(page: number, size: number) { - return this.entriesService.getLastComment(page,size); + fetch(page: number, size: number,asc: boolean, filter: any) { + return this.entriesService.getLastComment(page, size,asc, filter); } } diff --git a/src/app/pages/login/login.page.html b/src/app/pages/login/login.page.html index d6a859f..1994c02 100644 --- a/src/app/pages/login/login.page.html +++ b/src/app/pages/login/login.page.html @@ -53,7 +53,7 @@
\ No newline at end of file diff --git a/src/app/pages/new/new.page.ts b/src/app/pages/new/new.page.ts index 03c32e1..53887b8 100644 --- a/src/app/pages/new/new.page.ts +++ b/src/app/pages/new/new.page.ts @@ -18,8 +18,8 @@ export class PageNew implements OnInit { this.boundFetch = this.fetch.bind(this); } - fetch(page: number, size: number) { - return this.entriesService.getNew(page,size); + fetch(page: number, size: number, asc: boolean, filter: any) { + return this.entriesService.getNew(page, size, asc, filter); } } diff --git a/src/app/pages/submission/submission.page.html b/src/app/pages/submission/submission.page.html index 5d5e16d..304bfff 100644 --- a/src/app/pages/submission/submission.page.html +++ b/src/app/pages/submission/submission.page.html @@ -31,12 +31,15 @@ - + {{'submission.text.error' | i18n}} + + +