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