1/** 2* @author Amazzing 3* @copyright Amazzing 4* @license https://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) 5*/ 6 7var af_product_list_selector = '#js-product-list', 8 pagination_class = af_classes['pagination'], 9 customThemeActions = { 10 documentReady: function() {}, 11 updateContentAfter: function(jsonData){} 12 }; 13 14var af = { 15 defineVariables: function() { 16 $.extend(af, { 17 // basic varibales 18 blockAjax: false, resizeTimer: false, mouseLeaveTimer: false, qsTimer: false, cosCounter: 1, 19 // misc variables 20 isCompact: false, 21 autoScroll: false, 22 useUniform: !!$.fn.uniform, 23 dimZeroMatches: parseInt($('#af_dim_zero_matches').val()), 24 hideZeroMatches: parseInt($('#af_hide_zero_matches').val()), 25 showCounters: parseInt($('#af_count_data').val()), 26 includeGroup: parseInt($('#af_include_group').val()), 27 dynamicParams: { 28 f: parseInt($('#af_url_filters').val()), 29 s: parseInt($('#af_url_sorting').val()), 30 p: parseInt($('#af_url_page').val()), 31 }, 32 nbItems: { 33 current: $('#af_nb_items').val(), 34 orig: $('#af_npp').val(), 35 }, 36 isHorizontal: $('#af_layout').val() == 'horizontal', 37 productItemSelector: '.'+af_classes['js-product-miniature'], 38 noItemsClass: 'no-available-items', 39 popstateURL: af.removeHash(window.location.href), 40 reqNum: 0, 41 doAfterAjaxOnce: [], 42 // basic $elements 43 $w: $(window), 44 $listWrapper: $('.af_pl_wrapper'), // redefined later in setWrapper() 45 $filterBlock: $('#amazzing_filter'), 46 $selectedFilters: $('.selectedFilters'), 47 $pageInput: $('#af_page'), 48 $viewBtn: $('.viewFilteredProducts'), 49 $dynamicContainer: $('#products').first(), 50 }); 51 if (!af.$dynamicContainer.length) { 52 af.$dynamicContainer = $('#content').length ? $('#content') : $('#main'); 53 } 54 }, 55 documentReady: function() { 56 af.defineVariables(); 57 customThemeActions.documentReady(); 58 af.setWrapper(); 59 af.bindEvents(); 60 af.emit('documentReady'); 61 af.toggleCompactView(); 62 af.cutOff.prepare(); 63 af.adjustFolderedStructure(); 64 af.prepareLoadMoreIfRequired(); 65 af.updateSelectedFilters(); 66 af.updURLrequired = af.updURLrequired || (!af.dynamicParams.p && af.$pageInput.val() > 1); 67 if (af.updURLrequired && af.$listWrapper.length) { 68 af.updateURL(af.prepareUrlAndVerifyParams()); 69 } 70 }, 71 prepareLoadMoreIfRequired: function() { 72 if (load_more && af.$listWrapper.length) { 73 $('.dynamic-product-count').html(af_product_count_text); 74 $('.dynamic-loading.next').removeClass('hidden').insertAfter(af.$listWrapper); 75 $('.dynamic-loading.prev').removeClass('hidden').insertBefore(af.$listWrapper); 76 if (!show_load_more_btn) { 77 $('.loadMore.next').addClass('hidden'); 78 } 79 $('.loadMore').on('click', function() { 80 var $parent = $(this).closest('.dynamic-loading'), 81 p = parseInt(af.$pageInput.val()); 82 if ($parent.hasClass('next')) { 83 p++; 84 } else { // prev 85 $(this).data('p', $(this).data('p') - 1); 86 if ($(this).data('p') < 2) { 87 af.doAfterAjaxOnce.push(function() { 88 $parent.addClass('hidden'); 89 }); 90 } 91 } 92 $parent.addClass('loading'); 93 af.$pageInput.val(p).change(); 94 }); 95 af.rememberScrollPosition(); 96 if ($('#af_p_type').val() == 3) { 97 af.infScroll.init(); 98 } 99 } 100 }, 101 rememberScrollPosition: function() { 102 $(document).on('click', af.productItemSelector, function(e) { 103 var possibleLink = $(e.target).closest('a').attr('href'); 104 if (possibleLink && !possibleLink.startsWith('#')) { 105 af.$lastClickedItem = $(this); 106 clearTimeout(af.lastClickedItemTimer); 107 af.lastClickedItemTimer = setTimeout(function() { 108 delete af.$lastClickedItem; // if pagehide is not triggered within 3s after click 109 }, 3000); 110 } 111 }); 112 af.$w.on('pagehide', function(e) { 113 if (af.$lastClickedItem) { 114 if (e.originalEvent && e.originalEvent.persisted) { 115 return; // bfcache 116 } 117 var $currentItems = af.$listWrapper.find(af.productItemSelector), 118 prevNum = $currentItems.index(af.$lastClickedItem), 119 nbItems = parseInt(af.nbItems.current), 120 scrolledPage = Math.floor(prevNum / nbItems), 121 initialPage = $('.loadMore.prev').data('p') || 1, 122 elIndexInPage = prevNum - (scrolledPage * nbItems), 123 rememberPage = scrolledPage + initialPage, 124 scrollCompensation = (af.$w.height() - af.$lastClickedItem.height()) / 2, 125 requiredScrollPosition = $currentItems.eq(elIndexInPage).offset().top - scrollC
125ompensation; 126 af.dynamicParams.p = 1; 127 af.$pageInput.val(rememberPage); 128 af.updateURL(af.prepareUrlAndVerifyParams()); // page param is updated in URL and it will be loaded when user clicks back 129 window.scrollTo(0, requiredScrollPosition); // scroll position is restored when user clicks back 130 } 131 }); 132 }, 133 bindEvents: function() { 134 Object.keys(af.events).forEach(function(type) { 135 Object.keys(af.events[type]).forEach(function(event) { 136 af.events[type][event](); 137 }); 138 }); 139 }, 140 events: { 141 filter: { 142 general: function() { 143 $('.af-form').on('click', 'a[href="#"]', function(e) { 144 e.preventDefault(); 145 }).on('change', 'input, select', function() { 146 if ($(this).data('notrigger')) { 147 return; 148 } 149 var trigger = $(this).attr('id'), 150 type = $(this).attr('type') || $(this).prop('tagName').toLowerCase(), 151 $parent = $(this).closest('.af_filter'), 152 isHiddenInput = $(this).parent().hasClass('hidden_inputs'), 153 updateList = !af.$viewBtn.data('active') || isHiddenInput; 154 if (type == 'checkbox' || type == 'radio') { 155 if (type == 'radio') { 156 $parent.find('li.active').removeClass('active'); 157 } 158 $(this).closest('li').toggleClass('active', $(this).prop('checked')); 159 } else if (type == 'select' && !$(this).closest('.selector-with-customer-filter').hasClass('hidden') && 160 $(this).find('option[value="'+$(this).val()+'"]').hasClass('customer-filter')) { 161 $(this).closest('.af_filter').find('.customer-filter-label').click(); 162 return; 163 } 164 if (trigger != 'af_page') { 165 af.$pageInput.val(1); 166 } 167 if (!af.blockAjax) { 168 if (af.$viewBtn.data('active') && !isHiddenInput) { 169 af.$viewBtn.addClass('loading').data('animate-after-loading', 1); 170 } 171 af.applyFilters(trigger, updateList); 172 } 173 }); 174 af.moreFilters.init() 175 }, 176 selectedFilters: function() { 177 af.$selectedFilters.on('click', 'a', function(e) { 178 e.preventDefault(); 179 var $parentRow = $(this).parent(), 180 $groupBlock = $('.af_filter[data-url="'+$parentRow.data('group')+'"]'); 181 if ($(this).hasClass('close')) { 182 if ($groupBlock.hasClass('type-1') || $groupBlock.hasClass('type-2')) { 183 var $input = $groupBlock.find('#'+$parentRow.data('id')); 184 $input.prop('checked', false).change(); 185 if (af.useUniform) { 186 $input.parent().removeClass('checked'); 187 } 188 } else if ($groupBlock.hasClass('type-3')) { 189 $groupBlock.find('select').val('').change(); 190 } else if ($groupBlock.hasClass('has-slider')) { 191 af.slider.resetValues(af.slider.$[$parentRow.data('id')]); 192 } 193 } else if ($(this).hasClass('all')) { 194 af.blockAjax = true; 195 af.$selectedFilters.find('.cf').find('a').click(); 196 af.blockAjax = false; 197 if (af.$viewBtn.data('active')) { 198 af.$viewBtn.addClass('loading').data('animate-after-loading', 1); 199 } 200 af.applyFilters('clear_all', !af.$viewBtn.data('active')); 201 } 202 }); 203 }, 204 dim: function() { 205 if (af.dimZeroMatches && !af.hideZeroMatches) { // block visible checkboxes/radio with 0 matches 206 $('.af-form').on('click', 'input.af.checkbox, input.af.radio', function(e) { 207 // prop checked becomes true for unchecked inputs, right after click 208 if ($(this).prop('checked') && $(this).closest('li').hasClass('no-matches')) { 209 e.preventDefault(); 210 $(this).prop('checked', false); 211 if (af.useUniform) { 212 $(this).parent().removeClass('checked').parent().removeClass('focus'); 213 if ($(this).hasClass('radio')) { 214 var $parentBlock = $(this).closest('.af_filter'), 215 id = $('.cf[data-group="'+$parentBlock.data('url')+'"]').data('id'); 216 // keep checked styles on radioboxes that were checked before 217 $parentBlock.find('#'+id).parent().addClass('checked').parent().addClass('focus'); 218 } 219 } 220 } 221 }); 222 } 223 }, 224 viewBtn: function() { 225 af.$viewBtn.on('click', function(e) { 226 e.preventDefault(); 227 if (!$(this).hasClass('loading')) { 228 $(this).addClass('loading');
229 af.applyFilters('view_products', true); 230 if (af.isCompact) { 231 $('.af-compact-overlay').trigger('click'); 232 } 233 } 234 }); 235 }, 236 foldered: function() { 237 $('.af-form').on('click', '.af-toggle-child', function(e) { 238 e.stopPropagation(); 239 $(this).closest('.af-parent-category').toggleClass('open'); 240 }); 241 }, 242 toggleableContent: function() { 243 $('.af-form').on('click', '.af_subtitle.toggle-content', function(e) { 244 e.preventDefault(); 245 var $filter = $(this).closest('.af_filter'); 246 if (!$filter.hasClass(af.noItemsClass)) { 247 $filter.toggleClass('closed'); 248 if (!$filter.hasClass('closed')) { 249 if ($filter.hasClass('type-3') && af.useUniform) { 250 $filter.find('.af-select').uniform(); 251 } 252 if (af.isCompact) { 253 $filter.siblings('.af_filter').addClass('closed'); 254 } else if (af.isHorizontal) { 255 af.autoCloseFilterContent($filter); 256 } 257 } 258 } 259 af.cutOff.prepare($filter); 260 }); 261 }, 262 quickSearch: function() { 263 $('.af-form').on('keyup', '.qsInput', function() { 264 var $qsInput = $(this); 265 clearTimeout(af.qsTimer); 266 af.qsTimer = setTimeout(function() { 267 var value = $qsInput.val().toLowerCase(), 268 $options = $qsInput.closest('.af_filter_content').find('li'); 269 $options.removeClass('qs-hidden'); 270 if (value.length) { 271 $options.each(function() { 272 if ($(this).children('label').children('.name').text().toLowerCase().indexOf(value) === -1) { 273 $(this).addClass('qs-hidden'); 274 } 275 }); 276 } 277 $qsInput.toggleClass('has-value', value.length > 0).siblings('.qs-no-matches'). 278 toggleClass('hidden', !!$options.not('.qs-hidden, .no-matches').length); 279 if ($qsInput.data('tree')) { 280 $options.removeClass('qs-half-hidden').filter('.af-parent-category.qs-hidden').each(function() { 281 if ($(this).find('li').not('.qs-hidden').length) { 282 $(this).addClass('qs-half-hidden open'); 283 } 284 }); 285 } 286 af.cutOff.prepare($qsInput.closest('.af_filter')); 287 }, 200); 288 }); 289 }, 290 }, 291 theme: { 292 nbItems: function() { 293 $(document).off('change', 'select[name="n"]').on('change', 'select[name="n"]', function() { 294 af.nbItems.current = $(this).val(); 295 $('#af_nb_items').val(af.nbItems.current).change(); 296 }).on('submit', '.showall', function(e) { 297 e.preventDefault(); 298 var num = $(this).find('input[name="n"]').val(), 299 $nSelect = $('select[name="n"]'); 300 if (!$nSelect.find('option[value="'+num+'"]').length) { 301 var maxNum = $nSelect.find('option').last().val(); 302 if (parseInt(maxNum) >= parseInt(num)) { 303 num = maxNum; 304 } else { 305 var newOptionHTML = '<option value="'+num+'">'+num+'</option>'; 306 $nSelect.append(newOptionHTML); 307 if (af.useUniform) { 308 $nSelect.uniform(); 309 } 310 } 311 } 312 $nSelect.val(num).change(); 313 }); 314 }, 315 sorting: function() { 316 $('body').off('click', '.js-search-link').on('click', '.select-list.js-search-link', function(e) { 317 e.preventDefault(); 318 $(this).addClass('current').siblings().removeClass('current'); 319 // todo: consider cases when "order=" is not present in href 320 var value = $(this).attr('href').split('order=')[1].split('&')[0].split('.'); 321 orderBy = value[1], 322 orderWay = value[2], 323 sortingName = $(this).text(), 324 $title = $(this).closest('.products-sort-order').find('.select-title'), 325 $htmlElementsInTitle = $title.children();
326 af.applySorting(orderBy, orderWay); 327 $title.html(sortingName).append($htmlElementsInTitle); 328 }); 329 }, 330 pagination: function() { 331 $(document).on('click','.'+pagination_class+' a', function(e) { 332 e.preventDefault(); 333 var page = 1; 334 if ($(this).attr('href').indexOf('?') > -1) { 335 var params = af.unserialize($(this).attr('href').split('?')[1], false); 336 if (af_param_names.p in params && params[af_param_names.p] > 1) { 337 page = params[af_param_names.p]; 338 } 339 } 340 af.$pageInput.val(page).change(); 341 }); 342 if (window.Theme && Theme.selectors.listing.pagerLink) { // hummingbird 343 setTimeout(function() {$('body').off('click', Theme.selectors.listing.pagerLink)}, 0); 344 } 345 }, 346 qty: function() { 347 if (window.Theme && Theme.components && Theme.components.useQuantityInput) { 348 let unreadyQtySelector = af_product_list_selector+' ' 349 +Theme.selectors.qtyInput.default + ':not(.ready)'; 350 $(unreadyQtySelector).addClass('ready'); 351 af.on('afterAjax', function(r) { 352 Theme.components.useQuantityInput(unreadyQtySelector); 353 $(unreadyQtySelector).addClass('ready'); 354 }); 355 } 356 }, 357 }, 358 browser: { 359 popstate: function() { 360 af.$w.on('popstate', function() { // when user clicks back/forward in browser 361 if (af.removeHash(window.location.href) != af.popstateURL) { 362 af.updateFiltersBasingOnURL(window.location.href); 363 } 364 }); 365 }, 366 resize: function() { 367 af.$w.on('resize', function() { 368 clearTimeout(af.resizeTimer); 369 af.resizeTimer = setTimeout(function() {af.toggleCompactView()}, 100); 370 }); 371 }, 372 }, 373 }, 374 autoCloseFilterContent: function($filter) { 375 $filter.off('mouseenter mouseleave').on('mouseenter', function() { 376 clearTimeout(af.mouseLeaveTimer); 377 }).on('mouseleave', function() { 378 af.mouseLeaveTimer = setTimeout(function() { 379 if (!$filter.hasClass('closed') && !$filter.find('input[type="text"]:focus').length) { 380 $filter.find('.af_subtitle.toggle-content').click(); 381 } 382 $filter.off('mouseenter mouseleave'); 383 }, 1000); 384 }); 385 af.onClickOutSide( 386 $filter.find('.af_filter_content'), 387 function() {$filter.addClass('closed');} 388 ); 389 }, 390 onClickOutSide: function($el, action) { 391 setTimeout(function() { 392 let clickEvent = 'click.outside'+(af.cosCounter++); 393 $(document).on(clickEvent, function(e) { 394 if (!$el.is(e.target) && $el.has(e.target).length === 0) { 395 action(); 396 $(document).off(clickEvent); 397 } 398 }); 399 }, 0); 400 }, 401 applySorting: function (orderBy, orderWay) { 402 $('#af_orderBy').val(orderBy); 403 $('#af_orderWay').val(orderWay).change(); 404 }, 405 toggleSidePanel: function() { 406 let $body = $('body'); 407 if (!$body.hasClass('show-filter')) { 408 // compensate autoscrolling to top caused by position: fixed 409 af.compactScroll = af.$w.scrollTop(); 410 $body.addClass('show-filter').css('top', '-'+af.compactScroll+'px') 411 .append('<div class="af-compact-overlay compact-toggle"></div>'); 412 requestAnimationFrame(function(){$('.af-compact-overlay').addClass('show');}); 413 } else { 414 $body.removeClass('show-filter').css('top', '').find('.af-compact-overlay').remove(); 415 window.scrollTo({top: af.compactScroll, left: 0, behavior: 'instant'}); 416 } 417 }, 418 prepareCompactView: function() { 419 if (af.compactReady) { 420 return; 421 } 422 $('body').on('click', '.compact-toggle', function() { 423 af.toggleSidePanel(); 424 }); 425 if ('ontouchstart' in document.documentElement) { 426 var swipeThreshold = 150, xStart = 0, xEnd = 0, 427 compactLeft = af.$filterBlock.hasClass('compact-offset-left'); 428 af.$filterBlock.on('touchstart', function (e) { 429 xStart = e.originalEvent.touches[0].clientX; 430 xEnd = xStart; 431 }).on('touchmove',function (e) { 432 xEnd = e.originalEvent.touches[0].clientX; 433 }).on('touchend',function (e) { 434 var diff = compactLeft ? xStart - xEnd : xEnd - xStart; 435 if (diff > swipeThreshold && // detect swipe towards edge 436 !$(e.target).closest('.af_filter').not('.closed').hasClass('has-slider')) { // no swiping on sliders 437 af.toggleSidePanel(); 438 } // TODO: else detect swipe from edge to open filter panel 439 }); 440 } 441 af.compactReady = true; 442 }, 443 toggleCompactView: function() { 444 var isCompactBefore = af.isCompact; 445 af.isCompact = af.$filterBlock.css('position') == 'fixed'; 446 af.autoScroll = af.isCompact ? 1 : parseInt($('#af_autoscroll').val()); 447 if (isCompactBefore != af.isCompact) { 448 $('body').toggleClass('has-compact-filter', af.isCompact); 449 var $afBlocks = af.$filterBlock.find('.af_filter'), $btnHolder = af.$filterBlock.find('.btn-holder'); 450 if (af.isCompact) { 451 af.prepareCompactView(); 452 $afBlocks.filter('.closed').addClass('cl-orig'); 453 $afBlocks.filter('.foldered').addClass('fd-orig'); 454 $afBlocks.addClass('closed').filter('.folderable').addClass('foldered'); 455 $afBlocks.not('.no-available-items').first().removeClass('closed'); 456 af.$filterBlock.removeClass('horizontal-layout').before('<span class="af-orig hidden"></span>').appendTo('body'); 457 $('.af-compact-overlay').appendTo('body'); 458 $btnHolder.appendTo(af.$filterBlock); // avoid position:absolute + -webkit-overflow-scrolling: touch; 459 setTimeout(function() { 460 af.$filterBlock.addClass('animation-ready'); 461 }, 500); 462 af.moreFilters.cancel(); 463 } else { 464 af.$filterBlock.removeClass('animation-ready').toggleClass('horizontal-layout', af.isHorizontal); 465 $('.af-orig').before(af.$filterBlock).before($('.af-compact-overlay')).remove(); 466 $btnHolder.insertAfter('#af_form'); // original position 467 $afBlocks.each(function() { 468 $(this).toggleClass('closed', $(this).hasClass('cl-orig')) 469 .toggleClass('foldered', $(this).hasClass('fd-orig')); 470 }); 471 af.moreFilters.update(); 472 } 473 af.cutOff.prepare($afBlocks); 474 af.emit('toggleCompactView'); 475 } 476 af.updateSFPositionIfRequired(); 477 af.toggleViewBtn(); 478 }, 479 toggleViewBtn: function() { 480 var showBtn = $('#af_reload_action').val() == 2 || af.isCompact; 481 af.$viewBtn.toggleClass('hidden', !showBtn).data('active', showBtn) 482 .parent().toggleClass('hidden', !showBtn && !$('.manage-permanent-filters').length); 483 }, 484 setWrapper: function() { 485 if (!af.$listWrapper.length) { 486 $(af_product_list_selector).first().wrap('<div class="af_pl_wrapper clearfix"></div>'); 487 af.$listWrapper = $('.af_pl_wrapper'); 488 } 489 }, 490 updateSFPositionIfRequired: function() { 491 let aboveProductList = $('#af_sf_position').val() == 1; 492 af.$selectedFilters.toggleClass('inline', af.isCompact || af.isHorizontal || aboveProductList); 493 if (aboveProductList) { 494 if (!af.isCompact) { 495 let $before = af_is_modern ? $('#products').first() : $('.content_sortPagiBar').first(); 496 af.$selectedFilters.addClass('af').insertBefore($before); 497 } else { 498 af.$selectedFilters.removeClass('af').insertBefore('#af_form'); 499 } 500 } 501 }, 502 applyFilters: function(trigger, updateList) { 503 if (af.$listWrapper.length && (updateList || af.$viewBtn.data('active'))) { 504 af.updateSelectedFilters(); 505 } 506 af.loadProducts(trigger, updateList); 507 }, 508 prepareParamsForAjaxRequest: function(trigger, updateList) { 509 if (updateList && !$('.dynamic-loading').hasClass('loading')) { 510 af.$listWrapper.stop().animate({'opacity': 0.3}, 350); 511 } 512 $('.af-select').each(function() { 513 if (!$(this).val()) { 514 if (!$(this).hasClass('no-submit')) { 515 $(this).addClass('no-submit').data('inputname', $(this).attr('name')). 516 attr('name', 'no_submit'); // do not submit empty value from select 517 } 518 } else if ($(this).hasClass('no-submit')) { 519 $(this).removeClass('no-submit').attr('name', $(this).data('inputname')); 520 } 521 if (af.dimZeroMatches) { 522 // submit values from selected options without matches 523 $(this).find('.no-matches:selected:disabled').prop('disabled', false); 524 } 525 }); 526 var params = $('.af-form').serialize(); 527 if (!updateList) { 528 params += '&nb_items=0'; 529 } else if (!af.$listWrapper.length) { 530 if (!af_is_modern && page_name != 'index') { 531 af.updateSelectedFilters(); 532 af.updateURL(af.prepareUrlAndVerifyParams()); 533 window.location.reload(); 534 return; 535 } 536 params += '&layout_required=1'; 537 af.$dynamicContainer.animate({'opacity': 0.3}, 350); 538 } 539 if (load_more) { 540 var $prevLoader = $('.dynamic-loading.prev'); 541 if (trigger == 'af_page') { 542 if (!$prevLoader.length) { 543 params += '&page_from=1'; 544 } else if ($prevLoader.hasClass('loading')) { 545 params += '&page='+$('.loadMore.prev').data('p')+'&page_to='+af.$pageInput.val(); 546 } else { 547 params += '&page_from='+$('.loadMore.prev').data('p'); 548 } 549 } else { 550 $prevLoader.remove(); 551 } 552 } 553 return params; 554 }, 555 loadProducts: function(trigger, updateList) { 556 if (af.blockAjax) { 557 return; 558 } 559 var params = af.prepareParamsForAjaxRequest(trigger, updateList); 560 requestIdentifier = ++af.reqNum; 561 af.newURL = af.prepareUrlAndVerifyParams(); 562 $.ajax({
563 type: 'POST', 564 url: af_ajax.path, 565 dataType : 'json', 566 data: { 567 action: 'getFilteredProducts', 568 params: params, 569 current_url: af.newURL, 570 trigger: trigger, 571 token: af_ajax.token, 572 }, 573 success: function(r) { 574 if (requestIdentifier != af.reqNum) { 575 return; // update layout only for last request if checkboxes are clicked too fast 576 } 577 af.updateContent(r, trigger, updateList); 578 af.updateURL(af.newURL); 579 af.emit('afterAjax', r); 580 if (af.doAfterAjaxOnce.length > 0) { 581 af.doAfterAjaxOnce.forEach(function(f) {f();}); 582 af.doAfterAjaxOnce = []; 583 } 584 }, 585 error: function(r) { 586 console.warn($(r.responseText).text() || r.responseText); 587 } 588 }); 589 }, 590 updateContent: function(jsonData, trigger, updateList) { 591 // var af_timeStart = new Date().getTime()/1000; 592 if (updateList) { 593 if ('layout' in jsonData) { 594 af.updateListLayout(jsonData.layout); 595 af.newURL = af.prepareUrlAndVerifyParams(); 596 } 597 af.updateProductList(jsonData, trigger); 598 if (af.autoScroll && (!load_more || trigger != 'af_page')) { 599 af.autoscrollToTopOfTheList(); 600 } 601 } 602 if (trigger != 'af_page') { 603 $('.af-total-count').html(parseInt(jsonData.products_num)); 604 af.updateFilteringBlocks(jsonData); 605 } 606 if (af.$viewBtn.data('active')) { 607 af.$viewBtn.removeClass('loading'); 608 if (af.$viewBtn.data('animate-after-loading')) { 609 af.$viewBtn.addClass('btn-pulsate').data('animate-after-loading', 0); 610 setTimeout(function() { 611 af.$viewBtn.removeClass('btn-pulsate'); 612 }, 300); 613 } 614 } 615 // var af_timeEnd = new Date().getTime()/1000; 616 // af_timeEnd = af_timeEnd - af_timeStart 617 // console.dir('all elements updated: '+af_timeEnd); 618 }, 619 updateProductList: function(jsonData, trigger) { 620 if (load_more && trigger == 'af_page') { 621 var $result = $('<div>'+jsonData.product_list_html+'</div>'), 622 $items = $result.find(af.productItemSelector); 623 if ($('.dynamic-loading.prev').hasClass('loading')) { 624 af.$listWrapper.find(af.productItemSelector).first().before($items); 625 } else { 626 af.$listWrapper.find(af.productItemSelector).last().after($items); 627 } 628 $('.dynamic-loading.loading').removeClass('loading').find('.loadMore').trigger('blur'); 629 if (af_is_modern) { 630 $('#js-product-list-top').replaceWith(jsonData.product_list_top_html); 631 } 632 } else { 633 af.$listWrapper.html(jsonData.product_list_html); 634 if (af_is_modern) { 635 $('#js-product-list-top').replaceWith(jsonData.product_list_top_html); 636 $('#js-product-list-bottom').replaceWith(jsonData.product_list_bottom_html); 637 } else { 638 $('.'+af_classes['product-count']).remove(); 639 $('#'+pagination_holder_id).replaceWith(jsonData.pagination_html); 640 $('#'+pagination_bottom_holder_id).replaceWith(jsonData.pagination_bottom_html); 641 } 642 } 643 if (load_more) { 644 var $countContainer = af_is_modern ? $('.dynamic-product-count') : $('.'+af_classes['product-count']); 645 $countContainer.html(jsonData.product_count_text); 646 $('.loadMore.next').toggleClass('hidden', jsonData.hide_load_more_btn); 647 } 648 var animationTime = af_is_modern ? 500 : 1000; 649 af.$listWrapper.animate({'opacity': 1}, animationTime); 650 af.updateListAfter(jsonData); 651 }, 652 updateListAfter: function(jsonData) { 653 if (typeof display == 'function' && $.totalStorage 654 && $.totalStorage('display') && $.totalStorage('display') != 'grid') { 655 display($.totalStorage('display')); 656 } 657 // prestashop.emit('updateProductList'); //todo: add configurable action 658 customThemeActions.updateContentAfter(jsonData); 659 if (typeof updateContentAfter == 'function') updateContentAfter(jsonData); // retro compatibility 660 af.$filterBlock.trigger('updateProductList', jsonData); 661 }, 662 updateFilteringBlocks: function(jsonData) { 663 if ($.isEmptyObject(jsonData.count_data)) { 664 return; 665 } 666 $('.af_filter').each(function() { 667 let key = $(this).data('key'), 668 sortByMatches = $(this).hasClass('sort-by-matches') && !$(this).hasClass('has-selection'); 669 if ($.inArray($(this).data('type'), [1,2,5]) > -1) { // checkbox, radio, textbox 670 $(this).find('input.af').each(function() { 671 var count = jsonData.count_data[key][$(this).val()] || 0, 672 $li = $(this).closest('li'); 673 if (count) { 674 $li.removeClass('no-matches'); 675 } else if (!$li.hasClass('no-matches')) { 676 $li.addClass('no-matches'); 677 } 678 if (af.showCounters) { 679 $li.find('.count').first().html(count); 680 }; 681 if (sortByMatches) { 682 $li.data('count', count); 683 if (!$li.next().length) { 684 af.sortByMatches($li.parent(), 'li'); 685 } 686 } 687 }); 688 af.checkAvailableItems($(this), false); 689 } else if ($(this).data('type') == 3) { // selects 690 var $select = $(this).find('.af-select'), 691 currentValue = $select.val(), 692 html = ''; 693 $(this).find('.dynamic-select-options').children().each(function() { 694 var data = $(this).data(), 695 count = jsonData.count_data[key][data.value] || 0; 696 if (count || data.value == currentValue || $(this).hasClass('customer-filter') || !af.hideZeroMatches) { 697 html += '<option id="'+data.id+'" value="'+data.value+'"'; 698 html += ' class="'+$(this).attr('class')+(count ? '' : ' no-matches')+'"'; 699 html += ' data-url="'+data.url+'" data-text="'+data.text+'"'; 700 if (sortByMatches) { 701 html += ' data-count="'+count+'"'; 702 } 703 html += (af.dimZeroMatches && !count ? ' disabled' : '')+'>'; 704 html += data.prefix+data.text+(af.showCounters ? ' ('+count+')': '')+'</option>'; 705 } 706 }); 707 $select.children().first().nextAll().remove(); // keep only first option 708 if (html) { 709 $select.append(html).val(currentValue); 710 if (sortByMatches) { 711 af.sortByMatches($select, 'option:not(.first)'); 712 } 713 if (af.useUniform) { 714 $select.uniform(); 715 }; 716 } 717 af.checkAvailableItems($(this), true); 718 } 719 }); 720 af.cutOff.prepare(); 721 if (!af.isCompact) { 722 af.moreFilters.update(); 723 } 724 af.adjustFolderedStructure(); 725 }, 726 sortByMatches: function($parent, itemSelector) { 727 $parent.children(itemSelector).sort(function(a, b) { 728 return $(b).data('count') - $(a).data('count'); 729 }).appendTo($parent); 730 }, 731 prepareUrlAndVerifyParams: function(baseURL) { 732 var url = baseURL || af.getStaticURL(), 733 dynamicParams = af.prepareDynamicParams(); 734 if (!$.isEmptyObject(dynamicParams)) { 735 url += (url.indexOf('?') > -1 ? '&' : '?')+decodeURIComponent($.param(dynamicParams, true)); 736 } 737 return url; 738 }, 739 updateURL: function(url) { 740 if (url && url != window.location.href) { 741 window.history.pushState(null, null, url); 742 af.popstateURL = url; 743 } 744 }, 745 getStaticURL: function() { 746 if (!af.staticURL) { 747 var splittedUrl = decodeURIComponent(window.location.href).split('?'); 748 af.staticURL = af.removeHash(splittedUrl[0]); 749 if (splittedUrl.length == 2) { 750 var staticParams = af.unserialize(splittedUrl[1], true); 751 if (!$.isEmptyObject(staticParams)) { 752 af.staticURL += '?'+decodeURIComponent($.param(staticParams, true)); 753 } 754 } 755 } 756 return af.staticURL; 757 }, 758 prepareDynamicParams: function() { 759 var dynamicParams = {}, page = af.$pageInput.val(); 760 if (af.dynamicParams.f) { 761 af.$selectedFilters.find('.cf').add('.sp-dynamic-params').each(function() { 762 let n = $(this).data('group'), v = $(this).data('url'); 763 if (n && v) { 764 if (n in dynamicParams) { 765 dynamicParams[n] += ','+v; 766 } else { 767 dynamicParams[n] = v; 768 } 769 } 770 }); 771 } 772 if (af.dynamicParams.p && page > 1) { 773 dynamicParams[af_param_names.p] = page; 774 } 775 if (af.dynamicParams.s) { 776 var order = {by: $('#af_orderBy').val(), way: $('#af_orderWay').val()}; 777 if (order.by+'.'+order.way != $('#af_default_sorting').val()) { 778 if (af_is_modern) { 779 dynamicParams.order = 'product.'+order.by+'.'+order.way; 780 } else { 781 dynamicParams.orderby = order.by 782 dynamicParams.orderway = order.way 783 } 784 } 785 } 786 if (af.nbItems.current != af.nbItems.orig) { 787 dynamicParams[af_param_names.n] = af.nbItems.current; 788 } 789 af.emit('prepareDynamicParams', dynamicParams); 790 return dynamicParams; 791 }, 792 autoscrollToTopOfTheList: function() { 793 if (af.$listWrapper.length) { 794 var wrapperTop = af.$listWrapper.offset().top; 795 if (af.isCompact || !af.isInViewPort(wrapperTop, wrapperTop)) { 796 $('html, body').animate({scrollTop: wrapperTop - 150}, 100); 797 } 798 } 799 }, 800 isInViewPort: function (top, bottom) { 801 var scrollTop = af.$w.scrollTop(), windowHeight = af.$w.height(); 802 return (scrollTop + windowHeight) > top && scrollTop < bottom; 803 }, 804 checkAvailableItems: function($block, isSelect) { 805 if (af.dimZeroMatches || af.hideZeroMatches) { 806 var noItems = !isSelect ? $block.find('li').not('.no-matches:not(.active)').length < 1 807 : $block.find('option').not('.no-matches:not(:selected), .first').length < 1; 808 $block.toggleClass(af.noItemsClass, noItems); 809 } 810 }, 811 cutOff: { 812 prepare: function($blocks) { 813 $blocks = $blocks ? $blocks : $('.af_filter'); 814 $blocks.not('.closed').find('.toggle-cut-off').each(function() { 815 var $filter = $(this).closest('.af_filter'); 816 af.cutOff.apply($filter, $(this).data('cut')); 817 if (!$(this).data('click-ready')) { 818 $(this).on('click', function(e) { 819 e.preventDefault(); 820 $filter.toggleClass('cut-off'); 821 }).data('click-ready', 1); 822 } 823 }); 824 }, 825 apply: function($filter, aboveCut) { 826 if (!$filter.hasClass('cut-off')) { 827 return; 828 } 829 let except = '.qs-hidden'+(af.hideZeroMatches ? ', .no-matches' : ''); 830 $filter.find('ul').first().children('li').not(except).each(function() { 831 if (--aboveCut >= 0) { 832 $(this).removeClass('cut'); 833 } else if (!$(this).hasClass('cut')) { 834 $(this).addClass('cut'); 835 } 836 }); 837 $filter.toggleClass('expandable', aboveCut < 0); 838 }, 839 cancel: function($filter) { 840 $filter.find('.cut').removeClass('cut'); 841 }, 842 }, 843 moreFilters: { 844 init: function() { 845 af.moreFilters.$btn = af.$filterBlock.find('.toggleMoreFilters').on('click', function() { 846 $('.af-form').toggleClass('show-more-f'); 847 }); 848 }, 849 update: function() { 850 if (af.moreFilters.$btn.length) { 851 let $blocks = af.$filterBlock.find('.af_filter'); 852 if (af.hideZeroMatches) { 853 $blocks = $blocks.not('.no-available-items'); 854 } 855 $blocks.each(function(i) { 856 if (i < af.moreFilters.$btn.data('num')) { 857 $(this).removeClass('more-f'); 858 } else if (!$(this).hasClass('more-f')) { 859 $(this).addClass('more-f'); 860 } 861 }); 862 af.moreFilters.$btn.parent().toggleClass('hidden', !$blocks.filter('.more-f').length); 863 } 864 }, 865 cancel: function() { 866 af.$filterBlock.find('.af_filter').removeClass('more-f'); 867 af.moreFilters.$btn.parent().addClass('hidden'); 868 } 869 }, 870 adjustFolderedStructure: function() { 871 $('.af_filter.foldered').find('.af-parent-category').each(function() { 872 var $children = $(this).children('ul').find('li'), 873 childrenWithMatches = $children.not('.no-matches').length, 874 checkedChildren = $children.filter('.active').length; 875 if (af.hideZeroMatches) { 876 // hide foldered trigger if none of subcategories are available 877 $(this).children('label').find('.af-toggle-child').toggleClass('hidden', !childrenWithMatches && !checkedChildren); 878 } 879 if (checkedChildren || (childrenWithMatches && $(this).hasClass('no-matches'))) { 880 $(this).addClass('open'); 881 if (af.hideZeroMatches || af.dimZeroMatches) { 882 $(this).removeClass('no-matches'); 883 } 884 } 885 }); 886 }, 887 updateListLayout: function(layout_html) { 888 if ($.contains(af.$dynamicContainer[0], af.$filterBlock[0])) { 889 af.$filterBlock.insertBefore(af.$dynamicContainer); 890 $('.af.dynamic-loading').insertAfter(af.$filterBlock); 891 } 892 af.$dynamicContainer.html(layout_html).animate({'opacity': 1}, 350); 893 af.setWrapper(); 894 af.updateSFPositionIfRequired(); 895 af.updateSelectedFilters(); 896 af.prepareLoadMoreIfRequired(); 897 }, 898 updateSelectedFilters: function() { 899 let html = ''; 900 $('.af_filter').each(function() { 901 let groupURL = $(this).data('url'), 902 groupText = af.includeGroup && !$(this).hasClass('special') ? $(this).find('.af_subtitle').text()+': ' : '', 903 hasSelection = $(this).find('.customer-filter-label').not('.unlocked').length > 0;
904 if ($(this).hasClass('has-slider')) { 905 let type = $(this).find('.af-slider').data('type'), 906 $bar = af.slider.$[type]; 907 if ($bar.values.from > $bar.values.min || $bar.values.to < $bar.values.max) { 908 let nt = af.slider.selectedRangeNotation($bar); 909 html += af.renderSelectedOption(nt.url, groupURL, groupText+nt.txt, type); 910 hasSelection = true; 911 } 912 } else { 913 $(this).find('input, option:not(.first, .customer-filter)').filter(':checked, :selected').each(function() { 914 let text = groupText+($(this).data('text') || $(this).closest('label').find('.name').text()); 915 html += af.renderSelectedOption($(this).data('url'), groupURL, text, $(this).attr('id')); 916 hasSelection = true; 917 }); 918 } 919 $(this).toggleClass('has-selection', hasSelection); 920 }); 921 af.$selectedFilters.find('.cf').remove(); 922 af.$selectedFilters.append(html).toggleClass('hidden', !html); 923 }, 924 renderSelectedOption: function(url, group, text, id) { 925 return '<div class="cf" data-url="'+url+'" data-group="'+group+'" data-id="'+id+'">' 926 +text+' <a href="#" class="'+af_classes['u-times']+' close"></a></div>'; 927 }, 928 infScroll: { 929 threshold: [70, 700], 930 init: function() { 931 this.$dl = $('.dynamic-loading.next'); 932 this.$btn = $('.loadMore.next'); 933 this.bind(); 934 }, 935 bind: function() { 936 this.viewPortTop = af.$w.scrollTop(); 937 af.$w.on('scroll.afis', function() { 938 clearTimeout(af.infScroll.timer); 939 af.infScroll.timer = setTimeout(function() { 940 if (af.infScroll.isScrollingDown() && !af.infScroll.$dl.hasClass('loading') && 941 !af.infScroll.$btn.hasClass('hidden')) { 942 let offset = parseInt(af.infScroll.$dl.offset().top); 943 thresholdOffset = { 944 top: af.infScroll.viewPortTop + af.infScroll.threshold[0], 945 bottom: af.infScroll.viewPortTop + af.$w.height() + af.infScroll.threshold[1], 946 }; 947 if (offset < thresholdOffset.bottom) { 948 offset > thresholdOffset.top ? af.infScroll.$btn.click() : af.infScroll.unbind(true); 949 } 950 } 951 }, 50); 952 }); 953 }, 954 unbind: function(showBtnOnce) { 955 af.$w.off('scroll.afis'); 956 if (showBtnOnce) { 957 this.$dl.removeClass('infinite-scroll'); 958 af.doAfterAjaxOnce.push(function() { 959 af.infScroll.$dl.addClass('infinite-scroll'); 960 af.infScroll.bind(); 961 }); 962 } 963 }, 964 isScrollingDown: function() { 965 let prevTop = this.viewPortTop; 966 this.viewPortTop = af.$w.scrollTop(); 967 return this.viewPortTop > prevTop; 968 }, 969 }, 970 unserialize: function(params, excludeDynamicParams) { 971 params = params.split('&'); 972 var result = {}, 973 dynamicParams = {order:0, orderby:0, orderway:0}; 974 dynamicParams[af_param_names.p] = 0; 975 dynamicParams[af_param_names.n] = 0; 976 for (var i in params) { 977 if (params.hasOwnProperty(i)) { // make sure params[i] does not come from Array.prototype 978 var splitted = params[i].split('='), name = splitted[0]; 979 if (splitted.length == 2 && (!excludeDynamicParams || 980 !$('.af_filter[data-url="'+name+'"]').length && !(name in dynamicParams))) { 981 result[name] = splitted[1]; 982 } 983 } 984 } 985 return result; 986 }, 987 updateFiltersBasingOnURL: function(url) { 988 window.location.reload(); 989 // TODO: dynamically update filters and product list basing on URL, or may be other global variable 990 // var splittedUrl = decodeURIComponent(url).split('?'); 991 // if (splittedUrl.length == 2) { 992 // $.each(af.unserialize(splittedUrl[1]), function(name, val) { 993 // if ($('.af_filter[data-url="'+name+'"]').length) { 994 // console.dir(val); 995 // } 996 // }); 997 998 // } 999 }, 1000 removeHash: function(url) { 1001 return url.split('#')[0]; 1002 }, 1003 externalEvents: {}, 1004 emit: function(key, arg) { 1005 if (af.externalEvents[key]) { 1006 af.externalEvents[key].forEach(function(callback) { 1007 callback(arg); 1008 }); 1009 } 1010 }, 1011 on: function(key, callback) { 1012 af.externalEvents[key] = af.externalEvents[key] || []; 1013 af.externalEvents[key].push(callback); 1014 }, 1015}; 1016 1017$(document).ready(function() { 1018 af.documentReady(); 1019}); 1020/* since 3.3.3 */
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.