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 !== '' ? 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)); 51 52 //Event to get filtered data 53 XA.component.search.vent.on("facet-data-filtered", this.processData.bind(this)); 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)); 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 (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 facetItem, 86 facedData, 87 i, j; 88 89 for (j = 0; j < searchResultsSignature.length; j++) { 90 if (data.Facets.length > 0 && (data.Signature === searchResultsSignature[j]) || data.Signature === "" || data.Signature === null) { 91 facedData = _.find(data.Facets, function (f) { 92 return f.Key.toLowerCase() === facet.toLowerCase(); 93 }); 94 95 if (facedData === undefined) { 96 return; 97 } 98 99 for (i = 0; i < sig.length; i++) { 100 if (!jQuery.isEmptyObject(_.pick(hashObj, sig[i]))) { 101 if (hashObj[sig[i]] !== "") { 102 facetItem = _.where(facedData.Values, { Name: hashObj[sig[i]] }); 103 if (facetItem.length === 0) { 104 facetItem = _.where(facedData.Values, { Name: "" }); 105 } 106 if (facetItem.length > 0) { 107 facetItem[0].Selected = true; 108 inst.optionSelected = true; 109 } 110 } 111 } 112 } 113 114 this.sortFacetArray(sortOrder, facedData.Values); 115 inst.set({ resultData: facedData.Values }); 116 } 117 } 118 }, 119 /** 120 * Sets option selected value to model based on hash 121 * @param {Object} hash Hash stored as an object 122 * @memberof module:dropdown.FacetDropdownModel 123 * @alias module:dropdown.FacetDropdownModel#updateComponent 124 */
125 updateComponent: function (hash) { 126 var sig = this.get("sig"), i, facetPart; 127 128 for (i = 0; i < sig.length; i++) { 129 facetPart = sig[i].toLowerCase(); 130 if (hash.hasOwnProperty(facetPart) && hash[facetPart] !== "") { 131 this.set({ optionSelected: true }); 132 } else { 133 this.set({ optionSelected: false }); 134 } 135 } 136 } 137 }); 138 /** 139 * @name module:dropdown.FacetDropdownView 140 * @constructor 141 * @augments Backbone.View 142 */ 143 var FacetDropdownView = XA.component.search.baseView.extend( 144 /** @lends module:dropdown.FacetDropdownView.prototype **/ 145 146 { 147 /** 148 * Initially sets data to model and watches events on which 149 * view should be updated 150 * @listens module:dropdown.FacetDropdownModel~event:change 151 * @memberof module:dropdown.FacetDropdownView 152 * @alias module:dropdown.FacetDropdownView#initialize 153 */ 154 initialize: function () { 155 var dataProperties = this.$el.data(); 156 this.properties = dataProperties.properties; 157 158 if (this.model) { 159 this.model.set({ dataProperties: this.properties }); 160 this.model.set("sig", this.translateSignatures(this.properties.searchResultsSignature, this.properties.f)); 161 } 162 163 this.model.on("change", this.render, this); 164 }, 165 /** 166 * list of events for Backbone View 167 * @memberof module:dropdown.FacetDropdownView 168 * @alias module:dropdown.FacetDropdownView#events 169 */ 170 events: { 171 "change .facet-dropdown-select": "updateFacet", 172 "click .bottom-remove-filter, .clear-filter": "clearFilter" 173 }, 174 /** 175 * Calculates value of optionSelected value in model and calls 176 * ["updateSignaturesHash"]{@link module dropdown.FacetDropdownView#updateSignaturesHash} 177 * inside of ["updateHash"]{@link module:searchQuery.updateHash} 178 * @memberof module:dropdown.FacetDropdownView 179 * @alias module:dropdown.FacetDropdownView#updateFacet 180 */ 181 updateFacet: function (param) { 182 var $selectedOption = this.$el.find(".facet-dropdown-select").find("option:selected"), 183 facetName = decodeURIComponent($selectedOption.data("facetname")), 184 sig = this.model.get("sig"); 185 186 if (facetName === "") { 187 this.model.set({ optionSelected: false }); 188 } else { 189 this.model.set({ optionSelected: true }); 190 } 191 queryModel.updateHash(this.updateSignaturesHash(sig, facetName, {})); 192 }, 193 /** 194 * Renders view 195 * @memberof module:dropdown.FacetDropdownView 196 * @alias module:dropdown.FacetDropdownView#render 197 */ 198 render: function () { 199 var inst = this, 200 resultData = inst.model.get("resultData"), 201 dropdown = this.$el.find(".facet-dropdown-select"), 202 emptyValueText = inst.model.get('dataProperties').emptyValueText, 203 facetClose = this.$el.find(".facet-heading > span"), 204 notSelectedOption = dropdown.find("option:first"), 205 notSelectedOptionEntry = $("<option />"), 206 template = _.template(inst.model.get("template")), 207 templateResult = template({ results: resultData, emptyText: emptyValueText }); 208 209 this.manageVisibilityByData(this.$el, resultData) 210 notSelectedOptionEntry.text(notSelectedOption.text()); 211 notSelectedOptionEntry.data("facetname", ""); 212 213 if (this.model.get("optionSelected")) { 214 facetClose.addClass("has-active-facet"); 215 } else if (notSelectedOption.data("facetname") === "") { 216 facetClose.removeClass("has-active-facet"); 217 } 218 219 dropdown.empty().append(notSelectedOptionEntry).append(templateResult); 220 }, 221 /** 222 * Clears selected filters and updates hash by calling 223 * ["updateHash"]{@link module:searchQuery.updateHash} 224 * @memberof module:dropdown.FacetDropdownView 225 * @alias module:dropdown.FacetDropdownView#clearFilter 226 */ 227 clearFilter: function () { 228 var dropdown = this.$el.find(".facet-dropdown-select"), 229 facetClose = this.$el.find(".facet-heading > span"), 230 sig = this.model.get("sig"); 231
232 queryModel.updateHash(this.updateSignaturesHash(sig, "", {})); 233 this.model.set({ optionSelected: false }); 234 facetClose.removeClass("has-active-facet"); 235 dropdown.val(dropdown.find("option:first").val()); 236 } 237 }); 238 /** 239 * For each search dropdown component on a page creates instance of 240 * ["FacetDropdownModel"]{@link module:dropdown.FacetDropdownModel} and 241 * ["FacetDropdownView"]{@link module:dropdown.FacetDropdownView} 242 * @memberOf module:dropdown 243 * @alias module:dropdown.init 244 */ 245 246 api.init = function () { 247 if ($("body").hasClass("on-page-editor")) { 248 return; 249 } 250 251 queryModel = XA.component.search.query; 252 urlHelperModel = XA.component.search.url; 253 254 var facetDropdownList = $(".facet-dropdown:not(.initialized)"); 255 256 _.each(facetDropdownList, function (elem) { 257 var $el = $(elem), 258 view = new FacetDropdownView({ el: $el, model: new FacetDropdownModel() }); 259 260 $el.addClass("initialized"); 261 }); 262 }; 263 /** 264 * 265 * @memberOf module:dropdown 266 * @alias module:dropdown.getFacetDataRequestInfo 267 * @returns {Array<FacetDataRequestInfo>} facet data needed for request 268 */ 269 api.getFacetDataRequestInfo = function () { 270 var facetDropdownList = $(".facet-dropdown"), 271 result = []; 272 273 _.each(facetDropdownList, function (elem) { 274 var properties = $(elem).data().properties, 275 signatures = properties.searchResultsSignature.split(','), 276 i; 277 278 for (i = 0; i < signatures.length; i++) { 279 result.push({ 280 signature: signatures[i] === null ? "" : signatures[i], 281 facetName: properties.f, 282 endpoint: properties.endpoint, 283 filterWithoutMe: true 284 }); 285 } 286 }); 287 288 return result; 289 }; 290 291 return api; 292 293}(jQuery, document)); 294 295XA.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.