You've already forked pigallery2
mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-07-07 00:57:28 +02:00
Updating random photo query builder to use advanced search #58
This commit is contained in:
@ -154,15 +154,11 @@ export class GalleryMWs {
|
|||||||
|
|
||||||
|
|
||||||
public static async search(req: Request, res: Response, next: NextFunction) {
|
public static async search(req: Request, res: Response, next: NextFunction) {
|
||||||
if (Config.Client.Search.enabled === false || !req.query[QueryParams.gallery.search.query]) {
|
if (Config.Client.Search.enabled === false || !(req.params.searchQueryDTO)) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(req.params.text)) {
|
const query: SearchQueryDTO = JSON.parse(<any>req.params.searchQueryDTO);
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
const query: SearchQueryDTO = <any>req.query[QueryParams.gallery.search.query];
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await ObjectManagers.getInstance().SearchManager.search(query);
|
const result = await ObjectManagers.getInstance().SearchManager.search(query);
|
||||||
@ -199,11 +195,12 @@ export class GalleryMWs {
|
|||||||
|
|
||||||
|
|
||||||
public static async getRandomImage(req: Request, res: Response, next: NextFunction) {
|
public static async getRandomImage(req: Request, res: Response, next: NextFunction) {
|
||||||
if (Config.Client.RandomPhoto.enabled === false) {
|
if (Config.Client.RandomPhoto.enabled === false || !(req.params.searchQueryDTO)) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const query: SearchQueryDTO = <any>req.query[QueryParams.gallery.search.query];
|
const query: SearchQueryDTO = JSON.parse(<any>req.params.searchQueryDTO);
|
||||||
|
|
||||||
const photo = await ObjectManagers.getInstance()
|
const photo = await ObjectManagers.getInstance()
|
||||||
.SearchManager.getRandomPhoto(query);
|
.SearchManager.getRandomPhoto(query);
|
||||||
|
@ -450,6 +450,7 @@ export class SearchManager implements ISearchManager {
|
|||||||
textParam['CtextC' + paramCounter.value] = `%,${(<TextSearch>query).text},%`;
|
textParam['CtextC' + paramCounter.value] = `%,${(<TextSearch>query).text},%`;
|
||||||
textParam['Ctext' + paramCounter.value] = `%,${(<TextSearch>query).text}`;
|
textParam['Ctext' + paramCounter.value] = `%,${(<TextSearch>query).text}`;
|
||||||
textParam['textC' + paramCounter.value] = `${(<TextSearch>query).text},%`;
|
textParam['textC' + paramCounter.value] = `${(<TextSearch>query).text},%`;
|
||||||
|
textParam['text_exact' + paramCounter.value] = `${(<TextSearch>query).text}`;
|
||||||
|
|
||||||
qb[whereFN](`${fieldName} ${LIKE} :CtextC${paramCounter.value} COLLATE utf8_general_ci`,
|
qb[whereFN](`${fieldName} ${LIKE} :CtextC${paramCounter.value} COLLATE utf8_general_ci`,
|
||||||
textParam);
|
textParam);
|
||||||
@ -457,6 +458,8 @@ export class SearchManager implements ISearchManager {
|
|||||||
textParam);
|
textParam);
|
||||||
qb[whereFN](`${fieldName} ${LIKE} :textC${paramCounter.value} COLLATE utf8_general_ci`,
|
qb[whereFN](`${fieldName} ${LIKE} :textC${paramCounter.value} COLLATE utf8_general_ci`,
|
||||||
textParam);
|
textParam);
|
||||||
|
qb[whereFN](`${fieldName} ${LIKE} :text_exact${paramCounter.value} COLLATE utf8_general_ci`,
|
||||||
|
textParam);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if ((<TextSearch>query).negate) {
|
if ((<TextSearch>query).negate) {
|
||||||
|
@ -113,7 +113,7 @@ export class GalleryRouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static addRandom(app: Express) {
|
protected static addRandom(app: Express) {
|
||||||
app.get(['/api/gallery/random'],
|
app.get(['/api/gallery/random/:searchQueryDTO'],
|
||||||
// common part
|
// common part
|
||||||
AuthenticationMWs.authenticate,
|
AuthenticationMWs.authenticate,
|
||||||
AuthenticationMWs.authorise(UserRoles.Guest),
|
AuthenticationMWs.authorise(UserRoles.Guest),
|
||||||
@ -184,7 +184,7 @@ export class GalleryRouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static addSearch(app: Express) {
|
protected static addSearch(app: Express) {
|
||||||
app.get('/api/search/:text',
|
app.get('/api/search/:searchQueryDTO',
|
||||||
// common part
|
// common part
|
||||||
AuthenticationMWs.authenticate,
|
AuthenticationMWs.authenticate,
|
||||||
AuthenticationMWs.authorise(UserRoles.Guest),
|
AuthenticationMWs.authorise(UserRoles.Guest),
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
export enum OrientationType {
|
|
||||||
any = 0, portrait = 1, landscape = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO replace it with advanced search
|
|
||||||
export interface RandomQueryDTO {
|
|
||||||
directory?: string;
|
|
||||||
recursive?: boolean;
|
|
||||||
orientation?: OrientationType;
|
|
||||||
fromDate?: string;
|
|
||||||
toDate?: string;
|
|
||||||
minResolution?: number;
|
|
||||||
maxResolution?: number;
|
|
||||||
}
|
|
||||||
|
@ -94,6 +94,7 @@ import {ErrorInterceptor} from './model/network/helper/error.interceptor';
|
|||||||
import {CSRFInterceptor} from './model/network/helper/csrf.interceptor';
|
import {CSRFInterceptor} from './model/network/helper/csrf.interceptor';
|
||||||
import {SettingsEntryComponent} from './ui/settings/_abstract/settings-entry/settings-entry.component';
|
import {SettingsEntryComponent} from './ui/settings/_abstract/settings-entry/settings-entry.component';
|
||||||
import {GallerySearchQueryEntryComponent} from './ui/gallery/search/query-enrty/query-entry.search.gallery.component';
|
import {GallerySearchQueryEntryComponent} from './ui/gallery/search/query-enrty/query-entry.search.gallery.component';
|
||||||
|
import {StringifySearchQuery} from './pipes/StringifySearchQuery';
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -215,7 +216,8 @@ export function translationsFactory(locale: string) {
|
|||||||
StringifySortingMethod,
|
StringifySortingMethod,
|
||||||
DurationPipe,
|
DurationPipe,
|
||||||
FileSizePipe,
|
FileSizePipe,
|
||||||
GPXFilesFilterPipe
|
GPXFilesFilterPipe,
|
||||||
|
StringifySearchQuery
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{provide: HTTP_INTERCEPTORS, useClass: CSRFInterceptor, multi: true},
|
{provide: HTTP_INTERCEPTORS, useClass: CSRFInterceptor, multi: true},
|
||||||
|
13
src/frontend/app/pipes/StringifySearchQuery.ts
Normal file
13
src/frontend/app/pipes/StringifySearchQuery.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import {Pipe, PipeTransform} from '@angular/core';
|
||||||
|
import {SearchQueryDTO} from '../../../common/entities/SearchQueryDTO';
|
||||||
|
|
||||||
|
|
||||||
|
@Pipe({name: 'searchQuery'})
|
||||||
|
export class StringifySearchQuery implements PipeTransform {
|
||||||
|
transform(query: SearchQueryDTO): string {
|
||||||
|
console.log(query);
|
||||||
|
console.log(SearchQueryDTO.stringify(query));
|
||||||
|
return SearchQueryDTO.stringify(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -128,9 +128,7 @@ export class GalleryService {
|
|||||||
const cw = new ContentWrapper();
|
const cw = new ContentWrapper();
|
||||||
cw.searchResult = this.galleryCacheService.getSearch(query);
|
cw.searchResult = this.galleryCacheService.getSearch(query);
|
||||||
if (cw.searchResult == null) {
|
if (cw.searchResult == null) {
|
||||||
const params: { [key: string]: any } = {};
|
cw.searchResult = (await this.networkService.getJson<ContentWrapper>('/search/' + query)).searchResult;
|
||||||
params[QueryParams.gallery.search.query] = query;
|
|
||||||
cw.searchResult = (await this.networkService.getJson<ContentWrapper>('/search', params)).searchResult;
|
|
||||||
this.galleryCacheService.setSearch(query, cw.searchResult);
|
this.galleryCacheService.setSearch(query, cw.searchResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<div class="photo-position" *ngIf="gridMedia.hasPositionData()">
|
<div class="photo-position" *ngIf="gridMedia.hasPositionData()">
|
||||||
<span class="oi oi-map-marker"></span>
|
<span class="oi oi-map-marker"></span>
|
||||||
<ng-template [ngIf]="getPositionText()">
|
<ng-template [ngIf]="getPositionText()">
|
||||||
<a [routerLink]="['/search', getPositionText(), {type:SearchTypes[SearchTypes.position]}]"
|
<a [routerLink]="['/search', getPositionSearchQuery()]"
|
||||||
*ngIf="searchEnabled">
|
*ngIf="searchEnabled">
|
||||||
{{getPositionText()}}
|
{{getPositionText()}}
|
||||||
</a>
|
</a>
|
||||||
@ -37,13 +37,13 @@
|
|||||||
<div class="photo-keywords" *ngIf="keywords">
|
<div class="photo-keywords" *ngIf="keywords">
|
||||||
<ng-template ngFor let-keyword [ngForOf]="keywords" let-last="last">
|
<ng-template ngFor let-keyword [ngForOf]="keywords" let-last="last">
|
||||||
<a *ngIf="searchEnabled"
|
<a *ngIf="searchEnabled"
|
||||||
[routerLink]="['/search', keyword.value, {type: SearchTypes[keyword.type]}]" [ngSwitch]="keyword.type">
|
[routerLink]="['/search', getTextSearchQuery(keyword.value,keyword.type)]" [ngSwitch]="keyword.type">
|
||||||
<ng-template [ngSwitchCase]="SearchTypes.keyword">#</ng-template><!--
|
<ng-template [ngSwitchCase]="SearchQueryTypes.keyword">#</ng-template><!--
|
||||||
--><ng-template [ngSwitchCase]="SearchTypes.person"><span class="oi oi-person"></span></ng-template><!--
|
--><ng-template [ngSwitchCase]="SearchQueryTypes.person"><span class="oi oi-person"></span></ng-template><!--
|
||||||
-->{{keyword.value}}</a>
|
-->{{keyword.value}}</a>
|
||||||
<span *ngIf="!searchEnabled" [ngSwitch]="keyword.type">
|
<span *ngIf="!searchEnabled" [ngSwitch]="keyword.type">
|
||||||
<ng-template [ngSwitchCase]="SearchTypes.keyword">#</ng-template><!--
|
<ng-template [ngSwitchCase]="SearchQueryTypes.keyword">#</ng-template><!--
|
||||||
--><ng-template [ngSwitchCase]="SearchTypes.person"><span class="oi oi-person"></span></ng-template><!--
|
--><ng-template [ngSwitchCase]="SearchQueryTypes.person"><span class="oi oi-person"></span></ng-template><!--
|
||||||
-->{{keyword.value}}</span>
|
-->{{keyword.value}}</span>
|
||||||
<ng-template [ngIf]="!last">, </ng-template>
|
<ng-template [ngIf]="!last">, </ng-template>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -6,7 +6,7 @@ import {Thumbnail, ThumbnailManagerService} from '../../thumbnailManager.service
|
|||||||
import {Config} from '../../../../../../common/config/public/Config';
|
import {Config} from '../../../../../../common/config/public/Config';
|
||||||
import {PageHelper} from '../../../../model/page.helper';
|
import {PageHelper} from '../../../../model/page.helper';
|
||||||
import {PhotoDTO, PhotoMetadata} from '../../../../../../common/entities/PhotoDTO';
|
import {PhotoDTO, PhotoMetadata} from '../../../../../../common/entities/PhotoDTO';
|
||||||
import {SearchQueryTypes} from '../../../../../../common/entities/SearchQueryDTO';
|
import {SearchQueryDTO, SearchQueryTypes, TextSearch, TextSearchQueryMatchTypes} from '../../../../../../common/entities/SearchQueryDTO';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-gallery-grid-photo',
|
selector: 'app-gallery-grid-photo',
|
||||||
@ -91,6 +91,18 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPositionSearchQuery(): string {
|
||||||
|
return JSON.stringify(<TextSearch>{type: SearchQueryTypes.position, text: this.getPositionText()});
|
||||||
|
}
|
||||||
|
|
||||||
|
getTextSearchQuery(name: string, type: SearchQueryTypes): string {
|
||||||
|
return JSON.stringify(<TextSearch>{
|
||||||
|
type: type,
|
||||||
|
matchType: TextSearchQueryMatchTypes.exact_match,
|
||||||
|
text: name
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getPositionText(): string {
|
getPositionText(): string {
|
||||||
if (!this.gridMedia || !this.gridMedia.isPhoto()) {
|
if (!this.gridMedia || !this.gridMedia.isPhoto()) {
|
||||||
return '';
|
return '';
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
*ngIf="facesEnabled && activePhoto && zoom == 1 && activePhoto.gridMedia.Photo.metadata.faces && activePhoto.gridMedia.Photo.metadata.faces.length > 0">
|
*ngIf="facesEnabled && activePhoto && zoom == 1 && activePhoto.gridMedia.Photo.metadata.faces && activePhoto.gridMedia.Photo.metadata.faces.length > 0">
|
||||||
<a
|
<a
|
||||||
class="face"
|
class="face"
|
||||||
[routerLink]="['/search', face.name, {type: SearchTypes[SearchTypes.person]}]"
|
[routerLink]="['/search', getPersonSearchQuery(face.name)]"
|
||||||
[style.top.%]="face.box.top / activePhoto.gridMedia.Photo.metadata.size.height*100"
|
[style.top.%]="face.box.top / activePhoto.gridMedia.Photo.metadata.size.height*100"
|
||||||
[style.left.%]="face.box.left / activePhoto.gridMedia.Photo.metadata.size.width*100"
|
[style.left.%]="face.box.left / activePhoto.gridMedia.Photo.metadata.size.width*100"
|
||||||
[style.height.%]="face.box.height / activePhoto.gridMedia.Photo.metadata.size.height*100"
|
[style.height.%]="face.box.height / activePhoto.gridMedia.Photo.metadata.size.height*100"
|
||||||
|
@ -7,7 +7,7 @@ import {filter} from 'rxjs/operators';
|
|||||||
import {PhotoDTO} from '../../../../../../common/entities/PhotoDTO';
|
import {PhotoDTO} from '../../../../../../common/entities/PhotoDTO';
|
||||||
import {GalleryLightboxMediaComponent} from '../media/media.lightbox.gallery.component';
|
import {GalleryLightboxMediaComponent} from '../media/media.lightbox.gallery.component';
|
||||||
import {Config} from '../../../../../../common/config/public/Config';
|
import {Config} from '../../../../../../common/config/public/Config';
|
||||||
import {SearchQueryTypes} from '../../../../../../common/entities/SearchQueryDTO';
|
import {SearchQueryTypes, TextSearch, TextSearchQueryMatchTypes} from '../../../../../../common/entities/SearchQueryDTO';
|
||||||
|
|
||||||
export enum PlayBackStates {
|
export enum PlayBackStates {
|
||||||
Paused = 1,
|
Paused = 1,
|
||||||
@ -47,12 +47,12 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges {
|
|||||||
public controllersVisible = true;
|
public controllersVisible = true;
|
||||||
public drag = {x: 0, y: 0};
|
public drag = {x: 0, y: 0};
|
||||||
public SearchQueryTypes = SearchQueryTypes;
|
public SearchQueryTypes = SearchQueryTypes;
|
||||||
|
public faceContainerDim = {width: 0, height: 0};
|
||||||
private visibilityTimer: number = null;
|
private visibilityTimer: number = null;
|
||||||
private timer: Observable<number>;
|
private timer: Observable<number>;
|
||||||
private timerSub: Subscription;
|
private timerSub: Subscription;
|
||||||
private prevDrag = {x: 0, y: 0};
|
private prevDrag = {x: 0, y: 0};
|
||||||
private prevZoom = 1;
|
private prevZoom = 1;
|
||||||
public faceContainerDim = {width: 0, height: 0};
|
|
||||||
|
|
||||||
constructor(public fullScreenService: FullScreenService) {
|
constructor(public fullScreenService: FullScreenService) {
|
||||||
}
|
}
|
||||||
@ -296,6 +296,14 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges {
|
|||||||
this.closed.emit();
|
this.closed.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPersonSearchQuery(name: string): string {
|
||||||
|
return JSON.stringify(<TextSearch>{
|
||||||
|
type: SearchQueryTypes.person,
|
||||||
|
matchType: TextSearchQueryMatchTypes.exact_match,
|
||||||
|
text: name
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private checkZoomAndDrag() {
|
private checkZoomAndDrag() {
|
||||||
const fixDrag = (drag: { x: number, y: number }) => {
|
const fixDrag = (drag: { x: number, y: number }) => {
|
||||||
if (this.zoom === 1) {
|
if (this.zoom === 1) {
|
||||||
@ -378,6 +386,5 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges {
|
|||||||
this.faceContainerDim.width = this.photoFrameDim.width;
|
this.faceContainerDim.width = this.photoFrameDim.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,14 +92,14 @@
|
|||||||
<div class="col-10 keywords">
|
<div class="col-10 keywords">
|
||||||
<ng-template ngFor let-keyword [ngForOf]="keywords" let-last="last">
|
<ng-template ngFor let-keyword [ngForOf]="keywords" let-last="last">
|
||||||
<a *ngIf="searchEnabled"
|
<a *ngIf="searchEnabled"
|
||||||
[routerLink]="['/search', keyword.value, {type: SearchTypes[keyword.type]}]" [ngSwitch]="keyword.type">
|
[routerLink]="['/search', getTextSearchQuery(keyword.value,keyword.type)]" [ngSwitch]="keyword.type">
|
||||||
<ng-template [ngSwitchCase]="SearchTypes.keyword">#</ng-template><!--
|
<ng-template [ngSwitchCase]="SearchQueryTypes.keyword">#</ng-template><!--
|
||||||
-->
|
-->
|
||||||
<ng-template [ngSwitchCase]="SearchTypes.person"><span class="oi oi-person"></span></ng-template><!--
|
<ng-template [ngSwitchCase]="SearchQueryTypes.person"><span class="oi oi-person"></span></ng-template><!--
|
||||||
-->{{keyword.value}}</a>
|
-->{{keyword.value}}</a>
|
||||||
<span *ngIf="!searchEnabled" [ngSwitch]="keyword.type">
|
<span *ngIf="!searchEnabled" [ngSwitch]="keyword.type">
|
||||||
<ng-template [ngSwitchCase]="SearchTypes.keyword">#</ng-template><!--
|
<ng-template [ngSwitchCase]="SearchQueryTypes.keyword">#</ng-template><!--
|
||||||
--><ng-template [ngSwitchCase]="SearchTypes.person"><span class="oi oi-person"></span></ng-template><!--
|
--><ng-template [ngSwitchCase]="SearchQueryTypes.person"><span class="oi oi-person"></span></ng-template><!--
|
||||||
-->{{keyword.value}}</span>
|
-->{{keyword.value}}</span>
|
||||||
<ng-template [ngIf]="!last">, </ng-template>
|
<ng-template [ngIf]="!last">, </ng-template>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -6,7 +6,7 @@ import {VideoDTO, VideoMetadata} from '../../../../../../common/entities/VideoDT
|
|||||||
import {Utils} from '../../../../../../common/Utils';
|
import {Utils} from '../../../../../../common/Utils';
|
||||||
import {QueryService} from '../../../../model/query.service';
|
import {QueryService} from '../../../../model/query.service';
|
||||||
import {MapService} from '../../map/map.service';
|
import {MapService} from '../../map/map.service';
|
||||||
import {SearchQueryTypes} from '../../../../../../common/entities/SearchQueryDTO';
|
import {SearchQueryTypes, TextSearch, TextSearchQueryMatchTypes} from '../../../../../../common/entities/SearchQueryDTO';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-info-panel',
|
selector: 'app-info-panel',
|
||||||
@ -121,5 +121,14 @@ export class InfoPanelLightboxComponent implements OnInit {
|
|||||||
close() {
|
close() {
|
||||||
this.closed.emit();
|
this.closed.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTextSearchQuery(name: string, type: SearchQueryTypes): string {
|
||||||
|
return JSON.stringify(<TextSearch>{
|
||||||
|
type: type,
|
||||||
|
matchType: TextSearchQueryMatchTypes.exact_match,
|
||||||
|
text: name
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,15 +10,7 @@
|
|||||||
<ol *ngIf="searchResult" class="breadcrumb">
|
<ol *ngIf="searchResult" class="breadcrumb">
|
||||||
<li class="active">
|
<li class="active">
|
||||||
<ng-container i18n>Searching for:</ng-container>
|
<ng-container i18n>Searching for:</ng-container>
|
||||||
<span class="search-type" [ngSwitch]="searchResult.searchType">
|
<strong> {{searchResult.searchQuery | searchQuery}}</strong>
|
||||||
<span *ngSwitchCase="SearchTypes.photo" class="oi oi-image"></span>
|
|
||||||
<span *ngSwitchCase="SearchTypes.video" class="oi oi-video"></span>
|
|
||||||
<span *ngSwitchCase="SearchTypes.directory" class="oi oi-folder"></span>
|
|
||||||
<span *ngSwitchCase="SearchTypes.keyword" class="oi oi-tag"></span>
|
|
||||||
<span *ngSwitchCase="SearchTypes.person" class="oi oi-person"></span>
|
|
||||||
<span *ngSwitchCase="SearchTypes.position" class="oi oi-map-marker"></span>
|
|
||||||
</span>
|
|
||||||
<strong> {{searchResult.searchText}}</strong>
|
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ export class GalleryNavigatorComponent implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
|
console.log(this.searchResult);
|
||||||
this.getPath();
|
this.getPath();
|
||||||
this.DefaultSorting = this.galleryService.getDefaultSorting(this.directory);
|
this.DefaultSorting = this.galleryService.getDefaultSorting(this.directory);
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,11 @@
|
|||||||
<ng-container i18n>Random link</ng-container>
|
<ng-container i18n>Random link</ng-container>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
||||||
<ng-template #randomModal>
|
<ng-template #randomModal>
|
||||||
<!-- sharing Modal-->
|
<!-- sharing Modal-->
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" i18n>Random Link generator</h5>
|
<h5 class="modal-title" i18n>Random Link creator</h5>
|
||||||
<button type="button" class="close" (click)="hideModal()" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" (click)="hideModal()" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
@ -30,105 +31,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
<div class="row">
|
<form #searchPanelForm="ngForm" class="form-horizontal">
|
||||||
<div class="col-4">
|
|
||||||
<label class="control-label" i18n>In Folder:</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-8">
|
|
||||||
<input disabled type="text"
|
|
||||||
class="full-width form-control"
|
|
||||||
[ngModel]="data.directory">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-4">
|
|
||||||
<label class="control-label" i18n>Include subfolders:</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-8">
|
|
||||||
<bSwitch
|
|
||||||
class="switch"
|
|
||||||
name="includeSubfolders"
|
|
||||||
[switch-on-color]="'success'"
|
|
||||||
[switch-inverse]="'inverse'"
|
|
||||||
[switch-off-text]="text.No"
|
|
||||||
[switch-on-text]="text.Yes"
|
|
||||||
[switch-handle-width]="'100'"
|
|
||||||
[switch-label-width]="'20'"
|
|
||||||
(change)="update()"
|
|
||||||
[(ngModel)]="data.recursive">
|
|
||||||
</bSwitch>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-4">
|
|
||||||
<label class="control-label" i18n>Orientation:</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
<select class="form-control" [(ngModel)]="data.orientation" (change)="update()" name="orientation"
|
|
||||||
required>
|
|
||||||
<option [ngValue]="OrientationType.any" i18n>Any</option>
|
|
||||||
<option [ngValue]="OrientationType.landscape" i18n>Landscape</option>
|
|
||||||
<option [ngValue]="OrientationType.portrait" i18n>Portrait</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
<div class="col-4">
|
|
||||||
<label class="control-label" i18n>Date:</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-4 form-group">
|
|
||||||
<input type="text"
|
<input type="text"
|
||||||
placeholder="from: YYYY-MM-DD"
|
|
||||||
class="form-control"
|
class="form-control"
|
||||||
bsDatepicker
|
i18n-placeholder
|
||||||
(bsValueChange)="update()"
|
placeholder="Search"
|
||||||
[(ngModel)]="data.fromDate"
|
[(ngModel)]="rawSearchText"
|
||||||
[bsConfig]="{ dateInputFormat: 'YYYY-MM-DD' }">
|
(ngModelChange)="validateRawSearchText()"
|
||||||
</div>
|
size="30"
|
||||||
<div class="col-4 form-group">
|
name="srch-term-preview"
|
||||||
<input type="text"
|
id="srch-term-preview"
|
||||||
placeholder="to: YYYY-MM-DD"
|
autocomplete="off">
|
||||||
class="form-control"
|
|
||||||
bsDatepicker
|
|
||||||
(bsValueChange)="update()"
|
|
||||||
[(ngModel)]="data.toDate"
|
|
||||||
[bsConfig]="{ dateInputFormat: 'YYYY-MM-DD' }">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
<app-gallery-search-query-entry
|
||||||
<div class="col-4">
|
[(ngModel)]="searchQueryDTO"
|
||||||
<label class="control-label" i18n>Resolution:</label>
|
(change)="onQueryChange()"
|
||||||
</div>
|
name="search-root"
|
||||||
<div class="col-4">
|
(delete)="resetQuery()">
|
||||||
<div class="input-group">
|
|
||||||
<input type="number" class="form-control"
|
|
||||||
(change)="update()"
|
|
||||||
[(ngModel)]="data.minResolution"
|
|
||||||
id="minResolution" placeholder="min" step="1" min="0">
|
|
||||||
|
|
||||||
<div class="input-group-append">
|
</app-gallery-search-query-entry>
|
||||||
<div class="input-group-text">Mpx</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="number" class="form-control"
|
|
||||||
(change)="update()"
|
|
||||||
[(ngModel)]="data.maxResolution"
|
|
||||||
id="maxResolution" placeholder="max" step="1" min="0">
|
|
||||||
<div class="input-group-append">
|
|
||||||
<div class="input-group-text">Mpx</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import {Component, OnDestroy, OnInit, TemplateRef} from '@angular/core';
|
import {Component, OnDestroy, OnInit, TemplateRef} from '@angular/core';
|
||||||
import {Utils} from '../../../../../common/Utils';
|
|
||||||
import {GalleryService} from '../gallery.service';
|
import {GalleryService} from '../gallery.service';
|
||||||
import {ContentWrapper} from '../../../../../common/entities/ConentWrapper';
|
import {ContentWrapper} from '../../../../../common/entities/ConentWrapper';
|
||||||
import {Config} from '../../../../../common/config/public/Config';
|
import {Config} from '../../../../../common/config/public/Config';
|
||||||
import {NotificationService} from '../../../model/notification.service';
|
import {NotificationService} from '../../../model/notification.service';
|
||||||
import {DirectoryDTO} from '../../../../../common/entities/DirectoryDTO';
|
|
||||||
import {I18n} from '@ngx-translate/i18n-polyfill';
|
import {I18n} from '@ngx-translate/i18n-polyfill';
|
||||||
import {BsModalService} from 'ngx-bootstrap/modal';
|
import {BsModalService} from 'ngx-bootstrap/modal';
|
||||||
import {BsModalRef} from 'ngx-bootstrap/modal/bs-modal-ref.service';
|
import {BsModalRef} from 'ngx-bootstrap/modal/bs-modal-ref.service';
|
||||||
import {OrientationType, RandomQueryDTO} from '../../../../../common/entities/RandomQueryDTO';
|
|
||||||
import {NetworkService} from '../../../model/network/network.service';
|
import {NetworkService} from '../../../model/network/network.service';
|
||||||
import {Subscription} from 'rxjs';
|
import {Subscription} from 'rxjs';
|
||||||
|
import {SearchQueryDTO, SearchQueryTypes, TextSearch} from '../../../../../common/entities/SearchQueryDTO';
|
||||||
|
import {ActivatedRoute, Params} from '@angular/router';
|
||||||
|
import {QueryParams} from '../../../../../common/QueryParams';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -20,37 +20,55 @@ import {Subscription} from 'rxjs';
|
|||||||
})
|
})
|
||||||
export class RandomQueryBuilderGalleryComponent implements OnInit, OnDestroy {
|
export class RandomQueryBuilderGalleryComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
public searchQueryDTO: SearchQueryDTO;
|
||||||
|
public rawSearchText: string;
|
||||||
enabled = true;
|
enabled = true;
|
||||||
url = '';
|
url = '';
|
||||||
|
|
||||||
data: RandomQueryDTO = {
|
|
||||||
orientation: OrientationType.any,
|
|
||||||
directory: '',
|
|
||||||
recursive: true,
|
|
||||||
minResolution: null,
|
|
||||||
maxResolution: null,
|
|
||||||
toDate: null,
|
|
||||||
fromDate: null
|
|
||||||
};
|
|
||||||
contentSubscription: Subscription = null;
|
contentSubscription: Subscription = null;
|
||||||
|
|
||||||
readonly OrientationType: typeof OrientationType;
|
|
||||||
modalRef: BsModalRef;
|
modalRef: BsModalRef;
|
||||||
|
|
||||||
text = {
|
|
||||||
Yes: 'Yes',
|
private readonly subscription: Subscription = null;
|
||||||
No: 'No'
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(public _galleryService: GalleryService,
|
constructor(public _galleryService: GalleryService,
|
||||||
private _notification: NotificationService,
|
private _notification: NotificationService,
|
||||||
public i18n: I18n,
|
public i18n: I18n,
|
||||||
|
private _route: ActivatedRoute,
|
||||||
private modalService: BsModalService) {
|
private modalService: BsModalService) {
|
||||||
this.OrientationType = OrientationType;
|
this.resetQuery();
|
||||||
this.text.Yes = i18n('Yes');
|
|
||||||
this.text.No = i18n('No');
|
this.subscription = this._route.params.subscribe((params: Params) => {
|
||||||
|
if (!params[QueryParams.gallery.search.query]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const searchQuery = JSON.parse(params[QueryParams.gallery.search.query]);
|
||||||
|
if (searchQuery) {
|
||||||
|
this.searchQueryDTO = searchQuery;
|
||||||
|
this.onQueryChange();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get HTMLSearchQuery() {
|
||||||
|
return JSON.stringify(this.searchQueryDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateRawSearchText() {
|
||||||
|
try {
|
||||||
|
this.searchQueryDTO = SearchQueryDTO.parse(this.rawSearchText);
|
||||||
|
this.url = NetworkService.buildUrl(Config.Client.publicUrl + '/api/gallery/random/' + this.HTMLSearchQuery);
|
||||||
|
console.log(this.searchQueryDTO);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onQueryChange() {
|
||||||
|
this.rawSearchText = SearchQueryDTO.stringify(this.searchQueryDTO);
|
||||||
|
this.url = NetworkService.buildUrl(Config.Client.publicUrl + '/api/gallery/random/' + this.HTMLSearchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.contentSubscription = this._galleryService.content.subscribe((content: ContentWrapper) => {
|
this.contentSubscription = this._galleryService.content.subscribe((content: ContentWrapper) => {
|
||||||
@ -58,7 +76,7 @@ export class RandomQueryBuilderGalleryComponent implements OnInit, OnDestroy {
|
|||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.data.directory = Utils.concatUrls((<DirectoryDTO>content.directory).path, (<DirectoryDTO>content.directory).name);
|
// this.data.directory = Utils.concatUrls((<DirectoryDTO>content.directory).path, (<DirectoryDTO>content.directory).name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,19 +84,12 @@ export class RandomQueryBuilderGalleryComponent implements OnInit, OnDestroy {
|
|||||||
if (this.contentSubscription !== null) {
|
if (this.contentSubscription !== null) {
|
||||||
this.contentSubscription.unsubscribe();
|
this.contentSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.subscription !== null) {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
|
||||||
setTimeout(() => {
|
|
||||||
const data = Utils.clone(this.data);
|
|
||||||
for (const key of Object.keys(data)) {
|
|
||||||
if (!(<any>data)[key]) {
|
|
||||||
delete (<any>data)[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.url = NetworkService.buildUrl(Config.Client.publicUrl + '/api/gallery/random/', data);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
openModal(template: TemplateRef<any>) {
|
openModal(template: TemplateRef<any>) {
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
@ -87,9 +98,10 @@ export class RandomQueryBuilderGalleryComponent implements OnInit, OnDestroy {
|
|||||||
if (this.modalRef) {
|
if (this.modalRef) {
|
||||||
this.modalRef.hide();
|
this.modalRef.hide();
|
||||||
}
|
}
|
||||||
this.modalRef = this.modalService.show(template);
|
|
||||||
|
this.modalRef = this.modalService.show(template, {class: 'modal-lg'});
|
||||||
document.body.style.paddingRight = '0px';
|
document.body.style.paddingRight = '0px';
|
||||||
this.update();
|
this.onQueryChange();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,4 +114,10 @@ export class RandomQueryBuilderGalleryComponent implements OnInit, OnDestroy {
|
|||||||
this.modalRef = null;
|
this.modalRef = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
resetQuery() {
|
||||||
|
this.searchQueryDTO = <TextSearch>{text: '', type: SearchQueryTypes.any_text};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
(focus)="onFocus()"
|
(focus)="onFocus()"
|
||||||
[(ngModel)]="rawSearchText"
|
[(ngModel)]="rawSearchText"
|
||||||
(ngModelChange)="validateRawSearchText()"
|
(ngModelChange)="validateRawSearchText()"
|
||||||
|
(keydown.enter)="Search()"
|
||||||
#name="ngModel"
|
#name="ngModel"
|
||||||
size="30"
|
size="30"
|
||||||
ngControl="search"
|
ngControl="search"
|
||||||
@ -78,6 +79,14 @@
|
|||||||
(delete)="resetQuery()">
|
(delete)="resetQuery()">
|
||||||
|
|
||||||
</app-gallery-search-query-entry>
|
</app-gallery-search-query-entry>
|
||||||
|
|
||||||
|
<div class="input-group-btn float-right" style="display: block">
|
||||||
|
<button class="btn btn-primary" type="button"
|
||||||
|
[routerLink]="['/search', HTMLSearchQuery]"
|
||||||
|
(click)="hideModal()">
|
||||||
|
<span class="oi oi-magnifying-glass"></span> Search
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {Component, OnDestroy, TemplateRef} from '@angular/core';
|
import {Component, OnDestroy, TemplateRef} from '@angular/core';
|
||||||
import {AutoCompleteService} from './autocomplete.service';
|
import {AutoCompleteService} from './autocomplete.service';
|
||||||
import {AutoCompleteItem} from '../../../../../common/entities/AutoCompleteItem';
|
import {AutoCompleteItem} from '../../../../../common/entities/AutoCompleteItem';
|
||||||
import {ActivatedRoute, Params, RouterLink} from '@angular/router';
|
import {ActivatedRoute, Params, Router, RouterLink} from '@angular/router';
|
||||||
import {GalleryService} from '../gallery.service';
|
import {GalleryService} from '../gallery.service';
|
||||||
import {Subscription} from 'rxjs';
|
import {Subscription} from 'rxjs';
|
||||||
import {Config} from '../../../../../common/config/public/Config';
|
import {Config} from '../../../../../common/config/public/Config';
|
||||||
@ -36,24 +36,27 @@ export class GallerySearchComponent implements OnDestroy {
|
|||||||
private _galleryService: GalleryService,
|
private _galleryService: GalleryService,
|
||||||
private navigationService: NavigationService,
|
private navigationService: NavigationService,
|
||||||
private _route: ActivatedRoute,
|
private _route: ActivatedRoute,
|
||||||
|
public router: Router,
|
||||||
private modalService: BsModalService) {
|
private modalService: BsModalService) {
|
||||||
|
|
||||||
this.SearchQueryTypes = SearchQueryTypes;
|
this.SearchQueryTypes = SearchQueryTypes;
|
||||||
this.MetadataSearchQueryTypes = MetadataSearchQueryTypes.map(v => ({key: v, value: SearchQueryTypes[v]}));
|
this.MetadataSearchQueryTypes = MetadataSearchQueryTypes.map(v => ({key: v, value: SearchQueryTypes[v]}));
|
||||||
|
|
||||||
this.subscription = this._route.params.subscribe((params: Params) => {
|
this.subscription = this._route.params.subscribe((params: Params) => {
|
||||||
const searchQuery = params[QueryParams.gallery.search.query];
|
if (!params[QueryParams.gallery.search.query]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const searchQuery = JSON.parse(params[QueryParams.gallery.search.query]);
|
||||||
if (searchQuery) {
|
if (searchQuery) {
|
||||||
this.searchQueryDTO = searchQuery;
|
this.searchQueryDTO = searchQuery;
|
||||||
|
this.onQueryChange();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
get HTMLSearchQuery() {
|
get HTMLSearchQuery() {
|
||||||
const searchQuery: any = {};
|
return JSON.stringify(this.searchQueryDTO);
|
||||||
searchQuery[QueryParams.gallery.search.query] = this.searchQueryDTO;
|
|
||||||
return searchQuery;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -118,6 +121,10 @@ export class GallerySearchComponent implements OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Search() {
|
||||||
|
this.router.navigate(['/search', this.HTMLSearchQuery]).catch(console.error);
|
||||||
|
}
|
||||||
|
|
||||||
private emptyAutoComplete() {
|
private emptyAutoComplete() {
|
||||||
this.autoCompleteItems = [];
|
this.autoCompleteItems = [];
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user