<!-- header, pager, and list of records -->
<div id="staff-catalog-results-container" *ngIf="searchHasResults()">
+ <div class="row d-flex mb-2" *ngIf="searchContext.termSearch.browseEntry">
+ <div class="col-lg-10 offset-lg-2">
+ <h3 i18n>Results for browse entry "{{searchContext.termSearch.browseEntry.value()}}"</h3>
+ </div>
+ </div>
<div class="row">
<div class="col-lg-2" *ngIf="!searchContext.basket">
- <ng-container *ngIf="searchContext.termSearch.browseEntry">
- <h3 i18n>Results for browse "{{searchContext.termSearch.browseEntry.value()}}"</h3>
- </ng-container>
<ng-container *ngIf="!searchContext.termSearch.browseEntry">
<h3 i18n>Search Results ({{searchContext.result.count}})</h3>
</ng-container>
</span>
</label>
</div>
- <div class="col-lg-8">
- <div class="float-right">
- <eg-catalog-result-pagination></eg-catalog-result-pagination>
+
+ <ng-container *ngIf="searchContext.browseSearch.value">
+ <div class="col-lg-3">
+ <ng-container *ngIf="browseLoading">
+ <eg-progress-inline></eg-progress-inline>
+ </ng-container>
+ <ng-container *ngIf="!browseLoading">
+ <button class="btn btn-sm btn-outline-dark"
+ (click)="browseNav(true)" i18n>Previous Heading</button>
+ <button class="btn btn-sm btn-outline-dark ml-2"
+ (click)="browseNav()" i18n>Next Heading</button>
+ </ng-container>
</div>
- </div>
+ <div class="col-lg-5">
+ <div class="float-right">
+ <eg-catalog-result-pagination></eg-catalog-result-pagination>
+ </div>
+ </div>
+ </ng-container>
+ <ng-container *ngIf="!searchContext.browseSearch.value">
+ <div class="col-lg-8">
+ <div class="float-right">
+ <eg-catalog-result-pagination></eg-catalog-result-pagination>
+ </div>
+ </div>
+ </ng-container>
</div>
<div>
<div class="row mt-2">
import {Component, OnInit, OnDestroy, Input} from '@angular/core';
import {Observable, Subscription} from 'rxjs';
-import {map, switchMap, distinctUntilChanged} from 'rxjs/operators';
+import {tap, map, switchMap, distinctUntilChanged} from 'rxjs/operators';
import {ActivatedRoute, ParamMap} from '@angular/router';
import {CatalogService} from '@eg/share/catalog/catalog.service';
import {BibRecordService} from '@eg/share/catalog/bib-record.service';
searchSub: Subscription;
routeSub: Subscription;
basketSub: Subscription;
+ browseResults: any[] = [];
+ browseLoading = false;
constructor(
private route: ActivatedRoute,
});
// After each completed search, update the record selector.
- this.searchSub = this.cat.onSearchComplete.subscribe(
- ctx => this.applyRecordSelection());
+ this.searchSub = this.cat.onSearchComplete.subscribe(ctx => {
+ this.applyRecordSelection();
+ });
// Watch for basket changes applied by other components.
this.basketSub = this.basket.onChange.subscribe(
() => this.applyRecordSelection());
+
+
+ // Load browse data to support browse paging.
+ /*
+ if (this.searchContext.termSearch.hasBrowseEntry &&
+ this.searchContext.browseSearch.value) {
+ this.fetchBrowseData().toPromise();
+ }
+ */
}
ngOnDestroy() {
this.basket.removeRecordIds(ids);
}
}
+
+ // Grab a page of browse results
+ fetchBrowseData(prev?: boolean): Promise<any> {
+ const ctx = this.searchContext.clone();
+ ctx.termSearch.hasBrowseEntry = null; // avoid term search
+
+ // Grab a few extras so we can last a bit longer before
+ // having to fetch more browse data. Could make this bigger.
+ ctx.pager.limit = 20;
+
+ const results = [];
+
+ return this.cat.browse(ctx)
+ .pipe(tap(result => results.push(result)))
+ .toPromise().then(_ => {
+ if (prev) {
+ this.browseResults = results.concat(this.browseResults);
+ } else {
+ this.browseResults = this.browseResults.concat(results);
+ }
+ });
+ }
+
+ // Find the browse entry for the next/prev page and navigate there
+ // if possible. Returns false if not enough data is available.
+ goToBrowsePage(prev?: boolean): boolean {
+ const ctx = this.searchContext;
+
+ // See if we have enough info to direct to the selected page.
+
+ const mbeId = Number( // for this page
+ this.searchContext.termSearch.hasBrowseEntry.split(',')[0]);
+
+ let target, previous;
+
+ this.browseResults.forEach(result => {
+ if (!result.browse_entry) { return; } // ignore pivot entries
+
+ if (previous) {
+ if (prev) {
+ if (result.browse_entry === mbeId) {
+ target = previous;
+ }
+ } else {
+ if (previous.browse_entry === mbeId) {
+ target = result;
+ }
+ }
+ }
+ previous = result;
+ });
+
+ if (!target) { return false; }
+
+ // Jump to the selected browse entry's page.
+ ctx.termSearch.hasBrowseEntry = target.browse_entry + ',' + target.fields;
+ ctx.pager.offset = 0; // this is a brand new search
+ this.staffCat.search();
+
+ return true;
+ }
+
+
+ // Navigate to next or previous browse entry page.
+ // take1: navigate without fetching data if possible
+ // take2: fetch data and navigate if possible.
+ // take3: data fetched in take2 contains data for this page, but
+ // not the requested page. This happens when the user navigates
+ // cold to a browse page boundary and the current page of data
+ // does not yet exist.
+ browseNav(prev?: boolean, take?: number) {
+ if (!take) { take = 1; }
+
+ this.browseLoading = true;
+
+ if (take > 3) {
+ // We tried our best, but could not find the requested
+ // browse data Could happen if we reach the end of the data set.
+ this.browseLoading = false;
+ return;
+ }
+
+ if (this.goToBrowsePage(prev)) {
+ // Navigation successful
+ this.browseLoading = false;
+ return;
+ }
+
+ // We need another page of browse data before we can direct
+ // the user to the requested page.
+
+ const results = this.browseResults;
+ if (results.length > 0) {
+ this.searchContext.browseSearch.pivot = prev ?
+ results[0].pivot_point :
+ results[results.length - 1].pivot_point;
+ }
+
+ this.fetchBrowseData(prev).then(_ => this.browseNav(prev, take + 1));
+ }
}