PageSourceSearch

https://okoptica.ru/local/templates/okoptica/components/bitrix/catalog.item/main/script.js

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