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