1/** 2 * Search result component functionality 3 * @module searchResults 4 * @param {jQuery} $ Instance of jQuery 5 * @param {Document} document dom document object 6 * @return {Object} list of methods for working with component search result 7*/ 8XA.component.search.results = (function ($, document) { 9 10 "use strict"; 11 /** 12 * This object stores all public api methods 13 * @type {Object.<Methods>} 14 * @memberOf module:searchResults 15 */ 16 var api = {}, 17 searchResultViews = [], 18 searchResultModels = [], 19 urlHelperModel, 20 queryModel, 21 apiModel 22 /** 23 * @name module:searchResults.SearchResultModel 24 * @constructor 25 * @augments Backbone.Model 26 */ 27 var SearchResultModel = Backbone.Model.extend( 28 /** @lends module:searchResults.SearchResultModel.prototype **/ 29 { 30 defaults: { 31 template: "<% if(!results.length){ %><div class='no-results'><%= noResultsText %></div> <% }else { %>" + 32 "<ul class='search-result-list'> " + 33 "<% _.forEach(results, function(result){ %>" + 34 "<li " + "<% if(result.Geospatial){%>data-id='<%= result.Id %>' data-longitude='<%= result.Geospatial.Longitude %>' data-latitude='<%= result.Geospatial.Latitude %>'<% } %>" + "><%= result.Html %></li>" + 35 "<% }); %>" + 36 "</ul>" + 37 "<% } %>" + 38 "<div class='search-result-overlay'>", 39 templateItems: "<% _.forEach(results, function(result){ %>" + 40 "<li " + "<% if(result.Geospatial){%>data-id='<%= result.Id %>' data-longitude='<%= result.Geospatial.Longitude %>' data-latitude='<%= result.Geospatial.Latitude %>'<% } %>" + "><%= result.Html %></li>" + 41 "<% }); %>", 42 dataProperties: {}, 43 blockNextRequest: false, 44 noResultsText: "", 45 resultData: {}, 46 loadingInProgress: false, 47 loadingMoreInProgress: false, 48 resultDataMore: {}, 49 loadMoreOffset: 0, 50 loadMore: false 51 }, 52 /** 53 * Listens for changes on data from server 54 * @listens module:XA.component.search.vent~event:facet-data-loaded 55 * @listens module:XA.component.search.vent~event:results-loading 56 */ 57 initialize: function () { 58 var hashObj = queryModel.parseHashParameters(window.location.hash), 59 signature = encodeURIComponent(this.get("dataProperties").sig), 60 offsetKey = "e_" + signature; 61 62 //If there is "e" in hash object, then one of page selectors on the page is global (not assigned to any of the 63 //search results - in such case it will paginate all search results without signature 64 if (hashObj.hasOwnProperty("e") && signature === '') { 65 this.set("loadMoreOffset", parseInt(hashObj.e)); 66 } 67 68 //checks if there is page selector assigned to this specific search results 69 if (hashObj.hasOwnProperty(offsetKey)) { 70 this.set("loadMoreOffset", parseInt(hashObj[offsetKey])); 71 } 72 73 XA.component.search.vent.on('new-search', this.resetModel.bind(this)); 74 XA.component.search.vent.on("results-loaded", this.resultsLoaded.bind(this)); 75 XA.component.search.vent.on('results-loading', this.resultsLoading.bind(this)); 76 }, 77 /** 78 * Sets value of blockNextRequest variable 79 * @param {String} value new value of blockNextRequest variable 80 * @memberof module:searchResults.SearchResultModel 81 * @alias module:searchResults.SearchResultModel#blockRequests 82 */ 83 blockRequests: function (value) { 84 this.set("blockNextRequest", value); 85 }, 86 /** 87 * Returns value of blockNextRequest variable 88 * @memberof module:searchResults.SearchResultModel 89 * @alias module:searchResults.SearchResultModel#checkBlockingRequest 90 * @returns {String} value of blockNextRequest variable 91 */ 92 checkBlockingRequest: function () { 93 return this.get("blockNextRequest"); 94 }, 95 /** 96 * Returns value of component offset from hash parameters 97 * @memberof module:searchResults.SearchResultModel 98 * @alias module:searchResults.SearchResultModel#getMyOffset 99 * @returns {String|0} value of offset 100 */ 101 getMyOffset: function () { 102 var hash = queryModel.parseHashParameters(window.location.hash), 103 signature = encodeURIComponent(this.get("dataProperties").sig); 104 if (hash.hasOwnProperty("e_" + signature)) { 105 return hash["e_" + signature]; 106 } 107 return 0; 108 }, 109 /** 110 * Updates model with new data from resultData parameter 111 * @param {Object} resultsData new component data 112 * @memberof module:searchResults.SearchResultModel 113 * @alias module:searchResults.SearchResultModel#resultsLoaded 114 */ 115 resultsLoaded: function (resultsData) { 116 var signature = encodeURIComponent(this.get("dataProperties").sig); 117 118 if (signature === resultsData.searchResultsSignature) { 119 if (this.get("loadMore")) { 120 this.set({ resultDataMore: resultsData }); 121 this.set({ loadingMoreInProgress: false }); 122 this.unset("loadMore", { silent: true });
123 } else { 124 this.set({ resultData: resultsData }); 125 this.set({ loadingInProgress: false }); 126 this.unset("resultDataMore", { silent: true }); 127 } 128 this.blockRequests(false); 129 } 130 }, 131 /** 132 * Manages loadingMoreInProgress model variable 133 * @param {Object} cid component id 134 * @memberof module:searchResults.SearchResultModel 135 * @alias module:searchResults.SearchResultModel#resultsLoading 136 */ 137 resultsLoading: function (cid) { 138 if (this.cid == cid) { 139 if (this.get("loadMore")) { 140 this.set({ loadingMoreInProgress: true }); 141 } else { 142 this.set({ loadingInProgress: true }); 143 } 144 } 145 }, 146 /** 147 * Resets search results model 148 * @memberof module:searchResults.SearchResultModel 149 * @alias module:searchResults.SearchResultModel#resultsLoading 150 */ 151 resetModel: function() { 152 this.set({ loadMoreOffset: 0 }); 153 this.unset("resultDataMore", { silent: true }); 154 } 155 }); 156 /** 157 * @name module:searchResults.SearchResultView 158 * @constructor 159 * @augments Backbone.View 160 */ 161 var SearchResultView = Backbone.View.extend( 162 /** @lends module:searchResults.SearchResultView.prototype **/ 163 { 164 /** 165 * Initially sets data to model and watches events on which 166 * view should be updated 167 * @listens module:searchResults.SearchResultModel~event:change:loadingInProgress 168 * @listens module:searchResults.SearchResultModel~event:change:loadingMoreInProgress 169 * @listens module:searchResults.SearchResultModel~event:change:resultData 170 * @listens module:searchResults.SearchResultModel~event:change:resultDataMore 171 * @listens module:XA.component.search.vent~event:add-variant-class 172 * @listens module:XA.component.search.vent~event:loadMore 173 * @listens module:XA.component.search.vent~event:my-location-coordinates-changed 174 * @memberof module:searchResults.SearchResultView 175 * @alias module:searchResults.SearchResultView#initialize 176 */ 177 initialize: function () { 178 var dataProperties = this.$el.data(), 179 noResultsText = this.$el.find(".no-results").html(), 180 searchRouter = XA.component.search.router, 181 searchRouterInstance = searchRouter ? searchRouter.routerInstance : undefined, 182 maxHeight = 0, 183 inst = this; 184 185 if (dataProperties.properties.sig === null) { 186 dataProperties.properties.sig = ""; 187 } 188 189 if (this.model) { 190 this.model.set({ dataProperties: dataProperties.properties, noResultsText: noResultsText }); 191 } 192 193 this.model.on("change:loadingInProgress", this.loading, this); 194 this.model.on("change:loadingMoreInProgress", this.loadingMore, this); 195 this.model.on("change:resultData", this.render, this); 196 this.model.on("change:resultDataMore", this.renderPart, this); 197 198 this.$el.on("remove", function () { 199 searchResultModels = searchResultModels.filter(function (m) { 200 return m.cid !== inst.model.cid 201 }) 202 }) 203 204 XA.component.search.vent.on("add-variant-class", function (data) { 205 var signature = inst.model.get("dataProperties").sig; 206 if (data.sig === signature) { 207 inst.$el.removeClass(inst.$el.attr("data-class-variant")); 208 inst.$el.attr("data-class-variant", data.classes); 209 inst.$el.addClass(data.classes); 210 } 211 }); 212 213 XA.component.search.vent.on("loadMore", function (data) { 214 var signature = inst.model.get("dataProperties").sig; 215 if (data.sig === signature) { 216 XA.component.search.service.getData({
217 loadMore: "true", 218 p: inst.model.get("dataProperties").p, 219 singleRequestMode: signature 220 }); 221 } 222 }); 223 224 XA.component.search.vent.on("my-location-coordinates-changed", function (data) { 225 if (data.sig === inst.model.get("dataProperties").sig && inst.model.get("loadMore")) { 226 inst.$el.find(".search-result-list").html(""); 227 } 228 }); 229 230 if (searchRouterInstance && dataProperties.properties.autoFireSearch && this.$el.closest('.overlay-inner').length) { 231 searchRouterInstance.checkUrl(window.location.hash, true) 232 } 233 234 this.render(); 235 }, 236 /** 237 * list of events for Backbone View 238 * @memberof module:searchResults.SearchResultView 239 * @alias module:searchResults.SearchResultView#events 240 */ 241 events: { 242 'click .search-result-list > li[data-longitude][data-latitude]': "poiClick" 243 }, 244 /** 245 * Manage 'loading-in-progress' css class 246 * @memberof module:searchResults.SearchResultView 247 * @alias module:searchResults.SearchResultView#loading 248 */ 249 loading: function () { 250 if (this.model.get("loadingInProgress")) { 251 this.$el.addClass("loading-in-progress"); 252 } else { 253 this.$el.removeClass("loading-in-progress"); 254 } 255 }, 256 /** 257 * Manage 'loading-more-in-progress' css class 258 * @memberof module:searchResults.SearchResultView 259 * @alias module:searchResults.SearchResultView#loadingMore 260 */ 261 loadingMore: function () { 262 if (this.model.get("loadingMoreInProgress")) { 263 this.$el.addClass("loading-more-in-progress"); 264 } else { 265 this.$el.removeClass("loading-more-in-progress"); 266 } 267 }, 268 /** 269 * Renders search result list 270 * @memberof module:searchResults.SearchResultView 271 * @alias module:searchResults.SearchResultView#renderPart 272 */ 273 renderPart: function () { 274 var template = _.template(this.model.get("templateItems")); 275 var templateResult = template({ results: this.model.get("resultDataMore").data }); 276 this.$el.find(".search-result-list").append(templateResult); 277 }, 278 /** 279 * Renders view 280 * @memberof module:searchResults.SearchResultView 281 * @alias module:searchResults.SearchResultView#render 282 */ 283 render: function () { 284 var inst = this, 285 maxHeight = 0, 286 results = inst.model.get("resultData").data; 287 288 //checks if page is opened from disc - if yes then we are in Creative Exchange mode 289 if (window.location.href.startsWith("file://")) { 290 return; 291 } 292 293 if (typeof results === "undefined") { 294 results = []; 295 } 296 297 var template = _.template(inst.model.get("template")); 298 var templateResult = template({ results: results, noResultsText: inst.model.get("noResultsText") }); 299 this.$el.html(templateResult); 300 }, 301 /** 302 * Renders view 303 * @param {Event} e Event object that contains target poi elment 304 * @fires XA.component.search.vent#center-map 305 * @memberof module:searchResults.SearchResultView 306 * @alias module:searchResults.SearchResultView#poiClick 307 */ 308 poiClick: function (e) { 309 var li = $(e.currentTarget); 310 311 XA.component.search.vent.trigger("center-map", { 312 sig: this.model.get("dataProperties").sig, 313 coordinates: [li.data('latitude'), li.data('longitude')], 314 id: li.data('id') 315 }); 316 } 317 }); 318 /** 319 * For each search result component on a page creates instance of 320 * ["SearchResultModel"]{@link module:searchResults.SearchResultModel} and
321 * ["SearchResultView"]{@link module:searchResults.SearchResultView} 322 * @memberOf module:searchResults 323 * @alias module:searchResults.init 324 */ 325 api.init = function () { 326 if ($("body").hasClass("on-page-editor")) { 327 return; 328 } 329 330 urlHelperModel = XA.component.search.url; 331 queryModel = XA.component.search.query; 332 apiModel = XA.component.search.ajax; 333 334 var searchResults = $(".search-results:not(.initialized)"); 335 336 _.each(searchResults, function (elem) { 337 var $el = $(elem), 338 resultsModel = new SearchResultModel(); 339 340 searchResultModels.push(resultsModel); 341 searchResultViews.push(new SearchResultView({ el: $el, model: resultsModel })); 342 343 $el.addClass("initialized"); 344 }); 345 }; 346 /** 347 *Extends API methods with searchResultModels 348 * @alias module:searchResults.searchResultViews 349 */ 350 api.searchResultViews = searchResultViews; 351 /** 352 * Extends API methods with searchResultModels 353 * @memberOf module:searchResults 354 * @alias module:searchResults.searchResultModels 355 */ 356 api.searchResultModels = searchResultModels; 357 358 return api; 359 360}(jQuery, document)); 361 362XA.register('searchResults', XA.component.search.results);
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.