PageSourceSearch

https://www.epogen.com/-/media/Base-Themes/SearchTheme/Scripts/component-search-facet-dropdown.js

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