mirror of
https://github.com/xuthus83/pigallery2.git
synced 2025-01-14 14:43:17 +08:00
Improving autocomplete and search
This commit is contained in:
parent
af67a8ac1c
commit
928a8918c6
@ -121,22 +121,26 @@ export class SearchQueryParser {
|
|||||||
|
|
||||||
if (tokenEnd !== str.length - 1) {
|
if (tokenEnd !== str.length - 1) {
|
||||||
if (str.startsWith(' ' + this.keywords.and, tokenEnd)) {
|
if (str.startsWith(' ' + this.keywords.and, tokenEnd)) {
|
||||||
|
const rest = this.parse(str.slice(tokenEnd + (' ' + this.keywords.and).length), implicitOR);
|
||||||
return {
|
return {
|
||||||
type: SearchQueryTypes.AND,
|
type: SearchQueryTypes.AND,
|
||||||
list: [this.parse(str.slice(0, tokenEnd), implicitOR), // trim brackets
|
list: [this.parse(str.slice(0, tokenEnd), implicitOR), // trim brackets
|
||||||
this.parse(str.slice(tokenEnd + (' ' + this.keywords.and).length), implicitOR)]
|
...(rest.type === SearchQueryTypes.AND ? (rest as SearchListQuery).list : [rest])]
|
||||||
} as ANDSearchQuery;
|
} as ANDSearchQuery;
|
||||||
} else if (str.startsWith(' ' + this.keywords.or, tokenEnd)) {
|
} else if (str.startsWith(' ' + this.keywords.or, tokenEnd)) {
|
||||||
|
const rest = this.parse(str.slice(tokenEnd + (' ' + this.keywords.or).length), implicitOR);
|
||||||
return {
|
return {
|
||||||
type: SearchQueryTypes.OR,
|
type: SearchQueryTypes.OR,
|
||||||
list: [this.parse(str.slice(0, tokenEnd), implicitOR), // trim brackets
|
list: [this.parse(str.slice(0, tokenEnd), implicitOR), // trim brackets
|
||||||
this.parse(str.slice(tokenEnd + (' ' + this.keywords.or).length), implicitOR)]
|
...(rest.type === SearchQueryTypes.OR ? (rest as SearchListQuery).list : [rest])]
|
||||||
} as ORSearchQuery;
|
} as ORSearchQuery;
|
||||||
} else { // Relation cannot be detected
|
} else { // Relation cannot be detected
|
||||||
|
const t = implicitOR === true ? SearchQueryTypes.OR : SearchQueryTypes.UNKNOWN_RELATION;
|
||||||
|
const rest = this.parse(str.slice(tokenEnd), implicitOR);
|
||||||
return {
|
return {
|
||||||
type: implicitOR === true ? SearchQueryTypes.OR : SearchQueryTypes.UNKNOWN_RELATION,
|
type: t,
|
||||||
list: [this.parse(str.slice(0, tokenEnd), implicitOR), // trim brackets
|
list: [this.parse(str.slice(0, tokenEnd), implicitOR), // trim brackets
|
||||||
this.parse(str.slice(tokenEnd), implicitOR)]
|
...(rest.type === t ? (rest as SearchListQuery).list : [rest])]
|
||||||
} as SearchListQuery;
|
} as SearchListQuery;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,24 +253,33 @@ export class SearchQueryParser {
|
|||||||
return {type: SearchQueryTypes.any_text, text: str} as TextSearch;
|
return {type: SearchQueryTypes.any_text, text: str} as TextSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public stringify(query: SearchQueryDTO): string {
|
public stringify(query: SearchQueryDTO): string {
|
||||||
|
const ret = this.stringifyOnEntry(query);
|
||||||
|
if (ret.charAt(0) === '(' && ret.charAt(ret.length - 1) === ')') {
|
||||||
|
return ret.slice(1, ret.length - 1);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private stringifyOnEntry(query: SearchQueryDTO): string {
|
||||||
if (!query || !query.type) {
|
if (!query || !query.type) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
switch (query.type) {
|
switch (query.type) {
|
||||||
case SearchQueryTypes.AND:
|
case SearchQueryTypes.AND:
|
||||||
return '(' + (query as SearchListQuery).list.map(q => this.stringify(q)).join(' ' + this.keywords.and + ' ') + ')';
|
return '(' + (query as SearchListQuery).list.map(q => this.stringifyOnEntry(q)).join(' ' + this.keywords.and + ' ') + ')';
|
||||||
|
|
||||||
case SearchQueryTypes.OR:
|
case SearchQueryTypes.OR:
|
||||||
return '(' + (query as SearchListQuery).list.map(q => this.stringify(q)).join(' ' + this.keywords.or + ' ') + ')';
|
return '(' + (query as SearchListQuery).list.map(q => this.stringifyOnEntry(q)).join(' ' + this.keywords.or + ' ') + ')';
|
||||||
|
|
||||||
case SearchQueryTypes.SOME_OF:
|
case SearchQueryTypes.SOME_OF:
|
||||||
if ((query as SomeOfSearchQuery).min) {
|
if ((query as SomeOfSearchQuery).min) {
|
||||||
return (query as SomeOfSearchQuery).min + '-' + this.keywords.NSomeOf + ':(' +
|
return (query as SomeOfSearchQuery).min + '-' + this.keywords.NSomeOf + ':(' +
|
||||||
(query as SearchListQuery).list.map(q => this.stringify(q)).join(' ') + ')';
|
(query as SearchListQuery).list.map(q => this.stringifyOnEntry(q)).join(' ') + ')';
|
||||||
}
|
}
|
||||||
return this.keywords.someOf + ':(' +
|
return this.keywords.someOf + ':(' +
|
||||||
(query as SearchListQuery).list.map(q => this.stringify(q)).join(' ') + ')';
|
(query as SearchListQuery).list.map(q => this.stringifyOnEntry(q)).join(' ') + ')';
|
||||||
|
|
||||||
|
|
||||||
case SearchQueryTypes.orientation:
|
case SearchQueryTypes.orientation:
|
||||||
|
@ -1,6 +1,18 @@
|
|||||||
.query-list {
|
.query-list {
|
||||||
padding-left: 25px;
|
padding-left: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
margin-top: 0.3rem;
|
margin-top: 0.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.match-type {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-top: -0.8rem;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.match-type.exact-match {
|
||||||
|
color: #0069d9;
|
||||||
|
}
|
||||||
|
@ -59,6 +59,11 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group col-md-8" *ngIf="IsTextQuery">
|
<div class="input-group col-md-8" *ngIf="IsTextQuery">
|
||||||
|
<span title="exact match"
|
||||||
|
p18n-title
|
||||||
|
class="match-type"
|
||||||
|
(click)="toggleMatchType()"
|
||||||
|
[class.exact-match]="AsTextQuery.matchType === TextSearchQueryMatchTypes.exact_match">"</span>
|
||||||
<input
|
<input
|
||||||
id="searchField"
|
id="searchField"
|
||||||
name="searchField"
|
name="searchField"
|
||||||
@ -68,6 +73,11 @@
|
|||||||
(change)="onChange()"
|
(change)="onChange()"
|
||||||
(ngModelChange)="onChange()"
|
(ngModelChange)="onChange()"
|
||||||
type="text"/>
|
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">
|
<ng-container [ngSwitch]="queryEntry.type">
|
||||||
<div *ngSwitchCase="SearchQueryTypes.distance" class="col-md-8 d-flex">
|
<div *ngSwitchCase="SearchQueryTypes.distance" class="col-md-8 d-flex">
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
SearchQueryTypes,
|
SearchQueryTypes,
|
||||||
SomeOfSearchQuery,
|
SomeOfSearchQuery,
|
||||||
TextSearch,
|
TextSearch,
|
||||||
|
TextSearchQueryMatchTypes,
|
||||||
TextSearchQueryTypes
|
TextSearchQueryTypes
|
||||||
} from '../../../../../../common/entities/SearchQueryDTO';
|
} from '../../../../../../common/entities/SearchQueryDTO';
|
||||||
import {Utils} from '../../../../../../common/Utils';
|
import {Utils} from '../../../../../../common/Utils';
|
||||||
@ -36,6 +37,7 @@ export class GallerySearchQueryEntryComponent implements ControlValueAccessor, V
|
|||||||
public queryEntry: SearchQueryDTO;
|
public queryEntry: SearchQueryDTO;
|
||||||
public SearchQueryTypesEnum: { value: string; key: SearchQueryTypes }[];
|
public SearchQueryTypesEnum: { value: string; key: SearchQueryTypes }[];
|
||||||
public SearchQueryTypes = SearchQueryTypes;
|
public SearchQueryTypes = SearchQueryTypes;
|
||||||
|
public TextSearchQueryMatchTypes = TextSearchQueryMatchTypes;
|
||||||
@Output() delete = new EventEmitter<void>();
|
@Output() delete = new EventEmitter<void>();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -145,6 +147,12 @@ export class GallerySearchQueryEntryComponent implements ControlValueAccessor, V
|
|||||||
this.propagateChange(this.queryEntry);
|
this.propagateChange(this.queryEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public toggleMatchType(): void {
|
||||||
|
this.AsTextQuery.matchType = this.AsTextQuery.matchType === TextSearchQueryMatchTypes.exact_match ?
|
||||||
|
TextSearchQueryMatchTypes.like : TextSearchQueryMatchTypes.exact_match;
|
||||||
|
this.onChange();
|
||||||
|
}
|
||||||
|
|
||||||
private propagateChange = (_: any): void => {
|
private propagateChange = (_: any): void => {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,6 +13,19 @@
|
|||||||
z-index: 7;
|
z-index: 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.insert-button {
|
||||||
|
margin-right: -15px;
|
||||||
|
display: none;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autocomplete-item-selected .insert-button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.autocomplete-item-selected .insert-button:hover {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
.autocomplete-item {
|
.autocomplete-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
(keyup)="onSearchChange($event)"
|
(keyup)="onSearchChange($event)"
|
||||||
(blur)="onFocusLost()"
|
(blur)="onFocusLost()"
|
||||||
(focus)="onFocus()"
|
|
||||||
[(ngModel)]="rawSearchText"
|
[(ngModel)]="rawSearchText"
|
||||||
(ngModelChange)="onChange()"
|
(ngModelChange)="onChange()"
|
||||||
(keydown.enter)="OnEnter($event)"
|
(keydown.enter)="OnEnter($event)"
|
||||||
@ -49,6 +48,7 @@
|
|||||||
<span *ngSwitchCase="SearchQueryTypes.distance" class="oi oi-map-marker"></span>
|
<span *ngSwitchCase="SearchQueryTypes.distance" class="oi oi-map-marker"></span>
|
||||||
</span>
|
</span>
|
||||||
{{item.preText}}<strong>{{item.highLightText}}</strong>{{item.postText}}
|
{{item.preText}}<strong>{{item.highLightText}}</strong>{{item.postText}}
|
||||||
|
<span class="oi oi-chevron-right insert-button float-right" (click)="applyAutoComplete(item)"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -109,16 +109,12 @@ export class GallerySearchFieldComponent implements ControlValueAccessor, Valida
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onFocusLost(): void {
|
public onFocusLost(): void {
|
||||||
|
return;
|
||||||
if (this.mouseOverAutoComplete === false) {
|
if (this.mouseOverAutoComplete === false) {
|
||||||
this.autoCompleteRenders = [];
|
this.autoCompleteRenders = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public onFocus(): void {
|
|
||||||
// TODO: implement autocomplete
|
|
||||||
// this.autocomplete(this.searchText).catch(console.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
applyHint($event: any): void {
|
applyHint($event: any): void {
|
||||||
if ($event.target.selectionStart !== this.rawSearchText.length) {
|
if ($event.target.selectionStart !== this.rawSearchText.length) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user