export class EgCatalogService {
ccvmMap: {[ccvm:string] : EgIdlObject[]} = {};
- cmfMap: {[cmf:string] : EgIdlObject[]} = {};
+ cmfMap: {[cmf:string] : EgIdlObject} = {};
constructor(
private net: EgNetService,
) {}
search(ctx: CatalogSearchContext): Promise<void> {
- ctx.result = {};
ctx.searchInProgress = true;
var fullQuery = ctx.compileSearch();
})
}
+ fetchFacets(ctx: CatalogSearchContext): Promise<void> {
+
+ if (!ctx.result) return Promise.resolve();
+
+ return new Promise((resolve, reject) => {
+ this.net.request('open-ils.search',
+ 'open-ils.search.facet_cache.retrieve',
+ ctx.result.facet_key
+ ).subscribe(facets => {
+ let facetData = {};
+ Object.keys(facets).forEach(cmfId => {
+ let facetHash = facets[cmfId];
+ let cmf = this.cmfMap[cmfId];
+
+ let cmfData = [];
+ Object.keys(facetHash).forEach(value => {
+ let count = facetHash[value];
+ cmfData.push({value : value, count : count});
+ });
+
+ if (!facetData[cmf.field_class()])
+ facetData[cmf.field_class()] = {};
+
+ facetData[cmf.field_class()][cmf.name()] = {
+ cmfLabel : cmf.label(),
+ valueList : cmfData.sort((a, b) => {
+ if (a.count > b.count) return -1;
+ if (a.count < b.count) return 1;
+ // secondary alpha sort on display value
+ return a.value < b.value ? -1 : 1;
+ })
+ };
+ });
+
+ ctx.result.facetData = facetData;
+ resolve();
+ });
+ })
+ }
+
fetchCcvms(): Promise<void> {
if (Object.keys(this.ccvmMap).length)
isStaff: boolean;
// Result from most recent search.
- result: any;
+ result: any = {};
searchInProgress: boolean = false;
// Utility stuff
console.debug('EgCatalogResolver:resolve()');
return Promise.all([
- this.cat.fetchCcvms()
+ this.cat.fetchCcvms(),
+ this.cat.fetchCmfs()
]);
}
}
-TEST FACETS
+<style>
+ .facet-selected {
+ background-color: #DDD;
+ }
+ .card {
+ width: 100%;
+ }
+ .list-group-item {padding: .5rem .75rem .5rem .75rem}
+</style>
+<div *ngIf="searchContext.result.facetData">
+ <div *ngFor="let facetConf of facetConfig.display">
+ <div *ngIf="searchContext.result.facetData[facetConf.facetClass]">
+ <div *ngFor="let name of facetConf.facetOrder">
+ <div class="row"
+ *ngIf="searchContext.result.facetData[facetConf.facetClass][name]">
+ <div class="card mb-2">
+ <h5 class="card-header">
+ {{searchContext.result.facetData[facetConf.facetClass][name].cmfLabel}}
+ </h5>
+ <ul class="list-group list-group-flush">
+ <li class="list-group-item"
+ [ngClass]="{'facet-selected' :
+ facetIsApplied(facetConf.facetClass, name, value.value)}"
+ *ngFor="
+ let value of searchContext.result.facetData[facetConf.facetClass][name].valueList | slice:0:facetConfig.displayCount">
+ <div class="row">
+ <div class="col-10">
+ <a class="card-link"
+ (click)="context.apply_facet(facetConf.facetClass, name, value.value)">
+ {{value.value}}
+ </a>
+ </div>
+ <div class="col-2">{{value.count}}</div>
+ </div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
import {CatalogSearchContext} from '@eg/share/catalog/search-context';
import {StaffCatalogService} from '../staff-catalog.service';
+export const FACET_CONFIG = {
+ display: [
+ {facetClass : 'author', facetOrder : ['personal', 'corporate']},
+ {facetClass : 'subject', facetOrder : ['topic']},
+ {facetClass : 'identifier', facetOrder : ['genre']},
+ {facetClass : 'series', facetOrder : ['seriestitle']},
+ {facetClass : 'subject', facetOrder : ['name', 'geographic']}
+ ],
+ displayCount : 5
+};
+
@Component({
selector: 'eg-catalog-result-facets',
styleUrls: ['facets.component.css'],
export class ResultFacetsComponent implements OnInit {
searchContext: CatalogSearchContext;
+ facetConfig: any;
constructor(
private cat: EgCatalogService,
private staffCat: StaffCatalogService
- ) {}
+ ) {
+ this.facetConfig = FACET_CONFIG;
+ }
ngOnInit() {
this.searchContext = this.staffCat.searchContext;
}
+ facetIsApplied(cls: string, name: string, value: string) {
+ return this.searchContext.facetFilters.filter(f => {
+ return (
+ f.facetClass == cls &&
+ f.facetName == name &&
+ f.facetValue == value
+ );
+ })[0];
+ }
}
<div class="float-right">
<span>
<button (click)="placeHold()"
- class="btn btn-sm btn-success with-material-icon weak-text-1">
+ class="btn btn-sm btn-outline-success with-material-icon weak-text-1">
<span class="material-icons">check</span>
<span i18n>Place Hold</span>
</button>
</span>
<span>
<button (click)="addToList()"
- class="btn btn-sm btn-info with-material-icon weak-text-1">
+ class="btn btn-sm btn-outline-info with-material-icon weak-text-1">
<span class="material-icons">playlist_add_check</span>
<span i18n>Add to List</span>
</button>
</div>
<div class="row">
<div class="col-2">
- <!-- facets -->
+ <eg-catalog-result-facets></eg-catalog-result-facets>
</div>
<div class="col-10">
<div *ngIf="searchContext.result">
if (!this.searchContext.query[0]) return;
this.cat.search(this.searchContext).then(ok => {
+ this.cat.fetchFacets(this.searchContext);
this.fleshSearchResults();
});
}
(click)="searchContext.reset()">
Clear Form
</button>
- <button class="btn btn-secondary" type="button"
+ <button class="btn btn-outline-secondary" type="button"
*ngIf="!showAdvanced()"
(click)="showAdvancedSearch=true">
More Filters...
</button>
- <button class="btn btn-secondary" type="button"
+ <button class="btn btn-outline-secondary" type="button"
*ngIf="showAdvanced()"
(click)="showAdvancedSearch=false">
Hide Filters
searchContext: CatalogSearchContext;
ccvmMap: {[ccvm:string] : EgIdlObject[]} = {};
- cmfMap: {[cmf:string] : EgIdlObject[]} = {};
+ cmfMap: {[cmf:string] : EgIdlObject} = {};
showAdvancedSearch: boolean = false;
constructor(