1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2025-01-14 14:43:17 +08:00

implementing typed search

This commit is contained in:
Braun Patrik 2016-05-16 11:03:11 +02:00
parent 60dab77cf4
commit d32914bc02
17 changed files with 178 additions and 74 deletions

View File

@ -4,7 +4,7 @@ import {NextFunction, Request, Response} from "express";
import {Error, ErrorCodes} from "../../common/entities/Error"; import {Error, ErrorCodes} from "../../common/entities/Error";
import {Directory} from "../../common/entities/Directory"; import {Directory} from "../../common/entities/Directory";
import {ObjectManagerRepository} from "../model/ObjectManagerRepository"; import {ObjectManagerRepository} from "../model/ObjectManagerRepository";
import {AutoCompleteItem} from "../../common/entities/AutoCompleteItem"; import {AutoCompleteItem, SearchTypes} from "../../common/entities/AutoCompleteItem";
import {ContentWrapper} from "../../common/entities/ConentWrapper"; import {ContentWrapper} from "../../common/entities/ConentWrapper";
import {SearchResult} from "../../common/entities/SearchResult"; import {SearchResult} from "../../common/entities/SearchResult";
import {Photo} from "../../common/entities/Photo"; import {Photo} from "../../common/entities/Photo";
@ -70,8 +70,14 @@ export class GalleryMWs {
if (!(req.params.text)) { if (!(req.params.text)) {
return next(); return next();
} }
ObjectManagerRepository.getInstance().getSearchManager().search(req.params.text, (err, result:SearchResult) => { let type:SearchTypes;
console.log()
if (req.query.type) {
type = parseInt(req.query.type);
}
ObjectManagerRepository.getInstance().getSearchManager().search(req.params.text, type, (err, result:SearchResult) => {
if (err || !result) { if (err || !result) {
return next(new Error(ErrorCodes.GENERAL_ERROR, err)); return next(new Error(ErrorCodes.GENERAL_ERROR, err));
} }
@ -90,6 +96,7 @@ export class GalleryMWs {
return next(); return next();
} }
ObjectManagerRepository.getInstance().getSearchManager().instantSearch(req.params.text, (err, result:SearchResult) => { ObjectManagerRepository.getInstance().getSearchManager().instantSearch(req.params.text, (err, result:SearchResult) => {
if (err || !result) { if (err || !result) {
return next(new Error(ErrorCodes.GENERAL_ERROR, err)); return next(new Error(ErrorCodes.GENERAL_ERROR, err));

View File

@ -1,7 +1,7 @@
import {AutoCompleteItem} from "../../common/entities/AutoCompleteItem"; import {AutoCompleteItem, SearchTypes} from "../../common/entities/AutoCompleteItem";
import {SearchResult} from "../../common/entities/SearchResult"; import {SearchResult} from "../../common/entities/SearchResult";
export interface ISearchManager { export interface ISearchManager {
autocomplete(text, cb:(error:any, result:Array<AutoCompleteItem>) => void); autocomplete(text:string, cb:(error:any, result:Array<AutoCompleteItem>) => void);
search(text, cb:(error:any, result:SearchResult) => void); search(text:string, searchType:SearchTypes, cb:(error:any, result:SearchResult) => void);
instantSearch(text, cb:(error:any, result:SearchResult) => void); instantSearch(text:string, cb:(error:any, result:SearchResult) => void);
} }

View File

@ -1,4 +1,4 @@
import {AutoCompleteItem} from "../../../common/entities/AutoCompleteItem"; import {AutoCompleteItem, SearchTypes} from "../../../common/entities/AutoCompleteItem";
import {ISearchManager} from "../ISearchManager"; import {ISearchManager} from "../ISearchManager";
import {SearchResult} from "../../../common/entities/SearchResult"; import {SearchResult} from "../../../common/entities/SearchResult";
@ -9,7 +9,7 @@ export class SearchManager implements ISearchManager {
throw new Error("not implemented"); throw new Error("not implemented");
} }
search(text, cb:(error:any, result:SearchResult) => void) { search(text, searchType:SearchTypes, cb:(error:any, result:SearchResult) => void) {
throw new Error("not implemented"); throw new Error("not implemented");
} }

View File

@ -1,4 +1,4 @@
import {AutoCompleteItem, AutoCompeleteTypes} from "../../../common/entities/AutoCompleteItem"; import {AutoCompleteItem, SearchTypes} from "../../../common/entities/AutoCompleteItem";
import {ISearchManager} from "../ISearchManager"; import {ISearchManager} from "../ISearchManager";
import {DirectoryModel} from "./entities/DirectoryModel"; import {DirectoryModel} from "./entities/DirectoryModel";
import {PhotoModel} from "./entities/PhotoModel"; import {PhotoModel} from "./entities/PhotoModel";
@ -18,25 +18,25 @@ export class MongoSearchManager implements ISearchManager {
promises.push( promises.push(
PhotoModel.find({name: {$regex: text, $options: "i"}}) PhotoModel.find({name: {$regex: text, $options: "i"}})
.limit(10).select('name').exec().then((res:Array<any>)=> { .limit(10).select('name').exec().then((res:Array<any>)=> {
items = items.concat(this.encapsulateAutoComplete(res.map(r => r.name), AutoCompeleteTypes.image)); items = items.concat(this.encapsulateAutoComplete(res.map(r => r.name), SearchTypes.image));
})); }));
promises.push( promises.push(
PhotoModel.find({"metadata.positionData.city": {$regex: text, $options: "i"}}) PhotoModel.find({"metadata.positionData.city": {$regex: text, $options: "i"}})
.limit(10).select('metadata.positionData.city').exec().then((res:Array<any>)=> { .limit(10).select('metadata.positionData.city').exec().then((res:Array<any>)=> {
items = items.concat(this.encapsulateAutoComplete(res.map(r => r.metadata.positionData.city), AutoCompeleteTypes.position)); items = items.concat(this.encapsulateAutoComplete(res.map(r => r.metadata.positionData.city), SearchTypes.position));
})); }));
promises.push( promises.push(
PhotoModel.find({"metadata.positionData.state": {$regex: text, $options: "i"}}) PhotoModel.find({"metadata.positionData.state": {$regex: text, $options: "i"}})
.limit(10).select('metadata.positionData.state').exec().then((res:Array<any>)=> { .limit(10).select('metadata.positionData.state').exec().then((res:Array<any>)=> {
items = items.concat(this.encapsulateAutoComplete(res.map(r => r.metadata.positionData.state), AutoCompeleteTypes.position)); items = items.concat(this.encapsulateAutoComplete(res.map(r => r.metadata.positionData.state), SearchTypes.position));
})); }));
promises.push( promises.push(
PhotoModel.find({"metadata.positionData.country": {$regex: text, $options: "i"}}) PhotoModel.find({"metadata.positionData.country": {$regex: text, $options: "i"}})
.limit(10).select('metadata.positionData.country').exec().then((res:Array<any>)=> { .limit(10).select('metadata.positionData.country').exec().then((res:Array<any>)=> {
items = items.concat(this.encapsulateAutoComplete(res.map(r => r.metadata.positionData.country), AutoCompeleteTypes.position)); items = items.concat(this.encapsulateAutoComplete(res.map(r => r.metadata.positionData.country), SearchTypes.position));
})); }));
//TODO: fix caseinsensitivity //TODO: fix caseinsensitivity
@ -44,7 +44,7 @@ export class MongoSearchManager implements ISearchManager {
PhotoModel.find({"metadata.keywords": {$regex: text, $options: "i"}}) PhotoModel.find({"metadata.keywords": {$regex: text, $options: "i"}})
.limit(10).select('metadata.keywords').exec().then((res:Array<any>)=> { .limit(10).select('metadata.keywords').exec().then((res:Array<any>)=> {
res.forEach((photo)=> { res.forEach((photo)=> {
items = items.concat(this.encapsulateAutoComplete(photo.metadata.keywords.filter(k => k.indexOf(text) != -1), AutoCompeleteTypes.keyword)); items = items.concat(this.encapsulateAutoComplete(photo.metadata.keywords.filter(k => k.indexOf(text) != -1), SearchTypes.keyword));
}); });
})); }));
@ -52,7 +52,7 @@ export class MongoSearchManager implements ISearchManager {
DirectoryModel.find({ DirectoryModel.find({
name: {$regex: text, $options: "i"} name: {$regex: text, $options: "i"}
}).limit(10).select('name').exec().then((res:Array<any>)=> { }).limit(10).select('name').exec().then((res:Array<any>)=> {
items = items.concat(this.encapsulateAutoComplete(res.map(r => r.name), AutoCompeleteTypes.directory)); items = items.concat(this.encapsulateAutoComplete(res.map(r => r.name), SearchTypes.directory));
})); }));
@ -66,39 +66,59 @@ export class MongoSearchManager implements ISearchManager {
} }
search(text, cb:(error:any, result:SearchResult) => void) { search(text:string, searchType:SearchTypes, cb:(error:any, result:SearchResult) => void) {
console.log("instantSearch: " + text); console.log("search: " + text + ", type:" + searchType);
let result:SearchResult = new SearchResult(); let result:SearchResult = new SearchResult();
let promises = [];
let photoFilterOR = [];
result.searchText = text; result.searchText = text;
PhotoModel.find({ result.searchType = searchType;
$or: [
{name: {$regex: text, $options: "i"}},
{"metadata.positionData.city": {$regex: text, $options: "i"}},
{"metadata.positionData.state": {$regex: text, $options: "i"}},
{"metadata.positionData.country": {$regex: text, $options: "i"}},
{"metadata.keywords": {$regex: text, $options: "i"}}
]
}).populate('directory', 'name path').exec((err, res:Array<any>) => {
if (err || !res) {
return cb(err, null);
}
result.photos = res;
DirectoryModel.find({ if (!searchType || searchType === SearchTypes.image) {
photoFilterOR.push({name: {$regex: text, $options: "i"}});
}
if (!searchType || searchType === SearchTypes.position) {
photoFilterOR.push({"metadata.positionData.city": {$regex: text, $options: "i"}});
photoFilterOR.push({"metadata.positionData.state": {$regex: text, $options: "i"}});
photoFilterOR.push({"metadata.positionData.country": {$regex: text, $options: "i"}});
}
if (!searchType || searchType === SearchTypes.keyword) {
photoFilterOR.push({"metadata.keywords": {$regex: text, $options: "i"}});
}
let photoFilter = {};
if (photoFilterOR.length == 1) {
photoFilter = photoFilterOR[0];
} else {
photoFilter = {$or: photoFilterOR};
}
if (!searchType || photoFilterOR.length > 0) {
promises.push(PhotoModel.find(photoFilter).populate('directory', 'name path').exec().then((res:Array<any>) => {
result.photos = res;
}));
}
if (!searchType || searchType === SearchTypes.directory) {
promises.push(DirectoryModel.find({
name: { name: {
$regex: text, $regex: text,
$options: "i" $options: "i"
} }
}).select('name').exec((err, res:Array<any>) => { }).exec().then((res:Array<any>) => {
if (err || !res) {
return cb(err, null);
}
result.directories = res; result.directories = res;
return cb(null, result); }));
}); }
Promise.all(promises).then(()=> {
return cb(null, result);
}).catch((err)=> {
console.error(err);
return cb(err, null);
}); });
} }
@ -138,7 +158,7 @@ export class MongoSearchManager implements ISearchManager {
}); });
} }
private encapsulateAutoComplete(values:Array<string>, type:AutoCompeleteTypes) { private encapsulateAutoComplete(values:Array<string>, type:SearchTypes) {
let res = []; let res = [];
values.forEach((value)=> { values.forEach((value)=> {
res.push(new AutoCompleteItem(value, type)); res.push(new AutoCompleteItem(value, type));

View File

@ -45,7 +45,7 @@ export class GalleryRouter {
private addSearch() { private addSearch() {
this.app.get("/api/gallery/search/:text", this.app.get("/api/gallery/search/:text",
AuthenticationMWs.authenticate, // AuthenticationMWs.authenticate,
GalleryMWs.search, GalleryMWs.search,
RenderingMWs.renderResult RenderingMWs.renderResult
); );
@ -61,7 +61,7 @@ export class GalleryRouter {
private addAutoComplete() { private addAutoComplete() {
this.app.get("/api/gallery/autocomplete/:text", this.app.get("/api/gallery/autocomplete/:text",
// AuthenticationMWs.authenticate, AuthenticationMWs.authenticate,
GalleryMWs.autocomplete, GalleryMWs.autocomplete,
RenderingMWs.renderResult RenderingMWs.renderResult
); );

View File

@ -29,7 +29,7 @@ export class PublicRouter {
res.render(_path.resolve(__dirname, './../../frontend/index.ejs'), res.tpl); res.render(_path.resolve(__dirname, './../../frontend/index.ejs'), res.tpl);
}; };
this.app.get(['/', '/login', "/gallery*", "/admin"], renderIndex); this.app.get(['/', '/login', "/gallery*", "/admin", "/search*"], renderIndex);
} }

View File

@ -1,4 +1,4 @@
export enum AutoCompeleteTypes { export enum SearchTypes {
image, image,
directory, directory,
keyword, keyword,
@ -6,7 +6,7 @@ export enum AutoCompeleteTypes {
} }
export class AutoCompleteItem { export class AutoCompleteItem {
constructor(public text:string, public type:AutoCompeleteTypes) { constructor(public text:string, public type:SearchTypes) {
} }
equals(other:AutoCompleteItem) { equals(other:AutoCompleteItem) {

View File

@ -1,9 +1,9 @@
import {Directory} from "./Directory"; import {Directory} from "./Directory";
import {Photo} from "./Photo"; import {Photo} from "./Photo";
import {SearchTypes} from "./AutoCompleteItem";
export class SearchResult { export class SearchResult {
public searchText:string = "";
public searchText:string; public searchType:SearchTypes;
public directories:Array<Directory>; public directories:Array<Directory> = [];
public photos:Array<Photo>; public photos:Array<Photo> = [];
} }

View File

@ -50,6 +50,11 @@ import {NetworkService} from "./model/network/network.service";
name: 'Gallery', name: 'Gallery',
component: GalleryComponent component: GalleryComponent
}, },
{
path: '/search/:searchText',
name: 'Search',
component: GalleryComponent
},
]) ])
export class AppComponent implements OnInit { export class AppComponent implements OnInit {

View File

@ -1,7 +1,7 @@
<gallery-lightbox #lightbox></gallery-lightbox> <gallery-lightbox #lightbox></gallery-lightbox>
<app-frame> <app-frame>
<div navbar> <div navbar>
<gallery-search *ngIf="showSearchBar"></gallery-search> <gallery-search #search *ngIf="showSearchBar"></gallery-search>
</div> </div>
<div body class="container" style="width: 100%; padding:0" *ngIf="_galleryService.content.directory"> <div body class="container" style="width: 100%; padding:0" *ngIf="_galleryService.content.directory">
<gallery-directory *ngFor="let directory of _galleryService.content.directory.directories" <gallery-directory *ngFor="let directory of _galleryService.content.directory.directories"
@ -11,7 +11,16 @@
<div body class="container" style="width: 100%; padding:0" *ngIf="_galleryService.content.searchResult"> <div body class="container" style="width: 100%; padding:0" *ngIf="_galleryService.content.searchResult">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li class="active"> Searching for: <strong>{{_galleryService.content.searchResult.searchText}}</strong></li> <li class="active">
Searching for:
<span [ngSwitch]="_galleryService.content.searchResult.searchType">
<span *ngSwitchWhen="0" class="glyphicon glyphicon-picture"></span>
<span *ngSwitchWhen="1" class="glyphicon glyphicon-folder-open"></span>
<span *ngSwitchWhen="2" class="glyphicon glyphicon-tag"></span>
<span *ngSwitchWhen="3" class="glyphicon glyphicon-map-marker"></span>
</span>
<strong>{{_galleryService.content.searchResult.searchText}}</strong>
</li>
</ol> </ol>
<div *ngFor="let directory of _galleryService.content.searchResult.directories"> <div *ngFor="let directory of _galleryService.content.searchResult.directories">
<gallery-directory *ngIf="directory" [directory]="directory"></gallery-directory> <gallery-directory *ngIf="directory" [directory]="directory"></gallery-directory>

View File

@ -1,6 +1,6 @@
///<reference path="../../browser.d.ts"/> ///<reference path="../../browser.d.ts"/>
import {Component, OnInit} from "@angular/core"; import {Component, OnInit, ViewChild} from "@angular/core";
import {AuthenticationService} from "../model/network/authentication.service.ts"; import {AuthenticationService} from "../model/network/authentication.service.ts";
import {Router, RouteParams} from "@angular/router-deprecated"; import {Router, RouteParams} from "@angular/router-deprecated";
import {GalleryService} from "./gallery.service"; import {GalleryService} from "./gallery.service";
@ -10,6 +10,7 @@ import {FrameComponent} from "../frame/frame.component";
import {GalleryLightboxComponent} from "./lightbox/lightbox.gallery.component"; import {GalleryLightboxComponent} from "./lightbox/lightbox.gallery.component";
import {GallerySearchComponent} from "./search/search.gallery.component"; import {GallerySearchComponent} from "./search/search.gallery.component";
import {Config} from "../config/Config"; import {Config} from "../config/Config";
import {SearchTypes} from "../../../common/entities/AutoCompleteItem";
@Component({ @Component({
selector: 'gallery', selector: 'gallery',
@ -23,9 +24,10 @@ import {Config} from "../config/Config";
}) })
export class GalleryComponent implements OnInit { export class GalleryComponent implements OnInit {
@ViewChild(GallerySearchComponent) search:GallerySearchComponent;
public showSearchBar:boolean = true; public showSearchBar:boolean = true;
constructor(private _galleryService:GalleryService, constructor(private _galleryService:GalleryService,
private _params:RouteParams, private _params:RouteParams,
private _authService:AuthenticationService, private _authService:AuthenticationService,
@ -40,12 +42,30 @@ export class GalleryComponent implements OnInit {
return; return;
} }
let directoryName = this._params.get('directory');
console.log(this._params); console.log(this._params);
console.log(directoryName);
let searchText = this._params.get('searchText');
if (searchText && searchText != "") {
console.log("searching");
let typeString = this._params.get('type');
if (typeString && typeString != "") {
console.log("with type");
let type:SearchTypes = SearchTypes[typeString];
this._galleryService.search(searchText, type);
return;
}
this._galleryService.search(searchText);
return;
}
let directoryName = this._params.get('directory');
directoryName = directoryName ? directoryName : ""; directoryName = directoryName ? directoryName : "";
this._galleryService.getDirectory(directoryName); this._galleryService.getDirectory(directoryName);
} }

View File

@ -6,6 +6,7 @@ import {Message} from "../../../common/entities/Message";
import {ContentWrapper} from "../../../common/entities/ConentWrapper"; import {ContentWrapper} from "../../../common/entities/ConentWrapper";
import {Photo} from "../../../common/entities/Photo"; import {Photo} from "../../../common/entities/Photo";
import {Directory} from "../../../common/entities/Directory"; import {Directory} from "../../../common/entities/Directory";
import {SearchTypes} from "../../../common/entities/AutoCompleteItem";
@Injectable() @Injectable()
export class GalleryService { export class GalleryService {
@ -33,12 +34,18 @@ export class GalleryService {
} }
//TODO: cache //TODO: cache
public search(text:string):Promise<Message<ContentWrapper>> { public search(text:string, type?:SearchTypes):Promise<Message<ContentWrapper>> {
clearTimeout(this.searchId); clearTimeout(this.searchId);
if (text === null || text === '') { if (text === null || text === '') {
return Promise.resolve(new Message(null, null)); return Promise.resolve(new Message(null, null));
} }
return this._networkService.getJson("/gallery/search/" + text).then(
let queryString = "/gallery/search/" + text;
if (type) {
queryString += "?type=" + type;
}
return this._networkService.getJson(queryString).then(
(message:Message<ContentWrapper>) => { (message:Message<ContentWrapper>) => {
if (!message.error && message.result) { if (!message.error && message.result) {
this.content = message.result; this.content = message.result;

View File

@ -5,16 +5,16 @@
<div class="photo-position" *ngIf="gridPhoto.photo.metadata.positionData"> <div class="photo-position" *ngIf="gridPhoto.photo.metadata.positionData">
<span class="glyphicon glyphicon-map-marker"></span> <span class="glyphicon glyphicon-map-marker"></span>
<a *ngIf="gridPhoto.photo.metadata.positionData.city || gridPhoto.photo.metadata.positionData.state || gridPhoto.photo.metadata.positionData.country"> <a [routerLink]="['Search',{searchText: getPositionText(), type:SearchTypes[SearchTypes.position]}]"
{{gridPhoto.photo.metadata.positionData.city || gridPhoto.photo.metadata.positionData.state || *ngIf="getPositionText()">
gridPhoto.photo.metadata.positionData.country}} {{getPositionText()}}
</a> </a>
</div> </div>
<div class="photo-keywords"> <div class="photo-keywords">
<template ngFor let-keyword [ngForOf]="gridPhoto.photo.metadata.keywords" let-last="last"> <template ngFor let-keyword [ngForOf]="gridPhoto.photo.metadata.keywords" let-last="last">
#<a>{{keyword}}</a> <a [routerLink]="['Search',{searchText: keyword, type: SearchTypes[SearchTypes.keyword]}]">#{{keyword}}</a>
<template [ngIf]="!last">,</template> <template [ngIf]="!last">,</template>
</template> </template>

View File

@ -3,11 +3,14 @@
import {Component, Input, ElementRef, ViewChild} from "@angular/core"; import {Component, Input, ElementRef, ViewChild} from "@angular/core";
import {IRenderable, Dimension} from "../../../model/IRenderable"; import {IRenderable, Dimension} from "../../../model/IRenderable";
import {GridPhoto} from "../GridPhoto"; import {GridPhoto} from "../GridPhoto";
import {SearchTypes} from "../../../../../common/entities/AutoCompleteItem";
import {RouterLink} from "@angular/router-deprecated";
@Component({ @Component({
selector: 'gallery-grid-photo', selector: 'gallery-grid-photo',
templateUrl: 'app/gallery/grid/photo/photo.grid.gallery.component.html', templateUrl: 'app/gallery/grid/photo/photo.grid.gallery.component.html',
styleUrls: ['app/gallery/grid/photo/photo.grid.gallery.component.css'], styleUrls: ['app/gallery/grid/photo/photo.grid.gallery.component.css'],
directives: [RouterLink],
}) })
export class GalleryPhotoComponent implements IRenderable { export class GalleryPhotoComponent implements IRenderable {
@Input() gridPhoto:GridPhoto; @Input() gridPhoto:GridPhoto;
@ -18,15 +21,25 @@ export class GalleryPhotoComponent implements IRenderable {
height: 0, height: 0,
background: "" background: ""
}; };
SearchTypes:any = [];
constructor() { constructor() {
this.SearchTypes = SearchTypes;
} }
getPositionText():string {
if (!this.gridPhoto) {
return ""
}
return this.gridPhoto.photo.metadata.positionData.city ||
this.gridPhoto.photo.metadata.positionData.state ||
this.gridPhoto.photo.metadata.positionData.country;
}
hover() { hover() {
this.infoStyle.height = this.infoDiv.nativeElement.clientHeight; this.infoStyle.height = this.infoDiv.nativeElement.clientHeight;
this.infoStyle.background = "rgba(0,0,0,0.8)"; this.infoStyle.background = "rgba(0,0,0,0.8)";
} }
mouseOut() { mouseOut() {
@ -34,7 +47,7 @@ export class GalleryPhotoComponent implements IRenderable {
this.infoStyle.background = "rgba(0,0,0,0.0)"; this.infoStyle.background = "rgba(0,0,0,0.0)";
} }
public getDimension():Dimension { public getDimension():Dimension {
return new Dimension(this.imageRef.nativeElement.offsetTop, return new Dimension(this.imageRef.nativeElement.offsetTop,
this.imageRef.nativeElement.offsetLeft, this.imageRef.nativeElement.offsetLeft,

View File

@ -6,8 +6,10 @@
ngControl="search" ngControl="search"
name="srch-term" id="srch-term" autocomplete="off"> name="srch-term" id="srch-term" autocomplete="off">
<div class="autocomplete-list" *ngIf="autoCompleteItems.length > 0"> <div class="autocomplete-list" *ngIf="autoCompleteItems.length > 0"
<div class="autocomplete-item" *ngFor="let item of autoCompleteItems" (mousedown)="search(item)"> (mouseover)="setMouseOverAutoComplete(true)" (mouseout)="setMouseOverAutoComplete(false)">
<div class="autocomplete-item" *ngFor="let item of autoCompleteItems">
<a [routerLink]="['Search',{searchText: item.text, type: SearchTypes[item.type]}]">
<span [ngSwitch]="item.type"> <span [ngSwitch]="item.type">
<span *ngSwitchWhen="0" class="glyphicon glyphicon-picture"></span> <span *ngSwitchWhen="0" class="glyphicon glyphicon-picture"></span>
<span *ngSwitchWhen="1" class="glyphicon glyphicon-folder-open"></span> <span *ngSwitchWhen="1" class="glyphicon glyphicon-folder-open"></span>
@ -15,6 +17,7 @@
<span *ngSwitchWhen="3" class="glyphicon glyphicon-map-marker"></span> <span *ngSwitchWhen="3" class="glyphicon glyphicon-map-marker"></span>
</span> </span>
{{item.preText}}<strong>{{item.highLightText}}</strong>{{item.postText}} {{item.preText}}<strong>{{item.highLightText}}</strong>{{item.postText}}
</a>
</div> </div>
</div> </div>

View File

@ -2,7 +2,8 @@
import {Component} from "@angular/core"; import {Component} from "@angular/core";
import {AutoCompleteService} from "./autocomplete.service"; import {AutoCompleteService} from "./autocomplete.service";
import {AutoCompleteItem, AutoCompeleteTypes} from "../../../../common/entities/AutoCompleteItem"; import {AutoCompleteItem, SearchTypes} from "../../../../common/entities/AutoCompleteItem";
import {RouteParams, RouterLink} from "@angular/router-deprecated";
import {Message} from "../../../../common/entities/Message"; import {Message} from "../../../../common/entities/Message";
import {GalleryService} from "../gallery.service"; import {GalleryService} from "../gallery.service";
import {FORM_DIRECTIVES} from "@angular/common"; import {FORM_DIRECTIVES} from "@angular/common";
@ -13,14 +14,22 @@ import {Config} from "../../config/Config";
templateUrl: 'app/gallery/search/search.gallery.component.html', templateUrl: 'app/gallery/search/search.gallery.component.html',
styleUrls: ['app/gallery/search/search.gallery.component.css'], styleUrls: ['app/gallery/search/search.gallery.component.css'],
providers: [AutoCompleteService], providers: [AutoCompleteService],
directives: [FORM_DIRECTIVES] directives: [FORM_DIRECTIVES, RouterLink]
}) })
export class GallerySearchComponent { export class GallerySearchComponent {
autoCompleteItems:Array<AutoCompleteRenderItem> = []; autoCompleteItems:Array<AutoCompleteRenderItem> = [];
private searchText:string = ""; private searchText:string = "";
constructor(private _autoCompleteService:AutoCompleteService, private _galleryService:GalleryService) { SearchTypes:any = [];
constructor(private _autoCompleteService:AutoCompleteService, private _galleryService:GalleryService, private _params:RouteParams) {
this.SearchTypes = SearchTypes;
let searchText = this._params.get('searchText');
if (searchText && searchText != "") {
this.searchText = searchText;
}
} }
onSearchChange(event:KeyboardEvent) { onSearchChange(event:KeyboardEvent) {
@ -49,9 +58,16 @@ export class GallerySearchComponent {
} }
mouseOverAutoComplete:boolean = false;
public setMouseOverAutoComplete(value) {
this.mouseOverAutoComplete = value;
}
public onFocusLost(event) { public onFocusLost(event) {
this.autoCompleteItems = []; if (this.mouseOverAutoComplete == false) {
this.autoCompleteItems = [];
}
} }
public onFocus(event) { public onFocus(event) {
@ -88,15 +104,19 @@ export class GallerySearchComponent {
}); });
} }
public setSearchText(searchText:string) {
this.searchText = searchText;
}
} }
class AutoCompleteRenderItem { class AutoCompleteRenderItem {
public preText:string = ""; public preText:string = "";
public highLightText:string = ""; public highLightText:string = "";
public postText:string = ""; public postText:string = "";
public type:AutoCompeleteTypes; public type:SearchTypes;
constructor(public text:string, searchText:string, type:AutoCompeleteTypes) { constructor(public text:string, searchText:string, type:SearchTypes) {
let preIndex = text.toLowerCase().indexOf(searchText.toLowerCase()); let preIndex = text.toLowerCase().indexOf(searchText.toLowerCase());
if (preIndex > -1) { if (preIndex > -1) {
this.preText = text.substring(0, preIndex); this.preText = text.substring(0, preIndex);

View File

@ -23,7 +23,7 @@ export class NetworkService {
.toPromise() .toPromise()
.then(res => <Message<any>> res.json()) .then(res => <Message<any>> res.json())
.catch(NetworkService.handleError); .catch(NetworkService.handleError);
} }
return this._http[method](this._baseUrl + url, body, options) return this._http[method](this._baseUrl + url, body, options)
.toPromise() .toPromise()