diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 3ef2ede..1d9bd69 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -6,15 +6,12 @@ import { PageBookmarks } from './pages/bookmarks/bookmarks.page'; import { PageComment } from './pages/comment/comment.page'; import { PageEntryEdit } from './pages/entry/edit/edit.page'; import { PageEntry } from './pages/entry/entry.page'; -import { PageHot } from './pages/hot/hot.page'; -import { PageLast } from './pages/last/last.page'; import { PageLogin } from './pages/login/login.page'; import { PageModerationComments } from './pages/moderation/comments/moderation.comments.page'; import { PageModerationEntries } from './pages/moderation/entries/moderation.entries.page'; -import { PageNew } from './pages/new/new.page'; import { PageNotFound } from './pages/notfound/notfound.page'; +import { PageSearch } from './pages/search/search.page'; import { PageSettings } from './pages/settings/settings.page'; -import { PageTop } from './pages/top/top.page'; import { PageUnavailable } from './pages/unavailable/unavailable.page'; import { PageUser } from './pages/user/user.page'; @@ -28,18 +25,11 @@ import { UiMain } from './ui/main/main.ui'; const routes: Routes = [ { path: '', component: UiMain, children: [ - { path: '', redirectTo: "/top", pathMatch: 'full' }, + { path: '', redirectTo: "/p/TOP", pathMatch: 'full' }, { path: 'login', component: PageLogin, canActivate: [ AnonymousGuard ] }, - { path: 'top', component: PageTop, canActivate: [ AuthenticatedGuard ] }, - { path: 'hot', component: PageHot, 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: 'search', component: PageSearch, canActivate: [ AuthenticatedGuard ] }, { path: 'moderation/comments', component: PageModerationComments, canActivate: [ AuthenticatedGuard ] }, { path: 'moderation/entries', component: PageModerationEntries, canActivate: [ AuthenticatedGuard ] }, - { path: 'new', component: PageNew, canActivate: [ AuthenticatedGuard ] }, { path: 'bookmarks', component: PageBookmarks, canActivate: [ AuthenticatedGuard ] }, { path: 'settings', component: PageSettings, canActivate: [ AuthenticatedGuard ] }, { path: 'submit', component: PageEntryEdit, canActivate: [ AuthenticatedGuard ] }, @@ -50,6 +40,10 @@ const routes: Routes = [ { path: 'u/c/:username', component: PageUserComments, canActivate: [ AuthenticatedGuard ] }, { path: 'u/e/:username', component: PageUserEntries, canActivate: [ AuthenticatedGuard ] }, { path: 'unavailable', component: PageUnavailable }, + { 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: '**', component: PageNotFound, pathMatch: 'full', canActivate: [ AuthUpdateGuard ] }, ] }, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index b19904d..d1870cd 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -13,7 +13,7 @@ import * as moment from 'moment'; import { AutofocusDirective } from './material/autofocus'; -import { I18nPipe } from './utils/i18n.pipe'; +import { I18nPipe, I18nEmptyPipe } from './utils/i18n.pipe'; import { MomentPipe } from './utils/moment.pipe'; import { UrlBasePipe, UrlTextPipe } from './utils/urltext.pipe'; import { AppComponent } from './app.component'; @@ -22,15 +22,11 @@ import { PageComment } from './pages/comment/comment.page'; import { PageEntry } from './pages/entry/entry.page'; import { PageEntryEdit } from './pages/entry/edit/edit.page'; import { PageEntries } from './pages/entries/entries.page'; -import { PageHot } from './pages/hot/hot.page'; -import { PageLast } from './pages/last/last.page'; import { PageLogin } from './pages/login/login.page'; import { PageModerationComments } from './pages/moderation/comments/moderation.comments.page'; import { PageModerationEntries } from './pages/moderation/entries/moderation.entries.page'; -import { PageNew } from './pages/new/new.page'; import { PageNotFound } from './pages/notfound/notfound.page' import { PageSettings } from './pages/settings/settings.page'; -import { PageTop } from './pages/top/top.page'; import { PageUnavailable } from './pages/unavailable/unavailable.page' import { PageUser } from './pages/user/user.page'; import { PageUserComments } from './pages/user/usercomments/usercomments.page'; @@ -52,6 +48,7 @@ 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'; +import { PageSearch } from './pages/search/search.page'; export function fetchI18n(i18n: I18nService) { @@ -84,7 +81,7 @@ export class XhrInterceptor implements HttpInterceptor { @NgModule({ declarations: [ AutofocusDirective, - I18nPipe, + I18nPipe, I18nEmptyPipe, MomentPipe, UrlBasePipe, UrlTextPipe, @@ -94,15 +91,12 @@ export class XhrInterceptor implements HttpInterceptor { PageEntry, PageEntryEdit, PageEntries, - PageHot, - PageLast, PageLogin, PageModerationComments, PageModerationEntries, - PageNew, PageNotFound, + PageSearch, PageSettings, - PageTop, PageUnavailable, PageUser, PageUserComments, PageUserEntries, PageUserPage, diff --git a/src/app/pages/entries/entries.page.html b/src/app/pages/entries/entries.page.html index 3f210c1..475598d 100644 --- a/src/app/pages/entries/entries.page.html +++ b/src/app/pages/entries/entries.page.html @@ -1,2 +1,2 @@ \ No newline at end of file + [gravityFilter]="gravityFilter" [text]="text"> \ 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 a8cbc29..fef4091 100644 --- a/src/app/pages/entries/entries.page.ts +++ b/src/app/pages/entries/entries.page.ts @@ -13,6 +13,7 @@ export class PageEntries implements OnInit, OnDestroy { @Input() fetch: Function; @Input() filter: boolean = true; + @Input() text: boolean = false; @Input() gravityFilter: boolean = false; entries: any; asc: boolean = false; @@ -114,7 +115,7 @@ export class PageEntries implements OnInit, OnDestroy { this.entries = data; this.entries.filter = filter; }, (error) => { - this.entries = {}; + this.entries = { error: error }; }) } diff --git a/src/app/pages/entry/entry.page.html b/src/app/pages/entry/entry.page.html index 1598164..d89a53a 100644 --- a/src/app/pages/entry/entry.page.html +++ b/src/app/pages/entry/entry.page.html @@ -1,9 +1,7 @@
- - -

+ diff --git a/src/app/pages/entry/entry.page.scss b/src/app/pages/entry/entry.page.scss index 4584f54..e69de29 100644 --- a/src/app/pages/entry/entry.page.scss +++ b/src/app/pages/entry/entry.page.scss @@ -1,4 +0,0 @@ -.text { - max-width: 100%; - white-space: break-spaces; -} diff --git a/src/app/pages/hot/hot.page.html b/src/app/pages/hot/hot.page.html deleted file mode 100644 index 49dce6b..0000000 --- a/src/app/pages/hot/hot.page.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/pages/hot/hot.page.ts b/src/app/pages/hot/hot.page.ts deleted file mode 100644 index b4eb208..0000000 --- a/src/app/pages/hot/hot.page.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -import { Router, ActivatedRoute } from '@angular/router'; - -import { EntriesService } from '../../services/entries.service'; -import { PageEvent } from '@angular/material/paginator'; - -@Component({ - selector: 'page-hot', - templateUrl: './hot.page.html' -}) -export class PageHot implements OnInit { - - boundFetch: Function; - - constructor(private entriesService: EntriesService) { } - - ngOnInit(): void { - this.boundFetch = this.fetch.bind(this); - } - - 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.html b/src/app/pages/last/last.page.html deleted file mode 100644 index 9d79ea7..0000000 --- a/src/app/pages/last/last.page.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/pages/last/last.page.ts b/src/app/pages/last/last.page.ts deleted file mode 100644 index 813b856..0000000 --- a/src/app/pages/last/last.page.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -import { EntriesService } from '../../services/entries.service'; - -@Component({ - selector: 'page-last', - templateUrl: './last.page.html' -}) -export class PageLast implements OnInit { - - boundFetch: Function; - - constructor(private entriesService: EntriesService) { } - - ngOnInit(): void { - this.boundFetch = this.fetch.bind(this); - } - - fetch(page: number, size: number,asc: boolean, filter: any) { - return this.entriesService.getLastComment(page, size,asc, filter); - } - -} diff --git a/src/app/pages/new/new.page.html b/src/app/pages/new/new.page.html deleted file mode 100644 index 9d79ea7..0000000 --- a/src/app/pages/new/new.page.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/pages/new/new.page.ts b/src/app/pages/new/new.page.ts deleted file mode 100644 index 53887b8..0000000 --- a/src/app/pages/new/new.page.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { Router, ActivatedRoute } from '@angular/router'; -import { PageEvent } from '@angular/material/paginator'; - -import { EntriesService } from '../../services/entries.service'; - -@Component({ - selector: 'page-new', - templateUrl: './new.page.html' -}) -export class PageNew implements OnInit { - - boundFetch: Function; - - constructor(private entriesService: EntriesService) { } - - ngOnInit(): void { - this.boundFetch = this.fetch.bind(this); - } - - fetch(page: number, size: number, asc: boolean, filter: any) { - return this.entriesService.getNew(page, size, asc, filter); - } - -} diff --git a/src/app/pages/search/search.page.html b/src/app/pages/search/search.page.html new file mode 100644 index 0000000..dbebd83 --- /dev/null +++ b/src/app/pages/search/search.page.html @@ -0,0 +1,103 @@ +
+
+ + {{'search.query' | i18n}} + + + + + + + {{'search.types.' + searchType + '.icon' | i18n}} {{'search.types.' + + searchType | i18n}} + + + + + {{'search.types.' + type + '.icon' | i18n}} {{'search.types.' + type | i18n}} + + + {{'search.types.all' | i18n}} + + + + + + + + {{'search.byDate.' + byDate + '.icon' | i18n}} {{'search.byDate.' + + byDate | i18n}} + + + {{'search.byDate.false.icon' | i18n}} + {{'search.byDate.false' | i18n}} + + + {{'search.byDate.true.icon' | i18n}} + {{'search.byDate.true' | i18n}} + + + + + + + {{'search.asc.' + asc + '.icon' | i18n}} {{'search.asc.' + + asc | i18n}} + + + {{'search.asc.false.icon' | i18n}} + {{'search.asc.false' | i18n}} + + + {{'search.asc.true.icon' | i18n}} + {{'search.asc.true' | i18n}} + + + +
+ + + +
+ + + {{ 'search.error.' + results.error.status | i18n}} + {{'search.error' | i18n}} + + +

+ {{ 'search.error.' + results.error.status + '.text' | i18n}} +

+
+
+
+ +
+ + + + + + + + + + + + + +

{{'search.nothing' | i18n}}

+
+
+ + + + +
+ +
\ No newline at end of file diff --git a/src/app/pages/search/search.page.scss b/src/app/pages/search/search.page.scss new file mode 100644 index 0000000..4322c08 --- /dev/null +++ b/src/app/pages/search/search.page.scss @@ -0,0 +1,61 @@ +.results { + height: 100%; +} + +mat-list mat-list-item { + height: auto; +} + +mat-form-field { + margin-right: 15px; +} + +.container { + margin-bottom: 0; +} + +mat-form-field .mat-form-field-wrapper { + padding-bottom: 0; +} + +.entry { + display: inline-block; + width: 100%; + max-width: 100%; +} + +.entry-item { + height: auto; + min-height: 48px; +} + +mat-chip mat-icon.mat-icon-inline { + margin-top: -12px; + margin-right: -2px; +} + +.mat-option .mat-icon { + margin-right: -2px; +} + +ui-tagspicker { + 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%; + } +} diff --git a/src/app/pages/search/search.page.ts b/src/app/pages/search/search.page.ts new file mode 100644 index 0000000..5524a71 --- /dev/null +++ b/src/app/pages/search/search.page.ts @@ -0,0 +1,109 @@ +import { Component, OnInit, ViewChild } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { PageEvent } from '@angular/material/paginator'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Subscription } from 'rxjs'; +import { debounceTime } from 'rxjs/operators'; +import { SearchService } from 'src/app/services/search.service'; +import { SettingsService } from 'src/app/services/settings.service'; + +@Component({ + selector: 'page-search', + templateUrl: './search.page.html', + styleUrls: [ './search.page.scss' ] +}) +export class PageSearch implements OnInit { + + searchFormControl = new FormControl(); + pageSizeOptions: number[] = [ 1, 2, 3, 4, 5, 10, 15, 30, 50, 100 ]; + results: any; + asc: boolean = false; + byDate: boolean = false; + settings: any; + settingsSubscription: Subscription; + boundRefresh: Function; + types: string[] = [ 'all', 'entry', 'comment' ]; + searchType: string = this.types[ 1 ]; + + constructor( + private searchService: SearchService, + private settingsService: SettingsService, + private router: Router, + private route: ActivatedRoute) { } + + ngOnInit(): void { + this.boundRefresh = this.refresh.bind(this); + this.asc = this.route.snapshot.queryParamMap.get('asc') == 'true'; + this.byDate = this.route.snapshot.queryParamMap.get('byDate') == 'true'; + this.searchType = this.route.snapshot.queryParamMap.get('type') || this.types[ 1 ]; + this.searchFormControl.setValue(this.route.snapshot.queryParamMap.get('q')); + this.searchFormControl.valueChanges.pipe( + debounceTime(300)).subscribe((value: string) => { + this.refresh(); + }) + + this.settingsSubscription = this.settingsService.settings.subscribe((settings) => { + this.settings = settings; + this.refresh(); + }) + } + + + ngOnDestroy(): void { + this.settingsSubscription.unsubscribe(); + } + + refresh(): void { + if (!this.results) { + this.results = {}; + } + + const params: any = { q: null, p: null }; + params.q = this.searchFormControl.value; + params.asc = this.asc ? 'true' : undefined; + params.byDate = this.byDate ? 'true' : undefined; + params.type = this.searchType != 'entry' ? this.searchType : undefined; + + this.router.navigate( + [], + { + relativeTo: this.route, + queryParams: params, + queryParamsHandling: 'merge' + }); + + this.results.content = null; + this.searchService.search(this.searchFormControl.value || " ", this.searchType, 0, this.results.size || this.settings.pageSize, this.asc, this.byDate).subscribe((data: any) => { + this.results = data; + }, (error) => { + this.results = { error: error }; + }) + } + + update(event: PageEvent) { + this.results.content = null; + const params: any = { p: null, s: null }; + + if (event.pageIndex != 0) { + params.p = event.pageIndex + 1; + } + + if (event.pageSize != this.settings.pageSize) { + params.s = event.pageSize; + } + + this.router.navigate( + [], + { + relativeTo: this.route, + queryParams: params, + queryParamsHandling: 'merge' + }); + + this.searchService.search(this.searchFormControl.value, this.searchType, event.pageIndex, event.pageSize, this.asc, this.byDate).subscribe((data: any) => { + this.results = data; + }, (error) => { + this.results = { error: error }; + }) + } +} diff --git a/src/app/pages/settings/settings.page.ts b/src/app/pages/settings/settings.page.ts index 76ca70e..34a392e 100644 --- a/src/app/pages/settings/settings.page.ts +++ b/src/app/pages/settings/settings.page.ts @@ -1,5 +1,5 @@ -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormGroup, Validators, NgForm } from '@angular/forms'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { UserService } from '../../services/user.service'; import { SettingsService } from 'src/app/services/settings.service'; @@ -18,7 +18,6 @@ export class PageSettings implements OnInit, OnDestroy { success: boolean = false; form: FormGroup; settings: any; - @ViewChild('formDirective') private formDirective: NgForm; settingsSubscription: Subscription; constructor( diff --git a/src/app/pages/top/top.page.html b/src/app/pages/top/top.page.html deleted file mode 100644 index 49dce6b..0000000 --- a/src/app/pages/top/top.page.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/pages/top/top.page.ts b/src/app/pages/top/top.page.ts deleted file mode 100644 index 9e86c1d..0000000 --- a/src/app/pages/top/top.page.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -import { EntriesService } from '../../services/entries.service'; - -@Component({ - selector: 'page-top', - templateUrl: './top.page.html' -}) -export class PageTop implements OnInit { - - boundFetch: Function; - - constructor(private entriesService: EntriesService) { } - - ngOnInit(): void { - this.boundFetch = this.fetch.bind(this); - } - - fetch(page: number, size: number, asc: boolean, filter: any) { - return this.entriesService.getRanked(page, size, asc, filter); - } - -} diff --git a/src/app/pages/userpage/edit/edit.page.html b/src/app/pages/userpage/edit/edit.page.html index c09c562..dd0dc1d 100644 --- a/src/app/pages/userpage/edit/edit.page.html +++ b/src/app/pages/userpage/edit/edit.page.html @@ -50,6 +50,15 @@ + + + +
+ {{'userpages.index.error.' + error.key | i18n}}
+
+
+
+