PageSourceSearch

https://okoptica.ru/local/templates/okoptica/components/bitrix/catalog.element/main2/script.js

js okoptica.ru collected 2026-10-07 16:34:16 UTC 120,057 bytes, 2,943 lines download raw bytes

1(function(window) {
2    'use strict';
3
4    if (window.JCCatalogElement)
5        return;
6
7    var BasketButton = function(params) {
8        BasketButton.superclass.constructor.apply(this, arguments);
9        this.buttonNode = BX.create('SPAN', {
10            props:  {className: 'btn btn-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.JCCatalogElement = function(arParams) {
23        this.productType = 0;
24
25        this.config = {
26            useCatalog:           true,
27            showQuantity:         true,
28            showPrice:            true,
29            showAbsent:           true,
30            showOldPrice:         false,
31            showPercent:          false,
32            showSkuProps:         false,
33            showOfferGroup:       false,
34            useCompare:           false,
35            useStickers:          false,
36            useSubscribe:         false,
37            usePopup:             false,
38            useMagnifier:         false,
39            usePriceRanges:       false,
40            basketAction:         ['BUY'],
41            showClosePopup:       false,
42            templateTheme:        '',
43            showSlider:           false,
44            sliderInterval:       5000,
45            useEnhancedEcommerce: false,
46            dataLayerName:        'dataLayer',
47            brandProperty:        false,
48            alt:                  '',
49            title:                '',
50            magnifierZoomPercent: 200
51        };
52
53        this.checkQuantity     = false;
54        this.maxQuantity       = 0;
55        this.minQuantity       = 0;
56        this.stepQuantity      = 1;
57        this.isDblQuantity     = false;
58        this.canBuy            = true;
59        this.isGift            = false;
60        this.canSubscription   = true;
61        this.currentIsSet      = false;
62        this.updateViewedCount = false;
63
64        this.currentPriceMode             = '';
65        this.currentPrices                = [];
66        this.currentPriceSelected         = 0;
67        this.currentQuantityRanges        = [];
68        this.currentQuantityRangeSelected = 0;
69
70        this.precision       = 6;
71        this.precisionFactor = Math.pow(10, this.precision);
72
73        this.visual     = {};
74        this.basketMode = '';
75        this.product    = {
76            checkQuantity:   false,
77            maxQuantity:     0,
78            stepQuantity:    1,
79            startQuantity:   1,
80            isDblQuantity:   false,
81            canBuy:          true,
82            canSubscription: true,
83            name:            '',
84            pict:            {},
85            id:              0,
86            addUrl:          '',
87            buyUrl:          '',
88            slider:          {},
89            sliderCount:     0,
90            useSlider:       false,
91            sliderPict:      []
92        };
93        this.mess       = {};
94
95        this.basketData  = {
96            useProps:      false,
97            emptyProps:    false,
98            quantity:      'quantity',
99            props:         'prop',
100            basketUrl:     '',
101            sku_props:     '',
102            sku_props_var: 'basket_props',
103            add_url:       '',
104            buy_url:       ''
105        };
106        this.compareData = {
107            compareUrl:       '',
108            compareDeleteUrl: '',
109            comparePath:      ''
110        };
111
112        this.defaultPict = {
113            preview: null,
114            detail:  null
115        };
116
117        this.offers         = [];
118        this.offerNum       = 0;
119        this.treeProps      = [];
120        this.selectedValues = {};
121
122        this.mouseTimer    = null;
123        this.isTouchDevice = BX.hasClass(document.documentElement, 'bx-touch');
124        this.touch         = null;
125        this.slider        = {
126            interval: null,
127            progress: null,
128            paused:   null,
129            controls: []
130        };
131
132        this.quantityDelay = null;
133        this.quantityTimer = null;
134
135        this.obProduct        = null;
136        this.obQuantity       = null;
137        this.obQuantityUp     = null;
138        this.obQuantityDown   = null;
139        this.obPrice          = {
140            price:    null,
141            full:     null,
142            discount: null,
143            percent:  null,
144            total:    null
145        };
146        this.obTree           = null;
147        this.obPriceRanges    = null;
148        this.obBuyBtn         = null;
149        this.obAddToBasketBtn = null;
150        this.obBasketActions  = null;
151        this.obNotAvail       = null;
152        this.obSubscribe      = null;
153        this.obSkuProps       = null;
154        this.obMainSkuProps   = null;
155        this.obBigSlider      = null;
156        this.obMeasure        = null;
157        this.obQuantityLimit  = {
158            all:   null,
159            value: null
160        };
161        this.obCompare        = null;
162        this.obTabsPanel      = null;
163
164        this.node           = {};
165        // top panel small card
166        this.smallCardNodes = {};
167
168        this.magnify       = {
169            enabled:     false,
170            obBigImg:    null,
171            obBigSlider: null,
172            height:      0,
173            width:       0,
174            timer:       0
175        };
176        this.currentImg    = {
177            id:     0,
178            src:    '',
179            width:  0,
180            height: 0
181        };
182        this.viewedCounter = {
183            path:   '/bitrix/components/bitrix/catalog.element/ajax.php',
184            params: {
185                AJAX:       'Y',
186                SITE_ID:    '',
187                PRODUCT_ID: 0,
188                PARENT_ID:  0
189            }
190        };
191
192        this.obPopupWin   = null;
193        this.basketUrl    = '';
194        this.basketParams = {};
195
196        this.errorCode = 0;
197
198        if (typeof arParams === 'object') {
199            this.params = arParams;
200            this.initConfig();
201
202            if (this.params.MESS) {
203                this.mess = this.params.MESS;
204            }
205
206            switch (this.productType) {
207                case 0: // no catalog
208                case 1: // product
209                case 2: // set
210                    this.initProductData();
211                    break;
212                case 3: // sku
213                    this.initOffersData();
214                    break;
215                default:
216                    this.errorCode = -1;
217            }
218
219            this.initBasketData();
220            this.initCompareData();
221        }
222
223        if (this.errorCode === 0) {
224            BX.ready(BX.delegate(this.init, this));
225        }
226
227        this.params = {};
228
229        BX.addCustomEvent('onSaleProductIsGift', BX.delegate(this.onSaleProductIsGift, this));
230        BX.addCustomEvent('onSaleProductIsNotGift', BX.delegate(this.onSaleProductIsNotGift, this));
231    };
232
233    window.JCCatalogElement.prototype = {
234        getEntity: function(parent, entity, additionalFilter) {
235            if (!parent || !entity)
236                return null;
237
238            additionalFilter = additionalFilter || '';
239
240            return parent.querySelector(additionalFilter + '[data-entity="' + entity + '"]');
241        },
242
243        getEntities: function(parent, entity, additionalFilter) {
244            if (!parent || !entity)
245                return {length: 0};
246
247            additionalFilter = additionalFilter || '';
248
249            return parent.querySelectorAll(additionalFilter + '[data-entity="' + entity + '"]');
250        },
251
252        onSaleProductIsGift: function(productId, offerId) {
253            if (offerId && this.offers && this.offers[this.offerNum].ID == offerId) {
254                this.setGift();
255            }
256        },
257
258        onSaleProductIsNotGift: function(productId, offerId) {
259            if (offerId && this.offers && this.offers[this.offerNum].ID == offerId) {
260                this.restoreSticker();
261                this.isGift = false;
262                this.setPrice();
263            }
264        },
265
266        reloadGiftInfo: function() {
267            if (this.productType === 3) {
268                this.checkQuantity = true;
269                this.maxQuantity   = 1;
270
271                this.setPrice();
272                this.redrawSticker({text: BX.message('PRODUCT_GIFT_LABEL')});
273            }
274        },
275
276        setGift: function() {
277            if (this.productType === 3) {
278                // sku
279                this.isGift = true;
280            }
281
282            if (this.productType === 1 || this.productType === 2) {
283                // simple
284                this.isGift = true;
285            }
286
287            if (this.productType === 0) {
288                this.isGift = false;
289            }
290
291            this.reloadGiftInfo();
292        },
293
294        setOffer: function(offerNum) {
295            this.offerNum = parseInt(offerNum);
296            this.setCurrent();
297        },
298
299        init: function() {
300            var i         = 0,
301                j         = 0,
302                treeItems = null;
303
304            this.obProduct = BX(this.visual.ID);
305            if (!this.obProduct) {
306                this.errorCode = -1;
307            }
308
309            this.obBigSlider             = BX(this.visual.BIG_SLIDER_ID);
310            this.node.imageContainer     = this.getEntity(this.obProduct, 'images-container');
311            this.node.imageSliderBlock   = this.getEntity(this.obProduct, 'images-slider-block');
312            this.node.sliderProgressBar  = this.getEntity(this.obProduct, 'slider-progress-bar');
313            this.node.sliderControlLeft  = this.getEntity(this.obBigSlider, 'slider-control-left');
314            this.node.sliderControlRight = this.getEntity(this.obBigSlider, 'slider-control-right');
315
316            if (!this.obBigSlider || !this.node.imageContainer || !this.node.imageContainer) {
317                this.errorCode = -2;
318            }
319
320            if (this.config.showPrice) {
321                this.obPrice.price = BX(this.visual.PRICE_ID);
322                if (!this.obPrice.price && this.config.useCatalog) {
323                    this.errorCode = -16;
324                } else {
325                    this.obPrice.total = BX(this.visual.PRICE_TOTAL);
326
327                    if (this.config.showOldPrice) {
328                        this.obPrice.full     = BX(this.visual.OLD_PRICE_ID);
329                        this.obPrice.discount = BX(this.visual.DISCOUNT_PRICE_ID);
330
331                        if (!this.obPrice.full || !this.obPrice.discount) {
332                            this.config.showOldPrice = false;
333                        }
334                    }
335
336                    if (this.config.showPercent) {
337                        this.obPrice.percent = BX(this.visual.DISCOUNT_PERCENT_ID);
338                        if (!this.obPrice.percent) {
339                            this.config.showPercent = false;
340                        }
341                    }
342                }
343
344                this.obBasketActions = BX(this.visual.BASKET_ACTIONS_ID);
345                if (this.obBasketActions) {
346                    if (BX.util.in_array('BUY', this.config.basketAction)) {
347                        this.obBuyBtn = BX(this.visual.BUY_LINK);
348                    }
349
350                    if (BX.util.in_array('ADD', this.config.basketAction)) {
351                        this.obAddToBasketBtn = BX(this.visual.ADD_BASKET_LINK);
352                    }
353                }
354                this.obNotAvail = BX(this.visual.NOT_AVAILABLE_MESS);
355            }
356
357            if (this.config.showQuantity) {
358                this.obQuantity    = BX(this.visual.QUANTITY_ID);
359                this.node.quantity = this.getEntity(this.obProduct, 'quantity-block');
360                if (this.visual.QUANTITY_UP_ID) {
361                    this.obQuantityUp = BX(this.visual.QUANTITY_UP_ID);
362                }
363
364                if (this.visual.QUANTITY_DOWN_ID) {
365                    this.obQuantityDown = BX(this.visual.QUANTITY_DOWN_ID);
366                }
367            }
368
369            if (this.productType === 3) {
370                if (this.visual.TREE_ID) {
371                    this.obTree = BX(this.visual.TREE_ID);
372                    if (!this.obTree) {
373                        this.errorCode = -256;
374                    }
375                }
376
377                if (this.visual.QUANTITY_MEASURE) {
378                    this.obMeasure = BX(this.visual.QUANTITY_MEASURE);
379                }
380
381                if (this.visual.QUANTITY_LIMIT && this.config.showMaxQuantity !== 'N') {
382                    this.obQuantityLimit.all = BX(this.visual.QUANTITY_LIMIT);
383                    if (this.obQuantityLimit.all) {
384                        this.obQuantityLimit.value = this.getEntity(this.obQuantityLimit.all, 'quantity-limit-value');
385                        if (!this.obQuantityLimit.value) {
386                            this.obQuantityLimit.all = null;
387                        }
388                    }
389                }
390
391                if (this.config.usePriceRanges) {
392                    this.obPriceRanges = this.getEntity(this.obProduct, 'price-ranges-block');
393                }
394            }
395
396            if (this.config.showSkuProps) {
397                this.obSkuProps     = BX(this.visual.DISPLAY_PROP_DIV);
398                this.obMainSkuProps = BX(this.visual.DISPLAY_MAIN_PROP_DIV);
399            }
400
401            if (this.config.useCompare) {
402                this.obCompare = BX(this.visual.COMPARE_LINK);
403            }
404
405            if (this.config.useSubscribe) {
406                this.obSubscribe = BX(this.visual.SUBSCRIBE_LINK);
407            }
408
409            this.obTabs          = BX(this.visual.TABS_ID);
410            this.obTabContainers = BX(this.visual.TAB_CONTAINERS_ID);
411            this.obTabsPanel     = BX(this.visual.TABS_PANEL_ID);
412
413            this.smallCardNodes.panel = BX(this.visual.SMALL_CARD_PANEL_ID);
414            if (this.smallCardNodes.panel) {
415                this.smallCardNodes.picture            = this.getEntity(this.smallCardNodes.panel, 'panel-picture');
416                this.smallCardNodes.title              = this.getEntity(this.smallCardNodes.panel, 'panel-title');
417                this.smallCardNodes.price              = this.getEntity(this.smallCardNodes.panel, 'panel-price');
418                this.smallCardNodes.sku                = this.getEntity(this.smallCardNodes.panel, 'panel-sku-container');
419                this.smallCardNodes.oldPrice           = this.getEntity(this.smallCardNodes.panel, 'panel-old-price');
420                this.smallCardNodes.buyButton          = this.getEntity(this.smallCardNodes.panel, 'panel-buy-button');
421                this.smallCardNodes.addButton          = this.getEntity(this.smallCardNodes.panel, 'panel-add-button');
422                this.smallCardNodes.notAvailableButton = this.getEntity(this.smallCardNodes.panel, 'panel-not-available-button');
423                this.smallCardNodes.aligner            = this.getEntity(this.obProduct, 'main-button-container');
424            }
425
426            this.initPopup();
427            this.initTabs();
428
429            if (this.smallCardNodes.panel) {
430                this.smallCardNodes.picture && BX.bind(this.smallCardNodes.picture.parentNode, 'click', BX.proxy(this.scrollToProduct, this));
431                this.smallCardNodes.title && BX.bind(this.smallCardNodes.title, 'click', BX.proxy(this.scrollToProduct, this));
432                this.smallCardNodes.sku && BX.bind(this.smallCardNodes.sku, 'click', BX.proxy(this.scrollToProduct, this));
433            }
434
435            if (this.obTabsPanel || this.smallCardNodes.panel) {
436                this.checkTopPanels();
437                BX.bind(window, 'scroll', BX.proxy(this.checkTopPanels, this));
438            }
439
440            if (this.errorCode === 0) {
441                // product slider events
442                if (this.config.showSlider && !this.isTouchDevice) {
443                    BX.bind(this.obBigSlider, 'mouseenter', BX.proxy(this.stopSlider, this));
444                    BX.bind(this.obBigSlider, 'mouseleave', BX.proxy(this.cycleSlider, this));
445                }
446
447                if (this.isTouchDevice) {
448                    BX.bind(this.node.imageContainer, 'touchstart', BX.proxy(this.touchStartEvent, this));
449                    BX.bind(this.node.imageContainer, 'touchend', BX.proxy(this.touchEndEvent, this));
450                    BX.bind(this.node.imageContainer, 'touchcancel', BX.proxy(this.touchEndEvent, this));
451                }
452
453                BX.bind(this.node.sliderControlLeft, 'click', BX.proxy(this.slidePrev, this));
454                BX.bind(this.node.sliderControlRight, 'click', BX.proxy(this.slideNext, this));
455
456                if (this.config.showQuantity) {
457                    var startEventName = this.isTouchDevice ? 'touchstart' : 'mousedown';
458                    var endEventName   = this.isTouchDevice ? 'touchend' : 'mouseup';
459
460                    if (this.obQuantityUp) {
461                        BX.bind(this.obQuantityUp, startEventName, BX.proxy(this.startQuantityInterval, this));
462                        BX.bind(this.obQuantityUp, endEventName, BX.proxy(this.clearQuantityInterval, this));
463                        BX.bind(this.obQuantityUp, 'mouseout', BX.proxy(this.clearQuantityInterval, this));
464                        BX.bind(this.obQuantityUp, 'click', BX.delegate(this.quantityUp, this));
465                    }
466
467                    if (this.obQuantityDown) {
468                        BX.bind(this.obQuantityDown, startEventName, BX.proxy(this.startQuantityInterval, this));
469                        BX.bind(this.obQuantityDown, endEventName, BX.proxy(this.clearQuantityInterval, this));
470                        BX.bind(this.obQuantityDown, 'mouseout', BX.proxy(this.clearQuantityInterval, this));
471                        BX.bind(this.obQuantityDown, 'click', BX.delegate(this.quantityDown, this));
472                    }
473
474                    if (this.obQuantity) {
475                        BX.bind(this.obQuantity, 'change', BX.delegate(this.quantityChange, this));
476                    }
477                }
478
479                switch (this.productType) {
480                    case 0: // no catalog
481                    case 1: // product
482                    case 2: // set
483                        if (this.product.useSlider) {
484                            this.product.slider       = {
485                                ID:    this.visual.SLIDER_CONT_ID,
486                                CONT:  BX(this.visual.SLIDER_CONT_ID),
487                                COUNT: this.product.sliderCount
488                            };
489                            this.product.slider.ITEMS = this.getEntities(this.product.slider.CONT, 'slider-control');
490                            for (j = 0; j < this.product.slider.ITEMS.length; j++) {
491                                BX.bind(this.product.slider.ITEMS[j], 'mouseenter', BX.delegate(this.onSliderControlHover, this));
492                                BX.bind(this.product.slider.ITEMS[j], 'mouseleave', BX.delegate(this.onSliderControlLeave, this));
493                                BX.bind(this.product.slider.ITEMS[j], 'click', BX.delegate(this.selectSliderImg, this));
494                            }
495
496                            this.setCurrentImg(this.product.sliderPict[0], true, true);
497                            this.checkSliderControls(this.product.sliderCount);
498
499                            if (this.product.slider.ITEMS.length > 1) {
500                                this.initSlider();
501                            }
502                        }
503
504                        this.checkQuantityControls();
505                        this.fixFontCheck();
506                        this.setAnalyticsDataLayer('showDetail');
507                        break;
508                    case 3: // sku
509                        treeItems = this.obTree.querySelectorAll('li');
510                        for (i = 0; i < treeItems.length; i++) {
511                            BX.bind(treeItems[i], 'click', BX.delegate(this.selectOfferProp, this));
512                        }
513
514                        for (i = 0; i < this.offers.length; i++) {
515                            this.offers[i].SLIDER_COUNT = parseInt(this.offers[i].SLIDER_COUNT, 10) || 0;
516
517                            if (this.offers[i].SLIDER_COUNT === 0) {
518                                this.slider.controls[i] = {
519                                    ID:    '',
520                                    COUNT: this.offers[i].SLIDER_COUNT,
521                                    ITEMS: []
522                                };
523                            } else {
524                                for (j = 0; j < this.offers[i].SLIDER.length; j++) {
525                                    this.offers[i].SLIDER[j].WIDTH  = parseInt(this.offers[i].SLIDER[j].WIDTH, 10);
526                                    this.offers[i].SLIDER[j].HEIGHT = parseInt(this.offers[i].SLIDER[j].HEIGHT, 10);
527                                }
528
529                                this.slider.controls[i] = {
530                                    ID:       this.visual.SLIDER_CONT_OF_ID + this.offers[i].ID,
531                                    OFFER_ID: this.offers[i].ID,
532                                    CONT:     BX(this.visual.SLIDER_CONT_OF_ID + this.offers[i].ID),
533                                    COUNT:    this.offers[i].SLIDER_COUNT
534                                };
535
536                                this.slider.controls[i].ITEMS = this.getEntities(this.slider.controls[i].CONT, 'slider-control');
537                                for (j = 0; j < this.slider.controls[i].ITEMS.length; j++) {
538                                    BX.bind(this.slider.controls[i].ITEMS[j], 'mouseenter', BX.delegate(this.onSliderControlHover, this));
539                                    BX.bind(this.slider.controls[i].ITEMS[j], 'mouseleave', BX.delegate(this.onSliderControlLeave, this));
540                                    BX.bind(this.slider.controls[i].ITEMS[j], 'click', BX.delegate(this.selectSliderImg, this));
541                                }
542                            }
543                        }
544
545                        this.setCurrent();
546                        break;
547                }
548
549                this.obBuyBtn && BX.bind(this.obBuyBtn, 'click', BX.proxy(this.buyBasket, this));
550                this.smallCardNodes.buyButton && BX.bind(this.smallCardNodes.buyButton, 'click', BX.proxy(this.buyBasket, this));
551
552                this.obAddToBasketBtn && BX.bind(this.obAddToBasketBtn, 'click', BX.proxy(this.add2Basket, this));
553                this.smallCardNodes.addButton && BX.bind(this.smallCardNodes.addButton, 'click', BX.proxy(this.add2Basket, this));
554
555                if (this.obCompare) {
556                    BX.bind(this.obCompare, 'click', BX.proxy(this.compare, this));
557                    BX.addCustomEvent('onCatalogDeleteCompare', BX.proxy(this.checkDeletedCompare, this));
558                }
559            }
560        },
561
562        initConfig: function() {
563            if (this.params.PRODUCT_TYPE) {
564                this.productType = parseInt(this.params.PRODUCT_TYPE, 10);
565            }
566
567            if (this.params.CONFIG.USE_CATALOG !== 'undefined' && BX.type.isBoolean(this.params.CONFIG.USE_CATALOG)) {
568                this.config.useCatalog = this.params.CONFIG.USE_CATALOG;
569            }
570
571            this.config.showQuantity           = this.params.CONFIG.SHOW_QUANTITY;
572            this.config.showPrice              = this.params.CONFIG.SHOW_PRICE;
573            this.config.showPercent            = this.params.CONFIG.SHOW_DISCOUNT_PERCENT;
574            this.config.showOldPrice           = this.params.CONFIG.SHOW_OLD_PRICE;
575            this.config.showSkuProps           = this.params.CONFIG.SHOW_SKU_PROPS;
576            this.config.showOfferGroup         = this.params.CONFIG.OFFER_GROUP;
577            this.config.useCompare             = this.params.CONFIG.DISPLAY_COMPARE;
578            this.config.useStickers            = this.params.CONFIG.USE_STICKERS;
579            this.config.useSubscribe           = this.params.CONFIG.USE_SUBSCRIBE;
580            this.config.showMaxQuantity        = this.params.CONFIG.SHOW_MAX_QUANTITY;
581            this.config.relativeQuantityFactor = parseInt(this.params.CONFIG.RELATIVE_QUANTITY_FACTOR);
582            this.config.usePriceRanges         = this.params.CONFIG.USE_PRICE_COUNT;
583
584            if (this.params.CONFIG.MAIN_PICTURE_MODE) {
585                this.config.usePopup     = BX.util.in_array('POPUP', this.params.CONFIG.MAIN_PICTURE_MODE);
586                this.config.useMagnifier = BX.util.in_array('MAGNIFIER', this.params.CONFIG.MAIN_PICTURE_MODE);
587            }
588
589            if (this.params.CONFIG.ADD_TO_BASKET_ACTION) {
590                this.config.basketAction = this.params.CONFIG.ADD_TO_BASKET_ACTION;
591            }
592
593            this.config.showClosePopup = this.params.CONFIG.SHOW_CLOSE_POPUP;
594            this.config.templateTheme  = this.params.CONFIG.TEMPLATE_THEME || '';
595            this.config.showSlider     = this.params.CONFIG.SHOW_SLIDER === 'Y';
596
597            if (this.config.showSlider && !this.isTouchDevice) {
598                this.config.sliderInterval = parseInt(this.params.CONFIG.SLIDER_INTERVAL) || 5000;
599            } else {
600                this.config.sliderInterval = false;
601            }
602
603            this.config.useEnhancedEcommerce = this.params.CONFIG.USE_ENHANCED_ECOMMERCE === 'Y';
604            this.config.dataLayerName        = this.params.CONFIG.DATA_LAYER_NAME;
605            this.config.brandProperty        = this.params.CONFIG.BRAND_PROPERTY;
606
607            this.config.alt   = this.params.CONFIG.ALT || '';
608            this.config.title = this.params.CONFIG.TITLE || '';
609
610            this.config.magnifierZoomPercent = parseInt(this.params.CONFIG.MAGNIFIER_ZOOM_PERCENT) || 200;
611
612            if (!this.params.VISUAL || typeof this.params.VISUAL !== 'object' || !this.params.VISUAL.ID) {
613                this.errorCode = -1;
614                return;
615            }
616
617            this.visual = this.params.VISUAL;
618        },
619
620        initProductData: function() {
621            var j = 0;
622
623            if (this.params.PRODUCT && typeof this.params.PRODUCT === 'object') {
624                if (this.config.showPrice) {
625                    this.currentPriceMode             = this.params.PRODUCT.ITEM_PRICE_MODE;
626                    this.currentPrices                = this.params.PRODUCT.ITEM_PRICES;
627                    this.currentPriceSelected         = this.params.PRODUCT.ITEM_PRICE_SELECTED;
628                    this.currentQuantityRanges        = this.params.PRODUCT.ITEM_QUANTITY_RANGES;
629                    this.currentQuantityRangeSelected = this.params.PRODUCT.ITEM_QUANTITY_RANGE_SELECTED;
630                }
631
632                if (this.config.showQuantity) {
633                    this.product.checkQuantity = this.params.PRODUCT.CHECK_QUANTITY;
634                    this.product.isDblQuantity = this.params.PRODUCT.QUANTITY_FLOAT;
635
636                    if (this.product.checkQuantity) {
637                        this.product.maxQuantity = this.product.isDblQuantity
638                            ? parseFloat(this.params.PRODUCT.MAX_QUANTITY)
639                            : parseInt(this.params.PRODUCT.MAX_QUANTITY, 10);
640                    }
641
642                    this.product.stepQuantity = this.product.isDblQuantity
643                        ? parseFloat(this.params.PRODUCT.STEP_QUANTITY)
644                        : parseInt(this.params.PRODUCT.STEP_QUANTITY, 10);
645                    this.checkQuantity        = this.product.checkQuantity;
646                    this.isDblQuantity        = this.product.isDblQuantity;
647                    this.stepQuantity         = this.product.stepQuantity;
648                    this.maxQuantity          = this.product.maxQuantity;
649                    this.minQuantity          = this.currentPriceMode === 'Q' ? parseFloat(this.currentPrices[this.currentPriceSelected].MIN_QUANTITY) : this.stepQuantity;
650
651                    if (this.isDblQuantity) {
652                        this.stepQuantity = Math.round(this.stepQuantity * this.precisionFactor) / this.precisionFactor;
653                    }
654                }
655
656                this.product.canBuy  = this.params.PRODUCT.CAN_BUY;
657                this.canSubscription = this.product.canSubscription = this.params.PRODUCT.SUBSCRIPTION;
658
659                this.product.name     = this.params.PRODUCT.NAME;
660                this.product.pict     = this.params.PRODUCT.PICT;
661                this.product.id       = this.params.PRODUCT.ID;
662                this.product.category = this.params.PRODUCT.CATEGORY;
663
664                if (this.params.PRODUCT.ADD_URL) {
665                    this.product.addUrl = this.params.PRODUCT.ADD_URL;
666                }
667
668                if (this.params.PRODUCT.BUY_URL) {
669                    this.product.buyUrl = this.params.PRODUCT.BUY_URL;
670                }
671
672                if (this.params.PRODUCT.SLIDER_COUNT) {
673                    this.product.sliderCount = parseInt(this.params.PRODUCT.SLIDER_COUNT, 10) || 0;
674
675                    if (this.product.sliderCount > 0 && this.params.PRODUCT.SLIDER.length) {
676                        for (j = 0; j < this.params.PRODUCT.SLIDER.length; j++) {
677                            this.product.useSlider               = true;
678                            this.params.PRODUCT.SLIDER[j].WIDTH  = parseInt(this.params.PRODUCT.SLIDER[j].WIDTH, 10);
679                            this.params.PRODUCT.SLIDER[j].HEIGHT = parseInt(this.params.PRODUCT.SLIDER[j].HEIGHT, 10);
680                        }
681
682                        this.product.sliderPict = this.params.PRODUCT.SLIDER;
683                        this.setCurrentImg(this.product.sliderPict[0], false);
684                    }
685                }
686
687                this.currentIsSet = true;
688            } else {
689                this.errorCode = -1;
690            }
691        },
692
693        initOffersData: function() {
694            if (this.params.OFFERS && BX.type.isArray(this.params.OFFERS)) {
695                this.offers   = this.params.OFFERS;
696                this.offerNum = 0;
697
698                if (this.params.OFFER_SELECTED) {
699                    this.offerNum = parseInt(this.params.OFFER_SELECTED, 10) || 0;
700                }
701
702                if (this.params.TREE_PROPS) {
703                    this.treeProps = this.params.TREE_PROPS;
704                }
705
706                if (this.params.DEFAULT_PICTURE) {
707                    this.defaultPict.preview = this.params.DEFAULT_PICTURE.PREVIEW_PICTURE;
708                    this.defaultPict.detail  = this.params.DEFAULT_PICTURE.DETAIL_PICTURE;
709                }
710
711                if (this.params.PRODUCT && typeof this.params.PRODUCT === 'object') {
712                    this.product.id       = parseInt(this.params.PRODUCT.ID, 10);
713                    this.product.name     = this.params.PRODUCT.NAME;
714                    this.product.category = this.params.PRODUCT.CATEGORY;
715                }
716            } else {
717                this.errorCode = -1;
718            }
719        },
720
721        initBasketData: function() {
722            if (this.params.BASKET && typeof this.params.BASKET === 'object') {
723                if (this.productType === 1 || this.productType === 2) {
724                    this.basketData.useProps   = this.params.BASKET.ADD_PROPS;
725                    this.basketData.emptyProps = this.params.BASKET.EMPTY_PROPS;
726                }
727
728                if (this.params.BASKET.QUANTITY) {
729                    this.basketData.quantity = this.params.BASKET.QUANTITY;
730                }
731
732                if (this.params.BASKET.PROPS) {
733                    this.basketData.props = this.params.BASKET.PROPS;
734                }
735
736                if (this.params.BASKET.BASKET_URL) {
737                    this.basketData.basketUrl = this.params.BASKET.BASKET_URL;
738                }
739
740                if (this.productType === 3) {
741                    if (this.params.BASKET.SKU_PROPS) {
742                        this.basketData.sku_props = this.params.BASKET.SKU_PROPS;
743                    }
744                }
745
746                if (this.params.BASKET.ADD_URL_TEMPLATE) {
747                    this.basketData.add_url = this.params.BASKET.ADD_URL_TEMPLATE;
748                }
749
750                if (this.params.BASKET.BUY_URL_TEMPLATE) {
751                    this.basketData.buy_url = this.params.BASKET.BUY_URL_TEMPLATE;
752                }
753
754                if (this.basketData.add_url === '' && this.basketData.buy_url === '') {
755                    this.errorCode = -1024;
756                }
757            }
758        },
759
760        initCompareData: function() {
761            if (this.config.useCompare) {
762                if (this.params.COMPARE && typeof this.params.COMPARE === 'object') {
763                    if (this.params.COMPARE.COMPARE_PATH) {
764                        this.compareData.comparePath = this.params.COMPARE.COMPARE_PATH;
765                    }
766
767                    if (this.params.COMPARE.COMPARE_URL_TEMPLATE) {
768                        this.compareData.compareUrl = this.params.COMPARE.COMPARE_URL_TEMPLATE;
769                    } else {
770                        this.config.useCompare = false;
771                    }
772
773                    if (this.params.COMPARE.COMPARE_DELETE_URL_TEMPLATE) {
774                        this.compareData.compareDeleteUrl = this.params.COMPARE.COMPARE_DELETE_URL_TEMPLATE;
775                    } else {
776                        this.config.useCompare = false;
777                    }
778                } else {
779                    this.config.useCompare = false;
780                }
781            }
782        },
783
784        initSlider: function() {
785            if (this.node.sliderProgressBar) {
786                if (this.slider.progress) {
787                    this.resetProgress();
788                } else {
789                    this.slider.progress = new BX.easing({
790                        transition: BX.easing.transitions.linear,
791                        step:       BX.delegate(function(state) {
792                            this.node.sliderProgressBar.style.width = state.width / 10 + '%';
793                        }, this)
794                    });
795                }
796            }
797
798            this.cycleSlider();
799        },
800
801        setAnalyticsDataLayer: function(action) {
802            if (!this.config.useEnhancedEcommerce || !this.config.dataLayerName)
803                return;
804
805            var item     = {},
806                info     = {},
807                variants = [],
808                i, k, j, propId, skuId, propValues;
809
810            switch (this.productType) {
811                case 0: //no catalog
812                case 1: //product
813                case 2: //set
814                    item = {
815                        'id':       this.product.id,
816                        'name':     this.product.name,
817                        'price':    this.currentPrices[this.currentPriceSelected] && this.currentPrices[this.currentPriceSelected].PRICE,
818                        'category': this.product.category,
819                        'brand':    BX.type.isArray(this.config.brandProperty) ? this.config.brandProperty.join('/') : this.config.brandProperty
820                    };
821                    break;
822                case 3: //sku
823                    for (i in this.offers[this.offerNum].TREE) {
824                        if (this.offers[this.offerNum].TREE.hasOwnProperty(i)) {
825                            propId = i.substring(5);
826                            skuId  = this.offers[this.offerNum].TREE[i];
827
828                            for (k in this.treeProps) {
829                                if (this.treeProps.hasOwnProperty(k) && this.treeProps[k].ID == propId) {
830                                    for (j in this.treeProps[k].VALUES) {
831                                        propValues = this.treeProps[k].VALUES[j];
832                                        if (propValues.ID == skuId) {
833                                            variants.push(propValues.NAME);
834                                            break;
835                                        }
836                                    }
837
838                                }
839                            }
840                        }
841                    }
842
843                    item = {
844                        'id':       this.offers[this.offerNum].ID,
845                        'name':     this.offers[this.offerNum].NAME,
846                        'price':    this.currentPrices[this.currentPriceSelected] && this.currentPrices[this.currentPriceSelected].PRICE,
847                        'category': this.product.category,
848                        'brand':    BX.type.isArray(this.config.brandProperty) ? this.config.brandProperty.join('/') : this.config.brandProperty,
849                        'variant':  variants.join('/')
850                    };
851                    break;
852            }
853
854            switch (action) {
855                case 'showDetail':
856                    info = {
857                        'event':     'showDetail',
858                        'ecommerce': {
859                            'currencyCode': this.currentPrices[this.currentPriceSelected] && this.currentPrices[this.currentPriceSelected].CURRENCY || '',
860                            'detail':       {
861                                'products': [{
862                                    'name':     item.name || '',
863                                    'id':       item.id || '',
864                                    'price':    item.price || 0,
865                                    'brand':    item.brand || '',
866                                    'category': item.category || '',
867                                    'variant':  item.variant || ''
868                                }]
869                            }
870                        }
871                    };
872                    break;
873                case 'addToCart':
874                    info = {
875                        'event':     'addToCart',
876                        'ecommerce': {
877                            'currencyCode': this.currentPrices[this.currentPriceSelected] && this.currentPrices[this.currentPriceSelected].CURRENCY || '',
878                            'add':          {
879                                'products': [{
880                                    'name':     item.name || '',
881                                    'id':       item.id || '',
882                                    'price':    item.price || 0,
883                                    'brand':    item.brand || '',
884                                    'category': item.category || '',
885                                    'variant':  item.variant || '',
886                                    'quantity': this.config.showQuantity && this.obQuantity ? this.obQuantity.value : 1
887                                }]
888                            }
889                        }
890                    };
891                    break;
892            }
893
894            window[this.config.dataLayerName] = window[this.config.dataLayerName] || [];
895            window[this.config.dataLayerName].push(info);
896        },
897
898        initTabs: function() {
899            var tabs      = this.getEntities(this.obTabs, 'tab'),
900                panelTabs = this.getEntities(this.obTabsPanel, 'tab');
901
902            var tabValue, targetTab, haveActive = false;
903
904            if (tabs.length !== panelTabs.length)
905                return;
906
907            for (var i in tabs) {
908                if (tabs.hasOwnProperty(i) && BX.type.isDomNode(tabs[i])) {
909                    tabValue = tabs[i].getAttribute('data-value');
910                    if (tabValue) {
911                        targetTab = this.obTabContainers.querySelector('[data-value="' + tabValue + '"]');
912                        if (BX.type.isDomNode(targetTab)) {
913                            BX.bind(tabs[i], 'click', BX.proxy(this.changeTab, this));
914                            BX.bind(panelTabs[i], 'click', BX.proxy(this.changeTab, this));
915
916                            if (!haveActive) {
917                                BX.addClass(tabs[i], 'active');
918                                BX.addClass(panelTabs[i], 'active');
919                                BX.show(targetTab);
920                                haveActive = true;
921                            } else {
922                                BX.removeClass(tabs[i], 'active');
923                                BX.removeClass(panelTabs[i], 'active');
924                                BX.hide(targetTab);
925                            }
926                        }
927                    }
928                }
929            }
930        },
931
932        checkTouch: function(event) {
933            if (!event || !event.changedTouches)
934                return false;
935
936            return event.changedTouches[0].identifier === this.touch.identifier;
937        },
938
939        touchStartEvent: function(event) {
940            if (event.touches.length != 1)
941                return;
942
943            this.touch = event.changedTouches[0];
944        },
945
946        touchEndEvent: function(event) {
947            if (!this.checkTouch(event))
948                return;
949
950            var deltaX = this.touch.pageX - event.changedTouches[0].pageX,
951                deltaY = this.touch.pageY - event.changedTouches[0].pageY;
952
953            if (Math.abs(deltaX) >= Math.abs(deltaY) + 10) {
954                if (deltaX > 0) {
955                    this.slideNext();
956                }
957
958                if (deltaX < 0) {
959                    this.slidePrev();
960                }
961            }
962        },
963
964        cycleSlider: function(event) {
965            event || (this.slider.paused = false);
966
967            this.slider.interval && clearInterval(this.slider.interval);
968
969            if (this.config.sliderInterval && !this.slider.paused) {
970                if (this.slider.progress) {
971                    this.slider.progress.stop();
972
973                    var width = parseInt(this.node.sliderProgressBar.style.width);
974
975                    this.slider.progress.options.duration = this.config.sliderInterval * (100 - width) / 100;
976                    this.slider.progress.options.start    = {width: width * 10};
977                    this.slider.progress.options.finish   = {width: 1000};
978                    this.slider.progress.options.complete = BX.delegate(function() {
979                        this.slider.interval = true;
980                        this.slideNext();
981                    }, this);
982                    this.slider.progress.animate();
983                } else {
984                    this.slider.interval = setInterval(BX.proxy(this.slideNext, this), this.config.sliderInterval);
985                }
986            }
987        },
988
989        stopSlider: function(event) {
990            event || (this.slider.paused = true);
991
992            this.slider.interval && (this.slider.interval = clearInterval(this.slider.interval));
993
994            if (this.slider.progress) {
995                this.slider.progress.stop();
996
997                var width = parseInt(this.node.sliderProgressBar.style.width);
998
999                this.slider.progress.options.duration = this.config.sliderInterval * width / 200;
1000                this.slider.progress.options.start    = {width: width * 10};
1001                this.slider.progress.options.finish   = {width: 0};
1002                this.slider.progress.options.complete = null;
1003                this.slider.progress.animate();
1004            }
1005        },
1006
1007        resetProgress: function() {
1008            this.slider.progress && this.slider.progress.stop();
1009            this.node.sliderProgressBar.style.width = 0;
1010        },
1011
1012        slideNext: function() {
1013            return this.slide('next');
1014        },
1015
1016        slidePrev: function() {
1017            return this.slide('prev');
1018        },
1019
1020        slide: function(type) {
1021            if (!this.product.slider || !this.product.slider.CONT)
1022                return;
1023
1024            var active = this.getEntity(this.product.slider.CONT, 'slider-control', '.active'),
1025                next   = this.getItemForDirection(type, active);
1026
1027            BX.removeClass(active, 'active');
1028            this.selectSliderImg(next);
1029
1030            this.slider.interval && this.cycleSlider();
1031        },
1032
1033        getItemForDirection: function(direction, active) {
1034            var activeIndex = this.getItemIndex(active),
1035                delta       = direction === 'prev' ? -1 : 1,
1036                itemIndex   = (activeIndex + delta) % this.product.slider.COUNT;
1037
1038            return this.eq(this.product.slider.ITEMS, itemIndex);
1039        },
1040
1041        getItemIndex: function(item) {
1042            return BX.util.array_values(this.product.slider.ITEMS).indexOf(item);
1043        },
1044
1045        eq: function(obj, i) {
1046            var len = obj.length,
1047                j   = +i + (i < 0 ? len : 0);
1048
1049            return j >= 0 && j < len ? obj[j] : {};
1050        },
1051
1052        scrollToProduct: function() {
1053            var scrollTop    = BX.GetWindowScrollPos().scrollTop,
1054                containerTop = BX.pos(this.obProduct).top - 30;
1055
1056            if (scrollTop >
1056 containerTop) {
1057                new BX.easing({
1058                    duration:   500,
1059                    start:      {scroll: scrollTop},
1060                    finish:     {scroll: containerTop},
1061                    transition: BX.easing.makeEaseOut(BX.easing.transitions.quint),
1062                    step:       BX.delegate(function(state) {
1063                        window.scrollTo(0, state.scroll);
1064                    }, this)
1065                }).animate();
1066            }
1067        },
1068
1069        checkTopPanels: function() {
1070            var scrollTop = BX.GetWindowScrollPos().scrollTop,
1071                targetPos;
1072
1073            if (this.smallCardNodes.panel) {
1074                targetPos = BX.pos(this.smallCardNodes.aligner).bottom - 50;
1075
1076                if (scrollTop > targetPos) {
1077                    BX.addClass(this.smallCardNodes.panel, 'active');
1078                } else if (BX.hasClass(this.smallCardNodes.panel, 'active')) {
1079                    BX.removeClass(this.smallCardNodes.panel, 'active');
1080                }
1081            }
1082
1083            if (this.obTabsPanel) {
1084                targetPos = BX.pos(this.obTabs).top;
1085
1086                if (scrollTop + 73 > targetPos) {
1087                    BX.addClass(this.obTabsPanel, 'active');
1088                } else if (BX.hasClass(this.obTabsPanel, 'active')) {
1089                    BX.removeClass(this.obTabsPanel, 'active');
1090                }
1091            }
1092        },
1093
1094        changeTab: function(event) {
1095            BX.PreventDefault(event);
1096
1097            var targetTabValue = BX.proxy_context && BX.proxy_context.getAttribute('data-value'),
1098                containers, tabs, panelTabs;
1099
1100            if (!BX.hasClass(BX.proxy_context, 'active') && targetTabValue) {
1101                containers = this.getEntities(this.obTabContainers, 'tab-container');
1102                for (var i in containers) {
1103                    if (containers.hasOwnProperty(i) && BX.type.isDomNode(containers[i])) {
1104                        if (containers[i].getAttribute('data-value') === targetTabValue) {
1105                            BX.show(containers[i]);
1106                        } else {
1107                            BX.hide(containers[i]);
1108                        }
1109                    }
1110                }
1111
1112                tabs      = this.getEntities(this.obTabs, 'tab');
1113                panelTabs = this.getEntities(this.obTabsPanel, 'tab');
1114
1115                for (i in tabs) {
1116                    if (tabs.hasOwnProperty(i) && BX.type.isDomNode(tabs[i])) {
1117                        if (tabs[i].getAttribute('data-value') === targetTabValue) {
1118                            BX.addClass(tabs[i], 'active');
1119                            BX.addClass(panelTabs[i], 'active');
1120                        } else {
1121                            BX.removeClass(tabs[i], 'active');
1122                            BX.removeClass(panelTabs[i], 'active');
1123                        }
1124                    }
1125                }
1126            }
1127
1128            var scrollTop    = BX.GetWindowScrollPos().scrollTop,
1129                containerTop = BX.pos(this.obTabContainers).top;
1130
1131            if (scrollTop + 150 > containerTop) {
1132                new BX.easing({
1133                    duration:   500,
1134                    start:      {scroll: scrollTop},
1135                    finish:     {scroll: containerTop - 150},
1136                    transition: BX.easing.makeEaseOut(BX.easing.transitions.quint),
1137                    step:       BX.delegate(function(state) {
1138                        window.scrollTo(0, state.scroll);
1139                    }, this)
1140                }).animate();
1141            }
1142        },
1143
1144        initPopup: function() {
1145            if (this.config.usePopup) {
1146                this.node.imageContainer.style.cursor = 'zoom-in';
1147                BX.bind(this.node.imageContainer, 'click', BX.delegate(this.toggleMainPictPopup, this));
1148                BX.bind(document, 'keyup', BX.proxy(this.closeByEscape, this));
1149                BX.bind(
1150                    this.getEntity(this.obBigSlider, 'close-popup'),
1151                    'click',
1152                    BX.proxy(this.hideMainPictPopup, this)
1153                );
1154            }
1155        },
1156
1157        checkSliderControls: function(count) {
1158            var display = count > 1 ? '' : 'none';
1159
1160            this.node.sliderControlLeft && (this.node.sliderControlLeft.style.display = display);
1161            this.node.sliderControlRight && (this.node.sliderControlRight.style.display = display);
1162        },
1163
1164        setCurrentImg: function(img, showImage, showPanelImage) {
1165            var images, l;
1166
1167            this.currentImg.id     = img.ID;
1168            this.currentImg.src    = img.SRC;
1169            this.currentImg.width  = img.WIDTH;
1170            this.currentImg.height = img.HEIGHT;
1171
1172            if (showImage && this.node.imageContainer) {
1173                images = this.getEntities(this.node.imageContainer, 'image');
1174                l      = images.length;
1175                while (l--) {
1176                    if (images[l].getAttribute('data-id') == img.ID) {
1177                        if (!BX.hasClass(images[l], 'active')) {
1178                            this.node.sliderProgressBar && this.resetProgress();
1179                        }
1180
1181                        BX.addClass(images[l], 'active');
1182                    } else if (BX.hasClass(images[l], 'active')) {
1183                        BX.removeClass(images[l], 'active');
1184                    }
1185                }
1186            }
1187
1188            if (showPanelImage && this.smallCardNodes.picture) {
1189                this.smallCardNodes.picture.setAttribute('src', this.currentImg.src);
1190            }
1191
1192            if (this.config.useMagnifier && !this.isTouchDevice) {
1193                //this.setMagnifierParams();
1194
1195                if (showImage) {
1196                    this.disableMagnifier(true);
1197                }
1198            }
1199        },
1200
1201        setMagnifierParams: function() {
1202            var images = this.getEntities(this.node.imageContainer, 'image'),
1203                l      = images.length,
1204                current;
1205
1206            while (l--) {
1207                // disable image title show
1208                current = images[l].querySelector('img');
1209                current.setAttribute('data-title', current.getAttribute('title') || '');
1210                current.removeAttribute('title');
1211
1212                if (images[l].getAttribute('data-id') == this.currentImg.id) {
1213                    BX.unbind(this.currentImg.node, 'mouseover', BX.proxy(this.enableMagnifier, this));
1214
1215                    this.currentImg.node                       = current;
1216                    this.currentImg.node.style.backgroundImage = 'url(\'' + this.currentImg.src + '\')';
1217                    this.currentImg.node.style.backgroundSize  = '100% auto';
1218
1219                    BX.bind(this.currentImg.node, 'mouseover', BX.proxy(this.enableMagnifier, this));
1220                }
1221            }
1222        },
1223
1224        enableMagnifier: function() {
1225            BX.bind(document, 'mousemove', BX.proxy(this.moveMagnifierArea, this));
1226        },
1227
1228        disableMagnifier: function(animateSize) {
1229            if (!this.magnify.enabled)
1230                return;
1231
1232            clearTimeout(this.magnify.timer);
1233            BX.removeClass(this.obBigSlider, 'magnified');
1234            this.magnify.enabled = false;
1235
1236            this.currentImg.node.style.backgroundSize = '100% auto';
1237            if (animateSize) {
1238                // set initial size for css animation
1239                this.currentImg.node.style.height = this.magnify.height + 'px';
1240                this.currentImg.node.style.width  = this.magnify.width + 'px';
1241
1242                this.magnify.timer = setTimeout(
1243                    BX.delegate(function() {
1244                        this.currentImg.node.src          = this.currentImg.src;
1245                        this.currentImg.node.style.height = '';
1246                        this.currentImg.node.style.width  = '';
1247                    }, this),
1248                    250
1249                );
1250            } else {
1251                this.currentImg.node.src          = this.currentImg.src;
1252                this.currentImg.node.style.height = '';
1253                this.currentImg.node.style.width  = '';
1254            }
1255
1256            BX.unbind(document, 'mousemove', BX.proxy(this.moveMagnifierArea, this));
1257        },
1258
1259        moveMagnifierArea: function(e) {
1260            var posBigImg  = BX.pos(this.currentImg.node),
1261                currentPos = this.inRect(e, posBigImg);
1262
1263            if (this.inBound(posBigImg, currentPos)) {
1264                var posPercentX = (currentPos.X / this.currentImg.node.width) * 100,
1265                    posPercentY = (currentPos.Y / this.currentImg.node.height) * 100,
1266                    resolution, sliderWidth, w, h, zoomPercent;
1267
1268                this.currentImg.node.style.backgroundPosition = posPercentX + '% ' + posPercentY + '%';
1269
1270                if (!this.magnify.enabled) {
1271                    clearTimeout(this.magnify.timer);
1272                    BX.addClass(this.obBigSlider, 'magnified');
1273
1274                    // set initial size for css animation
1275                    this.currentImg.node.style.height = (this.magnify.height = this.currentImg.node.clientHeight) + 'px';
1276                    this.currentImg.node.style.width  = (this.magnify.width = this.currentImg.node.offsetWidth) + 'px';
1277
1278                    resolution  = this.currentImg.width / this.currentImg.height;
1279                    sliderWidth = this.obBigSlider.offsetWidth;
1280
1281                    if (sliderWidth > this.currentImg.width && !BX.hasClass(this.obBigSlider, 'popup')) {
1282                        w           = sliderWidth;
1283                        h           = w / resolution;
1284                        zoomPercent = 100;
1285                    } else {
1286                        w           = this.currentImg.width;
1287                        h           = this.currentImg.height;
1288                        zoomPercent = this.config.magnifierZoomPercent > 100 ? this.config.magnifierZoomPercent : 100;
1289                    }
1290
1291                    // base64 transparent pixel
1292                    this.currentImg.node.src                  = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQI12P4zwAAAgEBAKrChTYAAAAASUVORK5CYII=';
1293                    this.currentImg.node.style.backgroundSize = zoomPercent + '% auto';
1294
1295                    // set target size
1296                    this.magnify.timer = setTimeout(BX.delegate(function() {
1297                            this.currentImg.node.style.height = h + 'px';
1298                            this.currentImg.node.style.width  = w + 'px';
1299                        }, this),
1300                        10
1301                    );
1302                }
1303
1304                this.magnify.enabled = true;
1305            } else {
1306                this.disableMagnifier(true);
1307            }
1308        },
1309
1310        inBound: function(rect, point) {
1311            return (
1312                (point.Y >= 0 && rect.height >= point.Y)
1313                && (point.X >= 0 && rect.width >= point.X)
1314            );
1315        },
1316
1317        inRect: function(e, rect) {
1318            var wndSize    = BX.GetWindowSize(),
1319                currentPos = {
1320                    X:       0,
1321                    Y:       0,
1322                    globalX: 0,
1323                    globalY: 0
1324                };
1325
1326            currentPos.globalX = e.clientX + wndSize.scrollLeft;
1327
1328            if (e.offsetX && e.offsetX < 0) {
1329                currentPos.globalX -= e.offsetX;
1330            }
1331
1332            currentPos.X       = currentPos.globalX - rect.left;
1333            currentPos.globalY = e.clientY + wndSize.scrollTop;
1334
1335            if (e.offsetY && e.offsetY < 0) {
1336                currentPos.globalY -= e.offsetY;
1337            }
1338
1339            currentPos.Y = currentPos.globalY - rect.top;
1340
1341            return currentPos;
1342        },
1343
1344        setProductMainPict: function(intPict) {
1345            var indexPict = -1,
1346                i         = 0,
1347                j         = 0,
1348                value     = '';
1349
1350            if (this.product.sliderCount) {
1351                for (j = 0; j < this.product.sliderPict.length; j++) {
1352                    if (intPict === this.product.sliderPict[j].ID) {
1353                        indexPict = j;
1354                        break;
1355                    }
1356                }
1357
1358                if (indexPict > -1) {
1359                    if (this.product.sliderPict[indexPict]) {
1360                        this.setCurrentImg(this.product.sliderPict[indexPict], true);
1361                    }
1362
1363                    for (i = 0; i < this.product.slider.ITEMS.length; i++) {
1364                        value = this.product.slider.ITEMS[i].getAttribute('data-value');
1365
1366                        if (value === intPict) {
1367                            BX.addClass(this.product.slider.ITEMS[i], 'active');
1368                        } else if (BX.hasClass(this.product.slider.ITEMS[i], 'active')) {
1369                            BX.removeClass(this.product.slider.ITEMS[i], 'active');
1370                        }
1371                    }
1372                }
1373            }
1374        },
1375
1376        onSliderControlHover: function() {
1377            var target = BX.proxy_context;
1378
1379            this.mouseTimer = setTimeout(
1380                BX.delegate(function() {
1381                    this.selectSliderImg(target);
1382                }, this),
1383                200
1384            );
1385        },
1386
1387        onSliderControlLeave: function() {
1388            clearTimeout(this.mouseTimer);
1389            this.mouseTimer = null;
1390        },
1391
1392        selectSliderImg: function(target) {
1393            var strValue = '',
1394                arItem   = [];
1395
1396            target = BX.type.isDomNode(target) ? target : BX.proxy_context;
1397
1398            if (target && target.hasAttribute('data-value')) {
1399                strValue = target.getAttribute('data-value');
1400
1401                if (strValue.indexOf('_') !== -1) {
1402                    arItem = strValue.split('_');
1403                    this.setMainPict(arItem[0], arItem[1]);
1404                } else {
1405                    this.setProductMainPict(strValue);
1406                }
1407            }
1408        },
1409
1410        setMainPict: function(intSlider, intPict, changePanelPict) {
1411            var index     = -1,
1412                indexPict = -1,
1413                i,
1414                j,
1415                value     = '',
1416                strValue  = '';
1417
1418            for (i = 0; i < this.offers.length; i++) {
1419                if (intSlider === this.offers[i].ID) {
1420                    index = i;
1421                    break;
1422                }
1423            }
1424
1425            if (index > -1) {
1426                if (this.offers[index].SLIDER_COUNT > 0) {
1427                    for (j = 0; j < this.offers[index].SLIDER.length; j++) {
1428                        if (intPict === this.offers[index].SLIDER[j].ID) {
1429                            indexPict = j;
1430                            break;
1431                        }
1432                    }
1433
1434                    if (indexPict > -1) {
1435                        if (this.offers[index].SLIDER[indexPict]) {
1436                            this.setCurrentImg(this.offers[index].SLIDER[indexPict], true, changePanelPict);
1437                        }
1438
1439                        strValue = intSlider + '_' + intPict;
1440
1441                        for (i = 0; i < this.product.slider.ITEMS.length; i++) {
1442                            value = this.product.slider.ITEMS[i].getAttribute('data-value');
1443
1444                            if (value === strValue) {
1445                                BX.addClass(this.product.slider.ITEMS[i], 'active');
1446                            } else if (BX.hasClass(this.product.slider.ITEMS[i], 'active')) {
1447                                BX.removeClass(this.product.slider.ITEMS[i], 'active');
1448                            }
1449                        }
1450                    }
1451                }
1452            }
1453        },
1454
1455        setMainPictFromItem: function(index) {
1456            if (this.node.imageContainer) {
1457                var boolSet   = false,
1458                    obNewPict = {};
1459
1460                if (this.offers[index]) {
1461                    if (this.offers[index].DETAIL_PICTURE) {
1462                        obNewPict = this.offers[index].DETAIL_PICTURE;
1463                        boolSet   = true;
1464                    } else if (this.offers[index].PREVIEW_PICTURE) {
1465                        obNewPict = this.offers[index].PREVIEW_PICTURE;
1466                        boolSet   = true;
1467                    }
1468                }
1469
1470                if (!boolSet) {
1471                    if (this.defaultPict.detail) {
1472                        obNewPict = this.defaultPict.detail;
1473                        boolSet   = true;
1474                    } else if (this.defaultPict.preview) {
1475                        obNewPict = this.defaultPict.preview;
1476                        boolSet   = true;
1477                    }
1478                }
1479
1480                if (boolSet) {
1481                    this.setCurrentImg(obNewPict, true, true);
1482                }
1483            }
1484        },
1485
1486        toggleMainPictPopup: function() {
1487            if (BX.hasClass(this.obBigSlider, 'popup')) {
1488                this.hideMainPictPopup();
1489            } else {
1490                this.showMainPictPopup();
1491            }
1492        },
1493
1494        showMainPictPopup: function() {
1495            this.config.useMagnifier && this.disableMagnifier(false);
1496            BX.addClass(this.obBigSlider, 'popup');
1497            this.node.imageContainer.style.cursor = '';
1498            // remove double scroll bar
1499            document.body.style.overflow          = 'hidden';
1500        },
1501
1502        hideMainPictPopup: function() {
1503            this.config.useMagnifier && this.disableMagnifier(false);
1504            BX.removeClass(this.obBigSlider, 'popup');
1505            this.node.imageContainer.style.cursor = 'zoom-in';
1506            // remove double scroll bar
1507            document.body.style.overflow          = '';
1508        },
1509
1510        closeByEscape: function(event) {
1511            event = event || window.event;
1512
1513            if (event.keyCode == 27) {
1514                this.hideMainPictPopup();
1515            }
1516        },
1517
1518        startQuantityInterval: function() {
1519            var target = BX.proxy_context;
1520            var func   = target.id === this.visual.QUANTITY_DOWN_ID
1521                ? BX.proxy(this.quantityDown, this)
1522                : BX.proxy(this.quantityUp, this);
1523
1524            this.quantityDelay = setTimeout(
1525                BX.delegate(function() {
1526                    this.quantityTimer = setInterval(func, 150);
1527                }, this),
1528                300
1529            );
1530        },
1531
1532        clearQuantityInterval: function() {
1533            clearTimeout(this.quantityDelay);
1534            clearInterval(this.quantityTimer);
1535        },
1536
1537        quantityUp: function() {
1538            var curValue = 0,
1539                boolSet  = true;
1540
1541            if (this.errorCode === 0 && this.config.showQuantity && this.canBuy && !this.isGift) {
1542                curValue = this.isDblQuantity ? parseFloat(this.obQuantity.value) : parseInt(this.obQuantity.value, 10);
1543                if (!isNaN(curValue)) {
1544                    curValue += this.stepQuantity;
1545
1546                    curValue = this.checkQuantityRange(curValue, 'up');
1547
1548                    if (this.checkQuantity && curValue > this.maxQuantity) {
1549                        boolSet = false;
1550                    }
1551
1552                    if (boolSet) {
1553                        if (this.isDblQuantity) {
1554                            curValue = Math.round(curValue * this.precisionFactor) / this.precisionFactor;
1555                        }
1556
1557                        this.obQuantity.value = curValue;
1558
1559                        this.setPrice();
1560                    }
1561                }
1562            }
1563        },
1564
1565        quantityDown: function() {
1566            var curValue = 0,
1567                boolSet  = true;
1568
1569            if (this.errorCode === 0 && this.config.showQuantity && this.canBuy && !this.isGift) {
1570                curValue = (this.isDblQuantity ? parseFloat(this.obQuantity.value) : parseInt(this.obQuantity.value, 10));
1571                if (!isNaN(curValue)) {
1572                    curValue -= this.stepQuantity;
1573
1574                    curValue = this.checkQuantityRange(curValue, 'down');
1575
1576                    if (curValue < this.minQuantity) {
1577                        boolSet = false;
1578                    }
1579
1580                    if (boolSet) {
1581                        if (this.isDblQuantity) {
1582                            curValue = Math.round(curValue * this.precisionFactor) / this.precisionFactor;
1583                        }
1584
1585                        this.obQuantity.value = curValue;
1586
1587                        this.setPrice();
1588                    }
1589                }
1590            }
1591        },
1592
1593        quantityChange: function() {
1594            var curValue = 0,
1595                intCount;
1596
1597            if (this.errorCode === 0 && this.config.showQuantity) {
1598                if (this.canBuy) {
1599                    curValue = this.isDblQuantity ? parseFloat(this.obQuantity.value) : Math.round(this.obQuantity.value);
1600                    if (!isNaN(curValue)) {
1601                        curValue = this.checkQuantityRange(curValue);
1602
1603                        if (this.checkQuantity) {
1604                            if (curValue > this.maxQuantity) {
1605                                curValue = this.maxQuantity;
1606                            }
1607                        }
1608
1609                        this.checkPriceRange(curValue);
1610
1611                        intCount = Math.floor(
1612                            Math.round(curValue * this.precisionFactor / this.stepQuantity) / this.precisionFactor
1613                        ) || 1;
1614                        curValue = (intCount <= 1 ? this.stepQuantity : intCount * this.stepQuantity);
1615                        curValue = Math.round(curValue * this.precisionFactor) / this.precisionFactor;
1616
1617                        if (curValue < this.minQuantity) {
1618                            curValue = this.minQuantity;
1619                        }
1620
1621                        this.obQuantity.value = curValue;
1622                    } else {
1623                        this.obQuantity.value = this.minQuantity;
1624                    }
1625                } else {
1626                    this.obQuantity.value = this.minQuantity;
1627                }
1628
1629                this.setPrice();
1630            }
1631        },
1632
1633        quantitySet: function(index) {
1634            var strLimit, resetQuantity;
1635
1636            var newOffer = this.offers[index],
1637                oldOffer = this.offers[this.offerNum];
1638
1639            if (this.errorCode === 0) {
1640                this.canBuy = newOffer.CAN_BUY;
1641
1642                this.currentPriceMode             = newOffer.ITEM_PRICE_MODE;
1643                this.currentPrices                = newOffer.ITEM_PRICES;
1644                this.currentPriceSelected         = newOffer.ITEM_PRICE_SELECTED;
1645                this.currentQuantityRanges        = newOffer.ITEM_QUANTITY_RANGES;
1646                this.currentQuantityRangeSelected = newOffer.ITEM_QUANTITY_RANGE_SELECTED;
1647
1648                if (this.canBuy) {
1649                    this.node.quantity && BX.style(this.node.quantity, 'display', '');
1650
1651                    this.obBasketActions && BX.style(this.obBasketActions, 'display', '');
1652                    this.smallCardNodes.buyButton && BX.style(this.smallCardNodes.buyButton, 'display', '');
1653                    this.smallCardNodes.addButton && BX.style(this.smallCardNodes.addButton, 'display', '');
1654
1655                    this.obNotAvail && BX.style(this.obNotAvail, 'display', 'none');
1656                    this.smallCardNodes.notAvailableButton && BX.style(this.smallCardNodes.notAvailableButton, 'display', 'none');
1657
1658                    this.obSubscribe && BX.style(this.obSubscribe, 'display', 'none');
1659                } else {
1660                    this.node.quantity && BX.style(this.node.quantity, 'display', 'none');
1661
1662                    this.obBasketActions && BX.style(this.obBasketActions, 'display', 'none');
1663                    this.smallCardNodes.buyButton && BX.style(this.smallCardNodes.buyButton, 'display', 'none');
1664                    this.smallCardNodes.addButton && BX.style(this.smallCardNodes.addButton, 'display', 'none');
1665
1666                    this.obNotAvail && BX.style(this.obNotAvail, 'display', '');
1667                    this.smallCardNodes.notAvailableButton && BX.style(this.smallCardNodes.notAvailableButton, 'display', '');
1668
1669                    if (this.obSubscribe) {
1670                        if (newOffer.CATALOG_SUBSCRIBE === 'Y') {
1671                            BX.style(this.obSubscribe, 'display', '');
1672                            this.obSubscribe.setAttribute('data-item', newOffer.ID);
1673                            BX(this.visual.SUBSCRIBE_LINK + '_hidden').click();
1674                        } else {
1675                            BX.style(this.obSubscribe, 'display', 'none');
1676                        }
1677                    }
1678                }
1679
1680                this.isDblQuantity = newOffer.QUANTITY_FLOAT;
1681                this.checkQuantity = newOffer.CHECK_QUANTITY;
1682
1683                if (this.isDblQuantity) {
1684                    this.stepQuantity = Math.round(parseFloat(newOffer.STEP_QUANTITY) * this.precisionFactor) / this.precisionFactor;
1685                    this.maxQuantity  = parseFloat(newOffer.MAX_QUANTITY);
1686                    this.minQuantity  = this.currentPriceMode === 'Q' ? parseFloat(this.currentPrices[this.currentPriceSelected].MIN_QUANTITY) : this.stepQuantity;
1687                } else {
1688                    this.stepQuantity = parseInt(newOffer.STEP_QUANTITY, 10);
1689                    this.maxQuantity  = parseInt(newOffer.MAX_QUANTITY, 10);
1690                    this.minQuantity  = this.currentPriceMode === 'Q' ? parseInt(this.currentPrices[this.currentPriceSelected].MIN_QUANTITY) : this.stepQuantity;
1691                }
1692
1693                if (this.config.showQuantity) {
1694                    var isDifferentMinQuantity = oldOffer.ITEM_PRICES.length
1695                        && oldOffer.ITEM_PRICES[oldOffer.ITEM_PRICE_SELECTED]
1696                        && oldOffer.ITEM_PRICES[oldOffer.ITEM_PRICE_SELECTED].MIN_QUANTITY != this.minQuantity;
1697
1698                    if (this.isDblQuantity) {
1699                        resetQuantity = Math.round(parseFloat(oldOffer.STEP_QUANTITY) * this.precisionFactor) / this.precisionFactor !== this.stepQuantity
1700                            || isDifferentMinQuantity
1701                            || oldOffer.MEASURE !== newOffer.MEASURE
1702                            || (
1703                                this.checkQuantity
1704                                && parseFloat(oldOffer.MAX_QUANTITY) > this.maxQuantity
1705                                && parseFloat(this.obQuantity.value) > this.maxQuantity
1706                            );
1707                    } else {
1708                        resetQuantity = parseInt(oldOffer.STEP_QUANTITY, 10) !== this.stepQuantity
1709                            || isDifferentMinQuantity
1710                            || oldOffer.MEASURE !== newOffer.MEASURE
1711                            || (
1712                                this.checkQuantity
1713                                && parseInt(oldOffer.MAX_QUANTITY, 10) > this.maxQuantity
1714                                && parseInt(this.obQuantity.value, 10) > this.maxQuantity
1715                            );
1716                    }
1717
1718                    this.obQuantity.disabled = !this.canBuy;
1719
1720                    if (resetQuantity) {
1721                        this.obQuantity.value = this.minQuantity;
1722                    }
1723
1724                    if (this.obMeasure) {
1725                        if (newOffer.MEASURE) {
1726                            BX.adjust(this.obMeasure, {html: newOffer.MEASURE});
1727                        } else {
1728                            BX.adjust(this.obMeasure, {html: ''});
1729                        }
1730                    }
1731                }
1732
1733                if (this.obQuantityLimit.all) {
1734                    if (!this.checkQuantity || this.maxQuantity == 0) {
1735                        BX.adjust(this.obQuantityLimit.value, {html: ''});
1736                        BX.adjust(this.obQuantityLimit.all, {style: {display: 'none'}});
1737                    } else {
1738                        if (this.config.showMaxQuantity === 'M') {
1739                            strLimit = (this.maxQuantity / this.stepQuantity >= this.config.relativeQuantityFactor)
1740                                ? BX.message('RELATIVE_QUANTITY_MANY')
1741                                : BX.message('RELATIVE_QUANTITY_FEW');
1742                        } else {
1743                            strLimit = this.maxQuantity;
1744
1745                            if (newOffer.MEASURE) {
1746                                strLimit += (' ' + newOffer.MEASURE);
1747                            }
1748                        }
1749
1750                        BX.adjust(this.obQuantityLimit.value, {html: strLimit});
1751                        BX.adjust(this.obQuantityLimit.all, {style: {display: ''}});
1752                    }
1753                }
1754
1755                if (this.config.usePriceRanges && this.obPriceRanges) {
1756                    if (
1757                        this.currentPriceMode === 'Q'
1758                        && newOffer.PRICE_RANGES_HTML
1759                    ) {
1760                        var rangesBody        = this.getEntity(this.obPriceRanges, 'price-ranges-body'),
1761                            rangesRatioHeader = this.getEntity(this.obPriceRanges, 'price-ranges-ratio-header');
1762
1763                        if (rangesBody) {
1764                            rangesBody.innerHTML = newOffer.PRICE_RANGES_HTML;
1765                        }
1766
1767                        if (rangesRatioHeader) {
1768                            rangesRatioHeader.innerHTML = newOffer.PRICE_RANGES_RATIO_HTML;
1769                        }
1770
1771                        this.obPriceRanges.style.display = '';
1772                    } else {
1773                        this.obPriceRanges.style.display = 'none';
1774                    }
1775
1776                }
1777            }
1778        },
1779
1780        selectOfferProp: function() {
1781            var i            = 0,
1782                strTreeValue = '',
1783                arTreeItem   = [],
1784                rowItems     = null,
1785                target       = BX.proxy_context,
1786                smallCardItem;
1787
1788            if (target && target.hasAttribute('data-treevalue')) {
1789                if (BX.hasClass(target, 'selected'))
1790                    return;
1791
1792                if (typeof document.activeElement === 'object') {
1793                    document.activeElement.blur();
1794                }
1795
1796                strTreeValue = target.getAttribute('data-treevalue');
1797                arTreeItem   = strTreeValue.split('_');
1798                this.searchOfferPropIndex(arTreeItem[0], arTreeItem[1]);
1799                rowItems = BX.findChildren(target.parentNode, {tagName: 'li'}, false);
1800
1801                if (rowItems && rowItems.length) {
1802                    for (i = 0; i < rowItems.length; i++) {
1803                        BX.removeClass(rowItems[i], 'selected');
1804                    }
1805                }
1806
1807                BX.addClass(target, 'selected');
1808
1809                if (this.smallCardNodes.panel) {
1810                    smallCardItem = this.smallCardNodes.panel.querySelector('[data-treevalue="' + strTreeValue + '"]');
1811                    if (smallCardItem) {
1812                        rowItems = this.smallCardNodes.panel.querySelectorAll('[data-sku-line="' + smallCardItem.getAttribute('data-sku-line') + '"]');
1813                        for (i = 0; i < rowItems.length; i++) {
1814                            rowItems[i].style.display = 'none';
1815                        }
1816
1817                        smallCardItem.style.display = '';
1818                    }
1819                }
1820            }
1821        },
1822
1823        searchOfferPropIndex: function(strPropID, strPropValue) {
1824            var strName        = '',
1825                arShowValues   = false,
1826                arCanBuyValues = [],
1827                allValues      = [],
1828                index          = -1,
1829                i, j,
1830                arFilter       = {},
1831                tmpFilter      = [];
1832
1833            for (i = 0; i < this.treeProps.length; i++) {
1834                if (this.treeProps[i].ID === strPropID) {
1835                    index = i;
1836                    break;
1837                }
1838            }
1839
1840            if (index > -1) {
1841                for (i = 0; i < index; i++) {
1842                    strName           = 'PROP_' + this.treeProps[i].ID;
1843                    arFilter[strName] = this.selectedValues[strName];
1844                }
1845
1846                strName           = 'PROP_' + this.treeProps[index].ID;
1847                arFilter[strName] = strPropValue;
1848
1849                for (i = index + 1; i < this.treeProps.length; i++) {
1850                    strName      = 'PROP_' + this.treeProps[i].ID;
1851                    arShowValues = this.getRowValues(arFilter, strName);
1852
1853                    if (!arShowValues)
1854                        break;
1855
1856                    allValues = [];
1857
1858                    if (this.config.showAbsent) {
1859                        arCanBuyValues = [];
1860                        tmpFilter      = [];
1861                        tmpFilter      = BX.clone(arFilter, true);
1862
1863                        for (j = 0; j < arShowValues.length; j++) {
1864                            tmpFilter[strName]          = arShowValues[j];
1865                            allValues[allValues.length] = arShowValues[j];
1866                            if (this.getCanBuy(tmpFilter))
1867                                arCanBuyValues[arCanBuyValues.length] = arShowValues[j];
1868                        }
1869                    } else {
1870                        arCanBuyValues = arShowValues;
1871                    }
1872
1873                    if (this.selectedValues[strName] && BX.util.in_array(this.selectedValues[strName], arC
1873anBuyValues)) {
1874                        arFilter[strName] = this.selectedValues[strName];
1875                    } else {
1876                        if (this.config.showAbsent) {
1877                            arFilter[strName] = (arCanBuyValues.length ? arCanBuyValues[0] : allValues[0]);
1878                        } else {
1879                            arFilter[strName] = arCanBuyValues[0];
1880                        }
1881                    }
1882
1883                    this.updateRow(i, arFilter[strName], arShowValues, arCanBuyValues);
1884                }
1885
1886                this.selectedValues = arFilter;
1887                this.changeInfo();
1888            }
1889        },
1890
1891        updateRow: function(intNumber, activeId, showId, canBuyId) {
1892            var i         = 0,
1893                value     = '',
1894                isCurrent = false,
1895                rowItems  = null;
1896
1897            var lineContainer = this.getEntities(this.obTree, 'sku-line-block');
1898
1899            if (intNumber > -1 && intNumber < lineContainer.length) {
1900                rowItems = lineContainer[intNumber].querySelectorAll('li');
1901                for (i = 0; i < rowItems.length; i++) {
1902                    value     = rowItems[i].getAttribute('data-onevalue');
1903                    isCurrent = value === activeId;
1904
1905                    if (isCurrent) {
1906                        BX.addClass(rowItems[i], 'selected');
1907                    } else {
1908                        BX.removeClass(rowItems[i], 'selected');
1909                    }
1910
1911                    if (BX.util.in_array(value, canBuyId)) {
1912                        BX.removeClass(rowItems[i], 'notallowed');
1913                    } else {
1914                        BX.addClass(rowItems[i], 'notallowed');
1915                    }
1916
1917                    rowItems[i].style.display = BX.util.in_array(value, showId) ? '' : 'none';
1918
1919                    if (isCurrent) {
1920                        lineContainer[intNumber].style.display = (value == 0 && canBuyId.length == 1) ? 'none' : '';
1921                    }
1922                }
1923
1924                if (this.smallCardNodes.panel) {
1925                    rowItems = this.smallCardNodes.panel.querySelectorAll('[data-sku-line="' + intNumber + '"]');
1926                    for (i = 0; i < rowItems.length; i++) {
1927                        value     = rowItems[i].getAttribute('data-onevalue');
1928                        isCurrent = value === activeId;
1929
1930                        if (isCurrent) {
1931                            rowItems[i].style.display = '';
1932                        } else {
1933                            rowItems[i].style.display = 'none';
1934                        }
1935
1936                        if (BX.util.in_array(value, canBuyId)) {
1937                            BX.removeClass(rowItems[i], 'notallowed');
1938                        } else {
1939                            BX.addClass(rowItems[i], 'notallowed');
1940                        }
1941
1942                        if (isCurrent) {
1943                            rowItems[i].style.display = (value == 0 && canBuyId.length == 1) ? 'none' : '';
1944                        }
1945                    }
1946                }
1947            }
1948        },
1949
1950        getRowValues: function(arFilter, index) {
1951            var arValues      = [],
1952                i             = 0,
1953                j             = 0,
1954                boolSearch    = false,
1955                boolOneSearch = true;
1956
1957            if (arFilter.length === 0) {
1958                for (i = 0; i < this.offers.length; i++) {
1959                    if (!BX.util.in_array(this.offers[i].TREE[index], arValues)) {
1960                        arValues[arValues.length] = this.offers[i].TREE[index];
1961                    }
1962                }
1963                boolSearch = true;
1964            } else {
1965                for (i = 0; i < this.offers.length; i++) {
1966                    boolOneSearch = true;
1967
1968                    for (j in arFilter) {
1969                        if (arFilter[j] !== this.offers[i].TREE[j]) {
1970                            boolOneSearch = false;
1971                            break;
1972                        }
1973                    }
1974
1975                    if (boolOneSearch) {
1976                        if (!BX.util.in_array(this.offers[i].TREE[index], arValues)) {
1977                            arValues[arValues.length] = this.offers[i].TREE[index];
1978                        }
1979
1980                        boolSearch = true;
1981                    }
1982                }
1983            }
1984
1985            return (boolSearch ? arValues : false);
1986        },
1987
1988        getCanBuy: function(arFilter) {
1989            var i,
1990                j             = 0,
1991                boolOneSearch = true,
1992                boolSearch    = false;
1993
1994            for (i = 0; i < this.offers.length; i++) {
1995                boolOneSearch = true;
1996
1997                for (j in arFilter) {
1998                    if (arFilter[j] !== this.offers[i].TREE[j]) {
1999                        boolOneSearch = false;
2000                        break;
2001                    }
2002                }
2003
2004                if (boolOneSearch) {
2005                    if (this.offers[i].CAN_BUY) {
2006                        boolSearch = true;
2007                        break;
2008                    }
2009                }
2010            }
2011
2012            return boolSearch;
2013        },
2014
2015        setCurrent: function() {
2016            var i,
2017                j              = 0,
2018                strName        = '',
2019                arShowValues   = false,
2020                arCanBuyValues = [],
2021                arFilter       = {},
2022                tmpFilter      = [],
2023                current        = this.offers[this.offerNum].TREE;
2024
2025            for (i = 0; i < this.treeProps.length; i++) {
2026                strName      = 'PROP_' + this.treeProps[i].ID;
2027                arShowValues = this.getRowValues(arFilter, strName);
2028
2029                if (!arShowValues)
2030                    break;
2031
2032                if (BX.util.in_array(current[strName], arShowValues)) {
2033                    arFilter[strName] = current[strName];
2034                } else {
2035                    arFilter[strName] = arShowValues[0];
2036                    this.offerNum     = 0;
2037                }
2038
2039                if (this.config.showAbsent) {
2040                    arCanBuyValues = [];
2041                    tmpFilter      = [];
2042                    tmpFilter      = BX.clone(arFilter, true);
2043
2044                    for (j = 0; j < arShowValues.length; j++) {
2045                        tmpFilter[strName] = arShowValues[j];
2046
2047                        if (this.getCanBuy(tmpFilter)) {
2048                            arCanBuyValues[arCanBuyValues.length] = arShowValues[j];
2049                        }
2050                    }
2051                } else {
2052                    arCanBuyValues = arShowValues;
2053                }
2054
2055                this.updateRow(i, arFilter[strName], arShowValues, arCanBuyValues);
2056            }
2057
2058            this.selectedValues = arFilter;
2059            this.changeInfo();
2060        },
2061
2062        changeInfo: function() {
2063            var index         = -1,
2064                j             = 0,
2065                boolOneSearch = true,
2066                eventData     = {
2067                    currentId: (this.offerNum > -1 ? this.offers[this.offerNum].ID : 0),
2068                    newId:     0
2069                };
2070
2071            var i, offerGroupNode;
2072
2073            for (i = 0; i < this.offers.length; i++) {
2074                boolOneSearch = true;
2075
2076                for (j in this.selectedValues) {
2077                    if (this.selectedValues[j] !== this.offers[i].TREE[j]) {
2078                        boolOneSearch = false;
2079                        break;
2080                    }
2081                }
2082
2083                if (boolOneSearch) {
2084                    index = i;
2085                    break;
2086                }
2087            }
2088
2089            if (index > -1) {
2090                if (index != this.offerNum) {
2091                    this.isGift = false;
2092                }
2093
2094                //this.drawImages(this.offers[index].SLIDER);
2095                this.checkSliderControls(this.offers[index].SLIDER_COUNT);
2096
2097                for (i = 0; i < this.offers.length; i++) {
2098                    if (this.config.showOfferGroup && this.offers[i].OFFER_GROUP) {
2099                        if (offerGroupNode = BX(this.visual.OFFER_GROUP + this.offers[i].ID)) {
2100                            offerGroupNode.style.display = (i == index ? '' : 'none');
2101                        }
2102                    }
2103
2104                    if (this.slider.controls[i].ID) {
2105                        if (i === index) {
2106                            this.product.slider = this.slider.controls[i];
2107                            this.slider.controls[i].CONT && BX.show(this.slider.controls[i].CONT);
2108                        } else {
2109                            this.slider.controls[i].CONT && BX.hide(this.slider.controls[i].CONT);
2110                        }
2111                    } else if (i === index) {
2112                        this.product.slider = {};
2113                    }
2114                }
2115
2116                if (this.offers[index].SLIDER_COUNT > 0) {
2117                    this.setMainPict(this.offers[index].ID, this.offers[index].SLIDER[0].ID, true);
2118                } else {
2119                    this.setMainPictFromItem(index);
2120                }
2121
2122                if (this.offers[index].SLIDER_COUNT > 1) {
2123                    this.initSlider();
2124                } else {
2125                    this.stopSlider();
2126                }
2127
2128                if (this.config.showSkuProps) {
2129                    if (this.obSkuProps) {
2130                        if (!this.offers[index].DISPLAY_PROPERTIES) {
2131                            BX.adjust(this.obSkuProps, {style: {display: 'none'}, html: ''});
2132                        } else {
2133                            BX.adjust(this.obSkuProps, {
2134                                style: {display: ''},
2135                                html:  this.offers[index].DISPLAY_PROPERTIES
2136                            });
2137                        }
2138                    }
2139
2140                    if (this.obMainSkuProps) {
2141                        if (!this.offers[index].DISPLAY_PROPERTIES_MAIN_BLOCK) {
2142                            BX.adjust(this.obMainSkuProps, {style: {display: 'none'}, html: ''});
2143                        } else {
2144                            BX.adjust(this.obMainSkuProps, {
2145                                style: {display: ''},
2146                                html:  this.offers[index].DISPLAY_PROPERTIES_MAIN_BLOCK
2147                            });
2148                        }
2149                    }
2150                }
2151
2152                this.quantitySet(index);
2153                this.setPrice();
2154                this.setCompared(this.offers[index].COMPARED);
2155
2156                this.offerNum = index;
2157                this.fixFontCheck();
2158                this.setAnalyticsDataLayer('showDetail');
2159                this.incViewedCounter();
2160
2161                eventData.newId = this.offers[this.offerNum].ID;
2162                // only for compatible catalog.store.amount custom templates
2163                BX.onCustomEvent('onCatalogStoreProductChange', [this.offers[this.offerNum].ID]);
2164                // new event
2165                BX.onCustomEvent('onCatalogElementChangeOffer', [eventData]);
2166                eventData = null;
2167            }
2168        },
2169
2170        drawImages: function(images) {
2171            if (!this.node.imageContainer)
2172                return;
2173
2174            var i, img, entities = this.getEntities(this.node.imageContainer, 'image');
2175            for (i in entities) {
2176                if (entities.hasOwnProperty(i) && BX.type.isDomNode(entities[i])) {
2177                    BX.remove(entities[i]);
2178                }
2179            }
2180
2181            for (i = 0; i < images.length; i++) {
2182                img = BX.create('IMG', {
2183                    props: {
2184                        src:   images[i].SRC,
2185                        alt:   this.config.alt,
2186                        title: this.config.title
2187                    }
2188                });
2189
2190                if (i == 0) {
2191                    img.setAttribute('itemprop', 'image');
2192                }
2193
2194                this.node.imageContainer.appendChild(
2195                    BX.create('DIV', {
2196                        attrs:    {
2197                            'data-entity': 'image',
2198                            'data-id':     images[i].ID
2199                        },
2200                        props:    {
2201                            className: 'product-item-detail-slider-image' + (i == 0 ? ' active' : '')
2202                        },
2203                        children: [img]
2204                    })
2205                );
2206            }
2207        },
2208
2209        restoreSticker: function() {
2210            if (this.previousStickerText) {
2211                this.redrawSticker({text: this.previousStickerText});
2212            } else {
2213                this.hideSticker();
2214            }
2215        },
2216
2217        hideSticker: function() {
2218            BX.hide(BX(this.visual.STICKER_ID));
2219        },
2220
2221        redrawSticker: function(stickerData) {
2222            stickerData = stickerData || {};
2223            var text    = stickerData.text || '';
2224
2225            var sticker = BX(this.visual.STICKER_ID);
2226            if (!sticker)
2227                return;
2228
2229            BX.show(sticker);
2230
2231            var previousStickerText = sticker.getAttribute('title');
2232            if (previousStickerText && previousStickerText != text) {
2233                this.previousStickerText = previousStickerText;
2234            }
2235
2236            BX.adjust(sticker, {text: text, attrs: {title: text}});
2237        },
2238
2239        checkQuantityRange: function(quantity, direction) {
2240            if (typeof quantity === 'undefined' || this.currentPriceMode !== 'Q') {
2241                return quantity;
2242            }
2243
2244            quantity = parseFloat(quantity);
2245
2246            var nearestQuantity = quantity;
2247            var range, diffFrom, absDiffFrom, diffTo, absDiffTo, shortestDiff;
2248
2249            for (var i in this.currentQuantityRanges) {
2250                if (this.currentQuantityRanges.hasOwnProperty(i)) {
2251                    range = this.currentQuantityRanges[i];
2252
2253                    if (
2254                        parseFloat(quantity) >= parseFloat(range.SORT_FROM)
2255                        && (
2256                            range.SORT_TO === 'INF'
2257                            || parseFloat(quantity) <= parseFloat(range.SORT_TO)
2258                        )
2259                    ) {
2260                        nearestQuantity = quantity;
2261                        break;
2262                    } else {
2263                        diffFrom    = parseFloat(range.SORT_FROM) - quantity;
2264                        absDiffFrom = Math.abs(diffFrom);
2265                        diffTo      = parseFloat(range.SORT_TO) - quantity;
2266                        absDiffTo   = Math.abs(diffTo);
2267
2268                        if (shortestDiff === undefined || shortestDiff > absDiffFrom) {
2269                            if (
2270                                direction === undefined
2271                                || (direction === 'up' && diffFrom > 0)
2272                                || (direction === 'down' && diffFrom < 0)
2273                            ) {
2274                                shortestDiff    = absDiffFrom;
2275                                nearestQuantity = parseFloat(range.SORT_FROM);
2276                            }
2277                        }
2278
2279                        if (shortestDiff === undefined || shortestDiff > absDiffTo) {
2280                            if (
2281                                direction === undefined
2282                                || (direction === 'up' && diffFrom > 0)
2283                                || (direction === 'down' && diffFrom < 0)
2284                            ) {
2285                                shortestDiff    = absDiffTo;
2286                                nearestQuantity = parseFloat(range.SORT_TO);
2287                            }
2288                        }
2289                    }
2290                }
2291            }
2292
2293            return nearestQuantity;
2294        },
2295
2296        checkPriceRange: function(quantity) {
2297            if (typeof quantity === 'undefined' || this.currentPriceMode !== 'Q') {
2298                return;
2299            }
2300
2301            var range, found = false;
2302
2303            for (var i in this.currentQuantityRanges) {
2304                if (this.currentQuantityRanges.hasOwnProperty(i)) {
2305                    range = this.currentQuantityRanges[i];
2306
2307                    if (
2308                        parseFloat(quantity) >= parseFloat(range.SORT_FROM)
2309                        && (
2310                            range.SORT_TO === 'INF'
2311                            || parseFloat(quantity) <= parseFloat(range.SORT_TO)
2312                        )
2313                    ) {
2314                        found                             = true;
2315                        this.currentQuantityRangeSelected = range.HASH;
2316                        break;
2317                    }
2318                }
2319            }
2320
2321            if (!found && (range = this.getMinPriceRange())) {
2322                this.currentQuantityRangeSelected = range.HASH;
2323            }
2324
2325            for (var k in this.currentPrices) {
2326                if (this.currentPrices.hasOwnProperty(k)) {
2327                    if (this.currentPrices[k].QUANTITY_HASH == this.currentQuantityRangeSelected) {
2328                        this.currentPriceSelected = k;
2329                        break;
2330                    }
2331                }
2332            }
2333        },
2334
2335        getMinPriceRange: function() {
2336            var range;
2337
2338            for (var i in this.currentQuantityRanges) {
2339                if (this.currentQuantityRanges.hasOwnProperty(i)) {
2340                    if (
2341                        !range
2342                        || parseInt(this.currentQuantityRanges[i].SORT_FROM) < parseInt(range.SORT_FROM)
2343                    ) {
2344                        range = this.currentQuantityRanges[i];
2345                    }
2346                }
2347            }
2348
2349            return range;
2350        },
2351
2352        checkQuantityControls: function() {
2353            if (!this.obQuantity)
2354                return;
2355
2356            var reachedTopLimit    = this.checkQuantity && parseFloat(this.obQuantity.value) + this.stepQuantity > this.maxQuantity,
2357                reachedBottomLimit = parseFloat(this.obQuantity.value) - this.stepQuantity < this.minQuantity;
2358
2359            if (reachedTopLimit) {
2360                BX.addClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled');
2361            } else if (BX.hasClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled')) {
2362                BX.removeClass(this.obQuantityUp, 'product-item-amount-field-btn-disabled');
2363            }
2364
2365            if (reachedBottomLimit) {
2366                BX.addClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled');
2367            } else if (BX.hasClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled')) {
2368                BX.removeClass(this.obQuantityDown, 'product-item-amount-field-btn-disabled');
2369            }
2370
2371            if (reachedTopLimit && reachedBottomLimit) {
2372                this.obQuantity.setAttribute('disabled', 'disabled');
2373            } else {
2374                this.obQuantity.removeAttribute('disabled');
2375            }
2376        },
2377
2378        setPrice: function() {
2379            var economyInfo = '', price;
2380
2381            if (this.obQuantity) {
2382                this.checkPriceRange(this.obQuantity.value);
2383            }
2384
2385            this.checkQuantityControls();
2386
2387            price = this.currentPrices[this.currentPriceSelected];
2388
2389            if (this.isGift) {
2390                price.PRICE    = 0;
2391                price.DISCOUNT = price.BASE_PRICE;
2392                price.PERCENT  = 100;
2393            }
2394
2395            if (this.obPrice.price) {
2396                if (price) {
2397                    BX.adjust(this.obPrice.price, {html: BX.Currency.currencyFormat(price.RATIO_PRICE, price.CURRENCY, true)});
2398                    this.smallCardNodes.price && BX.adjust(this.smallCardNodes.price, {
2399                        html: BX.Currency.currencyFormat(price.RATIO_PRICE, price.CURRENCY, true)
2400                    });
2401                } else {
2402                    BX.adjust(this.obPrice.price, {html: ''});
2403                    this.smallCardNodes.price && BX.adjust(this.smallCardNodes.price, {html: ''});
2404                }
2405
2406                if (price && price.RATIO_PRICE !== price.RATIO_BASE_PRICE) {
2407                    if (this.config.showOldPrice) {
2408                        this.obPrice.full && BX.adjust(this.obPrice.full, {
2409                            style: {display: ''},
2410                            html:  BX.Currency.currencyFormat(price.RATIO_BASE_PRICE, price.CURRENCY, true)
2411                        });
2412                        this.smallCardNodes.oldPrice && BX.adjust(this.smallCardNodes.oldPrice, {
2413                            style: {display: ''},
2414                            html:  BX.Currency.currencyFormat(price.RATIO_BASE_PRICE, price.CURRENCY, true)
2415                        });
2416
2417                        if (this.obPrice.discount) {
2418                            economyInfo = BX.message('ECONOMY_INFO_MESSAGE');
2419                            economyInfo = economyInfo.replace('#ECONOMY#', BX.Currency.currencyFormat(price.RATIO_DISCOUNT, price.CURRENCY, true));
2420                            BX.adjust(this.obPrice.discount, {style: {display: ''}, html: economyInfo});
2421                        }
2422                    }
2423
2424                    if (this.config.showPercent) {
2425                        this.obPrice.percent && BX.adjust(this.obPrice.percent, {
2426                            style: {display: ''},
2427                            html:  -price.PERCENT + '%'
2428                        });
2429                    }
2430                } else {
2431                    if (this.config.showOldPrice) {
2432                        this.obPrice.full && BX.adjust(this.obPrice.full, {style: {display: 'none'}, html: ''});
2433                        this.smallCardNodes.oldPrice && BX.adjust(this.smallCardNodes.oldPrice, {
2434                            style: {display: 'none'},
2435                            html:  ''
2436                        });
2437                        this.obPrice.discount && BX.adjust(this.obPrice.discount, {style: {display: 'none'}, html: ''});
2438                    }
2439
2440                    if (this.config.showPercent) {
2441                        this.obPrice.percent && BX.adjust(this.obPrice.percent, {style: {display: 'none'}, html: ''});
2442                    }
2443                }
2444
2445                if (this.obPrice.total) {
2446                    if (price && this.obQuantity && this.obQuantity.value != this.stepQuantity) {
2447                        BX.adjust(this.obPrice.total, {
2448                            html:  BX.message('PRICE_TOTAL_PREFIX') + ' <strong>'
2449                                       + BX.Currency.currencyFormat(price.PRICE * this.obQuantity.value, price.CURRENCY, true)
2450                                       + '</strong>',
2451                            style: {display: ''}
2452                        });
2453                    } else {
2454                        BX.adjust(this.obPrice.total, {
2455                            html:  '',
2456                            style: {display: 'none'}
2457                        });
2458                    }
2459                }
2460            }
2461        },
2462
2463        compare: function(event) {
2464            var checkbox = this.obCompare.querySelector('[data-entity="compare-checkbox"]'),
2465                target   = BX.getEventTarget(event),
2466                checked  = true;
2467
2468            if (checkbox) {
2469                checked = target === checkbox ? checkbox.checked : !checkbox.checked;
2470            }
2471
2472            var url = checked ? this.compareData.compareUrl : this.compareData.compareDeleteUrl,
2473                compareLink;
2474
2475            if (url) {
2476                if (target !== checkbox) {
2477                    BX.PreventDefault(event);
2478                    this.setCompared(checked);
2479                }
2480
2481                switch (this.productType) {
2482                    case 0: // no catalog
2483                    case 1: // product
2484                    case 2: // set
2485                        compareLink = url.replace('#ID#', this.product.id.toString());
2486                        break;
2487                    case 3: // sku
2488                        compareLink = url.replace('#ID#', this.offers[this.offerNum].ID);
2489                        break;
2490                }
2491
2492                BX.ajax({
2493                    method:    'POST',
2494                    dataType:  checked ? 'json' : 'html',
2495                    url:       compareLink + (compareLink.indexOf('?') !== -1 ? '&' : '?') + 'ajax_action=Y',
2496                    onsuccess: checked
2497                                   ? BX.proxy(this.compareResult, this)
2498                                   : BX.proxy(this.compareDeleteResult, this)
2499                });
2500            }
2501        },
2502
2503        compareResult: function(result) {
2504            var popupContent, popupButtons;
2505
2506            if (this.obPopupWin) {
2507                this.obPopupWin.close();
2508            }
2509
2510            if (!BX.type.isPlainObject(result))
2511                return;
2512
2513            this.initPopupWindow();
2514
2515            if (this.offers.length > 0) {
2516                this.offers[this.offerNum].COMPARED = result.STATUS === 'OK';
2517            }
2518
2519            if (result.STATUS === 'OK') {
2520                BX.onCustomEvent('OnCompareChange');
2521
2522                popupContent = '<div style="width: 100%; margin: 0; text-align: center;"><p>'
2523                    + BX.message('COMPARE_MESSAGE_OK')
2524                    + '</p></div>';
2525
2526                if (this.config.showClosePopup) {
2527                    popupButtons = [
2528                        new BasketButton({
2529                            text:   BX.message('BTN_MESSAGE_COMPARE_REDIRECT'),
2530                            events: {
2531                                click: BX.delegate(this.compareRedirect, this)
2532                            },
2533                            style:  {marginRight: '10px'}
2534                        }),
2535                        new BasketButton({
2536                            text:   BX.message('BTN_MESSAGE_CLOSE_POPUP'),
2537                            events: {
2538                                click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
2539                            }
2540                        })
2541                    ];
2542                } else {
2543                    popupButtons = [
2544                        new BasketButton({
2545                            text:   BX.message('BTN_MESSAGE_COMPARE_REDIRECT'),
2546                            events: {
2547                                click: BX.delegate(this.compareRedirect, this)
2548                            }
2549                        })
2550                    ];
2551                }
2552            } else {
2553                popupContent = '<div style="width: 100%; margin: 0; text-align: center;"><p>'
2554                    + (result.MESSAGE ? result.MESSAGE : BX.message('COMPARE_UNKNOWN_ERROR'))
2555                    + '</p></div>';
2556                popupButtons = [
2557                    new BasketButton({
2558                        text:   BX.message('BTN_MESSAGE_CLOSE'),
2559                        events: {
2560                            click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
2561                        }
2562                    })
2563                ];
2564            }
2565
2566            this.obPopupWin.setTitleBar(BX.message('COMPARE_TITLE'));
2567            this.obPopupWin.setContent(popupContent);
2568            this.obPopupWin.setButtons(popupButtons);
2569            this.obPopupWin.show();
2570        },
2571
2572        compareDeleteResult: function() {
2573            BX.onCustomEvent('OnCompareChange');
2574
2575            if (this.offers && this.offers.length) {
2576                this.offers[this.offerNum].COMPARED = false;
2577            }
2578        },
2579
2580        setCompared: function(state) {
2581            if (!this.obCompare)
2582                return;
2583
2584            var checkbox = this.getEntity(this.obCompare, 'compare-checkbox');
2585            if (checkbox) {
2586                checkbox.checked = state;
2587            }
2588        },
2589
2590        setCompareInfo: function(comparedIds) {
2591            if (!BX.type.isArray(comparedIds))
2592                return;
2593
2594            for (var i in this.offers) {
2595                if (this.offers.hasOwnProperty(i)) {
2596                    this.offers[i].COMPARED = BX.util.in_array(this.offers[i].ID, comparedIds);
2597                }
2598            }
2599        },
2600
2601        compareRedirect: function() {
2602            if (this.compareData.comparePath) {
2603                location.href = this.compareData.comparePath;
2604            } else {
2605                this.obPopupWin.close();
2606            }
2607        },
2608
2609        checkDeletedCompare: function(id) {
2610            switch (this.productType) {
2611                case 0: // no catalog
2612                case 1: // product
2613                case 2: // set
2614                    if (this.product.id == id) {
2615                        this.setCompared(false);
2616                    }
2617
2618                    break;
2619                case 3: // sku
2620                    var i = this.offers.length;
2621                    while (i--) {
2622                        if (this.offers[i].ID == id) {
2623                            this.offers[i].COMPARED = false;
2624
2625                            if (this.offerNum == i) {
2626                                this.setCompared(false);
2627                            }
2628
2629                            break;
2630                        }
2631                    }
2632            }
2633        },
2634
2635        initBasketUrl: function() {
2636            this.basketUrl = (this.basketMode === 'ADD' ? this.basketData.add_url : this.basketData.buy_url);
2637
2638            switch (this.productType) {
2639                case 1: // product
2640                case 2: // set
2641                    this.basketUrl = this.basketUrl.replace('#ID#', this.product.id.toString());
2642                    break;
2643                case 3: // sku
2644                    this.basketUrl = this.basketUrl.replace('#ID#', this.offers[this.offerNum].ID);
2645                    break;
2646            }
2647
2648            this.basketParams = {
2649                'ajax_basket': 'Y'
2650            };
2651
2652            if (this.config.showQuantity) {
2653                this.basketParams[this.basketData.quantity] = this.obQuantity.value;
2654            }
2655
2656            if (this.basketData.sku_props) {
2657                this.basketParams[this.basketData.sku_props_var] = this.basketData.sku_props;
2658            }
2659        },
2660
2661        fillBasketProps: function() {
2662            if (!this.visual.BASKET_PROP_DIV)
2663                return;
2664
2665            var
2666                i              = 0,
2667                propCollection = null,
2668                foundValues    = false,
2669                obBasketProps  = null;
2670
2671            if (this.basketData.useProps && !this.basketData.emptyProps) {
2672                if (this.obPopupWin && this.obPopupWin.contentContainer) {
2673                    obBasketProps = this.obPopupWin.contentContainer;
2674                }
2675            } else {
2676                obBasketProps = BX(this.visual.BASKET_PROP_DIV);
2677            }
2678
2679            if (obBasketProps) {
2680                propCollection = obBasketProps.getElementsByTagName('select');
2681                if (propCollection && propCollection.length) {
2682                    for (i = 0; i < propCollection.length; i++) {
2683                        if (!propCollection[i].disabled) {
2684                            switch (propCollection[i].type.toLowerCase()) {
2685                                case 'select-one':
2686                                    this.basketParams[propCollection[i].name] = propCollection[i].value;
2687                                    foundValues                               = true;
2688                                    break;
2689                                default:
2690                                    break;
2691                            }
2692                        }
2693                    }
2694                }
2695
2696                propCollection = obBasketProps.getElementsByTagName('input');
2697                if (propCollection && propCollection.length) {
2698                    for (i = 0; i < propCollection.length; i++) {
2699                        if (!propCollection[i].disabled) {
2700                            switch (propCollection[i].type.toLowerCase()) {
2701                                case 'hidden':
2702                                    this.basketParams[propCollection[i].name] = propCollection[i].value;
2703                                    foundValues                               = true;
2704                                    break;
2705                                case 'radio':
2706                                    if (propCollection[i].checked) {
2707                                        this.basketParams[propCollection[i].name] = propCollection[i].value;
2708                                        foundValues                               = true;
2709                                    }
2710                                    break;
2711                                default:
2712                                    break;
2713                            }
2714                        }
2715                    }
2716                }
2717            }
2718
2719            if (!foundValues) {
2720                this.basketParams[this.basketData.props]    = [];
2721                this.basketParams[this.basketData.props][0] = 0;
2722            }
2723        },
2724
2725        sendToBasket: function() {
2726            if (!this.canBuy)
2727                return;
2728
2729            this.initBasketUrl();
2730            this.fillBasketProps();
2731            BX.ajax({
2732                method:    'POST',
2733                dataType:  'json',
2734                url:       this.basketUrl,
2735                data:      this.basketParams,
2736                onsuccess: BX.proxy(this.basketResult, this)
2737            });
2738        },
2739
2740        add2Basket: function() {
2741            this.basketMode = 'ADD';
2742            this.basket();
2743        },
2744
2745        buyBasket: function() {
2746            this.basketMode = 'BUY';
2747            this.basket();
2748        },
2749
2750        basket: function() {
2751            var contentBasketProps = '';
2752
2753            if (!this.canBuy)
2754                return;
2755
2756            switch (this.productType) {
2757                case 1: // product
2758                case 2: // set
2759                    if (this.basketData.useProps && !this.basketData.emptyProps) {
2760                        this.initPopupWindow();
2761                        this.obPopupWin.setTitleBar(BX.message('TITLE_BASKET_PROPS'));
2762
2763                        if (BX(this.visual.BASKET_PROP_DIV)) {
2764                            contentBasketProps = BX(this.visual.BASKET_PROP_DIV).innerHTML;
2765                        }
2766
2767                        this.obPopupWin.setContent(contentBasketProps);
2768                        this.obPopupWin.setButtons([
2769                            new BasketButton({
2770                                text:   BX.message('BTN_SEND_PROPS'),
2771                                events: {
2772                                    click: BX.delegate(this.sendToBasket, this)
2773                                }
2774                            })
2775                        ]);
2776                        this.obPopupWin.show();
2777                    } else {
2778                        this.sendToBasket();
2779                    }
2780                    break;
2781                case 3: // sku
2782                    this.sendToBasket();
2783                    break;
2784            }
2785        },
2786
2787        basketResult: function(arResult) {
2788            var popupContent, popupButtons, productPict;
2789
2790            if (this.obPopupWin) {
2791                this.obPopupWin.close();
2792            }
2793
2794            if (!BX.type.isPlainObject(arResult))
2795                return;
2796
2797            if (arResult.STATUS === 'OK') {
2798                this.setAnalyticsDataLayer('addToCart');
2799            }
2800
2801            if (arResult.STATUS === 'OK' && this.basketMode === 'BUY') {
2802                this.basketRedirect();
2803            } else {
2804                this.initPopupWindow();
2805
2806                if (arResult.STATUS === 'OK') {
2807                    BX.onCustomEvent('OnBasketChange');
2808                    switch (this.productType) {
2809                        case 1: // product
2810                        case 2: // set
2811                            productPict = this.product.pict.SRC;
2812                            break;
2813                        case 3: // sku
2814                            productPict = this.offers[this.offerNum].PREVIEW_PICTURE
2815                                ? this.offers[this.offerNum].PREVIEW_PICTURE.SRC
2816                                : this.defaultPict.pict.SRC;
2817                            break;
2818                    }
2819
2820                    popupContent = '<div style="width: 100%; margin: 0; text-align: center;">'
2821                        + '<img src="' + productPict + '" height="130" style="max-height:130px"><p>'
2822                        + this.product.name + '</p></div>';
2823
2824                    if (this.config.showClosePopup) {
2825                        popupButtons = [
2826                            new BasketButton({
2827                                text:   BX.message('BTN_MESSAGE_BASKET_REDIRECT'),
2828                                events: {
2829                                    click: BX.delegate(this.basketRedirect, this)
2830                                },
2831                                style:  {marginRight: '10px'}
2832                            }),
2833                            new BasketButton({
2834                                text:   BX.message('BTN_MESSAGE_CLOSE_POPUP'),
2835                                events: {
2836                                    click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
2837                                }
2838                            })
2839                        ];
2840                    } else {
2841                        popupButtons = [
2842                            new BasketButton({
2843                                text:   BX.message('BTN_MESSAGE_BASKET_REDIRECT'),
2844                                events: {
2845                                    click: BX.delegate(this.basketRedirect, this)
2846                                }
2847                            })
2848                        ];
2849                    }
2850                } else {
2851                    popupContent = '<div style="width: 100%; margin: 0; text-align: center;"><p>'
2852                        + (arResult.MESSAGE ? arResult.MESSAGE : BX.message('BASKET_UNKNOWN_ERROR'))
2853                        + '</p></div>';
2854                    popupButtons = [
2855                        new BasketButton({
2856                            text:   BX.message('BTN_MESSAGE_CLOSE'),
2857                            events: {
2858                                click: BX.delegate(this.obPopupWin.close, this.obPopupWin)
2859                            }
2860                        })
2861                    ];
2862                }
2863
2864                this.obPopupWin.setTitleBar(arResult.STATUS === 'OK' ? BX.message('TITLE_SUCCESSFUL') : BX.message('TITLE_ERROR'));
2865                this.obPopupWin.setContent(popupContent);
2866                this.obPopupWin.setButtons(popupButtons);
2867                this.obPopupWin.show();
2868            }
2869        },
2870
2871        basketRedirect: function() {
2872            location.href = (this.basketData.basketUrl ? this.basketData.basketUrl : BX.message('BASKET_URL'));
2873        },
2874
2875        initPopupWindow: function() {
2876            if (this.obPopupWin)
2877                return;
2878
2879            this.obPopupWin = BX.PopupWindowManager.create('CatalogElementBasket_' + this.visual.ID, null, {
2880                autoHide:     false,
2881                offsetLeft:   0,
2882                offsetTop:    0,
2883                overlay:      true,
2884                closeByEsc:   true,
2885                titleBar:     true,
2886                closeIcon:    true,
2887                contentColor: 'white',
2888                className:    this.config.templateTheme ? 'bx-' + this.config.templateTheme : ''
2889            });
2890        },
2891
2892        incViewedCounter: function() {
2893            if (this.currentIsSet && !this.updateViewedCount) {
2894                switch (this.productType) {
2895                    case 1:
2896                    case 2:
2897                        this.viewedCounter.params.PRODUCT_ID = this.product.id;
2898                        this.viewedCounter.params.PARENT_ID  = this.product.id;
2899                        break;
2900                    case 3:
2901                        this.viewedCounter.params.PARENT_ID  = this.product.id;
2902                        this.viewedCounter.params.PRODUCT_ID = this.offers[this.offerNum].ID;
2903                        break;
2904                    default:
2905                        return;
2906                }
2907
2908                this.viewedCounter.params.SITE_ID = BX.message('SITE_ID');
2909                this.updateViewedCount            = true;
2910                BX.ajax.post(
2911                    this.viewedCounter.path,
2912                    this.viewedCounter.params,
2913                    BX.delegate(function() {
2914                        this.updateViewedCount = false;
2915                    }, this)
2916                );
2917            }
2918        },
2919
2920        allowViewedCount: function(update) {
2921            this.currentIsSet = true;
2922
2923            if (update) {
2924                this.incViewedCounter();
2925            }
2926        },
2927
2928        fixFontCheck: function() {
2929            if (BX.type.isDomNode(this.obPrice.price)) {
2930                BX.FixFontSize && BX.FixFontSize.init({
2931                    objList:          [{
2932                        node:          this.obPrice.price,
2933                        maxFontSize:   28,
2934                        smallestValue: false,
2935                        scaleBy:       this.obPrice.price.parentNode
2936                    }],
2937                    onAdaptiveResize: true
2938                });
2939
2940            }
2941        }
2942    }
2943})(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.