PageSourceSearch

https://aqua-floor.com/local/templates/aquafloor/components/bitrix/catalog.item/card_square/script.js

js aqua-floor.com collected 2026-10-07 18:02:51 UTC 56,809 bytes, 2,334 lines download raw bytes

1(function (window){
2	'use strict';
3
4	if (window.JCCatalogItem)
5		return;
6
7	var BasketButton = function(params)
8	{
9		BasketButton.superclass.constructor.apply(this, arguments);
10		this.buttonNode = BX.create('button', {
11			props: {className: 'btn btn-primary btn-buy btn-sm', id: this.id},
12			style: typeof params.style === 'object' ? params.style : {},
13			text: params.text,
14			events: this.contextEvents
15		});
16
17		if (BX.browser.IsIE())
18		{
19			this.buttonNode.setAttribute("hideFocus", "hidefocus");
20		}
21	};
22	BX.extend(BasketButton, BX.PopupWindowButton);
23
24	window.JCCatalogItem = function (arParams)
25	{
26		this.productType = 0;
27		this.showQuantity = true;
28		this.showAbsent = true;
29		this.secondPict = false;
30		this.showOldPrice = false;
31		this.showMaxQuantity = 'N';
32		this.relativeQuantityFactor = 5;
33		this.showPercent = false;
34		this.showSkuProps = false;
35		this.basketAction = 'ADD';
36		this.showClosePopup = false;
37		this.useCompare = false;
38		this.showSubscription = false;
39		this.visual = {
40			ID: '',
41			PICT_ID: '',
42			SECOND_PICT_ID: '',
43			QUANTITY_ID: '',
44			QUANTITY_UP_ID: '',
45			QUANTITY_DOWN_ID: '',
46			PRICE_ID: '',
47			PRICE_OLD_ID: '',
48			DSC_PERC: '',
49			SECOND_DSC_PERC: '',
50			DISPLAY_PROP_DIV: '',
51			BASKET_PROP_DIV: '',
52			SUBSCRIBE_ID: ''
53		};
54		this.product = {
55			checkQuantity: false,
56			maxQuantity: 0,
57			stepQuantity: 1,
58			isDblQuantity: false,
59			canBuy: true,
60			name: '',
61			pict: {},
62			id: 0,
63			addUrl: '',
64			buyUrl: ''
65		};
66
67		this.basketMode = '';
68		this.basketData = {
69			useProps: false,
70			emptyProps: false,
71			quantity: 'quantity',
72			props: 'prop',
73			basketUrl: '',
74			sku_props: '',
75			sku_props_var: 'basket_props',
76			add_url: '',
77			buy_url: ''
78		};
79
80		this.compareData = {
81			compareUrl: '',
82			compareDeleteUrl: '',
83			comparePath: ''
84		};
85
86		this.defaultPict = {
87			pict: null,
88			secondPict: null
89		};
90		this.touch = null;
91
92		this.quantityDelay = null;
93		this.quantityTimer = null;
94
95		this.checkQuantity = false;
96		this.maxQuantity = 0;
97		this.minQuantity = 0;
98		this.stepQuantity = 1;
99		this.isDblQuantity = false;
100		this.canBuy = true;
101		this.precision = 6;
102		this.precisionFactor = Math.pow(10, this.precision);
103		this.bigData = false;
104		this.fullDisplayMode = false;
105		this.viewMode = '';
106		this.templateTheme = '';
107
108		this.currentPriceMode = '';
109		this.currentPrices = [];
110		this.currentPriceSelected = 0;
111		this.currentQuantityRanges = [];
112		this.currentQuantityRangeSelected = 0;
113
114		this.offers = [];
115		this.offerNum = 0;
116		this.treeProps = [];
117		this.selectedValues = {};
118
119		this.obProduct = null;
120		this.blockNodes = {};
121		this.obQuantity = null;
122		this.obQuantityUp = null;
123		this.obQuantityDown = null;
124		this.obQuantityLimit = {};
125		this.obPict = null;
126		this.obSecondPict = null;
127		this.obPrice = null;
128		this.obTree = null;
129		this.obBuyBtn = null;
130		this.obBasketActions = null;
131		this.obNotAvail = null;
132		this.obSubscribe = null;
133		this.obDscPerc = null;
134		this.obSecondDscPerc = null;
135		this.obSkuProps = null;
136		this.obMeasure = null;
137		this.obCompare = null;
138
139		this.obPopupWin = null;
140		this.basketUrl = '';
141		this.basketParams = {};
142		this.isTouchDevice = BX.hasClass(document.documentElement, 'bx-touch');
143		this.hoverTimer = null;
144		this.hoverStateChangeForbidden = false;
145		this.mouseX = null;
146		this.mouseY = null;
147
148		this.useEnhancedEcommerce = false;
149		this.dataLayerName = 'dataLayer';
150		this.brandProperty = false;
151
152		this.errorCode = 0;
153
154		if (typeof arParams === 'object')
155		{
156			if (arParams.PRODUCT_TYPE)
157			{
158				this.productType = parseInt(arParams.PRODUCT_TYPE, 10);
159			}
160
161			this.showQuantity = arParams.SHOW_QUANTITY;
162			this.showAbsent = arParams.SHOW_ABSENT;
163			this.secondPict = arParams.SECOND_PICT;
164			this.showOldPrice = arParams.SHOW_OLD_PRICE;
165			this.showMaxQuantity = arParams.SHOW_MAX_QUANTITY;
166			this.relativeQuantityFactor = parseInt(arParams.RELATIVE_QUANTITY_FACTOR);
167			this.showPercent = arParams.SHOW_DISCOUNT_PERCENT;
168			this.showSkuProps = arParams.SHOW_SKU_PROPS;
169			this.showSubscription = arParams.USE_SUBSCRIBE;
170
171			if (arParams.ADD_TO_BASKET_ACTION)
172			{
173				this.basketAction = arParams.ADD_TO_BASKET_ACTION;
174			}
175
176			this.showClosePopup = arParams.SHOW_CLOSE_POPUP;
177			this.useCompare = arParams.DISPLAY_COMPARE;
178			this.fullDisplayMode = arParams.PRODUCT_DISPLAY_MODE === 'Y';
179			this.bigData = arParams.BIG_DATA;
180			this.viewMode = arParams.VIEW_MODE || '';
181			this.templateTheme = arParams.TEMPLATE_THEME || '';
182			this.useEnhancedEcommerce = arParams.USE_ENHANCED_ECOMMERCE === 'Y';
183			this.dataLayerName = arParams.DATA_LAYER_NAME;
184			this.brandProperty = arParams.BRAND_PROPERTY;
185
186			this.visual = arParams.VISUAL;
187
188			switch (this.productType)
189			{
190				case 0: // no catalog
191				case 1: // product
192				case 2: // set
193					if (arParams.PRODUCT && typeof arParams.PRODUCT === 'object')
194					{
195						this.currentPriceMode = arParams.PRODUCT.ITEM_PRICE_MODE;
196						this.currentPrices = arParams.PRODUCT.ITEM_PRICES;
197						this.currentPriceSelected = arParams.PRODUCT.ITEM_PRICE_SELECTED;
198						this.currentQuantityRanges = arParams.PRODUCT.ITEM_QUANTITY_RANGES;
199						this.currentQuantityRangeSelected = arParams.PRODUCT.ITEM_QUANTITY_RANGE_SELECTED;
200
201						if (this.showQuantity)
202						{
203							this.product.checkQuantity = arParams.PRODUCT.CHECK_QUANTITY;
204							this.product.isDblQuantity = arParams.PRODUCT.QUANTITY_FLOAT;
205
206							if (this.product.checkQuantity)
207							{
208								this.product.maxQuantity = (this.product.isDblQuantity ? parseFloat(arParams.PRODUCT.MAX_QUANTITY) : parseInt(arParams.PRODUCT.MAX_QUANTITY, 10));
209							}
210
211							this.product.stepQuantity = (this.product.isDblQuantity ? parseFloat(arParams.PRODUCT.STEP_QUANTITY) : parseInt(arParams.PRODUCT.STEP_QUANTITY, 10));
212
213							this.checkQuantity = this.product.checkQuantity;
214							this.isDblQuantity = this.product.isDblQuantity;
215							this.stepQuantity = this.product.stepQuantity;
216							this.maxQuantity = this.product.maxQuantity;
217							this.minQuantity = this.currentPriceMode === 'Q'
218								? parseFloat(this.currentPrices[this.currentPriceSelected].MIN_QUANTITY)
219								: this.stepQuantity;
220
221							if (this.isDblQuantity)
222							{
223								this.stepQuantity = Math.round(this.stepQuantity * this.precisionFactor) / this.precisionFactor;
224							}
225						}
226
227						this.product.canBuy = arParams.PRODUCT.CAN_BUY;
228
229						if (arParams.PRODUCT.MORE_PHOTO_COUNT)
230						{
231							this.product.morePhotoCount = arParams.PRODUCT.MORE_PHOTO_COUNT;
232							this.product.morePhoto = arParams.PRODUCT.MORE_PHOTO;
233						}
234
235						if (arParams.PRODUCT.RCM_ID)
236						{
237							this.product.rcmId = arParams.PRODUCT.RCM_ID;
238						}
239
240						this.canBuy = this.product.canBuy;
241						this.product.name = arParams.PRODUCT.NAME;
242						this.product.pict = arParams.PRODUCT.PICT;
243						this.product.id = arParams.PRODUCT.ID;
244						this.product.DETAIL_PAGE_URL = arParams.PRODUCT.DETAIL_PAGE_URL;
245
246						if (arParams.PRODUCT.ADD_URL)
247						{
248							this.product.addUrl = arParams.PRODUCT.ADD_URL;
249						}
250
251						if (arParams.PRODUCT.BUY_URL)
252						{
253							this.product.buyUrl = arParams.PRODUCT.BUY_URL;
254						}
255
256						if (arParams.BASKET && typeof arParams.BASKET === 'object')
257						{
258							this.basketData.useProps = arParams.BASKET.ADD_PROPS;
259							this.basketData.emptyProps = arParams.BASKET.EMPTY_PROPS;
260						}
261					}
262					else
263					{
264						this.errorCode = -1;
265					}
266
267					break;
268				case 3: // sku
269					if (arParams.PRODUCT && typeof arParams.PRODUCT === 'object')
270					{
271						this.product.name = arParams.PRODUCT.NAME;
272						this.product.id = arParams.PRODUCT.ID;
273						this.product.DETAIL_PAGE_URL = arParams.PRODUCT.DETAIL_PAGE_URL;
274						this.product.morePhotoCount = arParams.PRODUCT.MORE_PHOTO_COUNT;
275						this.product.morePhoto = arParams.PRODUCT.MORE_PHOTO;
276
277						if (arParams.PRODUCT.RCM_ID)
278						{
279							this.product.rcmId = arParams.PRODUCT.RCM_ID;
280						}
281					}
282
283					if (arParams.OFFERS && BX.type.isArray(arParams.OFFERS))
284					{
285						this.offers = arParams.OFFERS;
286						this.offerNum = 0;
287
288						if (arParams.OFFER_SELECTED)
289						{
290							this.offerNum = parseInt(arParams.OFFER_SELECTED, 10);
291						}
292
293						if (isNaN(this.offerNum))
294						{
295							this.offerNum = 0;
296						}
297
298						if (arParams.TREE_PROPS)
299						{
300							this.treeProps = arParams.TREE_PROPS;
301						}
302
303						if (arParams.DEFAULT_PICTURE)
304						{
305							this.defaultPict.pict = arParams.DEFAULT_PICTURE.PICTURE;
306							this.defaultPict.secondPict = arParams.DEFAULT_PICTURE.PICTURE_SECOND;
307						}
308					}
309
310					break;
311				default:
312					this.errorCode = -1;
313			}
314			if (arParams.BASKET && typeof arParams.BASKET === 'object')
315			{
316				if (arParams.BASKET.QUANTITY)
317				{
318					this.basketData.quantity = arParams.BASKET.QUANTITY;
319				}
320
321				if (arParams.BASKET.PROPS)
322				{
323					this.basketData.props = arParams.BASKET.PROPS;
324				}
325
326				if (arParams.BASKET.BASKET_URL)
327				{
328					this.basketData.basketUrl = arParams.BASKET.BASKET_URL;
329				}
330
331				if (3 === this.productType)
332				{
333					if (arParams.BASKET.SKU_PROPS)
334					{
335						this.basketData.sku_props = arParams.BASKET.SKU_PROPS;
336					}
337				}
338
339				if (arParams.BASKET.ADD_URL_TEMPLATE)
340				{
341					this.basketData.add_url = arParams.BASKET.ADD_URL_TEMPLATE;
342				}
343
344				if (arParams.BASKET.BUY_URL_TEMPLATE)
345				{
346					this.basketData.buy_url = arParams.BASKET.BUY_URL_TEMPLATE;
347				}
348
349				if (this.basketData.add_url === '' && this.basketData.buy_url === '')
350				{
351					this.errorCode = -1024;
352				}
353			}
354
355			if (this.useCompare)
356			{
357				if (arParams.COMPARE && typeof arParams.COMPARE === 'object')
358				{
359					if (arParams.COMPARE.COMPARE_PATH)
360					{
361						this.compareData.comparePath = arParams.COMPARE.COMPARE_PATH;
362					}
363
364					if (arParams.COMPARE.COMPARE_URL_TEMPLATE)
365					{
366						this.compareData.compareUrl = arParams.COMPARE.COMPARE_URL_TEMPLATE;
367					}
368					else
369					{
370						this.useCompare = false;
371					}
372
373					if (arParams.COMPARE.COMPARE_DELETE_URL_TEMPLATE)
374					{
375						this.compareData.compareDeleteUrl = arParams.COMPARE.COMPARE_DELETE_URL_TEMPLATE;
376					}
377					else
378					{
379						this.useCompare = false;
380					}
381				}
382				else
383				{
384					this.useCompare = false;
385				}
386			}
387
388			this.isFacebookConversionCustomizeProductEventEnabled
389				= arParams.IS_FACEBOOK_CONVERSION_CUSTOMIZE_PRODUCT_EVENT_ENABLED
390			;
391		}
392
393		if (this.errorCode === 0)
394		{
395			BX.ready(BX.delegate(this.init,this));
396		}
397	};
398
399	BX.ready(function()
400	{
401		$(document).on('click.overlay-open', '.js-zoom-overlay', function clickHandler(e)
402		{
403			e.preventDefault();
404
405			let $it = $(this);
406			let $productCard = $it.closest('.product');
407			let $popup = $it.attr('href');
408			let objVar = $it.data('obj-varname');
409			if ('undefined' === typeof window[objVar])
410				return;
411
412			let obj = window[objVar];
413
414			let $productName = $('.js-zoom-product_name', $popup);
415			let $price = $('.product__price .new-price', $popup);
416			let $priceOld = $('.product__price .old-price', $popup);
417			let $buttons = $('.js-zoom-buttons', $popup);
418			let $advantages = $('.js-zoom-product_advantages', $popup);
419			let $pictureSlider = $('.js-zoom-slider', $popup);
420			let $pictureSliderControls = $('.js-zoom-slider-controls', $popup);
421
422			$productName.attr('href', '#');
423
424			$.overlayLoader(true, {
425				node: $popup,
426				hideSelector: '.js-close-popup',
427				fixedElements: '.js-fixed-element',
428				onShow(node)
429				{
430					let $productNameSrc = $productCard.find('.product__name');
431					if ($productNameSrc.length > 0)
432					{
433						$productName.text($productNameSrc.text());
434						if (String($productNameSrc.attr('href')).length > 0)
435							$productName.attr('href', $productNameSrc.attr('href'));
436					}
437
438					$advantages.html($productCard.find('.product__advantages').html());
439					$price.html($productCard.find('.product__price .new-price').html());
440					$priceOld
441						.html($productCard.find('.product__price .old-price').html())
442						.toggle($productCard.find('.product__price .old-price').is(':visible'))
443					;
444					$pictureSliderControls.children().remove();
445					$pictureSliderControls.html($productCard.find('.product__zoom-properties').html());
446
447					if ($pictureSlider.hasClass('slick-initialized')) {
448						$pictureSlider = $pictureSlider.slick('unslick');
449					}
450					$pictureSlider.children().remove();
451
452					/*
453					 * Битриксовый компонент всегда добавляет product.pict в morePhoto
454					if (obj.product && obj.product.pict && obj.product.pict.SRC)
455					{
456						$pictureSlider.append('<img src="' + String(obj.product.pict.SRC) + '" class="zoom-popup__slider-item">');
457					}
458					*/
459
460					if (obj.product && obj.product.morePhoto && obj.product.morePhoto.length > 0)
461					{
462						for (let pictureIndex = 0; pictureIndex < obj.product.morePhoto.length; pictureIndex++)
463						{
464							$pictureSlider.append('<img src="' + String(obj.product.morePhoto[pictureIndex].SRC) + '" class="zoom-popup__slider-item">');
465						}
466
467						$pictureSlider.slick({
468							slidesToShow: 1,
469							slidesToScroll: 1,
470							infinite: true,
471							arrows: true,
472							appendArrows: $pictureSliderControls,
473							dots: false,
474							fade: true,
475							touchThreshold: 100,
476						});
477					}
478					else
479					{
480						// TODO: default ???
481					}
482
483					let parentCompare = $('.vitrine__product-control.product__compare', $productCard);
484					if (parentCompare.length > 0) {
485						let buttonCompare = $('.zoom-popup__compare', $buttons);
486						buttonCompare.toggleClass('is-active', parentCompare.hasClass('is-active'));
487						buttonCompare
488							.off("click")
489							.on("click", function(e) {
490								e.preventDefault();
491								clickCompareButton(parentCompare.get(0), function (element, mode, data) {
492									buttonCompare.toggleClass('is-active', mode === 'add');
493								});
494
495								return false;
496							});
497					}
498
499					let parentFavorite = $('.vitrine__product-control.product__favorite', $productCard);
500					if (parentFavorite.length > 0) {
501						let buttonFavorite = $('.zoom-popup__favorite', $buttons);
502						buttonFavorite.toggleClass('is-active', parentFavorite.hasClass('is-active'));
503						buttonFavorite.addClass('vitrine__product-control product__favorite');
504						buttonFavorite
505							.off("click")
506							.on("click", function(e) {
507								e.preventDefault();
508
509								clickFavoriteButton(parentFavorite.get(0), function (element, mode, data) {
510									buttonFavorite.toggleClass('is-active', mode === 'add');
511								});
512
513								return false;
514							});
515					}
516
517					$(document).trigger('popupShown', node);
518				},
519				onHide(node)
520				{
521					$productName.text('');
522					$price.text('');
523					$priceOld.text('');
524					$advantages.text('');
525
526					if ($pictureSlider.hasClass('slick-initialized')) {
527						$pictureSlider = $pictureSlider.slick('unslick');
528					}
529					$pictureSlider.children().remove();
530					let buttonCompare = $('.zoom-popup__compare', $buttons);
531					buttonCompare.off("click").removeClass('is-active');
532
533					let buttonFavorite = $('.zoom-popup__favorite', $buttons);
534					buttonFavorite.off("click").removeClass('is-active');
535
536					$(document).trigger('popupHidden', node);
537				},
538			});
539		});
540	});
541
542	window.JCCatalogItem.prototype = {
543		init: function()
544		{
545			var i = 0,
546				treeItems = null;
547
548			this.obProduct = BX(this.visual.ID);
549			if (!this.obProduct)
550			{
551				this.errorCode = -1;
552			}
553
554			this.obPict = BX(this.visual.PICT_ID);
555			if (!this.obPict)
556			{
557				this.errorCode = -2;
558			}
559
560			if (this.secondPict && this.visual.SECOND_PICT_ID)
561			{
562				this.obSecondPict = BX(this.visual.SECOND_PICT_ID);
563			}
564
565			this.obPrice = BX(this.visual.PRICE_ID);
566			this.obPriceOld = BX(this.visual.PRICE_OLD_ID);
567			this.obPriceTotal = BX(this.visual.PRICE_TOTAL_ID);
568			if (!this.obPrice)
569			{
570				this.errorCode = -16;
571			}
572
573			if (this.showQuantity && this.visual.QUANTITY_ID)
574			{
575				this.obQuantity = BX(this.visual.QUANTITY_ID);
576				this.blockNodes.quantity = this.obProduct.querySelector('[data-entity="quantity-block"]');
577
578				if (!this.isTouchDevice)
579				{
580					BX.bind(this.obQuantity, 'focus', BX.proxy(this.onFocus, this));
581					BX.bind(this.obQuantity, 'blur', BX.proxy(this.onBlur, this));
582				}
583
584				if (this.visual.QUANTITY_UP_ID)
585				{
586					this.obQuantityUp = BX(this.visual.QUANTITY_UP_ID);
587				}
588
589				if (this.visual.QUANTITY_DOWN_ID)
590				{
591					this.obQuantityDown = BX(this.visual.QUANTITY_DOWN_ID);
592				}
593			}
594
595			if (this.visual.QUANTITY_LIMIT && this.showMaxQuantity !== 'N')
596			{
597				this.obQuantityLimit.all = BX(this.visual.QUANTITY_LIMIT);
598				if (this.obQuantityLimit.all)
599				{
600					this.obQuantityLimit.value = this.obQuantityLimit.all.querySelector('[data-entity="quantity-limit-value"]');
601					if (!this.obQuantityLimit.value)
602					{
603						this.obQuantityLimit.all = null;
604					}
605				}
606			}
607
608			if (this.productType === 3 && this.fullDisplayMode)
609			{
610				if (this.visual.TREE_ID)
611				{
612					this.obTree = BX(this.visual.TREE_ID);
613					if (!this.obTree)
614					{
615						this.errorCode = -256;
616					}
617				}
618
619				if (this.visual.QUANTITY_MEASURE)
620				{
621					this.obMeasure = BX(this.visual.QUANTITY_MEASURE);
622				}
623			}
624
625			this.obBasketActions = BX(this.visual.BASKET_ACTIONS_ID);
626			if (this.obBasketActions)
627			{
628				if (this.visual.BUY_ID)
629				{
630					this.obBuyBtn = BX(this.visual.BUY_ID);
631				}
632			}
633
634			this.obNotAvail = BX(this.visual.NOT_AVAILABLE_MESS);
635
636			if (this.showSubscription)
637			{
638				this.obSubscribe = BX(this.visual.SUBSCRIBE_ID);
639			}
640
641			if (this.showPercent)
642			{
643				if (this.visual.DSC_PERC)
644				{
645					this.obDscPerc = BX(this.visual.DSC_PERC);
646				}
647				if (this.secondPict && this.visual.SECOND_DSC_PERC)
648				{
649					this.obSecondDscPerc = BX(this.visual.SECOND_DSC_PERC);
650				}
651			}
652
653			if (this.showSkuProps)
654			{
655				if (this.visual.DISPLAY_PROP_DIV)
656				{
657					this.obSkuProps = BX(this.visual.DISPLAY_PROP_DIV);
658				}
659			}
660
661			if (this.errorCode === 0)
662			{
663				if (this.bigData)
664				{
665					var links = BX.findChildren(this.obProduct, {tag:'a'}, true);
666					if (links)
667					{
668						for (i in links)
669						{
670							if (links.hasOwnProperty(i))
671							{
672								if (links[i].getAttribute('href') == this.product.DETAIL_PAGE_URL)
673								{
674									BX.bind(links[i], 'click', BX.proxy(this.rememberProductRecommendation, this));
675								}
676							}
677						}
678					}
679				}
680
681				if (this.showQuantity)
682				{
683					var startEventName = this.isTouchDevice ? 'touchstart' : 'mousedown';
684					var endEventName = this.isTouchDevice ? 'touchend' : 'mouseup';
685
686					if (this.obQuantityUp)
687					{
688						BX.bind(this.obQuantityUp, startEventName, BX.proxy(this.startQuantityInterval, this));
689						BX.bind(this.obQuantityUp, endEventName, BX.proxy(this.clearQuantityInterval, this));
690						BX.bind(this.obQuantityUp, 'mouseout', BX.proxy(this.clearQuantityInterval, this));
691						BX.bind(this.obQuantityUp, 'click', BX.delegate(this.quantityUp, this));
692					}
693
694					if (this.obQuantityDown)
695					{
696						BX.bind(this.obQuantityDown, startEventName, BX.proxy(this.startQuantityInterval, this));
697						BX.bind(this.obQuantityDown, endEventName, BX.proxy(this.clearQuantityInterval, this));
698						BX.bind(this.obQuantityDown, 'mouseout', BX.proxy(this.clearQuantityInterval, this));
699						BX.bind(this.obQuantityDown, 'click', BX.delegate(this.quantityDown, this));
700					}
701
702					if (this.obQuantity)
703					{
704						BX.bind(this.obQuantity, 'change', BX.delegate(this.quantityChange, this));
705					}
706				}
707
708				switch (this.productType)
709				{
710					case 0: // no catalog
711					case 1: // product
712					case 2: // set
713
714						this.checkQuantityControls();
715
716						break;
717					case 3: // sku
718						if (this.offers.length > 0)
719						{
720							treeItems = BX.findChildren(this.obTree, {tagName: 'li'}, true);
721
722							if (treeItems && treeItems.length)
723							{
724								for (i = 0; i < treeItems.length; i++)
725								{
726									BX.bind(treeItems[i], 'click', BX.delegate(this.selectOfferProp, this));
727								}
728							}
729
730							this.setCurrent();
731						}
732
733						break;
734				}
735
736				if (this.obBuyBtn)
737				{
738					if (this.basketAction === 'ADD')
739					{
740						BX.bind(this.obBuyBtn, 'click', BX.proxy(this.add2Basket, this));
741					}
742					else
743					{
744						BX.bind(this.obBuyBtn, 'click', BX.proxy(this.buyBasket, this));
745					}
746				}
747
748				if (this.useCompare)
749				{
750					this.obCompare = BX(this.visual.COMPARE_LINK_ID);
751					if (this.obCompare)
752					{
753						BX.bind(this.obCompare, 'click', BX.proxy(this.compare, this));
754					}
755
756					BX.addCustomEvent('onCatalogDeleteCompare', BX.proxy(this.checkDeletedCompare, this));
757				}
758			}
759		},
760
761		setAnalyticsDataLayer: function(action)
762		{
763			if (!this.useEnhancedEcommerce || !this.dataLayerName)
764				return;
765
766			var item = {},
767				info = {},
768				variants = [],
769				i, k, j, propId, skuId, propValues;
770
771			switch (this.productType)
772			{
773				case 0: //no catalog
774				case 1: //product
775				case 2: //set
776					item = {
777						'id': this.product.id,
778						'name': this.product.name,
779						'price': this.currentPrices[this.currentPriceSelected] && this.currentPrices[this.currentPriceSelected].PRICE,
780						'brand': BX.type.isArray(this.brandProperty) ? this.brandProperty.join('/') : this.brandProperty
781					};
782					break;
783				case 3: //sku
784					for (i in this.offers[this.offerNum].TREE)
785					{
786						if (this.offers[this.offerNum].TREE.hasOwnProperty(i))
787						{
788							propId = i.substring(5);
789							skuId = this.offers[this.offerNum].TREE[i];
790
791							for (k in this.treeProps)
792							{
793								if (this.treeProps.hasOwnProperty(k) && this.treeProps[k].ID == propId)
794								{
795									for (j in this.treeProps[k].VALUES)
796									{
797										propValues = this.treeProps[k].VALUES[j];
798										if (propValues.ID == skuId)
799										{
800											variants.push(propValues.NAME);
801											break;
802										}
803									}
804
805								}
806							}
807						}
808					}
809
810					item = {
811						'id': this.offers[this.offerNum].ID,
812						'name': this.offers[this.offerNum].NAME,
813						'price': this.currentPrices[this.currentPriceSelected] && this.currentPrices[this.currentPriceSelected].PRICE,
814						'brand': BX.type.isArray(this.brandProperty) ? this.brandProperty.join('/') : this.brandProperty,
815						'variant': variants.join('/')
816					};
817					break;
818			}
819
820			switch (action)
821			{
822				case 'addToCart':
823					info = {
824						'ecommerce': {
825							'currencyCode': this.currentPrices[this.currentPriceSelected] && this.currentPrices[this.currentPriceSelected].CURRENCY || '',
826							'add': {
827								'products': [{
828									'name': item.name || '',
829									'id': item.id || '',
830									'price': item.price || 0,
831									'brand': item.brand || '',
832									'category': item.category || '',
833									'variant': item.variant || '',
834									'quantity': this.showQuantity && this.obQuantity ? this.obQuantity.value : 1
835								}]
836							}
837						}
838					};
839					break;
840			}
841
842			window[this.dataLayerName] = window[this.dataLayerName] || [];
843			window[this.dataLayerName].push(info);
844		},
845
846		hoverOn: function(event)
847		{
848			clearTimeout(this.hoverTimer);
849			this.obProduct.style.height = getComputedStyle(this.obProduct).height;
850			BX.addClass(this.obProduct, 'hover');
851
852			BX.PreventDefault(event);
853		},
854
855		hoverOff: function(event)
856		{
857			if (this.hoverStateChangeForbidden)
858				return;
859
860			BX.removeClass(this.obProduct, 'hover');
861			this.hoverTimer = setTimeout(
862				BX.delegate(function(){
863					this.obProduct.style.height = 'auto';
864				}, this),
865				300
866			);
867
868			BX.PreventDefault(event);
869		},
870
871		onFocus: function()
872		{
873			this.hoverStateChangeForbidden = true;
874			BX.bind(document, 'mousemove', BX.proxy(this.captureMousePosition, this));
875		},
876
877		onBlur: function()
878		{
879			this.hoverStateChangeForbidden = false;
880			BX.unbind(document, 'mousemove', BX.proxy(this.captureMousePosition, this));
881
882			var cursorElement = document.elementFromPoint(this.mouseX, this.mouseY);
883			if (!cursorElement || !this.obProduct.contains(cursorElement))
884			{
885				this.hoverOff();
886			}
887		},
888
889		captureMousePosition: function(event)
890		{
891			this.mouseX = event.clientX;
892			this.mouseY = event.clientY;
893		},
894
895		getCookie: function(name)
896		{
897			var matches = document.cookie.match(new RegExp(
898				"(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
899			));
900
901			return matches ? decodeURIComponent(matches[1]) : null;
902		},
903
904		rememberProductRecommendation: function()
905		{
906			// save to RCM_PRODUCT_LOG
907			var cookieName = BX.cookie_prefix + '_RCM_PRODUCT_LOG',
908				cookie = this.getCookie(cookieName),
909				itemFound = false;
910
911			var cItems = [],
912				cItem;
913
914			if (cookie)
915			{
916				cItems = cookie.split('.');
917			}
918
919			var i = cItems.length;
920
921			while (i--)
922			{
923				cItem = cItems[i].split('-');
924
925				if (cItem[0] == this.product.id)
926				{
927					// it's already in recommendations, update the date
928					cItem = cItems[i].split('-');
929
930					// update rcmId and date
931					cItem[1] = this.product.rcmId;
932					cItem[2] = BX.current_server_time;
933
934					cItems[i] = cItem.join('-');
935					itemFound = true;
936				}
937				else
938				{
939					if ((BX.current_server_time - cItem[2]) > 3600 * 24 * 30)
940					{
941						cItems.splice(i, 1);
942					}
943				}
944			}
945
946			if (!itemFound)
947			{
948				// add recommendation
949				cItems.push([this.product.id, this.product.rcmId, BX.current_server_time].join('-'));
950			}
951
952			// serialize
953			var plNewCookie = cItems.join('.'),
954				cookieDate = new Date(new Date().getTime() + 1000 * 3600 * 24 * 365 * 10).toUTCString();
955
956			document.cookie = cookieName + "=" + plNewCookie + "; path=/; expires=" + cookieDate + "; domain=" + BX.cookie_domain;
957		},
958
959		startQuantityInterval: function()
960		{
961			var target = BX.proxy_context;
962			var func = target.id === this.visual.QUANTITY_DOWN_ID
963				? BX.proxy(this.quantityDown, this)
964				: BX.proxy(this.quantityUp, this);
965
966			this.quantityDelay = setTimeout(
967				BX.delegate(function() {
968					this.quantityTimer = setInterval(func, 150);
969				}, this),
970				300
971			);
972		},
973
974		clearQuantityInterval: function()
975		{
976			clearTimeout(this.quantityDelay);
977			clearInterval(this.quantityTimer);
978		},
979
980		quantityUp: function()
981		{
982			var curValue = 0,
983				boolSet = true;
984
985			if (this.errorCode === 0 && this.showQuantity && this.canBuy)
986			{
987				curValue = (this.isDblQuantity ? parseFloat(this.obQuantity.value) : parseInt(this.obQuantity.value, 10));
988				if (!isNaN(curValue))
989				{
990					curValue += this.stepQuantity;
991					if (this.checkQuantity)
992					{
993						if (curValue > this.maxQuantity)
994						{
995							boolSet = false;
996						}
997					}
998
999					if (boolSet)
1000					{
1001						if (this.isDblQuantity)
1002						{
1003							curValue = Math.round(curValue * this.precisionFactor) / this.precisionFactor;
1004						}
1005
1006						this.obQuantity.value = curValue;
1007
1008						this.setPrice();
1009					}
1010				}
1011			}
1012		},
1013
1014		quantityDown: function()
1015		{
1016			var curValue = 0,
1017				boolSet = true;
1018
1019			if (this.errorCode === 0 && this.showQuantity && this.canBuy)
1020			{
1021				curValue = (this.isDblQuantity ? parseFloat(this.obQuantity.value) : parseInt(this.obQuantity.value, 10));
1022				if (!isNaN(curValue))
1023				{
1024					curValue -= this.stepQuantity;
1025
1026					this.checkPriceRange(curValue);
1027
1028					if (curValue < this.minQuantity)
1029					{
1030						boolSet = false;
1031					}
1032
1033					if (boolSet)
1034					{
1035						if (this.isDblQuantity)
1036						{
1037							curValue = Math.round(curValue * this.precisionFactor) / this.precisionFactor;
1038						}
1039
1040						this.obQuantity.value = curValue;
1041
1042						this.setPrice();
1043					}
1044				}
1045			}
1046		},
1047
1048		quantityChange: function()
1049		{
1050			var curValue = 0,
1051				intCount;
1052
1053			if (this.errorCode === 0 && this.showQuantity)
1054			{
1055				if (this.canBuy)
1056				{
1057					curValue = this.isDblQuantity ? parseFloat(this.obQuantity.value) : Math.round(this.obQuantity.value);
1058					if (!isNaN(curValue))
1059					{
1060						if (this.checkQuantity)
1061						{
1062							if (curValue > this.maxQuantity)
1063							{
1064								curValue = this.maxQuantity;
1065							}
1066						}
1067
1068						this.checkPriceRange(curValue);
1069
1070						intCount = Math.floor(
1071							Math.round(curValue * this.precisionFactor / this.stepQuantity) / this.precisionFactor
1072						) || 1;
1073						curValue = (intCount <= 1 ? this.stepQuantity : intCount * this.stepQuantity);
1074						curValue = Math.round(curValue * this.precisionFactor) / this.precisionFactor;
1075
1076						if (curValue < this.minQuantity)
1077						{
1078							curValue = this.minQuantity;
1079						}
1080
1081						this.obQuantity.value = curValue;
1082					}
1083					else
1084					{
1085						this.obQuantity.value = this.minQuantity;
1086					}
1087				}
1088				else
1089				{
1090					this.obQuantity.value = this.minQuantity;
1091				}
1092
1093				this.setPrice();
1094			}
1095		},
1096
1097		quantitySet: function(index)
1098		{
1099			var resetQuantity, strLimit;
1100
1101			var newOffer = this.offers[index],
1102				oldOffer = this.offers[this.offerNum];
1103
1104			if (this.errorCode === 0)
1105			{
1106				this.canBuy = newOffer.CAN_BUY;
1107
1108				this.currentPriceMode = newOffer.ITEM_PRICE_MODE;
1109				this.currentPrices = newOffer.ITEM_PRICES;
1110				this.currentPriceSelected = newOffer.ITEM_PRICE_SELECTED;
1111				this.currentQuantityRanges = newOffer.ITEM_QUANTITY_RANGES;
1112				this.currentQuantityRangeSelected = newOffer.ITEM_QUANTITY_RANGE_SELECTED;
1113
1114				if (this.canBuy)
1115				{
1116					if (this.blockNodes.quantity)
1117					{
1118						BX.style(this.blockNodes.quantity, 'display', '');
1119					}
1120
1121					if (this.obBasketActions)
1122					{
1123						BX.style(this.obBasketActions, 'display', '');
1124					}
1125
1126					if (this.obNotAvail)
1127					{
1128						BX.style(this.obNotAvail, 'display', 'none');
1129					}
1130
1131					if (this.obSubscribe)
1132					{
1133						BX.style(this.obSubscribe, 'display', 'none');
1134					}
1135				}
1136				else
1137				{
1138					if (this.blockNodes.quantity)
1139					{
1140						BX.style(this.blockNodes.quantity, 'display', 'none');
1141					}
1142
1143					if (this.obBasketActions)
1144					{
1145						BX.style(this.obBasketActions, 'display', 'none');
1146					}
1147
1148					if (this.obNotAvail)
1149					{
1150						BX.style(this.obNotAvail, 'display', '');
1151					}
1152
1153					if (this.obSubscribe)
1154					{
1155						if (newOffer.CATALOG_SUBSCRIBE === 'Y')
1156						{
1157							BX.style(this.obSubscribe, 'display', '');
1158							this.obSubscribe.setAttribute('data-item', newOffer.ID);
1159							BX(this.visual.SUBSCRIBE_ID + '_hidden').click();
1160						}
1161						else
1162						{
1163							BX.style(this.obSubscribe, 'display', 'none');
1164						}
1165					}
1166				}
1167
1168				this.isDblQuantity = newOffer.QUANTITY_FLOAT;
1169				this.checkQuantity = newOffer.CHECK_QUANTITY;
1170
1171				if (this.isDblQuantity)
1172				{
1173					this.stepQuantity = Math.round(parseFloat(newOffer.STEP_QUANTITY) * this.precisionFactor) / this.precisionFactor;
1174					this.maxQuantity = parseFloat(newOffer.MAX_QUANTITY);
1175					this.minQuantity = this.currentPriceMode === 'Q' ? parseFloat(this.currentPrices[this.currentPriceSelected].MIN_QUANTITY) : this.stepQuantity;
1176				}
1177				else
1178				{
1179					this.stepQuantity = parseInt(newOffer.STEP_QUANTITY, 10);
1180					this.maxQuantity = parseInt(newOffer.MAX_QUANTITY, 10);
1181					this.minQuantity = this.currentPriceMode === 'Q' ? parseInt(this.currentPrices[this.currentPriceSelected].MIN_QUANTITY) : this.stepQuantity;
1182				}
1183
1184				if (this.showQuantity)
1185				{
1186					var isDifferentMinQuantity = oldOffer.ITEM_PRICES.length
1187						&& oldOffer.ITEM_PRICES[oldOffer.ITEM_PRICE_SELECTED]
1188						&& oldOffer.ITEM_PRICES[oldOffer.ITEM_PRICE_SELECTED].MIN_QUANTITY != this.minQuantity;
1189
1190					if (this.isDblQuantity)
1191					{
1192						resetQuantity = Math.round(parseFloat(oldOffer.STEP_QUANTITY) * this.precisionFactor) / this.precisionFactor !== this.stepQuantity
1193							|| isDifferentMinQuantity
1194							|| oldOffer.MEASURE !== newOffer.MEASURE
1195							|| (
1196								this.checkQuantity
1197								&& parseFloat(oldOffer.MAX_QUANTITY) > this.maxQuantity
1198								&& parseFloat(this.obQuantity.value) > this.maxQuantity
1199							);
1200					}
1201					else
1202					{
1203						resetQuantity = parseInt(oldOffer.STEP_QUANTITY, 10) !== this.stepQuantity
1204							|| isDifferentMinQuantity
1205							|| oldOffer.MEASURE !== newOffer.MEASURE
1206							|| (
1207								this.checkQuantity
1208								&& parseInt(oldOffer.MAX_QUANTITY, 10) > this.maxQuantity
1209								&& parseInt(this.obQuantity.value, 10) > this.maxQuantity
1210							);
1211					}
1212
1213					this.obQuantity.disabled = !this.canBuy;
1214
1215					if (resetQuantity)
1216					{
1217						this.obQuantity.value = this.minQuantity;
1218					}
1219
1220					if (this.obMeasure)
1221					{
1222						if (newOffer.MEASURE)
1223						{
1224							BX.adjust(this.obMeasure, {html: newOffer.MEASURE});
1225						}
1226						else
1227						{
1228							BX.adjust(this.obMeasure, {html: ''});
1229						}
1230					}
1231				}
1232
1233				if (this.obQuantityLimit.all)
1234				{
1235					if (!this.checkQuantity || this.maxQuantity == 0)
1236					{
1237						BX.adjust(this.obQuantityLimit.value, {html: ''});
1238						BX.adjust(this.obQuantityLimit.all, {style: {display: 'none'}});
1239					}
1240					else
1241					{
1242						if (this.showMaxQuantity === 'M')
1243						{
1244							strLimit = (this.maxQuantity / this.stepQuantity >= this.relativeQuantityFactor)
1245								? BX.message('RELATIVE_QUANTITY_MANY')
1246								: BX.message('RELATIVE_QUANTITY_FEW');
1247						}
1248						else
1249						{
1250							strLimit = this.maxQuantity;
1251
1252							if (newOffer.MEASURE)
1253							{
1254								strLimit += (' ' + newOffer.MEASURE);
1255							}
1256						}
1257
1258						BX.adjust(this.obQuantityLimit.value, {html: strLimit});
1259						BX.adjust(this.obQuantityLimit.all, {style: {display: ''}});
1260					}
1261				}
1262			}
1263		},
1264
1265		eq: function(obj, i)
1266		{
1267			var len = obj.length,
1268				j = +i + (i < 0 ? len : 0);
1269
1270			return j >= 0 && j < len ? obj[j] : {};
1271		},
1272
1273		selectOfferProp: function()
1274		{
1275			var i = 0,
1276				value = '',
1277				strTreeValue = '',
1278				arTreeItem = [],
1279				rowItems = null,
1280				target = BX.proxy_context;
1281
1282			if (target && target.hasAttribute('data-treevalue'))
1283			{
1284				if (BX.hasClass(target, 'selected'))
1285					return;
1286
1287				strTreeValue = target.getAttribute('data-treevalue');
1288				arTreeItem = strTreeValue.split('_');
1289				if (this.searchOfferPropIndex(arTreeItem[0], arTreeItem[1]))
1290				{
1291					rowItems = BX.findChildren(target.parentNode, {tagName: 'li'}, false);
1292					if (rowItems && 0 < rowItems.length)
1293					{
1294						for (i = 0; i < rowItems.length; i++)
1295						{
1296							value = rowItems[i].getAttribute('data-onevalue');
1297							if (value === arTreeItem[1])
1298							{
1299								BX.addClass(rowItems[i], 'selected');
1300							}
1301							else
1302							{
1303								BX.removeClass(rowItems[i], 'selected');
1304							}
1305						}
1306					}
1307
1308					if (
1309						this.isFacebookConversionCustomizeProductEventEnabled
1310						&& BX.Type.isArrayFilled(this.offers)
1311						&& BX.Type.isObject(this.offers[this.offerNum])
1312					)
1313					{
1314						BX.ajax.runAction(
1315							'sale.facebookconversion.customizeProduct',
1316							{
1317								data: {
1318									offerId: this.offers[this.offerNum]['ID']
1319								}
1320							}
1321						);
1322					}
1323				}
1324			}
1325		},
1326
1327		searchOfferPropIndex: function(strPropID, strPropValue)
1328		{
1329			var strName = '',
1330				arShowValues = false,
1331				i, j,
1332				arCanBuyValues = [],
1333				allValues = [],
1334				index = -1,
1335				arFilter = {},
1336				tmpFilter = [];
1337
1338			for (i = 0; i < this.treeProps.length; i++)
1339			{
1340				if (this.treeProps[i].ID === strPropID)
1341				{
1342					index = i;
1343					break;
1344				}
1345			}
1346
1347			if (-1 < index)
1348			{
1349				for (i = 0; i < index; i++)
1350				{
1351					strName = 'PROP_'+this.treeProps[i].ID;
1352					arFilter[strName] = this.selectedValues[strName];
1353				}
1354				strName = 'PROP_'+this.treeProps[index].ID;
1355				arShowValues = this.getRowValues(arFilter, strName);
1356				if (!arShowValues)
1357				{
1358					return false;
1359				}
1360				if (!BX.util.in_array(strPropValue, arShowValues))
1361				{
1362					return false;
1363				}
1364				arFilter[strName] = strPropValue;
1365				for (i = index+1; i < this.treeProps.length; i++)
1366				{
1367					strName = 'PROP_'+this.treeProps[i].ID;
1368					arShowValues = this.getRowValues(arFilter, strName);
1369					if (!arShowValues)
1370					{
1371						return false;
1372					}
1373					allValues = [];
1374					if (this.showAbsent)
1375					{
1376						arCanBuyValues = [];
1377						tmpFilter = [];
1378						tmpFilter = BX.clone(arFilter, true);
1379						for (j = 0; j < arShowValues.length; j++)
1380						{
1381							tmpFilter[strName] = arShowValues[j];
1382							allValues[allValues.length] = arShowValues[j];
1383							if (this.getCanBuy(tmpFilter))
1384								arCanBuyValues[arCanBuyValues.length] = arShowValues[j];
1385						}
1386					}
1387					else
1388					{
1389						arCanBuyValues = arShowValues;
1390					}
1391					if (this.selectedValues[strName] && BX.util.in_array(this.selectedValues[strName], arCanBuyValues))
1392					{
1393						arFilter[strName] = this.selectedValues[strName];
1394					}
1395					else
1396					{
1397						if (this.showAbsent)
1398							arFilter[strName] = (arCanBuyValues.length > 0 ? arCanBuyValues[0] : allValues[0]);
1399						else
1400							arFilter[strName] = arCanBuyValues[0];
1401					}
1402					this.updateRow(i, arFilter[strName], arShowValues, arCanBuyValues);
1403				}
1404				this.selectedValues = arFilter;
1405				this.changeInfo();
1406			}
1407			return true;
1408		},
1409
1410		updateRow: function(intNumber, activeID, showID, canBuyID)
1411		{
1412			var i = 0,
1413				value = '',
1414				isCurrent = false,
1415				rowItems = null;
1416
1417			var lineContainer = this.obTree.querySelectorAll('[data-entity="sku-line-block"]'),
1418				listContainer;
1419
1420			if (intNumber > -1 && intNumber < lineContainer.length)
1421			{
1422				listContainer = lineContainer[intNumber].querySelector('ul');
1423				rowItems = BX.findChildren(listContainer, {tagName: 'li'}, false);
1424				if (rowItems && 0 < rowItems.length)
1425				{
1426					for (i = 0; i < rowItems.length; i++)
1427					{
1428						value = rowItems[i].getAttribute('data-onevalue');
1429						isCurrent = value === activeID;
1430
1431						if (isCurrent)
1432						{
1433							BX.addClass(rowItems[i], 'selected');
1434						}
1435						else
1436						{
1437							BX.removeClass(rowItems[i], 'selected');
1438						}
1439
1440						if (BX.util.in_array(value, canBuyID))
1441						{
1442							BX.removeClass(rowItems[i], 'notallowed');
1443						}
1444						else
1445						{
1446							BX.addClass(rowItems[i], 'notallowed');
1447						}
1448
1449						rowItems[i].style.display = BX.util.in_array(value, showID) ? '' : 'none';
1450
1451						if (isCurrent)
1452						{
1453							lineContainer[intNumber].style.display = (value == 0 && canBuyID.length == 1) ? 'none' : '';
1454						}
1455					}
1456				}
1457			}
1458		},
1459
1460		getRowValues: function(arFilter, index)
1461		{
1462			var i = 0,
1463				j,
1464				arValues = [],
1465				boolSearch = false,
1466				boolOneSearch = true;
1467
1468			if (0 === arFilter.length)
1469			{
1470				for (i = 0; i < this.offers.length; i++)
1471				{
1472					if (!BX.util.in_array(this.offers[i].TREE[index], arValues))
1473					{
1474						arValues[arValues.length] = this.offers[i].TREE[index];
1475					}
1476				}
1477				boolSearch = true;
1478			}
1479			else
1480			{
1481				for (i = 0; i < this.offers.length; i++)
1482				{
1483					boolOneSearch = true;
1484					for (j in arFilter)
1485					{
1486						if (arFilter[j] !== this.offers[i].TREE[j])
1487						{
1488							boolOneSearch = false;
1489							break;
1490						}
1491					}
1492					if (boolOneSearch)
1493					{
1494						if (!BX.util.in_array(this.offers[i].TREE[index], arValues))
1495						{
1496							arValues[arValues.length] = this.offers[i].TREE[index];
1497						}
1498						boolSearch = true;
1499					}
1500				}
1501			}
1502			return (boolSearch ? arValues : false);
1503		},
1504
1505		getCanBuy: function(arFilter)
1506		{
1507			var i, j,
1508				boolSearch = false,
1509				boolOneSearch = true;
1510
1511			for (i = 0; i < this.offers.length; i++)
1512			{
1513				boolOneSearch = true;
1514				for (j in arFilter)
1515				{
1516					if (arFilter[j] !== this.offers[i].TREE[j])
1517					{
1518						boolOneSearch = false;
1519						break;
1520					}
1521				}
1522				if (boolOneSearch)
1523				{
1524					if (this.offers[i].CAN_BUY)
1525					{
1526						boolSearch = true;
1527						break;
1528					}
1529				}
1530			}
1531
1532			return boolSearch;
1533		},
1534
1535		setCurrent: function()
1536		{
1537			var i,
1538				j = 0,
1539				arCanBuyValues = [],
1540				strName = '',
1541				arShowValues = false,
1542				arFilter = {},
1543				tmpFilter = [],
1544				current = this.offers[this.offerNum].TREE;
1545
1546			for (i = 0; i < this.treeProps.length; i++)
1547			{
1548				strName = 'PROP_'+this.treeProps[i].ID;
1549				arShowValues = this.getRowValues(arFilter, strName);
1550				if (!arShowValues)
1551				{
1552					break;
1553				}
1554				if (BX.util.in_array(current[strName], arShowValues))
1555				{
1556					arFilter[strName] = current[strName];
1557				}
1558				else
1559				{
1560					arFilter[strName] = arShowValues[0];
1561					this.offerNum = 0;
1562				}
1563				if (this.showAbsent)
1564				{
1565					arCanBuyValues = [];
1566					tmpFilter = [];
1567					tmpFilter = BX.clone(arFilter, true);
1568					for (j = 0; j < arShowValues.length; j++)
1569					{
1570						tmpFilter[strName] = arShowValues[j];
1571						if (this.getCanBuy(tmpFilter))
1572						{
1573							arCanBuyValues[arCanBuyValues.length] = arShowValues[j];
1574						}
1575					}
1576				}
1577				else
1578				{
1579					arCanBuyValues = arShowValues;
1580				}
1581				this.updateRow(i, arFilter[strName], arShowValues, arCanBuyValues);
1582			}
1583			this.selectedValues = arFilter;
1584			this.changeInfo();
1585		},
1586
1587		changeInfo: function()
1588		{
1589			var i, j,
1590				index = -1,
1591				boolOneSearch = true,
1592				quantityChanged;
1593
1594			for (i = 0; i < this.offers.length; i++)
1595			{
1596				boolOneSearch = true;
1597				for (j in this.selectedValues)
1598				{
1599					if (this.selectedValues[j] !== this.offers[i].TREE[j])
1600					{
1601						boolOneSearch = false;
1602						break;
1603					}
1604				}
1605				if (boolOneSearch)
1606				{
1607					index = i;
1608					break;
1609				}
1610			}
1611			if (index > -1)
1612			{
1613				if (this.showSkuProps && this.obSkuProps)
1614				{
1615					if (this.offers[index].DISPLAY_PROPERTIES.length)
1616					{
1617						BX.adjust(this.obSkuProps, {style: {display: ''}, html: this.offers[index].DISPLAY_PROPERTIES});
1618					}
1619					else
1620					{
1621						BX.adjust(this.obSkuProps, {style: {display: 'none'}, html: ''});
1622					}
1623				}
1624
1625				this.quantitySet(index);
1626				this.setPrice();
1627				this.setCompared(this.offers[index].COMPARED);
1628
1629				this.offerNum = index;
1630			}
1631		},
1632
1633		checkPriceRange: function(quantity)
1634		{
1635			if (typeof quantity === 'undefined'|| this.currentPriceMode != 'Q')
1636				return;
1637
1638			var range, found = false;
1639
1640			for (var i in this.currentQuantityRanges)
1641			{
1642				if (this.currentQuantityRanges.hasOwnProperty(i))
1643				{
1644					range = this.currentQuantityRanges[i];
1645
1646					if (
1647						parseInt(quantity) >= parseInt(range.SORT_FROM)
1648						&& (
1649							range.SORT_TO == 'INF'
1650							|| parseInt(quantity) <= parseInt(range.SORT_TO)
1651						)
1652					)
1653					{
1654						found = true;
1655						this.currentQuantityRangeSelected = range.HASH;
1656						break;
1657					}
1658				}
1659			}
1660
1661			if (!found && (range = this.getMinPriceRange()))
1662			{
1663				this.currentQuantityRangeSelected = range.HASH;
1664			}
1665
1666			for (var k in this.currentPrices)
1667			{
1668				if (this.currentPrices.hasOwnProperty(k))
1669				{
1670					if (this.currentPrices[k].QUANTITY_HASH == this.currentQuantityRangeSelected)
1671					{
1672						this.currentPriceSelected = k;
1673						break;
1674					}
1675				}
1676			}
1677		},
1678
1679		getMinPriceRange: function()
1680		{
1681			var range;
1682
1683			for (var i in this.currentQuantityRanges)
1684			{
1685				if (this.currentQuantityRanges.hasOwnProperty(i))
1686				{
1687					if (
1688						!range
1689						|| parseInt(this.currentQuantityRanges[i].SORT_FROM) < parseInt(range.SORT_FROM)
1690					)
1691					{
1692						range = this.currentQuantityRanges[i];
1693					}
1694				}
1695			}
1696
1697			return range;
1698		},
1699
1700		checkQuantityControls: function()
1701		{
1702			if (!this.obQuantity)
1703				return;
1704
1705			var reachedTopLimit = this.checkQuantity && parseFloat(this.obQuantity.value) + this.stepQuantity > this.maxQuantity,
1706				reachedBottomLimit = parseFloat(this.obQuantity.value) - this.stepQuantity < this.minQuantity;
1707
1708			if (reachedTopLimit)
1709			{
1710				BX.addClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled');
1711			}
1712			else if (BX.hasClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled'))
1713			{
1714				BX.removeClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled');
1715			}
1716
1717			if (reachedBottomLimit)
1718			{
1719				BX.addClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled');
1720			}
1721			else if (BX.hasClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled'))
1722			{
1723				BX.removeClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled');
1724			}
1725
1726			if (reachedTopLimit && reachedBottomLimit)
1727			{
1728				this.obQuantity.setAttribute('disabled', 'disabled');
1729			}
1730			else
1731			{
1732				this.obQuantity.removeAttribute('disabled');
1733			}
1734		},
1735
1736		setPrice: function()
1737		{
1738			var obData, price;
1739
1740			if (this.obQuantity)
1741			{
1742				this.checkPriceRange(this.obQuantity.value);
1743			}
1744
1745			this.checkQuantityControls();
1746
1747			price = this.currentPrices[this.currentPriceSelected];
1748
1749			if (this.obPrice)
1750			{
1751				if (price)
1752				{
1753					BX.adjust(this.obPrice, {html: BX.Currency.currencyFormat(price.RATIO_PRICE, price.CURRENCY, true)});
1754				}
1755				else
1756				{
1757					BX.adjust(this.obPrice, {html: ''});
1758				}
1759
1760				if (this.showOldPrice && this.obPriceOld)
1761				{
1762					if (price && price.RATIO_PRICE !== price.RATIO_BASE_PRICE)
1763					{
1764						BX.adjust(this.obPriceOld, {
1765							style: {display: ''},
1766							html: BX.Currency.currencyFormat(price.RATIO_BASE_PRICE, price.CURRENCY, true)
1767						});
1768					}
1769					else
1770					{
1771						BX.adjust(this.obPriceOld, {
1772							style: {display: 'none'},
1773							html: ''
1774						});
1775					}
1776				}
1777
1778				if (this.obPriceTotal)
1779				{
1780					if (price && this.obQuantity && this.obQuantity.value != this.stepQuantity)
1781					{
1782						BX.adjust(this.obPriceTotal, {
1783							html: BX.message('PRICE_TOTAL_PREFIX') + ' <strong>'
1784							+ BX.Currency.currencyFormat(price.PRICE * this.obQuantity.value, price.CURRENCY, true)
1785							+ '</strong>',
1786							style: {display: ''}
1787						});
1788					}
1789					else
1790					{
1791						BX.adjust(this.obPriceTotal, {
1792							html: '',
1793							style: {display: 'none'}
1794						});
1795					}
1796				}
1797
1798				if (this.showPercent)
1799				{
1800					if (price && parseInt(price.PERCENT) > 0)
1801					{
1802						obData = {style: {display: ''}, html: -price.PERCENT + '%'};
1803					}
1804					else
1805					{
1806						obData = {style: {display: 'none'}, html: ''};
1807					}
1808
1809					if (this.obDscPerc)
1810					{
1811						BX.adjust(this.obDscPerc, obData);
1812					}
1813
1814					if (this.obSecondDscPerc)
1815					{
1816						BX.adjust(this.obSecondDscPerc, obData);
1817					}
1818				}
1819			}
1820		},
1821
1822		compare: function(event)
1823		{
1824			var checkbox = this.obCompare.querySelector('[data-entity="compare-checkbox"]'),
1825				target = BX.getEventTarget(event),
1826				checked = true;
1827
1828			if (checkbox)
1829			{
1830				checked = target === checkbox ? checkbox.checked : !checkbox.checked;
1831			}
1832
1833			var url = checked ? this.compareData.compareUrl : this.compareData.compareDeleteUrl,
1834				compareLink;
1835
1836			if (url)
1837			{
1838				if (target !== checkbox)
1839				{
1840					BX.PreventDefault(event);
1841					this.setCompared(checked);
1842				}
1843
1844				switch (this.productType)
1845				{
1846					case 0: // no catalog
1847					case 1: // product
1848					case 2: // set
1849						compareLink = url.replace('#ID#', this.product.id.toString());
1850						break;
1851					case 3: // sku
1852						compareLink = url.replace('#ID#', this.offers[this.offerNum].ID);
1853						break;
1854				}
1855
1856				BX.ajax({
1857					method: 'POST',
1858					dataType: checked ? 'json' : 'html',
1859					url: compareLink + (compareLink.indexOf('?') !== -1 ? '&' : '?') + 'ajax_action=Y',
1860					onsuccess: checked
1861						? BX.proxy(this.compareResult, this)
1862						: BX.proxy(this.compareDeleteResult, this)
1863				});
1864			}
1865		},
1866
1867		compareResult: function(result)
1868		{
1869			var popupContent, popupButtons;
1870
1871			if (this.obPopupWin)
1872			{
1873				this.obPopupWin.close();
1874			}
1875
1876			if (!BX.type.isPlainObject(result))
1877				return;
1878
1879			this.initPopupWindow();
1880
1881			if (this.offers.length > 0)
1882			{
1883				this.offers[this.offerNum].COMPARED = result.STATUS === 'OK';
1884			}
1885
1886			if (result.STATUS === 'OK')
1887			{
1888				BX.onCustomEvent('OnCompareChange');
1889
1890				popupContent = '<div style="width: 100%; margin: 0; text-align: center;"><p>'
1891					+ BX.message('COMPARE_MESSAGE_OK')
1892					+ '</p></div>';
1893
1894				if (this.showClosePopup)
1895				{
1896					popupButtons = [
1897						new BasketButton({
1898							text: BX.message('BTN_MESSAGE_COMPARE_REDIRECT'),
1899							events: {
1900								click: BX.delegate(this.compareRedirect, this)
1901							},
1902							style: {marginRight: '10px'}
1903						}),
1904						new BasketButton({
1905							text: BX.message('BTN_MESSAGE_CLOSE_POPUP'),
1906							events: {
1907								click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
1908							}
1909						})
1910					];
1911				}
1912				else
1913				{
1914					popupButtons = [
1915						new BasketButton({
1916							text: BX.message('BTN_MESSAGE_COMPARE_REDIRECT'),
1917							events: {
1918								click: BX.delegate(this.compareRedirect, this)
1919							}
1920						})
1921					];
1922				}
1923			}
1924			else
1925			{
1926				popupContent = '<div style="width: 100%; margin: 0; text-align: center;"><p>'
1927					+ (result.MESSAGE ? result.MESSAGE : BX.message('COMPARE_UNKNOWN_ERROR'))
1928					+ '</p></div>';
1929				popupButtons = [
1930					new BasketButton({
1931						text: BX.message('BTN_MESSAGE_CLOSE'),
1932						events: {
1933							click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
1934						}
1935					})
1936				];
1937			}
1938
1939			this.obPopupWin.setTitleBar(BX.message('COMPARE_TITLE'));
1940			this.obPopupWin.setContent(popupContent);
1941			this.obPopupWin.setButtons(popupButtons);
1942			this.obPopupWin.show();
1943		},
1944
1945		compareDeleteResult: function()
1946		{
1947			BX.onCustomEvent('OnCompareChange');
1948
1949			if (this.offers && this.offers.length)
1950			{
1951				this.offers[this.offerNum].COMPARED = false;
1952			}
1953		},
1954
1955		setCompared: function(state)
1956		{
1957			if (!this.obCompare)
1958				return;
1959
1960			var checkbox = this.obCompare.querySelector('[data-entity="compare-checkbox"]');
1961			if (checkbox)
1962			{
1963				checkbox.checked = state;
1964			}
1965		},
1966
1967		setCompareInfo: function(comparedIds)
1968		{
1969			if (!BX.type.isArray(comparedIds))
1970				return;
1971
1972			for (var i in this.offers)
1973			{
1974				if (this.offers.hasOwnProperty(i))
1975				{
1976					this.offers[i].COMPARED = BX.util.in_array(this.offers[i].ID, comparedIds);
1977				}
1978			}
1979		},
1980
1981		compareRedirect: function()
1982		{
1983			if (this.compareData.comparePath)
1984			{
1985				location.href = this.compareData.comparePath;
1986			}
1987			else
1988			{
1989				this.obPopupWin.close();
1990			}
1991		},
1992
1993		checkDeletedCompare: function(id)
1994		{
1995			switch (this.productType)
1996			{
1997				case 0: // no catalog
1998				case 1: // product
1999				case 2: // set
2000					if (this.product.id == id)
2001					{
2002						this.setCompared(false);
2003					}
2004
2005					break;
2006				case 3: // sku
2007					var i = this.offers.length;
2008					while (i--)
2009					{
2010						if (this.offers[i].ID == id)
2011						{
2012							this.offers[i].COMPARED = false;
2013
2014							if (this.offerNum == i)
2015							{
2016								this.setCompared(false);
2017							}
2018
2019							break;
2020						}
2021					}
2022			}
2023		},
2024
2025		initBasketUrl: function()
2026		{
2027			this.basketUrl = (this.basketMode === 'ADD' ? this.basketData.add_url : this.basketData.buy_url);
2028			switch (this.productType)
2029			{
2030				case 1: // product
2031				case 2: // set
2032					this.basketUrl = this.basketUrl.replace('#ID#', this.product.id.toString());
2033					break;
2034				case 3: // sku
2035					this.basketUrl = this.basketUrl.replace('#ID#', this.offers[this.offerNum].ID);
2036					break;
2037			}
2038			this.basketParams = {
2039				'ajax_basket': 'Y'
2040			};
2041			if (this.showQuantity)
2042			{
2043				this.basketParams[this.basketData.quantity] = this.obQuantity.value;
2044			}
2045			if (this.basketData.sku_props)
2046			{
2047				this.basketParams[this.basketData.sku_props_var] = this.basketData.sku_props;
2048			}
2049		},
2050
2051		fillBasketProps: function()
2052		{
2053			if (!this.visual.BASKET_PROP_DIV)
2054			{
2055				return;
2056			}
2057			var
2058				i = 0,
2059				propCollection = null,
2060				foundValues = false,
2061				obBasketProps = null;
2062
2063			if (this.basketData.useProps && !this.basketData.emptyProps)
2064			{
2065				if (this.obPopupWin && this.obPopupWin.contentContainer)
2066				{
2067					obBasketProps = this.obPopupWin.contentContainer;
2068				}
2069			}
2070			else
2071			{
2072				obBasketProps = BX(this.visual.BASKET_PROP_DIV);
2073			}
2074			if (obBasketProps)
2075			{
2076				propCollection = obBasketProps.getElementsByTagName('select');
2077				if (propCollection && propCollection.length)
2078				{
2079					for (i = 0; i < propCollection.length; i++)
2080					{
2081						if (!propCollection[i].disabled)
2082						{
2083							switch (propCollection[i].type.toLowerCase())
2084							{
2085								case 'select-one':
2086									this.basketParams[propCollection[i].name] = propCollection[i].value;
2087									foundValues = true;
2088									break;
2089								default:
2090									break;
2091							}
2092						}
2093					}
2094				}
2095				propCollection = obBasketProps.getElementsByTagName('input');
2096				if (propCollection && propCollection.length)
2097				{
2098					for (i = 0; i < propCollection.length; i++)
2099					{
2100						if (!propCollection[i].disabled)
2101						{
2102							switch (propCollection[i].type.toLowerCase())
2103							{
2104								case 'hidden':
2105									this.basketParams[propCollection[i].name] = propCollection[i].value;
2106									foundValues = true;
2107									break;
2108								case 'radio':
2109									if (propCollection[i].checked)
2110									{
2111										this.basketParams[propCollection[i].name] = propCollection[i].value;
2112										foundValues = true;
2113									}
2114									break;
2115								default:
2116									break;
2117							}
2118						}
2119					}
2120				}
2121			}
2122			if (!foundValues)
2123			{
2124				this.basketParams[this.basketData.props] = [];
2125				this.basketParams[this.basketData.props][0] = 0;
2126			}
2127		},
2128
2129		add2Basket: function()
2130		{
2131			this.basketMode = 'ADD';
2132			this.basket();
2133		},
2134
2135		buyBasket: function()
2136		{
2137			this.basketMode = 'BUY';
2138			this.basket();
2139		},
2140
2141		sendToBasket: function()
2142		{
2143			if (!this.canBuy)
2144			{
2145				return;
2146			}
2147
2148			// check recommendation
2149			if (this.product && this.product.id && this.bigData)
2150			{
2151				this.rememberProductRecommendation();
2152			}
2153
2154			this.initBasketUrl();
2155			this.fillBasketProps();
2156			BX.ajax({
2157				method: 'POST',
2158				dataType: 'json',
2159				url: this.basketUrl,
2160				data: this.basketParams,
2161				onsuccess: BX.proxy(this.basketResult, this)
2162			});
2163		},
2164
2165		basket: function()
2166		{
2167			var contentBasketProps = '';
2168			if (!this.canBuy)
2169			{
2170				return;
2171			}
2172			switch (this.productType)
2173			{
2174				case 1: // product
2175				case 2: // set
2176					if (this.basketData.useProps && !this.basketData.emptyProps)
2177					{
2178						this.initPopupWindow();
2179						this.obPopupWin.setTitleBar(BX.message('TITLE_BASKET_PROPS'));
2180						if (BX(this.visual.BASKET_PROP_DIV))
2181						{
2182							contentBasketProps = BX(this.visual.BASKET_PROP_DIV).innerHTML;
2183						}
2184						this.obPopupWin.setContent(contentBasketProps);
2185						this.obPopupWin.setButtons([
2186							new BasketButton({
2187								text: BX.message('BTN_MESSAGE_SEND_PROPS'),
2188								events: {
2189									click: BX.delegate(this.sendToBasket, this)
2190								}
2191							})
2192						]);
2193						this.obPopupWin.show();
2194					}
2195					else
2196					{
2197						this.sendToBasket();
2198					}
2199					break;
2200				case 3: // sku
2201					this.sendToBasket();
2202					break;
2203			}
2204		},
2205
2206		basketResult: function(arResult)
2207		{
2208			var strContent = '',
2209				strPict = '',
2210				successful,
2211				buttons = [];
2212
2213			if (this.obPopupWin)
2214				this.obPopupWin.close();
2215
2216			if (!BX.type.isPlainObject(arResult))
2217				return;
2218
2219			successful = arResult.STATUS === 'OK';
2220
2221			if (successful)
2222			{
2223				this.setAnalyticsDataLayer('addToCart');
2224			}
2225
2226			if (successful && this.basketAction === 'BUY')
2227			{
2228				this.basketRedirect();
2229			}
2230			else
2231			{
2232				this.initPopupWindow();
2233
2234				if (successful)
2235				{
2236					BX.onCustomEvent('OnBasketChange');
2237
2238					if  (BX.findParent(this.obProduct, {className: 'bx_sale_gift_main_products'}, 10))
2239					{
2240						BX.onCustomEvent('onAddToBasketMainProduct', [this]);
2241					}
2242
2243					switch (this.productType)
2244					{
2245						case 1: // product
2246						case 2: // set
2247							strPict = this.product.pict.SRC;
2248							break;
2249						case 3: // sku
2250							strPict = (this.offers[this.offerNum].PREVIEW_PICTURE ?
2251									this.offers[this.offerNum].PREVIEW_PICTURE.SRC :
2252									this.defaultPict.pict.SRC
2253							);
2254							break;
2255					}
2256
2257					strContent = '<div style="width: 100%; margin: 0; text-align: center;"><img src="'
2258						+ strPict + '" height="130" style="max-height:130px"><p>' + this.product.name + '</p></div>';
2259
2260					if (this.showClosePopup)
2261					{
2262						buttons = [
2263							new BasketButton({
2264								text: BX.message("BTN_MESSAGE_BASKET_REDIRECT"),
2265								events: {
2266									click: BX.delegate(this.basketRedirect, this)
2267								},
2268								style: {marginRight: '10px'}
2269							}),
2270							new BasketButton({
2271								text: BX.message("BTN_MESSAGE_CLOSE_POPUP"),
2272								events: {
2273									click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
2274								}
2275							})
2276						];
2277					}
2278					else
2279					{
2280						buttons = [
2281							new BasketButton({
2282								text: BX.message("BTN_MESSAGE_BASKET_REDIRECT"),
2283								events: {
2284									click: BX.delegate(this.basketRedirect, this)
2285								}
2286							})
2287						];
2288					}
2289				}
2290				else
2291				{
2292					strContent = '<div style="width: 100%; margin: 0; text-align: center;"><p>'
2293						+ (arResult.MESSAGE ? arResult.MESSAGE : BX.message('BASKET_UNKNOWN_ERROR'))
2294						+ '</p></div>';
2295					buttons = [
2296						new BasketButton({
2297							text: BX.message('BTN_MESSAGE_CLOSE'),
2298							events: {
2299								click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
2300							}
2301						})
2302					];
2303				}
2304				this.obPopupWin.setTitleBar(successful ? BX.message('TITLE_SUCCESSFUL') : BX.message('TITLE_ERROR'));
2305				this.obPopupWin.setContent(strContent);
2306				this.obPopupWin.setButtons(buttons);
2307				this.obPopupWin.show();
2308			}
2309		},
2310
2311		basketRedirect: function()
2312		{
2313			location.href = (this.basketData.basketUrl ? this.basketData.basketUrl : BX.message('BASKET_URL'));
2314		},
2315
2316		initPopupWindow: function()
2317		{
2318			if (this.obPopupWin)
2319				return;
2320
2321			this.obPopupWin = BX.PopupWindowManager.create('CatalogSectionBasket_' + this.visual.ID, null, {
2322				autoHide: true,
2323				offsetLeft: 0,
2324				offsetTop: 0,
2325				overlay : true,
2326				closeByEsc: true,
2327				titleBar: true,
2328				closeIcon: true,
2329				contentColor: 'white',
2330				className: this.templateTheme ? 'bx-' + this.templateTheme : ''
2331			});
2332		}
2333	};
2334})(window);

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.