PageSourceSearch

https://avto-trakt.ru/local/templates/at_2024/components/bitrix/ca…/bootstrap_v4/script.js?173676912666682

js avto-trakt.ru collected 2026-10-01 14:33:21 UTC 66,682 bytes, 2,764 lines download raw bytes

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