PageSourceSearch

https://www.maluna.cz/themes/default-bootstrap/js/product.js

js maluna.cz collected 2026-10-07 04:25:18 UTC 49,944 bytes, 1,509 lines download raw bytes

1/*
2* 2007-2015 PrestaShop
3*
4* NOTICE OF LICENSE
5*
6* This source file is subject to the Academic Free License (AFL 3.0)
7* that is bundled with this package in the file LICENSE.txt.
8* It is also available through the world-wide-web at this URL:
9* http://opensource.org/licenses/afl-3.0.php
10* If you did not receive a copy of the license and are unable to
11* obtain it through the world-wide-web, please send an email
12* to [email protected] so we can send you a copy immediately.
13*
14* DISCLAIMER
15*
16* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
17* versions in the future. If you wish to customize PrestaShop for your
18* needs please refer to http://www.prestashop.com for more information.
19*
20*  @author PrestaShop SA <[email protected]>
21*  @copyright  2007-2015 PrestaShop SA
22*  @license    http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
23*  International Registered Trademark & Property of PrestaShop SA
24*/
25
26//global variables
27var serialScrollNbImagesDisplayed;
28var selectedCombination = [];
29var globalQuantity = 0;
30var colors = [];
31var original_url = window.location + '';
32var first_url_check = true;
33var firstTime = true;
34var sticky_button_slider;
35
36/* Retro compat from product.tpl */
37if (typeof customizationFields !== 'undefined' && customizationFields)
38{
39	var customizationFieldsBk = customizationFields;
40	customizationFields = [];
41	var j = 0;
42	for (var i = 0; i < customizationFieldsBk.length; ++i)
43	{
44		var key = 'pictures_' + parseInt(id_product) + '_' + parseInt(customizationFieldsBk[i]['id_customization_field']);
45		customizationFields[i] = [];
46		customizationFields[i][0] = (parseInt(customizationFieldsBk[i]['type']) == 0) ? 'img' + i : 'textField' + j++;
47		customizationFields[i][1] = (parseInt(customizationFieldsBk[i]['type']) == 0 && customizationFieldsBk[i][key]) ? 2 : parseInt(customizationFieldsBk[i]['required']);
48	}
49}
50
51if (typeof combinationImages !== 'undefined' && combinationImages)
52{
53	combinationImagesJS = [];
54	combinationImagesJS[0] = [];
55	var k = 0;
56	for (var i in combinationImages)
57	{
58		combinationImagesJS[i] = [];
59		for (var j in combinationImages[i])
60		{
61			var id_image = parseInt(combinationImages[i][j]['id_image']);
62			if (id_image)
63			{
64				combinationImagesJS[0][k++] = id_image;
65				combinationImagesJS[i][j] = [];
66				combinationImagesJS[i][j] = id_image;
67			}
68		}
69	}
70
71	if (typeof combinationImagesJS[0] !== 'undefined' && combinationImagesJS[0])
72	{
73		var array_values = [];
74		for (var key in arrayUnique(combinationImagesJS[0]))
75			array_values.push(combinationImagesJS[0][key]);
76		combinationImagesJS[0] = array_values;
77	}
78	combinationImages = combinationImagesJS;
79}
80
81if (typeof combinations !== 'undefined' && combinations)
82{
83	combinationsJS = [];
84	var k = 0;
85	for (var i in combinations)
86	{
87		globalQuantity += combinations[i]['quantity'];
88		combinationsJS[k] = [];
89		combinationsJS[k]['idCombination'] = parseInt(i);
90		combinationsJS[k]['idsAttributes'] = combinations[i]['attributes'];
91		combinationsJS[k]['quantity'] = combinations[i]['quantity'];
92		combinationsJS[k]['price'] = combinations[i]['price'];
93		combinationsJS[k]['ecotax'] = combinations[i]['ecotax'];
94		combinationsJS[k]['image'] = parseInt(combinations[i]['id_image']);
95		combinationsJS[k]['reference'] = combinations[i]['reference'];
96		combinationsJS[k]['unit_price'] = combinations[i]['unit_impact'];
97		combinationsJS[k]['minimal_quantity'] = parseInt(combinations[i]['minimal_quantity']);
98
99		combinationsJS[k]['available_date'] = [];
100		combinationsJS[k]['available_date']['date'] = combinations[i]['available_date'];
101		combinationsJS[k]['available_date']['date_formatted'] = combinations[i]['date_formatted'];
102
103		combinationsJS[k]['specific_price'] = [];
104		combinationsJS[k]['specific_price']['reduction_percent'] = (combinations[i]['specific_price'] && combinations[i]['specific_price']['reduction'] && combinations[i]['specific_price']['reduction_type'] == 'percentage') ? combinations[i]['specific_price']['reduction'] * 100 : 0;
105		combinationsJS[k]['specific_price']['reduction_price'] = (combinations[i]['specific_price'] && combinations[i]['specific_price']['reduction'] && combinations[i]['specific_price']['reduction_type'] == 'amount') ? combinations[i]['specific_price']['reduction'] : 0;
106		combinationsJS[k]['price'] = (combinations[i]['specific_price'] && combinations[i]['specific_price']['price'] && parseInt(combinations[i]['specific_price']['price']) != -1) ? combinations[i]['specific_price']['price'] :  combinations[i]['price'];
107
108		combinationsJS[k]['reduction_type'] = (combinations[i]['specific_price'] && combinations[i]['specific_price']['reduction_type']) ? combinations[i]['specific_price']['reduction_type'] : '';
109		combinationsJS[k]['id_product_attribute'] = (combinations[i]['specific_price'] && combinations[i]['specific_price']['id_product_attribute']) ? combinations[i]['specific_price']['id_product_attribute'] : 0;
110		k++;
111	}
112	combinations = combinationsJS;
113}
114/* */
115
116$(document).ready(function() {
117	var url_found = checkUrl();
118	//init the price in relation of the selected attributes
119	if (!url_found)
120	{
121		if (typeof productHasAttributes != 'undefined' && productHasAttributes)
122			findCombination();
123		else
124			refreshProductImages(0);
125	}
126
127	serialScrollSetNbImages();
128
129	//init the serialScroll for thumbs
130	if (!!$.prototype.serialScroll)
131		$('#thumbs_list').serialScroll({
132			items:'li:visible',
133			prev:'#view_scroll_left',
134			next:'#view_scroll_right',
135			axis:'x',
136			offset:0,
137			start:0,
138			stop:true,
139			onBefore:serialScrollFixLock,
140			duration:700,
141			lazy: true,
142			lock: false,
143			force:false,
144			cycle:false
145		});
146
147	$('#thumbs_list').trigger('goto', 0);
148
149	//set jqZoom parameters if needed
150	if (typeof(jqZoomEnabled) != 'undefined' && jqZoomEnabled)
151	{
152		if ($('#thumbs_list .shown img').length)
153		{
154			var new_src = $('#thumbs_list .shown img').attr('src').replace('cart_', 'large_');
155			if ($('.jqzoom img').attr('src')!= new_src)
156				$('.jqzoom img').attr('src', new_src).parent().attr('href', new_src);
157		}
158
159		$('.jqzoom').jqzoom({
160			zoomType: 'innerzoom', //innerzoom/standard/reverse/drag
161			zoomWidth: 458, //zooming div default width(default width value is 200)
162			zoomHeight: 458, //zooming div default width(default height value is 200)
163			xOffset: 21, //zooming div default offset(default offset value is 10)
164			yOffset: 0,
165			title: false
166		});
167
168	}
169	if (typeof(contentOnly) != 'undefined' && !contentOnly)
170	{
171		if (!!$.prototype.fancybox)
172			$('li:visible .fancybox, .fancybox.shown').fancybox({
173				'hideOnContentClick': true,
174				'openEffect'	: 'elastic',
175				'closeEffect'	: 'elastic'
176			});
177	}
178	else if (typeof ajax_allowed != 'undefined' && !ajax_allowed)
179		$('#buy_block').attr('target', '_top');
180
181	if ($('#bxslider li').length && !!$.prototype.bxSlider)
182		$('#bxslider').bxSlider({
183			minSlides: 1,
184			maxSlides: 6,
185			slideWidth: 178,
186			slideMargin: 20,
187			pager: false,
188			nextText: '',
189			prevText: '',
190			moveSlides:1,
191			infiniteLoop:false,
192			hideControlOnEnd: true
193		});
194
195	if (!$('#bxslider li').length)
196		$('.accessories-block').parent().remove();
197
198	if (!!$.prototype.uniform)
199	{
200		if (typeof product_fileDefaultHtml !== 'undefined')
201			$.uniform.defaults.fileDefaultHtml = product_fileDefaultHtml;
202		if (typeof product_fileButtonHtml !== 'undefined')
203			$.uniform.defaults.fileButtonHtml = product_fileButtonHtml;
204	}
205
206	if ($('#customizationForm').length)
207	{
208		var url = window.location + '';
209		if (url.indexOf('#') != -1)
210			getProductAttribute();
211	}
212
213	// natc
214	$('.size_table_anchor, .size_table_anchor_royalslider').fancybox({
215		'hideOnContentClick': true,
216		'openEffect'	: 'elastic',
217		'closeEffect'	: 'elastic'
218	});
219
220	$('#availability-tooltip').fancybox({
221		'hideOnContentClick': true,
222		'openEffect'	: 'elastic',
223		'closeEffect'	: 'elastic'
224	});
225
226	$('#availability-tooltip').on('click', function () {
227		window.setTimeout(() => {
228			gtag('event', 'click', {event_category: 'UX', event_label: 'tooltip-dostupnost'});
229		}, 0);
230	});
231
232	// transparent price
233	var transparent_price_content_shown = false;
234	$('#transparent-price-tooltip').on('click', function () {
235		if (transparent_price_content_shown) {
236			transparent_price_content_shown = false;
237			$('#transparent-price-content').hide();
238		} else {
239			window.setTimeout(() => {
240				gtag('event', 'click', {event_category: 'UX', event_label: 'tooltip-transparentni-cena'});
241				transparent_price_content_shown = true;
242				$('#transparent-price-content').show();
243			}, 0);
244		}
245	});
246	$('#transparent-price-content').on('click', function () {
247		transparent_price_content_shown = false;
248		$('#transparent-price-content').hide();
249	});
250
251	// klarna
252	$('#klarna-tooltip').off('click').on('click', function () {
253		$('#klarna-popup-wrapper').show();
254	});
255
256	$('#klarna-popup, #klarna-header-close-button').off('click').on('click', function () {
257		$('#klarna-popup-wrapper').hide();
258	});
259
260	$('#klarna-popup-content').off('click').on('click', function (e) {
261		e.stopPropagation();
262	});
263
264    // log clicking on sizetable
265    $('a.size_table_anchor, a.size_table_anchor_royalslider').on('click', function () {
266        let type = $(this).data('clicktype');
267        $.ajax({
268            type: 'POST',
269            headers: {"cache-control": "no-cache"},
270            url: '/?rand=' + new Date().getTime(),
271            async: true,
272            cache: false,
273            dataType: "json",
274            data: 'ajax=true&method=sizetableclick&type=' + type + '&id_product=' + id_product + '&token=' + static_token,
275        });
276    });
277
278	$(".royalSlider").royalSlider({
279		// options go here
280		keyboardNavEnabled: true,
281		autoScaleSlider: true,
282		autoScaleSliderWidth: 558,
283		autoScaleSliderHeight: 558,
284		navigateByClick: false,
285		fadeinLoadedSlide: false,
286		thumbs: {
287			spacing: 10,
288			fitInViewport: false
289		},
290		controlNavigation: 'thumbnails',
291		imageScaleMode: 'fit-if-smaller',
292		imageScalePadding: 0,
293		fullscreen: {
294			// fullscreen options go gere
295			enabled: true,
296			nativeFS: false,
297			buttonFS: true,
298		}
299	});
300
301	// add sticker overlay to the royalslider container
302	sticker_overlay_image = ($('#detail_sticker_overlay')[0].innerHTML);
303	$('#detail_sticker_overlay').remove();
304	if (sticker_overlay_image.length) {
305		$('.royalSlider').append(sticker_overlay_image);
306		// propagate click on sticker overlay to show fullscreen image
307		$('.royalSlider .sticker-overlay').on('click', function () {
308			$('.rsOverflow .rsContainer', $(this).parent()).click();
309		});
310	}
311
312	var slider = $(".royalSlider").data('royalSlider');
313	var thumb_height;
314	slider.ev.on('rsExitFullscreen', function() {
315		// exit fullscreen mode
316		$('.rsDefault .rsThumbsHor').css('height', thumb_height);
317		$('#royalslider-overlay').removeClass('show');
318	});
319
320	if (typeof slider != 'undefined') {
321		slider.ev.on('rsSlideClick', function (elem, event) {
322			if (slider.isFullscreen) {
323				if ((event.pageX - $('.rsOverflow').offset().left) < (slider.width / 2)) {
324					slider.prev();
325				} else {
326					slider.next();
327				}
328			} else {
329				var width = $('body').width();
330				if (width > 767) {
331					thumb_height = $('.rsDefault .rsThumbsHor').css('height');
332					$('.rsDefault .rsThumbsHor').css('height', '0');
333					slider.enterFullscreen();
334					$('#royalslider-overlay').addClass('show');
335				} else {
336					if ((event.pageX - $('.rsOverflow').offset().left) < (slider.width / 2)) {
337						slider.prev();
338					} else {
339						slider.next();
340					}
341				}
342			}
343		});
344
345		$('#royalslider-overlay').on('click', function() {
346			slider.exitFullscreen();
347		});
348	}
349
350	let options = {
351		useCSS: false,
352		maxSlides: 4,
353		moveSlides: 1,
354		slideWidth: 300,
355		infiniteLoop: false,
356		hideControlOnEnd: true,
357		pager: false,
358		autoHover: true,
359		oneToOneTouch: false,
360		auto: false,
361		speed: 300,
362		pause: 3000,
363		controls: true
364	};
365
366	onVisible($('#accessories')[0], function () {
367		$('#accessories').bxSlider(options);
368	});
369
370	onVisible($('#natc-add_to_cart')[0], function () {
371		$('#sticky-button').addClass('hidden');
372	}, function () {
373		// get add to cart button top offset from the page
374		let natc_add_to_cart_button_offset_top = $('#natc-add_to_cart')[0].getBoundingClientRect().top + window.scrollY;
375		// get current scroll offset
376		let scroll_top = $(window).scrollTop();
377		// only show sticky button when scrolled below add to cart button
378		if (scroll_top > natc_add_to_cart_button_offset_top) {
379			$('#sticky-button').removeClass('hidden');
380
381			// přepočtení velikosti slideru v sticky-button - jelikož když je skrytý má pro jS tehnicky jinou velikost něž odkrytý
382			sticky_button_slider.recalculate();
383			// posunutí slideru v sticky-button na vybranou velikost
384			var index = $('.sticky-button-size-slider').find('ul.product_list_combs').find('li.natc-variant.selected').index();
385			sticky_button_slider.goToPosition((index + 1));
386		}
387	})
388});
389
390$(window).resize(function(){
391	serialScrollSetNbImages();
392	$('#thumbs_list').trigger('goto', 0);
393	serialScrollFixLock('', '', '', '', 0);
394});
395
396$(window).bind('hashchange', function(){
397	checkUrl();
398	findCombination();
399});
400
401//hover 'other views' images management
402$(document).on('mouseover', '#views_block li a', function(){
403	displayImage($(this));
404});
405//add a link on the span 'view full size' and on the big image
406$(document).on('click', '#view_full_size, #image-block', function(e){
407	$('#views_block .shown').click();
408});
409//catch the click on the "more infos" button at the top of the page
410$(document).on('click', '#short_description_block .button', function(e){
411	$('#more_info_tab_more_info').click();
412	$.scrollTo( '#more_info_tabs', 1200 );
413});
414// Hide the customization submit button and display some message
415$(document).on('click', '#customizedDatas input', function(e){
416	$('#customizedDatas input').hide();
417	$('#ajax-loader').fadeIn();
418	$('#customizedDatas').append(uploading_in_progress);
419});
420
421$(document).on('click', 'a[data-id=resetImages]', function(e){
422	e.preventDefault();
423	refreshProductImages(0);
424});
425
426$(document).on('click', '.color_pick', function(e){
427	e.preventDefault();
428	colorPickerClick($(this));
429	getProductAttribute();
430});
431
432$(document).on('change', '.attribute_select', function(e){
433	e.preventDefault();
434	findCombination();
435	getProductAttribute();
436});
437
438$(document).on('click', '.attribute_radio', function(e){
439	e.preventDefault();
440	findCombination();
441	getProductAttribute();
442});
443
444$(document).on('click', '.natc-variant', function(e) {
445	e.preventDefault();
446	$('select[name=group_4]').val($(this).attr('data-id_attribute')).change();
447
448	// při výběru velikosti na strance produktu posunout pozici slideru v sticky-button
449	if ($(this).closest('.sticky-button-size-slider').length == 0) {
450		var index = $(this).index();
451		sticky_button_slider.goToPosition((index + 1));
452	}
453});
454
455$(document).on('click', 'button[name=saveCustomization]', function(e){
456	saveCustomization();
457});
458
459if (typeof ad !== 'undefined' && ad && typeof adtoken !== 'undefined' && adtoken)
460{
461	$(document).on('click', 'a#publish_button', function(e){
462		e.preventDefault();
463		submitPublishProduct(ad, 0, adtoken);
464	});
465	$(document).on('click', 'a#lnk_view', function(e){
466		e.preventDefault();
467		submitPublishProduct(ad, 1, adtoken);
468	});
469}
470
471if (typeof(contentOnly) != 'undefined' && contentOnly)
472{
473	$(document).on('click', '.fancybox', function(e){
474		e.preventDefault();
475	});
476
477	$(document).on('click', '#image-block', function(e){
478		e.preventDefault();
479		var productUrl = window.document.location.href + '';
480		var data = productUrl.replace(/[\?|&]content_only=1/, '');
481
482		if (window.parent.page_name == 'search')
483			data += ((data.indexOf('?') < 0) ? '?' : '&') + 'HTTP_REFERER=' + encodeURIComponent(window.parent.document.location.href);
484
485		window.parent.document.location.href = data;
486		return;
487	});
488}
489
490function check_free_shipping(quantity) {
491	if (quantity >= quantity_for_free_shipping) {
492		$('#product-claim-shipping-free').show();
493		$('#product-claim-shipping-notfree').hide();
494	} else {
495		$('#product-claim-shipping-free').hide();
496		$('#product-claim-shipping-notfree').show();
497	}
498}
499
500// The button to increment the product value
501$(document).on('click', '.product_quantity_up', function(e){
502	e.preventDefault();
503	fieldName = $(this).data('field-qty');
504	var currentVal = parseInt($('input[name='+fieldName+']').val());
505	if (!allowBuyWhenOutOfStock && quantityAvailable > 0)
506		quantityAvailableT = quantityAvailable;
507	else
508		quantityAvailableT = 100000000;
509	if (!isNaN(currentVal) && currentVal < quantityAvailableT)
510		$('input[name='+fieldName+']').val(currentVal + 1).trigger('keyup');
511	else
512		$('input[name='+fieldName+']').val(quantityAvailableT);
513
514	check_free_shipping($('input[name='+fieldName+']').val());
515});
516// The button to decrement the product value
517$(document).on('click', '.product_quantity_down', function(e){
518	e.preventDefault();
519	fieldName = $(this).data('field-qty');
520	var currentVal = parseInt($('input[name='+fieldName+']').val());
521	if (!isNaN(currentVal) && currentVal > 1)
522		$('input[name='+fieldName+']').val(currentVal - 1).trigger('keyup');
523	else
524		$('input[name='+fieldName+']').val(1);
525
526	check_free_shipping($('input[name='+fieldName+']').val());
527});
528
529if (typeof minimalQuantity != 'undefined' && minimalQuantity)
530{
531	checkMinimalQuantity();
532	$(document).on('keyup', 'input[name=qty]', function(e){
533		checkMinimalQuantity(minimalQuantity);
534	});
535}
536
537function arrayUnique(a)
538{
539	return a.reduce(function(p, c){
540		if (p.indexOf(c) < 0)
541			p.push(c);
542		return p;
543		}, []);
544};
545
546//check if a function exists
547function function_exists(function_name)
548{
549	if (typeof function_name === 'string')
550		function_name = this.window[function_name];
551	return typeof function_name === 'function';
552}
553
554//execute oosHook js code
555function oosHookJsCode()
556{
557	for (var i = 0; i < oosHookJsCodeFunctions.length; i++)
558	{
559		if (function_exists(oosHookJsCodeFunctions[i]))
560			setTimeout(oosHookJsCodeFunctions[i] + '()', 0);
561	}
562}
563
564//add a combination of attributes in the global JS sytem
565function addCombination(idCombination, arrayOfIdAttributes, quantity, price, ecotax, id_image, reference, unit_price, minimal_quantity, available_date, combination_specific_price)
566{
567	globalQuantity += quantity;
568
569	var combination = [];
570	combination['idCombination'] = idCombination;
571	combination['quantity'] = quantity;
572	combination['idsAttributes'] = arrayOfIdAttributes;
573	combination['price'] = price;
574	combination['ecotax'] = ecotax;
575	combination['image'] = id_image;
576	combination['reference'] = reference;
577	combination['unit_price'] = unit_price;
578	combination['minimal_quantity'] = minimal_quantity;
579	combination['available_date'] = [];
580	combination['available_date'] = available_date;
581	combination['specific_price'] = [];
582	combination['specific_price'] = combination_specific_price;
583	combinations.push(combination);
584}
585
586// search the combinations' case of attributes and update displaying of availability, prices, ecotax, and image
587function findCombination()
588{
589	$('#minimal_quantity_wanted_p').fadeOut();
590	if (typeof $('#minimal_quantity_label').text() === 'undefined' || $('#minimal_quantity_label').html() > 1)
591		$('#quantity_wanted').val(1);
592
593	//create a temporary 'choice' array containing the choices of the customer
594	var choice = [];
595	var radio_inputs = parseInt($('#attributes .checked > input[type=radio]').length);
596	if (radio_inputs)
597		radio_inputs = '#attributes .checked > input[type=radio]';
598	else
599		radio_inputs = '#attributes input[type=radio]:checked';
600
601	$('#attributes select, #attributes input[type=hidden], ' + radio_inputs).each(function(){
602		choice.push(parseInt($(this).val()));
603	});
604
605	if (typeof combinations == 'undefined' || !combinations)
606		combinations = [];
607	//testing every combination to find the conbination's attributes' case of the user
608	for (var combination = 0; combination < combinations.length; ++combination)
609	{
610		//verify if this combinaison is the same that the user's choice
611		var combinationMatchForm = true;
612		$.each(combinations[combination]['idsAttributes'], function(key, value)
613			{
614				if (!in_array(parseInt(value), choice))
615					combinationMatchForm = false;
616		});
617
618		if (combinationMatchForm)
619		{
620			if (combinations[combination]['minimal_quantity'] > 1)
621			{
622				$('#minimal_quantity_label').html(combinations[combination]['minimal_quantity']);
623				$('#minimal_quantity_wanted_p').fadeIn();
624				$('#quantity_wanted').val(combinations[combination]['minimal_quantity']);
625				$('#quantity_wanted').bind('keyup', function() {checkMinimalQuantity(combinations[combination]['minimal_quantity']);});
626			}
627			//combination of the user has been found in our specifications of combinations (created in back office)
628			selectedCombination['unavailable'] = false;
629			selectedCombination['reference'] = combinations[combination]['reference'];
630			$('#idCombination').val(combinations[combination]['idCombination']);
631			// natc
632			$('#natc-id_product_attribute').val(combinations[combination]['idCombination']);
633			var elem = $('.natc-variant[data-id_product_attribute=' + combinations[combination]['idCombination'] + ']');
634			$('#quantity_in_stock').html(elem.attr('data-quantity-text'));
635			$('.natc-variant').removeClass('selected');
636			elem.addClass('selected');
637			// sticky button
638			$('#sticky-button-size').html(attributesCombinations [combination]['attribute']);
639
640			//get the data of product with these attributes
641			quantityAvailable = combinations[combination]['quantity'];
642			selectedCombination['price'] = combinations[combination]['price'];
643			selectedCombination['unit_price'] = combinations[combination]['unit_price'];
644			selectedCombination['specific_price'] = combinations[combination]['specific_price'];
645			if (combinations[combination]['ecotax'])
646				selectedCombination['ecotax'] = combinations[combination]['ecotax'];
647			else
648				selectedCombination['ecotax'] = default_eco_tax;
649
650			//show the large image in relation to the selected combination
651			if (combinations[combination]['image'] && combinations[combination]['image'] != -1)
652				displayImage($('#thumb_' + combinations[combination]['image']).parent());
653
654			//show discounts values according to the selected combination
655			if (combinations[combination]['idCombination'] && combinations[combination]['idCombination'] > 0)
656				displayDiscounts(combinations[combination]['idCombination']);
657
658			//get available_date for combination product
659			selectedCombination['available_date'] = combinations[combination]['available_date'];
660
661			//update the display
662			updateDisplay();
663
664			if (firstTime)
665			{
666				refreshProductImages(0);
667				firstTime = false;
668			}
669			else
670				refreshProductImages(combinations[combination]['idCombination']);
671			//leave the function because combination has been found
672			return;
673		}
674	}
675
676	//this combination doesn't exist (not created in back office)
677	selectedCombination['unavailable'] = true;
678	if (typeof(selectedCombination['available_date']) != 'undefined')
679		delete selectedCombination['available_date'];
680
681	updateDisplay();
682}
683
684//update display of the availability of the product AND the prices of the product
685function updateDisplay()
686{
687	var productPriceDisplay = productPrice;
688	var productPriceWithoutReductionDisplay = productPriceWithoutReduction;
689
690	if (!selectedCombination['unavailable'] && quantityAvailable > 0 && productAvailableForOrder == 1)
691	{
692		//show the choice of quantities
693		$('#quantity_wanted_p:hidden').show('slow');
694
695		//show the "add to cart" button ONLY if it was hidden
696		$('#add_to_cart:hidden').fadeIn(600);
697
698		// show natc add to cart button
699		$('#availability:hidden').show();
700		$('#add-to-cart-buttons:hidden').show();
701		$('#quantity_in_stock:hidden').show();
702
703		//hide the hook out of stock
704		$('#oosHook').hide();
705
706		$('#availability_date').fadeOut();
707
708		//availability value management
709		if (stock_management && availableNowValue != '')
710		{
711			$('#availability_value').removeClass('label-warning').addClass('label-success').text(availableNowValue).show();
712			$('#availability_statut:hidden').show('slow');
713		}
714		else
715			$('#availability_statut:visible').hide('slow');
716
717		//'last quantities' message management
718		if (!allowBuyWhenOutOfStock)
719		{
720			// nezobrazuj posledni kus skladem
721			//			if (quantityAvailable <= maxQuantityToAllowDisplayOfLastQuantityMessage)
722			//				$('#last_quantities').show('slow');
723			//			else
724			//				$('#last_quantities').hide('slow');
725		}
726
727		if (quantitiesDisplayAllowed)
728		{
729			$('#pQuantityAvailable:hidden').show('slow');
730			$('#quantityAvailable').text(quantityAvailable);
731
732			if (quantityAvailable < 2) // we have 1 or less product in stock and need to show "item" instead of "items"
733			{
734				$('#quantityAvailableTxt').show();
735				$('#quantityAvailableTxtMultiple').hide();
736			}
737			else
738			{
739				$('#quantityAvailableTxt').hide();
740				$('#quantityAvailableTxtMultiple').show();
741			}
742		}
743	}
744	else
745	{
746		//show the hook out of stock
747		if (productAvailableForOrder == 1)
748		{
749			$('#oosHook').show();
750			if ($('#oosHook').length > 0 && function_exists('oosHookJsCode'))
751				oosHookJsCode();
752		}
753
754		//hide 'last quantities' message if it was previously visible
755		$('#last_quantities:visible').hide('slow');
756
757		//hide the quantity of pieces if it was previously visible
758		$('#pQuantityAvailable:visible').hide('slow');
759
760		// hide natc availability and add to cart button
761		$('#availability:visible').hide();
762		$('#add-to-cart-buttons:visible').hide();
763		$('#quantity_in_stock:visible').hide();
764
765		//hide the choice of quantities
766		if (!allowBuyWhenOutOfStock)
767			$('#quantity_wanted_p:visible').hide('slow');
768
769		//display that the product is unavailable with theses attributes
770		if (!selectedCombination['unavailable'])
771		{
772			$('#availability_value').text(doesntExistNoMore + (globalQuantity > 0 ? ' ' + doesntExistNoMoreBut : ''));
773			if (!allowBuyWhenOutOfStock)
774				$('#availability_value').removeClass('label-success').addClass('label-warning');
775		}
776		else
777		{
778			$('#availability_value').text(doesntExist).removeClass('label-success').addClass('label-warning');
779			$('#oosHook').hide();
780		}
781
782		if ((stock_management == 1 && !allowBuyWhenOutOfStock) || (!stock_management && selectedCombination['unavailable']))
783			$('#availability_statut:hidden').show();
784
785		if (typeof(selectedCombination['available_date']) != 'undefined' && typeof(selectedCombination['available_date']['date_formatted']) != 'undefined' && selectedCombination['available_date']['date'].length != 0)
786		{
787			var available_date = selectedCombination['available_date']['date'];
788			var tab_date = available_date.split('-');
789			var time_available = new Date(tab_date[0], tab_date[1], tab_date[2]);
790			time_available.setMonth(time_available.getMonth()-1);
791			var now = new Date();
792			if (now.getTime() < time_available.getTime() && $('#availability_date_value').text() != selectedCombination['available_date']['date_formatted'])
793			{
794				$('#availability_date').fadeOut('normal', function(){
795					$('#availability_date_value').text(selectedCombination['available_date']['date_formatted']);
796					$(this).fadeIn();
797				});
798			}
799			else if (now.getTime() < time_available.getTime())
800				$('#availability_date').fadeIn();
801		}
802		else
803			$('#availability_date').fadeOut();
804
805		//show the 'add to cart' button ONLY IF it's possible to buy when out of stock AND if it was previously invisible
806		if (allowBuyWhenOutOfStock && !selectedCombination['unavailable'] && productAvailableForOrder)
807		{
808			$('#add_to_cart:hidden').fadeIn(600);
809
810			if (stock_management && availableLaterValue != '')
811			{
812				$('#availability_value').addClass('label-warning').text(availableLaterValue).show('slow');
813				$('#availability_statut:hidden').show('slow');
814			}
815			else
816				$('#availability_statut:visible').hide('slow');
817		}
818		else
819		{
820			$('#add_to_cart:visible').fadeOut(600);
821			if (stock_management == 1 && productAvailableForOrder)
822				$('#availability_statut:hidden').show('slow');
823		}
824
825		if (productAvailableForOrder == 0)
826			$('#availability_statut:visible').hide();
827	}
828
829	if (selectedCombination['reference'] || productReference)
830	{
831		if (selectedCombination['reference'])
832			$('#product_reference span').text(selectedCombination['reference']);
833		else if (productReference)
834			$('#product_reference span').text(productReference);
835		$('#product_reference:hidden').show('slow');
836	}
837	else
838		$('#product_reference:visible').hide('slow');
839
840	// If we have combinations, update price section: amounts, currency, discount amounts,...
841	if (productHasAttributes)
842		updatePrice();
843}
844
845function updatePrice()
846{
847	// Get combination prices
848	var combID = $('#idCombination').val();
849	var combination = combinationsFromController[combID];
850	if (typeof combination == 'undefined')
851		return;
852
853	// Set product (not the combination) base price
854	var basePriceWithoutTax = +productPriceTaxExcluded;
855	var basePriceWithTax = +productPriceTaxIncluded;
856	var priceWithGroupReductionWithoutTax = 0;
857
858	priceWithGroupReductionWithoutTax = basePriceWithoutTax * (1 - groupReduction);
859
860	// Apply combination price impact (only if there is no specific price)
861	// 0 by default, +x if price is inscreased, -x if price is decreased
862	basePriceWithoutTax = basePriceWithoutTax + +combination.price;
863	basePriceWithTax = basePriceWithTax + +combination.price * (taxRate/100 + 1);
864
865	// If a specific price redefine the combination base price
866	if (combination.specific_price && combination.specific_price.price > 0)
867	{
868		basePriceWithoutTax = +combination.specific_price.price;
869		basePriceWithTax = +combination.specific_price.price * (taxRate/100 + 1);
870	}
871
872	var priceWithDiscountsWithoutTax = basePriceWithoutTax;
873	var priceWithDiscountsWithTax = basePriceWithTax;
874
875	if (default_eco_tax)
876	{
877		// combination.ecotax doesn't modify the price but only the display
878		priceWithDiscountsWithoutTax = priceWithDiscountsWithoutTax + default_eco_tax * (1 + ecotaxTax_rate / 100);
879		priceWithDiscountsWithTax = priceWithDiscountsWithTax + default_eco_tax * (1 + ecotaxTax_rate / 100);
880		basePriceWithTax = basePriceWithTax + default_eco_tax * (1 + ecotaxTax_rate / 100);
881		basePriceWithoutTax = basePriceWithoutTax + default_eco_tax * (1 + ecotaxTax_rate / 100);
882	}
883
884	// Apply specific price (discount)
885	// We only apply percentage discount and discount amount given before tax
886	// Specific price give after tax will be handled after taxes are added
887	if (combination.specific_price && combination.specific_price.reduction > 0)
888	{
889		if (combination.specific_price.reduction_type == 'amount')
890		{
891			if (typeof combination.specific_price.reduction_tax !== 'undefined' && combination.specific_price.reduction_tax === "0")
892			{
893				var reduction = combination.specific_price.reduction;
894				if (combination.specific_price.id_currency == 0)
895					reduction = reduction * currencyRate * (1 - groupReduction);
896				priceWithDiscountsWithoutTax -= reduction;
897				priceWithDiscountsWithTax -= reduction * (taxRate/100 + 1);
898			}
899		}
900		else if (combination.specific_price.reduction_type == 'percentage')
901		{
902			priceWithDiscountsWithoutTax = priceWithDiscountsWithoutTax * (1 - +combination.specific_price.reduction);
903			priceWithDiscountsWithTax = priceWithDiscountsWithTax * (1 - +combination.specific_price.reduction);
904		}
905	}
906
907
908	// Apply Tax if necessary
909	if (noTaxForThisProduct || customerGroupWithoutTax)
910	{
911		basePriceDisplay = basePriceWithoutTax;
912		priceWithDiscountsDisplay = priceWithDiscountsWithoutTax;
913	}
914	else
915	{
916		basePriceDisplay = basePriceWithTax;
917		priceWithDiscountsDisplay = priceWithDiscountsWithTax;
918	}
919
920	// If the specific price was given after tax, we apply it now
921	if (combination.specific_price && combination.specific_price.reduction > 0)
922	{
923		if (combination.specific_price.reduction_type == 'amount')
924		{
925			if (typeof combination.specific_price.reduction_tax === 'undefined'
926				|| (typeof combination.specific_price.reduction_tax !== 'undefined' && combination.specific_price.reduction_tax === '1'))
927			{
928				var reduction = combination.specific_price.reduction;
929
930				if (typeof specific_currency !== 'undefined' && specific_currency && parseInt(combination.specific_price.id_currency) && combination.specific_price.id_currency != currency.id)
931					reduction = reduction / currencyRate;
932				else if(!specific_currency)
933					reduction = reduction * currencyRate;
934
935				if (typeof groupReduction !== 'undefined' && groupReduction > 0)
936					reduction *= 1 - parseFloat(groupReduction);
937
938				priceWithDiscountsDisplay -= reduction;
939				// We recalculate the price without tax in order to keep the data consistency
940				priceWithDiscountsWithoutTax = priceWithDiscountsDisplay - reduction * ( 1/(1+taxRate/100) );
941			}
942		}
943	}
944
945	// Compute discount value and percentage
946	// Done just before display update so we have final prices
947	if (basePriceDisplay != priceWithDiscountsDisplay)
948	{
949		var discountValue = basePriceDisplay - priceWithDiscountsDisplay;
950		var discountPercentage = (1-(priceWithDiscountsDisplay/basePriceDisplay))*100;
951	}
952
953	var unit_impact = +combination.unit_impact;
954	if (productUnitPriceRatio > 0 || unit_impact)
955	{
956		if (unit_impact)
957		{
958			baseUnitPrice = productBasePriceTaxExcl / productUnitPriceRatio;
959			unit_price = baseUnitPrice + unit_impact;
960
961			if (!noTaxForThisProduct || !customerGroupWithoutTax)
962				unit_price = unit_price * (taxRate/100 + 1);
963		}
964		else
965			unit_price = priceWithDiscountsDisplay / productUnitPriceRatio;
966	}
967
968	/*  Update the page content, no price calculation happens after */
969
970	// Hide everything then show what needs to be shown
971	$('#reduction_percent').hide();
972	$('#reduction_amount').hide();
973	$('#old_price, #old_price_display, #old_price_display_taxes').hide();
974	$('.price-ecotax').hide();
975	$('.unit-price').hide();
976
977	$('#our_price_display').text(formatCurrency(priceWithDiscountsDisplay, currencyFormat, currencySign, currencyBlank)).trigger('change');
978
979	// If the calculated price (after all discounts) is different than the base price
980	// we show the old price striked through
981
982	if (priceWithDiscountsDisplay.toFixed(2) != basePriceDisplay.toFixed(2))
983	{
984		$('#old_price_display span.price').text(formatCurrency(basePriceDisplay, currencyFormat, currencySign, currencyBlank));
985		$('#old_price, #old_price_display, #old_price_display_taxes').removeClass('hidden').show();
986
987		// Then if it's not only a group reduction we display the discount in red box
988		if (priceWithDiscountsWithoutTax != priceWithGroupReductionWithoutTax)
989		{
990			if (combination.specific_price.reduction_type == 'amount')
991			{
992				$('#reduction_amount_display').html('-' + formatCurrency(discountValue, currencyFormat, currencySign, currencyBlank));
993				$('#reduction_amount').show();
994			}
995			else
996			{
997				var toFix = 2;
998				if ((parseFloat(discountPercentage).toFixed(2) - parseFloat(discountPercentage).toFixed(0)) == 0)
999					toFix = 0;
1000				$('#reduction_percent_display').html('-' + parseFloat(discountPercentage).toFixed(toFix) + '%');
1001				$('#reduction_percent').show();
1002			}
1003		}
1004	}
1005
1006	// Green Tax (Eco tax)
1007	// Update display of Green Tax
1008	if (default_eco_tax)
1009	{
1010		ecotax = default_eco_tax;
1011
1012		// If the default product ecotax is overridden by the combination
1013		if (combination.ecotax)
1014			ecotax = +combination.ecotax;
1015
1016		if (!noTaxForThisProduct)
1017			ecotax = ecotax * (1 + ecotaxTax_rate/100)
1018
1019		$('#ecotax_price_display').text(formatCurrency(ecotax * currencyRate, currencyFormat, currencySign, currencyBlank));
1020		$('.price-ecotax').show();
1021	}
1022
1023	// Unit price are the price per piece, per Kg, per m²
1024	// It doesn't modify the price, it's only for display
1025	if (productUnitPriceRatio > 0)
1026	{
1027		$('#unit_price_display').text(formatCurrency(unit_price * currencyRate, currencyFormat, currencySign, currencyBlank));
1028		$('.unit-price').show();
1029	}
1030
1031	if (noTaxForThisProduct || customerGroupWithoutTax)
1032		updateDiscountTable(productBasePriceTaxExcl);
1033	else
1034		updateDiscountTable(productBasePriceTaxIncl);
1035}
1036
1037//update display of the large image
1038function displayImage(domAAroundImgThumb, no_animation)
1039{
1040	if (typeof(no_animation) == 'undefined')
1041		no_animation = false;
1042	if (domAAroundImgThumb.attr('href'))
1043	{
1044		var new_src = domAAroundImgThumb.attr('href').replace('thickbox', 'large');
1045		var new_title = domAAroundImgThumb.attr('title');
1046		var new_href = domAAroundImgThumb.attr('href');
1047		if ($('#bigpic').attr('src') != new_src)
1048		{
1049			$('#bigpic').attr({
1050				'src' : new_src,
1051				'alt' : new_title,
1052				'title' : new_title
1053			}).load(function(){
1054				if (typeof(jqZoomEnabled) != 'undefined' && jqZoomEnabled)
1055					$(this).attr('rel', new_href);
1056			});
1057		}
1058		$('#views_block li a').removeClass('shown');
1059		$(domAAroundImgThumb).addClass('shown');
1060	}
1061}
1062
1063/**
1064* Update display of the discounts table.
1065* @param combination Combination ID.
1066*/
1067function displayDiscounts(combination)
1068{
1069	// Tables & rows selection
1070	var quantityDiscountTable = $('#quantityDiscount');
1071	var combinationsSpecificQuantityDiscount = $('#quantityDiscount_'+combination, quantityDiscountTable);
1072	var allQuantityDiscount = $('#quantityDiscount_0', quantityDiscountTable);
1073
1074	// If there is some combinations specific quantity discount, show them, else, if there are some
1075	// products quantity discount: show them. In case of result, show the category.
1076	if (combinationsSpecificQuantityDiscount.length != 0)
1077	{
1078		combinationsSpecificQuantityDiscount.show();
1079		allQuantityDiscount.hide();
1080		quantityDiscountTable.show();
1081	}
1082	else if(allQuantityDiscount.length != 0)
1083	{
1084		allQuantityDiscount.show();
1085		$('tbody tr', quantityDiscountTable).not('#quantityDiscount_0').hide();
1086		quantityDiscountTable.show();
1087	}
1088	else
1089	{
1090		quantityDiscountTable.hide();
1091	}
1092}
1093
1094function updateDiscountTable(newPrice)
1095{
1096	$('#quantityDiscount tbody tr').each(function(){
1097		var type = $(this).data("discount-type");
1098		var discount = $(this).data("discount");
1099		var quantity = $(this).data("discount-quantity");
1100
1101		if (type == 'percentage')
1102		{
1103			var discountedPrice = newPrice * (1 - discount/100);
1104			var discountUpTo = newPrice * (discount/100) * quantity;
1105		}
1106		else if (type == 'amount')
1107		{
1108			var discountedPrice = newPrice - discount;
1109			var discountUpTo = discount * quantity;
1110		}
1111
1112		if (displayDiscountPrice != 0)
1113			$(this).children('td').eq(1).text( formatCurrency(discountedPrice * currencyRate, currencyFormat, currencySign, currencyBlank) );
1114		$(this).children('td').eq(2).text(upToTxt + ' ' + formatCurrency(discountUpTo * currencyRate, currencyFormat, currencySign, currencyBlank));
1115	});
1116}
1117
1118function serialScrollFixLock(event, targeted, scrolled, items, position)
1119{
1120	var serialScrollNbImages = $('#thumbs_list li:visible').length;
1121	var leftArrow = position == 0 ? true : false;
1122	var rightArrow = position + serialScrollNbImagesDisplayed >= serialScrollNbImages ? true : false;
1123
1124	$('#view_scroll_left').css('cursor', leftArrow ? 'default' : 'pointer').css('display', leftArrow ? 'none' : 'block').fadeTo(0, leftArrow ? 0 : 1);
1125	$('#view_scroll_right').css('cursor', rightArrow ? 'default' : 'pointer').fadeTo(0, rightArrow ? 0 : 1).css('display', rightArrow ? 'none' : 'block');
1126	return true;
1127}
1128
1129function serialScrollSetNbImages()
1130{
1131	serialScrollNbImagesDisplayed = 4;
1132	if ($('#thumbs_list').outerWidth(true) < 194)
1133		serialScrollNbImagesDisplayed = 1;
1134	else if ($('#thumbs_list').outerWidth(true) < 294)
1135		serialScrollNbImagesDisplayed = 2;
1136		else if ($('#thumbs_list').outerWidth(true) < 392)
1137			serialScrollNbImagesDisplayed = 3;
1138}
1139
1140
1141// Change the current product images regarding the combination selected
1142function refreshProductImages(id_product_attribute)
1143{
1144	id_product_attribute = parseInt(id_product_attribute);
1145
1146	if (id_product_attribute > 0 && typeof(combinationImages) != 'undefined' && typeof(combinationImages[id_product_attribute]) != 'undefined')
1147	{
1148		$('#thumbs_list li').hide();
1149		for (var i = 0; i < combinationImages[id_product_attribute].length; i++)
1150			if (typeof(jqZoomEnabled) != 'undefined' && jqZoomEnabled)
1151				$('#thumbnail_' + parseInt(combinationImages[id_product_attribute][i])).show().children('a.shown').trigger('click');
1152			else
1153				$('#thumbnail_' + parseInt(combinationImages[id_product_attribute][i])).show();
1154	}
1155	else
1156	{
1157		$('#thumbs_list li').show();
1158
1159		var choice = [];
1160		var radio_inputs = parseInt($('#attributes .checked > input[type=radio]').length);
1161		if (radio_inputs)
1162			radio_inputs = '#attributes .checked > input[type=radio]';
1163		else
1164			radio_inputs = '#attributes input[type=radio]:checked';
1165
1166		$('#attributes select, #attributes input[type=hidden], ' + radio_inputs).each(function(){
1167			choice.push(parseInt($(this).val()));
1168		});
1169
1170		if (typeof combinations == 'undefined' || !combinations)
1171			combinations = [];
1172
1173		//testing every combination to find the conbination's attributes' case of the user
1174		for (var combination = 0; combination < combinations.length; ++combination)
1175		{
1176			//verify if this combinaison is the same that the user's choice
1177			var combinationMatchForm = true;
1178
1179			$.each(combinations[combination]['idsAttributes'], function(key, value)
1180				{
1181					if (!in_array(parseInt(value), choice))
1182						combinationMatchForm = false;
1183			});
1184
1185			if (combinationMatchForm)
1186			{
1187				//show the large image in relation to the selected combination
1188				if (combinations[combination]['image'] && combinations[combination]['image'] != -1)
1189					displayImage($('#thumb_' + combinations[combination]['image']).parent());
1190			}
1191		}
1192	}
1193
1194	if (parseInt($('#thumbs_list_frame >li:visible').length) != parseInt($('#thumbs_list_frame >li').length))
1195		$('#wrapResetImages').stop(true, true).show();
1196	else
1197		$('#wrapResetImages').stop(true, true).hide();
1198
1199	$('#thumbs_list_frame').width(parseInt($('#thumbs_list_frame >li').outerWidth(true) * $('#thumbs_list_frame >li').length) + 'px');
1200	$('#thumbs_list').trigger('goto', 0);
1201	serialScrollFixLock('', '', '', '', 0);
1202}
1203
1204function saveCustomization()
1205{
1206	$('#quantityBackup').val($('#quantity_wanted').val());
1207	$('#customizationForm').submit();
1208}
1209
1210function submitPublishProduct(url, redirect, token)
1211{
1212	var id_product = $('#admin-action-product-id').val();
1213
1214	$.ajaxSetup({async: false});
1215	$.post(url + '/index.php', {
1216		action:'publishProduct',
1217		id_product: id_product,
1218		status: 1,
1219		redirect: redirect,
1220		ajax: 1,
1221		tab: 'AdminProducts',
1222		token: token
1223		},
1224		function(data)
1225		{
1226			if (data.indexOf('error') === -1)
1227				document.location.href = data;
1228		}
1229	);
1230	return true;
1231}
1232
1233function checkMinimalQuantity(minimal_quantity)
1234{
1235	if ($('#quantity_wanted').val() < minimal_quantity)
1236	{
1237		$('#quantity_wanted').css('border', '1px solid red');
1238		$('#minimal_quantity_wanted_p').css('color', 'red');
1239	}
1240	else
1241	{
1242		$('#quantity_wanted').css('border', '1px solid #BDC2C9');
1243		$('#minimal_quantity_wanted_p').css('color', '#374853');
1244	}
1245}
1246
1247function colorPickerClick(elt)
1248{
1249	id_attribute = $(elt).attr('id').replace('color_', '');
1250	$(elt).parent().parent().children().removeClass('selected');
1251	$(elt).fadeTo('fast', 1, function(){
1252		$(this).fadeTo('fast', 0, function(){
1253			$(this).fadeTo('fast', 1, function(){
1254				$(this).parent().addClass('selected');
1255			});
1256		});
1257	});
1258	$(elt).parent().parent().parent().children('.color_pick_hidden').val(id_attribute);
1259}
1260
1261
1262function getProductAttribute()
1263{
1264	// get every attributes values
1265	request = '';
1266	//create a temporary 'tab_attributes' array containing the choices of the customer
1267	var tab_attributes = [];
1268	var radio_inputs = parseInt($('#attributes .checked > input[type=radio]').length);
1269	if (radio_inputs)
1270		radio_inputs = '#attributes .checked > input[type=radio]';
1271	else
1272		radio_inputs = '#attributes input[type=radio]:checked';
1273
1274	$('#attributes select, #attributes input[type=hidden], ' + radio_inputs).each(function(){
1275		tab_attributes.push($(this).val());
1276	});
1277
1278	// build new request
1279	for (var i in attributesCombinations)
1280		for (var a in tab_attributes)
1281			if (attributesCombinations[i]['id_attribute'] === tab_attributes[a])
1282		request += '/' + attributesCombinations[i]['id_attribute'] + '-' + attributesCombinations[i]['group'] + attribute_anchor_separator + attributesCombinations[i]['attribute'];
1283	request = request.replace(request.substring(0, 1), '#/');
1284	var url = window.location + '';
1285
1286	// redirection
1287	if (url.indexOf('#') != -1)
1288		url = url.substring(0, url.indexOf('#'));
1289
1290	if ($('#customizationForm').length)
1291	{
1292		// set ipa to the customization form
1293		customAction = $('#customizationForm').attr('action');
1294		if (customAction.indexOf('#') != -1)
1295			customAction = customAction.substring(0, customAction.indexOf('#'));
1296		$('#customizationForm').attr('action', customAction + request);
1297	}
1298
1299	window.location.replace(url + request);
1300}
1301
1302function checkUrl()
1303{
1304	if (original_url != window.location || first_url_check)
1305	{
1306		first_url_check = false;
1307		var url = window.location + '';
1308		// if we need to load a specific combination
1309		if (url.indexOf('#/') != -1)
1310		{
1311			// get the params to fill from a "normal" url
1312			params = url.substring(url.indexOf('#') + 1, url.length);
1313			tabParams = params.split('/');
1314			tabValues = [];
1315			if (tabParams[0] == '')
1316				tabParams.shift();
1317
1318			var len = tabParams.length;
1319			for (var i=0; i<len; i++)
1320				tabValues.push(tabParams[i].split(attribute_anchor_separator));
1321
1322			// fill html with values
1323			$('.color_pick').removeClass('selected').parent().parent().children().removeClass('selected');
1324
1325			count = 0;
1326			for (var z in tabValues)
1327				for (var a in attributesCombinations)
1328					if (attributesCombinations[a]['group'] === decodeURIComponent(tabValues[z][1])
1329						&& attributesCombinations[a]['id_attribute'] === decodeURIComponent(tabValues[z][0]))
1330					{
1331						count++;
1332
1333						// add class 'selected' to the selected color
1334						$('#color_' + attributesCombinations[a]['id_attribute']).addClass('selected').parent().addClass('selected');
1335						$('input:radio[value=' + attributesCombinations[a]['id_attribute'] + ']').prop('checked', true);
1336						$('input[type=hidden][name=group_' + attributesCombinations[a]['id_attribute_group'] + ']').val(attributesCombinations[a]['id_attribute']);
1337						$('select[name=group_' + attributesCombinations[a]['id_attribute_group'] + ']').val(attributesCombinations[a]['id_attribute']);
1338						if (!!$.prototype.uniform)
1339							$.uniform.update('input[name=group_' + attributesCombinations[a]['id_attribute_group'] + '], select[name=group_' + attributesCombinations[a]['id_attribute_group'] + ']');
1340
1341			}
1342			// find combination and select corresponding thumbs
1343			if (count)
1344			{
1345				if (firstTime)
1346				{
1347					firstTime = false;
1348					findCombination();
1349				}
1350				original_url = url;
1351				return true;
1352			}
1353			// no combination found = removing attributes from url
1354			else
1355				window.location.replace(url.substring(0, url.indexOf('#')));
1356		}
1357	}
1358	return false;
1359}
1360
1361class ReSimpleSlider {
1362	constructor(selector) {
1363		this.$container = $(selector);
1364		this.$list = this.$container.find('ul, ol').first();
1365		this.$items = this.$list.children();
1366
1367		// Konstanty
1368		this.ITEM_WIDTH = 40;
1369		this.ITEM_MARGIN = 10;
1370		this.ITEM_TOTAL_WIDTH = this.ITEM_WIDTH + this.ITEM_MARGIN;
1371
1372		// Stavové proměnné
1373		this.current_position = 0;
1374		this.visible_items = 0;
1375		this.max_position = 0;
1376
1377		// Inicializace
1378		this.initialSetup();
1379		this.recalculate();
1380		this.bindResize();
1381	}
1382
1383	initialSetup() {
1384		this.$list.wrap('<div class="re_slider-viewport"></div>');
1385		this.$viewport = this.$container.find('.re_slider-viewport');
1386		this.$viewport.css({
1387			'overflow': 'hidden',
1388			'position': 'relative'
1389		});
1390
1391		this.$list.css({
1392			'position': 'relative',
1393			'transition': 'left 0.3s ease'
1394		});
1395
1396		this.$viewport.before('<span class="re_slider-prev"></span>');
1397		this.$viewport.after('<span class="re_slider-next"></span>');
1398
1399		this.$prev_btn = this.$container.find('.re_slider-prev');
1400		this.$next_btn = this.$container.find('.re_slider-next');
1401
1402		this.$prev_btn.on('click', () => this.prev());
1403		this.$next_btn.on('click', () => this.next());
1404	}
1405
1406	recalculate() {
1407		const container_width = this.$container.width();
1408		this.visible_items = Math.floor(container_width / this.ITEM_TOTAL_WIDTH);
1409		const slider_width = this.visible_items * this.ITEM_TOTAL_WIDTH - this.ITEM_MARGIN;
1410
1411		this.$viewport.css('width', slider_width + 'px');
1412		this.$list.css('width', (this.$items.length * this.ITEM_TOTAL_WIDTH) + 'px');
1413
1414		this.max_position = Math.max(0, this.$items.length - this.visible_items);
1415
1416		if (this.current_position > this.max_position) {
1417			this.current_position = this.max_position;
1418		}
1419
1420		this.updatePosition();
1421	}
1422
1423	updatePosition() {
1424		this.$list.css('left', -(this.current_position * this.ITEM_TOTAL_WIDTH) + 'px');
1425		this.updateArrows();
1426	}
1427
1428	updateArrows() {
1429		if (this.current_position > 0) {
1430			this.$prev_btn.css('display', 'inline-block');
1431		} else {
1432			this.$prev_btn.css('display', 'none');
1433		}
1434
1435		if (this.current_position < this.max_position) {
1436			this.$next_btn.css('display', 'inline-block');
1437		} else {
1438			this.$next_btn.css('display', 'none');
1439		}
1440	}
1441
1442	prev() {
1443		if (this.current_position > 0) {
1444			this.current_position--;
1445			this.updatePosition();
1446		}
1447	}
1448
1449	next() {
1450		if (this.current_position < this.max_position) {
1451			this.current_position++;
1452			this.updatePosition();
1453		}
1454	}
1455
1456	bindResize() {
1457		let resize_timer;
1458		$(window).on('resize', () => {
1459			clearTimeout(resize_timer);
1460			resize_timer = setTimeout(() => {
1461				this.recalculate();
1462			}, 100);
1463		});
1464	}
1465
1466	// Scrolluj na konkrétní prvek (index od 1)
1467	goToPosition(item_index) {
1468
1469		const index = item_index - 1;
1470
1471		if (index < 0 || index >= this.$items.length) {
1472			console.warn('Item index out of range');
1473			return;
1474		}
1475
1476		const first_visible = this.current_position;
1477		const last_visible = this.current_position + this.visible_items - 1;
1478
1479		if (index >= first_visible && index <= last_visible) {
1480			return;
1481		}
1482
1483		if (index < first_visible) {
1484			this.current_position = index;
1485		} else if (index > last_visible) {
1486			this.current_position = Math.min(index - this.visible_items + 1, this.max_position);
1487		}
1488
1489		this.updatePosition();
1490	}
1491
1492	destroy() {
1493		this.$prev_btn.off('click');
1494		this.$next_btn.off('click');
1495		this.$prev_btn.remove();
1496		this.$next_btn.remove();
1497		this.$list.unwrap();
1498		this.$list.css({
1499			'position': '',
1500			'transition': '',
1501			'left': '',
1502			'width': ''
1503		});
1504	}
1505}
1506
1507$(document).ready(function () {
1508	sticky_button_slider = new ReSimpleSlider('.sticky-button-size-slider');
1509});

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.