PageSourceSearch

https://www.trieagleenergy.com/-/media/Base-Themes/SearchTheme/Scripts/component-search-results-filter.js

js trieagleenergy.com collected 2026-10-07 16:14:43 UTC 25,344 bytes, 530 lines download raw bytes

1/**
2 * Facet facet result filter component functionality
3 * @module facetResultsFilter
4 * @param  {jQuery} $ Instance of jQuery
5 * @param  {Document} document dom document object
6 * @return {Object} list of methods for working with component facet result filter
7*/
8XA.component.search.facet.resultsfilter = (function ($, document) {
9    /**
10    * This object stores all public api methods
11    * @type {Object.<Methods>}
12    * @memberOf module:facetResultsFilter
13    */
14    var api = {},
15        urlHelperModel,
16        queryModel,
17        apiModel,
18        initialized = false;
19    /**
20    * @name module:facetResultsFilter.FacetResultsFilterModel
21    * @constructor
22    * @augments Backbone.Model
23    */
24    var FacetResultsFilterModel = XA.component.search.baseModel.extend(
25        /** @lends module:facetResultsFilter.FacetResultsFilterModel.prototype **/
26        {
27            /**
28            * Default model options
29            * @default
30            */
31            defaults: {
32                template: "<div class='facet-search-filter <% if(!showAllFacets){%>facet-hided<%}%>'><% " +
33                    "_.forEach(facet.Values, function(value,key){" +
34                    "%><p class='facet-value <% if(highlightBehaviour<=key){ %> hide-facet-value <% } %>' data-facetValue='<%= value.Name !== '' ? encodeURI(value.Name) : '_empty_' %>'>" +
35                    "<span><%= value.Name !== '' ? value.Name : emptyText %> " +
36                    "<span class='facet-count'>(<%= value.Count %>)</span>" +
37                    "</span>" +
38                    "</p><%" +
39                    " }); %>" +
40                    "<% if(highlightBehaviour>=1){ %>" +
41                    "<div class='toogle-facet-visibility'><% if(showAllFacets){ %><%=showLessText%><%}else{%><%=showMoreText%><%} %></div>" +
42                    "<%}%>" +
43                    "</div>",
44
45                templateMulti: "<div class='facet-search-filter <% if(!showAllFacets){%>facet-hided<%}%>'><% " +
46                    "_.forEach(facet.Values, function(value,key){" +
47                    "%><p class='facet-value <% if(highlightBehaviour<=key){ %> hide-facet-value <% } %>' data-facetValue='<%= value.Name !== '' ? encodeURI(value.Name) : '_empty_' %>'>" +
48                    "<input type='checkbox' name='facetValue' />" +
49                    "<label for='facetName'><%= value.Name !== '' ? value.Name : emptyText %> " +
50                    "<span class='facet-count' data-facetCount='<%= value.Count %>'>(<%= value.Count %>)</span>" +
51                    "</label>" +
52                    "</p><%" +
53                    " }); %>" +
54                    "<% if(highlightBehaviour>=1){ %>" +
55                    "<div class='toogle-facet-visibility'><% if(showAllFacets){ %><%=showLessText%><%}else{%><%=showMoreText%><%} %></div>" +
56                    "<%}%>" +
57                    "</div>",
58                dataProperties: {},
59                blockNextRequest: false,
60                resultData: {},
61                timeStamp: '',
62                showAllFacets: false,
63                sig: []
64            },
65            /**
66            * Listens to changes on facets and hash
67           * @listens module:XA.component.search.vent~event:facet-data-loaded
68           * @listens module:XA.component.search.vent~event:facet-data-filtered
69           * @listens module:XA.component.search.vent~event:facet-data-partial-filtered
70           * @listens module:XA.component.search.vent~event:hashChanged
71           */
72            initialize: function () {
73                //event to get data at the begining or in case that there are no hash parameters in the url - one request for all controls
74                XA.component.search.vent.on("facet-data-loaded", this.processData.bind(this));
75                //if in the url hash we have this control facet name (someone clicked this control) then we have to listen for partial filtering
76                XA.component.search.vent.on("facet-data-partial-filtered", this.processData.bind(this));
77                //in case that we are not filtering by this control (not clicked)
78                XA.component.search.vent.on("facet-data-filtered", this.processData.bind(this));
79                //event after change of hash
80                XA.component.search.vent.on("hashChanged", this.updateComponent.bind(this));
81
82                this.set({ facetArray: [] });
83            },
84            /**
85             * Toggles value of blockNextRequest variable
86             * @memberof module:facetResultsFilter.FacetResultsFilterModel
87             * @alias module:facetResultsFilter.FacetResultsFilterModel#toggleBlockRequests
88             */
89            toggleBlockRequests: function () {
90                var state = this.get("blockNextRequest");
91                this.set(this.get("blockNextRequest"), !state);
92            },
93            /**
94            * Processes data that comes as parameter update
95            * model and sort facets
96            * @param {Object} data Data from server with facet values
97            * @memberof module:facetResultsFilter.FacetResultsFilterModel
98            * @alias module:facetResultsFilter.FacetResultsFilterModel#processData
99            */
100            processData: function (data) {
101                var inst = this,
102                    dataProperties = this.get('dataProperties'),
103                    sig = dataProperties.searchResultsSignature.split(','),
104                    sortOrder = dataProperties.sortOrder,
105                    i;
106
107                if (data.Signature === null) {
108                    data.Signature = "";
109                }
110
111
112                for (i = 0; i < sig.length; i++) {
113                    if (data.Facets.length > 0 && (data.Signature === sig[i])) {
114                        var facedData = _.find(data.Facets, function (f) {
115                            return f.Key.toLowerCase() === inst.get('dataProperties').f.toLowerCase();
116                        });
117                        if (facedData !== undefined) {
118                            this.sortFacetArray(sortOrder, facedData.Values);
119                            inst.set({ resultData: facedData });
120                        }
121                    }
122                }
123            },
124            /**
125             * Updates model value 'facetArray' with values from valuesString parameter
126             * @param {String} valuesString facet values separated by coma
127             * @memberof module:facetResultsFilter.FacetResultsFilterModel
128             * @alias module:facetResultsFilter.FacetResultsFilterModel#updateFacetArray
129             */
130            updateFacetArray: function (valuesString) {
131                if (valuesString) {
132                    var values = valuesString.split(','),
133                        array = this.get('facetArray');
134                    for (var i = 0; i < values.length; i++) {
135                        array.push(values[i]);
136                    }
137                    this.set({ facetArray: _.unique(array) });
138                }
139            },
140            /**
141             * Sets option selected value to model based on hash
142             * @param {Object} hash Hash stored as an object
143             * @memberof module:facetResultsFilter.FacetResultsFilterModel
144             * @alias module:facetResultsFilter.FacetResultsFilterModel#updateComponent
145             */
146            updateComponent: function (hash) {
147                var sig = this.get("sig");
148                for (i = 0; i < sig.length; i++) {
149                    if (!hash.hasOwnProperty(sig[i])) {
150                        this.set({ facetArray: [] });
151                    } else {
152                        this.updateFacetArray(hash[sig[i]]);
153                    }
154                    //in some cases change of facetArray doesn't trigger model change event (why?) and view isn't updates
155                    //and because of that timeStamp is updated which properly triggers model change event
156                    this.set("timeStamp", (new Date()).getTime());
157                }
158            }
159        });
160    /**
161    * @name module:facetResultsFilter.FacetResultsFilterView
162    * @constructor
163    * @augments Backbone.View
164    */
165    var FacetResultsFilterView = XA.component.search.baseView.extend(
166        /** @lends module:facetResultsFilter.FacetResultsFilterView.prototype **/
167        {
168            /**
169            * Initially sets data to model and watches events on which
170            * view should be updated
171            * @listens module:facetResultsFilter.FacetResultsFilterModel~event:change
172            * @memberof module:facetResultsFilter.FacetResultsFilterView
173            * @alias module:facetResultsFilter.FacetResultsFilterView#initialize
174            */
175            initialize: function () {
176                var dataProperties = this.$el.data(),
177                    hash = queryModel.parseHashParameters(window.location.hash),
178                    properties = dataProperties.properties,
179                    signatures,
180                    i;
181
182
183                if (dataProperties.properties.searchResultsSignature === null) {
184                    dataProperties.properties.searchResultsSignature = "";
185                }
186
187                signatures = this.translateSignatures(properties.searchResultsSignature, properties.f);
188
189                this.model.set({ dataProperties: properties });
190                this.model.set("sig", signatures);
191
192                for (i = 0; i < signatures.length; i++) {
193                    if (!jQuery.isEmptyObject(_.pick(hash, signatures[i]))) {
194                        var values = _.values(_.pick(hash, signatures[i]))[0];
195                        this.model.updateFacetArray(values)
196                    }
197                }
198
199                this.model.on("change", this.render, this);
200            },
201            /**
202             * list of events for Backbone View
203            * @memberof module:facetResultsFilter.FacetResultsFilterView
204            * @alias module:facetResultsFilter.FacetResultsFilterView#events
205             */
206            events: {
207                'click .facet-value': 'updateFacet',
208                'click .filterButton': 'updateFacet',
209                'click .clear-filter': 'removeFacet',
210                'click .bottom-remove-filter > button': 'removeFacet',
211                'click .toogle-facet-visibility': 'toogleFacetVisibility'
212            },
213
214            toogleFacetVisibility: function () {
215                var showFacets = this.model.get('showAllFacets');
216                this.model.set('showAllFacets', !showFacets);
217
218
219            },
220            /**
221            * Updates model 'facetArray' based on params
222            * @param {Event}  param Event object with current target
223            * @memberof module:facetResultsFilter.FacetResultsFilterView
224            * @alias module:facetResultsFilter.FacetResultsFilterView#updateFacet
225            */
226            updateFacet: function (param) {
227                var currentFacet = $(param.currentTarget),
228                    facetArray = this.model.get('facetArray'),
229                    properties = this.model.get('dataProperties'),
230                    facetClose = this.$el.find('.facet-heading > span'),
231                    facetGroup = currentFacet.parents('.component-content').find('.facet-search-filter'),
232                    facetName = properties.f.toLowerCase(),
233                    facetDataValue = currentFacet.data('facetvalue'),
234                    facetValue = typeof facetDataValue !== "undefined" ? decodeURIComponent(facetDataValue) : facetDataValue,
235                    sig = this.model.get('sig'),
236                    index,
237                    hash = {},
238                    i;
239
240                if (properties.multi) {
241                    if (facetValue) {
242                        if (currentFacet.is(':not(.active-facet)')) {
243                            this.setActiveFacet(facetName, facetValue);
244                            facetArray.push(facetValue);
245                        } else {
246                            currentFacet.removeClass('active-facet');
247
248                            currentFacet.find('[type=checkbox]').prop('checked', false);
249                            currentFacet.find('[type=checkbox] + label:after').css({ 'background': '#fff' });
250
251                            index = facetArray.indexOf(facetValue);
252                            if (index > -1) {
253                                facetArray.splice(index, 1);
254                            }
255
256                            if (facetArray.length == 0) {
257                                facetClose.removeClass('has-active-facet');
258                            }
259                        }
260                        this.model.set({ facetArray: facetArray });
261                    }
262
263                    //is there any better way to check what action start method?
264                    if (currentFacet[0].type == "button") {
265                        for (i = 0; i < sig.length; i++) {
266                            hash[sig[i]] = _.uniq(facetArray, function (item) {
267                                return JSON.stringify(item);
268                            }).toString();
269                        }
270                        queryModel.updateHash(hash);
271                    }
272                } else {
273                    if (facetValue) {
274                        for (i = 0; i < sig.length; i++) {
275                            hash[sig[i]] = facetValue;
276                        }
277                        facetGroup.data('active-facet', hash);
278                        this.setActiveFacet(facetName, facetValue);
279                        queryModel.updateHash(hash);
280                    }
281                }
282
283            },
284            /**
285            * Sets default values for Search Result Filter and updates hash accordingly
286            * @param {Event} evt Event object
287            * @memberof module:facetResultsFilter.FacetResultsFilterView
288            * @alias module:facetResultsFilter.FacetResultsFilterView#removeFacet
289            */
290            removeFacet: function (evt) {
291                evt.preventDefault();
292
293                var facets = this.$el,
294                    facetClose = facets.find('.facet-heading > span'),
295                    facetValues = facets.find('.facet-value'),
296                    sig = this.model.get('sig');
297
298                queryModel.updateHash(this.updateSignaturesHash(sig, "", {}));
299
300                facetClose.removeClass('has-active-facet');
301
302                _.each(facetValues, function (single) {
303                    var $single = $(single);
304                    if ($single.hasClass('active-facet')) {
305                        $single.removeClass('active-facet');
306                        $single.find('[type=checkbox]').prop('checked', false);
307                        $single.find('[type=checkbox] + label:after').css({ 'background': '#fff' });
308                    }
309                });
310
311                this.model.set({ facetArray: [] });
312            },
313            /**
314            * Renders view
315            * @memberof module:facetResultsFilter.FacetResultsFilterView
316            * @alias module:facetResultsFilter.FacetResultsFilterView#render
317            */
318            render: function () {
319                var inst = this,
320                    resultData = this.model.get("resultData"),
321                    facetClose = this.$el.find('.facet-heading > span'),
322                    facetNames = this.model.get('dataProperties').f.split('|'),
323                    emptyValueText = this.model.get('dataProperties').emptyValueText,
324                    highlightThreshold = this.model.get('dataProperties').highlightThreshold,
325                    showLessText = this.model.get('dataProperties').showLessText,
326                    showMoreText = this.model.get('dataProperties').showMoreText,
327                    highlightBehaviour = parseInt(this.model.get('dataProperties').highlightBehaviour),
328                    showAllFacets = this.model.get('showAllFacets'),
329                    hash = queryModel.parseHashParameters(window.location.hash),
330                    sig = this.model.get('sig'),
331                    template, facetName, templateResult;
332
333                //checks if page is opened from disc - if yes then we are in Creative Exchange mode
334                if (window.location.href.startsWith("file://")) {
335                    return;
336                }
337                this.manageVisibilityByData(this.$el, resultData)
338                if (resultData !== undefined) {
339                    if (inst.model.get('dataProperties').multi === true) {
340                        template = _.template(inst.model.get("templateMulti"));
341                    } else {
342                        template = _.template(inst.model.get("template"));
343                    }
344                    templateResult = template({
345                        facet: resultData, emptyText: emptyValueText, showLessText: showLessText,
346                        showMoreText: showMoreText, highlightBehaviour: highlightBehaviour, showAllFacets: showAllFacets
347                    });
348                }
349
350                inst.$el.find(".contentContainer").html(templateResult);
351
352                //checks url hash for facets and runs setActiveFacet method for each facet filter
353                _.each(facetNames, function (val) {
354                    facetName = val.toLowerCase();
355                    for (var i = 0; i < sig.length; i++) {
356                        if (!jQuery.isEmptyObject(_.pick(hash, sig))) {
357                            var values = _.values(_.pick(hash, sig))[0];
358                            if (values) {
359                                inst.setActiveFacet(facetName, values);
360
361                                //If this rendering is supporting multiple signatures, we will mark active facet once.
362                                return;
363                            }
364                        }
365                    }
366                });
367
368                //highlights facets count greater than chosen threshold
369                if (highlightThreshold) {
370                    this.handleThreshold(highlightThreshold);
371                }
372
373                //if no facet is selected, remove previously highlighted cross icon (while back button)
374                if (this.model.get("facetArray").length === 0) {
375                    facetClose.removeClass('has-active-facet');
376                } else {
377                    facetClose.addClass('has-active-facet');
378                }
379            },
380            /**
381            * Manages search result filter active state
382            * @param {String} facetGroupName facet name
383            * @param {String} facetValueName facet value
384            * @memberof module:facetResultsFilter.FacetResultsFilterView
385            * @alias module:facetResultsFilter.FacetResultsFilterView#setActiveFacet
386            */
387            setActiveFacet: function (facetGroupName, facetValueName) {
388                var properties = this.model.get('dataProperties'),
389                    facetChildren = this.$el.find('p[data-facetvalue]'),
390                    facetClose = this.$el.find('.facet-heading > span'),
391                    inst = this,
392                    facetValue,
393                    values;
394
395                facetValueName = facetValueName.toString().toLowerCase();
396                facetValue = this.$el.find("[data-facetvalue]").filter(function () {
397                    return decodeURIComponent($(this).attr("data-facetvalue").toLowerCase()) === facetValueName;
398                });
399
400
401                if (typeof (facetValueName) !== "undefined" && facetValueName !== null) {
402                    values = facetValueName.split(',');
403                } else {
404                    return;
405                }
406
407                if (values.length > 1) {
408                    properties.multi = true;
409                }
410
411                if (properties.multi) {
412                    //multi selection facet search results
413                    _.each(facetChildren, function (val) {
414
415                        if (values.length > 1) {
416                            for (var i = 0, l = values.length; i < l; i++) {
417                                facetValue = inst.$el.find("[data-facetvalue]").filter(function () {
418                                    return $(this).attr('data-facetvalue').toLowerCase() === values[i];
419                                });
420                                if (val === facetValue[0]) {
421                                    $(val).addClass('active-facet');
422                                    $(val).find('[type=checkbox]').prop('checked', true);
423                                }
424                            }
425                        }
426
427                        if (val === facetValue[0]) {
428                            $(val).addClass('active-facet');
429                            $(val).find('[type=checkbox]').prop('checked', true);
430                        }
431
432
433                    });
434                } else {
435                    //single selection facet search results filter allows only one facet type to be selected
436                    _.each(facetChildren, function (val) {
437                        if (val !== facetValue[0]) {
438                            $(val).removeClass('active-facet');
439                            $(val).find('[type=checkbox]').prop('checked', false);
440                            $(val).find('[type=checkbox] + label:after').css({ 'background': '#fff' });
441                        } else {
442                            $(val).addClass('active-facet');
443                        }
444                    });
445                }
446
447                //adds active class to group close button
448                facetClose.addClass('has-active-facet');
449            },
450            /**
451            * Manages search result filter highlight of threshold
452            * @param {Number} highlightThreshold value of threshold highlight
453            * @memberof module:facetResultsFilter.FacetResultsFilterView
454            * @alias module:facetResultsFilter.FacetResultsFilterView#handleThreshold
455            */
456            handleThreshold: function (highlightThreshold) {
457                var facets = this.$el.find('.facet-search-filter').children('p');
458
459                _.each(facets, function (single) {
460                    var $facet = $(single),
461                        $facetCount = $facet.find('.facet-count'),
462                        facetCount = $facetCount.data('facetcount');
463
464                    if (facetCount > highlightThreshold) {
465                        $facetCount.addClass('highlighted');
466                    }
467                });
468            }
469        });
470    /**
471    * For each search result component on a page creates instance of 
472    * ["FacetResultsFilterModel"]{@link module:facetResultsFilter.FacetResultsFilterModel} and 
473    * ["FacetResultsFilterView"]{@link module:facetResultsFilter.FacetResultsFilterView} 
474    * @memberOf module:facetResultsFilter
475    * @alias module:facetResultsFilter.init
476    */
477    api.init = function () {
478        if ($("body").hasClass("on-page-editor") || initialized) {
479            return;
480        }
481
482        queryModel = XA.component.search.query;
483        apiModel = XA.component.search.ajax;
484        urlHelperModel = XA.component.search.url;
485
486        var facetResultsFilterList = $(".facet-single-selection-list");
487        _.each(facetResultsFilterList, function (elem) {
488            var model = new FacetResultsFilterModel(),
489                view = new FacetResultsFilterView({ el: $(elem), model: model });
490        });
491
492        initialized = true;
493    };
494    /**
495    * Returns information about facet component
496    * @memberOf module:facetResultsFilter
497    * @alias module:facetResultsFilter.getFacetDataRequestInfo
498    * @returns {Array<FacetDataRequestInfo>} facet data needed for request
499    */
500    api.getFacetDataRequestInfo = function () {
501        var facetList = $(".facet-single-selection-list"),
502            result = [];
503
504        _.each(facetList, function (elem) {
505            var properties = $(elem).data().properties,
506                signatures = properties.searchResultsSignature.split(','),
507                i;
508
509            for (i = 0; i < signatures.length; i++) {
510                result.push({
511                    signature: signatures[i] === null ? "" : signatures[i],
512                    facetName: properties.f,
513                    endpoint: properties.endpoint,
514                    showMoreText: properties.showMoreText,
515                    showLessText: properties.showLessText,
516                    highlightBehaviour: properties.highlightBehaviour,
517                    s: properties.s,
518                    filterWithoutMe: !properties.collapseOnSelection
519                });
520            }
521        });
522
523        return result;
524    };
525
526    return api;
527
528}(jQuery, document));
529
530XA.register('facetResultsFilter', XA.component.search.facet.resultsfilter);

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.