PageSourceSearch

https://kraskitula.ru/bitrix/templates/starservice/components/bitrix/catalog.item/tcatitem/script.js

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