mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-01-10 04:07:35 +02:00
Improving search modal UI including fixing search modal delete button event propagation #587
This commit is contained in:
parent
66d20e200f
commit
b9b41eded9
@ -8,7 +8,7 @@
|
||||
<hr>
|
||||
<app-gallery-search-query-entry
|
||||
[(ngModel)]="searchQueryDTO"
|
||||
(change)="onQueryChange()"
|
||||
(change)="onChange()"
|
||||
(ngModelChange)="onChange()"
|
||||
name="search-root"
|
||||
(delete)="resetQuery()">
|
||||
|
@ -1,24 +1,7 @@
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
forwardRef,
|
||||
Input,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
SearchQueryDTO,
|
||||
SearchQueryTypes,
|
||||
TextSearch,
|
||||
} from '../../../../../../common/entities/SearchQueryDTO';
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
UntypedFormControl,
|
||||
NG_VALIDATORS,
|
||||
NG_VALUE_ACCESSOR,
|
||||
ValidationErrors,
|
||||
Validator,
|
||||
} from '@angular/forms';
|
||||
import { SearchQueryParserService } from '../search-query-parser.service';
|
||||
import {Component, EventEmitter, forwardRef, Input, Output,} from '@angular/core';
|
||||
import {SearchQueryDTO, SearchQueryTypes, TextSearch,} from '../../../../../../common/entities/SearchQueryDTO';
|
||||
import {ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, UntypedFormControl, ValidationErrors, Validator,} from '@angular/forms';
|
||||
import {SearchQueryParserService} from '../search-query-parser.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery-search-query-builder',
|
||||
@ -38,8 +21,7 @@ import { SearchQueryParserService } from '../search-query-parser.service';
|
||||
],
|
||||
})
|
||||
export class GallerySearchQueryBuilderComponent
|
||||
implements ControlValueAccessor, Validator
|
||||
{
|
||||
implements ControlValueAccessor, Validator {
|
||||
public searchQueryDTO: SearchQueryDTO = {
|
||||
type: SearchQueryTypes.any_text,
|
||||
text: '',
|
||||
@ -48,7 +30,8 @@ export class GallerySearchQueryBuilderComponent
|
||||
@Input() placeholder = $localize`Search`;
|
||||
public rawSearchText = '';
|
||||
|
||||
constructor(private searchQueryParserService: SearchQueryParserService) {}
|
||||
constructor(private searchQueryParserService: SearchQueryParserService) {
|
||||
}
|
||||
|
||||
validateRawSearchText(): void {
|
||||
try {
|
||||
@ -66,21 +49,16 @@ export class GallerySearchQueryBuilderComponent
|
||||
text: '',
|
||||
type: SearchQueryTypes.any_text,
|
||||
} as TextSearch;
|
||||
}
|
||||
|
||||
onQueryChange(): void {
|
||||
this.rawSearchText = this.searchQueryParserService.stringify(
|
||||
this.searchQueryDTO
|
||||
);
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
validate(control: UntypedFormControl): ValidationErrors {
|
||||
return { required: true };
|
||||
return {required: true};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
public onTouched(): void {}
|
||||
public onTouched(): void {
|
||||
}
|
||||
|
||||
public writeValue(obj: any): void {
|
||||
this.searchQueryDTO = obj;
|
||||
@ -98,12 +76,17 @@ export class GallerySearchQueryBuilderComponent
|
||||
}
|
||||
|
||||
public onChange(): void {
|
||||
this.rawSearchText = this.searchQueryParserService.stringify(
|
||||
this.searchQueryDTO
|
||||
);
|
||||
this.propagateChange(this.searchQueryDTO);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
private propagateChange = (_: unknown): void => {};
|
||||
private propagateChange = (_: unknown): void => {
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
private propagateTouch = (_: unknown): void => {};
|
||||
private propagateTouch = (_: unknown): void => {
|
||||
};
|
||||
}
|
||||
|
@ -5,14 +5,3 @@
|
||||
label {
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
.match-type {
|
||||
font-size: 2rem;
|
||||
margin-top: -0.8rem;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.match-type.exact-match {
|
||||
color: #0069d9;
|
||||
}
|
||||
|
@ -51,24 +51,31 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!IsListQuery">
|
||||
<div class="col-md-3">
|
||||
<select
|
||||
id="searchType"
|
||||
name="searchType"
|
||||
class="form-select"
|
||||
[(ngModel)]="queryEntry.type"
|
||||
(ngModelChange)="onChangeType()">
|
||||
<option *ngFor="let opt of SearchQueryTypesEnum" [ngValue]="opt.key">{{opt.key | stringifySearchType}}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-11 col-md-8" *ngIf="IsTextQuery">
|
||||
<div class="col-lg-4 col-xl-3">
|
||||
<div class="input-group">
|
||||
<select
|
||||
id="searchType"
|
||||
name="searchType"
|
||||
class="form-select"
|
||||
[(ngModel)]="queryEntry.type"
|
||||
(ngModelChange)="onChangeType()">
|
||||
<option *ngFor="let opt of SearchQueryTypesEnum" [ngValue]="opt.key">{{opt.key | stringifySearchType}}
|
||||
</option>
|
||||
</select>
|
||||
<select
|
||||
id="negate"
|
||||
name="negate"
|
||||
class="form-select w-auto flex-grow-0"
|
||||
title="Negate"
|
||||
p18n-title
|
||||
[(ngModel)]="SelectedMatchType"
|
||||
(ngModelChange)="onChange()">
|
||||
<option *ngFor="let mt of MatchingTypes" [ngValue]="mt">{{mt}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-10 col-lg" *ngIf="IsTextQuery">
|
||||
<div class="input-group">
|
||||
<span title="exact match"
|
||||
p18n-title
|
||||
class="match-type"
|
||||
(click)="toggleMatchType()"
|
||||
[class.exact-match]="AsTextQuery.matchType === TextSearchQueryMatchTypes.exact_match">"</span>
|
||||
<input
|
||||
id="searchField"
|
||||
name="searchField"
|
||||
@ -79,15 +86,10 @@
|
||||
(change)="onChange()"
|
||||
(ngModelChange)="onChange()"
|
||||
type="text"/>
|
||||
<span title="exact match"
|
||||
p18n-title
|
||||
class="match-type"
|
||||
(click)="toggleMatchType()"
|
||||
[class.exact-match]="AsTextQuery.matchType === TextSearchQueryMatchTypes.exact_match">"</span>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container [ngSwitch]="queryEntry.type">
|
||||
<div *ngSwitchCase="SearchQueryTypes.distance" class="col-11 col-md-8 ">
|
||||
<div *ngSwitchCase="SearchQueryTypes.distance" class="col-10 col-lg">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="input-group">
|
||||
@ -118,7 +120,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- Range Search Query -->
|
||||
<div *ngSwitchCase="SearchQueryTypes.from_date" class="col-11 col-md-8 d-flex">
|
||||
<div *ngSwitchCase="SearchQueryTypes.from_date" class="col-10 col-lg d-flex">
|
||||
<input id="from_date"
|
||||
name="from_date"
|
||||
title="From date"
|
||||
@ -129,7 +131,7 @@
|
||||
class="form-control input-md rounded-2"
|
||||
type="date">
|
||||
</div>
|
||||
<div *ngSwitchCase="SearchQueryTypes.to_date" class="col-11 col-md-8 d-flex">
|
||||
<div *ngSwitchCase="SearchQueryTypes.to_date" class="col-10 col-lg d-flex">
|
||||
<input id="to_date"
|
||||
name="to_date"
|
||||
title="To date"
|
||||
@ -140,7 +142,7 @@
|
||||
class="form-control input-md rounded-2"
|
||||
type="date">
|
||||
</div>
|
||||
<div *ngSwitchCase="SearchQueryTypes.min_rating" class="col-11 col-md-8 d-flex">
|
||||
<div *ngSwitchCase="SearchQueryTypes.min_rating" class="col-10 col-lg d-flex">
|
||||
<input id="minRating"
|
||||
name="minRating"
|
||||
title="Minimum Rating"
|
||||
@ -153,7 +155,7 @@
|
||||
(ngModelChange)="onChange()"
|
||||
type="number">
|
||||
</div>
|
||||
<div *ngSwitchCase="SearchQueryTypes.max_rating" class="col-11 col-md-8 d-flex">
|
||||
<div *ngSwitchCase="SearchQueryTypes.max_rating" class="col-10 col-lg d-flex">
|
||||
<input id="maxRating"
|
||||
name="maxRating"
|
||||
title="Maximum Rating"
|
||||
@ -166,7 +168,7 @@
|
||||
(ngModelChange)="onChange()"
|
||||
type="number">
|
||||
</div>
|
||||
<div *ngSwitchCase="SearchQueryTypes.min_resolution" class="col-11 col-md-8">
|
||||
<div *ngSwitchCase="SearchQueryTypes.min_resolution" class="col-10 col-lg">
|
||||
<div class="input-group">
|
||||
<input id="minResolution"
|
||||
name="minResolution"
|
||||
@ -182,7 +184,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="SearchQueryTypes.max_resolution" class="col-11 col-md-8">
|
||||
<div *ngSwitchCase="SearchQueryTypes.max_resolution" class="col-10 col-lg">
|
||||
<div class="input-group">
|
||||
<input id="maxResolution"
|
||||
name="maxResolution"
|
||||
@ -197,7 +199,7 @@
|
||||
<span class="input-group-text">Mpx</span>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngSwitchCase="SearchQueryTypes.orientation" class="col-11 col-md-8 d-flex">
|
||||
<div *ngSwitchCase="SearchQueryTypes.orientation" class="col-10 col-lg d-flex">
|
||||
<div class="input-group col-md-6">
|
||||
<select class="form-select rounded-2"
|
||||
[(ngModel)]="AsOrientationQuery.landscape"
|
||||
@ -212,11 +214,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<button [ngClass]="'btn-danger'"
|
||||
class="btn float-end col-1 align-self-center"
|
||||
(click)="deleteItem()">
|
||||
<span class="oi oi-trash" aria-hidden="true" aria-label="Delete"></span>
|
||||
</button>
|
||||
<div class="col-2 col-lg-1 align-self-center">
|
||||
<button [ngClass]="'btn-danger'"
|
||||
class="btn w-auto float-end"
|
||||
(click)="deleteItem()">
|
||||
<span class="oi oi-trash" aria-hidden="true" aria-label="Delete"></span>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, EventEmitter, forwardRef, Output } from '@angular/core';
|
||||
import {Component, EventEmitter, forwardRef, Output} from '@angular/core';
|
||||
import {
|
||||
DistanceSearch,
|
||||
ListSearchQueryTypes,
|
||||
@ -12,15 +12,8 @@ import {
|
||||
TextSearchQueryMatchTypes,
|
||||
TextSearchQueryTypes,
|
||||
} from '../../../../../../common/entities/SearchQueryDTO';
|
||||
import { Utils } from '../../../../../../common/Utils';
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
UntypedFormControl,
|
||||
NG_VALIDATORS,
|
||||
NG_VALUE_ACCESSOR,
|
||||
ValidationErrors,
|
||||
Validator,
|
||||
} from '@angular/forms';
|
||||
import {Utils} from '../../../../../../common/Utils';
|
||||
import {ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, UntypedFormControl, ValidationErrors, Validator,} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery-search-query-entry',
|
||||
@ -40,8 +33,7 @@ import {
|
||||
],
|
||||
})
|
||||
export class GallerySearchQueryEntryComponent
|
||||
implements ControlValueAccessor, Validator
|
||||
{
|
||||
implements ControlValueAccessor, Validator {
|
||||
public queryEntry: SearchQueryDTO;
|
||||
public SearchQueryTypesEnum: { value: string; key: SearchQueryTypes }[];
|
||||
public SearchQueryTypes = SearchQueryTypes;
|
||||
@ -93,7 +85,48 @@ export class GallerySearchQueryEntryComponent
|
||||
}
|
||||
|
||||
validate(control: UntypedFormControl): ValidationErrors {
|
||||
return { required: true };
|
||||
return {required: true};
|
||||
}
|
||||
|
||||
get MatchingTypes(): string[] {
|
||||
if (this.IsListQuery) {
|
||||
return [];
|
||||
}
|
||||
if (this.IsTextQuery) {
|
||||
return ['=~', '=', '!=', '!~'];
|
||||
}
|
||||
return ['=', '!=']; //normal negatable query
|
||||
}
|
||||
|
||||
get SelectedMatchType(): string {
|
||||
if (this.AsTextQuery.matchType !== TextSearchQueryMatchTypes.like) {
|
||||
if (this.AsTextQuery.negate) {
|
||||
return '!=';
|
||||
} else {
|
||||
return '=';
|
||||
}
|
||||
} else {
|
||||
if (this.AsTextQuery.negate) {
|
||||
return '!~';
|
||||
} else {
|
||||
return '=~';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set SelectedMatchType(value: string) {
|
||||
if (this.IsListQuery) {
|
||||
return;
|
||||
}
|
||||
this.AsTextQuery.negate = value.charAt(0) === '!';
|
||||
if (!this.IsTextQuery) {
|
||||
return;
|
||||
}
|
||||
if (value === '!~' || value === '=~') {
|
||||
this.AsTextQuery.matchType = TextSearchQueryMatchTypes.like;
|
||||
} else {
|
||||
this.AsTextQuery.matchType = TextSearchQueryMatchTypes.exact_match;
|
||||
}
|
||||
}
|
||||
|
||||
addQuery(): void {
|
||||
@ -110,14 +143,14 @@ export class GallerySearchQueryEntryComponent
|
||||
if (this.IsListQuery) {
|
||||
delete this.AsTextQuery.text;
|
||||
this.AsListQuery.list = this.AsListQuery.list || [
|
||||
{ type: SearchQueryTypes.any_text, text: '' } as TextSearch,
|
||||
{ type: SearchQueryTypes.any_text, text: '' } as TextSearch,
|
||||
{type: SearchQueryTypes.any_text, text: ''} as TextSearch,
|
||||
{type: SearchQueryTypes.any_text, text: ''} as TextSearch,
|
||||
];
|
||||
} else {
|
||||
delete this.AsListQuery.list;
|
||||
}
|
||||
if (this.queryEntry.type === SearchQueryTypes.distance) {
|
||||
this.AsDistanceQuery.from = { text: '' };
|
||||
this.AsDistanceQuery.from = {text: ''};
|
||||
this.AsDistanceQuery.distance = 1;
|
||||
} else {
|
||||
delete this.AsDistanceQuery.from;
|
||||
@ -136,12 +169,14 @@ export class GallerySearchQueryEntryComponent
|
||||
this.delete.emit();
|
||||
}
|
||||
|
||||
itemDeleted(i: number): void {
|
||||
this.AsListQuery.list.splice(i, 1);
|
||||
itemDeleted(index: number): void {
|
||||
this.AsListQuery.list.splice(index, 1);
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
public onTouched(): void {}
|
||||
public onTouched(): void {
|
||||
}
|
||||
|
||||
public writeValue(obj: SearchQueryDTO): void {
|
||||
this.queryEntry = obj;
|
||||
@ -159,18 +194,13 @@ export class GallerySearchQueryEntryComponent
|
||||
this.propagateChange(this.queryEntry);
|
||||
}
|
||||
|
||||
public toggleMatchType(): void {
|
||||
this.AsTextQuery.matchType =
|
||||
this.AsTextQuery.matchType === TextSearchQueryMatchTypes.exact_match
|
||||
? TextSearchQueryMatchTypes.like
|
||||
: TextSearchQueryMatchTypes.exact_match;
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
private propagateChange = (_: unknown): void => {};
|
||||
private propagateChange = (_: unknown): void => {
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
private propagateTouch = (_: unknown): void => {};
|
||||
private propagateTouch = (_: unknown): void => {
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user