LP1819745 Ang staff result page link repairs
[working/Evergreen.git] / Open-ILS / src / eg2 / src / app / share / catalog / catalog-url.service.ts
1 import {Injectable} from '@angular/core';
2 import {ParamMap} from '@angular/router';
3 import {OrgService} from '@eg/core/org.service';
4 import {CatalogSearchContext, CatalogBrowseContext, CatalogMarcContext,
5    CatalogTermContext, FacetFilter} from './search-context';
6 import {CATALOG_CCVM_FILTERS} from './search-context';
7 import {HashParams} from '@eg/share/util/hash-params';
8
9 @Injectable()
10 export class CatalogUrlService {
11
12     // consider supporting a param name prefix/namespace
13
14     constructor(private org: OrgService) { }
15
16     /**
17      * Returns a URL query structure suitable for using with
18      * router.navigate(..., {queryParams:...}).
19      * No navigation is performed within.
20      */
21     toUrlParams(context: CatalogSearchContext):
22             {[key: string]: string | string[]} {
23
24         const params: any = {};
25
26         if (context.searchOrg) {
27             params.org = context.searchOrg.id();
28         }
29
30         if (context.pager.limit) {
31             params.limit = context.pager.limit;
32         }
33
34         if (context.pager.offset) {
35             params.offset = context.pager.offset;
36         }
37
38         // These fields can be copied directly into place
39         ['limit', 'offset', 'sort', 'global', 'showBasket', 'sort']
40         .forEach(field => {
41             if (context[field]) {
42                 // Only propagate applied values to the URL.
43                 params[field] = context[field];
44             }
45         });
46
47         if (context.marcSearch.isSearchable()) {
48             const ms = context.marcSearch;
49             params.marcTag = [];
50             params.marcSubfield = [];
51             params.marcValue = [];
52
53             ms.values.forEach((val, idx) => {
54                 if (val !== '') {
55                     params.marcTag.push(ms.tags[idx]);
56                     params.marcSubfield.push(ms.subfields[idx]);
57                     params.marcValue.push(ms.values[idx]);
58                 }
59             });
60         }
61
62         if (context.identSearch.isSearchable()) {
63             params.identQuery = context.identSearch.value;
64             params.identQueryType = context.identSearch.queryType;
65         }
66
67         if (context.browseSearch.isSearchable()) {
68             params.browseTerm = context.browseSearch.value;
69             params.browseClass = context.browseSearch.fieldClass;
70             if (context.browseSearch.pivot) {
71                 params.browsePivot = context.browseSearch.pivot;
72             }
73         }
74
75         if (context.termSearch.isSearchable()) {
76
77             const ts = context.termSearch;
78
79             params.query = [];
80             params.fieldClass = [];
81             params.joinOp = [];
82             params.matchOp = [];
83
84             ['format', 'available', 'hasBrowseEntry', 'date1',
85                 'date2', 'dateOp', 'groupByMetarecord', 'fromMetarecord']
86             .forEach(field => {
87                 if (ts[field]) {
88                     params[field] = ts[field];
89                 }
90             });
91
92             ts.query.forEach((val, idx) => {
93                 if (val !== '') {
94                     params.query.push(ts.query[idx]);
95                     params.fieldClass.push(ts.fieldClass[idx]);
96                     params.joinOp.push(ts.joinOp[idx]);
97                     params.matchOp.push(ts.matchOp[idx]);
98                 }
99             });
100
101             // CCVM filters are encoded as comma-separated lists
102             Object.keys(ts.ccvmFilters).forEach(code => {
103                 if (ts.ccvmFilters[code] &&
104                     ts.ccvmFilters[code][0] !== '') {
105                     params[code] = ts.ccvmFilters[code].join(',');
106                 }
107             });
108
109             // Each facet is a JSON encoded blob of class, name, and value
110             if (ts.facetFilters.length) {
111                 params.facets = [];
112                 ts.facetFilters.forEach(facet => {
113                     params.facets.push(JSON.stringify({
114                         c : facet.facetClass,
115                         n : facet.facetName,
116                         v : facet.facetValue
117                     }));
118                 });
119             }
120
121             if (ts.copyLocations.length && ts.copyLocations[0] !== '') {
122                 params.copyLocations = ts.copyLocations.join(',');
123             }
124         }
125
126         if (context.cnBrowseSearch.isSearchable()) {
127             params.cnBrowseTerm = context.cnBrowseSearch.value;
128             params.cnBrowsePage = context.cnBrowseSearch.offset;
129         }
130
131         return params;
132     }
133
134     fromUrlHash(params: any): CatalogSearchContext {
135         return this.fromUrlParams(new HashParams(params));
136     }
137
138     /**
139      * Creates a new search context from the active route params.
140      */
141     fromUrlParams(params: ParamMap): CatalogSearchContext {
142         const context = new CatalogSearchContext();
143
144         this.applyUrlParams(context, params);
145
146         return context;
147     }
148
149     applyUrlParams(context: CatalogSearchContext, params: ParamMap): void {
150
151         // Reset query/filter args.  The will be reconstructed below.
152         context.reset();
153         let val;
154
155         if (params.get('org')) {
156             context.searchOrg = this.org.get(+params.get('org'));
157         }
158
159         if (val = params.get('limit')) {
160             context.pager.limit = +val;
161         }
162
163         if (val = params.get('offset')) {
164             context.pager.offset = +val;
165         }
166
167         if (val = params.get('sort')) {
168             context.sort = val;
169         }
170
171         if (val = params.get('global')) {
172             context.global = val;
173         }
174
175         if (val = params.get('showBasket')) {
176             context.showBasket = val;
177         }
178
179         if (params.get('marcValue')) {
180             context.marcSearch.tags = params.getAll('marcTag');
181             context.marcSearch.subfields = params.getAll('marcSubfield');
182             context.marcSearch.values = params.getAll('marcValue');
183         }
184
185         if (params.get('identQuery')) {
186             context.identSearch.value = params.get('identQuery');
187             context.identSearch.queryType = params.get('identQueryType');
188         }
189
190         if (params.get('browseTerm')) {
191             context.browseSearch.value = params.get('browseTerm');
192             context.browseSearch.fieldClass = params.get('browseClass');
193             if (params.has('browsePivot')) {
194                 context.browseSearch.pivot = +params.get('browsePivot');
195             }
196         }
197
198         if (params.get('cnBrowseTerm')) {
199             context.cnBrowseSearch.value = params.get('cnBrowseTerm');
200             context.cnBrowseSearch.offset = Number(params.get('cnBrowsePage'));
201         }
202
203         const ts = context.termSearch;
204
205         // browseEntry and query searches may be facet-limited
206         params.getAll('facets').forEach(blob => {
207             const facet = JSON.parse(blob);
208             ts.addFacet(new FacetFilter(facet.c, facet.n, facet.v));
209         });
210
211         if (params.has('hasBrowseEntry')) {
212
213             ts.hasBrowseEntry = params.get('hasBrowseEntry');
214
215         } else if (params.has('query')) {
216
217             // Scalars
218             ['format', 'available', 'date1', 'date2',
219                 'dateOp', 'groupByMetarecord', 'fromMetarecord']
220             .forEach(field => {
221                 if (params.has(field)) {
222                     ts[field] = params.get(field);
223                 }
224             });
225
226             // Arrays
227             ['query', 'fieldClass', 'joinOp', 'matchOp'].forEach(field => {
228                 const arr = params.getAll(field);
229                 if (params.has(field)) {
230                     ts[field] = params.getAll(field);
231                 }
232             });
233
234             CATALOG_CCVM_FILTERS.forEach(code => {
235                 const ccvmVal = params.get(code);
236                 if (ccvmVal) {
237                     ts.ccvmFilters[code] = ccvmVal.split(/,/);
238                 } else {
239                     ts.ccvmFilters[code] = [''];
240                 }
241             });
242
243             if (params.get('copyLocations')) {
244                 ts.copyLocations = params.get('copyLocations').split(/,/);
245             }
246         }
247     }
248 }
249
250