PageSourceSearch

https://tehnoindustria.ru/bitrix/components/bitrix/catalog.item/templates/hommes/script.js

js tehnoindustria.ru collected 2026-10-07 02:54:32 UTC 63,290 bytes, 2,620 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						if (curValue < this.minQuantity)
979						{
980							curValue = this.minQuantity;
981						}
982						else
983						{
984							intCount = Math.round(
985									Math.round(curValue * this.precisionFactor / this.stepQuantity) / this.precisionFactor
986								) || 1;
987							curValue = (intCount <= 1 ? this.stepQuantity : intCount * this.stepQuantity);
988							curValue = Math.round(curValue * this.precisionFactor) / this.precisionFactor;
989						}
990
991						this.obQuantity.value = curValue;
992					}
993					else
994					{
995						this.obQuantity.value = this.minQuantity;
996					}
997				}
998				else
999				{
1000					this.obQuantity.value = this.minQuantity;
1001				}
1002
1003				this.setPrice();
1004			}
1005		},
1006
1007		quantitySet: function(index)
1008		{
1009			var resetQuantity, strLimit;
1010			
1011			var newOffer = this.offers[index],
1012				oldOffer = this.offers[this.offerNum];
1013
1014			if (this.errorCode === 0)
1015			{
1016				this.canBuy = newOffer.CAN_BUY;
1017
1018				this.currentPriceMode = newOffer.ITEM_PRICE_MODE;
1019				this.currentPrices = newOffer.ITEM_PRICES;
1020				this.currentPriceSelected = newOffer.ITEM_PRICE_SELECTED;
1021				this.currentQuantityRanges = newOffer.ITEM_QUANTITY_RANGES;
1022				this.currentQuantityRangeSelected = newOffer.ITEM_QUANTITY_RANGE_SELECTED;
1023
1024				if (this.canBuy)
1025				{
1026					if (this.blockNodes.quantity)
1027					{
1028						BX.style(this.blockNodes.quantity, 'display', '');
1029					}
1030
1031					if (this.obBasketActions)
1032					{
1033						BX.style(this.obBasketActions, 'display', '');
1034					}
1035
1036					if (this.obNotAvail)
1037					{
1038						BX.style(this.obNotAvail, 'display', 'none');
1039					}
1040
1041					if (this.obSubscribe)
1042					{
1043						BX.style(this.obSubscribe, 'display', 'none');
1044					}
1045				}
1046				else
1047				{
1048					if (this.blockNodes.quantity)
1049					{
1050						BX.style(this.blockNodes.quantity, 'display', 'none');
1051					}
1052
1053					if (this.obBasketActions)
1054					{
1055						BX.style(this.obBasketActions, 'display', 'none');
1056					}
1057
1058					if (this.obNotAvail)
1059					{
1060						BX.style(this.obNotAvail, 'display', '');
1061					}
1062
1063					if (this.obSubscribe)
1064					{
1065						if (newOffer.CATALOG_SUBSCRIBE === 'Y')
1066						{
1067							BX.style(this.obSubscribe, 'display', '');
1068							this.obSubscribe.setAttribute('data-item', newOffer.ID);
1069							BX(this.visual.SUBSCRIBE_ID + '_hidden').click();
1070						}
1071						else
1072						{
1073							BX.style(this.obSubscribe, 'display', 'none');
1074						}
1075					}
1076				}
1077
1078				this.isDblQuantity = newOffer.QUANTITY_FLOAT;
1079				this.checkQuantity = newOffer.CHECK_QUANTITY;
1080
1081				if (this.isDblQuantity)
1082				{
1083					this.stepQuantity = Math.round(parseFloat(newOffer.STEP_QUANTITY) * this.precisionFactor) / this.precisionFactor;
1084					this.maxQuantity = parseFloat(newOffer.MAX_QUANTITY);
1085					this.minQuantity = this.currentPriceMode === 'Q' ? parseFloat(this.currentPrices[this.currentPriceSelected].MIN_QUANTITY) : this.stepQuantity;
1086				}
1087				else
1088				{
1089					this.stepQuantity = parseInt(newOffer.STEP_QUANTITY, 10);
1090					this.maxQuantity = parseInt(newOffer.MAX_QUANTITY, 10);
1091					this.minQuantity = this.currentPriceMode === 'Q' ? parseInt(this.currentPrices[this.currentPriceSelected].MIN_QUANTITY) : this.stepQuantity;
1092				}
1093
1094				if (this.showQuantity)
1095				{
1096					var isDifferentMinQuantity = oldOffer.ITEM_PRICES.length
1097						&& oldOffer.ITEM_PRICES[oldOffer.ITEM_PRICE_SELECTED]
1098						&& oldOffer.ITEM_PRICES[oldOffer.ITEM_PRICE_SELECTED].MIN_QUANTITY != this.minQuantity;
1099
1100					if (this.isDblQuantity)
1101					{
1102						resetQuantity = Math.round(parseFloat(oldOffer.STEP_QUANTITY) * this.precisionFactor) / this.precisionFactor !== this.stepQuantity
1103							|| isDifferentMinQuantity
1104							|| oldOffer.MEASURE !== newOffer.MEASURE
1105							|| (
1106								this.checkQuantity
1107								&& parseFloat(oldOffer.MAX_QUANTITY) > this.maxQuantity
1108								&& parseFloat(this.obQuantity.value) > this.maxQuantity
1109							);
1110					}
1111					else
1112					{
1113						resetQuantity = parseInt(oldOffer.STEP_QUANTITY, 10) !== this.stepQuantity
1114							|| isDifferentMinQuantity
1115							|| oldOffer.MEASURE !== newOffer.MEASURE
1116							|| (
1117								this.checkQuantity
1118								&& parseInt(oldOffer.MAX_QUANTITY, 10) > this.maxQuantity
1119								&& parseInt(this.obQuantity.value, 10) > this.maxQuantity
1120							);
1121					}
1122
1123					this.obQuantity.disabled = !this.canBuy;
1124
1125					if (resetQuantity)
1126					{
1127						this.obQuantity.value = this.minQuantity;
1128					}
1129
1130					if (this.obMeasure)
1131					{
1132						if (newOffer.MEASURE)
1133						{
1134							BX.adjust(this.obMeasure, {html: newOffer.MEASURE});
1135						}
1136						else
1137						{
1138							BX.adjust(this.obMeasure, {html: ''});
1139						}
1140					}
1141				}
1142
1143				if (this.obQuantityLimit.all)
1144				{
1145					if (!this.checkQuantity || this.maxQuantity == 0)
1146					{
1147						BX.adjust(this.obQuantityLimit.value, {html: ''});
1148						BX.adjust(this.obQuantityLimit.all, {style: {display: 'none'}});
1149					}
1150					else
1151					{
1152						if (this.showMaxQuantity === 'M')
1153						{
1154							strLimit = (this.maxQuantity / this.stepQuantity >= this.relativeQuantityFactor)
1155								? BX.message('RELATIVE_QUANTITY_MANY')
1156								: BX.message('RELATIVE_QUANTITY_FEW');
1157						}
1158						else
1159						{
1160							strLimit = this.maxQuantity;
1161
1162							if (newOffer.MEASURE)
1163							{
1164								strLimit += (' ' + newOffer.MEASURE);
1165							}
1166						}
1167
1168						BX.adjust(this.obQuantityLimit.value, {html: strLimit});
1169						BX.adjust(this.obQuantityLimit.all, {style: {display: ''}});
1170					}
1171				}
1172			}
1173		},
1174
1175		initializeSlider: function()
1176		{
1177			var wrap = this.obPictSlider.getAttribute('data-slider-wrap');
1178			if (wrap)
1179			{
1180				this.slider.options.wrap = wrap === 'true';
1181			}
1182			else
1183			{
1184				this.slider.options.wrap = this.defaultSliderOptions.wrap;
1185			}
1186
1187			if (this.isTouchDevice)
1188			{
1189				this.slider.options.interval = false;
1190			}
1191			else
1192			{
1193				this.slider.options.interval = parseInt(this.obPictSlider.getAttribute('data-slider-interval')) || this.defaultSliderOptions.interval;
1194				// slider interval must be more than 700ms because of css transitions
1195				if (this.slider.options.interval < 700)
1196				{
1197					this.slider.options.interval = 700;
1198				}
1199
1200				if (this.obPictSliderIndicator)
1201				{
1202					var controls = this.obPictSliderIndicator.querySelectorAll('[data-go-to]');
1203					for (var i in controls)
1204					{
1205						if (controls.hasOwnProperty(i))
1206						{
1207							BX.bind(controls[i], 'click', BX.proxy(this.sliderClickHandler, this));
1208						}
1209					}
1210				}
1211
1212				if (this.obPictSliderProgressBar)
1213				{
1214					if (this.slider.progress)
1215					{
1216						this.resetProgress();
1217						this.cycleSlider();
1218					}
1219					else
1220					{
1221						this.slider.progress = new BX.easing({
1222							transition: BX.easing.transitions.linear,
1223							step: BX.delegate(function(state){
1224								this.obPictSliderProgressBar.style.width = state.width / 10 + '%';
1225							}, this)
1226						});
1227					}
1228				}
1229			}
1230		},
1231
1232		checkTouch: function(event)
1233		{
1234			if (!event || !event.changedTouches)
1235				return false;
1236
1237			return event.changedTouches[0].identifier === this.touch.identifier;
1238		},
1239
1240		touchStartEvent: function(event)
1241		{
1242			if (event.touches.length != 1)
1243				return;
1244
1245			this.touch = event.changedTouches[0];
1246		},
1247
1248		touchEndEvent: function(event)
1249		{
1250			if (!this.checkTouch(event))
1251				return;
1252
1253			var deltaX = this.touch.pageX - event.changedTouches[0].pageX,
1254				deltaY = this.touch.pageY - event.changedTouches[0].pageY;
1255
1256			if (Math.abs(deltaX) >= Math.abs(deltaY) + 10)
1257			{
1258				if (deltaX > 0)
1259				{
1260					this.slideNext();
1261				}
1262
1263				if (deltaX < 0)
1264				{
1265					this.slidePrev();
1266				}
1267			}
1268		},
1269
1270		sliderClickHandler: function(event)
1271		{
1272			var target = BX.getEventTarget(event),
1273				slideIndex = target.getAttribute('data-go-to');
1274
1275			if (slideIndex)
1276			{
1277				this.slideTo(slideIndex)
1278			}
1279
1280			BX.PreventDefault(event);
1281		},
1282
1283		slideNext: function()
1284		{
1285			if (this.slider.sliding)
1286				return;
1287
1288			return this.slide('next');
1289		},
1290
1291		slidePrev: function()
1292		{
1293			if (this.slider.sliding)
1294				return;
1295
1296			return this.slide('prev');
1297		},
1298
1299		slideTo: function(pos)
1300		{
1301			this.slider.active = BX.findChild(this.obPictSlider, {className: 'item active'}, true, false);
1302			this.slider.progress && (this.slider.interval = true);
1303
1304			var activeIndex = this.getItemIndex(this.slider.active);
1305
1306			if (pos > (this.slider.items.length - 1) || pos < 0)
1307				return;
1308
1309			if (this.slider.sliding)
1310				return false;
1311
1312			if (activeIndex == pos)
1313			{
1314				this.stopSlider();
1315				this.cycleSlider();
1316				return;
1317			}
1318
1319			return this.slide(pos > activeIndex ? 'next' : 'prev', this.eq(this.slider.items, pos));
1320		},
1321
1322		slide: function(type, next)
1323		{
1324			var active = BX.findChild(this.obPictSlider, {className: 'item active'}, true, false),
1325				isCycling = this.slider.interval,
1326				direction = type === 'next' ? 'left' : 'right';
1327
1328			next = next || this.getItemForDirection(type, active);
1329
1330			if (BX.hasClass(next, 'active'))
1331			{
1332				return (this.slider.sliding = false);
1333			}
1334
1335			this.slider.sliding = true;
1336
1337			isCycling && this.stopSlider();
1338
1339			if (this.obPictSliderIndicator)
1340			{
1341				BX.removeClass(this.obPictSliderIndicator.querySelector('.active'), 'active');
1342				var nextIndicator = this.obPictSliderIndicator.querySelectorAll('[data-go-to]')[this.getItemIndex(next)];
1343				nextIndicator && BX.addClass(nextIndicator, 'active');
1344			}
1345
1346			if (BX.hasClass(this.obPictSlider, 'slide') && !BX.browser.IsIE())
1347			{
1348				var self = this;
1349				BX.addClass(next, type);
1350				next.offsetWidth; // force reflow
1351				BX.addClass(active, direction);
1352				BX.addClass(next, direction);
1353				setTimeout(function() {
1354					BX.addClass(next, 'active');
1355					BX.removeClass(active, 'active');
1356					BX.removeClass(active, direction);
1357					BX.removeClass(next, type);
1358					BX.removeClass(next, direction);
1359					self.slider.sliding = false;
1360				}, 700);
1361			}
1362			else
1363			{
1364				BX.addClass(next, 'active');
1365				this.slider.sliding = false;
1366			}
1367
1368			this.obPictSliderProgressBar && this.resetProgress();
1369			isCycling && this.cycleSlider();
1370		},
1371
1372		stopSlider: function(event)
1373		{
1374			event || (this.slider.paused = true);
1375
1376			this.slider.interval && clearInterval(this.slider.interval);
1377
1378			if (this.slider.progress)
1379			{
1380				this.slider.progress.stop();
1381
1382				var width = parseInt(this.obPictSliderProgressBar.style.width);
1383
1384				this.slider.progress.options.duration = this.slider.options.interval * width / 200;
1385				this.slider.progress.options.start = {width: width * 10};
1386				this.slider.progress.options.finish = {width: 0};
1387				this.slider.progress.options.complete = null;
1388				this.slider.progress.animate();
1389			}
1390		},
1391
1392		cycleSlider: function(event)
1393		{
1394			event || (this.slider.paused = false);
1395
1396			this.slider.interval && clearInterval(this.slider.interval);
1397
1398			if (this.slider.options.interval && !this.slider.paused)
1399			{
1400				if (this.slider.progress)
1401				{
1402					this.slider.progress.stop();
1403
1404					var width = parseInt(this.obPictSliderProgressBar.style.width);
1405
1406					this.slider.progress.options.duration = this.slider.options.interval * (100 - width) / 100;
1407					this.slider.progress.options.start = {width: width * 10};
1408					this.slider.progress.options.finish = {width: 1000};
1409					this.slider.progress.options.complete = BX.delegate(function(){
1410						this.slider.interval = true;
1411						this.slideNext();
1412					}, this);
1413					this.slider.progress.animate();
1414				}
1415				else
1416				{
1417					this.slider.interval = setInterval(BX.proxy(this.slideNext, this), this.slider.options.interval);
1418				}
1419			}
1420		},
1421
1422		resetProgress: function()
1423		{
1424			this.slider.progress && this.slider.progress.stop();
1425			this.obPictSliderProgressBar.style.width = 0;
1426		},
1427
1428		getItemForDirection: function(direction, active)
1429		{
1430			var activeIndex = this.getItemIndex(active),
1431				willWrap = direction === 'prev' && activeIndex === 0
1432					|| direction === 'next' && activeIndex == (this.slider.items.length - 1);
1433
1434			if (willWrap && !this.slider.options.wrap)
1435				return active;
1436
1437			var delta = direction === 'prev' ? -1 : 1,
1438				itemIndex = (activeIndex + delta) % this.slider.items.length;
1439
1440			return this.eq(this.slider.items, itemIndex);
1441		},
1442
1443		getItemIndex: function(item)
1444		{
1445			this.slider.items = BX.findChildren(item.parentNode, {className: 'item'}, true);
1446
1447			return this.slider.items.indexOf(item || this.slider.active);
1448		},
1449
1450		eq: function(obj, i)
1451		{
1452			var len = obj.length,
1453				j = +i + (i < 0 ? len : 0);
1454
1455			return j >= 0 && j < len ? obj[j] : {};
1456		},
1457
1458		selectOfferProp: function()
1459		{
1460			var i = 0,
1461				value = '',
1462				strTreeValue = '',
1463				arTreeItem = [],
1464				rowItems = null,
1465				target = BX.proxy_context;
1466
1467			if (target && target.hasAttribute('data-treevalue'))
1468			{
1469				if (BX.hasClass(target, 'selected'))
1470					return;
1471
1472				strTreeValue = target.getAttribute('data-treevalue');
1473				arTreeItem = strTreeValue.split('_');
1474				if (this.searchOfferPropIndex(arTreeItem[0], arTreeItem[1]))
1475				{
1476					rowItems = BX.findChildren(target.parentNode, {tagName: 'li'}, false);
1477					if (rowItems && 0 < rowItems.length)
1478					{
1479						for (i = 0; i < rowItems.length; i++)
1480						{
1481							value = rowItems[i].getAttribute('data-onevalue');
1482							if (value === arTreeItem[1])
1483							{
1484								BX.addClass(rowItems[i], 'selected');
1485							}
1486							else
1487							{
1488								BX.removeClass(rowItems[i], 'selected');
1489							}
1490						}
1491					}
1492				}
1493			}
1494		},
1495
1496		searchOfferPropIndex: function(strPropID, strPropValue)
1497		{
1498			var strName = '',
1499				arShowValues = false,
1500				i, j,
1501				arCanBuyValues = [],
1502				allValues = [],
1503				index = -1,
1504				arFilter = {},
1505				tmpFilter = [];
1506
1507			for (i = 0; i < this.treeProps.length; i++)
1508			{
1509				if (this.treeProps[i].ID === strPropID)
1510				{
1511					index = i;
1512					break;
1513				}
1514			}
1515
1516			if (-1 < index)
1517			{
1518				for (i = 0; i < index; i++)
1519				{
1520					strName = 'PROP_'+this.treeProps[i].ID;
1521					arFilter[strName] = this.selectedValues[strName];
1522				}
1523				strName = 'PROP_'+this.treeProps[index].ID;
1524				arShowValues = this.getRowValues(arFilter, strName);
1525				if (!arShowValues)
1526				{
1527					return false;
1528				}
1529				if (!BX.util.in_array(strPropValue, arShowValues))
1530				{
1531					return false;
1532				}
1533				arFilter[strName] = strPropValue;
1534				for (i = index+1; i < this.treeProps.length; i++)
1535				{
1536					strName = 'PROP_'+this.treeProps[i].ID;
1537					arShowValues = this.getRowValues(arFilter, strName);
1538					if (!arShowValues)
1539					{
1540						return false;
1541					}
1542					allValues = [];
1543					if (this.showAbsent)
1544					{
1545						arCanBuyValues = [];
1546						tmpFilter = [];
1547						tmpFilter = BX.clone(arFilter, true);
1548						for (j = 0; j < arShowValues.length; j++)
1549						{
1550							tmpFilter[strName] = arShowValues[j];
1551							allValues[allValues.length] = arShowValues[j];
1552							if (this.getCanBuy(tmpFilter))
1553								arCanBuyValues[arCanBuyValues.length] = arShowValues[j];
1554						}
1555					}
1556					else
1557					{
1558						arCanBuyValues = arShowValues;
1559					}
1560					if (this.selectedValues[strName] && BX.util.in_array(this.selectedValues[strName], arCanBuyValues))
1561					{
1562						arFilter[strName] = this.selectedValues[strName];
1563					}
1564					else
1565					{
1566						if (this.showAbsent)
1567							arFilter[strName] = (arCanBuyValues.length > 0 ? arCanBuyValues[0] : allValues[0]);
1568						else
1569							arFilter[strName] = arCanBuyValues[0];
1570					}
1571					this.updateRow(i, arFilter[strName], arShowValues, arCanBuyValues);
1572				}
1573				this.selectedValues = arFilter;
1574				this.changeInfo();
1575			}
1576			return true;
1577		},
1578
1579		updateRow: function(intNumber, activeID, showID, canBuyID)
1580		{
1581			var i = 0,
1582				value = '',
1583				isCurrent = false,
1584				rowItems = null;
1585
1586			var lineContainer = this.obTree.querySelectorAll('[data-entity="sku-line-block"]'),
1587				listContainer;
1588
1589			if (intNumber > -1 && intNumber < lineContainer.length)
1590			{
1591				listContainer = lineContainer[intNumber].querySelector('ul');
1592				rowItems = BX.findChildren(listContainer, {tagName: 'li'}, false);
1593				if (rowItems && 0 < rowItems.length)
1594				{
1595					for (i = 0; i < rowItems.length; i++)
1596					{
1597						value = rowItems[i].getAttribute('data-onevalue');
1598						isCurrent = value === activeID;
1599
1600						if (isCurrent)
1601						{
1602							BX.addClass(rowItems[i], 'selected');
1603						}
1604						else
1605						{
1606							BX.removeClass(rowItems[i], 'selected');
1607						}
1608
1609						if (BX.util.in_array(value, canBuyID))
1610						{
1611							BX.removeClass(rowItems[i], 'notallowed');
1612						}
1613						else
1614						{
1615							BX.addClass(rowItems[i], 'notallowed');
1616						}
1617
1618						rowItems[i].style.display = BX.util.in_array(value, showID) ? '' : 'none';
1619
1620						if (isCurrent)
1621						{
1622							lineContainer[intNumber].style.display = (value == 0 && canBuyID.length == 1) ? 'none' : '';
1623						}
1624					}
1625				}
1626			}
1627		},
1628
1629		getRowValues: function(arFilter, index)
1630		{
1631			var i = 0,
1632				j,
1633				arValues = [],
1634				boolSearch = false,
1635				boolOneSearch = true;
1636
1637			if (0 === arFilter.length)
1638			{
1639				for (i = 0; i < this.offers.length; i++)
1640				{
1641					if (!BX.util.in_array(this.offers[i].TREE[index], arValues))
1642					{
1643						arValues[arValues.length] = this.offers[i].TREE[index];
1644					}
1645				}
1646				boolSearch = true;
1647			}
1648			else
1649			{
1650				for (i = 0; i < this.offers.length; i++)
1651				{
1652					boolOneSearch = true;
1653					for (j in arFilter)
1654					{
1655						if (arFilter[j] !== this.offers[i].TREE[j])
1656						{
1657							boolOneSearch = false;
1658							break;
1659						}
1660					}
1661					if (boolOneSearch)
1662					{
1663						if (!BX.util.in_array(this.offers[i].TREE[index], arValues))
1664						{
1665							arValues[arValues.length] = this.offers[i].TREE[index];
1666						}
1667						boolSearch = true;
1668					}
1669				}
1670			}
1671			return (boolSearch ? arValues : false);
1672		},
1673
1674		getCanBuy: function(arFilter)
1675		{
1676			var i, j,
1677				boolSearch = false,
1678				boolOneSearch = true;
1679
1680			for (i = 0; i < this.offers.length; i++)
1681			{
1682				boolOneSearch = true;
1683				for (j in arFilter)
1684				{
1685					if (arFilter[j] !== this.offers[i].TREE[j])
1686					{
1687						boolOneSearch = false;
1688						break;
1689					}
1690				}
1691				if (boolOneSearch)
1692				{
1693					if (this.offers[i].CAN_BUY)
1694					{
1695						boolSearch = true;
1696						break;
1697					}
1698				}
1699			}
1700
1701			return boolSearch;
1702		},
1703
1704		setCurrent: function()
1705		{
1706			var i,
1707				j = 0,
1708				arCanBuyValues = [],
1709				strName = '',
1710				arShowValues = false,
1711				arFilter = {},
1712				tmpFilter = [],
1713				current = this.offers[this.offerNum].TREE;
1714
1715			for (i = 0; i < this.treeProps.length; i++)
1716			{
1717				strName = 'PROP_'+this.treeProps[i].ID;
1718				arShowValues = this.getRowValues(arFilter, strName);
1719				if (!arShowValues)
1720				{
1721					break;
1722				}
1723				if (BX.util.in_array(current[strName], arShowValues))
1724				{
1725					arFilter[strName] = current[strName];
1726				}
1727				else
1728				{
1729					arFilter[strName] = arShowValues[0];
1730					this.offerNum = 0;
1731				}
1732				if (this.showAbsent)
1733				{
1734					arCanBuyValues = [];
1735					tmpFilter = [];
1736					tmpFilter = BX.clone(arFilter, true);
1737					for (j = 0; j < arShowValues.length; j++)
1738					{
1739						tmpFilter[strName] = arShowValues[j];
1740						if (this.getCanBuy(tmpFilter))
1741						{
1742							arCanBuyValues[arCanBuyValues.length] = arShowValues[j];
1743						}
1744					}
1745				}
1746				else
1747				{
1748					arCanBuyValues = arShowValues;
1749				}
1750				this.updateRow(i, arFilter[strName], arShowValues, arCanBuyValues);
1751			}
1752			this.selectedValues = arFilter;
1753			this.changeInfo();
1754		},
1755
1756		changeInfo: function()
1757		{
1758			var i, j,
1759				index = -1,
1760				boolOneSearch = true,
1761				quantityChanged;
1762
1763			for (i = 0; i < this.offers.length; i++)
1764			{
1765				boolOneSearch = true;
1766				for (j in this.selectedValues)
1767				{
1768					if (this.selectedValues[j] !== this.offers[i].TREE[j])
1769					{
1770						boolOneSearch = false;
1771						break;
1772					}
1773				}
1774				if (boolOneSearch)
1775				{
1776					index = i;
1777					break;
1778				}
1779			}
1780			if (index > -1)
1781			{
1782				if (parseInt(this.offers[index].MORE_PHOTO_COUNT) > 1 && this.obPictSlider)
1783				{
1784					// hide pict and second_pict containers
1785					if (this.obPict)
1786					{
1787						this.obPict.style.display = 'none';
1788					}
1789
1790					if (this.obSecondPict)
1791					{
1792						this.obSecondPict.style.display = 'none';
1793					}
1794
1795					// clear slider container
1796					BX.cleanNode(this.obPictSlider);
1797
1798					// fill slider container with slides
1799					for (i in this.offers[index].MORE_PHOTO)
1800					{
1801						if (this.offers[index].MORE_PHOTO.hasOwnProperty(i))
1802						{
1803							this.obPictSlider.appendChild(
1804								BX.create('SPAN', {
1805									props: {className: 'product-item-image-slide item' + (i == 0 ? ' active' : '')},
1806									style: {backgroundImage: 'url(\'' + this.offers[index].MORE_PHOTO[i].SRC + '\')'}
1807								})
1808							);
1809						}
1810					}
1811
1812					// fill slider indicator if exists
1813					if (this.obPictSliderIndicator)
1814					{
1815						BX.cleanNode(this.obPictSliderIndicator);
1816
1817						for (i in this.offers[index].MORE_PHOTO)
1818						{
1819							if (this.offers[index].MORE_PHOTO.hasOwnProperty(i))
1820							{
1821								this.obPictSliderIndicator.appendChild(
1822									BX.create('DIV', {
1823										attrs: {'data-go-to': i},
1824										props: {className: 'product-item-image-slider-control' + (i == 0 ? ' active' : '')}
1825									})
1826								);
1827								this.obPictSliderIndicator.appendChild(document.createTextNode(' '));
1828							}
1829						}
1830
1831						this.obPictSliderIndicator.style.display = '';
1832					}
1833
1834					if (this.obPictSliderProgressBar)
1835					{
1836						this.obPictSliderProgressBar.style.display = '';
1837					}
1838
1839					// show slider container
1840					this.obPictSlider.style.display = '';
1841					this.initializeSlider();
1842				}
1843				else
1844				{
1845					// hide slider container
1846					if (this.obPictSlider)
1847					{
1848						this.obPictSlider.style.display = 'none';
1849					}
1850
1851					if (this.obPictSliderIndicator)
1852					{
1853						this.obPictSliderIndicator.style.display = 'none';
1854					}
1855
1856					if (this.obPictSliderProgressBar)
1857					{
1858						this.obPictSliderProgressBar.style.display = 'none';
1859					}
1860
1861					// show pict and pict_second containers
1862					if (this.obPict)
1863					{
1864						if (this.offers[index].PREVIEW_PICTURE)
1865						{
1866							BX.adjust(this.obPict, {style: {backgroundImage: 'url(\'' + this.offers[index].PREVIEW_PICTURE.SRC + '\')'}});
1867						}
1868						else
1869						{
1870							BX.adjust(this.obPict, {style: {backgroundImage: 'url(\'' + this.defaultPict.pict.SRC + '\')'}});
1871						}
1872
1873						this.obPict.style.display = '';
1874					}
1875
1876					if (this.secondPict && this.obSecondPict)
1877					{
1878						if (this.offers[index].PREVIEW_PICTURE_SECOND)
1879						{
1880							BX.adjust(this.obSecondPict, {style: {backgroundImage: 'url(\'' + this.offers[index].PREVIEW_PICTURE_SECOND.SRC + '\')'}});
1881						}
1882						else if (this.offers[index].PREVIEW_PICTURE.SRC)
1883						{
1884							BX.adjust(this.obSecondPict, {style: {backgroundImage: 'url(\'' + this.offers[index].PREVIEW_PICTURE.SRC + '\')'}});
1885						}
1886						else if (this.defaultPict.secondPict)
1887						{
1888							BX.adjust(this.obSecondPict, {style: {backgroundImage: 'url(\'' + this.defaultPict.secondPict.SRC + '\')'}});
1889						}
1890						else
1891						{
1892							BX.adjust(this.obSecondPict, {style: {backgroundImage: 'url(\'' + this.defaultPict.pict.SRC + '\')'}});
1893						}
1894
1895						this.obSecondPict.style.display = '';
1896					}
1897				}
1898
1899				if (this.showSkuProps && this.obSkuProps)
1900				{
1901					if (this.offers[index].DISPLAY_PROPERTIES.length)
1902					{
1903						BX.adjust(this.obSkuProps, {style: {display: ''}, html: this.offers[index].DISPLAY_PROPERTIES});
1904					}
1905					else
1906					{
1907						BX.adjust(this.obSkuProps, {style: {display: 'none'}, html: ''});
1908					}
1909				}
1910
1911				this.quantitySet(index);
1912				this.setPrice();
1913				this.setCompared(this.offers[index].COMPARED);
1914
1915				this.offerNum = index;
1916			}
1917		},
1918
1919		checkPriceRange: function(quantity)
1920		{
1921			if (typeof quantity === 'undefined'|| this.currentPriceMode != 'Q')
1922				return;
1923
1924			var range, found = false;
1925
1926			for (var i in this.currentQuantityRanges)
1927			{
1928				if (this.currentQuantityRanges.hasOwnProperty(i))
1929				{
1930					range = this.currentQuantityRanges[i];
1931
1932					if (
1933						parseInt(quantity) >= parseInt(range.SORT_FROM)
1934						&& (
1935							range.SORT_TO == 'INF'
1936							|| parseInt(quantity) <= parseInt(range.SORT_TO)
1937						)
1938					)
1939					{
1940						found = true;
1941						this.currentQuantityRangeSelected = range.HASH;
1942						break;
1943					}
1944				}
1945			}
1946
1947			if (!found && (range = this.getMinPriceRange()))
1948			{
1949				this.currentQuantityRangeSelected = range.HASH;
1950			}
1951
1952			for (var k in this.currentPrices)
1953			{
1954				if (this.currentPrices.hasOwnProperty(k))
1955				{
1956					if (this.currentPrices[k].QUANTITY_HASH == this.currentQuantityRangeSelected)
1957					{
1958						this.currentPriceSelected = k;
1959						break;
1960					}
1961				}
1962			}
1963		},
1964
1965		getMinPriceRange: function()
1966		{
1967			var range;
1968
1969			for (var i in this.currentQuantityRanges)
1970			{
1971				if (this.currentQuantityRanges.hasOwnProperty(i))
1972				{
1973					if (
1974						!range
1975						|| parseInt(this.currentQuantityRanges[i].SORT_FROM) < parseInt(range.SORT_FROM)
1976					)
1977					{
1978						range = this.currentQuantityRanges[i];
1979					}
1980				}
1981			}
1982
1983			return range;
1984		},
1985
1986		checkQuantityControls: function()
1987		{
1988			if (!this.obQuantity)
1989				return;
1990
1991			var reachedTopLimit = this.checkQuantity && parseFloat(this.obQuantity.value) + this.stepQuantity > this.maxQuantity,
1992				reachedBottomLimit = parseFloat(this.obQuantity.value) - this.stepQuantity < this.minQuantity;
1993
1994			if (reachedTopLimit)
1995			{
1996				BX.addClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled');
1997			}
1998			else if (BX.hasClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled'))
1999			{
2000				BX.removeClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled');
2001			}
2002
2003			if (reachedBottomLimit)
2004			{
2005				BX.addClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled');
2006			}
2007			else if (BX.hasClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled'))
2008			{
2009				BX.removeClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled');
2010			}
2011
2012			if (reachedTopLimit && reachedBottomLimit)
2013			{
2014				this.obQuantity.setAttribute('disabled', 'disabled');
2015			}
2016			else
2017			{
2018				this.obQuantity.removeAttribute('disabled');
2019			}
2020		},
2021
2022		setPrice: function()
2023		{
2024			var obData, price;
2025
2026			if (this.obQuantity)
2027			{
2028				this.checkPriceRange(this.obQuantity.value);
2029			}
2030
2031			this.checkQuantityControls();
2032
2033			price = this.currentPrices[this.currentPriceSelected];
2034
2035			if (this.obPrice)
2036			{
2037				if (price)
2038				{
2039					BX.adjust(this.obPrice, {html: BX.Currency.currencyFormat(price.RATIO_PRICE, price.CURRENCY, true)});
2040				}
2041				else
2042				{
2043					BX.adjust(this.obPrice, {html: ''});
2044				}
2045
2046				if (this.showOldPrice && this.obPriceOld)
2047				{
2048					if (price && price.RATIO_PRICE !== price.RATIO_BASE_PRICE)
2049					{
2050						BX.adjust(this.obPriceOld, {
2051							style: {display: ''},
2052							html: BX.Currency.currencyFormat(price.RATIO_BASE_PRICE, price.CURRENCY, true)
2053						});
2054					}
2055					else
2056					{
2057						BX.adjust(this.obPriceOld, {
2058							style: {display: 'none'},
2059							html: ''
2060						});
2061					}
2062				}
2063
2064				if (this.obPriceTotal)
2065				{
2066					if (price && this.obQuantity && this.obQuantity.value != this.stepQuantity)
2067					{
2068						BX.adjust(this.obPriceTotal, {
2069							html: BX.message('PRICE_TOTAL_PREFIX') + ' <strong>'
2070							+ BX.Currency.currencyFormat(price.PRICE * this.obQuantity.value, price.CURRENCY, true)
2071							+ '</strong>',
2072							style: {display: ''}
2073						});
2074					}
2075					else
2076					{
2077						BX.adjust(this.obPriceTotal, {
2078							html: '',
2079							style: {display: 'none'}
2080						});
2081					}
2082				}
2083
2084				if (this.showPercent)
2085				{
2086					if (price && parseInt(price.DISCOUNT) > 0)
2087					{
2088						obData = {style: {display: ''}, html: -price.PERCENT + '%'};
2089					}
2090					else
2091					{
2092						obData = {style: {display: 'none'}, html: ''};
2093					}
2094
2095					if (this.obDscPerc)
2096					{
2097						BX.adjust(this.obDscPerc, obData);
2098					}
2099
2100					if (this.obSecondDscPerc)
2101					{
2102						BX.adjust(this.obSecondDscPerc, obData);
2103					}
2104				}
2105			}
2106		},
2107
2108		compare: function(event)
2109		{
2110			var checkbox = this.obCompare.querySelector('[data-entity="compare-checkbox"]'),
2111				target = BX.getEventTarget(event),
2112				checked = true;
2113
2114			if (checkbox)
2115			{
2116				checked = target === checkbox ? checkbox.checked : !checkbox.checked;
2117			}
2118
2119			var url = checked ? this.compareData.compareUrl : this.compareData.compareDeleteUrl,
2120				compareLink;
2121
2122			if (url)
2123			{
2124				if (target !== checkbox)
2125				{
2126					BX.PreventDefault(event);
2127					this.setCompared(checked);
2128				}
2129
2130				switch (this.productType)
2131				{
2132					case 0: // no catalog
2133					case 1: // product
2134					case 2: // set
2135						compareLink = url.replace('#ID#', this.product.id.toString());
2136						break;
2137					case 3: // sku
2138						compareLink = url.replace('#ID#', this.offers[this.offerNum].ID);
2139						break;
2140				}
2141
2142				BX.ajax({
2143					method: 'POST',
2144					dataType: checked ? 'json' : 'html',
2145					url: compareLink + (compareLink.indexOf('?') !== -1 ? '&' : '?') + 'ajax_action=Y',
2146					onsuccess: checked
2147						? BX.proxy(this.compareResult, this)
2148						: BX.proxy(this.compareDeleteResult, this)
2149				});
2150			}
2151		},
2152
2153		compareResult: function(result)
2154		{
2155			var popupContent, popupButtons;
2156
2157			if (this.obPopupWin)
2158			{
2159				this.obPopupWin.close();
2160			}
2161
2162			if (!BX.type.isPlainObject(result))
2163				return;
2164
2165			this.initPopupWindow();
2166
2167			if (this.offers.length > 0)
2168			{
2169				this.offers[this.offerNum].COMPARED = result.STATUS === 'OK';
2170			}
2171
2172			if (result.STATUS === 'OK')
2173			{
2174				BX.onCustomEvent('OnCompareChange');
2175
2176				popupContent = '<div style="width: 100%; margin: 0; text-align: center;"><p>'
2177					+ BX.message('COMPARE_MESSAGE_OK')
2178					+ '</p></div>';
2179
2180				if (this.showClosePopup)
2181				{
2182					popupButtons = [
2183						new BasketButton({
2184							text: BX.message('BTN_MESSAGE_COMPARE_REDIRECT'),
2185							events: {
2186								click: BX.delegate(this.compareRedirect, this)
2187							},
2188							style: {marginRight: '10px'}
2189						}),
2190						new BasketButton({
2191							text: BX.message('BTN_MESSAGE_CLOSE_POPUP'),
2192							events: {
2193								click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
2194							}
2195						})
2196					];
2197				}
2198				else
2199				{
2200					popupButtons = [
2201						new BasketButton({
2202							text: BX.message('BTN_MESSAGE_COMPARE_REDIRECT'),
2203							events: {
2204								click: BX.delegate(this.compareRedirect, this)
2205							}
2206						})
2207					];
2208				}
2209			}
2210			else
2211			{
2212				popupContent = '<div style="width: 100%; margin: 0; text-align: center;"><p>'
2213					+ (result.MESSAGE ? result.MESSAGE : BX.message('COMPARE_UNKNOWN_ERROR'))
2214					+ '</p></div>';
2215				popupButtons = [
2216					new BasketButton({
2217						text: BX.message('BTN_MESSAGE_CLOSE'),
2218						events: {
2219							click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
2220						}
2221					})
2222				];
2223			}
2224
2225			this.obPopupWin.setTitleBar(BX.message('COMPARE_TITLE'));
2226			this.obPopupWin.setContent(popupContent);
2227			this.obPopupWin.setButtons(popupButtons);
2228			this.obPopupWin.show();
2229		},
2230
2231		compareDeleteResult: function()
2232		{
2233			BX.onCustomEvent('OnCompareChange');
2234
2235			if (this.offers && this.offers.length)
2236			{
2237				this.offers[this.offerNum].COMPARED = false;
2238			}
2239		},
2240
2241		setCompared: function(state)
2242		{
2243			if (!this.obCompare)
2244				return;
2245
2246			var checkbox = this.obCompare.querySelector('[data-entity="compare-checkbox"]');
2247			if (checkbox)
2248			{
2249				checkbox.checked = state;
2250			}
2251		},
2252
2253		setCompareInfo: function(comparedIds)
2254		{
2255			if (!BX.type.isArray(comparedIds))
2256				return;
2257
2258			for (var i in this.offers)
2259			{
2260				if (this.offers.hasOwnProperty(i))
2261				{
2262					this.offers[i].COMPARED = BX.util.in_array(this.offers[i].ID, comparedIds);
2263				}
2264			}
2265		},
2266
2267		compareRedirect: function()
2268		{
2269			if (this.compareData.comparePath)
2270			{
2271				location.href = this.compareData.comparePath;
2272			}
2273			else
2274			{
2275				this.obPopupWin.close();
2276			}
2277		},
2278
2279		checkDeletedCompare: function(id)
2280		{
2281			switch (this.productType)
2282			{
2283				case 0: // no catalog
2284				case 1: // product
2285				case 2: // set
2286					if (this.product.id == id)
2287					{
2288						this.setCompared(false);
2289					}
2290
2291					break;
2292				case 3: // sku
2293					var i = this.offers.length;
2294					while (i--)
2295					{
2296						if (this.offers[i].ID == id)
2297						{
2298							this.offers[i].COMPARED = false;
2299
2300							if (this.offerNum == i)
2301							{
2302								this.setCompared(false);
2303							}
2304
2305							break;
2306						}
2307					}
2308			}
2309		},
2310
2311		initBasketUrl: function()
2312		{
2313			this.basketUrl = (this.basketMode === 'ADD' ? this.basketData.add_url : this.basketData.buy_url);
2314			switch (this.productType)
2315			{
2316				case 1: // product
2317				case 2: // set
2318					this.basketUrl = this.basketUrl.replace('#ID#', this.product.id.toString());
2319					break;
2320				case 3: // sku
2321					this.basketUrl = this.basketUrl.replace('#ID#', this.offers[this.offerNum].ID);
2322					break;
2323			}
2324			this.basketParams = {
2325				'ajax_basket': 'Y'
2326			};
2327			if (this.showQuantity)
2328			{
2329				this.basketParams[this.basketData.quantity] = this.obQuantity.value;
2330			}
2331			if (this.basketData.sku_props)
2332			{
2333				this.basketParams[this.basketData.sku_props_var] = this.basketData.sku_props;
2334			}
2335		},
2336
2337		fillBasketProps: function()
2338		{
2339			if (!this.visual.BASKET_PROP_DIV)
2340			{
2341				return;
2342			}
2343			var
2344				i = 0,
2345				propCollection = null,
2346				foundValues = false,
2347				obBasketProps = null;
2348
2349			if (this.basketData.useProps && !this.basketData.emptyProps)
2350			{
2351				if (this.obPopupWin && this.obPopupWin.contentContainer)
2352				{
2353					obBasketProps = this.obPopupWin.contentContainer;
2354				}
2355			}
2356			else
2357			{
2358				obBasketProps = BX(this.visual.BASKET_PROP_DIV);
2359			}
2360			if (obBasketProps)
2361			{
2362				propCollection = obBasketProps.getElementsByTagName('select');
2363				if (propCollection && propCollection.length)
2364				{
2365					for (i = 0; i < propCollection.length; i++)
2366					{
2367						if (!propCollection[i].disabled)
2368						{
2369							switch (propCollection[i].type.toLowerCase())
2370							{
2371								case 'select-one':
2372									this.basketParams[propCollection[i].name] = propCollection[i].value;
2373									foundValues = true;
2374									break;
2375								default:
2376									break;
2377							}
2378						}
2379					}
2380				}
2381				propCollection = obBasketProps.getElementsByTagName('input');
2382				if (propCollection && propCollection.length)
2383				{
2384					for (i = 0; i < propCollection.length; i++)
2385					{
2386						if (!propCollection[i].disabled)
2387						{
2388							switch (propCollection[i].type.toLowerCase())
2389							{
2390								case 'hidden':
2391									this.basketParams[propCollection[i].name] = propCollection[i].value;
2392									foundValues = true;
2393									break;
2394								case 'radio':
2395									if (propCollection[i].checked)
2396									{
2397										this.basketParams[propCollection[i].name] = propCollection[i].value;
2398										foundValues = true;
2399									}
2400									break;
2401								default:
2402									break;
2403							}
2404						}
2405					}
2406				}
2407			}
2408			if (!foundValues)
2409			{
2410				this.basketParams[this.basketData.props] = [];
2411				this.basketParams[this.basketData.props][0] = 0;
2412			}
2413		},
2414
2415		add2Basket: function()
2416		{
2417			this.basketMode = 'ADD';
2418			this.basket();
2419		},
2420
2421		buyBasket: function()
2422		{
2423			this.basketMode = 'BUY';
2424			this.basket();
2425		},
2426
2427		sendToBasket: function()
2428		{
2429			if (!this.canBuy)
2430			{
2431				return;
2432			}
2433
2434			// check recommendation
2435			if (this.product && this.product.id && this.bigData)
2436			{
2437				this.rememberProductRecommendation();
2438			}
2439
2440			this.initBasketUrl();
2441			this.fillBasketProps();
2442			BX.ajax({
2443				method: 'POST',
2444				dataType: 'json',
2445				url: this.basketUrl,
2446				data: this.basketParams,
2447				onsuccess: BX.proxy(this.basketResult, this)
2448			});
2449		},
2450
2451		basket: function()
2452		{
2453			var contentBasketProps = '';
2454			if (!this.canBuy)
2455			{
2456				return;
2457			}
2458			switch (this.productType)
2459			{
2460				case 1: // product
2461				case 2: // set
2462					if (this.basketData.useProps && !this.basketData.emptyProps)
2463					{
2464						this.initPopupWindow();
2465						this.obPopupWin.setTitleBar(BX.message('TITLE_BASKET_PROPS'));
2466						if (BX(this.visual.BASKET_PROP_DIV))
2467						{
2468							contentBasketProps = BX(this.visual.BASKET_PROP_DIV).innerHTML;
2469						}
2470						this.obPopupWin.setContent(contentBasketProps);
2471						this.obPopupWin.setButtons([
2472							new BasketButton({
2473								text: BX.message('BTN_MESSAGE_SEND_PROPS'),
2474								events: {
2475									click: BX.delegate(this.sendToBasket, this)
2476								}
2477							})
2478						]);
2479						this.obPopupWin.show();
2480					}
2481					else
2482					{
2483						this.sendToBasket();
2484					}
2485					break;
2486				case 3: // sku
2487					this.sendToBasket();
2488					break;
2489			}
2490		},
2491
2492		basketResult: function(arResult)
2493		{
2494			var strContent = '',
2495				strPict = '',
2496				successful,
2497				buttons = [];
2498
2499			if (this.obPopupWin)
2500				this.obPopupWin.close();
2501
2502			if (!BX.type.isPlainObject(arResult))
2503				return;
2504
2505			successful = arResult.STATUS === 'OK';
2506
2507			if (successful)
2508			{
2509				this.setAnalyticsDataLayer('addToCart');
2510			}
2511
2512			if (successful && this.basketAction === 'BUY')
2513			{
2514				this.basketRedirect();
2515			}
2516			else
2517			{
2518				this.initPopupWindow();
2519
2520				if (successful)
2521				{
2522					BX.onCustomEvent('OnBasketChange');
2523
2524					if  (BX.findParent(this.obProduct, {className: 'bx_sale_gift_main_products'}, 10))
2525					{
2526						BX.onCustomEvent('onAddToBasketMainProduct', [this]);
2527					}
2528
2529					switch (this.productType)
2530					{
2531						case 1: // product
2532						case 2: // set
2533							strPict = this.product.pict.SRC;
2534							break;
2535						case 3: // sku
2536							strPict = (this.offers[this.offerNum].PREVIEW_PICTURE ?
2537									this.offers[this.offerNum].PREVIEW_PICTURE.SRC :
2538									this.defaultPict.pict.SRC
2539							);
2540							break;
2541					}
2542
2543					strContent = '<div style="width: 100%; margin: 0; text-align: center;"><img src="'
2544						+ strPict + '" height="130" style="max-height:130px"><p>' + this.product.name + '</p></div>';
2545
2546					if (this.showClosePopup)
2547					{
2548						buttons = [
2549							new BasketButton({
2550								text: BX.message("BTN_MESSAGE_BASKET_REDIRECT"),
2551								events: {
2552									click: BX.delegate(this.basketRedirect, this)
2553								},
2554								style: {marginRight: '10px'}
2555							}),
2556							new BasketButton({
2557								text: BX.message("BTN_MESSAGE_CLOSE_POPUP"),
2558								events: {
2559									click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
2560								}
2561							})
2562						];
2563					}
2564					else
2565					{
2566						buttons = [
2567							new BasketButton({
2568								text: BX.message("BTN_MESSAGE_BASKET_REDIRECT"),
2569								events: {
2570									click: BX.delegate(this.basketRedirect, this)
2571								}
2572							})
2573						];
2574					}
2575				}
2576				else
2577				{
2578					strContent = '<div style="width: 100%; margin: 0; text-align: center;"><p>'
2579						+ (arResult.MESSAGE ? arResult.MESSAGE : BX.message('BASKET_UNKNOWN_ERROR'))
2580						+ '</p></div>';
2581					buttons = [
2582						new BasketButton({
2583							text: BX.message('BTN_MESSAGE_CLOSE'),
2584							events: {
2585								click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
2586							}
2587						})
2588					];
2589				}
2590				this.obPopupWin.setTitleBar(successful ? BX.message('TITLE_SUCCESSFUL') : BX.message('TITLE_ERROR'));
2591				this.obPopupWin.setContent(strContent);
2592				this.obPopupWin.setButtons(buttons);
2593				this.obPopupWin.show();
2594			}
2595		},
2596
2597		basketRedirect: function()
2598		{
2599			location.href = (this.basketData.basketUrl ? this.basketData.basketUrl : BX.message('BASKET_URL'));
2600		},
2601
2602		initPopupWindow: function()
2603		{
2604			if (this.obPopupWin)
2605				return;
2606
2607			this.obPopupWin = BX.PopupWindowManager.create('CatalogSectionBasket_' + this.visual.ID, null, {
2608				autoHide: true,
2609				offsetLeft: 0,
2610				offsetTop: 0,
2611				overlay : true,
2612				closeByEsc: true,
2613				titleBar: true,
2614				closeIcon: true,
2615				contentColor: 'white',
2616				className: this.templateTheme ? 'bx-' + this.templateTheme : ''
2617			});
2618		}
2619	};
2620})(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.