PageSourceSearch

https://3c-group.ru/bitrix/components/bitrix/catalog.item/templates/.default/script.js?165893320263728

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