LP1819745 Ang staff result page link repairs
authorBill Erickson <berickxx@gmail.com>
Tue, 12 Mar 2019 16:56:47 +0000 (12:56 -0400)
committerDan Wells <dbw2@calvin.edu>
Wed, 29 May 2019 19:30:51 +0000 (15:30 -0400)
Title, Title-by-Jacket-image, Author, and Facet links in the Angular
staff catalog now behave like regular browser links, which means they
can used to open new tabs via control-click, etc.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Dan Wells <dbw2@calvin.edu>
Open-ILS/src/eg2/src/app/share/catalog/catalog-url.service.ts
Open-ILS/src/eg2/src/app/share/catalog/catalog.service.ts
Open-ILS/src/eg2/src/app/share/catalog/search-context.ts
Open-ILS/src/eg2/src/app/share/util/hash-params.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/catalog/catalog.service.ts
Open-ILS/src/eg2/src/app/staff/catalog/result/facets.component.html
Open-ILS/src/eg2/src/app/staff/catalog/result/facets.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.html
Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.ts

index a59b7fc..91922d4 100644 (file)
@@ -4,6 +4,7 @@ import {OrgService} from '@eg/core/org.service';
 import {CatalogSearchContext, CatalogBrowseContext, CatalogMarcContext,
    CatalogTermContext, FacetFilter} from './search-context';
 import {CATALOG_CCVM_FILTERS} from './search-context';
