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:
parent
60dab77cf4
commit
d32914bc02
@ -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));
|
||||||
|
@ -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);
|
||||||
}
|
}
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -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
|
||||||
);
|
);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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> = [];
|
||||||
|
|
||||||
}
|
}
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user