PageSourceSearch

https://detoyboys.nl/modules/amazzingfilter/views/js/front.js

js detoyboys.nl collected 2026-10-08 06:00:48 UTC 38,062 bytes, 1,020 lines download raw bytes

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.