PageSourceSearch

https://xokk.ru/local/templates/xokk/components/bitrix/catalog.item/main/script.js?176140551070537

js xokk.ru collected 2026-10-08 14:44:10 UTC 70,537 bytes, 1,810 lines download raw bytes

1(function (window) {
2    'use strict';
3
4    if (window.JCCatalogItem)
5        return;
6
7    var BasketButton = function (params) {
8        BasketButton.superclass.constructor.apply(this, arguments);
9        this.buttonNode = BX.create('span', {
10            props: {className: 'btn btn-default btn-buy btn-sm', id: this.id},
11            style: typeof params.style === 'object' ? params.style : {},
12            text: params.text,
13            events: this.contextEvents
14        });
15
16        if (BX.browser.IsIE()) {
17            this.buttonNode.setAttribute("hideFocus", "hidefocus");
18        }
19    };
20    BX.extend(BasketButton, BX.PopupWindowButton);
21
22    window.JCCatalogItem = function (arParams) {
23        this.productType = 0;
24        this.showQuantity = true;
25        this.showAbsent = true;
26        this.secondPict = false;
27        this.showOldPrice = false;
28        this.showMaxQuantity = 'N';
29        this.relativeQuantityFactor = 5;
30        this.showPercent = false;
31        this.showSkuProps = false;
32        this.basketAction = 'ADD';
33        this.showClosePopup = false;
34        this.useCompare = false;
35        this.showSubscription = false;
36        this.visual = {
37            ID: '',
38            PICT_ID: '',
39            SECOND_PICT_ID: '',
40            PICT_SLIDER_ID: '',
41            QUANTITY_ID: '',
42            QUANTITY_UP_ID: '',
43            QUANTITY_DOWN_ID: '',
44            PRICE_ID: '',
45            PRICE_OLD_ID: '',
46            DSC_PERC: '',
47            SECOND_DSC_PERC: '',
48            DISPLAY_PROP_DIV: '',
49            BASKET_PROP_DIV: '',
50            SUBSCRIBE_ID: ''
51        };
52        this.product = {
53            checkQuantity: false,
54            maxQuantity: 0,
55            stepQuantity: 1,
56            isDblQuantity: false,
57            canBuy: true,
58            name: '',
59            pict: {},
60            id: 0,
61            addUrl: '',
62            buyUrl: ''
63        };
64
65        this.basketMode = '';
66        this.basketData = {
67            useProps: false,
68            emptyProps: false,
69            quantity: 'quantity',
70            props: 'prop',
71            basketUrl: '',
72            sku_props: '',
73            sku_props_var: 'basket_props',
74            add_url: '',
75            buy_url: ''
76        };
77
78        this.compareData = {
79            compareUrl: '',
80            compareDeleteUrl: '',
81            comparePath: ''
82        };
83
84        this.defaultPict = {
85            pict: null,
86            secondPict: null
87        };
88
89        this.defaultSliderOptions = {
90            interval: 3000,
91            wrap: true
92        };
93        this.slider = {
94            options: {},
95            items: [],
96            active: null,
97            sliding: null,
98            paused: null,
99            interval: null,
100            progress: null
101        };
102        this.touch = null;
103
104        this.quantityDelay = null;
105        this.quantityTimer = null;
106
107        this.checkQuantity = false;
108        this.maxQuantity = 0;
109        this.minQuantity = 0;
110        this.stepQuantity = 1;
111        this.isDblQuantity = false;
112        this.canBuy = true;
113        this.precision = 6;
114        this.precisionFactor = Math.pow(10, this.precision);
115        this.bigData = false;
116        this.fullDisplayMode = false;
117        this.viewMode = '';
118        this.templateTheme = '';
119
120        this.currentPriceMode = '';
121        this.currentPrices = [];
122        this.currentPriceSelected = 0;
123        this.currentQuantityRanges = [];
124        this.currentQuantityRangeSelected = 0;
125
126        this.offers = [];
127        this.offerNum = 0;
128        this.treeProps = [];
129        this.selectedValues = {};
130
131        this.obProduct = null;
132        this.blockNodes = {};
133        this.obQuantity = null;
134        this.obQuantityUp = null;
135        this.obQuantityDown = null;
136        this.obQuantityLimit = {};
137        this.obPict = null;
138        this.obSecondPict = null;
139        this.obPictSlider = null;
140        this.obPictSliderIndicator = null;
141        this.obPrice = null;
142        this.obTree = null;
143        this.obBuyBtn = null;
144        this.obOkBtn = null;
145        this.obBasketActions = null;
146        this.obNotAvail = null;
147        this.obSubscribe = null;
148        this.obDscPerc = null;
149        this.obSecondDscPerc = null;
150        this.obSkuProps = null;
151        this.obMeasure = null;
152        this.obCompare = null;
153
154        this.obPopupWin = null;
155        this.basketUrl = '';
156        this.basketParams = {};
157        this.isTouchDevice = BX.hasClass(document.documentElement, 'bx-touch');
158        this.hoverTimer = null;
159        this.hoverStateChangeForbidden = false;
160        this.mouseX = null;
161        this.mouseY = null;
162
163        this.useEnhancedEcommerce = false;
164        this.dataLayerName = 'dataLayer';
165        this.brandProperty = false;
166
167        this.errorCode = 0;
168
169        if (typeof arParams === 'object') {
170            if (arParams.PRODUCT_TYPE) {
171                this.productType = parseInt(arParams.PRODUCT_TYPE, 10);
172            }
173
174            this.showQuantity = false;//arParams.SHOW_QUANTITY;
175            this.showAbsent = arParams.SHOW_ABSENT;
176            this.secondPict = arParams.SECOND_PICT;
177            this.showOldPrice = arParams.SHOW_OLD_PRICE;
178            this.showMaxQuantity = arParams.SHOW_MAX_QUANTITY;
179            this.relativeQuantityFactor = parseInt(arParams.RELATIVE_QUANTITY_FACTOR);
180            this.showPercent = arParams.SHOW_DISCOUNT_PERCENT;
181            this.showSkuProps = arParams.SHOW_SKU_PROPS;
182            this.showSubscription = arParams.USE_SUBSCRIBE;
183
184            if (arParams.ADD_TO_BASKET_ACTION) {
185                this.basketAction = arParams.ADD_TO_BASKET_ACTION;
186            }
187
188            this.showClosePopup = arParams.SHOW_CLOSE_POPUP;
189            this.useCompare = arParams.DISPLAY_COMPARE;
190            this.fullDisplayMode = arParams.PRODUCT_DISPLAY_MODE === 'Y';
191            this.bigData = arParams.BIG_DATA;
192            this.viewMode = arParams.VIEW_MODE || '';
193            this.templateTheme = arParams.TEMPLATE_THEME || '';
194            this.useEnhancedEcommerce = arParams.USE_ENHANCED_ECOMMERCE === 'Y';
195            this.dataLayerName = arParams.DATA_LAYER_NAME;
196            this.brandProperty = arParams.BRAND_PROPERTY;
197
198            this.visual = arParams.VISUAL;
199
200            switch (this.productType) {
201                case 0: // no catalog
202                case 1: // product
203                case 2: // set
204                    if (arParams.PRODUCT && typeof arParams.PRODUCT === 'object') {
205                        this.currentPriceMode = arParams.PRODUCT.ITEM_PRICE_MODE;
206                        this.currentPrices = arParams.PRODUCT.ITEM_PRICES;
207                        this.currentPriceSelected = arParams.PRODUCT.ITEM_PRICE_SELECTED;
208                        this.currentQuantityRanges = arParams.PRODUCT.ITEM_QUANTITY_RANGES;
209                        this.currentQuantityRangeSelected = arParams.PRODUCT.ITEM_QUANTITY_RANGE_SELECTED;
210
211                        if (this.showQuantity) {
212                            this.product.checkQuantity = arParams.PRODUCT.CHECK_QUANTITY;
213                            this.product.isDblQuantity = arParams.PRODUCT.QUANTITY_FLOAT;
214
215                            if (this.product.checkQuantity) {
216                                this.product.maxQuantity = (this.product.isDblQuantity ? parseFloat(arParams.PRODUCT.MAX_QUANTITY) : parseInt(arParams.PRODUCT.MAX_QUANTITY, 10));
217                            }
218
219                            this.product.stepQuantity = (this.product.isDblQuantity ? parseFloat(arParams.PRODUCT.STEP_QUANTITY) : parseInt(arParams.PRODUCT.STEP_QUANTITY, 10));
220
221                            this.checkQuantity = this.product.checkQuantity;
222                            this.isDblQuantity = this.product.isDblQuantity;
223                            this.stepQuantity = this.product.stepQuantity;
224                            this.maxQuantity = this.product.maxQuantity;
225                            this.minQuantity = this.currentPriceMode === 'Q'
226                                ? parseFloat(this.currentPrices[this.currentPriceSelected].MIN_QUANTITY)
227                                : this.stepQuantity;
228
229                            if (this.isDblQuantity) {
230                                this.stepQuantity = Math.round(this.stepQuantity * this.precisionFactor) / this.precisionFactor;
231                            }
232                        }
233
234                        this.product.canBuy = arParams.PRODUCT.CAN_BUY;
235
236                        if (arParams.PRODUCT.MORE_PHOTO_COUNT) {
237                            this.product.morePhotoCount = arParams.PRODUCT.MORE_PHOTO_COUNT;
238                            this.product.morePhoto = arParams.PRODUCT.MORE_PHOTO;
239                        }
240
241                        if (arParams.PRODUCT.RCM_ID) {
242                            this.product.rcmId = arParams.PRODUCT.RCM_ID;
243                        }
244
245                        this.canBuy = this.product.canBuy;
246                        this.product.name = arParams.PRODUCT.NAME;
247                        this.product.pict = arParams.PRODUCT.PICT;
248                        this.product.id = arParams.PRODUCT.ID;
249                        this.product.DETAIL_PAGE_URL = arParams.PRODUCT.DETAIL_PAGE_URL;
250
251                        if (arParams.PRODUCT.ADD_URL) {
252                            this.product.addUrl = arParams.PRODUCT.ADD_URL;
253                        }
254
255                        if (arParams.PRODUCT.BUY_URL) {
256                            this.product.buyUrl = arParams.PRODUCT.BUY_URL;
257                        }
258
259                        if (arParams.BASKET && typeof arParams.BASKET === 'object') {
260                            this.basketData.useProps = arParams.BASKET.ADD_PROPS;
261                            this.basketData.emptyProps = arParams.BASKET.EMPTY_PROPS;
262                        }
263                    } else {
264                        this.errorCode = -1;
265                    }
266
267                    break;
268                case 3: // sku
269                    if (arParams.PRODUCT && typeof arParams.PRODUCT === 'object') {
270                        this.product.name = arParams.PRODUCT.NAME;
271                        this.product.id = arParams.PRODUCT.ID;
272                        this.product.DETAIL_PAGE_URL = arParams.PRODUCT.DETAIL_PAGE_URL;
273                        this.product.morePhotoCount = arParams.PRODUCT.MORE_PHOTO_COUNT;
274                        this.product.morePhoto = arParams.PRODUCT.MORE_PHOTO;
275
276                        if (arParams.PRODUCT.RCM_ID) {
277                            this.product.rcmId = arParams.PRODUCT.RCM_ID;
278                        }
279                    }
280
281                    if (arParams.OFFERS && BX.type.isArray(arParams.OFFERS)) {
282                        this.offers = arParams.OFFERS;
283                        this.offerNum = 0;
284
285                        if (arParams.OFFER_SELECTED) {
286                            this.offerNum = parseInt(arParams.OFFER_SELECTED, 10);
287                        }
288
289                        if (isNaN(this.offerNum)) {
290                            this.offerNum = 0;
291                        }
292
293                        if (arParams.TREE_PROPS) {
294                            this.treeProps = arParams.TREE_PROPS;
295                        }
296
297                        if (arParams.DEFAULT_PICTURE) {
298                            this.defaultPict.pict = arParams.DEFAULT_PICTURE.PICTURE;
299                            this.defaultPict.secondPict = arParams.DEFAULT_PICTURE.PICTURE_SECOND;
300                        }
301                    }
302
303                    break;
304                default:
305                    this.errorCode = -1;
306            }
307            if (arParams.BASKET && typeof arParams.BASKET === 'object') {
308                if (arParams.BASKET.QUANTITY) {
309                    this.basketData.quantity = arParams.BASKET.QUANTITY;
310                }
311
312                if (arParams.BASKET.PROPS) {
313                    this.basketData.props = arParams.BASKET.PROPS;
314                }
315
316                if (arParams.BASKET.BASKET_URL) {
317                    this.basketData.basketUrl = arParams.BASKET.BASKET_URL;
318                }
319
320                if (3 === this.productType) {
321                    if (arParams.BASKET.SKU_PROPS) {
322                        this.basketData.sku_props = arParams.BASKET.SKU_PROPS;
323                    }
324                }
325
326                if (arParams.BASKET.ADD_URL_TEMPLATE) {
327                    this.basketData.add_url = arParams.BASKET.ADD_URL_TEMPLATE;
328                }
329
330                if (arParams.BASKET.BUY_URL_TEMPLATE) {
331                    this.basketData.buy_url = arParams.BASKET.BUY_URL_TEMPLATE;
332                }
333
334                if (this.basketData.add_url === '' && this.basketData.buy_url === '') {
335                    this.errorCode = -1024;
336                }
337            }
338
339            if (this.useCompare) {
340                if (arParams.COMPARE && typeof arParams.COMPARE === 'object') {
341                    if (arParams.COMPARE.COMPARE_PATH) {
342                        this.compareData.comparePath = arParams.COMPARE.COMPARE_PATH;
343                    }
344
345                    if (arParams.COMPARE.COMPARE_URL_TEMPLATE) {
346                        this.compareData.compareUrl = arParams.COMPARE.COMPARE_URL_TEMPLATE;
347                    } else {
348                        this.useCompare = false;
349                    }
350
351                    if (arParams.COMPARE.COMPARE_DELETE_URL_TEMPLATE) {
352                        this.compareData.compareDeleteUrl = arParams.COMPARE.COMPARE_DELETE_URL_TEMPLATE;
353                    } else {
354                        this.useCompare = false;
355                    }
356                } else {
357                    this.useCompare = false;
358                }
359            }
360
361            this.isFacebookConversionCustomizeProductEventEnabled
362                = arParams.IS_FACEBOOK_CONVERSION_CUSTOMIZE_PRODUCT_EVENT_ENABLED
363            ;
364        }
365
366        if (this.errorCode === 0) {
367            BX.ready(BX.delegate(this.init, this));
368        }
369    };
370
371    window.JCCatalogItem.prototype = {
372        init: function () {
373            var i = 0,
374                treeItems = null;
375
376            this.obProduct = BX(this.visual.ID);
377            if (!this.obProduct) {
378                this.errorCode = -1;
379            }
380
381            this.obPict = BX(this.visual.PICT_ID);
382            if (!this.obPict) {
383                this.errorCode = -2;
384            }
385
386            if (this.secondPict && this.visual.SECOND_PICT_ID) {
387                this.obSecondPict = BX(this.visual.SECOND_PICT_ID);
388            }
389
390            this.obPrice = BX(this.visual.PRICE_ID);
391            this.obPriceOld = BX(this.visual.PRICE_OLD_ID);
392            this.obPriceTotal = BX(this.visual.PRICE_TOTAL_ID);
393            if (!this.obPrice) {
394                this.errorCode = -16;
395            }
396
397            if (this.showQuantity && this.visual.QUANTITY_ID) {
398                this.obQuantity = BX(this.visual.QUANTITY_ID);
399                this.blockNodes.quantity = this.obProduct.querySelector('[data-entity="quantity-block"]');
400
401                if (!this.isTouchDevice) {
402                    BX.bind(this.obQuantity, 'focus', BX.proxy(this.onFocus, this));
403                    BX.bind(this.obQuantity, 'blur', BX.proxy(this.onBlur, this));
404                }
405
406                if (this.visual.QUANTITY_UP_ID) {
407                    this.obQuantityUp = BX(this.visual.QUANTITY_UP_ID);
408                }
409
410                if (this.visual.QUANTITY_DOWN_ID) {
411                    this.obQuantityDown = BX(this.visual.QUANTITY_DOWN_ID);
412                }
413            }
414
415            if (this.visual.QUANTITY_LIMIT && this.showMaxQuantity !== 'N') {
416                this.obQuantityLimit.all = BX(this.visual.QUANTITY_LIMIT);
417                if (this.obQuantityLimit.all) {
418                    this.obQuantityLimit.value = this.obQuantityLimit.all.querySelector('[data-entity="quantity-limit-value"]');
419                    if (!this.obQuantityLimit.value) {
420                        this.obQuantityLimit.all = null;
421                    }
422                }
423            }
424
425            if (this.productType === 3 && this.fullDisplayMode) {
426                if (this.visual.TREE_ID) {
427                    this.obTree = BX(this.visual.TREE_ID);
428                    if (!this.obTree) {
429                        this.errorCode = -256;
430                    }
431                }
432
433                if (this.visual.QUANTITY_MEASURE) {
434                    this.obMeasure = BX(this.visual.QUANTITY_MEASURE);
435                }
436            }
437
438            this.obBasketActions = BX(this.visual.BASKET_ACTIONS_ID);
439            if (this.obBasketActions) {
440                if (this.visual.BUY_ID) {
441                    this.obBuyBtn = BX(this.visual.BUY_ID);
442                    this.obOkBtn = BX('ok_' + this.visual.BUY_ID);
443                }
444            }
445
446            this.obNotAvail = BX(this.visual.NOT_AVAILABLE_MESS);
447
448            if (this.showSubscription) {
449                this.obSubscribe = BX(this.visual.SUBSCRIBE_ID);
450            }
451
452            if (this.showPercent) {
453                if (this.visual.DSC_PERC) {
454                    this.obDscPerc = BX(this.visual.DSC_PERC);
455                }
456                if (this.secondPict && this.visual.SECOND_DSC_PERC) {
457                    this.obSecondDscPerc = BX(this.visual.SECOND_DSC_PERC);
458                }
459            }
460
461            if (this.showSkuProps) {
462                if (this.visual.DISPLAY_PROP_DIV) {
463                    this.obSkuProps = BX(this.visual.DISPLAY_PROP_DIV);
464                }
465            }
466            if (this.errorCode === 0) {
467                if (this.bigData) {
468                    var links = BX.findChildren(this.obProduct, {tag: 'a'}, true);
469                    if (links) {
470                        for (i in links) {
471                            if (links.hasOwnProperty(i)) {
472                                if (links[i].getAttribute('href') == this.product.DETAIL_PAGE_URL) {
473                                    BX.bind(links[i], 'click', BX.proxy(this.rememberProductRecommendation, this));
474                                }
475                            }
476                        }
477                    }
478                }
479
480                if (this.showQuantity) {
481                    var startEventName = this.isTouchDevice ? 'touchstart' : 'mousedown';
482                    var endEventName = this.isTouchDevice ? 'touchend' : 'mouseup';
483
484                    if (this.obQuantityUp) {
485                        BX.bind(this.obQuantityUp, startEventName, BX.proxy(this.startQuantityInterval, this));
486                        BX.bind(this.obQuantityUp, endEventName, BX.proxy(this.clearQuantityInterval, this));
487                        BX.bind(this.obQuantityUp, 'mouseout', BX.proxy(this.clearQuantityInterval, this));
488                        BX.bind(this.obQuantityUp, 'click', BX.delegate(this.quantityUp, this));
489                    }
490
491                    if (this.obQuantityDown) {
492                        BX.bind(this.obQuantityDown, startEventName, BX.proxy(this.startQuantityInterval, this));
493                        BX.bind(this.obQuantityDown, endEventName, BX.proxy(this.clearQuantityInterval, this));
494                        BX.bind(this.obQuantityDown, 'mouseout', BX.proxy(this.clearQuantityInterval, this));
495                        BX.bind(this.obQuantityDown, 'click', BX.delegate(this.quantityDown, this));
496                    }
497
498                    if (this.obQuantity) {
499                        BX.bind(this.obQuantity, 'change', BX.delegate(this.quantityChange, this));
500                    }
501                }
502
503                switch (this.productType) {
504                    case 0: // no catalog
505                    case 1: // product
506                    case 2: // set
507                        this.checkQuantityControls();
508
509                        break;
510                    case 3: // sku
511                        if (this.offers.length > 0) {
512                            treeItems = BX.findChildren(this.obTree, {tagName: 'li'}, true);
513
514                            if (treeItems && treeItems.length) {
515                                for (i = 0; i < treeItems.length; i++) {
516                                    BX.bind(treeItems[i], 'click', BX.delegate(this.selectOfferProp, this));
517                                }
518                            }
519
520                            this.setCurrent();
521                        }
522                        break;
523                }
524                if (this.obBuyBtn) {
525                    if (this.basketAction === 'ADD') {
526                        BX.bind(this.obBuyBtn, 'click', BX.proxy(this.add2Basket, this));
527                    } else {
528                        BX.bind(this.obBuyBtn, 'click', BX.proxy(this.buyBasket, this));
529                    }
530                }
531
532                if (this.useCompare) {
533                    this.obCompare = BX(this.visual.COMPARE_LINK_ID);
534                    if (this.obCompare) {
535                        BX.bind(this.obCompare, 'click', BX.proxy(this.compare, this));
536                    }
537
538                    BX.addCustomEvent('onCatalogDeleteCompare', BX.proxy(this.checkDeletedCompare, this));
539                }
540            }
541        },
542
543        setAnalyticsDataLayer: function (action) {
544            if (!this.useEnhancedEcommerce || !this.dataLayerName)
545                return;
546
547            var item = {},
548                info = {},
549                variants = [],
550                i, k, j, propId, skuId, propValues;
551
552            switch (this.productType) {
553                case 0: //no catalog
554                case 1: //product
555                case 2: //set
556                    item = {
557                        'id': this.product.id,
558                        'name': this.product.name,
559                        'price': this.currentPrices[this.currentPriceSelected] && this.currentPrices[this.currentPriceSelected].PRICE,
560                        'brand': BX.type.isArray(this.brandProperty) ? this.brandProperty.join('/') : this.brandProperty
561                    };
562                    break;
563                case 3: //sku
564                    for (i in this.offers[this.offerNum].TREE) {
565                        if (this.offers[this.offerNum].TREE.hasOwnProperty(i)) {
566                            propId = i.substring(5);
567                            skuId = this.offers[this.offerNum].TREE[i];
568
569                            for (k in this.treeProps) {
570                                if (this.treeProps.hasOwnProperty(k) && this.treeProps[k].ID == propId) {
571                                    for (j in this.treeProps[k].VALUES) {
572                                        propValues = this.treeProps[k].VALUES[j];
573                                        if (propValues.ID == skuId) {
574                                            variants.push(propValues.NAME);
575                                            break;
576                                        }
577                                    }
578
579                                }
580                            }
581                        }
582                    }
583
584                    item = {
585                        'id': this.offers[this.offerNum].ID,
586                        'name': this.offers[this.offerNum].NAME,
587                        'price': this.currentPrices[this.currentPriceSelected] && this.currentPrices[this.currentPriceSelected].PRICE,
588                        'brand': BX.type.isArray(this.brandProperty) ? this.brandProperty.join('/') : this.brandProperty,
589                        'variant': variants.join('/')
590                    };
591                    break;
592            }
593
594            switch (action) {
595                case 'addToCart':
596                    info = {
597                        'ecommerce': {
598                            'currencyCode': this.currentPrices[this.currentPriceSelected] && this.currentPrices[this.currentPriceSelected].CURRENCY || '',
599                            'add': {
600                                'products': [{
601                                    'name': item.name || '',
602                                    'id': item.id || '',
603                                    'price': item.price || 0,
604                                    'brand': item.brand || '',
605                                    'category': item.category || '',
606                                    'variant': item.variant || '',
607                                    'quantity': this.showQuantity && this.obQuantity ? this.obQuantity.value : 1
608                                }]
609                            }
610                        }
611                    };
612                    break;
613            }
614
615            window[this.dataLayerName] = window[this.dataLayerName] || [];
616            window[this.dataLayerName].push(info);
617        },
618
619        hoverOn: function (event) {
620            clearTimeout(this.hoverTimer);
621            this.obProduct.style.height = getComputedStyle(this.obProduct).height;
622            BX.addClass(this.obProduct, 'hover');
623
624            BX.PreventDefault(event);
625        },
626
627        hoverOff: function (event) {
628            if (this.hoverStateChangeForbidden)
629                return;
630
631            BX.removeClass(this.obProduct, 'hover');
632            this.hoverTimer = setTimeout(
633                BX.delegate(function () {
634                    this.obProduct.style.height = 'auto';
635                }, this),
636                300
637            );
638
639            BX.PreventDefault(event);
640        },
641
642        onFocus: function () {
643            this.hoverStateChangeForbidden = true;
644            BX.bind(document, 'mousemove', BX.proxy(this.captureMousePosition, this));
645        },
646
647        onBlur: function () {
648            this.hoverStateChangeForbidden = false;
649            BX.unbind(document, 'mousemove', BX.proxy(this.captureMousePosition, this));
650
651            var cursorElement = document.elementFromPoint(this.mouseX, this.mouseY);
652            if (!cursorElement || !this.obProduct.contains(cursorElement)) {
653                this.hoverOff();
654            }
655        },
656
657        captureMousePosition: function (event) {
658            this.mouseX = event.clientX;
659            this.mouseY = event.clientY;
660        },
661
662        getCookie: function (name) {
663            var matches = document.cookie.match(new RegExp(
664                "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
665            ));
666
667            return matches ? decodeURIComponent(matches[1]) : null;
668        },
669
670        rememberProductRecommendation: function () {
671            // save to RCM_PRODUCT_LOG
672            var cookieName = BX.cookie_prefix + '_RCM_PRODUCT_LOG',
673                cookie = this.getCookie(cookieName),
674                itemFound = false;
675
676            var cItems = [],
677                cItem;
678
679            if (cookie) {
680                cItems = cookie.split('.');
681            }
682
683            var i = cItems.length;
684
685            while (i--) {
686                cItem = cItems[i].split('-');
687
688                if (cItem[0] == this.product.id) {
689                    // it's already in recommendations, update the date
690                    cItem = cItems[i].split('-');
691
692                    // update rcmId and date
693                    cItem[1] = this.product.rcmId;
694                    cItem[2] = BX.current_server_time;
695
696                    cItems[i] = cItem.join('-');
697                    itemFound = true;
698                } else {
699                    if ((BX.current_server_time - cItem[2]) > 3600 * 24 * 30) {
700                        cItems.splice(i, 1);
701                    }
702                }
703            }
704
705            if (!itemFound) {
706                // add recommendation
707                cItems.push([this.product.id, this.product.rcmId, BX.current_server_time].join('-'));
708            }
709
710            // serialize
711            var plNewCookie = cItems.join('.'),
712                cookieDate = new Date(new Date().getTime() + 1000 * 3600 * 24 * 365 * 10).toUTCString();
713
714            document.cookie = cookieName + "=" + plNewCookie + "; path=/; expires=" + cookieDate + "; domain=" + BX.cookie_domain;
715        },
716
717        startQuantityInterval: function () {
718            var target = BX.proxy_context;
719            var func = target.id === this.visual.QUANTITY_DOWN_ID
720                ? BX.proxy(this.quantityDown, this)
721                : BX.proxy(this.quantityUp, this);
722
723            this.quantityDelay = setTimeout(
724                BX.delegate(function () {
725                    this.quantityTimer = setInterval(func, 150);
726                }, this),
727                300
728            );
729        },
730
731        clearQuantityInterval: function () {
732            clearTimeout(this.quantityDelay);
733            clearInterval(this.quantityTimer);
734        },
735
736        quantityUp: function () {
737            var curValue = 0,
738                boolSet = true;
739
740            if (this.errorCode === 0 && this.showQuantity && this.canBuy) {
741                curValue = (this.isDblQuantity ? parseFloat(this.obQuantity.value) : parseInt(this.obQuantity.value, 10));
742                if (!isNaN(curValue)) {
743                    curValue += this.stepQuantity;
744                    if (this.checkQuantity) {
745                        if (curValue > this.maxQuantity) {
746                            boolSet = false;
747                        }
748                    }
749
750                    if (boolSet) {
751                        if (this.isDblQuantity) {
752                            curValue = Math.round(curValue * this.precisionFactor) / this.precisionFactor;
753                        }
754
755                        this.obQuantity.value = curValue;
756
757                        this.setPrice();
758                    }
759                }
760            }
761        },
762
763        quantityDown: function () {
764            var curValue = 0,
765                boolSet = true;
766
767            if (this.errorCode === 0 && this.showQuantity && this.canBuy) {
768                curValue = (this.isDblQuantity ? parseFloat(this.obQuantity.value) : parseInt(this.obQuantity.value, 10));
769                if (!isNaN(curValue)) {
770                    curValue -= this.stepQuantity;
771
772                    this.checkPriceRange(curValue);
773
774                    if (curValue < this.minQuantity) {
775                        boolSet = false;
776                    }
777
778                    if (boolSet) {
779                        if (this.isDblQuantity) {
780                            curValue = Math.round(curValue * this.precisionFactor) / this.precisionFactor;
781                        }
782
783                        this.obQuantity.value = curValue;
784
785                        this.setPrice();
786                    }
787                }
788            }
789        },
790
791        quantityChange: function () {
792            var curValue = 0,
793                intCount;
794
795            if (this.errorCode === 0 && this.showQuantity) {
796                if (this.canBuy) {
797                    curValue = this.isDblQuantity ? parseFloat(this.obQuantity.value) : Math.round(this.obQuantity.value);
798                    if (!isNaN(curValue)) {
799                        if (this.checkQuantity) {
800                            if (curValue > this.maxQuantity) {
801                                curValue = this.maxQuantity;
802                            }
803                        }
804
805                        this.checkPriceRange(curValue);
806
807                        intCount = Math.floor(
808                            Math.round(curValue * this.precisionFactor / this.stepQuantity) / this.precisionFactor
809                        ) || 1;
810                        curValue = (intCount <= 1 ? this.stepQuantity : intCount * this.stepQuantity);
811                        curValue = Math.round(curValue * this.precisionFactor) / this.precisionFactor;
812
813                        if (curValue < this.minQuantity) {
814                            curValue = this.minQuantity;
815                        }
816
817                        this.obQuantity.value = curValue;
818                    } else {
819                        this.obQuantity.value = this.minQuantity;
820                    }
821                } else {
822                    this.obQuantity.value = this.minQuantity;
823                }
824
825                this.setPrice();
826            }
827        },
828
829        quantitySet: function (index) {
830            var resetQuantity, strLimit;
831
832            var newOffer = this.offers[index],
833                oldOffer = this.offers[this.offerNum];
834
835            if (this.errorCode === 0) {
836                this.canBuy = newOffer.CAN_BUY;
837
838                this.currentPriceMode = newOffer.ITEM_PRICE_MODE;
839                this.currentPrices = newOffer.ITEM_PRICES;
840                this.currentPriceSelected = newOffer.ITEM_PRICE_SELECTED;
841                this.currentQuantityRanges = newOffer.ITEM_QUANTITY_RANGES;
842                this.currentQuantityRangeSelected = newOffer.ITEM_QUANTITY_RANGE_SELECTED;
843
844                if (this.canBuy) {
845                    if (this.blockNodes.quantity) {
846                        BX.style(this.blockNodes.quantity, 'display', '');
847                    }
848
849                    if (this.obBasketActions) {
850                        BX.style(this.obBasketActions, 'display', '');
851                    }
852
853                    if (this.obNotAvail) {
854                        BX.style(this.obNotAvail, 'display', 'none');
855                    }
856
857                    if (this.obSubscribe) {
858                        BX.style(this.obSubscribe, 'display', 'none');
859                    }
860                } else {
861                    if (this.blockNodes.quantity) {
862                        BX.style(this.blockNodes.quantity, 'display', 'none');
863                    }
864
865                    if (this.obBasketActions) {
866                        BX.style(this.obBasketActions, 'display', 'none');
867                    }
868
869                    if (this.obNotAvail) {
870                        BX.style(this.obNotAvail, 'display', '');
871                    }
872
873                    if (this.obSubscribe) {
874                        if (newOffer.CATALOG_SUBSCRIBE === 'Y') {
875                            BX.style(this.obSubscribe, 'display', '');
876                            this.obSubscribe.setAttribute('data-item', newOffer.ID);
877                            BX(this.visual.SUBSCRIBE_ID + '_hidden').click();
878                        } else {
879                            BX.style(this.obSubscribe, 'display', 'none');
880                        }
881                    }
882                }
883
884                this.isDblQuantity = newOffer.QUANTITY_FLOAT;
885                this.checkQuantity = newOffer.CHECK_QUANTITY;
886
887                if (this.isDblQuantity) {
888                    this.stepQuantity = Math.round(parseFloat(newOffer.STEP_QUANTITY) * this.precisionFactor) / this.precisionFactor;
889                    this.maxQuantity = parseFloat(newOffer.MAX_QUANTITY);
890                    this.minQuantity = this.currentPriceMode === 'Q' ? parseFloat(this.currentPrices[this.currentPriceSelected].MIN_QUANTITY) : this.stepQuantity;
891                } else {
892                    this.stepQuantity = parseInt(newOffer.STEP_QUANTITY, 10);
893                    this.maxQuantity = parseInt(newOffer.MAX_QUANTITY, 10);
894                    this.minQuantity = this.currentPriceMode === 'Q' ? parseInt(this.currentPrices[this.currentPriceSelected].MIN_QUANTITY) : this.stepQuantity;
895                }
896
897                if (this.showQuantity) {
898                    var isDifferentMinQuantity = oldOffer.ITEM_PRICES.length
899                        && oldOffer.ITEM_PRICES[oldOffer.ITEM_PRICE_SELECTED]
900                        && oldOffer.ITEM_PRICES[oldOffer.ITEM_PRICE_SELECTED].MIN_QUANTITY != this.minQuantity;
901
902                    if (this.isDblQuantity) {
903                        resetQuantity = Math.round(parseFloat(oldOffer.STEP_QUANTITY) * this.precisionFactor) / this.precisionFactor !== this.stepQuantity
904                            || isDifferentMinQuantity
905                            || oldOffer.MEASURE !== newOffer.MEASURE
906                            || (
907                                this.checkQuantity
908                                && parseFloat(oldOffer.MAX_QUANTITY) > this.maxQuantity
909                                && parseFloat(this.obQuantity.value) > this.maxQuantity
910                            );
911                    } else {
912                        resetQuantity = parseInt(oldOffer.STEP_QUANTITY, 10) !== this.stepQuantity
913                            || isDifferentMinQuantity
914                            || oldOffer.MEASURE !== newOffer.MEASURE
915                            || (
916                                this.checkQuantity
917                                && parseInt(oldOffer.MAX_QUANTITY, 10) > this.maxQuantity
918                                && parseInt(this.obQuantity.value, 10) > this.maxQuantity
919                            );
920                    }
921
922                    this.obQuantity.disabled = !this.canBuy;
923
924                    if (resetQuantity) {
925                        this.obQuantity.value = this.minQuantity;
926                    }
927
928                    if (this.obMeasure) {
929                        if (newOffer.MEASURE) {
930                            BX.adjust(this.obMeasure, {html: newOffer.MEASURE});
931                        } else {
932                            BX.adjust(this.obMeasure, {html: ''});
933                        }
934                    }
935                }
936
937                if (this.obQuantityLimit.all) {
938                    if (!this.checkQuantity || this.maxQuantity == 0) {
939                        BX.adjust(this.obQuantityLimit.value, {html: ''});
940                        BX.adjust(this.obQuantityLimit.all, {style: {display: 'none'}});
941                    } else {
942                        if (this.showMaxQuantity === 'M') {
943                            strLimit = (this.maxQuantity / this.stepQuantity >= this.relativeQuantityFactor)
944                                ? BX.message('RELATIVE_QUANTITY_MANY')
945                                : BX.message('RELATIVE_QUANTITY_FEW');
946                        } else {
947                            strLimit = this.maxQuantity;
948
949                            if (newOffer.MEASURE) {
950                                strLimit += (' ' + newOffer.MEASURE);
951                            }
952                        }
953
954                        BX.adjust(this.obQuantityLimit.value, {html: strLimit});
955                        BX.adjust(this.obQuantityLimit.all, {style: {display: ''}});
956                    }
957                }
958            }
959        },
960
961        checkTouch: function (event) {
962            if (!event || !event.changedTouches)
963                return false;
964
965            return event.changedTouches[0].identifier === this.touch.identifier;
966        },
967
968        touchStartEvent: function (event) {
969            if (event.touches.length != 1)
970                return;
971
972            this.touch = event.changedTouches[0];
973        },
974
975        touchEndEvent: function (event) {
976            if (!this.checkTouch(event))
977                return;
978
979            var deltaX = this.touch.pageX - event.changedTouches[0].pageX,
980                deltaY = this.touch.pageY - event.changedTouches[0].pageY;
981
982            if (Math.abs(deltaX) >= Math.abs(deltaY) + 10) {
983                if (deltaX > 0) {
984                    this.slideNext();
985                }
986
987                if (deltaX < 0) {
988                    this.slidePrev();
989                }
990            }
991        },
992
993        eq: function (obj, i) {
994            var len = obj.length,
995                j = +i + (i < 0 ? len : 0);
996
997            return j >= 0 && j < len ? obj[j] : {};
998        },
999
1000        selectOfferProp: function () {
1001            var i = 0,
1002                value = '',
1003                strTreeValue = '',
1004                arTreeItem = [],
1005                rowItems = null,
1006                target = BX.proxy_context;
1007
1008            if (target && target.hasAttribute('data-treevalue')) {
1009                if (BX.hasClass(target, 'selected'))
1010                    return;
1011
1012                strTreeValue = target.getAttribute('data-treevalue');
1013                arTreeItem = strTreeValue.split('_');
1014                if (this.searchOfferPropIndex(arTreeItem[0], arTreeItem[1])) {
1015                    rowItems = BX.findChildren(target.parentNode, {tagName: 'li'}, false);
1016                    if (rowItems && 0 < rowItems.length) {
1017                        for (i = 0; i < rowItems.length; i++) {
1018                            value = rowItems[i].getAttribute('data-onevalue');
1019                            if (value === arTreeItem[1]) {
1020                                BX.addClass(rowItems[i], 'selected');
1021                            } else {
1022                                BX.removeClass(rowItems[i], 'selected');
1023                            }
1024                        }
1025                    }
1026
1027                    if (
1028                        this.isFacebookConversionCustomizeProductEventEnabled
1029                        && BX.Type.isArrayFilled(this.offers)
1030                        && BX.Type.isObject(this.offers[this.offerNum])
1031                    ) {
1032                        BX.ajax.runAction(
1033                            'sale.facebookconversion.customizeProduct',
1034                            {
1035                                data: {
1036                                    offerId: this.offers[this.offerNum]['ID']
1037                                }
1038                            }
1039                        );
1040                    }
1041                }
1042            }
1043        },
1044
1045        searchOfferPropIndex: function (strPropID, strPropValue) {
1046            var strName = '',
1047                arShowValues = false,
1048                i, j,
1049                arCanBuyValues = [],
1050                allValues = [],
1051                index = -1,
1052                arFilter = {},
1053                tmpFilter = [];
1054
1055            for (i = 0; i < this.treeProps.length; i++) {
1056                if (this.treeProps[i].ID === strPropID) {
1057                    index = i;
1058                    break;
1059                }
1060            }
1061
1062            if (-1 < index) {
1063                for (i = 0; i < index; i++) {
1064                    strName = 'PROP_' + this.treeProps[i].ID;
1065                    arFilter[strName] = this.selectedValues[strName];
1066                }
1067                strName = 'PROP_' + this.treeProps[index].ID;
1068                arShowValues = this.getRowValues(arFilter, strName);
1069                if (!arShowValues) {
1070                    return false;
1071                }
1072                if (!BX.util.in_array(strPropValue, arShowValues)) {
1073                    return false;
1074                }
1075                arFilter[strName] = strPropValue;
1076                for (i = index + 1; i < this.treeProps.length; i++) {
1077                    strName = 'PROP_' + this.treeProps[i].ID;
1078                    arShowValues = this.getRowValues(arFilter, strName);
1079                    if (!arShowValues) {
1080                        return false;
1081                    }
1082                    allValues = [];
1083                    if (this.showAbsent) {
1084                        arCanBuyValues = [];
1085                        tmpFilter = [];
1086                        tmpFilter = BX.clone(arFilter, true);
1087                        for (j = 0; j < arShowValues.length; j++) {
1088                            tmpFilter[strName] = arShowValues[j];
1089                            allValues[allValues.length] = arShowValues[j];
1090                            if (this.getCanBuy(tmpFilter))
1091                                arCanBuyValues[arCanBuyValues.length] = arShowValues[j];
1092                        }
1093                    } else {
1094                        arCanBuyValues = arShowValues;
1095                    }
1096                    if (this.selectedValues[strName] && BX.util.in_array(this.selectedValues[strName], arCanBuyValues)) {
1097                        arFilter[strName] = this.selectedValues[strName];
1098                    } else {
1099                        if (this.showAbsent)
1100                            arFilter[strName] = (arCanBuyValues.length > 0 ? arCanBuyValues[0] : allValues[0]);
1101                        else
1102                            arFilter[strName] = arCanBuyValues[0];
1103                    }
1104                    this.updateRow(i, arFilter[strName], arShowValues, arCanBuyValues);
1105                }
1106                this.selectedValues = arFilter;
1107                this.changeInfo();
1108            }
1109            return true;
1110        },
1111
1112        updateRow: function (intNumber, activeID, showID, canBuyID) {
1113            var i = 0,
1114                value = '',
1115                isCurrent = false,
1116                rowItems = null;
1117
1118            var lineContainer = this.obTree.querySelectorAll('[data-entity="sku-line-block"]'),
1119                listContainer;
1120
1121            if (intNumber > -1 && intNumber < lineContainer.length) {
1122                listContainer = lineContainer[intNumber].querySelector('ul');
1123                rowItems = BX.findChildren(listContainer, {tagName: 'li'}, false);
1124                if (rowItems && 0 < rowItems.length) {
1125                    for (i = 0; i < rowItems.length; i++) {
1126                        value = rowItems[i].getAttribute('data-onevalue');
1127                        isCurrent = value === activeID;
1128
1129                        if (isCurrent) {
1130                            BX.addClass(rowItems[i], 'selected');
1131                        } else {
1132                            BX.removeClass(rowItems[i], 'selected');
1133                        }
1134
1135                        if (BX.util.in_array(value, canBuyID)) {
1136                            BX.removeClass(rowItems[i], 'notallowed');
1137                        } else {
1138                            BX.addClass(rowItems[i], 'notallowed');
1139                        }
1140
1141                        rowItems[i].style.display = BX.util.in_array(value, showID) ? '' : 'none';
1142
1143                        if (isCurrent) {
1144                            lineContainer[intNumber].style.display = (value == 0 && canBuyID.length == 1) ? 'none' : '';
1145                        }
1146                    }
1147                }
1148            }
1149        },
1150
1151        getRowValues: function (arFilter, index) {
1152            var i = 0,
1153                j,
1154                arValues = [],
1155                boolSearch = false,
1156                boolOneSearch = true;
1157
1158            if (0 === arFilter.length) {
1159                for (i = 0; i < this.offers.length; i++) {
1160                    if (!BX.util.in_array(this.offers[i].TREE[index], arValues)) {
1161                        arValues[arValues.length] = this.offers[i].TREE[index];
1162                    }
1163                }
1164                boolSearch = true;
1165            } else {
1166                for (i = 0; i < this.offers.length; i++) {
1167                    boolOneSearch = true;
1168                    for (j in arFilter) {
1169                        if (arFilter[j] !== this.offers[i].TREE[j]) {
1170                            boolOneSearch = false;
1171                            break;
1172                        }
1173                    }
1174                    if (boolOneSearch) {
1175                        if (!BX.util.in_array(this.offers[i].TREE[index], arValues)) {
1176                            arValues[arValues.length] = this.offers[i].TREE[index];
1177                        }
1178                        boolSearch = true;
1179                    }
1180                }
1181            }
1182            return (boolSearch ? arValues : false);
1183        },
1184
1185        getCanBuy: function (arFilter) {
1186            var i, j,
1187                boolSearch = false,
1188                boolOneSearch = true;
1189
1190            for (i = 0; i < this.offers.length; i++) {
1191                boolOneSearch = true;
1192                for (j in arFilter) {
1193                    if (arFilter[j] !== this.offers[i].TREE[j]) {
1194                        boolOneSearch = false;
1195                        break;
1196                    }
1197                }
1198                if (boolOneSearch) {
1199                    if (this.offers[i].CAN_BUY) {
1200                        boolSearch = true;
1201                        break;
1202                    }
1203                }
1204            }
1205
1206            return boolSearch;
1207        },
1208
1209        setCurrent: function () {
1210            var i,
1211                j = 0,
1212                arCanBuyValues = [],
1213                strName = '',
1214                arShowValues = false,
1215                arFilter = {},
1216                tmpFilter = [],
1217                current = this.offers[this.offerNum].TREE;
1218
1219            for (i = 0; i < this.treeProps.length; i++) {
1220                strName = 'PROP_' + this.treeProps[i].ID;
1221                arShowValues = this.getRowValues(arFilter, strName);
1222                if (!arShowValues) {
1223                    break;
1224                }
1225                if (BX.util.in_array(current[strName], arShowValues)) {
1226                    arFilter[strName] = current[strName];
1227                } else {
1228                    arFilter[strName] = arShowValues[0];
1229                    this.offerNum = 0;
1230                }
1231                if (this.showAbsent) {
1232                    arCanBuyValues = [];
1233                    tmpFilter = [];
1234                    tmpFilter = BX.clone(arFilter, true);
1235                    for (j = 0; j < arShowValues.length; j++) {
1236                        tmpFilter[strName] = arShowValues[j];
1237                        if (this.getCanBuy(tmpFilter)) {
1238                            arCanBuyValues[arCanBuyValues.length] = arShowValues[j];
1239                        }
1240                    }
1241                } else {
1242                    arCanBuyValues = arShowValues;
1243                }
1244                this.updateRow(i, arFilter[strName], arShowValues, arCanBuyValues);
1245            }
1246            this.selectedValues = arFilter;
1247            this.changeInfo();
1248        },
1249
1250        changeInfo: function () {
1251            var i, j,
1252                index = -1,
1253                boolOneSearch = true,
1254                quantityChanged;
1255
1256            for (i = 0; i < this.offers.length; i++) {
1257                boolOneSearch = true;
1258                for (j in this.selectedValues) {
1259                    if (this.selectedValues[j] !== this.offers[i].TREE[j]) {
1260                        boolOneSearch = false;
1261                        break;
1262                    }
1263                }
1264                if (boolOneSearch) {
1265                    index = i;
1266                    break;
1267                }
1268            }
1269            if (index > -1) {
1270                if (this.showSkuProps && this.obSkuProps) {
1271                    if (this.offers[index].DISPLAY_PROPERTIES.length) {
1272                        BX.adjust(this.obSkuProps, {style: {display: ''}, html: this.offers[index].DISPLAY_PROPERTIES});
1273                    } else {
1274                        BX.adjust(this.obSkuProps, {style: {display: 'none'}, html: ''});
1275                    }
1276                }
1277
1278                this.quantitySet(index);
1279                this.setPrice();
1280                this.setCompared(this.offers[index].COMPARED);
1281
1282                this.offerNum = index;
1283            }
1284        },
1285
1286        checkPriceRange: function (quantity) {
1287            if (typeof quantity === 'undefined' || this.currentPriceMode != 'Q')
1288                return;
1289
1290            var range, found = false;
1291
1292            for (var i in this.currentQuantityRanges) {
1293                if (this.currentQuantityRanges.hasOwnProperty(i)) {
1294                    range = this.currentQuantityRanges[i];
1295
1296                    if (
1297                        parseInt(quantity) >= parseInt(range.SORT_FROM)
1298                        && (
1299                            range.SORT_TO == 'INF'
1300                            || parseInt(quantity) <= parseInt(range.SORT_TO)
1301                        )
1302                    ) {
1303                        found = true;
1304                        this.currentQuantityRangeSelected = range.HASH;
1305                        break;
1306                    }
1307                }
1308            }
1309
1310            if (!found && (range = this.getMinPriceRange())) {
1311                this.currentQuantityRangeSelected = range.HASH;
1312            }
1313
1314            for (var k in this.currentPrices) {
1315                if (this.currentPrices.hasOwnProperty(k)) {
1316                    if (this.currentPrices[k].QUANTITY_HASH == this.currentQuantityRangeSelected) {
1317                        this.currentPriceSelected = k;
1318                        break;
1319                    }
1320                }
1321            }
1322        },
1323
1324        getMinPriceRange: function () {
1325            var range;
1326
1327            for (var i in this.currentQuantityRanges) {
1328                if (this.currentQuantityRanges.hasOwnProperty(i)) {
1329                    if (
1330                        !range
1331                        || parseInt(this.currentQuantityRanges[i].SORT_FROM) < parseInt(range.SORT_FROM)
1332                    ) {
1333                        range = this.currentQuantityRanges[i];
1334                    }
1335                }
1336            }
1337
1338            return range;
1339        },
1340
1341        checkQuantityControls: function () {
1342            if (!this.obQuantity)
1343                return;
1344
1345            var reachedTopLimit = this.checkQuantity && parseFloat(this.obQuantity.value) + this.stepQuantity > this.maxQuantity,
1346                reachedBottomLimit = parseFloat(this.obQuantity.value) - this.stepQuantity < this.minQuantity;
1347
1348            if (reachedTopLimit) {
1349                BX.addClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled');
1350            } else if (BX.hasClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled')) {
1351                BX.removeClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled');
1352            }
1353
1354            if (reachedBottomLimit) {
1355                BX.addClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled');
1356            } else if (BX.hasClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled')) {
1357                BX.removeClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled');
1358            }
1359
1360            if (reachedTopLimit && reachedBottomLimit) {
1361                this.obQuantity.setAttribute('disabled', 'disabled');
1362            } else {
1363                this.obQuantity.removeAttribute('disabled');
1364            }
1365        },
1366
1367        setPrice: function () {
1368            var obData, price;
1369
1370            if (this.obQuantity) {
1371                this.checkPriceRange(this.obQuantity.value);
1372            }
1373
1374            this.checkQuantityControls();
1375
1376            price = this.currentPrices[this.currentPriceSelected];
1377
1378            if (this.obPrice) {
1379                if (price) {
1380                    BX.adjust(this.obPrice, {html: BX.Currency.currencyFormat(price.RATIO_PRICE, price.CURRENCY, true)});
1381                } else {
1382                    BX.adjust(this.obPrice, {html: ''});
1383                }
1384
1385                if (this.showOldPrice && this.obPriceOld) {
1386                    if (price && price.RATIO_PRICE !== price.RATIO_BASE_PRICE) {
1387                        BX.adjust(this.obPriceOld, {
1388                            style: {display: ''},
1389                            html: BX.Currency.currencyFormat(price.RATIO_BASE_PRICE, price.CURRENCY, true)
1390                        });
1391                    } else {
1392                        console.log('tuta')
1393                        // BX.adjust(this.obPriceOld, {
1394                        //     style: {display: 'none'},
1395                        //     html: ''
1396                        // });
1397                    }
1398                }
1399
1400                if (this.obPriceTotal) {
1401                    if (price && this.obQuantity && this.obQuantity.value != this.stepQuantity) {
1402                        BX.adjust(this.obPriceTotal, {
1403                            html: BX.message('PRICE_TOTAL_PREFIX') + ' <strong>'
1404                                + BX.Currency.currencyFormat(price.PRICE * this.obQuantity.value, price.CURRENCY, true)
1405                                + '</strong>',
1406                            style: {display: ''}
1407                        });
1408                    } else {
1409                        BX.adjust(this.obPriceTotal, {
1410                            html: '',
1411                            style: {display: 'none'}
1412                        });
1413                    }
1414                }
1415
1416                if (this.showPercent) {
1417                    if (price && parseInt(price.PERCENT) > 0) {
1418                        obData = {style: {display: ''}, html: -price.PERCENT + '%'};
1419                    } else {
1420                        obData = {style: {display: 'none'}, html: ''};
1421                    }
1422
1423                    if (this.obDscPerc) {
1424                        BX.adjust(this.obDscPerc, obData);
1425                    }
1426
1427                    if (this.obSecondDscPerc) {
1428                        BX.adjust(this.obSecondDscPerc, obData);
1429                    }
1430                }
1431            }
1432        },
1433
1434        compare: function (event) {
1435            var checkbox = this.obCompare.querySelector('[data-entity="compare-checkbox"]'),
1436                target = BX.getEventTarget(event),
1437                checked = true;
1438
1439            if (checkbox) {
1440                checked = target === checkbox ? checkbox.checked : !checkbox.checked;
1441            }
1442
1443            var url = checked ? this.compareData.compareUrl : this.compareData.compareDeleteUrl,
1444                compareLink;
1445
1446            if (url) {
1447                if (target !== checkbox) {
1448                    BX.PreventDefault(event);
1449                    this.setCompared(checked);
1450                }
1451
1452                switch (this.productType) {
1453                    case 0: // no catalog
1454                    case 1: // product
1455                    case 2: // set
1456                        compareLink = url.replace('#ID#', this.product.id.toString());
1457                        break;
1458                    case 3: // sku
1459                        compareLink = url.replace('#ID#', this.offers[this.offerNum].ID);
1460                        break;
1461                }
1462
1463                BX.ajax({
1464                    method: 'POST',
1465                    dataType: checked ? 'json' : 'html',
1466                    url: compareLink + (compareLink.indexOf('?') !== -1 ? '&' : '?') + 'ajax_action=Y',
1467                    onsuccess: checked
1468                        ? BX.proxy(this.compareResult, this)
1469                        : BX.proxy(this.compareDeleteResult, this)
1470                });
1471            }
1472        },
1473
1474        compareResult: function (result) {
1475            var popupContent, popupButtons;
1476
1477            if (this.obPopupWin) {
1478                this.obPopupWin.close();
1479            }
1480
1481            if (!BX.type.isPlainObject(result))
1482                return;
1483
1484            this.initPopupWindow();
1485
1486            if (this.offers.length > 0) {
1487                this.offers[this.offerNum].COMPARED = result.STATUS === 'OK';
1488            }
1489
1490            if (result.STATUS === 'OK') {
1491                BX.onCustomEvent('OnCompareChange');
1492
1493                popupContent = '<div style="width: 100%; margin: 0; text-align: center;"><p>'
1494                    + BX.message('COMPARE_MESSAGE_OK')
1495                    + '</p></div>';
1496
1497                if (this.showClosePopup) {
1498                    popupButtons = [
1499                        new BasketButton({
1500                            text: BX.message('BTN_MESSAGE_COMPARE_REDIRECT'),
1501                            events: {
1502                                click: BX.delegate(this.compareRedirect, this)
1503                            },
1504                            style: {marginRight: '10px'}
1505                        }),
1506                        new BasketButton({
1507                            text: BX.message('BTN_MESSAGE_CLOSE_POPUP'),
1508                            events: {
1509                                click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
1510                            }
1511                        })
1512                    ];
1513                } else {
1514                    popupButtons = [
1515                        new BasketButton({
1516                            text: BX.message('BTN_MESSAGE_COMPARE_REDIRECT'),
1517                            events: {
1518                                click: BX.delegate(this.compareRedirect, this)
1519                            }
1520                        })
1521                    ];
1522                }
1523            } else {
1524                popupContent = '<div style="width: 100%; margin: 0; text-align: center;"><p>'
1525                    + (result.MESSAGE ? result.MESSAGE : BX.message('COMPARE_UNKNOWN_ERROR'))
1526                    + '</p></div>';
1527                popupButtons = [
1528                    new BasketButton({
1529                        text: BX.message('BTN_MESSAGE_CLOSE'),
1530                        events: {
1531                            click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
1532                        }
1533                    })
1534                ];
1535            }
1536
1537            this.obPopupWin.setTitleBar(BX.message('COMPARE_TITLE'));
1538            this.obPopupWin.setContent(popupContent);
1539            this.obPopupWin.setButtons(popupButtons);
1540            this.obPopupWin.show();
1541        },
1542
1543        compareDeleteResult: function () {
1544            BX.onCustomEvent('OnCompareChange');
1545
1546            if (this.offers && this.offers.length) {
1547                this.offers[this.offerNum].COMPARED = false;
1548            }
1549        },
1550
1551        setCompared: function (state) {
1552            if (!this.obCompare)
1553                return;
1554
1555            var checkbox = this.obCompare.querySelector('[data-entity="compare-checkbox"]');
1556            if (checkbox) {
1557                checkbox.checked = state;
1558            }
1559        },
1560
1561        setCompareInfo: function (comparedIds) {
1562            if (!BX.type.isArray(comparedIds))
1563                return;
1564
1565            for (var i in this.offers) {
1566                if (this.offers.hasOwnProperty(i)) {
1567                    this.offers[i].COMPARED = BX.util.in_array(this.offers[i].ID, comparedIds);
1568                }
1569            }
1570        },
1571
1572        compareRedirect: function () {
1573            if (this.compareData.comparePath) {
1574                location.href = this.compareData.comparePath;
1575            } else {
1576                this.obPopupWin.close();
1577            }
1578        },
1579
1580        checkDeletedCompare: function (id) {
1581            switch (this.productType) {
1582                case 0: // no catalog
1583                case 1: // product
1584                case 2: // set
1585                    if (this.product.id == id) {
1586                        this.setCompared(false);
1587                    }
1588
1589                    break;
1590                case 3: // sku
1591                    var i = this.offers.length;
1592                    while (i--) {
1593                        if (this.offers[i].ID == id) {
1594                            this.offers[i].COMPARED = false;
1595
1596                            if (this.offerNum == i) {
1597                                this.setCompared(false);
1598                            }
1599
1600                            break;
1601                        }
1602                    }
1603            }
1604        },
1605
1606        initBasketUrl: function () {
1607            this.basketUrl = (this.basketMode === 'ADD' ? this.basketData.add_url : this.basketData.buy_url);
1608            switch (this.productType) {
1609                case 1: // product
1610                case 2: // set
1611                    this.basketUrl = this.basketUrl.replace('#ID#', this.product.id.toString());
1612                    break;
1613                case 3: // sku
1614                    this.basketUrl = this.basketUrl.replace('#ID#', this.offers[this.offerNum].ID);
1615                    break;
1616            }
1617            this.basketParams = {
1618                'ajax_basket': 'Y'
1619            };
1620            if (this.showQuantity) {
1621                this.basketParams[this.basketData.quantity] = this.obQuantity.value;
1622            }
1623            if (this.basketData.sku_props) {
1624                this.basketParams[this.basketData.sku_props_var] = this.basketData.sku_props;
1625            }
1626        },
1627
1628        fillBasketProps: function () {
1629            if (!this.visual.BASKET_PROP_DIV) {
1630                return;
1631            }
1632            var
1633                i = 0,
1634                propCollection = null,
1635                foundValues = false,
1636                obBasketProps = null;
1637
1638            if (this.basketData.useProps && !this.basketData.emptyProps) {
1639                if (this.obPopupWin && this.obPopupWin.contentContainer) {
1640                    obBasketProps = this.obPopupWin.contentContainer;
1641                }
1642            } else {
1643                obBasketProps = BX(this.visual.BASKET_PROP_DIV);
1644            }
1645            if (obBasketProps) {
1646                propCollection = obBasketProps.getElementsByTagName('select');
1647                if (propCollection && propCollection.length) {
1648                    for (i = 0; i < propCollection.length; i++) {
1649                        if (!propCollection[i].disabled) {
1650                            switch (propCollection[i].type.toLowerCase()) {
1651                                case 'select-one':
1652                                    this.basketParams[propCollection[i].name] = propCollection[i].value;
1653                                    foundValues = true;
1654                                    break;
1655                                default:
1656                                    break;
1657                            }
1658                        }
1659                    }
1660                }
1661                propCollection = obBasketProps.getElementsByTagName('input');
1662                if (propCollection && propCollection.length) {
1663                    for (i = 0; i < propCollection.length; i++) {
1664                        if (!propCollection[i].disabled) {
1665                            switch (propCollection[i].type.toLowerCase()) {
1666                                case 'hidden':
1667                                    this.basketParams[propCollection[i].name] = propCollection[i].value;
1668                                    foundValues = true;
1669                                    break;
1670                                case 'radio':
1671                                    if (propCollection[i].checked) {
1672                                        this.basketParams[propCollection[i].name] = propCollection[i].value;
1673                                        foundValues = true;
1674                                    }
1675                                    break;
1676                                default:
1677                                    break;
1678                            }
1679                        }
1680                    }
1681                }
1682            }
1683            if (!foundValues) {
1684                this.basketParams[this.basketData.props] = [];
1685                this.basketParams[this.basketData.props][0] = 0;
1686            }
1687        },
1688
1689        add2Basket: function () {
1690            this.basketMode = 'ADD';
1691            this.basket();
1692        },
1693
1694        buyBasket: function () {
1695            this.basketMode = 'BUY';
1696            this.basket();
1697        },
1698
1699        sendToBasket: function () {
1700            if (!this.canBuy) {
1701                return;
1702            }
1703
1704            // check recommendation
1705            if (this.product && this.product.id && this.bigData) {
1706                this.rememberProductRecommendation();
1707            }
1708
1709            this.initBasketUrl();
1710            this.fillBasketProps();
1711            BX.ajax({
1712                method: 'POST',
1713                dataType: 'json',
1714                url: this.basketUrl,
1715                data: this.basketParams,
1716                onsuccess: BX.proxy(this.basketResult, this)
1717            });
1718        },
1719
1720        basket: function () {
1721            var contentBasketProps = '';
1722            if (!this.canBuy) {
1723                return;
1724            }
1725            switch (this.productType) {
1726                case 1: // product
1727                case 2: // set
1728                    if (this.basketData.useProps && !this.basketData.emptyProps) {
1729                        this.initPopupWindow();
1730                        this.obPopupWin.setTitleBar(BX.message('TITLE_BASKET_PROPS'));
1731                        if (BX(this.visual.BASKET_PROP_DIV)) {
1732                            contentBasketProps = BX(this.visual.BASKET_PROP_DIV).innerHTML;
1733                        }
1734                        this.obPopupWin.setContent(contentBasketProps);
1735                        this.obPopupWin.setButtons([
1736                            new BasketButton({
1737                                text: BX.message('BTN_MESSAGE_SEND_PROPS'),
1738                                events: {
1739                                    click: BX.delegate(this.sendToBasket, this)
1740                                }
1741                            })
1742                        ]);
1743                        this.obPopupWin.show();
1744                    } else {
1745                        this.sendToBasket();
1746                    }
1747                    break;
1748                case 3: // sku
1749                    this.sendToBasket();
1750                    break;
1751            }
1752        },
1753
1754        basketResult: function (arResult) {
1755            var strContent = '',
1756                strPict = '',
1757                successful,
1758                buttons = [];
1759
1760            if (this.obPopupWin)
1761                this.obPopupWin.close();
1762
1763            if (!BX.type.isPlainObject(arResult))
1764                return;
1765
1766            successful = arResult.STATUS === 'OK';
1767
1768            if (successful) {
1769                this.setAnalyticsDataLayer('addToCart');
1770            }
1771
1772            if (successful && this.basketAction === 'BUY') {
1773                this.basketRedirect();
1774            } else {
1775                //this.initPopupWindow();
1776
1777                if (successful) {
1778                    BX.onCustomEvent('OnBasketChange');
1779
1780                    if (BX.findParent(this.obProduct, {className: 'bx_sale_gift_main_products'}, 10)) {
1781                        BX.onCustomEvent('onAddToBasketMainProduct', [this]);
1782                    }
1783                    BX.remove(BX(this.obBuyBtn));
1784                    BX.removeClass(this.obOkBtn, 'hidden_btn');
1785                }
1786            }
1787        },
1788
1789        basketRedirect: function () {
1790            location.href = (this.basketData.basketUrl ? this.basketData.basketUrl : BX.message('BASKET_URL'));
1791        },
1792
1793        initPopupWindow: function () {
1794            if (this.obPopupWin)
1795                return;
1796
1797            this.obPopupWin = BX.PopupWindowManager.create('CatalogSectionBasket_' + this.visual.ID, null, {
1798                autoHide: true,
1799                offsetLeft: 0,
1800                offsetTop: 0,
1801                overlay: true,
1802                closeByEsc: true,
1803                titleBar: true,
1804                closeIcon: true,
1805                contentColor: 'white',
1806                className: this.templateTheme ? 'bx-' + this.templateTheme : ''
1807            });
1808        }
1809    };
1810})(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.