LP#1775466 Ang catalog supports most identifier query types
authorBill Erickson <berickxx@gmail.com>
Fri, 15 Jun 2018 21:57:45 +0000 (17:57 -0400)
committerBill Erickson <berickxx@gmail.com>
Fri, 15 Jun 2018 21:57:45 +0000 (17:57 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/share/catalog/catalog-url.service.ts
Open-ILS/src/eg2/src/app/share/catalog/search-context.ts
Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html
Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.ts

index b39f3ca..0974cb1 100644 (file)
@@ -25,6 +25,8 @@ export class CatalogUrlService {
             joinOp: [],
             matchOp: [],
             facets: [],
+            identQuery: null,
+            identQueryType: null,
             org: null,
             limit: null,
             offset: null
@@ -36,7 +38,7 @@ export class CatalogUrlService {
         }
 
         // These fields can be copied directly into place
-        ['format', 'sort', 'available', 'global']
+        ['format', 'sort', 'available', 'global', 'identQuery', 'identQueryType']
         .forEach(field => {
             if (context[field]) {
                 // Only propagate applied values to the URL.
@@ -92,7 +94,7 @@ export class CatalogUrlService {
         context.reset();
 
         // These fields can be copied directly into place
-        ['format', 'sort', 'available', 'global']
+        ['format', 'sort', 'available', 'global', 'identQuery', 'identQueryType']
         .forEach(field => {
             const val = params.get(field);
             if (val !== null) {
index 7b8908c..17789df 100644 (file)
@@ -39,6 +39,8 @@ export class CatalogSearchContext {
     sort: string;
     fieldClass: string[];
     query: string[];
+    identQuery: string; 
+    identQueryType: string; // isbn, issn, etc.
     joinOp: string[];
     matchOp: string[];
     format: string;
@@ -106,6 +108,8 @@ export class CatalogSearchContext {
         this.format = '';
         this.sort = '';
         this.query = [''];
+        this.identQuery = null;
+        this.identQueryType = 'isbn';
         this.fieldClass  = ['keyword'];
         this.matchOp = ['contains'];
         this.joinOp = [''];
@@ -117,6 +121,11 @@ export class CatalogSearchContext {
     }
 
     isSearchable(): boolean {
+
+        if (this.identQuery && this.identQueryType) {
+            return true;
+        }
+
         return this.query.length
             && this.query[0] !== ''
             && this.searchOrg !== null;
@@ -136,18 +145,25 @@ export class CatalogSearchContext {
             str += ' sort(' + parts[0] + ')';
         }
 
-        // -------
-        // Compile boolean sub-query components
-        if (str.length) { str += ' '; }
-        const qcount = this.query.length;
+        if (this.identQuery && this.identQueryType) {
+            if (str) { str += ' '; }
+            str += this.identQueryType + ':' + this.identQuery;
 
-        // if we multiple boolean query components, wrap them in parens.
-        if (qcount > 1) { str += '('; }
-        this.query.forEach((q, idx) => {
-            str += this.compileBoolQuerySet(idx);
-        });
-        if (qcount > 1) { str += ')'; }
-        // -------
+        } else {
+
+            // -------
+            // Compile boolean sub-query components
+            if (str.length) { str += ' '; }
+            const qcount = this.query.length;
+
+            // if we multiple boolean query components, wrap them in parens.
+            if (qcount > 1) { str += '('; }
+            this.query.forEach((q, idx) => {
+                str += this.compileBoolQuerySet(idx);
+            });
+            if (qcount > 1) { str += ')'; }
+            // -------
+        }
 
         if (this.format) {
             str += ' format(' + this.format + ')';
index 24ec4e6..ae9170c 100644 (file)
@@ -8,7 +8,7 @@ TODO focus search input
       <div class="flex-1">
         <div *ngIf="idx == 0">
           <select class="form-control" [(ngModel)]="searchContext.format">
-            <option value=''>All Formats</option>
+            <option i18n value=''>All Formats</option>
             <option *ngFor="let fmt of ccvmMap.search_format"
               value="{{fmt.code()}}">{{fmt.value()}}</option>
           </select>
@@ -16,30 +16,30 @@ TODO focus search input
         <div *ngIf="idx > 0">
           <select class="form-control"
             [(ngModel)]="searchContext.joinOp[idx]">
-            <option value='&&'>And</option>
-            <option value='||'>Or</option>
+            <option i18n value='&&'>And</option>
+            <option i18n value='||'>Or</option>
           </select>
         </div>
       </div>
       <div class="flex-1 pl-1">
         <select class="form-control" 
           [(ngModel)]="searchContext.fieldClass[idx]">
-          <option value='keyword'>Keyword</option>
-          <option value='title'>Title</option>
-          <option value='jtitle'>Journal Title</option>
-          <option value='author'>Author</option>
-          <option value='subject'>Subject</option>
-          <option value='series'>Series</option>
+          <option i18n value='keyword'>Keyword</option>
+          <option i18n value='title'>Title</option>
+          <option i18n value='jtitle'>Journal Title</option>
+          <option i18n value='author'>Author</option>
+          <option i18n value='subject'>Subject</option>
+          <option i18n value='series'>Series</option>
         </select>
       </div>
       <div class="flex-1 pl-1">
         <select class="form-control" 
           [(ngModel)]="searchContext.matchOp[idx]">
-          <option value='contains'>Contains</option>
-          <option value='nocontains'>Does not contain</option>
-          <option value='phrase'>Contains phrase</option>
-          <option value='exact'>Matches exactly</option>
-          <option value='starts'>Starts with</option>
+          <option i18n value='contains'>Contains</option>
+          <option i18n value='nocontains'>Does not contain</option>
+          <option i18n value='phrase'>Contains phrase</option>
+          <option i18n value='exact'>Matches exactly</option>
+          <option i18n value='starts'>Starts with</option>
         </select>
       </div>
       <div class="flex-2 pl-1">
@@ -193,6 +193,23 @@ TODO focus search input
           value="{{audience.code()}}">{{audience.value()}}</option>
       </select>
     </div>
+    <div class="col-lg-2">
+      <select class="form-control"
+        [(ngModel)]="searchContext.identQueryType">
+        <option i18n value="identifier|isbn">ISBN</option>
+        <option i18n value="identifier|issn">ISSN</option>
+        <option i18n disabled value="cnbrowse">Call Number (Shelf Browse)</option>
+        <option i18n value="identifier|lccn">LCCN</option>
+        <option i18n value="identifier|tcn">TCN</option>
+        <option i18n disabled value="item_barcode">Item Barcode</option>
+      </select>
+    </div>
+    <div class="col-lg-2">
+      <input id='ident-query-input' type="text" class="form-control"
+        [(ngModel)]="searchContext.identQuery"
+        (keyup.enter)="formEnter()"
+        placeholder="Numeric Query..."/>
+    </div>
   </div>
   <div class="row pt-2" *ngIf="showAdvanced()">
     <div class="col-lg-2">
index b679160..dbffe9c 100644 (file)
@@ -39,7 +39,14 @@ export class SearchFormComponent implements OnInit, AfterViewInit {
         // Query inputs are generated from search context data,
         // so they are not available until after the first render.
         // Search context data is extracted synchronously from the URL.
-        this.renderer.selectRootElement('#first-query-input').focus();
+
+        if (this.searchContext.identQuery) {
+            // Focus identifier query input if identQuery is in progress
+            this.renderer.selectRootElement('#ident-query-input').focus();
+        } else {
+            // Otherwise focus the main query input
+            this.renderer.selectRootElement('#first-query-input').focus();
+        }
     }
 
     /**
@@ -60,6 +67,10 @@ export class SearchFormComponent implements OnInit, AfterViewInit {
             }
         });
 
+        if (this.searchContext.identQuery) {
+            show = true;
+        }
+
         return show;
     }