search prep, refactor userpages
This commit is contained in:
parent
c2b29317c3
commit
d75fa5fe59
@ -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 ] },
|
||||
]
|
||||
},
|
||||
|
@ -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,
|
||||
|
@ -1,2 +1,2 @@
|
||||
<ui-entries [entries]="entries" [refresh]="boundRefresh" [update]="boundUpdate" [filter]="filter"
|
||||
[gravityFilter]="gravityFilter"></ui-entries>
|
||||
[gravityFilter]="gravityFilter" [text]="text"></ui-entries>
|
@ -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 };
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
<div class="container">
|
||||
<page-notfound *ngIf="notfound"></page-notfound>
|
||||
<ng-container *ngIf="entry">
|
||||
<ui-entry [entry]="entry" [change]="boundRefresh" [linkedTag]="false"></ui-entry>
|
||||
|
||||
<p class="text" [innerHTML]="entry.text | urltext"></p>
|
||||
<ui-entry [entry]="entry" [change]="boundRefresh" [linkedTag]="false" [text]="true"></ui-entry>
|
||||
|
||||
<ui-commentform [target]="entry.id" (replyCommentEvent)="replyCallback($event)"></ui-commentform>
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
.text {
|
||||
max-width: 100%;
|
||||
white-space: break-spaces;
|
||||
}
|
@ -1 +0,0 @@
|
||||
<page-entries [fetch]="boundFetch" [gravityFilter]="true"></page-entries>
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -1 +0,0 @@
|
||||
<page-entries [fetch]="boundFetch"></page-entries>
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -1 +0,0 @@
|
||||
<page-entries [fetch]="boundFetch"></page-entries>
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
103
src/app/pages/search/search.page.html
Normal file
103
src/app/pages/search/search.page.html
Normal file
@ -0,0 +1,103 @@
|
||||
<div fxLayout="column" fxFlexFill>
|
||||
<div class="container">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>{{'search.query' | i18n}}</mat-label>
|
||||
<input matInput [formControl]="searchFormControl">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-select placeholder="{{'search.types' | i18n}}" [value]="searchType"
|
||||
(selectionChange)="searchType = $event.value; refresh()">
|
||||
<mat-select-trigger>
|
||||
<span *ngIf="searchType">
|
||||
<mat-icon>{{'search.types.' + searchType + '.icon' | i18n}}</mat-icon> {{'search.types.' +
|
||||
searchType | i18n}}
|
||||
</span>
|
||||
</mat-select-trigger>
|
||||
<mat-option *ngFor="let type of types" [value]="type">
|
||||
<span *ngIf="type">
|
||||
<mat-icon>{{'search.types.' + type + '.icon' | i18n}}</mat-icon> {{'search.types.' + type | i18n}}
|
||||
</span>
|
||||
<span *ngIf="!type">
|
||||
{{'search.types.all' | i18n}}
|
||||
</span>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-select placeholder="{{'search.byDate' | i18n}}" [value]="byDate" (selectionChange)="byDate = $event.value; refresh()">
|
||||
<mat-select-trigger>
|
||||
<mat-icon>{{'search.byDate.' + byDate + '.icon' | i18n}}</mat-icon> {{'search.byDate.' +
|
||||
byDate | i18n}}
|
||||
</mat-select-trigger>
|
||||
<mat-option [value]="false">
|
||||
<mat-icon>{{'search.byDate.false.icon' | i18n}}</mat-icon>
|
||||
{{'search.byDate.false' | i18n}}
|
||||
</mat-option>
|
||||
<mat-option [value]="true">
|
||||
<mat-icon>{{'search.byDate.true.icon' | i18n}}</mat-icon>
|
||||
{{'search.byDate.true' | i18n}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-select placeholder="{{'search.asc' | i18n}}" [value]="asc" (selectionChange)="asc = $event.value; refresh()">
|
||||
<mat-select-trigger>
|
||||
<mat-icon>{{'search.asc.' + asc + '.icon' | i18n}}</mat-icon> {{'search.asc.' +
|
||||
asc | i18n}}
|
||||
</mat-select-trigger>
|
||||
<mat-option [value]="false">
|
||||
<mat-icon>{{'search.asc.false.icon' | i18n}}</mat-icon>
|
||||
{{'search.asc.false' | i18n}}
|
||||
</mat-option>
|
||||
<mat-option [value]="true">
|
||||
<mat-icon>{{'search.asc.true.icon' | i18n}}</mat-icon>
|
||||
{{'search.asc.true' | i18n}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<mat-progress-bar *ngIf="!results || !results.content && !results.error" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
<div *ngIf="results && results.error" fxLayout="column" fxFlexFill>
|
||||
<mat-card class="accent box">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ 'search.error.' + results.error.status | i18n}}</mat-card-title>
|
||||
<mat-card-subtitle>{{'search.error' | i18n}}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>
|
||||
{{ 'search.error.' + results.error.status + '.text' | i18n}}
|
||||
</p>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
<div class="results" *ngIf="results" fxLayout="column">
|
||||
<mat-list *ngIf="results.content">
|
||||
<ng-container *ngFor="let result of results.content; let i = index">
|
||||
<mat-divider *ngIf="i > 0"></mat-divider>
|
||||
<mat-list-item>
|
||||
<ui-entry *ngIf="result.type == 'entry'" class="entry" [entry]="result"
|
||||
[index]="i+1 + results.number*results.size" [change]="boundRefresh" [text]="true" [actions]="false">
|
||||
</ui-entry>
|
||||
<ui-comment *ngIf="result.type == 'comment'" class="comment" [comment]="result"
|
||||
[index]="i+1 + results.number*results.size" [change]="boundRefresh" [subcomments]="false"
|
||||
[parentLink]="true" [actions]="false"></ui-comment>
|
||||
</mat-list-item>
|
||||
</ng-container>
|
||||
</mat-list>
|
||||
|
||||
<mat-list *ngIf="results.totalElements == 0">
|
||||
<mat-list-item>
|
||||
<p>{{'search.nothing' | i18n}}</p>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
|
||||
<span fxFlexOffset="auto" fxFlexOffset.xs="none"></span>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" [pageIndex]="results.number" [length]="results.totalElements"
|
||||
[pageSize]="results.size" (page)="update && update($event)" showFirstLastButtons>
|
||||
</mat-paginator>
|
||||
</div>
|
||||
|
||||
</div>
|
61
src/app/pages/search/search.page.scss
Normal file
61
src/app/pages/search/search.page.scss
Normal file
@ -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%;
|
||||
}
|
||||
}
|
109
src/app/pages/search/search.page.ts
Normal file
109
src/app/pages/search/search.page.ts
Normal file
@ -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 };
|
||||
})
|
||||
}
|
||||
}
|
@ -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(
|
||||
|
@ -1 +0,0 @@
|
||||
<page-entries [fetch]="boundFetch" [gravityFilter]="true"></page-entries>
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -50,6 +50,15 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="{{'userpages.index' | i18n}}" formControlName="index" type="number" min="0">
|
||||
<mat-error *ngIf="hasError('index')">
|
||||
<div *ngFor="let error of form.get('index').errors | keyvalue">
|
||||
{{'userpages.index.error.' + error.key | i18n}}<br>
|
||||
</div>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
</mat-card-content>
|
||||
<mat-card-actions fxLayout="row wrap" fxFlexFill>
|
||||
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
|
||||
@ -58,9 +67,11 @@
|
||||
<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> {{
|
||||
<a mat-raised-button color="warn" *ngIf="!working && userpage.id" (click)="deleteUserPage()">
|
||||
<mat-icon>delete</mat-icon> {{
|
||||
'userpages.delete' |
|
||||
i18n}}</a>
|
||||
i18n}}
|
||||
</a>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</form>
|
||||
|
@ -27,6 +27,7 @@ export class PageUserPageEdit implements OnInit, OnDestroy {
|
||||
working: boolean = false;
|
||||
form: FormGroup;
|
||||
settings: any;
|
||||
index: number;
|
||||
|
||||
settingsSubscription: Subscription;
|
||||
|
||||
@ -45,12 +46,17 @@ export class PageUserPageEdit implements OnInit, OnDestroy {
|
||||
name: [ '', Validators.required ],
|
||||
entryType: [ '', Validators.nullValidator ],
|
||||
sorting: [ '', Validators.required ],
|
||||
index: [ '', Validators.required ],
|
||||
});
|
||||
|
||||
this.settingsSubscription = this.settingsService.settings.subscribe((settings) => {
|
||||
this.settings = settings;
|
||||
});
|
||||
|
||||
if (this.route.snapshot.queryParamMap.get('name')) {
|
||||
this.form.get('name').setValue(this.route.snapshot.queryParamMap.get('name'));
|
||||
}
|
||||
|
||||
this.form.get('entryType').setValue(this.entryType);
|
||||
this.form.get('entryType').valueChanges.subscribe((value) => {
|
||||
this.entryType = value;
|
||||
@ -59,6 +65,10 @@ export class PageUserPageEdit implements OnInit, OnDestroy {
|
||||
this.form.get('sorting').valueChanges.subscribe((value) => {
|
||||
this.sorting = value;
|
||||
});
|
||||
this.form.get('index').setValue(this.index);
|
||||
this.form.get('index').valueChanges.subscribe((value) => {
|
||||
this.index = value;
|
||||
});
|
||||
|
||||
this.name = this.route.snapshot.paramMap.get('name');
|
||||
this.refresh();
|
||||
@ -70,13 +80,10 @@ export class PageUserPageEdit implements OnInit, OnDestroy {
|
||||
|
||||
refresh() {
|
||||
if (this.name) {
|
||||
this.userPageService.getUserPage(this.name).subscribe((data) => {
|
||||
this.userPageService.getUserPage(this.name, undefined).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;
|
||||
@ -88,7 +95,13 @@ export class PageUserPageEdit implements OnInit, OnDestroy {
|
||||
this.userpage.sorting = this.sorting;
|
||||
this.userpage.tags = [];
|
||||
this.userpage.excludedTags = [];
|
||||
this.userpage.index = 99;
|
||||
}
|
||||
|
||||
this.form.get("name").setValue(this.userpage.name);
|
||||
this.form.get("entryType").setValue(this.userpage.entryType);
|
||||
this.form.get("sorting").setValue(this.userpage.sorting);
|
||||
this.form.get("index").setValue(this.userpage.index);
|
||||
}
|
||||
|
||||
hasError(controlName: string): boolean {
|
||||
@ -106,6 +119,7 @@ export class PageUserPageEdit implements OnInit, OnDestroy {
|
||||
this.userpage.name = this.form.get("name").value;
|
||||
this.userpage.entryType = this.entryType;
|
||||
this.userpage.sorting = this.sorting;
|
||||
this.userpage.index = this.index;
|
||||
|
||||
this.userPageService.createOrUpdate(this.userpage).subscribe((data) => {
|
||||
this.userpage = data;
|
||||
|
@ -1,8 +1,6 @@
|
||||
<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>
|
||||
<a mat-mini-fab routerLink="/p/{{name}}/edit" matTooltip="{{'userpages.edit' | i18n}}" color="primary">
|
||||
<mat-icon inline="true">edit</mat-icon>
|
||||
</a>
|
||||
<page-entries #entries [fetch]="boundFetch" fxFlex="grow"></page-entries>
|
||||
</div>
|
6
src/app/pages/userpage/userpage.page.scss
Normal file
6
src/app/pages/userpage/userpage.page.scss
Normal file
@ -0,0 +1,6 @@
|
||||
a.mat-mini-fab {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
right: 15px;
|
||||
z-index: 5;
|
||||
}
|
@ -1,13 +1,15 @@
|
||||
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { UserPageService } from 'src/app/services/userpage.service';
|
||||
|
||||
import { EntriesService } from '../../services/entries.service';
|
||||
import { PageEntries } from '../entries/entries.page';
|
||||
|
||||
@Component({
|
||||
selector: 'page-userpage',
|
||||
templateUrl: './userpage.page.html'
|
||||
templateUrl: './userpage.page.html',
|
||||
styleUrls: [ './userpage.page.scss' ]
|
||||
})
|
||||
export class PageUserPage implements OnInit, OnDestroy {
|
||||
|
||||
@ -19,6 +21,7 @@ export class PageUserPage implements OnInit, OnDestroy {
|
||||
|
||||
constructor(
|
||||
private entriesService: EntriesService,
|
||||
private userPageService: UserPageService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute) {
|
||||
}
|
||||
@ -27,9 +30,14 @@ export class PageUserPage implements OnInit, OnDestroy {
|
||||
this.paramsSub = this.route.params.subscribe((params: Params) => {
|
||||
this.name = params[ 'name' ];
|
||||
this.username = params[ 'username' ];
|
||||
if (this.entries) {
|
||||
this.entries.refresh();
|
||||
}
|
||||
|
||||
this.userPageService.getUserPage(this.name, this.username).subscribe((data) => {
|
||||
if (this.entries) {
|
||||
this.entries.refresh();
|
||||
}
|
||||
}, (error) => {
|
||||
this.router.navigate([ '/p' ], { queryParams: { name: this.name }, queryParamsHandling: 'merge' });
|
||||
})
|
||||
});
|
||||
this.boundFetch = this.fetch.bind(this);
|
||||
}
|
||||
@ -40,7 +48,12 @@ export class PageUserPage implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
fetch(page: number, size: number, asc: boolean, filter: any) {
|
||||
return this.entriesService.getByUserPage(this.name, page, size, asc, this.username);
|
||||
if (this.username) {
|
||||
filter = filter || {};
|
||||
filter.username = this.username;
|
||||
}
|
||||
|
||||
return this.entriesService.getByUserPage(this.name, page, size, asc, filter);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,30 +34,18 @@ export class EntriesService {
|
||||
return this.http.get(environment.apiUrl + "/entries" + path, { params: httpParams });
|
||||
}
|
||||
|
||||
getRanked(page: number, size: number, asc: boolean, filter: any) {
|
||||
return this.fetch("", page, size, asc, filter);
|
||||
}
|
||||
|
||||
getNew(page: number, size: number, asc: boolean, filter: any) {
|
||||
return this.fetch("/new", page, size, asc, filter);
|
||||
}
|
||||
|
||||
getComments(page: number, size: number, asc: boolean, filter: any) {
|
||||
return this.fetch("/comments", page, size, asc, filter);
|
||||
}
|
||||
|
||||
getLastComment(page: number, size: number, asc: boolean, filter: any) {
|
||||
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);
|
||||
getByUserPage(name: string, page: number, size: number, asc: boolean, filter: any) {
|
||||
return this.fetch("/" + name, page, size, asc, filter);
|
||||
}
|
||||
|
||||
getByUser(username: string, page: number, size: number, asc: boolean, filter: any) {
|
||||
return this.fetch("/byuser/" + username, page, size, asc, filter);
|
||||
}
|
||||
|
||||
search(query: string, page: number, size: number, asc: boolean, byDate: boolean) {
|
||||
return this.fetch("/search", page, size, asc, { q: query, byDate: byDate });
|
||||
}
|
||||
|
||||
getEntry(id: number) {
|
||||
return this.http.get(environment.apiUrl + "/entries/entry/" + id);
|
||||
}
|
||||
|
@ -65,30 +65,34 @@ export class I18nService {
|
||||
}
|
||||
|
||||
get(key, args: string[]): string {
|
||||
return this.getInternal(key, args, this.i18n, "");
|
||||
return this.getInternal(key, args, this.i18n, "", true);
|
||||
}
|
||||
|
||||
getInternal(key, args: string[], from, path): string {
|
||||
getEmpty(key, args: string[]): string {
|
||||
return this.getInternal(key, args, this.i18n, "", false);
|
||||
}
|
||||
|
||||
getInternal(key, args: string[], from, path, empty : boolean): string {
|
||||
key += '';
|
||||
if (!from) {
|
||||
return this.empty(key, args, path);
|
||||
return empty ? this.empty(key, args, path) : (key || "");
|
||||
} else if (from[ key ]) {
|
||||
if (typeof from[ key ] === 'object') {
|
||||
if (from[ key ][ "." ]) {
|
||||
return this.insertArguments(from[ key ][ "." ], args);
|
||||
}
|
||||
return this.empty(key, args, path);
|
||||
return empty ? this.empty(key, args, path) : (key || "");
|
||||
}
|
||||
return this.insertArguments(from[ key ], args);
|
||||
} else {
|
||||
let keys = key.split(".");
|
||||
if (from[ keys[ 0 ] ]) {
|
||||
key = keys.slice(1, keys.length).join(".");
|
||||
return this.getInternal(key, args, from[ keys[ 0 ] ], path + keys[ 0 ] + ".")
|
||||
return this.getInternal(key, args, from[ keys[ 0 ] ], path + keys[ 0 ] + ".", empty)
|
||||
}
|
||||
}
|
||||
|
||||
return this.empty(key, args, path);
|
||||
return empty ? this.empty(key, args, path) : (key || "");
|
||||
}
|
||||
|
||||
empty(key, args: string[], path: string): string {
|
||||
|
39
src/app/services/search.service.ts
Normal file
39
src/app/services/search.service.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class SearchService {
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
search(query: string, type: string, page: number, size: number, asc: boolean, byDate: boolean) {
|
||||
|
||||
let httpParams = new HttpParams();
|
||||
|
||||
httpParams = httpParams.set("q", "" + query);
|
||||
|
||||
if (type != undefined) {
|
||||
httpParams = httpParams.set("type", "" + type);
|
||||
}
|
||||
|
||||
if (page != undefined) {
|
||||
httpParams = httpParams.set("page", "" + page);
|
||||
}
|
||||
if (size != undefined) {
|
||||
httpParams = httpParams.set("size", "" + size);
|
||||
}
|
||||
if (asc) {
|
||||
httpParams = httpParams.set("asc", "" + asc);
|
||||
}
|
||||
if (byDate) {
|
||||
httpParams = httpParams.set("byDate", "" + byDate);
|
||||
}
|
||||
|
||||
return this.http.get(environment.apiUrl + "/search", { params: httpParams });
|
||||
}
|
||||
|
||||
}
|
@ -38,8 +38,13 @@ export class UserPageService {
|
||||
return this.http.get(environment.apiUrl + "/userpages/public", { params: httpParams });
|
||||
}
|
||||
|
||||
getUserPage(name: string) {
|
||||
return this.http.get(environment.apiUrl + "/userpages/userpage/" + name);
|
||||
getUserPage(name: string, username: string) {
|
||||
let httpParams = new HttpParams();
|
||||
if (username != undefined) {
|
||||
httpParams = httpParams.set("user", "" + username);
|
||||
}
|
||||
|
||||
return this.http.get(environment.apiUrl + "/userpages/userpage/" + name, { params: httpParams });
|
||||
}
|
||||
|
||||
createOrUpdate(userPage: any) {
|
||||
|
@ -1,8 +1,9 @@
|
||||
<div class="comment">
|
||||
<div mat-line>
|
||||
<mat-icon color="warn" *ngIf="comment.flaggedStatus == 'FLAGGED'">outlined_flag</mat-icon>
|
||||
<span *ngIf="index">{{index}}. </span>
|
||||
<small>
|
||||
<ng-container *ngIf="comment.metadata && !comment.metadata.unvote">
|
||||
<ng-container *ngIf="comment.metadata && !comment.metadata.unvote && actions">
|
||||
<a href="javascript:" (click)="voteUp(comment.id)" matTooltip="{{'vote.up' | i18n}}">
|
||||
<mat-icon inline="true">thumb_up</mat-icon>
|
||||
</a>
|
||||
@ -26,7 +27,7 @@
|
||||
routerLink="/c/{{comment.parent}}">{{'comment' | i18n}}</a></span>
|
||||
<span *ngIf="comment.metadata && comment.metadata.entry"> {{'comment.on' | i18n}} <a class="entry"
|
||||
routerLink="/e/{{comment.target}}">{{comment.metadata.entry || 'entry'}}</a></span>
|
||||
<span *ngIf="comment.metadata && comment.metadata.unvote"> | </span>
|
||||
<span *ngIf="comment.metadata && comment.metadata.unvote && actions"> | </span>
|
||||
<a *ngIf="comment.metadata.unvote" href="javascript:" (click)="unvote()">{{'comment.unvote' | i18n}}</a>
|
||||
<span *ngIf="comment.metadata && comment.metadata.flag"> | </span>
|
||||
<a *ngIf="comment.metadata && comment.metadata.flag" href="javascript:" (click)="flag(comment.id)" matTooltip="{{'comment.flag' |
|
||||
@ -46,7 +47,7 @@
|
||||
[style.opacity]="comment.metadata && comment.metadata.points && comment.metadata.points < 0 ? 1 + (comment.metadata.points / 10) : '1.0'"
|
||||
[innerHTML]="comment.text | urltext"></div>
|
||||
<div mat-line>
|
||||
<small>
|
||||
<small *ngIf="actions">
|
||||
<a href="javascript:" (click)="comment.metadata.reply=!comment.metadata.reply">{{(comment.metadata.reply ?
|
||||
'comment.replyHide' : 'comment.reply') | i18n}}</a>
|
||||
<span *ngIf="canEdit()"> | </span>
|
||||
|
@ -9,7 +9,7 @@ small a:not(.entry):hover {
|
||||
}
|
||||
|
||||
.text {
|
||||
white-space: break-spaces;
|
||||
white-space: break-spaces !important;
|
||||
}
|
||||
|
||||
span.voted {
|
||||
|
@ -21,14 +21,23 @@ export class UiComment implements OnInit {
|
||||
author: boolean = false;
|
||||
moderator: boolean = false;
|
||||
@Input() comment: any;
|
||||
@Input() index: number;
|
||||
@Input() change: Function;
|
||||
@Input() ignore: string[] = [];
|
||||
@Input() subcomments: boolean = false;
|
||||
@Input() parentLink: boolean = false;
|
||||
@Input() actions: boolean = true;
|
||||
@ViewChild('subcomments') comments: UiComments;
|
||||
form: FormGroup;
|
||||
|
||||
constructor(private authService: AuthService, private commentService: CommentService, private voteService: VoteService, private flagService: FlagService, private formBuilder: FormBuilder, private moderationService: ModerationService, public dialog: MatDialog) { }
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private commentService: CommentService,
|
||||
private voteService: VoteService,
|
||||
private flagService: FlagService,
|
||||
private formBuilder: FormBuilder,
|
||||
private moderationService: ModerationService,
|
||||
public dialog: MatDialog) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.authService.auth.subscribe((auth: any) => {
|
||||
@ -74,16 +83,38 @@ export class UiComment implements OnInit {
|
||||
}
|
||||
|
||||
flag() {
|
||||
this.flagService.flagComment(this.comment.id).subscribe((result) => {
|
||||
this.comment.metadata.flag = false;
|
||||
this.comment.metadata.unflag = true;
|
||||
const dialogRef = this.dialog.open(ConfirmDialog, {
|
||||
data: {
|
||||
'label': 'comment.confirmFlag',
|
||||
'args': [ this.comment.text, this.comment.author ]
|
||||
}
|
||||
})
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.flagService.flagComment(this.comment.id).subscribe((result) => {
|
||||
this.comment.metadata.flag = false;
|
||||
this.comment.metadata.unflag = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
unflag() {
|
||||
this.flagService.unflagComment(this.comment.id).subscribe((result) => {
|
||||
this.comment.metadata.flag = true;
|
||||
this.comment.metadata.unflag = false;
|
||||
const dialogRef = this.dialog.open(ConfirmDialog, {
|
||||
data: {
|
||||
'label': 'comment.confirmUnflag',
|
||||
'args': [ this.comment.text, this.comment.author ]
|
||||
}
|
||||
})
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.flagService.unflagComment(this.comment.id).subscribe((result) => {
|
||||
this.comment.metadata.flag = true;
|
||||
this.comment.metadata.unflag = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,8 @@
|
||||
<ng-container *ngFor="let entry of entries.content; let i = index">
|
||||
<mat-divider *ngIf="i > 0"></mat-divider>
|
||||
<mat-list-item class="entry-item">
|
||||
<ui-entry class="entry" [entry]="entry" [index]="i+1 + entries.number*entries.size" [change]="refresh">
|
||||
<ui-entry class="entry" [entry]="entry" [index]="i+1 + entries.number*entries.size" [change]="refresh"
|
||||
[text]="text">
|
||||
</ui-entry>
|
||||
</mat-list-item>
|
||||
</ng-container>
|
||||
@ -36,7 +37,8 @@
|
||||
|
||||
<div class="mat-paginator" fxLayout="row" fxLayout.xs="column" fxLayoutAlign.xs="start start">
|
||||
<div *ngIf="filter" class="filter-container">
|
||||
<a mat-icon-button mat-button (click)="filterOpen=!filterOpen" title="{{'entries.filter' | i18n}}" [color]="filterOpen ? 'accent' : 'primary'">
|
||||
<a mat-icon-button mat-button (click)="filterOpen=!filterOpen" title="{{'entries.filter' | i18n}}"
|
||||
[color]="filterOpen ? 'accent' : 'primary'">
|
||||
<mat-icon>filter_alt</mat-icon>
|
||||
</a>
|
||||
<div *ngIf="filterOpen" fxLayout="row wrap">
|
||||
@ -73,7 +75,8 @@
|
||||
</mat-form-field>
|
||||
|
||||
|
||||
<ui-tagspicker [(model)]="excludedTags" placeholder="{{'entries.filter.excludedTags' | i18n}}" [change]="boundExcludedTagsPickerChange">
|
||||
<ui-tagspicker [(model)]="excludedTags" placeholder="{{'entries.filter.excludedTags' | i18n}}"
|
||||
[change]="boundExcludedTagsPickerChange">
|
||||
</ui-tagspicker>
|
||||
|
||||
<mat-form-field *ngIf="gravityFilter">
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Component, OnInit, Input, ViewChild } from '@angular/core';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
@ -14,7 +13,7 @@ export class UiEntries implements OnInit {
|
||||
@Input() refresh: Function;
|
||||
@Input() gravityFilter: boolean = false;
|
||||
@Input() filter: boolean = true;
|
||||
@ViewChild(MatPaginator) matPaginator;
|
||||
@Input() text: boolean = false;
|
||||
pageSizeOptions: number[] = [ 1, 2, 3, 4, 5, 10, 15, 30, 50, 100 ];
|
||||
filterOpen: boolean = false;
|
||||
searchTags: Observable<Object>;
|
||||
|
@ -6,21 +6,21 @@
|
||||
<a class="title" *ngIf="!entry.url" routerLink="/e/{{entry.id}}">{{entry.title}}</a>
|
||||
<span *ngIf="entry.url" class="urlbase">(<a [href]="entry.url">{{entry.url | urlbase}}</a>)</span>
|
||||
<a *ngFor="let tag of entry.tags" class="tag" (click)="applyTag(tag)">#{{tag}}</a>
|
||||
<a *ngIf="entry.metadata.author && !entry.metadata.edit" class="tags-edit tag"
|
||||
<a *ngIf="entry.metadata.author && !entry.metadata.edit && actions" class="tags-edit tag"
|
||||
routerLink="/e/{{entry.id}}/edit"><mat-icon inline="true">local_offer</mat-icon>{{'entry.edit.tags' | i18n}}</a>
|
||||
</div>
|
||||
<div mat-line>
|
||||
<small>
|
||||
<a *ngIf="entry.metadata && entry.metadata.vote" href="javascript:" (click)="voteUp(entry.id)"
|
||||
<a *ngIf="entry.metadata && entry.metadata.vote && actions" href="javascript:" (click)="voteUp(entry.id)"
|
||||
matTooltip="{{'vote.up' | i18n}}">
|
||||
<mat-icon inline="true">thumb_up</mat-icon>
|
||||
</a>
|
||||
<span *ngIf="entry.metadata && entry.metadata.vote"> </span>
|
||||
<a *ngIf="entry.metadata && entry.metadata.downvote" href="javascript:" (click)="voteDown(entry.id)"
|
||||
<span *ngIf="entry.metadata && entry.metadata.vote && actions"> </span>
|
||||
<a *ngIf="entry.metadata && entry.metadata.downvote && actions" href="javascript:" (click)="voteDown(entry.id)"
|
||||
matTooltip="{{'vote.down' | i18n}}">
|
||||
<mat-icon inline="true">thumb_down</mat-icon>
|
||||
</a>
|
||||
<span *ngIf="entry.metadata && entry.metadata.downvote"> </span>
|
||||
<span *ngIf="entry.metadata && entry.metadata.downvote && actions"> </span>
|
||||
<span class="voted" *ngIf="entry.metadata && entry.metadata.unvote">
|
||||
<mat-icon *ngIf="entry.metadata && entry.metadata.upvoted" inline="true">thumb_up</mat-icon>
|
||||
<mat-icon *ngIf="entry.metadata && entry.metadata.downvoted" inline="true">thumb_down</mat-icon>
|
||||
@ -34,20 +34,20 @@
|
||||
<span> | </span>
|
||||
<a routerLink="/e/{{entry.id}}">{{(entry.metadata && entry.metadata.comments == 1 ? 'entry.comment' :
|
||||
'entry.comments') | i18n:(entry.metadata && entry.metadata.comments)}}</a>
|
||||
<span *ngIf="entry.metadata.edit"> | </span>
|
||||
<a *ngIf="entry.metadata.edit" routerLink="/e/{{entry.id}}/edit">{{'entry.edit' | i18n}}</a>
|
||||
<span *ngIf="entry.metadata && entry.metadata.bookmark"> | </span>
|
||||
<a *ngIf="entry.metadata && entry.metadata.bookmark" href="javascript:" (click)="addBookmark()"
|
||||
<span *ngIf="entry.metadata.edit && actions"> | </span>
|
||||
<a *ngIf="entry.metadata.edit && actions" routerLink="/e/{{entry.id}}/edit">{{'entry.edit' | i18n}}</a>
|
||||
<span *ngIf="entry.metadata && entry.metadata.bookmark && actions"> | </span>
|
||||
<a *ngIf="entry.metadata && entry.metadata.bookmark && actions" href="javascript:" (click)="addBookmark()"
|
||||
matTooltip="{{'bookmarks.add' | i18n}}">
|
||||
<mat-icon inline="true">bookmark_border</mat-icon>
|
||||
</a>
|
||||
<span *ngIf="entry.metadata && entry.metadata.removeBookmark"> | </span>
|
||||
<a *ngIf="entry.metadata && entry.metadata.removeBookmark" href="javascript:" (click)="removeBookmark()"
|
||||
<span *ngIf="entry.metadata && entry.metadata.removeBookmark && actions"> | </span>
|
||||
<a *ngIf="entry.metadata && entry.metadata.removeBookmark && actions" href="javascript:" (click)="removeBookmark()"
|
||||
matTooltip="{{'bookmarks.remove' | i18n}}">
|
||||
<mat-icon inline="true">bookmark</mat-icon>
|
||||
</a>
|
||||
<span *ngIf="entry.metadata && entry.metadata.unvote"> | </span>
|
||||
<a *ngIf="entry.metadata && entry.metadata.unvote" href="javascript:" (click)="unvote(entry.id)">{{'entry.unvote' |
|
||||
<span *ngIf="entry.metadata && entry.metadata.unvote && actions"> | </span>
|
||||
<a *ngIf="entry.metadata && entry.metadata.unvote && actions" href="javascript:" (click)="unvote(entry.id)">{{'entry.unvote' |
|
||||
i18n}}</a>
|
||||
<span *ngIf="entry.metadata && entry.metadata.flag"> | </span>
|
||||
<a *ngIf="entry.metadata && entry.metadata.flag" href="javascript:" (click)="flag(entry.id)" matTooltip="{{'entry.flag' |
|
||||
@ -59,8 +59,8 @@
|
||||
i18n}}">
|
||||
<mat-icon inline="true">flag</mat-icon>
|
||||
</a>
|
||||
<span *ngIf="entry.metadata.edit"> | </span>
|
||||
<a *ngIf="entry.metadata.edit" href="javascript:" (click)="deleteEntry()">{{'entry.delete' | i18n}}</a>
|
||||
<span *ngIf="entry.metadata.edit && actions"> | </span>
|
||||
<a *ngIf="entry.metadata.edit && actions" href="javascript:" (click)="deleteEntry()">{{'entry.delete' | i18n}}</a>
|
||||
<span *ngIf="moderator" class="mod">
|
||||
<span *ngIf="entry.metadata.flagged"> | </span>
|
||||
<a *ngIf="entry.metadata.flagged" href="javascript:" (click)="modUnflagEntry()">{{'moderation.entry.unflag' |
|
||||
@ -69,4 +69,7 @@
|
||||
<a href="javascript:" (click)="modDeleteEntry()">{{'moderation.entry.delete' | i18n}}</a>
|
||||
</span>
|
||||
</small>
|
||||
</div>
|
||||
<div mat-line *ngIf="text">
|
||||
<p class="text" [innerHTML]="entry.text | urltext"></p>
|
||||
</div>
|
@ -97,3 +97,8 @@ span.mod {
|
||||
.tags-edit:hover.tag {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.text {
|
||||
max-width: 100%;
|
||||
white-space: break-spaces;
|
||||
}
|
||||
|
@ -21,10 +21,20 @@ export class UiEntry implements OnInit {
|
||||
@Input() entry: any;
|
||||
@Input() index: number;
|
||||
@Input() linkedTag: boolean = true;
|
||||
@Input() text: boolean = false;
|
||||
@Input() change: Function;
|
||||
@Input() actions: boolean = true;
|
||||
|
||||
constructor(private authService: AuthService, private entriesService: EntriesService, private voteService: VoteService, private flagService: FlagService,
|
||||
private moderationService: ModerationService, private bookmarksService: BookmarksService, public dialog: MatDialog, private router: Router, private route: ActivatedRoute) { }
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private entriesService: EntriesService,
|
||||
private voteService: VoteService,
|
||||
private flagService: FlagService,
|
||||
private moderationService: ModerationService,
|
||||
private bookmarksService: BookmarksService,
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.authService.auth.subscribe((auth: any) => {
|
||||
@ -84,16 +94,38 @@ export class UiEntry implements OnInit {
|
||||
}
|
||||
|
||||
flag() {
|
||||
this.flagService.flagEntry(this.entry.id).subscribe((result) => {
|
||||
this.entry.metadata.flag = false;
|
||||
this.entry.metadata.unflag = true;
|
||||
const dialogRef = this.dialog.open(ConfirmDialog, {
|
||||
data: {
|
||||
'label': 'entry.confirmFlag',
|
||||
'args': [ this.entry.title, this.entry.author ]
|
||||
}
|
||||
})
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.flagService.flagEntry(this.entry.id).subscribe((result) => {
|
||||
this.entry.metadata.flag = false;
|
||||
this.entry.metadata.unflag = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
unflag() {
|
||||
this.flagService.unflagEntry(this.entry.id).subscribe((result) => {
|
||||
this.entry.metadata.unflag = false;
|
||||
this.entry.metadata.flag = true;
|
||||
const dialogRef = this.dialog.open(ConfirmDialog, {
|
||||
data: {
|
||||
'label': 'entry.confirmUnflag',
|
||||
'args': [ this.entry.title, this.entry.author ]
|
||||
}
|
||||
})
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.flagService.unflagEntry(this.entry.id).subscribe((result) => {
|
||||
this.entry.metadata.unflag = false;
|
||||
this.entry.metadata.flag = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -42,19 +42,6 @@
|
||||
<mat-sidenav #sidenav [mode]="isBiggerScreen() ? 'side' : 'over'" [(opened)]="opened"
|
||||
(click)="!isBiggerScreen() && opened=false">
|
||||
<mat-nav-list>
|
||||
<a *ngIf="authenticated" routerLink="/top" routerLinkActive="active" mat-list-item>
|
||||
<mat-icon>{{'sorting.TOP.icon' | i18n}}</mat-icon> {{'sorting.TOP' | i18n}}
|
||||
</a>
|
||||
<a *ngIf="authenticated" routerLink="/new" routerLinkActive="active" mat-list-item>
|
||||
<mat-icon>{{'sorting.NEW.icon' | i18n}}</mat-icon> {{'sorting.NEW' | i18n}}
|
||||
</a>
|
||||
<mat-divider *ngIf="authenticated"></mat-divider>
|
||||
<a *ngIf="authenticated" routerLink="/hot" routerLinkActive="active" mat-list-item>
|
||||
<mat-icon>{{'sorting.HOT.icon' | i18n}}</mat-icon> {{'sorting.HOT' | i18n}}
|
||||
</a>
|
||||
<a *ngIf="authenticated" routerLink="/last" routerLinkActive="active" mat-list-item>
|
||||
<mat-icon>{{'sorting.LAST.icon' | i18n}}</mat-icon> {{'sorting.LAST' | i18n}}
|
||||
</a>
|
||||
<ui-userpagemenu *ngIf="authenticated"></ui-userpagemenu>
|
||||
<mat-divider *ngIf="moderator"></mat-divider>
|
||||
<a *ngIf="moderator" routerLink="/moderation/entries" routerLinkActive="active" mat-list-item>
|
||||
|
@ -1,8 +1,11 @@
|
||||
<ng-container *ngIf="settings">
|
||||
<ng-container *ngFor="let userpage of userpages">
|
||||
<mat-divider *ngIf="userpage.divider"></mat-divider>
|
||||
<a routerLink="/p/{{userpage.name}}" routerLinkActive="active" mat-list-item>
|
||||
<mat-icon>{{'sorting.' + userpage.sorting + '.icon' | i18n}}</mat-icon> {{'sorting.' + userpage.name | i18nEmpty}}
|
||||
</a>
|
||||
</ng-container>
|
||||
<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>
|
||||
|
@ -1,3 +1,3 @@
|
||||
mat-form-field {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
@ -15,4 +15,17 @@ export class I18nPipe implements PipeTransform {
|
||||
transform(value: String, ...args: any[]): String {
|
||||
return this.i18n.get(value, args);
|
||||
}
|
||||
}
|
||||
|
||||
@Pipe({
|
||||
name: 'i18nEmpty'
|
||||
})
|
||||
export class I18nEmptyPipe implements PipeTransform {
|
||||
|
||||
constructor(private i18n: I18nService) {
|
||||
}
|
||||
|
||||
transform(value: String, ...args: any[]): String {
|
||||
return this.i18n.getEmpty(value, args);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user