PageSourceSearch

https://hobbit.ru/local/templates/.default/components/bitrix/catal…/window-main/script.js?160078457163257

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