PageSourceSearch

https://www.hqprofiline.ru/local/templates/main/components/bitrix/…/basket/js/component.js?164302108965412

js hqprofiline.ru collected 2026-10-08 10:36:49 UTC 65,412 bytes, 2,506 lines download raw bytes

1;(function() {
2	'use strict';
3
4	BX.namespace('BX.Sale.BasketComponent');
5
6	BX.Sale.BasketComponent = {
7		isMobile: BX.browser.IsMobile(),
8		isTouch: BX.hasClass(document.documentElement, 'bx-touch'),
9		lastAction: 'initialLoad',
10		maxItemsShowCount: 30,
11
12		precisionFactor: Math.pow(10, 6),
13
14		quantityDelay: null,
15		quantityTimer: null,
16
17		stickyHeaderOffset: 0,
18
19		duration: {
20			priceAnimation: 300,
21			filterTimer: 300
22		},
23
24		imagePopup: null,
25		loadingScreen: null,
26
27		templates: {},
28		nodes: {},
29
30		/** Object of all basket items (itemId => itemArray) */
31		items: {},
32
33		/** Array of all basket items to show sorted by field SORT */
34		sortedItems: [],
35
36		/** Array of basket items showed on screen */
37		shownItems: [],
38
39		/** Array of basket items changed since last request */
40		changedItems: [],
41
42		/** Array of basket items postponed by pool to edit */
43		postponedItems: [],
44
45		/** Array of basket items with warnings */
46		warningItems: [],
47
48		ids: {
49			item: 'basket-item-',
50			quantity: 'basket-item-quantity-',
51			price: 'basket-item-price-',
52			sumPrice: 'basket-item-sum-price-',
53			sumPriceOld: 'basket-item-sum-price-old-',
54			sumPriceDiff: 'basket-item-sum-price-difference-',
55			itemHeightAligner: 'basket-item-height-aligner-',
56			total: 'basket-total-price',
57			basketRoot: 'basket-root',
58			itemListWrapper: 'basket-items-list-wrapper',
59			itemListContainer: 'basket-items-list-container',
60			itemList: 'basket-item-list',
61			itemListTable: 'basket-item-table',
62			itemListEmptyResult: 'basket-item-list-empty-result',
63			itemListOverlay: 'basket-items-list-overlay',
64			warning: 'basket-warning'
65		},
66
67		init: function(parameters)
68		{
69			this.params = parameters.params || {};
70			this.template = parameters.template || '';
71			this.signedParamsString = parameters.signedParamsString || '';
72			this.siteId = parameters.siteId || '';
73			this.ajaxUrl = parameters.ajaxUrl || '';
74			this.templateFolder = parameters.templateFolder || '';
75
76			this.useDynamicScroll = this.params.USE_DYNAMIC_SCROLL === 'Y';
77			this.useItemsFilter = this.params.SHOW_FILTER === 'Y' && !this.isMobile;
78
79			this.initializeFilter();
80			this.applyBasketResult(parameters.result);
81			this.initializeActionPool();
82
83			if (this.useItemsFilter)
84			{
85				this.checkHeaderDisplay();
86				this.bindHeaderEvents();
87			}
88
89			this.initializeBasketItems();
90			this.editTotal();
91			this.editWarnings();
92
93			this.adjustBasketWrapperHeight();
94			this.getCacheNode(this.ids.basketRoot).style.opacity = 1;
95
96			this.bindInitialEvents();
97		},
98
99		getTemplate: function(templateName)
100		{
101			if (!this.templates.hasOwnProperty(templateName))
102			{
103				var template = BX(templateName);
104				this.templates[templateName] = BX.type.isDomNode(template) ? template.innerHTML : '';
105			}
106
107			return this.templates[templateName];
108		},
109
110		getCacheNode: function(id)
111		{
112			if (!this.nodes.hasOwnProperty(id))
113			{
114				this.nodes[id] = BX(id);
115			}
116
117			return this.nodes[id];
118		},
119
120		getEntity: function(parent, entity, additionalFilter)
121		{
122			if (!parent || !entity)
123				return null;
124
125			additionalFilter = additionalFilter || '';
126
127			return parent.querySelector(additionalFilter + '[data-entity="' + entity + '"]');
128		},
129
130		getEntities: function(parent, entity, additionalFilter)
131		{
132			if (!parent || !entity)
133				return {length: 0};
134
135			additionalFilter = additionalFilter || '';
136
137			return parent.querySelectorAll(additionalFilter + '[data-entity="' + entity + '"]');
138		},
139
140		bindInitialEvents: function()
141		{
142			this.bindWarningEvents();
143			/* BUG on scroll */
144			/*BX.bind(window, 'scroll', BX.proxy(this.checkStickyHeaders, this));
145			BX.bind(window, 'scroll', BX.proxy(this.lazyLoad, this));
146
147			BX.bind(window, 'resize', BX.throttle(this.checkStickyHeaders, 20, this));
148			BX.bind(window, 'resize', BX.throttle(this.adjustBasketWrapperHeight, 20, this));*/
149		},
150
151		bindWarningEvents: function()
152		{
153			var showItemsNode = this.getEntity(BX(this.ids.warning), 'basket-items-warning-count');
154
155			if (BX.type.isDomNode(showItemsNode))
156			{
157				showItemsNode.style.display = '';
158				BX.bind(showItemsNode, 'click', BX.delegate(function() {this.toggleFilter('warning');}, this));
159			}
160
161			BX.bind(
162				this.getEntity(BX(this.ids.warning), 'basket-items-warning-notification-close'),
163				'click',
164				BX.proxy(this.removeAllWarnings, this)
165			);
166		},
167
168		toggleFilter: function(event)
169		{
170			var target = BX.type.isNotEmptyString(event) ?
171				this.getEntity(
172					this.getCacheNode(this.ids.itemListWrapper),
173					'basket-items-count',
174					'[data-filter="' + event + '"]'
175				)
176				: BX.getEventTarget(event);
177
178			if (!BX.type.isDomNode(target) || BX.hasClass(target, 'active'))
179				return;
180
181			var entityName = target.getAttribute('data-filter');
182			var entities = target.parentNode.querySelectorAll('[data-filter]');
183
184			for (var i = 0; i < entities.length; i++)
185			{
186				if (entities[i].getAttribute('data-filter') === entityName)
187				{
188					BX.addClass(entities[i], 'active');
189				}
190				else if (BX.hasClass(entities[i], 'active'))
191				{
192					BX.removeClass(entities[i], 'active');
193				}
194			}
195
196			this.filter.showFilterByName(entityName);
197		},
198
199		scrollToFirstItem: function()
200		{
201			var headerNode = this.getEntity(this.getCacheNode(this.ids.itemListWrapper), 'basket-items-list-header');
202
203			if (BX.type.isDomNode(headerNode))
204			{
205				var itemListTopPosition = BX.pos(this.getCacheNode(this.ids.itemListContainer)).top;
206				var headerBottomPosition = BX.pos(headerNode).bottom;
207
208				if (itemListTopPosition < headerBottomPosition)
209				{
210					window.scrollTo(0, itemListTopPosition - this.stickyHeaderOffset);
211				}
212			}
213		},
214
215		showItemsOverlay: function()
216		{
217			var overlay = this.getCacheNode(this.ids.itemListOverlay);
218
219			if (BX.type.isDomNode(overlay))
220			{
221				overlay.style.display = '';
222			}
223		},
224
225		hideItemsOverlay: function()
226		{
227			var overlay = this.getCacheNode(this.ids.itemListOverlay);
228
229			if (BX.type.isDomNode(overlay))
230			{
231				overlay.style.display = 'none';
232			}
233		},
234
235		checkHeaderDisplay: function()
236		{
237			var header = this.getCacheNode(this.ids.itemListWrapper);
238
239			if (BX.type.isDomNode(header))
240			{
241				BX.removeClass(header, 'basket-items-list-wrapper-light');
242			}
243		},
244
245		bindHeaderEvents: function()
246		{
247			var entities = this.getEntities(this.getCacheNode(this.ids.itemListWrapper), 'basket-items-count');
248
249			for (var i = 0; i < entities.length; i++)
250			{
251				BX.bind(entities[i], 'click', BX.proxy(this.toggleFilter, this));
252			}
253		},
254
255		checkStickyHeaders: function()
256		{
257		    return;
258			if (this.isMobile)
259				return;
260
261			var node, position;
262			var border = 2, offset = 0;
263			var scrollTop = this.getDocumentScrollTop();
264			var basketPosition = BX.pos(this.getCacheNode(this.ids.basketRoot));
265			var basketScrolledToEnd = scrollTop + 200 >= basketPosition.bottom;
266
267			if (BX.util.in_array('top', this.params.TOTAL_BLOCK_DISPLAY))
268			{
269				var totalBlockNode = this.getEntity(this.getCacheNode(this.ids.basketRoot), 'basket-total-block');
270				if (BX.type.isDomNode(totalBlockNode))
271				{
272					node = this.getEntity(totalBlockNode, 'basket-checkout-aligner');
273					if (BX.type.isDomNode(node))
274					{
275						position = BX.pos(totalBlockNode);
276
277						if (scrollTop >= position.top)
278						{
279							offset += node.clientHeight;
280
281							if (!BX.hasClass(node, 'basket-checkout-container-fixed'))
282							{
283								totalBlockNode.style.height = position.height + 'px';
284
285								node.style.width = node.clientWidth + border + 'px';
286								BX.addClass(node, 'basket-checkout-container-fixed');
287							}
288						}
289						else if (BX.hasClass(node, 'basket-checkout-container-fixed'))
290						{
291							totalBlockNode.style.height = '';
292
293							node.style.width = '';
294							BX.removeClass(node, 'basket-checkout-container-fixed');
295						}
296
297						if (basketScrolledToEnd)
298						{
299							if (!BX.hasClass(node, 'basket-checkout-container-fixed-hide'))
300							{
301								BX.addClass(node, 'basket-checkout-container-fixed-hide');
302							}
303						}
304						else if (BX.hasClass(node, 'basket-checkout-container-fixed-hide'))
305						{
306							BX.removeClass(node, 'basket-checkout-container-fixed-hide');
307						}
308					}
309				}
310			}
311
312			if (this.useItemsFilter)
313			{
314				var itemWrapperNode = this.getCacheNode(this.ids.itemListWrapper);
315
316				node = this.getEntity(itemWrapperNode, 'basket-items-list-header');
317				if (BX.type.isDomNode(node))
318				{
319					position = BX.pos(itemWrapperNode);
320
321					if ((scrollTop + offset >= position.top) && !basketScrolledToEnd)
322					{
323						if (!BX.hasClass(node, 'basket-items-list-header-fixed'))
324						{
325							node.style.width = node.clientWidth + border + 'px';
326
327							itemWrapperNode.style.paddingTop = node.clientHeight + 'px';
328
329							BX.addClass(node, 'basket-items-list-header-fixed');
330						}
331
332						if (offset)
333						{
334							node.style.top = offset + 'px';
335						}
336
337						offset += node.clientHeight;
338					}
339					else if (BX.hasClass(node, 'basket-items-list-header-fixed'))
340					{
341						itemWrapperNode.style.paddingTop = '';
342
343						node.style.width = '';
344						node.style.top = '';
345
346						BX.removeClass(node, 'basket-items-list-header-fixed');
347					}
348				}
349			}
350
351			var offsetChanged = this.stickyHeaderOffset === offset;
352
353			this.stickyHeaderOffset = offset;
354
355			if (offsetChanged && !basketScrolledToEnd)
356			{
357				this.adjustBasketWrapperHeight();
358			}
359		},
360
361		getDocumentScrollTop: function()
362		{
363			return window.scrollY
364				|| window.pageYOffset
365				|| document.body.scrollTop + (document.documentElement && document.documentElement.scrollTop || 0);
366		},
367
368		lazyLoad: function()
369		{
370			var itemsNodePosition = BX.pos(this.getCacheNode(this.ids.itemListContainer));
371
372			if (this.getDocumentScrollTop() + window.innerHeight >= itemsNodePosition.bottom - 400)
373			{
374				var itemIds = this.getItemsAfter();
375				if (itemIds.length)
376				{
377					this.editBasketItems(itemIds);
378				}
379			}
380		},
381
382		fireCustomEvents: function()
383		{
384			if (this.result.EVENT_ONCHANGE_ON_START === 'Y')
385			{
386				BX.onCustomEvent('OnBasketChange');
387			}
388
389			if (this.result.GIFTS_RELOAD)
390			{
391				// ToDo call some event for gifts reload
392			}
393		},
394
395		adjustBasketWrapperHeight: function()
396		{
397			var itemListContainer = this.getCacheNode(this.ids.itemListContainer),
398				itemList = this.getCacheNode(this.ids.itemList);
399
400			if (BX.type.isDomNode(itemListContainer) && BX.type.isDomNode(itemList))
401			{
402				if (itemListContainer.clientHeight + this.stickyHeaderOffset > window.innerHeight)
403				{
404					itemListContainer.style.minHeight = 'calc(100vh - 15px - ' + this.stickyHeaderOffset + 'px)';
405					itemList.style.minHeight = 'calc(100vh - 15px - ' + this.stickyHeaderOffset + 'px)';
406				}
407				else
408				{
409					itemListContainer.style.minHeight = itemListContainer.clientHeight + 'px';
410					itemList.style.minHeight = itemListContainer.clientHeight + 'px';
411				}
412			}
413		},
414
415		editTotal: function()
416		{
417			this.fillTotalBlocks();
418			this.showItemsCount();
419			this.showWarningItemsCount();
420			this.showNotAvailableItemsCount();
421			this.showDelayedItemsCount();
422			this.addInitPopapform();
423		},
424
425		addInitPopapform: function() {
426			var popapForm = '';
427			jQuery('a.cart-submit__button').on('click', function () {
428				if(!popapForm) {
429					popapForm = new app.Popup(this);
430					popapForm.open();
431				} else {
432					popapForm.open();
433				}
434			});
435		},
436
437		fillTotalBlocks: function()
438		{
439			var totalNodes = this.getEntities(this.getCacheNode(this.ids.basketRoot), 'basket-total-block');
440
441			if (totalNodes && totalNodes.length)
442			{
443				var totalTemplate = this.getTemplate('basket-total-template');
444				if (totalTemplate)
445				{
446					var totalRender = this.render(totalTemplate, this.result.TOTAL_RENDER_DATA);
447
448					for (var i in totalNodes)
449					{
450						if (totalNodes.hasOwnProperty(i) && BX.type.isDomNode(totalNodes[i])
450)
451						{
452							totalNodes[i].innerHTML = totalRender;
453
454							this.bindTotalEvents(totalNodes[i]);
455						}
456					}
457				}
458			}
459
460			/* BUG on scroll */
461			//this.checkStickyHeaders();
462		},
463
464		showItemsCount: function()
465		{
466			var itemCountNode = this.getEntity(
467				this.getCacheNode(this.ids.itemListWrapper),
468				'basket-items-count',
469				'[data-filter="all"]'
470			);
471
472			if (BX.type.isDomNode(itemCountNode))
473			{
474				itemCountNode.innerHTML = BX.message('SBB_IN_BASKET') + ' ' + this.result.BASKET_ITEMS_COUNT + ' ' + this.getGoodsMessage(this.result.BASKET_ITEMS_COUNT);
475				itemCountNode.style.display = '';
476			}
477		},
478
479		showSimilarCount: function(state)
480		{
481			var itemCountNode = this.getEntity(
482				this.getCacheNode(this.ids.itemListWrapper),
483				'basket-items-count',
484				'[data-filter="similar"]'
485			);
486
487			if (BX.type.isDomNode(itemCountNode))
488			{
489				if (state)
490				{
491					itemCountNode.innerHTML = this.sortedItems.length + ' '
492						+ this.getGoodsMessage(this.result.BASKET_ITEMS_COUNT, 'SBB_SIMILAR_ITEM');
493					itemCountNode.style.display = '';
494				}
495				else
496				{
497					itemCountNode.style.display = 'none';
498				}
499			}
500		},
501
502		showWarningItemsCount: function()
503		{
504			var itemCountNode = this.getEntity(
505				this.getCacheNode(this.ids.itemListWrapper),
506				'basket-items-count',
507				'[data-filter="warning"]'
508			);
509
510			if (BX.type.isDomNode(itemCountNode))
511			{
512				if (this.warningItems.length)
513				{
514					itemCountNode.innerHTML = this.warningItems.length + ' ' + BX.message('SBB_BASKET_ITEMS_WARNING');
515					itemCountNode.style.display = '';
516				}
517				else
518				{
519					itemCountNode.style.display = 'none';
520				}
521			}
522		},
523
524		showNotAvailableItemsCount: function()
525		{
526			var itemCountNode = this.getEntity(
527				this.getCacheNode(this.ids.itemListWrapper),
528				'basket-items-count',
529				'[data-filter="not-available"]'
530			);
531
532			if (BX.type.isDomNode(itemCountNode))
533			{
534				if (parseInt(this.result.NOT_AVAILABLE_BASKET_ITEMS_COUNT))
535				{
536					itemCountNode.innerHTML = this.result.NOT_AVAILABLE_BASKET_ITEMS_COUNT + ' '
537						+ this.getGoodsMessage(this.result.NOT_AVAILABLE_BASKET_ITEMS_COUNT, 'SBB_NOT_AVAILABLE_ITEM');
538					itemCountNode.style.display = '';
539				}
540				else
541				{
542					itemCountNode.style.display = 'none';
543				}
544			}
545		},
546
547		showDelayedItemsCount: function()
548		{
549			var itemCountNode = this.getEntity(
550				this.getCacheNode(this.ids.itemListWrapper),
551				'basket-items-count',
552				'[data-filter="delayed"]'
553			);
554
555			if (BX.type.isDomNode(itemCountNode))
556			{
557				if (parseInt(this.result.DELAYED_BASKET_ITEMS_COUNT))
558				{
559					itemCountNode.innerHTML = this.result.DELAYED_BASKET_ITEMS_COUNT + ' '
560						+ this.getGoodsMessage(this.result.DELAYED_BASKET_ITEMS_COUNT, 'SBB_DELAYED_ITEM');
561					itemCountNode.style.display = '';
562				}
563				else
564				{
565					itemCountNode.style.display = 'none';
566				}
567			}
568		},
569
570		getGoodsMessage: function(count, customMessage)
571		{
572			var mesCode;
573			var countReminder = (count > 10 && count < 20) ? 0 : count % 10;
574
575			if (countReminder === 1)
576			{
577				mesCode = customMessage || 'SBB_GOOD';
578			}
579			else if (countReminder >= 2 && countReminder <= 4)
580			{
581				mesCode = customMessage ? customMessage + '_2' : 'SBB_GOOD_2';
582			}
583			else
584			{
585				mesCode = customMessage ? customMessage + 'S' : 'SBB_GOODS';
586			}
587
588			return BX.message(mesCode);
589		},
590
591		bindTotalEvents: function(node)
592		{
593			// if (!this.result.TOTAL_RENDER_DATA.DISABLE_CHECKOUT) {
594			// 	BX.bind(this.getEntity(node, 'basket-checkout-button'), 'click', BX.proxy(this.checkOutAction, this));
595			// }
596
597			BX.bind(this.getEntity(node, 'basket-coupon-input'), 'change', BX.proxy(this.addCouponAction, this));
598			BX.bind(this.getEntity(node, 'basket-coupon-input'), 'paste', BX.proxy(this.pasteCouponAction, this));
599
600			var couponNodes = this.getEntities(node, 'basket-coupon-delete');
601			for (var i = 0, l = couponNodes.length; i < l; i++)
602			{
603				BX.bind(couponNodes[i], 'click', BX.proxy(this.removeCouponAction, this));
604			}
605
606		},
607
608		checkOutAction: function()
609		{
610			document.location.href = this.params.PATH_TO_ORDER;
611		},
612
613		addCouponAction: function(event)
614		{
615			var target = BX.getEventTarget(event);
616			if (target && target.value)
617			{
618				this.actionPool.addCoupon(target.value);
619				target.disabled = true;
620			}
621		},
622
623		pasteCouponAction: function(event)
624		{
625			setTimeout(BX.delegate(function() {
626				this.addCouponAction(event);
627			}, this), 10);
628		},
629
630		removeCouponAction: function()
631		{
632			var value = BX.proxy_context && BX.util.trim(BX.proxy_context.getAttribute('data-coupon'));
633			if (value)
634			{
635				this.actionPool.removeCoupon(value);
636			}
637		},
638
639		initializeActionPool: function()
640		{
641			this.actionPool = new BX.Sale.BasketActionPool(this);
642		},
643
644		initializeFilter: function()
645		{
646			this.filter = new BX.Sale.BasketFilter(this);
647		},
648
649		/**
650		 * Send ajax request with basket data and executes callback by action
651		 */
652		sendRequest: function(action, data)
653		{
654			this.lastAction = action;
655
656			if (this.lastAction === 'recalculateAjax')
657			{
658				// we use it to reload all items if applied discounts changed
659				data.lastAppliedDiscounts = BX.util.array_keys(this.result.FULL_DISCOUNT_LIST).join(',');
660
661				if (this.params.USE_ENHANCED_ECOMMERCE === 'Y')
662				{
663					this.checkAnalytics(data);
664				}
665			}
666
667			var keys = Object.keys(data.basket);
668			if(keys[0]) {
669				var el_id = keys[0].split('_');
670				var is_del = (el_id[0] == 'DELETE') ? true : false;
671
672				el_id = el_id[1];
673
674				if(el_id) {
675					var el = $(document).find('#basket-item-' + el_id)[0];
676					var product_data = (el && el.dataset.product) ? el.dataset.product : '';
677					var action = (is_del) ? 'remove' : 'add';
678					var newVal = data.basket[keys[0]];
679
680					if(product_data) {
681						product_data = JSON.parse(product_data);
682						var oldVal = product_data.quantity_old;
683
684						if(!is_del) {
685							if(oldVal < newVal) {
686								product_data.quantity = newVal - oldVal;
687							} else {
688								action = 'remove';
689								product_data.quantity = oldVal - newVal;
690							}
691						} else {
692							product_data.quantity = oldVal;
693						}
694						//setDataLayer(action, product_data);
695					}
696				}
697			}
698
699			BX.ajax({
700				method: 'POST',
701				dataType: 'json',
702				url: this.ajaxUrl,
703				data: this.getData(data),
704				onsuccess: BX.delegate(function(result) {
705					this.actionPool.doProcessing(false);
706
707					if (!BX.type.isPlainObject(result))
708						return;
709
710					this.actionPool.setRefreshStatus(result.BASKET_REFRESHED);
711
712					if (result.RESTORED_BASKET_ITEMS)
713					{
714						this.restoreBasketItems(result.RESTORED_BASKET_ITEMS);
715					}
716
717					if (result.DELETED_BASKET_ITEMS)
718					{
719						this.deleteBasketItems(result.DELETED_BASKET_ITEMS, this.params.SHOW_RESTORE === 'Y');
720					}
721
722					if (result.MERGED_BASKET_ITEMS)
723					{
724						this.deleteBasketItems(result.MERGED_BASKET_ITEMS, false, true);
725					}
726
727					this.applyBasketResult(result.BASKET_DATA);
728					this.editBasketItems(this.getItemsToEdit());
729					this.editTotal();
730
731					this.adjustBasketWrapperHeight();
732					this.applyPriceAnimation();
733					this.editWarnings();
734
735					this.actionPool.switchTimer();
736
737					if (this.isBasketIntegrated() && this.isBasketChanged())
738					{
739						BX.Sale.OrderAjaxComponent.sendRequest();
740					}
741				}, this),
742				onfailure: BX.delegate(function() {
743					this.actionPool.doProcessing(false);
744				}, this)
745			});
746		},
747
748		isBasketIntegrated: function()
749		{
750			return this.params.BASKET_WITH_ORDER_INTEGRATION === 'Y';
751		},
752
753		isBasketChanged: function()
754		{
755			return this.changedItems.length;
756		},
757
758		addPriceAnimationData: function(nodeId, start, finish, currency)
759		{
760			if (!BX.type.isPlainObject(this.priceAnimationData))
761			{
762				this.clearPriceAnimationData();
763			}
764
765			this.priceAnimationData.start[nodeId] = parseFloat(start);
766			this.priceAnimationData.finish[nodeId] = parseFloat(finish);
767			this.priceAnimationData.currency[nodeId] = currency;
768			this.priceAnimationData.int[nodeId] = (parseFloat(start) === parseInt(start)) && (parseFloat(finish) === parseInt(finish));
769		},
770
771		clearPriceAnimationData: function()
772		{
773			this.priceAnimationData = {
774				start: {},
775				finish: {},
776				currency: {},
777				int: {}
778			};
779		},
780
781		applyBasketResult: function(result)
782		{
783			this.changedItems = [];
784			this.clearPriceAnimationData();
785
786			if (!BX.type.isPlainObject(result))
787			{
788				return;
789			}
790
791			if (result.BASKET_ITEM_RENDER_DATA)
792			{
793				var i, newData;
794
795				for (i in result.BASKET_ITEM_RENDER_DATA)
796				{
797					if (result.BASKET_ITEM_RENDER_DATA.hasOwnProperty(i))
798					{
799						newData = result.BASKET_ITEM_RENDER_DATA[i];
800						newData.WARNINGS = this.checkBasketItemWarnings(newData, result.WARNING_MESSAGE_WITH_CODE);
801
802						if (this.items[newData.ID])
803						{
804							if (JSON.stringify(this.items[newData.ID]) === JSON.stringify(newData))
805							{
806								continue;
807							}
808						}
809						else
810						{
811							this.addSortedItem(newData.ID, true);
812						}
813
814						this.changedItems.push(newData.ID);
815
816						newData = this.checkBasketItemsAnimation(newData);
817						this.items[newData.ID] = newData;
818					}
819				}
820
821				this.changedItems = BX.util.array_unique(this.changedItems.concat(this.getChangedSimilarOffers()));
822
823				if (this.isBasketChanged())
824				{
825					this.sortSortedItems(true);
826				}
827			}
828
829			if (result.TOTAL_RENDER_DATA)
830			{
831				result.TOTAL_RENDER_DATA = this.checkTotalAnimation(result.TOTAL_RENDER_DATA);
832			}
833
834			this.result = result;
835		},
836
837		itemSortFunction: function(a, b)
838		{
839			if (!this.items.hasOwnProperty(a) || !this.items.hasOwnProperty(b))
840			{
841				return 0;
842			}
843
844			return parseFloat(this.items[a].SORT) - parseFloat(this.items[b].SORT);
845		},
846
847		getChangedSimilarOffers: function()
848		{
849			var changedSimilarOffers = [];
850
851			var otherSimilarItemsQuantity, totalSimilarItemsQuantity;
852			var hashMap = this.getHashMap();
853
854			for (var hash in hashMap)
855			{
856				if (hashMap.hasOwnProperty(hash))
857				{
858					if (hashMap[hash].length > 1)
859					{
860						for (var i = 0; i < hashMap[hash].length; i++)
861						{
862							otherSimilarItemsQuantity = 0;
863							totalSimilarItemsQuantity = 0;
864
865							for (var k = 0; k < hashMap[hash].length; k ++)
866							{
867								if (hashMap[hash][k] != hashMap[hash][i])
868								{
869									otherSimilarItemsQuantity += parseFloat(this.items[hashMap[hash][k]].QUANTITY);
870								}
871
872								totalSimilarItemsQuantity += parseFloat(this.items[hashMap[hash][k]].QUANTITY);
873							}
874
875							if (
876								!this.items[hashMap[hash][i]].HAS_SIMILAR_ITEMS
877								|| this.items[hashMap[hash][i]].SIMILAR_ITEMS_QUANTITY != otherSimilarItemsQuantity
878								|| this.items[hashMap[hash][i]].TOTAL_SIMILAR_ITEMS_QUANTITY != totalSimilarItemsQuantity
879							)
880							{
881								changedSimilarOffers.push(hashMap[hash][i]);
882
883								this.items[hashMap[hash][i]].HAS_SIMILAR_ITEMS = true;
884								this.items[hashMap[hash][i]].SIMILAR_ITEMS_QUANTITY = otherSimilarItemsQuantity;
885								this.items[hashMap[hash][i]].TOTAL_SIMILAR_ITEMS_QUANTITY = totalSimilarItemsQuantity;
886
887								this.items[hashMap[hash][i]].ALL_AVAILABLE_QUANTITY = this.items[hashMap[hash][i]].AVAILABLE_QUANTITY;
888								this.items[hashMap[hash][i]].AVAILABLE_QUANTITY = this.items[hashMap[hash][i]].ALL_AVAILABLE_QUANTITY - otherSimilarItemsQuantity;
889							}
890						}
891					}
892					else if (hashMap[hash][0] && this.items[hashMap[hash][0]].HAS_SIMILAR_ITEMS)
893					{
894						changedSimilarOffers.push(hashMap[hash][0]);
895
896						delete this.items[hashMap[hash][0]].HAS_SIMILAR_ITEMS;
897						delete this.items[hashMap[hash][0]].SIMILAR_ITEMS_QUANTITY;
898						delete this.items[hashMap[hash][0]].TOTAL_SIMILAR_ITEMS_QUANTITY;
899
900						this.items[hashMap[hash][0]].AVAILABLE_QUANTITY = this.items[hashMap[hash][0]].ALL_AVAILABLE_QUANTITY;
901						delete this.items[hashMap[hash][0]].ALL_AVAILABLE_QUANTITY;
902					}
903				}
904			}
905
906			return changedSimilarOffers;
907		},
908
909		getHashMap: function()
910		{
911			var hashMap = {};
912
913			for (var id in this.items)
914			{
915				if (this.items.hasOwnProperty(id) && this.isItemAvailable(id))
916				{
917					if (!hashMap.hasOwnProperty(this.items[id].HASH))
918					{
919						hashMap[this.items[id].HASH] = [];
920					}
921
922					hashMap[this.items[id].HASH].push(id);
923				}
924			}
925
926			return hashMap;
927		},
928
929		isItemAvailable: function(itemId)
930		{
931			var sortedItems = this.filter.isActive() ? this.filter.realSortedItems : this.sortedItems;
932
933			return !this.items[itemId].NOT_AVAILABLE
934				&& !this.items[itemId].SHOW_RESTORE
935				&& BX.util.in_array(itemId, sortedItems);
936		},
937
938		checkTotalAnimation: function(totalData)
939		{
940			if (this.result && this.result.TOTAL_RENDER_DATA && parseFloat(this.result.TOTAL_RENDER_DATA.PRICE) > parseFloat(totalData.PRICE))
941			{
942				totalData.PRICE_NEW = totalData.PRICE;
943				totalData.PRICE = this.result.TOTAL_RENDER_DATA.PRICE;
944
945				totalData.PRICE_FORMATED_NEW = totalData.PRICE_FORMATED;
946				totalData.PRICE_FORMATED = this.result.TOTAL_RENDER_DATA.PRICE_FORMATED;
947
948				this.addPriceAnimationData(this.ids.total, totalData.PRICE, totalData.PRICE_NEW, totalData.CURRENCY);
949			}
950
951			return totalData;
952		},
953
954		checkBasketItemsAnimation: function(itemData)
955		{
956			var itemId = itemData.ID;
957
958			if (this.items[itemId])
959			{
960				var quantityNode = BX(this.ids.quantity + itemId);
961				if (
962					BX.type.isDomNode(quantityNode)
963					&& !this.actionPool.isItemInPool(itemId)
964					&& parseFloat(quantityNode.value) !== parseFloat(itemData.QUANTITY)
965				)
966				{
967					itemData.QUANTITY_ANIMATION = true;
968					this.actionPool.clearLastActualQuantityPool(itemId);
969				}
970
971				if (parseFloat(this.items[itemId].PRICE) > parseFloat(itemData.PRICE))
972				{
973					itemData.PRICE_NEW = itemData.PRICE;
974					itemData.PRICE = this.items[itemId].PRICE;
975
976					itemData.PRICE_FORMATED_NEW = itemData.PRICE_FORMATED;
977					itemData.PRICE_FORMATED = this.items[itemId].PRICE_FORMATED;
978
979					this.addPriceAnimationData(this.ids.price + itemId, itemData.PRICE, itemData.PRICE_NEW, itemData.CURRENCY);
980				}
981
982				if (
983					BX.util.in_array('SUM', this.params.COLUMNS_LIST)
984					&& parseFloat(this.items[itemId].SUM_PRICE) > parseFloat(itemData.SUM_PRICE)
985					&& parseFloat(this.items[itemId].QUANTITY) === parseFloat(itemData.QUANTITY)
986				)
987				{
988					itemData.SUM_PRICE_NEW = itemData.SUM_PRICE;
989					itemData.SUM_PRICE = this.items[itemId].SUM_PRICE;
990
991					itemData.SUM_PRICE_FORMATED_NEW = itemData.SUM_PRICE_FORMATED;
992					itemData.SUM_PRICE_FORMATED = this.items[itemId].SUM_PRICE_FORMATED;
993
994					this.addPriceAnimationData(this.ids.sumPrice + itemId, itemData.SUM_PRICE, itemData.SUM_PRICE_NEW, itemData.CURRENCY);
995				}
996			}
997
998			return itemData;
999		},
1000
1001		getData: function(data)
1002		{
1003			data = data || {};
1004
1005			data[this.params.ACTION_VARIABLE] = this.lastAction;
1006			data.via_ajax = 'Y';
1007			data.site_id = this.siteId;
1008			data.sessid = BX.bitrix_sessid();
1009			data.template = this.template;
1010			data.signedParamsString = this.signedParamsString;
1011
1012			return data;
1013		},
1014
1015		startLoader: function()
1016		{
1017			// if (!this.loadingScreen)
1018			// {
1019			// 	this.loadingScreen = new BX.PopupWindow('loading_screen', null, {
1020			// 		events: {
1021			// 			onAfterPopupShow: BX.delegate(function() {
1022			// 				BX.cleanNode(this.loadingScreen.popupContainer);
1023			// 				BX.removeClass(this.loadingScreen.popupContainer, 'popup-window');
1024			// 				this.loadingScreen.popupContainer.appendChild(
1025			// 					BX.create('IMG', {props: {src: this.templateFolder + '/images/loader.gif'}})
1026			// 				);
1027			// 				this.loadingScreen.popupContainer.removeAttribute('style');
1028			// 				this.loadingScreen.popupContainer.style.display = 'block';
1029			// 			}, this)
1030			// 		}
1031			// 	});
1032			// 	BX.addClass(this.loadingScreen.popupContainer, 'bx-step-opacity');
1033			// }
1034			//
1035			// this.loadingScreen.show();
1036		},
1037
1038		/**
1039		 * Hiding loader image with overlay.
1040		 */
1041		endLoader: function()
1042		{
1043			// if (this.loadingScreen && this.loadingScreen.isShown())
1044			// {
1045			// 	this.loadingScreen.close();
1046			// }
1047		},
1048
1049		editWarnings: function()
1050		{
1051			this.editGeneralWarnings();
1052			this.editBasketItemWarnings();
1053			this.toggleWarningBlock();
1054			this.showWarningItemsCount();
1055		},
1056
1057		editGeneralWarnings: function()
1058		{
1059			var warningsNode = this.getEntity(this.getCacheNode(this.ids.warning), 'basket-general-warnings');
1060
1061			if (BX.type.isDomNode(warningsNode))
1062			{
1063				var generalWarningText = warningsNode.innerHTML;
1064
1065				if (this.result.WARNING_MESSAGE_WITH_CODE)
1066				{
1067					for (var code in this.result.WARNING_MESSAGE_WITH_CODE)
1068					{
1069						if (this.result.WARNING_MESSAGE_WITH_CODE.hasOwnProperty(code))
1070						{
1071							if (
1072								!this.items[code]
1073								&& generalWarningText.indexOf(this.result.WARNING_MESSAGE_WITH_CODE[code]) === -1
1074							)
1075							{
1076								generalWarningText += this.result.WARNING_MESSAGE_WITH_CODE[code] + '<br/>';
1077							}
1078						}
1079					}
1080				}
1081
1082				if (generalWarningText)
1083				{
1084					warningsNode.innerHTML = generalWarningText;
1085					warningsNode.style.display = '';
1086				}
1087				else
1088				{
1089					warningsNode.style.display = 'none';
1090					warningsNode.innerHTML = '';
1091				}
1092			}
1093		},
1094
1095		editBasketItemWarnings: function()
1096		{
1097			var itemsWarningsNode = this.getEntity(this.getCacheNode(this.ids.warning), 'basket-item-warnings');
1098
1099			if (BX.type.isDomNode(itemsWarningsNode))
1100			{
1101				if (this.warningItems.length)
1102				{
1103					var warningCount = this.getEntity(itemsWarningsNode, 'basket-items-warning-count');
1104					if (BX.type.isDomNode(warningCount))
1105					{
1106						warningCount.innerHTML = this.warningItems.length + ' ' + this.getGoodsMessage(this.warningItems.length);
1107					}
1108
1109					itemsWarningsNode.style.display = '';
1110				}
1111				else if (itemsWarningsNode.style.display !== 'none')
1112				{
1113					itemsWarningsNode.style.display = 'none';
1114
1115					if (this.filter.isActive())
1116					{
1117						this.toggleFilter('all');
1118					}
1119				}
1120			}
1121		},
1122
1123		toggleWarningBlock: function()
1124		{
1125			var warningNode = this.getCacheNode(this.ids.warning);
1126
1127			if (BX.type.isDomNode(warningNode))
1128			{
1129				var generalWarningNode = this.getEntity(warningNode, 'basket-general-warnings');
1130				var itemsWarningsNode = this.getEntity(warningNode, 'basket-item-warnings');
1131
1132				if (
1133					(!BX.type.isDomNode(generalWarningNode) || generalWarningNode.style.display === 'none')
1134					&& (!BX.type.isDomNode(itemsWarningsNode) || itemsWarningsNode.style.display === 'none')
1135				)
1136				{
1137					warningNode.style.display = 'none';
1138				}
1139				else
1140				{
1141					warningNode.style.display = '';
1142				}
1143			}
1144		},
1145
1146		checkBasketItemWarnings: function(itemData, warnings)
1147		{
1148			if (!itemData)
1149				return;
1150
1151			var itemWarnings;
1152
1153			if (this.items[itemData.ID] && this.lastAction === 'refreshAjax')
1154			{
1155				itemWarnings = this.items[itemData.ID].WARNINGS;
1156			}
1157			else
1158			{
1159				itemWarnings = [];
1160			}
1161
1162			if (BX.type.isArray(warnings[itemData.ID]) && warnings[itemData.ID].length)
1163			{
1164				for (var i in warnings[itemData.ID])
1165				{
1166					if (warnings[itemData.ID].hasOwnProperty(i) && !BX.util.in_array(warnings[itemData.ID][i], itemWarnings))
1167					{
1168						itemWarnings.push(warnings[itemData.ID][i]);
1169					}
1170				}
1171			}
1172
1173			if (itemWarnings.length)
1174			{
1175				if (!BX.util.in_array(itemData.ID, this.warningItems))
1176				{
1177					this.warningItems.push(itemData.ID);
1178				}
1179			}
1180			else if (BX.util.in_array(itemData.ID, this.warningItems))
1181			{
1182				this.warningItems.splice(BX.util.array_search(itemData.ID, this.warningItems), 1);
1183			}
1184
1185			return itemWarnings;
1186		},
1187
1188		removeAllWarnings: function(event)
1189		{
1190			this.clearGeneralWarnings();
1191			this.clearBasketItemsWarnings();
1192
1193			this.editWarnings();
1194
1195			event && event.preventDefault();
1196		},
1197
1198		clearGeneralWarnings: function()
1199		{
1200			this.result.WARNING_MESSAGE_WITH_CODE = {};
1201
1202			var generalWarningNode = this.getEntity(this.getCacheNode(this.ids.warning), 'basket-general-warnings');
1203
1204			if (BX.type.isDomNode(generalWarningNode))
1205			{
1206				generalWarningNode.innerHTML = '';
1207			}
1208		},
1209
1210		clearBasketItemsWarnings: function()
1211		{
1212			var itemsToEdit = [];
1213
1214			for (var i in this.warningItems)
1215			{
1216				if (this.warningItems.hasOwnProperty(i))
1217				{
1218					this.items[this.warningItems[i]].WARNINGS = [];
1219
1220					if (this.isItemShown(this.warningItems[i]))
1221					{
1222						itemsToEdit.push(this.warningItems[i]);
1223					}
1224				}
1225			}
1226
1227			this.warningItems = [];
1228			this.editBasketItems(itemsToEdit);
1229		},
1230
1231		isItemShown: function(itemId)
1232		{
1233			return BX.util.in_array(itemId, this.shownItems);
1234		},
1235
1236		initializeBasketItems: function()
1237		{
1238			if (Object.keys(this.items).length === 0)
1239				return;
1240
1241			for (var i = 0; i < this.sortedItems.length; i++)
1242			{
1243				if (this.useDynamicScroll && this.shownItems.length >= this.maxItemsShowCount)
1244				{
1245					break;
1246				}
1247
1248				this.createBasketItem(this.sortedItems[i]);
1249			}
1250		},
1251
1252		createBasketItem: function(itemId)
1253		{
1254			if (!this.items[itemId])
1255			{
1256				return;
1257			}
1258
1259			var basketItemTemplate = this.getTemplate('basket-item-template');
1260			if (basketItemTemplate)
1261			{
1262				var basketItemHtml = this.renderBasketItem(basketItemTemplate, this.items[itemId]);
1263				var sortIndex = BX.util.array_search(itemId, this.sortedItems);
1264
1265				if (this.shownItems.length && sortIndex >= 0)
1266				{
1267					if (sortIndex < BX.util.array_search(this.shownItems[0], this.sortedItems))
1268					{
1269						// insert before
1270						BX(this.ids.item + this.shownItems[0]).insertAdjacentHTML('beforebegin', basketItemHtml);
1271						this.shownItems.unshift(itemId);
1272					}
1273					else if (sortIndex > BX.util.array_search(this.shownItems[this.shownItems.length - 1], this.sortedItems))
1274					{
1275						// insert after
1276						BX(this.ids.item + this.shownItems[this.shownItems.length - 1]).insertAdjacentHTML('afterend', basketItemHtml);
1277						this.shownItems.push(itemId);
1278					}
1279					else
1280					{
1281						// insert between
1282						BX(this.ids.item + this.sortedItems[sortIndex + 1]).insertAdjacentHTML('beforebegin', basketItemHtml);
1283						this.shownItems.splice(sortIndex + 1, 0, itemId);
1284					}
1285				}
1286				else
1287				{
1288					this.getCacheNode(this.ids.itemListTable).insertAdjacentHTML('beforeend', basketItemHtml);
1289					this.shownItems.push(itemId);
1290				}
1291
1292				this.bindBasketItemEvents(this.items[itemId]);
1293
1294				if (this.filter.isActive())
1295				{
1296					this.filter.highlightSearchMatch(this.items[itemId]);
1297				}
1298			}
1299		},
1300
1301		getItemsToEdit: function()
1302		{
1303			var itemIds = [];
1304
1305			if (this.isBasketChanged())
1306			{
1307				for (var i in this.changedItems)
1308				{
1309					if (this.changedItems.hasOwnProperty(i) && this.isItemShown(this.changedItems[i]))
1310					{
1311						itemIds.push(this.changedItems[i]);
1312					}
1313				}
1314			}
1315
1316			return itemIds;
1317		},
1318
1319		getItemsAfter: function()
1320		{
1321			var itemIdsAfter = [];
1322
1323			if (this.useDynamicScroll)
1324			{
1325				var lastShownItemId = this.shownItems[this.shownItems.length - 1] || false;
1326
1327				if (lastShownItemId)
1328				{
1329					var i = 0;
1330					var index = BX.util.array_search(lastShownItemId, this.sortedItems);
1331
1332					while (this.sortedItems[++index] && i++ < this.maxItemsShowCount)
1333					{
1334						itemIdsAfter.push(this.sortedItems[index]);
1335					}
1336				}
1337			}
1338
1339			return itemIdsAfter;
1340		},
1341
1342		editBasketItems: function(itemIds)
1343		{
1344			if (!itemIds || itemIds.length === 0)
1345			{
1346				return;
1347			}
1348
1349			var i, item;
1350
1351			for (i in itemIds)
1352			{
1353				if (!itemIds.hasOwnProperty(i) || !BX.type.isPlainObject(this.items[itemIds[i]]))
1354				{
1355					continue;
1356				}
1357
1358				item = this.items[itemIds[i]];
1359
1360				if (this.actionPool.isItemInPool(item.ID))
1361				{
1362					if (!BX.util.in_array(item.ID, this.postponedItems))
1363					{
1364						this.postponedItems.push(item.ID);
1365					}
1366
1367					continue;
1368				}
1369
1370				if (BX.type.isDomNode(BX(this.ids.item + item.ID)))
1371				{
1372					this.redrawBasketItemNode(item.ID);
1373					this.applyQuantityAnimation(item.ID);
1374				}
1375				else
1376				{
1377					this.createBasketItem(item.ID);
1378				}
1379			}
1380		},
1381
1382		editPostponedBasketItems: function()
1383		{
1384			if (!this.postponedItems.length)
1385				return;
1386
1387			var itemsToEdit = [];
1388
1389			for (var i in this.postponedItems)
1390			{
1391				if (this.postponedItems.hasOwnProperty(i) && this.isItemShown(this.postponedItems[i]))
1392				{
1393					itemsToEdit.push(this.postponedItems[i]);
1394				}
1395			}
1396
1397			this.postponedItems = [];
1398			this.editBasketItems(itemsToEdit);
1399		},
1400
1401		applyQuantityAnimation: function(itemId)
1402		{
1403			var basketItemNode = BX(this.ids.item + itemId);
1404
1405			if (BX.type.isDomNode(basketItemNode) && this.items[itemId])
1406			{
1407				if (this.items[itemId].QUANTITY_ANIMATION)
1408				{
1409					BX.addClass(BX(this.ids.quantity + itemId), 'basket-updated');
1410				}
1411			}
1412		},
1413
1414		applyPriceAnimation: function()
1415		{
1416			if (!this.priceAnimationData || Object.keys(this.priceAnimationData.start).length === 0)
1417				return;
1418
1419			var animationData = this.priceAnimationData,
1420				nodeCache = {};
1421
1422			new BX.easing({
1423				duration: this.params.USE_PRICE_ANIMATION === 'Y' ? this.duration.priceAnimation : 1,
1424				start: animationData.start,
1425				finish: animationData.finish,
1426				transition: BX.easing.makeEaseOut(BX.easing.transitions.quad),
1427				step: BX.delegate(function(state){
1428					for (var nodeId in animationData.start)
1429					{
1430						if (animationData.start.hasOwnProperty(nodeId))
1431						{
1432							if (!nodeCache[nodeId])
1433							{
1434								if (nodeId === this.ids.total)
1435								{
1436									nodeCache[nodeId] = this.getEntities(this.getCacheNode(this.ids.basketRoot), this.ids.total);
1437								}
1438								else
1439								{
1440									var node = BX(nodeId);
1441									nodeCache[nodeId] = node ? [node] : [];
1442								}
1443							}
1444
1445							if (!animationData.int[nodeId])
1446							{
1447								// fix price blinking
1448								state[nodeId] = (state[nodeId] + (state[nodeId] % 1000) / 1000).toFixed(5);
1449							}
1450
1451							for (var i = 0; i < nodeCache[nodeId].length; i++)
1452							{
1453								nodeCache[nodeId][i].innerHTML = this.getFormatPrice(state[nodeId], animationData.currency[nodeId]);
1454							}
1455						}
1456					}
1457				}, this),
1458				complete: BX.delegate(function() {
1459					var nodeId, formattedPrice, itemId, type;
1460
1461					for (nodeId in animationData.start)
1462					{
1463						if (animationData.start.hasOwnProperty(nodeId))
1464						{
1465							formattedPrice = this.getFormatPrice(animationData.finish[nodeId], animationData.currency[nodeId]);
1466
1467							for (var i = 0; i < nodeCache[nodeId].length; i++)
1468							{
1469								nodeCache[nodeId][i].innerHTML = formattedPrice;
1470							}
1471
1472							if (nodeId.indexOf(this.ids.sumPrice) !== -1)
1473							{
1474								type = 'SUM_PRICE';
1475								itemId = nodeId.substr(this.ids.sumPrice.length);
1476							}
1477							else if (nodeId.indexOf(this.ids.price) !== -1)
1478							{
1479								type = 'PRICE';
1480								itemId = nodeId.substr(this.ids.price.length);
1481							}
1482							else if (nodeId.indexOf(this.ids.total) !== -1)
1483							{
1484								type = 'TOTAL';
1485								itemId = '';
1486							}
1487							else
1488							{
1489								itemId = '';
1490								type = '';
1491							}
1492
1493							if (BX.type.isNotEmptyString(type))
1494							{
1495								if (itemId)
1496								{
1497									this.items[itemId][type] = animationData.finish[nodeId];
1498									delete this.items[itemId][type + '_NEW'];
1499									this.items[itemId][type + '_FORMATED'] = formattedPrice;
1500									delete this.items[itemId][type + '_FORMATED_NEW'];
1501								}
1502								else if (type === 'TOTAL')
1503								{
1504									this.result.TOTAL_RENDER_DATA.PRICE = animationData.finish[nodeId];
1505									delete this.result.TOTAL_RENDER_DATA.PRICE_NEW;
1506									this.result.TOTAL_RENDER_DATA.PRICE_FORMATED = formattedPrice;
1507									delete this.result.TOTAL_RENDER_DATA.PRICE_FORMATED_NEW;
1508								}
1509							}
1510						}
1511					}
1512
1513					this.filter.highlightFoundItems();
1514				}, this)
1515			}).animate();
1516		},
1517
1518		getFormatPrice: function(price, currency)
1519		{
1520			return BX.Currency.currencyFormat(price, currency, true);
1521		},
1522
1523		deleteBasketItems: function(items, restore, final)
1524		{
1525			if (!items || !items.length)
1526			{
1527				return;
1528			}
1529
1530			for (var i in items)
1531			{
1532				if (items.hasOwnProperty(i))
1533				{
1534					this.deleteBasketItem(items[i], restore, final);
1535				}
1536			}
1537		},
1538
1539		deleteBasketItem: function(itemId, restore, final)
1540		{
1541			// delete not available item with no chance to restore
1542			if (this.items[itemId].NOT_AVAILABLE && restore)
1543			{
1544				restore = false;
1545				final = true;
1546			}
1547
1548			if (restore)
1549			{
1550				this.items[itemId].SHOW_RESTORE = true;
1551				this.items[itemId].SHOW_LOADING = false;
1552				this.redrawBasketItemNode(itemId);
1553			}
1554			else
1555			{
1556				this.changeShownItem(itemId);
1557				BX.remove(BX(this.ids.item + itemId));
1558			}
1559
1560			if (final)
1561			{
1562				this.changeSortedItem(itemId, false, true);
1563				this.changeShownItem(itemId, false, true);
1564			}
1565		},
1566
1567		addSortedItem: function(itemId, all)
1568		{
1569			this.sortedItems.push(itemId.toString());
1570
1571			if (all && this.filter.isActive())
1572			{
1573				this.filter.realSortedItems.push(itemId.toString());
1574			}
1575		},
1576
1577		changeSortedItem: function(itemId, newItemId, all)
1578		{
1579			var index = BX.util.array_search(itemId, this.sortedItems);
1580
1581			if (index >= 0)
1582			{
1583				if (newItemId)
1584				{
1585					this.sortedItems.splice(index, 1, newItemId.toString());
1586				}
1587				else
1588				{
1589					this.sortedItems.splice(index, 1);
1590				}
1591			}
1592
1593			if (all && this.filter.isActive())
1594			{
1595				index = BX.util.array_search(itemId, this.filter.realSortedItems);
1596
1597				if (index >= 0)
1598				{
1599					if (newItemId)
1600					{
1601						this.filter.realSortedItems.splice(index, 1, newItemId.toString());
1602					}
1603					else
1604					{
1605						this.filter.realSortedItems.splice(index, 1);
1606					}
1607				}
1608			}
1609		},
1610
1611		sortSortedItems: function(all)
1612		{
1613			this.sortedItems.sort(BX.proxy(this.itemSortFunction, this));
1614
1615			if (all && this.filter.isActive())
1616			{
1617				this.filter.realSortedItems.sort(BX.proxy(this.itemSortFunction, this));
1618			}
1619		},
1620
1621		changeShownItem: function(itemId, newItemId, all)
1622		{
1623			var index = BX.util.array_search(itemId, this.shownItems);
1624
1625			if (index >= 0)
1626			{
1627				if (newItemId)
1628				{
1629					this.shownItems.splice(index, 1, newItemId.toString());
1630				}
1631				else
1632				{
1633					this.shownItems.splice(index, 1);
1634				}
1635			}
1636
1637			if (all && this.filter.isActive())
1638			{
1639				index = BX.util.array_search(itemId, this.filter.realShownItems);
1640
1641				if (index >= 0)
1642				{
1643					if (newItemId)
1644					{
1645						this.filter.realShownItems.splice(index, 1, newItemId.toString());
1646					}
1647					else
1648					{
1649						this.filter.realShownItems.splice(index, 1);
1650					}
1651				}
1652			}
1653		},
1654
1655		redrawBasketItemNode: function(itemId)
1656		{
1657			var basketItemNode = BX(this.ids.item + itemId);
1658
1659			if (!this.items[itemId] || !BX.type.isDomNode(basketItemNode))
1660				return;
1661
1662			var basketItemTemplate = this.getTemplate('basket-item-template');
1663			if (basketItemTemplate)
1664			{
1665				var nodeAligner = BX(this.ids.itemHeightAligner + itemId),
1666					oldHeight;
1667
1668				if (BX.type.isDomNode(nodeAligner))
1669				{
1670					oldHeight = nodeAligner.clientHeight;
1671				}
1672
1673				var basketItemHtml = this.renderBasketItem(basketItemTemplate, this.items[itemId]);
1674				basketItemNode.insertAdjacentHTML('beforebegin', basketItemHtml);
1675				BX.remove(basketItemNode);
1676
1677				if (oldHeight)
1678				{
1679					nodeAligner = BX(this.ids.itemHeightAligner + itemId);
1680
1681					if (BX.type.isDomNode(nodeAligner) && nodeAligner.clientHeight < oldHeight)
1682					{
1683						nodeAligner.style.minHeight = oldHeight + 'px';
1684						setTimeout(function(){nodeAligner.style.minHeight = '0px';}, 1);
1685					}
1686				}
1687
1688				this.bindBasketItemEvents(this.items[itemId]);
1689
1690				if (this.filter.isActive())
1691				{
1692					this.filter.highlightSearchMatch(this.items[itemId]);
1693				}
1694			}
1695		},
1696
1697		restoreBasketItems: function(items)
1698		{
1699			if (!items || Object.keys(items).length === 0)
1700			{
1701				return;
1702			}
1703
1704			var oldItemId, newItemId, basketItemNode;
1705
1706			for (oldItemId in items)
1707			{
1708				if (items.hasOwnProperty(oldItemId))
1709				{
1710					newItemId = items[oldItemId];
1711
1712					if (this.isItemShown(oldItemId))
1713					{
1714						this.changeShownItem(oldItemId, newItemId, true);
1715
1716						basketItemNode = BX(this.ids.item + oldItemId);
1717						if (BX.type.isDomNode(basketItemNode))
1718						{
1719							basketItemNode.id = this.ids.item + newItemId;
1720							basketItemNode.setAttribute('data-id', newItemId);
1721						}
1722					}
1723
1724					this.changeSortedItem(oldItemId, false, true);
1725				}
1726			}
1727		},
1728
1729		bindBasketItemEvents: function(itemData)
1730		{
1731			if (!itemData)
1732				return;
1733
1734			var itemNode = BX(this.ids.item + itemData.ID);
1735			if (BX.type.isDomNode(itemNode))
1736			{
1737				this.bindQuantityEvents(itemNode, itemData);
1738				this.bindSkuEvents(itemNode, itemData);
1739				this.bindImageEvents(itemNode, itemData);
1740				this.bindActionEvents(itemNode, itemData);
1741				this.bindRestoreAction(itemNode, itemData);
1742				this.bindItemWarningEvents(itemNode, itemData);
1743			}
1744		},
1745
1746		bindQuantityEvents: function(node, data)
1747		{
1748			if (!node || !data || !this.isItemAvailable(data.ID))
1749				return;
1750
1751			var entity;
1752
1753			var block = this.getEntity(node, 'basket-item-quantity-block');
1754			if (block)
1755			{
1756			    var that = this;
1757				var startEventName = this.isTouch ? 'touchstart' : 'mousedown';
1758				var endEventName = this.isTouch ? 'touchend' : 'mouseup';
1759
1760				entity = this.getEntity(block, 'basket-item-quantity-minus');
1761				BX.bind(entity, startEventName, BX.proxy(this.startQuantityInterval, this));
1762				BX.bind(entity, endEventName, BX.proxy(this.clearQuantityInterval, this));
1763				BX.bind(entity, 'mouseout', BX.proxy(this.clearQuantityInterval, this));
1764				BX.bind(entity, 'click', BX.proxy(this.quantityMinus, this));
1765
1766				entity = this.getEntity(block, 'basket-item-quantity-plus');
1767				BX.bind(entity, startEventName, BX.proxy(this.startQuantityInterval, this));
1768				BX.bind(entity, endEventName, BX.proxy(this.clearQuantityInterval, this));
1769				BX.bind(entity, 'mouseout', BX.proxy(this.clearQuantityInterval, this));
1770                BX.bind(entity, 'click', BX.proxy(this.quantityPlus, this));
1771
1772				entity = this.getEntity(block, 'basket-item-quantity-field');
1773                var entityContainer = document.querySelector('[data-entity="basket-item"][data-id="'+data.ID+'"]');
1774                var links = entityContainer.querySelectorAll('.card-counter__link');
1775                BX.Sale.BasketComponent.counters = BX.Sale.BasketComponent.counters || {};
1776                if (links && BX.Sale.BasketComponent.counters[data.ID]) {
1777                    Array.from(links).forEach(function(link) {
1778                        link.classList.remove('active');
1779                    });
1780                    links[BX.Sale.BasketComponent.counters[data.ID]].classList.add('active');
1781                    entity.nextElementSibling.value = entity.value / links[BX.Sale.BasketComponent.counters[data.ID]].dataset.counterChange;
1782                } else {
1783                    entity.nextElementSibling.value = entity.value;
1784                }
1785
1786				var counterSubscribe = function(counterInstance) {
1787                    counterInstance.on('change', function() {
1788                        if (links){
1789                            var activeLink = entityContainer.querySelector('.card-counter__link.active');
1790                            var activeLinkIndex = Array.from(links).indexOf(activeLink);
1791                            BX.Sale.BasketComponent.counters[data.ID] = activeLinkIndex;
1792                        }
1793                        entity.value = counterInstance.value;
1794                        BX.proxy_context = entity;
1795                        that.quantityChange.call(that);
1796                    });
1797                };
1798
1799                if (app.CatalogItemCounter){
1800                    var cardCounter = BX.findParent(entity, { className: 'card__counter' });
1801                    var value = entity.nextElementSibling.value;
1802                    var counterInstance = new app.CatalogItemCounter(cardCounter);
1803                    app.util.defer(function() {
1804                        counterInstance.counter.change(value, true);
1805                        counterSubscribe(counterInstance.counter);
1806                    });
1807                } else {
1808                    app.ready(function() {
1809                        counterSubscribe(entity.nextElementSibling.modules.counter);
1810                    });
1811                }
1812
1813				//BX.bind(entity, 'change', BX.proxy(this.quantityChange, this));
1814			}
1815		},
1816
1817		startQuantityInterval: function()
1818		{
1819			var target = BX.proxy_context;
1820			var func = target.getAttribute('data-entity') === 'basket-item-quantity-minus'
1821				? BX.proxy(this.quantityMinus, this)
1822				: BX.proxy(this.quantityPlus, this);
1823
1824			this.quantityDelay = setTimeout(
1825				BX.delegate(function() {
1826					this.quantityTimer = setInterval(function(){func(target);}, 150);
1827				}, this),
1828				300
1829			);
1830		},
1831
1832		clearQuantityInterval: function()
1833		{
1834			clearTimeout(this.quantityDelay);
1835			clearInterval(this.quantityTimer);
1836		},
1837
1838		quantityPlus: function(target)
1839		{
1840			if (!BX.type.isDomNode(target))
1841			{
1842				target = BX.proxy_context;
1843				this.clearQuantityInterval();
1844			}
1845
1846			var itemData = this.getItemDataByTarget(target);
1847			if (itemData)
1848			{
1849				var quantityField = BX(this.ids.quantity + itemData.ID);
1850				var isQuantityFloat = this.isQuantityFloat(itemData);
1851
1852				var currentQuantity = isQuantityFloat ? parseFloat(quantityField.value) : Math.round(quantityField.value);
1853				var measureRatio = isQuantityFloat ? parseFloat(itemData.MEASURE_RATIO) : parseInt(itemData.MEASURE_RATIO);
1854
1855				var quantity = parseFloat((currentQuantity + measureRatio).toFixed(5));
1856				quantity = this.getCorrectQuantity(itemData, quantity);
1857
1858				this.setQuantity(itemData, quantity);
1859			}
1860		},
1861
1862		quantityMinus: function(target)
1863		{
1864			target = BX.type.isDomNode(target) ? target : BX.proxy_context;
1865
1866			var itemData = this.getItemDataByTarget(target);
1867			if (itemData)
1868			{
1869				var quantityField = BX(this.ids.quantity + itemData.ID);
1870				var isQuantityFloat = this.isQuantityFloat(itemData);
1871
1872				var currentQuantity = isQuantityFloat ? parseFloat(quantityField.value) : Math.round(quantityField.value);
1873				var measureRatio = isQuantityFloat ? parseFloat(itemData.MEASURE_RATIO) : parseInt(itemData.MEASURE_RATIO);
1874
1875				var quantity = parseFloat((currentQuantity - measureRatio).toFixed(5));
1876				quantity = this.getCorrectQuantity(itemData, quantity);
1877
1878				this.setQuantity(itemData, quantity);
1879			}
1880		},
1881
1882		quantityChange: function()
1883		{
1884			var itemData = this.getItemDataByTarget(BX.proxy_context);
1885			if (itemData)
1886			{
1887				var quantityField, quantity;
1888
1889				quantityField = BX(this.ids.quantity + itemData.ID);
1890				quantity = this.getCorrectQuantity(itemData, quantityField.value);
1891
1892				this.setQuantity(itemData, quantity);
1893			}
1894		},
1895
1896		isQuantityFloat: function(item)
1897		{
1898			return this.params.QUANTITY_FLOAT === 'Y' || (parseInt(item.MEASURE_RATIO) !== parseFloat(item.MEASURE_RATIO));
1899		},
1900
1901		getCorrectQuantity: function(itemData, quantity)
1902		{
1903			var isQuantityFloat = this.isQuantityFloat(itemData),
1904				measureRatio = isQuantityFloat ? parseFloat(itemData.MEASURE_RATIO) : parseInt(itemData.MEASURE_RATIO),
1905				availableQuantity = 0;
1906
1907			quantity = (isQuantityFloat ? parseFloat(quantity) : parseInt(quantity, 10)) || 0;
1908			if (quantity < 0)
1909			{
1910				quantity = 0;
1911			}
1912
1913			if (measureRatio > 0 && quantity < measureRatio)
1914			{
1915				quantity = measureRatio;
1916			}
1917
1918			if (itemData.CHECK_MAX_QUANTITY === 'Y')
1919			{
1920				availableQuantity = isQuantityFloat ? parseFloat(itemData.AVAILABLE_QUANTITY) : parseInt(itemData.AVAILABLE_QUANTITY);
1921				if (availableQuantity > 0 && quantity > availableQuantity)
1922				{
1923					quantity = availableQuantity;
1924				}
1925			}
1926
1927			var reminder = (quantity / measureRatio - ((quantity / measureRatio).toFixed(0))).toFixed(5),
1928				remain;
1929
1930			if (parseFloat(reminder) === 0)
1931			{
1932				return quantity;
1933			}
1934
1935			if (measureRatio !== 0 && measureRatio !== 1)
1936			{
1937				remain = (quantity * this.precisionFactor) % (measureRatio * this.precisionFactor) / this.precisionFactor;
1938
1939				if (measureRatio > 0 && remain > 0)
1940				{
1941					if (
1942						remain >= measureRatio / 2
1943						&& (
1944							availableQuantity === 0
1945							|| (quantity + measureRatio - remain) <= availableQuantity
1946						)
1947					)
1948					{
1949						quantity += (measureRatio - remain);
1950					}
1951					else
1952					{
1953						quantity -= remain;
1954					}
1955				}
1956			}
1957
1958			quantity = isQuantityFloat ? parseFloat(quantity) : parseInt(quantity, 10);
1959
1960			return quantity;
1961		},
1962
1963		setQuantity: function(itemData, quantity)
1964		{
1965			var quantityField = BX(this.ids.quantity + itemData.ID),
1966				currentQuantity;
1967
1968			if (quantityField)
1969			{
1970				quantity = parseFloat(quantity);
1971				currentQuantity = parseFloat(quantityField.getAttribute('data-value'));
1972
1973				quantityField.value = quantity;
1974
1975				if (parseFloat(itemData.QUANTITY) !== parseFloat(quantity))
1976				{
1977					this.animatePriceByQuantity(itemData, quantity);
1978					this.actionPool.changeQuantity(itemData.ID, quantity, currentQuantity);
1979				}
1980			}
1981		},
1982
1983		animatePriceByQuantity: function(itemData, quantity)
1984		{
1985			var priceNode = BX(this.ids.sumPrice + itemData.ID);
1986			if (!BX.type.isDomNode(priceNode))
1987				return;
1988
1989			var quantityMultiplier = quantity / parseFloat(itemData.MEASURE_RATIO);
1990
1991			var startPrice = parseFloat(itemData.SUM_PRICE),
1992				finalPrice = parseFloat(itemData.PRICE) * quantityMultiplier,
1993				isInt = parseInt(startPrice) === parseFloat(startPrice)
1994					&& parseInt(finalPrice) === parseFloat(finalPrice);
1995
1996			if (startPrice !== finalPrice)
1997			{
1998				this.items[itemData.ID].QUANTITY = quantity;
1999				this.items[itemData.ID].SUM_PRICE = finalPrice;
2000
2001				new BX.easing({
2002					duration: this.params.USE_PRICE_ANIMATION === 'Y' ? this.duration.priceAnimation : 1,
2003					start: {price: startPrice},
2004					finish: {price: finalPrice},
2005					transition: BX.easing.makeEaseOut(BX.easing.transitions.quad),
2006					step: BX.delegate(function(state){
2007						if (!isInt)
2008						{
2009							// fix price blinking
2010							state.price = (state.price + (state.price % 1000) / 1000).toFixed(5);
2011						}
2012
2013						priceNode.innerHTML = this.getFormatPrice(state.price, itemData.CURRENCY);
2014					}, this),
2015					complete: BX.delegate(function() {
2016						var node, price;
2017
2018						priceNode.innerHTML = this.getFormatPrice(finalPrice, itemData.CURRENCY);
2019
2020						node = BX(this.ids.sumPriceOld + itemData.ID);
2021						if (BX.type.isDomNode(node))
2022						{
2023							price = parseFloat(itemData.FULL_PRICE) * quantityMultiplier;
2024							node.innerHTML = this.getFormatPrice(price, itemData.CURRENCY);
2025						}
2026
2027						node = BX(this.ids.sumPriceDiff + itemData.ID);
2028						if (BX.type.isDomNode(node))
2029						{
2030							price = parseFloat(itemData.DISCOUNT_PRICE) * quantityMultiplier;
2031							node.innerHTML = this.getFormatPrice(price, itemData.CURRENCY);
2032						}
2033					}, this)
2034				}).animate();
2035			}
2036		},
2037
2038		getItemDataByTarget: function(target)
2039		{
2040			var data = false;
2041			var id;
2042
2043			var itemNode = BX.findParent(target, {attribute: {'data-entity': 'basket-item'}});
2044			if (itemNode)
2045			{
2046				id = itemNode.getAttribute('data-id');
2047				data = this.items[id];
2048			}
2049
2050			return data;
2051		},
2052
2053		bindSkuEvents: function(node, data)
2054		{
2055			if (!node || !data)
2056				return;
2057
2058			var blocks = this.getEntities(node, 'basket-item-sku-block');
2059			var blockEntities, i, l, ii, ll;
2060
2061			for (i = 0, l = blocks.length; i < l; i++)
2062			{
2063				blockEntities = this.getEntities(blocks[i], 'basket-item-sku-field');
2064
2065				for (ii = 0, ll = blockEntities.length; ii < ll; ii++)
2066				{
2067					BX.bind(blockEntities[ii], 'click', BX.proxy(this.changeSku, this));
2068				}
2069			}
2070		},
2071
2072		changeSku: function()
2073		{
2074			var i, l;
2075
2076			var target = BX.proxy_context;
2077
2078			if (BX.hasClass(target, 'selected'))
2079				return;
2080
2081			var itemData = this.getItemDataByTarget(target);
2082			if (itemData)
2083			{
2084				var basketItemNode = BX(this.ids.item + itemData.ID);
2085				if (basketItemNode)
2086				{
2087					var currentSkuListNodes = this.getEntities(target.parentNode, 'basket-item-sku-field');
2088					for (i = 0, l = currentSkuListNodes.length; i < l; i++)
2089					{
2090						if (currentSkuListNodes[i].isEqualNode(target))
2091						{
2092							BX.addClass(currentSkuListNodes[i], 'selected');
2093						}
2094						else
2095						{
2096							BX.removeClass(currentSkuListNodes[i], 'selected');
2097						}
2098					}
2099
2100					this.actionPool.changeSku(
2101						itemData.ID,
2102						this.getSkuPropertyValues(basketItemNode),
2103						this.getInitialSkuPropertyValues(basketItemNode)
2104					);
2105				}
2106			}
2107		},
2108
2109		getSkuPropertyValues: function(basketItemNode)
2110		{
2111			var propertyValues = {};
2112
2113			var propNodes = this.getEntities(basketItemNode, 'basket-item-sku-field', '.selected');
2114			for (var i = 0, l = propNodes.length; i < l; i++)
2115			{
2116				propertyValues[propNodes[i].getAttribute('data-property')] = BX.util.htmlspecialcharsback(propNodes[i].getAttribute('data-value-id'));
2117			}
2118
2119			return propertyValues;
2120		},
2121
2122		getInitialSkuPropertyValues: function(basketItemNode)
2123		{
2124			var propertyValues = {};
2125
2126			var propNodes = this.getEntities(basketItemNode, 'basket-item-sku-field', '[data-initial="true"]');
2127			for (var i = 0, l = propNodes.length; i < l; i++)
2128			{
2129				propertyValues[propNodes[i].getAttribute('data-property')] = BX.util.htmlspecialcharsback(propNodes[i].getAttribute('data-value-id'));
2130			}
2131
2132			return propertyValues;
2133		},
2134
2135		bindImageEvents: function(node, data)
2136		{
2137			if (!node || !data)
2138				return;
2139
2140			var images = node.querySelectorAll('.basket-item-custom-block-photo-item');
2141			for (var i = 0, l = images.length; i < l; i++)
2142			{
2143				BX.bind(images[i], 'click', BX.proxy(this.showPropertyImagePopup, this));
2144			}
2145		},
2146
2147		showPropertyImagePopup: function()
2148		{
2149			var target, propertyCode, imageIndex, item, imageSrc, i;
2150
2151			target = BX.proxy_context;
2152			item = this.getItemDataByTarget(target);
2153
2154			propertyCode = target.getAttribute('data-column-property-code');
2155			imageIndex = target.getAttribute('data-image-index');
2156
2157			if (item && item.COLUMN_LIST)
2158			{
2159				for (i in item.COLUMN_LIST)
2160				{
2161					if (
2162						item.COLUMN_LIST.hasOwnProperty(i)
2163						&& item.COLUMN_LIST[i].CODE === propertyCode
2164						&& item.COLUMN_LIST[i].VALUE[imageIndex]
2165					)
2166					{
2167						imageSrc = item.COLUMN_LIST[i].VALUE[imageIndex].IMAGE_SRC_ORIGINAL;
2168						break;
2169					}
2170				}
2171			}
2172
2173			if (!imageSrc)
2174			{
2175				return;
2176			}
2177
2178			if (this.imagePopup)
2179			{
2180				this.imagePopup.destroy();
2181			}
2182
2183			var imageId = 'bx-soa-image-popup-content';
2184			var that = this;
2185
2186			this.imagePopup = new BX.PopupWindow('bx-soa-image-popup', null, {
2187				lightShadow: true,
2188				offsetTop: 0,
2189				offsetLeft: 0,
2190				closeIcon: {top: '3px', right: '10px'},
2191				autoHide: true,
2192				bindOptions: {position: 'bottom'},
2193				closeByEsc: true,
2194				zIndex: 100,
2195				events: {
2196					onPopupShow: function() {
2197						BX.create('IMG', {
2198							props: {src: imageSrc},
2199							events: {
2200								load: function() {
2201									var content = BX(imageId);
2202									if (content)
2203									{
2204										var windowSize = BX.GetWindowInnerSize(),
2205											ratio = that.isMobile ? 0.5 : 0.9,
2206											contentHeight, contentWidth;
2207
2208										BX.cleanNode(content);
2209										content.appendChild(this);
2210
2211										contentHeight = content.offsetHeight;
2212										contentWidth = content.offsetWidth;
2213
2214										if (contentHeight >
2214 windowSize.innerHeight * ratio)
2215										{
2216											content.style.height = windowSize.innerHeight * ratio + 'px';
2217											content.style.width = contentWidth * (windowSize.innerHeight * ratio / contentHeight) + 'px';
2218											contentHeight = content.offsetHeight;
2219											contentWidth = content.offsetWidth;
2220										}
2221
2222										if (contentWidth > windowSize.innerWidth * ratio)
2223										{
2224											content.style.width = windowSize.innerWidth * ratio + 'px';
2225											content.style.height = contentHeight * (windowSize.innerWidth * ratio / contentWidth) + 'px';
2226										}
2227
2228										content.style.height = content.offsetHeight + 'px';
2229										content.style.width = content.offsetWidth + 'px';
2230
2231										that.imagePopup.adjustPosition();
2232									}
2233								}
2234							}
2235						});
2236					},
2237					onPopupClose: function() {
2238						this.destroy();
2239					}
2240				},
2241				content: BX.create('DIV', {props: {id: imageId}})
2242			});
2243			this.imagePopup.show();
2244		},
2245
2246		bindActionEvents: function(node, data)
2247		{
2248			if (!node || !data)
2249				return;
2250
2251			var entity;
2252
2253			if (BX.util.in_array('DELETE', this.params.COLUMNS_LIST))
2254			{
2255				entity = this.getEntities(node, 'basket-item-delete');
2256				for (var i = 0, l = entity.length; i < l; i++)
2257				{
2258					BX.bind(entity[i], 'click', BX.proxy(this.deleteAction, this));
2259				}
2260			}
2261
2262			if (BX.util.in_array('DELAY', this.params.COLUMNS_LIST))
2263			{
2264				entity = this.getEntity(node, 'basket-item-add-delayed');
2265				BX.bind(entity, 'click', BX.proxy(this.addDelayedAction, this));
2266			}
2267
2268			entity = this.getEntity(node, 'basket-item-remove-delayed');
2269			BX.bind(entity, 'click', BX.proxy(this.removeDelayedAction, this));
2270
2271			entity = this.getEntity(node, 'basket-item-merge-sku-link');
2272			BX.bind(entity, 'click', BX.proxy(this.mergeAction, this));
2273
2274			entity = this.getEntity(node, 'basket-item-show-similar-link');
2275			BX.bind(entity, 'click', BX.delegate(function() {this.toggleFilter('similar');}, this));
2276		},
2277
2278		deleteAction: function()
2279		{
2280			var itemData = this.getItemDataByTarget(BX.proxy_context);
2281			if (itemData)
2282			{
2283				this.actionPool.deleteItem(itemData.ID);
2284
2285				this.items[itemData.ID].SHOW_LOADING = true;
2286
2287				if (this.params.SHOW_RESTORE === 'Y' && this.isItemAvailable(itemData.ID))
2288				{
2289					this.items[itemData.ID].SHOW_RESTORE = true;
2290				}
2291
2292				this.redrawBasketItemNode(itemData.ID);
2293				BX.onCustomEvent("OnBasketChange");
2294			}
2295		},
2296
2297		addDelayedAction: function()
2298		{
2299			var itemData = this.getItemDataByTarget(BX.proxy_context);
2300			if (itemData)
2301			{
2302				this.actionPool.addDelayed(itemData.ID);
2303
2304				this.items[itemData.ID].SHOW_LOADING = true;
2305				this.redrawBasketItemNode(itemData.ID);
2306			}
2307		},
2308
2309		removeDelayedAction: function()
2310		{
2311			var itemData = this.getItemDataByTarget(BX.proxy_context);
2312			if (itemData)
2313			{
2314				this.actionPool.removeDelayed(itemData.ID);
2315
2316				this.items[itemData.ID].SHOW_LOADING = true;
2317				this.redrawBasketItemNode(itemData.ID);
2318			}
2319		},
2320
2321		mergeAction: function()
2322		{
2323			var itemData = this.getItemDataByTarget(BX.proxy_context);
2324			if (itemData)
2325			{
2326				this.actionPool.mergeSku(itemData.ID);
2327			}
2328		},
2329
2330		bindRestoreAction: function(node, itemData)
2331		{
2332			if (!node || !itemData || this.params.SHOW_RESTORE !== 'Y')
2333				return;
2334
2335			BX.bind(
2336				this.getEntity(node, 'basket-item-restore-button'),
2337				'click',
2338				BX.delegate(function() {
2339					this.actionPool.restoreItem(itemData.ID, {
2340						PRODUCT_ID: itemData.PRODUCT_ID,
2341						QUANTITY: itemData.QUANTITY,
2342						PROPS: itemData.PROPS_ALL,
2343						SORT: itemData.SORT,
2344						MODULE: itemData.MODULE,
2345						PRODUCT_PROVIDER_CLASS: itemData.PRODUCT_PROVIDER_CLASS
2346					});
2347
2348					this.items[itemData.ID].SHOW_RESTORE = false;
2349					this.items[itemData.ID].SHOW_LOADING = true;
2350					this.redrawBasketItemNode(itemData.ID);
2351				}, this)
2352			);
2353			BX.bind(
2354				this.getEntity(node, 'basket-item-close-restore-button'),
2355				'click',
2356				BX.delegate(function() {
2357					this.deleteBasketItem(itemData.ID, false, true);
2358				}, this)
2359			);
2360		},
2361
2362		bindItemWarningEvents: function(node, data)
2363		{
2364			if (!node || !data)
2365				return;
2366
2367			BX.bind(
2368				this.getEntity(BX(this.ids.item + data.ID), 'basket-item-warning-close'),
2369				'click',
2370				BX.proxy(this.closeItemWarnings, this)
2371			);
2372		},
2373
2374		closeItemWarnings: function()
2375		{
2376			var target = BX.proxy_context;
2377
2378			if (BX.type.isDomNode(target))
2379			{
2380				var itemData = this.getItemDataByTarget(target);
2381
2382				this.items[itemData.ID].WARNINGS = [];
2383				this.warningItems.splice(BX.util.array_search(itemData.ID, this.warningItems), 1);
2384
2385				this.redrawBasketItemNode(itemData.ID);
2386				this.editWarnings();
2387			}
2388		},
2389
2390		renderBasketItem: function(template, data)
2391		{
2392			var clonedData = BX.clone(data);
2393
2394			if (BX.type.isPlainObject(clonedData))
2395			{
2396				clonedData.USE_FILTER = this.useItemsFilter
2397					&& !this.filter.currentFilter.similarHash.length;
2398			}
2399
2400			return Mustache.render(template, clonedData);
2401		},
2402
2403		render: function(template, data)
2404		{
2405			return Mustache.render(template, data);
2406		},
2407
2408		checkAnalytics: function(data)
2409		{
2410			if (!data || !data.basket)
2411				return;
2412
2413			var itemId, itemsDiff = {};
2414
2415			for (var i in data.basket)
2416			{
2417				if (data.basket.hasOwnProperty(i) && i.indexOf('QUANTITY_') >= 0)
2418				{
2419					itemId = i.substr(9);
2420
2421					if (this.items[itemId])
2422					{
2423						itemsDiff[itemId] = parseFloat(data.basket[i]) - parseFloat(BX(this.ids.quantity + itemId).getAttribute('data-value'));
2424					}
2425				}
2426			}
2427
2428			this.setAnalyticsDataLayer(itemsDiff);
2429		},
2430
2431		setAnalyticsDataLayer: function(itemsDiff)
2432		{
2433			if (!itemsDiff || Object.keys(itemsDiff).length === 0)
2434				return;
2435
2436			window[this.params.DATA_LAYER_NAME] = window[this.params.DATA_LAYER_NAME] || [];
2437
2438			var plus = [], minus = [];
2439
2440			for (var itemId in itemsDiff)
2441			{
2442				if (itemsDiff.hasOwnProperty(itemId))
2443				{
2444					if (itemsDiff[itemId] > 0)
2445					{
2446						plus.push(this.getItemAnalyticsInfo(itemId, itemsDiff[itemId]));
2447					}
2448					else if (itemsDiff[itemId] < 0)
2449					{
2450						minus.push(this.getItemAnalyticsInfo(itemId, itemsDiff[itemId]));
2451					}
2452				}
2453			}
2454
2455			if (plus.length)
2456			{
2457				window[this.params.DATA_LAYER_NAME].push({
2458					event: 'addToCart',
2459					ecommerce: {
2460						currencyCode: this.items[itemId].CURRENCY || '',
2461						add: {
2462							products: plus
2463						}
2464					}
2465				});
2466			}
2467
2468			if (minus.length)
2469			{
2470				window[this.params.DATA_LAYER_NAME].push({
2471					event: 'removeFromCart',
2472					ecommerce: {
2473						currencyCode: this.items[itemId].CURRENCY || '',
2474						remove: {
2475							products: minus
2476						}
2477					}
2478				});
2479			}
2480		},
2481
2482		getItemAnalyticsInfo: function(itemId, diff)
2483		{
2484			if (!this.items[itemId])
2485				return {};
2486
2487			var brand = (this.items[itemId].BRAND || '').split(',  ').join('/');
2488			var variants = [];
2489
2490			var selectedSku = this.getEntities(BX(this.ids.item + itemId), 'basket-item-sku-field', '.selected');
2491			for (var i = 0, l = selectedSku.length; i < l; i++)
2492			{
2493				variants.push(selectedSku[i].getAttribute('data-sku-name'));
2494			}
2495
2496			return {
2497				'name': this.items[itemId].NAME || '',
2498				'id': this.items[itemId].ID || '',
2499				'price': this.items[itemId].PRICE || 0,
2500				'brand': brand,
2501				'variant': variants.join('/'),
2502				'quantity': Math.abs(diff)
2503			};
2504		}
2505	};
2506})();

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.