PageSourceSearch

https://www.stlouisfed.org/-/media/base-themes/searchtheme/scripts/component-search-service.js

js stlouisfed.org collected 2026-09-24 06:39:49 UTC 18,012 bytes, 347 lines download raw bytes

1/**
2 * Model for search services
3 * @module SearchServiceModel
4 * @param  {jQuery} $ Instance of jQuery
5 * @param  {Document} document dom document object
6 * @return {SearchServiceModel} instance of search service model
7*/
8XA.component.search.service = (function ($, document) {
9
10    'use strict';
11
12    var searchResultsModels = XA.component.search.results.searchResultModels,
13        urlHelperModel = XA.component.search.url,
14        queryModel = XA.component.search.query,
15        queryParameters = XA.component.search.parameters,
16        apiModel = XA.component.search.ajax,
17        SearchServiceModel;
18    /**
19     * @name module:SearchServiceModel.SearchServiceModel
20     * @constructor
21     * @augments Backbone.Model
22     */
23    SearchServiceModel = Backbone.Model.extend(
24        /** @lends module:SearchServiceModel.SearchServiceModel.prototype **/
25        {
26            /**
27            * Default model options
28            * @default
29            */
30            defaults: {
31            },
32            /**
33            * Watches for event 'orderChanged' and trigger
34            * ['getData']{@link module:SearchServiceModel.SearchServiceModel#getData}
35            * @listens module:XA.component.search.vent~event:orderChanged
36            * @memberof module:SearchServiceModel.SearchServiceModel
37            */
38            initialize: function () {
39                var that = this;
40                XA.component.search.vent.on('orderChanged', function (data) {
41                    that.getData(data);
42                });
43            },
44            /**
45            * If search result model created call
46            * ['getSearchResultsData']{@link module:SearchServiceModel.SearchServiceModel#getSearchResultsData}
47            * in other case call 
48            * ['getEndpointAndSearch']{@link module:SearchServiceModel.SearchServiceModel#getEndpointAndSearch} 
49            * @param {Object} overrideProps new properties fro overriding
50            * @memberof module:SearchServiceModel.SearchServiceModel
51            * @alias module:SearchServiceModel.SearchServiceModel#getData
52            */
53            getData: function (overrideProps) {
54                if (searchResultsModels.length > 0) {
55                    this.getSearchResultsData(overrideProps);
56                } else {
57                    this.getEndpointAndSearch(overrideProps);
58                }
59            },
60            /**
61            * Processes search result data
62            * @param {Object} overrideProps properties for overriding
63            * @memberof module:SearchServiceModel.SearchServiceModel
64            * @alias module:SearchServiceModel.SearchServiceModel#getSearchResultsData
65            */
66            getSearchResultsData: function (overrideProps) {
67                var hash = queryModel.parseHashParameters(window.location.hash),
68                    that = this,
69                    defaultSortOrder,
70                    offsetSignature,
71                    searchResultsDefaultPageSize,
72                    searchResultsDefaultVariant,
73                    signature,
74                    mergedProps,
75                    url;
76
77                _.each(searchResultsModels, function (searchModel) {
78                    signature = searchModel.get('dataProperties').sig !== null
79                        ? encodeURIComponent(searchModel.get('dataProperties').sig)
80                        : "";
81                    offsetSignature = signature !== '' ? signature + "_e" : "e";
82
83                    if (!searchModel.get('dataProperties').autoFireSearch) {
84                        //If hash is not present or no criteria with search model signature is present in hash, then do not fire search
85                        if (!hash || !queryModel.isSignaturePresentInHash(hash, signature)) {
86                            return;
87                        }
88                    }
89
90                    defaultSortOrder = searchModel.get('dataProperties').defaultSortOrder;
91                    searchResultsDefaultPageSize = searchModel.get('dataProperties').p;
92                    searchResultsDefaultVariant = searchModel.get('dataProperties').v;
93
94                    //if we have singleRequestMode with signature, then we are getting data just for that signature
95                    if (typeof overrideProps !== "undefined" &&
96                        overrideProps.hasOwnProperty("singleRequestMode") &&
97                        overrideProps["singleRequestMode"] != signature) {
98                        return;
99                    }
100
101                    //if there is no page size param in the query, but we have page size component on the page, then take
102                    //default page size or first (if default isn't set)
103                    hash = that.getDefaultDefaultPageSize(signature, searchResultsDefaultPageSize, hash);
104
105                    //in case of facet that filters items by language
106                    //when someone is filtering by certain language, and removes that filter, then without
107                    //this if statement, search results language parameter would not be considered - because l="" from hash object
108                    //will override default language from dataProperties
109                    if (hash.hasOwnProperty('l') && hash.l === '') {
110                        hash.l = searchModel.get('dataProperties').l;
111                    }
112
113                    mergedProps = $.extend({}, searchModel.get('dataProperties'), hash);
114                    mergedProps = $.extend(mergedProps, overrideProps);
115
116                    if (mergedProps.hasOwnProperty('loadMore')) {
117                        searchModel.set('loadMore', true);
118                        delete mergedProps.loadMore;
119
120                        var newOffset = searchModel.get('loadMoreOffset') + mergedProps.p;
121                        searchModel.set('loadMoreOffset', newOffset);
122                        mergedProps[offsetSignature] = newOffset;
123                    }
124                    else if (searchModel.get('loadMoreOffset')) { //if results reload is caused by variant change, loadMoreOffset should be considered in request, so after changing variant, the same number of results will be visible
125                        if (mergedProps.p !== 0) {
126                            mergedProps.p = mergedProps.p * (1 + searchModel.get('loadMoreOffset') / mergedProps.p);
127                            mergedProps[offsetSignature] = 0;
128                            searchModel.set('loadMoreOffset', 0);
129                        }
130                        delete mergedProps.variantChanged;
131                    }
132
133                    mergedProps = that.getSortOrder(signature, mergedProps, defaultSortOrder);
134                    mergedProps = that.setVariant(signature, mergedProps, searchResultsDefaultVariant);
135
136                    url = urlHelperModel.createSearchUrl(mergedProps, signature);
137                    if (!url) {
138                        return;
139                    }
140
141                    if (!searchModel.checkBlockingRequest()) {
142                        searchModel.blockRequests(true);
143                        XA.component.search.vent.trigger('results-loading', searchModel.cid);
144                        apiModel.getData({
145                            callback: function (data) {
146                                data.Signature = data.Signature !== null ? data.Signature : '';
147                                XA.component.search.vent.trigger('results-loaded', {
148                                    dataCount: data.Count,
149                                    data: data.Results,
150                                    pageSize: data.Signature !== '' && mergedProps.hasOwnProperty(data.Signature + '_p') ? mergedProps[data.Signature + '_p'] : mergedProps.p,
151                                    offset: data.Signature !== '' && mergedProps.hasOwnProperty(data.Signature + '_e') ? mergedProps[data.Signature + '_e'] : mergedProps.e,
152                                    searchResultsSignature: data.Signature,
153                                    loadMore: searchModel.get('loadMore')
154                                });
155                            },
156                            url: url
157                        });
158                    }
159                });
160            },
161            /**
162            * Processes search result data. Call for apiModel.getData
163            * @param {Object} overrideProps properties for overriding
164            * @fires XA.component.search.vent#results-loaded
165            * @listens module:XA.component.search.vent~event:orderChanged
166            * @memberof module:SearchServiceModel.SearchServiceModel
167            * @alias module:SearchServiceModel.SearchServiceModel#getSearchData
168            */
169            getSearchData: function (overrideProps) {
170                var hash = queryModel.parseHashParameters(window.location.hash),
171                    mergedProps = $.extend({}, hash, mergedProps, overrideProps),
172                    signatures = [],
173                    firstSortingOption,
174                    url,
175                    i;
176
177
178                mergedProps = this.getDefaultDefaultPageSize("", 0, mergedProps);
179
180
181                //if there is no sort param in the query, but we have sort results component on the page, then take first sorting option
182                if (!mergedProps.hasOwnProperty('o') && typeof XA.component.search.sort !== 'undefined') {
183                    firstSortingOption = XA.component.search.sort.getFirstSortingOption();
184                    if (firstSortingOption !== -1) {
185                        mergedProps.o = firstSortingOption;
186                    }
187                }
188
189                //currently we are taking endpoint from Map component (atm it's only which can handle showing of search results)
190                mergedProps.endpoint = XA.component.map.getSearchEndpoint();
191                //the same with signature
192                signatures = XA.component.map.getSignatures();
193
194                for (i = 0; i < signatures.length; i++) {
195                    mergedProps.sig = signatures[i];
196                    url = urlHelperModel.createSearchUrl(mergedProps, signatures[i]);
197
198                    if (!url) {
199                        return;
200                    }
201
202                    apiModel.getData({
203                        callback: function (data) {
204                            data.Signature = data.Signature !== null ? data.Signature : '';
205                            XA.component.search.vent.trigger('results-loaded', {
206                                dataCount: data.Count,
207                                data: data.Results,
208                                pageSize: mergedProps.p,
209                                offset: 0,
210                                searchResultsSignature: data.Signature
211                            });
212                        },
213                        url: url
214                    });
215                }
216            },
217            /**
218           * Checks if map component exists and getSearchEndpoint returns not undefined value. If yes
219           * call ["getSearchData"]{@link module:SearchServiceModel.SearchServiceModel#getSearchData}
220           * @memberof module:SearchServiceModel.SearchServiceModel
221           * @alias module:SearchServiceModel.SearchServiceModel#getEndpointAndSearch
222           */
223            getEndpointAndSearch: function () {
224                if (XA.component.map && typeof (XA.component.map.getSearchEndpoint()) !== 'undefined') {
225                    this.getSearchData();
226                } else {
227                    setTimeout(this.getEndpointAndSearch.bind(this), 100);
228                }
229            },
230            /**
231            * Sorts search result due to selected properties
232            * @param {String} signature component signature
233            * @param {Object} mergedProps 
234            * @param {String} searchResultsDefaultSortOrder default sorting order
235            * @memberof module:SearchServiceModel.SearchServiceModel
236            * @alias module:SearchServiceModel.SearchServiceModel#getSortOrder
237            * @returns {Object} merged properties
238            */
239            getSortOrder: function (signature, mergedProps, searchResultsDefaultSortOrder) {
240                var firstSortingOption = XA.component.search.sort.getFirstSortingOption(signature),
241                    paramName = signature !== '' ? signature + '_o' : 'o',
242                    obj = {},
243                    defaultSortOrder = "",
244                    defaultSigned = {};
245
246
247                if (firstSortingOption !== -1) {
248                    defaultSortOrder = firstSortingOption;
249                } else if (searchResultsDefaultSortOrder !== "") {
250                    defaultSortOrder = searchResultsDefaultSortOrder;
251                }
252
253                if (!mergedProps.hasOwnProperty(paramName) && defaultSortOrder !== "") {
254                    delete mergedProps.defaultSortOrder;
255                    delete mergedProps.o;
256
257                    mergedProps[paramName] = defaultSortOrder;
258                    obj[paramName] = defaultSortOrder;
259                }
260                defaultSigned[paramName] = defaultSortOrder;
261                queryParameters.registerDefault(defaultSigned);
262
263                return mergedProps;
264            },
265
266            /**
267            * Sets default page size into hash
268            * @param {String} signature component signature
269            * @param {Number} searchResultsDefaultPageSize  default page size
270            * @param {Object} hash hash represented as an object
271            * @memberof module:SearchServiceModel.SearchServiceModel
272            * @alias module:SearchServiceModel.SearchServiceModel#getDefaultDefaultPageSize
273            * @returns {Object} hash object
274            */
275            getDefaultDefaultPageSize: function (signature, searchResultsDefaultPageSize, hash) {
276                var defaultPageSizes = XA.component.search.pageSize.getDefaultPageSizes(),
277                    paramName = signature !== "" ? signature + "_p" : "p",
278                    pageSizes;
279
280                if (!hash.hasOwnProperty(paramName) && typeof XA.component.search.pageSize !== 'undefined') {
281                    if (defaultPageSizes !== -1) {
282                        pageSizes = defaultPageSizes.filter(function (x) {
283                            return x.signatures.indexOf(signature) !== -1;
284                        });
285                        if (pageSizes.length > 0) {
286                            hash[paramName] = pageSizes[0].defaultPageSize;
287                        }
288                    }
289                }
290
291                if (!hash.hasOwnProperty(paramName) && searchResultsDefaultPageSize != 0) {
292                    hash[paramName] = searchResultsDefaultPageSize;
293                }
294
295                var defaultParam = {};
296                defaultParam[paramName] = searchResultsDefaultPageSize;
297                queryParameters.registerDefault(defaultParam);
298                return hash;
299            },
300            /**
301            * Sets variant of view search result based on variant selector component
302            * @param {String} signature component signature
303            * @param {Number} searchResultsDefaultPageSize  default page size
304            * @param {Object} hash hash represented as an object
305            * @memberof module:SearchServiceModel.SearchServiceModel
306            * @alias module:SearchServiceModel.SearchServiceModel#setVariant
307            * @returns {Object} hash object
308            */
309            setVariant: function (signature, mergedProps, searchResultsDefaultVariant) {
310                var variantMappings = XA.component.search.variantFilter.getVariantMappings(signature),
311                    paramName = signature !== "" ? signature + "_v" : "v",
312                    variantIndex;
313
314                if (signature === "" && $.isEmptyObject(variantMappings)
314) {
315                    //there is no signature, and no variant selector on the page, therefore, do nothing - mergedPropes should have v param
316                } else if (signature === "" && mergedProps.hasOwnProperty(paramName) && variantMappings.hasOwnProperty(mergedProps[paramName])) {
317                    //there is no signature, but there is variant selector on the page, and it was clicked
318                    mergedProps[paramName] = variantMappings[mergedProps[paramName]].id;
319                } else if (signature === "" && variantMappings.hasOwnProperty(0)) {
320                    //there is no signature, but there is variant selector on the page, therefore take its first variant
321                    mergedProps[paramName] = variantMappings[0].id;
322                } else {
323                    delete mergedProps.v;
324                    if (mergedProps.hasOwnProperty(paramName)) {
325                        //variant switcher was clicked
326                        mergedProps[paramName] = variantMappings[mergedProps[paramName]].id;
327                    } else {
328                        //if there is variant selector on the page, take first variant form the component, otherwise use search results default variant
329                        if (variantMappings.hasOwnProperty(0)) {
330                            mergedProps[paramName] = variantMappings[0].id;
331                        } else {
332                            mergedProps[paramName] = searchResultsDefaultVariant;
333                        }
334                    }
335                }
336
337                var defaultVariant = {};
338                defaultVariant[paramName] = 0;
339                queryParameters.registerDefault(defaultVariant);
340
341                return mergedProps;
342            }
343        });
344
345    return new SearchServiceModel();
346
347}(jQuery, document));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.