PageSourceSearch

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

js stlouisfed.org collected 2026-10-01 07:00:26 UTC 13,215 bytes, 294 lines download raw bytes

1/**
2 * Facet dropdown component functionality
3 * @module dropdown
4 * @param  {jQuery} $ Instance of jQuery
5 * @param  {Document} document dom document object
6 * @return {Object} list of methods for working with component dropdown
7*/
8XA.component.search.facet.dropdown = (function ($, document) {
9
10    "use strict";
11    /**
12    * This object stores all public api methods
13    * @type {Object.<Methods>}
14    * @memberOf module:dropdown
15    */
16    var api = {},
17        urlHelperModel,
18        queryModel,
19        initialized = false;
20    /**
21    * @name module:dropdown.FacetDropdownModel
22    * @constructor
23    * @augments Backbone.Model
24    */
25    var FacetDropdownModel = XA.component.search.baseModel.extend(
26        /** @lends module:dropdown.FacetDropdownModel.prototype **/
27        {
28            /**
29            * Default model options
30            * @default
31            */
32            defaults: {
33                template: "<% _.forEach(results, function(result){" +
34                    "%><option data-facetName=\"<%= result.Name !== '' ? encodeURIComponent(result.Name) : '_empty_' %>\" <%= result.Selected !== undefined ? 'selected' : '' %> ><%= result.Name !== '' ? result.Name.replaceAll('zPast-Participant', 'Past-Participant').replaceAll('--', '(HYPHEN)').replaceAll('-', ' ').replaceAll('_','/').replaceAll('~','&').replaceAll('(HYPHEN)','-') : emptyText %> (<%= result.Count %>)</option><%" +
35                    "}); %>",
36                dataProperties: {},
37                blockNextRequest: false,
38                resultData: {},
39                optionSelected: false,
40                sig: []
41            },
42            /**
43             * Listens to changes on facets and hash
44            * @listens module:XA.component.search.vent~event:facet-data-loaded
45            * @listens module:XA.component.search.vent~event:facet-data-filtered
46            * @listens module:XA.component.search.vent~event:facet-data-partial-filtered
47            * @listens module:XA.component.search.vent~event:hashChanged
48            */
49            initialize: function () {
50                //Event to get data at the begining or when there are no hash parameters in the url - one request for all controls
51                XA.component.search.vent.on("facet-data-loaded", this.processData.bind(this));
52
53                //Event to get filtered data
54                XA.component.search.vent.on("facet-data-filtered", this.processData.bind(this));
55
56                //If the url contains a hash, and facet name control is clicked, then we have to listen for partial filtering
57                XA.component.search.vent.on("facet-data-partial-filtered", this.processData.bind(this));
58
59                //Event after change of hash
60                XA.component.search.vent.on("hashChanged", this.updateComponent.bind(this));
61            },
62            /**
63             * Toggle value of blockNextRequest variable
64             * @memberof module:dropdown.FacetDropdownModel
65             * @alias module:dropdown.FacetDropdownModel#toggleBlockRequests
66             */
67            toggleBlockRequests: function () {
68                var state = this.get("blockNextRequest");
69                this.set(this.get("blockNextRequest"), !state);
70            },
71            /**
72             * Processes data that comes as parameter update
73             * model and sorts facets
74             * @param {Object} data Data from server with facet values
75             * @memberof module:dropdown.FacetDropdownModel
76             * @alias module:dropdown.FacetDropdownModel#processData
77             */
78            processData: function (data) {
79                var inst = this,
80                    hashObj = queryModel.parseHashParameters(window.location.hash),
81                    sig = inst.get("sig"),
82                    dataProperties = this.get("dataProperties"),
83                    searchResultsSignature = dataProperties.searchResultsSignature.split(','),
84                    sortOrder = dataProperties.sortOrder,
85                    facet = dataProperties.f,
86                    facetItem,
87                    facedData,
88                    i, j;
89
90                for (j = 0; j < searchResultsSignature.length; j++) {
91                    if (data.Facets.length > 0 && (data.Signature === searchResultsSignature[j]) || data.Signature === "" || data.Signature === null) {
92                        facedData = _.find(data.Facets, function (f) {
93                            return f.Key.toLowerCase() === facet.toLowerCase();
94                        });
95
96                        if (facedData === undefined) {
97                            return;
98                        }
99
100                        for (i = 0; i < sig.length; i++) {
101                            if (!jQuery.isEmptyObject(_.pick(hashObj, sig[i]))) {
102                                if (hashObj[sig[i]] !== "") {
103                                    facetItem = _.where(facedData.Values, { Name: hashObj[sig[i]] });
104                                    if (facetItem.length === 0) {
105                                        facetItem = _.where(facedData.Values, { Name: "" });
106                                    }
107                                    if (facetItem.length > 0) {
108                                        facetItem[0].Selected = true;
109                                        inst.optionSelected = true;
110                                    }
111                                }
112                            }
113                        }
114
115                        this.sortFacetArray(sortOrder, facedData.Values);
116                        inst.set({ resultData: facedData.Values });
117                    }
118                }
119            },
120            /**
121             * Sets option selected value to model based on hash
122             * @param {Object} hash Hash stored as an object
123             * @memberof module:dropdown.FacetDropdownModel
124             * @alias module:dropdown.FacetDropdownModel#updateComponent
125             */
126            updateComponent: function (hash) {
127                var sig = this.get("sig"), i, facetPart;
128
129                for (i = 0; i < sig.length; i++) {
130                    facetPart = sig[i].toLowerCase();
131                    if (hash.hasOwnProperty(facetPart) && hash[facetPart] !== "") {
132                        this.set({ optionSelected: true });
133                    } else {
134                        this.set({ optionSelected: false });
135                    }
136                }
137            }
138        });
139    /**
140    * @name module:dropdown.FacetDropdownView
141    * @constructor
142    * @augments Backbone.View
143    */
144    var FacetDropdownView = XA.component.search.baseView.extend(
145        /** @lends module:dropdown.FacetDropdownView.prototype **/
146
147        {
148            /**
149            * Initially sets data to model and watches events on which
150            * view should be updated
151            * @listens module:dropdown.FacetDropdownModel~event:change
152            * @memberof module:dropdown.FacetDropdownView
153            * @alias module:dropdown.FacetDropdownView#initialize
154            */
155            initialize: function () {
156                var dataProperties = this.$el.data();
157                this.properties = dataProperties.properties;
158
159                if (this.model) {
160                    this.model.set({ dataProperties: this.properties });
161                    this.model.set("sig", this.translateSignatures(this.properties.searchResultsSignature, this.properties.f));
162                }
163
164                this.model.on("change", this.render, this);
165            },
166            /**
167             * list of events for Backbone View
168            * @memberof module:dropdown.FacetDropdownView
169            * @alias module:dropdown.FacetDropdownView#events
170             */
171            events: {
172                "change .facet-dropdown-select": "updateFacet",
173                "click .bottom-remove-filter, .clear-filter": "clearFilter"
174            },
175            /**
176             * Calculates value of optionSelected value in model and calls
177             * ["updateSignaturesHash"]{@link module dropdown.FacetDropdownView#updateSignaturesHash}
178             * inside of ["updateHash"]{@link module:searchQuery.updateHash}
179            * @memberof module:dropdown.FacetDropdownView
180            * @alias module:dropdown.FacetDropdownView#updateFacet
181             */
182            updateFacet: function (param) {
183                var $selectedOption = this.$el.find(".facet-dropdown-select").find("option:selected"),
184                    facetName = decodeURIComponent($selectedOption.data("facetname")),
185                    sig = this.model.get("sig");
186
187                if (facetName === "") {
188                    this.model.set({ optionSelected: false });
189                } else {
190                    this.model.set({ optionSelected: true });
191                }
192                queryModel.updateHash(this.updateSignaturesHash(sig, facetName, {}));
193            },
194            /**
195            * Renders view
196            * @memberof module:dropdown.FacetDropdownView
197            * @alias module:dropdown.FacetDropdownView#render
198            */
199            render: function () {
200                var inst = this,
201                    resultData = inst.model.get("resultData"),
202                    dropdown = this.$el.find(".facet-dropdown-select"),
203                    emptyValueText = inst.model.get('dataProperties').emptyValueText,
204                    facetClose = this.$el.find(".facet-heading > span"),
205                    notSelectedOption = dropdown.find("option:first"),
206                    notSelectedOptionEntry = $("<option />"),
207                    template = _.template(inst.model.get("template")),
208                    templateResult = template({ results: resultData, emptyText: emptyValueText });
209
210                this.manageVisibilityByData(this.$el, resultData)
211                notSelectedOptionEntry.text(notSelectedOption.text());
212                notSelectedOptionEntry.data("facetname", "");
213
214                if (this.model.get("optionSelected")) {
215                    facetClose.addClass("has-active-facet");
216                } else if (notSelectedOption.data("facetname") === "") {
217                    facetClose.removeClass("has-active-facet");
218                }
219
220                dropdown.empty().append(notSelectedOptionEntry).append(templateResult);
221            },
222            /**
223            * Clears selected filters and updates hash by calling
224            * ["updateHash"]{@link module:searchQuery.updateHash}
225            * @memberof module:dropdown.FacetDropdownView
226            * @alias module:dropdown.FacetDropdownView#clearFilter
227             */
228            clearFilter: function () {
229                var dropdown = this.$el.find(".facet-dropdown-select"),
230                    facetClose = this.$el.find(".facet-heading > span"),
231                    sig = this.model.get("sig");
232
233                queryModel.updateHash(this.updateSignaturesHash(sig, "", {}));
234                this.model.set({ optionSelected: false });
235                facetClose.removeClass("has-active-facet");
236                dropdown.val(dropdown.find("option:first").val());
237            }
238        });
239    /**
240    * For each search dropdown component on a page creates instance of
241    * ["FacetDropdownModel"]{@link module:dropdown.FacetDropdownModel} and
242    * ["FacetDropdownView"]{@link module:dropdown.FacetDropdownView}
243    * @memberOf module:dropdown
244    * @alias module:dropdown.init
245    */
246
247    api.init = function () {
248        if ($("body").hasClass("on-page-editor") || initialized) {
249            return;
250        }
251
252        queryModel = XA.component.search.query;
253        urlHelperModel = XA.component.search.url;
254
255        var facetDropdownList = $(".facet-dropdown");
256        _.each(facetDropdownList, function (elem) {
257            var view = new FacetDropdownView({ el: $(elem), model: new FacetDropdownModel() });
258        });
259
260        initialized = true;
261    };
262    /**
263    *
264    * @memberOf module:dropdown
265    * @alias module:dropdown.getFacetDataRequestInfo
266    * @returns {Array<FacetDataRequestInfo>} facet data needed for request
267    */
268    api.getFacetDataRequestInfo = function () {
269        var facetDropdownList = $(".facet-dropdown"),
270            result = [];
271
272        _.each(facetDropdownList, function (elem) {
273            var properties = $(elem).data().properties,
274                signatures = properties.searchResultsSignature.split(','),
275                i;
276
277            for (i = 0; i < signatures.length; i++) {
278                result.push({
279                    signature: signatures[i] === null ? "" : signatures[i],
280                    facetName: properties.f,
281                    endpoint: properties.endpoint,
282                    filterWithoutMe: true
283                });
284            }
285        });
286
287        return result;
288    };
289
290    return api;
291
292}(jQuery, document));
293
294XA.register("facetDropdown", XA.component.search.facet.dropdown);

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.