import {Injectable} from '@angular/core';
import {ParamMap} from '@angular/router';
import {EgOrgService} from '@eg/core/org';
-import {CatalogSearchContext} from './search-context';
+import {CatalogSearchContext, FacetFilter} from './search-context';
import {CATALOG_CCVM_FILTERS} from './catalog.service';
@Injectable()
});
params.getAll('facets').forEach(blob => {
- context.facetFilters.push(JSON.parse(blob));
+ let facet: FacetFilter = JSON.parse(blob)
+ context.addFacet(facet);
});
context.searchOrg =
import {EgIdlObject} from '@eg/core/idl';
import {EgNetService} from '@eg/core/net';
import {EgPcrudService} from '@eg/core/pcrud';
-import {CatalogSearchContext} from './search-context';
+import {CatalogSearchContext, CatalogSearchState} from './search-context';
export const CATALOG_CCVM_FILTERS = [
'item_type',
) {}
search(ctx: CatalogSearchContext): Promise<void> {
- ctx.searchInProgress = true;
+ ctx.searchState = CatalogSearchState.SEARCHING;
var fullQuery = ctx.compileSearch();
ctx.result = result;
ctx.result.records = [];
ctx.pager.resultCount = result.count;
- ctx.searchInProgress = false;
+ ctx.searchState = CatalogSearchState.COMPLETE;
let promises = [];
result.ids.forEach(blob => {
// Document and enforce facet filter entries.
-interface FacetFilter {
+export class FacetFilter {
facetClass: string;
facetName: string;
facetValue: string;
+
+ constructor(cls: string, name: string, value: string) {
+ this.facetClass = cls;
+ this.facetName = name;
+ this.facetValue = value;
+ }
+
+ equals(filter: FacetFilter): boolean {
+ return (
+ this.facetClass == filter.facetClass &&
+ this.facetName == filter.facetName &&
+ this.facetValue == filter.facetValue
+ );
+ }
+}
+
+export enum CatalogSearchState {
+ PENDING,
+ SEARCHING,
+ COMPLETE
}
// Not an angular service.
export class CatalogSearchContext {
// Search options and filters
- available: boolean;
- global: boolean;
+ available: boolean = false;
+ global: boolean = false;
sort: string;
fieldClass: string[];
query: string[];
// Result from most recent search.
result: any = {};
- searchInProgress: boolean = false;
+ searchState: CatalogSearchState = CatalogSearchState.PENDING;
// Utility stuff
pager: Pager;
this.reset();
}
+ /**
+ * Reset search parameters. This does not reset global filters
+ * like limit-to-available and search-global.
+ */
reset(): void {
this.pager.offset = 0,
this.format = '',
this.fieldClass = ['keyword'];
this.matchOp = ['contains'];
this.joinOp = [''];
- this.available = false;
- this.global = false;
this.ccvmFilters = {};
this.facetFilters = [];
}
compileSearch(): string {
let str: string = '';
- if (this.available) str += ' #available';
+ if (this.available) str += '#available';
if (this.sort) {
// e.g. title, title.descending
return str + query + ')';
}
+
+ hasFacet(facet: FacetFilter): boolean {
+ return Boolean(
+ this.facetFilters.filter(
+ f => {return f.equals(facet)})[0]
+ );
+ }
+
+ removeFacet(facet: FacetFilter): void {
+ this.facetFilters = this.facetFilters.filter(
+ f => { return !f.equals(facet); });
+ }
+
+ addFacet(facet: FacetFilter): void {
+ if (!this.hasFacet(facet))
+ this.facetFilters.push(facet);
+ }
+
+ toggleFacet(facet: FacetFilter): void {
+ if (this.hasFacet(facet)) {
+ this.removeFacet(facet);
+ } else {
+ this.facetFilters.push(facet);
+ }
+ }
}
import {EgCatalogComponent} from './catalog.component';
import {SearchFormComponent} from './search-form.component';
import {ResultsComponent} from './result/results.component';
+import {RecordComponent} from './record/record.component';
import {ResultPaginationComponent} from './result/pagination.component';
import {ResultFacetsComponent} from './result/facets.component';
import {ResultRecordComponent} from './result/record.component';
declarations: [
EgCatalogComponent,
ResultsComponent,
+ RecordComponent,
SearchFormComponent,
ResultRecordComponent,
ResultFacetsComponent,
--- /dev/null
+
+<div id="staff-catalog-record-container">
+ RECORD {{recordId}}
+</div>
+
--- /dev/null
+import {Component, OnInit, Input} from '@angular/core';
+import {ActivatedRoute, ParamMap} from '@angular/router';
+import {EgPcrudService} from '@eg/core/pcrud';
+import {EgIdlObject} from '@eg/core/idl';
+import {CatalogSearchContext, CatalogSearchState}
+ from '@eg/share/catalog/search-context';
+import {StaffCatalogService} from '../staff-catalog.service';
+
+@Component({
+ selector: 'eg-catalog-record',
+ styleUrls: ['record.component.css'],
+ templateUrl: 'record.component.html'
+})
+export class RecordComponent implements OnInit {
+
+ recordId: number;
+ searchContext: CatalogSearchContext;
+
+ // Cache record creator/editor since this will likely be a
+ // reasonably small set of data w/ lots of repitition.
+ userCache: {[id:number] : EgIdlObject} = {};
+
+ constructor(
+ private route: ActivatedRoute,
+ private pcrud: EgPcrudService,
+ private staffCat: StaffCatalogService
+ ) {}
+
+ ngOnInit() {
+ this.recordId = +this.route.snapshot.paramMap.get('id');
+ }
+}
+
+
*ngFor="
let value of searchContext.result.facetData[facetConf.facetClass][name].valueList | slice:0:facetConfig.displayCount">
<div class="row">
- <div class="col-10">
+ <div class="col-9">
<a class="card-link"
- (click)="context.apply_facet(facetConf.facetClass, name, value.value)">
+ href='javascript:;'
+ (click)="applyFacet(facetConf.facetClass, name, value.value)">
{{value.value}}
</a>
</div>
- <div class="col-2">{{value.count}}</div>
+ <div class="col-3">{{value.count}}</div>
</div>
</li>
</ul>
import {Component, OnInit, Input} from '@angular/core';
import {EgCatalogService} from '@eg/share/catalog/catalog.service';
-import {CatalogSearchContext} from '@eg/share/catalog/search-context';
+import {CatalogSearchContext, FacetFilter} 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
+ 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({
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];
+ facetIsApplied(cls: string, name: string, value: string): boolean {
+ return this.searchContext.hasFacet(new FacetFilter(cls, name, value));
+ }
+
+ applyFacet(cls: string, name: string, value: string): void {
+ this.searchContext.toggleFacet(new FacetFilter(cls, name, value));
+ this.searchContext.pager.offset = 0;
+ this.staffCat.search();
}
}
/* Bootstrap default is 20px */
.pagination {margin: 10px 0px 10px 0px}
-/* style a's without hrefs
- * TODO: consider moving this to a shared css file
- * */
-.pagination a:hover {
- cursor: pointer;
-}
-
<ul class="pagination">
<li class="page-item" [ngClass]="{disabled : searchContext.pager.isFirstPage()}">
- <a (click)="prevPage()"
+ <a
+ href='javascript:;'
+ (click)="prevPage()"
class="page-link" aria-label="[% l('Previous') %]">
<span aria-hidden="true">«</span>
</a>
</li>
<li class="page-item" *ngFor="let page of searchContext.pager.pageList()"
[ngClass]="{active : searchContext.pager.currentPage() == page}">
- <a (click)="setPage(page)" class="page-link">
+ <a href='javascript:;' (click)="setPage(page)" class="page-link">
{{page}} <span class="sr-only">(current)</span></a>
</li>
<li class="page-item" [ngClass]="{disabled : searchContext.pager.isLastPage()}">
- <a (click)="nextPage()"
+ <a href='javascript:;' (click)="nextPage()"
class="page-link" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
<div class="row">
<div class="col-12 font-weight-bold">
<!-- nbsp allows the column to take shape when no value exists -->
- <a href="./cat/staffcat/record/{{bibSummary.id}}">
+ <a href='javascript:;' routerLink="/staff/catalog/record/{{bibSummary.id}}">
{{bibSummary.title || ' '}}
</a>
</div>
<div class="row pt-2">
<div class="col-12">
<!-- nbsp allows the column to take shape when no value exists -->
- <a href (click)="searchAuthor(bibSummary)" style="font-style:italic">
+ <a href='javascript:;'
+ (click)="searchAuthor(bibSummary)" style="font-style:italic">
{{bibSummary.author || ' '}}
</a>
</div>
<div class="float-right">
<span>
<button (click)="placeHold()"
- class="btn btn-sm btn-outline-success with-material-icon weak-text-1">
+ class="btn btn-sm btn-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-outline-info with-material-icon weak-text-1">
+ class="btn btn-sm btn-info with-material-icon weak-text-1">
<span class="material-icons">playlist_add_check</span>
<span i18n>Add to List</span>
</button>
alert('Adding to list for bib ' + this.bibSummary.id);
}
+ searchAuthor(bibSummary: any) {
+ this.searchContext.reset();
+ this.searchContext.fieldClass = ['author'];
+ this.searchContext.query = [bibSummary.author];
+ this.staffCat.search();
+ }
+
}
-<div id="staff-catalog-results-container">
+<div id="staff-catalog-results-container" *ngIf="searchIsDone()">
<div class="row">
<div class="col-2" style="margin-top:10px"><!--match pagination margin-->
<h5 i18n>Search Results ({{searchContext.result.count}})</h5>
import {ActivatedRoute, ParamMap} from '@angular/router';
import {EgCatalogService} from '@eg/share/catalog/catalog.service';
import {EgCatalogUrlService} from '@eg/share/catalog/catalog-url.service';
-import {CatalogSearchContext} from '@eg/share/catalog/search-context';
+import {CatalogSearchContext, CatalogSearchState}
+ from '@eg/share/catalog/search-context';
import {EgPcrudService} from '@eg/core/pcrud';
import {StaffCatalogService} from '../staff-catalog.service';
import {EgIdlObject} from '@eg/core/idl';
});
}
- searchAuthor(bibSummary: any) {
+ searchIsDone(): boolean {
+ return this.searchContext.searchState == CatalogSearchState.COMPLETE;
}
+
}
import {RouterModule, Routes} from '@angular/router';
import {EgCatalogComponent} from './catalog.component';
import {ResultsComponent} from './result/results.component';
+import {RecordComponent} from './record/record.component';
import {EgCatalogResolver} from './resolver.service';
const routes: Routes = [{
children : [{
path: 'search',
component: ResultsComponent,
+ }, {
+ path: 'record/:id',
+ component: RecordComponent,
}]
}];
<button class="btn btn-outline-secondary" type="button"
*ngIf="!showAdvanced()"
(click)="showAdvancedSearch=true">
- More Filters...
+ More Filters
</button>
<button class="btn btn-outline-secondary" type="button"
*ngIf="showAdvanced()"
</p>
<hr class="my-4"/>
<p i18n>
- But maybe you meant to go to the <a routerLink="/staff">staff page</a>
+ But maybe you meant to go to the <a routerLink="/staff/splash">staff page</a>
or <a routerLink="/catalog">the catalog.</a>
</p>
</div>