+import {HashParams} from '@eg/share/util/hash-params';
 
 @Injectable()
 export class CatalogUrlService {
@@ -130,6 +131,10 @@ export class CatalogUrlService {
         return params;
     }
 
+    fromUrlHash(params: any): CatalogSearchContext {
+        return this.fromUrlParams(new HashParams(params));
+    }
+
     /**
      * Creates a new search context from the active route params.
      */
index 55fd18e..9cff2c4 100644 (file)
@@ -1,6 +1,6 @@
 import {Injectable, EventEmitter} from '@angular/core';
 import {Observable} from 'rxjs';
-import {mergeMap, map, tap} from 'rxjs/operators';
+import {map, tap} from 'rxjs/operators';
 import {OrgService} from '@eg/core/org.service';
 import {UnapiService} from '@eg/share/catalog/unapi.service';
 import {IdlService, IdlObject} from '@eg/core/idl.service';
index 222536f..ef0fd55 100644 (file)
@@ -1,7 +1,6 @@
 import {OrgService} from '@eg/core/org.service';
 import {IdlObject} from '@eg/core/idl.service';
 import {Pager} from '@eg/share/util/pager';
-import {Params} from '@angular/router';
 
 // CCVM's we care about in a catalog context
 // Don't fetch them all because there are a lot.
diff --git a/Open-ILS/src/eg2/src/app/share/util/hash-params.ts b/Open-ILS/src/eg2/src/app/share/util/hash-params.ts
new file mode 100644 (file)
index 0000000..86a7bb5
--- /dev/null
@@ -0,0 +1,29 @@
+import {ParamMap} from '@angular/router';
+
+
+/**
+ * Class to map a generic hash to an Angular ParamMap.
+ */
+export class HashParams implements ParamMap {
+    private params: {[key: string]: any[]};
+
+    public get keys(): string[] {
+        return Object.keys(this.params);
+    }
+
+    constructor(params: {[key: string]: any}) {
+        this.params = params || {};
+    }
+
+    has(key: string): boolean {
+        return key in this.params;
+    }
+
+    get(key: string): string | null {
+        return this.has(key) ? [].concat(this.params[key])[0] : null;
+    }
+
+    getAll(key: string): string[] {
+        return this.has(key) ? [].concat(this.params[key]) : [];
+    }
+}
index 3b4f696..3c1ba95 100644 (file)
@@ -47,6 +47,11 @@ export class StaffCatalogService {
         this.applySearchDefaults();
     }
 
+    cloneContext(context: CatalogSearchContext): CatalogSearchContext {
+        const params: any = this.catUrl.toUrlParams(context);
+        return this.catUrl.fromUrlHash(params);
+    }
+
     applySearchDefaults(): void {
         if (!this.searchContext.searchOrg) {
             this.searchContext.searchOrg =
index 9681747..2c2cb14 100644 (file)
@@ -26,8 +26,8 @@
                 <div class="row">
                   <div class="col-lg-9">
                     <a class="card-link"
-                      href='javascript:;'
-                      (click)="applyFacet(facetConf.facetClass, name, value.value)">
+                      routerLink="/staff/catalog/search"
+                      [queryParams]="getFacetUrlParams(facetConf.facetClass, name, value.value)">
                       {{value.value}}
                     </a>
                   </div>
index f16215a..aacb27c 100644 (file)
@@ -1,5 +1,6 @@
 import {Component, OnInit, Input} from '@angular/core';
 import {CatalogService} from '@eg/share/catalog/catalog.service';
+import {CatalogUrlService} from '@eg/share/catalog/catalog-url.service';
 import {CatalogSearchContext, FacetFilter} from '@eg/share/catalog/search-context';
 import {StaffCatalogService} from '../catalog.service';
 
@@ -25,6 +26,7 @@ export class ResultFacetsComponent implements OnInit {
 
     constructor(
         private cat: CatalogService,
+        private catUrl: CatalogUrlService,
         private staffCat: StaffCatalogService
     ) {
         this.facetConfig = FACET_CONFIG;
@@ -38,10 +40,11 @@ export class ResultFacetsComponent implements OnInit {
         return this.searchContext.termSearch.hasFacet(new FacetFilter(cls, name, value));
     }
 
-    applyFacet(cls: string, name: string, value: string): void {
-        this.searchContext.termSearch.toggleFacet(new FacetFilter(cls, name, value));
-        this.searchContext.pager.offset = 0;
-        this.staffCat.search();
+    getFacetUrlParams(cls: string, name: string, value: string): any {
+        const context = this.staffCat.cloneContext(this.searchContext);
+        context.termSearch.toggleFacet(new FacetFilter(cls, name, value));
+        context.pager.offset = 0;
+        return this.catUrl.toUrlParams(context);
     }
 }
 
index eb33fe8..5ddf94e 100644 (file)
         <!-- XXX hard-coded width so columns align vertically regardless
              of the presence of a jacket image -->
         <div class="pl-2 record-jacket-div" >
-          <a href="javascript:void(0)" (click)="navigateToRecord(summary)">
-            <img src="/opac/extras/ac/jacket/small/r/{{summary.id}}"/>
-          </a>
+          <ng-container *ngIf="hasMrConstituentRecords(summary)">
+            <a routerLink="/staff/catalog/search"
+              [queryParams]="appendFromMrParam(summary)">
+              <img src="/opac/extras/ac/jacket/small/r/{{summary.id}}"/>
+            </a>
+          </ng-container>
+          <ng-container *ngIf="!hasMrConstituentRecords(summary)">
+              <a routerLink="/staff/catalog/record/{{summary.id}}"
+                [queryParams]="currentParams()">
+                <img src="/opac/extras/ac/jacket/small/r/{{summary.id}}"/>
+              </a>
+          </ng-container>
         </div>
         <!-- for call number browse display -->
         <ng-container *ngIf="callNumber">
           <div class="row">
             <div class="col-lg-12 font-weight-bold">
               <!-- nbsp allows the column to take shape when no value exists -->
-              <a href="javascript:void(0)"
-                (click)="navigateToRecord(summary)">
-                {{summary.display.title || '&nbsp;'}}
-              </a>
+              <ng-container *ngIf="hasMrConstituentRecords(summary)">
+                  <a routerLink="/staff/catalog/search"
+                    [queryParams]="appendFromMrParam(summary)">
+                    {{summary.display.title || '&nbsp;'}}
+                  </a>
+              </ng-container>
+              <ng-container *ngIf="!hasMrConstituentRecords(summary)">
+                <a routerLink="/staff/catalog/record/{{summary.id}}"
+                  [queryParams]="currentParams()">
+                  {{summary.display.title || '&nbsp;'}}
+                </a>
+              </ng-container>
             </div>
           </div>
           <div class="row pt-2">
             <div class="col-lg-12">
               <!-- nbsp allows the column to take shape when no value exists -->
-              <a href="javascript:void(0)"
-                (click)="searchAuthor(summary)">
+              <a routerLink="/staff/catalog/search"
+                  [queryParams]="getAuthorSearchParams(summary)">
                 {{summary.display.author || '&nbsp;'}}
               </a>
             </div>
index 8505e76..b46e4ca 100644 (file)
@@ -1,6 +1,6 @@
 import {Component, OnInit, OnDestroy, Input} from '@angular/core';
 import {Subscription} from 'rxjs';
-import {Router} from '@angular/router';
+import {Router, ParamMap} from '@angular/router';
 import {OrgService} from '@eg/core/org.service';
 import {NetService} from '@eg/core/net.service';
 import {IdlObject} from '@eg/core/idl.service';
@@ -82,29 +82,35 @@ export class ResultRecordComponent implements OnInit, OnDestroy {
         alert('Adding to list for bib ' + this.summary.id);
     }
 
-    searchAuthor(summary: any) {
-        this.searchContext.reset();
-        this.searchContext.termSearch.fieldClass = ['author'];
-        this.searchContext.termSearch.query = [summary.display.author];
-        this.staffCat.search();
+    // Params to genreate a new author search based on a reset
+    // clone of the current page params.
+    getAuthorSearchParams(summary: BibRecordSummary): any {
+        const tmpContext = this.staffCat.cloneContext(this.searchContext);
+        tmpContext.reset();
+        tmpContext.termSearch.fieldClass = ['author'];
+        tmpContext.termSearch.query = [summary.display.author];
+        return this.catUrl.toUrlParams(tmpContext);
     }
 
-    /**
-     * Propagate the search params along when navigating to each record.
-     */
-    navigateToRecord(summary: BibRecordSummary) {
-        const params = this.catUrl.toUrlParams(this.searchContext);
-
-        // Jump to metarecord constituent records page when a
-        // MR has more than 1 constituents.
-        if (summary.metabibId && summary.metabibRecords.length > 1) {
-            this.searchContext.termSearch.fromMetarecord = summary.metabibId;
-            this.staffCat.search();
-            return;
-        }
+    // Returns the URL parameters for the current page plus the
+    // "fromMetarecord" param used for linking title links to
+    // MR constituent result records list.
+    appendFromMrParam(summary: BibRecordSummary): any {
+        const tmpContext = this.staffCat.cloneContext(this.searchContext);
+        tmpContext.termSearch.fromMetarecord = summary.metabibId;
+        return this.catUrl.toUrlParams(tmpContext);
+    }
+
+    // Returns true if the selected record summary is a metarecord summary
+    // and it links to more than one constituent bib record.
+    hasMrConstituentRecords(summary: BibRecordSummary): boolean {
+        return (
+            summary.metabibId && summary.metabibRecords.length > 1
+        );
+    }
 
-        this.router.navigate(
-            ['/staff/catalog/record/' + summary.id], {queryParams: params});
+    currentParams(): any {
+        return this.catUrl.toUrlParams(this.searchContext);
     }
 
     toggleBasketEntry() {