https://starrcompanies.com/-/media/Base-Themes/SearchTheme/Scripts/component-search-page-selector.js
1/** 2 * Facet page selector component functionality 3 * @module searchPageSelector 4 * @param {jQuery} $ Instance of jQuery 5 * @param {Document} document dom document object 6 * @return {Object} list of methods for working with component page selector 7*/ 8XA.component.search.pageSelector = (function ($, document) { 9 /** 10 * This object stores all public api methods 11 * @type {Object.<Methods>} 12 * @memberOf module:searchPageSelector 13 */ 14 var api = {}, 15 queryModel; 16 facetName = "e"; 17 /** 18 * @name module:searchPageSelector.SearchPageSelectorModel 19 * @constructor 20 * @augments Backbone.Model 21 */ 22 var SearchPageSelectorModel = Backbone.Model.extend( 23 /** @lends module:searchPageSelector.SearchPageSelectorModel.prototype **/ 24 { 25 /** 26 * Default model options 27 * @default 28 */ 29 defaults: { 30 dataProperties: {}, 31 resultsCount: 0, 32 offset: 0, 33 selectedValue: 1, 34 pageSize: 0, 35 repeatRequest: false, 36 template: "<ul class='page-selector-list'> " + 37 "<li class='page-selector-item-first'><a href='#'><%= data.first %></a></li>" + 38 "<li class='page-selector-item-previous'><a href='#'><%= data.previous %></a></li>" + 39 "<% var beforePage = 0; %>" + 40 "<% _.each(data.pages, function(page){ %>" + 41 "<% if((beforePage+1) != page.number){ %>" + 42 "<li><span class='page-selector-more'>...</span></li>" + 43 "<% } %>" + 44 "<% beforePage = page.number; %>" + 45 "<% if(data.selectedValue === page.number){ %>" + 46 "<% active = 'active'; %>" + 47 "<% }else { active = '' } %>" + 48 "<li><a class='page-selector-item-link <%= active %>' data-offset='<%= page.offset %>' data-itemNumber='<%= page.number %>' href='#'><%= page.number %></a></li>" + 49 "<% }); %>" + 50 "<li class='page-selector-item-next'><a href='#'><%= data.next %></a></li>" + 51 "<li class='page-selector-item-last'><a href='#'><%= data.last %></a></li>" + 52 "</ul>", 53 sig: [], 54 timeStamp: new Date().getTime() 55 } 56 }); 57 /** 58 * @name module:searchPageSelector.SearchPageSelectorView 59 * @constructor 60 * @augments Backbone.View 61 */ 62 var SearchPageSelectorView = XA.component.search.baseView.extend( 63 /** @lends module:searchPageSelector.SearchPageSelectorView **/ 64 { 65 /** 66 * Initially sets data to model and watches events on which 67 * view should be updated 68 * @listens module:searchPageSelector.SearchPageSelectorView~event:change 69 * @listens module:XA.component.search.vent~event:results-loaded 70 * @memberof module:searchPageSelector.SearchPageSelectorView 71 * @alias module:searchPageSelector.SearchPageSelectorView#initialize 72 */ 73 initialize: function () { 74 var dataProp = this.$el.data(); 75 76 if (dataProp.properties.searchResultsSignature === null) { 77 dataProp.properties.searchResultsSignature = ""; 78 } 79 80 this.model.set("dataProperties", dataProp); 81 this.model.set("sig", this.translateSignatures(dataProp.properties.searchResultsSignature, facetName)); 82 this.model.on("change", this.render, this); 83 84 XA.component.search.vent.on("results-loaded", this.handleLoadedData.bind(this)); 85 86 //check whether page is opened from disc - if yes then we are in Creative Exchange mode and lets mock some content 87 if (window.location.href.startsWith("file://")) { 88 this.model.set({ 89 "resultsCount": 10, 90 "pageSize": 2, 91 "selectedValue": 2 92 }); 93 } 94 }, 95 /** 96 * list of events for Backbone View 97 * @memberof module:searchPageSelector.SearchPageSelectorView 98 * @alias module:searchPageSelector.SearchPageSelectorView#events 99 */ 100 events: { 101 'click .page-selector-item-link': "updateSelectedValue", 102 'click .page-selector-item-first a': "showFirstPage", 103 'click .page-selector-item-last a': "showLastPage", 104 'click .page-selector-item-previous a': "showPrevPage", 105 'click .page-selector-item-next a': "showNextPage" 106 }, 107 /** 108 * Updates model values with selectedValue 109 * and data object from server response 110 * @param {Object} data Data that contains component properties 111 * @param {Number} selectedValue number of selected page 112 * @memberOf module:searchPageSelector.SearchPageSelectorView 113 * @alias module:searchPageSelector.SearchPageSelectorView#updateModelAfterSearch 114 */ 115 updateModelAfterSearch: function (data, selectedValue) { 116 this.model.set({ 117 "pageSize": parseInt(data.pageSize), 118 "resultsCount": parseInt(data.dataCount), 119 "offset": parseInt(data.offset), 120 "selectedValue": parseInt(selectedValue) 121 }); 122 this.model.set("timeStamp", new Date().getTime()); 123 this.updateElementCssClass(data); 124 }, 125 /** 126 * Function that based on selected component values sets css class 127 * page-selector-empty or page-selector-single-page 128 * @param {Object} data Data that contains component properties 129 * @memberOf module:searchPageSelector.SearchPageSelectorView 130 * @alias module:searchPageSelector.SearchPageSelectorView#updateElementCssClass 131 */ 132 updateElementCssClass: function (data) { 133 this.el.classList.remove("page-selector-empty") 134 this.el.classList.remove("page-selector-single-page") 135 if (data.dataCount === 0) { 136 this.el.classList.add("page-selector-empty") 137 } else if (data.pageSize >= data.dataCount || data.offset > data.dataCount) { 138 this.el.classList.add("page-selector-single-page") 139 } 140 }, 141 /** 142 * Updates hash according to changed component value 143 * @param {Event} event Event object that contains target with selected component value 144 * @memberOf module:searchPageSelector.SearchPageSelectorView 145 * @alias module:searchPageSelector.SearchPageSelectorView#updateSelectedValue 146 */ 147 updateSelectedValue: function (event) { 148 event.preventDefault(); 149 150 var sig = this.model.get("sig"), 151 dataProp = $(event.target).data(); 152
153 queryModel.updateHash(this.updateSignaturesHash(sig, dataProp.offset, {})); 154 }, 155 /** 156 * Switches page selector to the first page and updates hash parameters 157 * @param {Event} event Event object that contains target with selected component value 158 * @memberOf module:searchPageSelector.SearchPageSelectorView 159 * @alias module:searchPageSelector.SearchPageSelectorView#showFirstPage 160 */ 161 showFirstPage: function (event) { 162 event.preventDefault(); 163 164 var sig = this.model.get("sig"), 165 dataProp = $(event.target).data(); 166 167 queryModel.updateHash(this.updateSignaturesHash(sig, 0, {})); 168 }, 169 /** 170 * Switches page selector to the last page and updates hash parameters 171 * @param {Event} event Event object that contains target with selected component value 172 * @memberOf module:searchPageSelector.SearchPageSelectorView 173 * @alias module:searchPageSelector.SearchPageSelectorView#showLastPage 174 */ 175 showLastPage: function (event) { 176 event.preventDefault(); 177 var lastPageItems = this.model.get("resultsCount") % this.model.get("pageSize"), 178 offset = this.model.get("resultsCount") - ((lastPageItems === 0) ? this.model.get("pageSize") : lastPageItems), 179 sig = this.model.get("sig"); 180 181 queryModel.updateHash(this.updateSignaturesHash(sig, offset, {})); 182 }, 183 /** 184 * Switches page selector to the next page and updates hash parameters 185 * @param {Event} event Event object that contains target with selected component value 186 * @memberOf module:searchPageSelector.SearchPageSelectorView 187 * @alias module:searchPageSelector.SearchPageSelectorView#showNextPage 188 */ 189 showNextPage: function (event) { 190 event.preventDefault(); 191 192 var offset = this.model.get("offset"), 193 sig = this.model.get("sig"); 194 195 if ((offset + this.model.get("pageSize")) < this.model.get("resultsCount")) { 196 offset += this.model.get("pageSize"); 197 } 198 199 queryModel.updateHash(this.updateSignaturesHash(sig, offset, {})); 200 }, 201 /** 202 * Switches page selector to the precious page and updates hash parameters 203 * @param {Event} event Event object that contains target with selected component value 204 * @memberOf module:searchPageSelector.SearchPageSelectorView 205 * @alias module:searchPageSelector.SearchPageSelectorView#showPrevPage 206 */ 207 showPrevPage: function (event) { 208 event.preventDefault(); 209 210 var offset = this.model.get("offset"), 211 dataProp = $(event.target).data(), 212 sig = this.model.get("sig"); 213 214 if ((offset - this.model.get("pageSize")) >= 0) { 215 offset -= this.model.get("pageSize"); 216 } 217 218 queryModel.updateHash(this.updateSignaturesHash(sig, offset, {})); 219 }, 220 /** 221 * Renders view 222 * @memberOf module:searchPageSelector.SearchPageSelectorView 223 * @alias module:searchPageSelector.SearchPageSelectorView#render 224 */ 225 render: function () { 226 var inst = this, 227 dataProp = this.model.get("dataProperties").properties, 228 resultsCount = this.model.get("resultsCount"), 229 pageSize = this.model.get("pageSize"), 230 selectedValue = this.model.get("selectedValue"), 231 pagesCount = Math.ceil(resultsCount / pageSize), 232 pages = [], 233 rangeStart = selectedValue - dataProp.treshold / 2, 234 rangeEnd = selectedValue + dataProp.treshold / 2,
235 templateObj; 236 237 if (rangeStart < 0) { 238 rangeEnd += Math.abs(rangeStart); 239 } 240 241 if (rangeEnd > pagesCount) { 242 rangeStart -= (rangeEnd - pagesCount); 243 } 244 245 if (dataProp.treshold >= pagesCount) { 246 for (var i = 0; i < pagesCount; i++) { 247 pages.push({ number: i + 1, offset: i * pageSize }); 248 } 249 } 250 else { 251 for (var i = 1; i <= pagesCount; i++) { 252 if ((i === 1) || (i === pagesCount)) { 253 pages.push({ number: i, offset: (i - 1) * pageSize }); 254 } 255 else if ((i >= rangeStart) && (i <= rangeEnd)) { 256 pages.push({ number: i, offset: (i - 1) * pageSize }); 257 } 258 } 259 } 260 261 templateObj = { 262 previous: dataProp.previous, 263 first: dataProp.first, 264 next: dataProp.next, 265 last: dataProp.last, 266 pages: pages, 267 selectedValue: selectedValue 268 }; 269 var template = _.template(inst.model.get("template")); 270 var templateResult = template({ data: templateObj }); 271 this.$el.html(templateResult); 272 273 this.handleButtonState(selectedValue, pagesCount); 274 }, 275 /** 276 * Sets up page selectors buttons state depending on selected values 277 * @param {Number} selectedPage number of selected page 278 * @param {Number} pageCount number of pages 279 * @memberOf module:searchPageSelector.SearchPageSelectorView 280 * @alias module:searchPageSelector.SearchPageSelectorView#handleButtonState 281 */ 282 handleButtonState: function (selectedPage, pageCount) { 283 this.$el.find(".page-selector-item-last, .page-selector-item-next").removeClass("inactive"); 284 this.$el.find(".page-selector-item-first, .page-selector-item-previous").removeClass("inactive"); 285 286 287 if (pageCount == 0) { 288 this.$el.find(".page-selector-item-first, .page-selector-item-previous").addClass("inactive"); 289 this.$el.find(".page-selector-item-last, .page-selector-item-next").addClass("inactive"); 290 } 291 else { 292 if (selectedPage == 1) { 293 this.$el.find(".page-selector-item-first, .page-selector-item-previous").addClass("inactive"); 294 } 295 if (selectedPage == pageCount) { 296 this.$el.find(".page-selector-item-last, .page-selector-item-next").addClass("inactive"); 297 } 298 } 299 }, 300 /** 301 * Updates hash and model based on data object 302 * @param {Object} data Data that contains component properties 303 * @memberOf module:searchPageSelector.SearchPageSelectorView 304 * @alias module:searchPageSelector.SearchPageSelectorView#handleLoadedData 305 */ 306 handleLoadedData: function (data) { 307 var that = this, 308 sig = this.model.get("dataProperties").properties.searchResultsSignature.split(','), 309 hash = queryModel.parseHashParameters(window.location.hash), 310 newSelectedValue, 311 param, 312 hashObj, 313 i; 314 315 if (typeof data.offset === 'undefined') { 316 data.offset = 0; 317 } 318 319 for (i = 0; i < sig.length; i++) { 320 if (encodeURIComponent(sig[i]) === data.searchResultsSignature) { 321 if (data.pageSize >= data.dataCount || data.offset > data.dataCount) { 322 //When we have less results then page size then show first page 323 this.updateModelAfterSearch(data, 1); 324 //Wait till all requests are done and go to first page 325 setTimeout(function () { 326 //queryModel.updateHash({e: 0}); //- this will work, but doesn't give us proper browser history 327 hashObj = queryModel.parseHashParameters(window.location.hash); 328 param = data.searchResultsSignature !== "" ? data.searchResultsSignature + "_e" : "e"; 329 if (hash[param] !== "0") { 330 hashObj[param] = 0; 331 Backbone.history.navigate(that.createFirstPageUrlHash(hashObj), { trigger: true, replace: true });
332 } 333 }, 100); 334 } else { 335 newSelectedValue = Math.ceil(data.offset / data.pageSize) + 1; 336 this.updateModelAfterSearch(data, newSelectedValue); 337 } 338 } 339 } 340 }, 341 /** 342 * Calculates hash parameters for first page 343 * @param {Object} data Data that contains component properties 344 * @memberOf module:searchPageSelector.SearchPageSelectorView 345 * @alias module:searchPageSelector.SearchPageSelectorView#createFirstPageUrlHash 346 * @returns {String} hash parameter for first page 347 */ 348 createFirstPageUrlHash: function (hashObj) { 349 var hashStr = ""; 350 351 var i = 0; 352 _.each(hashObj, function (item, key) { 353 if (i > 0) { 354 hashStr += "&"; 355 } 356 i++; 357 hashStr += key + "=" + item; 358 }); 359 360 return hashStr; 361 } 362 }); 363 364 /** 365 * For each page selector on a page creates instance of 366 * ["SearchPageSelectorModel"]{@link module:searchPageSelector.SearchPageSelectorModel} and 367 * ["SearchPageSelectorView"]{@link module:searchPageSelector.SearchPageSelectorView} 368 * @memberOf module:searchPageSelector 369 * @alias module:searchPageSelector.SearchPageSelectorView.init 370 */ 371 api.init = function () { 372 if ($("body").hasClass("on-page-editor")) { 373 return; 374 } 375 376 queryModel = XA.component.search.query; 377 378 var searchPageSelector = $(".page-selector:not(.initialized)"); 379 380 _.each(searchPageSelector, function (elem) { 381 var $el = $(elem); 382 383 new SearchPageSelectorView({ el: $el, model: new SearchPageSelectorModel }); 384 385 $el.addClass("initialized"); 386 }); 387 }; 388 389 return api; 390 391}(jQuery, document)); 392 393XA.register('searchPageSelector', XA.component.search.pageSelector);
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.