PageSourceSearch

https://solarscouts.de/templates/NIUplus/js/jtl.article.js?v=4.10.6

js solarscouts.de collected 2026-10-04 04:37:26 UTC 76,710 bytes, 1,797 lines download raw bytes

1(function($, document, window, viewport){
2    'use strict';
3
4    var _stock_info = ['out-of-stock', 'in-short-supply', 'in-stock'],
5        $v,
6        ArticleClass = function () {
7            this.init();
8        };
9
10    ArticleClass.DEFAULTS = {
11        input: {
12            id: 'a',
13            childId: 'VariKindArtikel',
14            quantity: 'anzahl'
15        },
16        action: {
17            compareList: 'Vergleichsliste',
18            compareListRemove: 'Vergleichsliste.remove',
19            wishList: 'Wunschliste',
20            wishListRemove: 'Wunschliste.remove'
21        },
22        selector: {
23            navUpdateCompare: '#comparelist-dropdown-content',
24            navBadgeUpdateCompare: '#comparelist-badge',
25            navCompare: '#shop-nav-compare',
26            navContainerWish: '#wishlist-dropdown-container',
27            navBadgeWish: '#badge-wl-count',
28            navBadgeAppend: '#shop-nav li.cart-menu',
29            boxContainer: '#sidebox',
30            boxContainerWish: '#sidebox',
31            quantity: 'input.quantity'
32        },
33        modal: {
34            id: 'modal-article-dialog',
35            wrapper: '#result-wrapper',
36            wrapper_modal: '#result-wrapper-modal'
37        }
38    };
39
40    ArticleClass.prototype = {
41        modalShown: false,
42        modalView: null,
43
44        constructor: ArticleClass,
45
46        init: function () {
47            this.options = ArticleClass.DEFAULTS;
48            this.gallery = null;
49        },
50
51        onLoad: function() {
52            if (this.isSingleArticle()) {
53                var that = this;
54                var form = $.evo.io().getFormValues('buy_form');
55
56                if (typeof history.replaceState === 'function') {
57                    history.replaceState({
58                        a: form.a,
59                        a2: form.VariKindArtikel || form.a,
60                        url: document.location.href,
61                        variations: {}
62                    }, document.title, document.location.href);
63                }
64
65                window.addEventListener('popstate', function (event) {
66                    if (event.state) {
67                        that.setArticleContent(event.state.a, event.state.a2, event.state.url, event.state.variations);
68                    }
69                }, false);
70            }
71        },
72
73        isSingleArticle: function() {
74            return $('#buy_form').length > 0;
75        },
76
77        getWrapper: function(wrapper) {
78            return typeof wrapper === 'undefined' ? $(this.options.modal.wrapper) : $(wrapper);
79        },
80
81        getCurrent: function($item) {
82            if ($item.hasClass('variation')) {
83                return $item;
84            }
85            let $current = $item.closest('.variation');
86            let $checked = $item.find('input:checked');
87            if ($checked.parent().hasClass('variation')) {
88                //swatch and textbox
89                $current = $checked.parent();
90            } else if ($checked.next().hasClass('variation')) {
91                //radio
92                $current = $checked.next();
93            } else if ($item.find('option:selected').hasClass('variation')) {
94                //select
95                $current = $item.find('option:selected');
96            } else if ($current.length === 0) {
97                $current = $item.next('.variation');
98            }
99
100            return $current;
101        },
102
103        incrementProductVisitCount: function() {
104            console.log('This function is deprecated since JTL Shop 5.4.0');
105        },
106
107        navigateBackToList: function() {
108            console.log('This function is deprecated since JTL Shop 5.4.0');
109        },
110
111        register: function(wrapper) {
112            var $wrapper = this.getWrapper(wrapper);
113
114            if (this.isSingleArticle()) {
115                this.registerGallery($wrapper);
116                this.registerConfig();
117                this.registerHoverVariations($wrapper);
118            }
119
120            this.registerSimpleVariations($wrapper);
121            this.registerSwitchVariations($wrapper);
122            this.registerBulkPrices($wrapper);
123            this.registerAccordion();
124            // this.registerImageSwitch($wrapper);
125            this.registerArticleOverlay($wrapper);
126            this.registerImageHover($wrapper);
127            this.registerFinish($wrapper);
128            window.initNumberInput();
129            this.initAbnahmeIntervallError();
130            this.setClickableProductbox();
131        },
132
133        setClickableProductbox: function() {
134            $('.productbox[tabindex="0"]').on('keydown', function(e) {
135                // on Enter or Space
136                if (e.keyCode === 13 || e.keyCode === 32) {
137                    e.preventDefault();
138                    $(this).find('a')[0].click();
139                }
140            });
141        },
142
143        registerAccordion: function() {
144            $('.is-mobile .accordion [id^="tab-"]').on('shown.bs.collapse', function () {
145                let self = $(this);
146                $.evo.destroyScrollSearchEvent();
147                setTimeout(function() {
148                    $('html').animate(
149                        {scrollTop: self.offset().top-40},
150                        100,
151                        'linear',
152                        function () {
153                            setTimeout(function() {
154                                $.evo.initScrollSearchEvent();
155                            }, 500);
156                        });
157                }, 400);
158            });
159        },
160
161        registerArticleOverlay: function($wrapper) {
162            var that         = this;
163
164            $('.configpreview', $wrapper)
165                .each(function(i, item) {
166                    let $item   = $(item);
167                    let wrapper = that.options.modal.wrapper_modal + '_modal';
168
169                    $item.on('click', function (event) {
170                        event.preventDefault();
171                        that.modalArticleDetail(this, wrapper);
172                    });
173                });
174            $wrapper.hover(null, function() {
175                $(this).removeClass('active');
176            })
177        },
178
179        registerGallery: function(wrapper) {
180            /*
181             * product slider and zoom (details)
182             */
183            function slickinit()
184            {
185                $('.initial-slick-dots').on('click', function () {
186                    let mainNode = $('#gallery');
187                    mainNode.removeClass('slick-lazy');
188                    $.evo.extended().initSlick(mainNode, mainNode.data('slick-type'));
189                    if(mainNode.slick('getSlick').slideCount > mainNode.slick('slickGetOption', 'slidesToShow')) {
190                        mainNode.slick('slickGoTo', 1);
191                    }
192                });
193            }
194
195            function toggleFullscreen(fullscreen = false)
196            {
197                let $imgWrapper = $('#image_wrapper'),
198                    $gallery    = $('#gallery');
199                if (!$gallery.hasClass('slick-initialized') || (fullscreen && $imgWrapper.hasClass('fullscreen'))){
200                    return;
201                }
202
203                let maxHeight       = Math.max(document.documentElement.clientHeight, window.innerHeight || 0
203),
204                    otherElemHeight = 0,
205                    current         = ($('#gallery .slick-current').data('slick-index')),
206                    $galleryImages  = $('#gallery img, #gallery picture source'),
207                    hidePreview     = maxHeight < 700,
208                    previewHeight   = $('#gallery_preview_wrapper').length > 0 && !hidePreview ? 170 : 30,
209                    $previewBar     = $('.product-detail-image-preview-bar');
210
211                if (fullscreen) {
212                    $imgWrapper.addClass('fullscreen');
213                    let $galleryTopbar = $('#image_wrapper .product-detail-image-topbar');
214
215                    otherElemHeight = $galleryTopbar.outerHeight()
216                        + 2*parseInt($imgWrapper.css('paddingTop'))
217                        + previewHeight;
218
219                    $galleryImages.removeAttr('sizes');
220                    // lazySizes.autoSizer.updateElem($galleryImages);
221
222                    if (hidePreview) {
223                        $previewBar.addClass('d-none');
224                    }
225
226                    $galleryImages.css('max-height', maxHeight-otherElemHeight);
227                    $gallery.css('max-height', maxHeight-otherElemHeight);
228
229                    $('body').off('click.toggleFullscreen').on('click.toggleFullscreen', function (event) {
230                        if (!($(event.target).hasClass('product-image') || $(event.target).hasClass('slick-arrow'))) {
231                            toggleFullscreen(false);
232                            $('body').off('click.toggleFullscreen');
233                        }
234                    });
235                } else {
236                    $imgWrapper.removeClass('fullscreen');
237                    $galleryImages.css('max-height', '100%');
238                    $gallery.css('max-height', '100%');
239                    $previewBar.removeClass('d-none');
240                }
241
242                $gallery.slick('slickSetOption','initialSlide', current, true);
243                $('#gallery_preview').slick('slickGoTo', current, true);
244
245                //fix firefox height bug
246                $('.slick-slide, .slick-arrow').css({'display': 'none'});
247                setTimeout(function(){
248                    $('.slick-slide, .slick-arrow').css({'display': 'block'});
249                }, 50);
250            }
251
252            function addClickListener() {
253                $('#gallery img').off('click').on('click', e => {
254                    if (window.innerWidth > globals.breakpoints.lg) {
255                        toggleFullscreen(true);
256                    }
257                });
258            }
259
260            slickinit();
261
262            if (wrapper[0].id.indexOf(this.options.modal.wrapper_modal.slice(1)) === -1) {
263                addClickListener();
264
265                $(document).on('keyup', e => {
266                    if (e.key === "Escape" && $('#image_wrapper').hasClass('fullscreen')) {
267                        toggleFullscreen();
268                        addClickListener();
269                    }
270                });
271            }
272        },
273
274        registerConfig: function() {
275            var that   = this,
276                config = $('#product-configurator')
277                    .closest('form')
278                    .find('input[type="radio"], input[type="text"], input[type="checkbox"], input[type="number"], select'),
279                dropdown = $('#product-configurator')
280                    .closest('form')
281                    .find('select');
282            let offset = $('#jtl-nav-wrapper').height();
283
284            if (dropdown.length > 0) {
285                dropdown.on('change', function () {
286                    var item = $(this).val();
287                    $(this).parents('.cfg-group').find('.cfg-drpdwn-item.collapse.show').collapse('hide');
288                    $('#drpdwn_qnt_' + item).collapse('show');
289                })
290            }
291
292            if (config.length > 0) {
293                config.on('change', function() {
294                    that.configurator();
295                })
296                    .on('keypress', function (e) {
297                        if (e.key === 'Enter') {
298                            return false;
299                        }
300                    });
301                // timeout fixes problem with loading order of bootstrap dropdowns
302                setTimeout(function(){
303                    that.configurator(true);
304                },0);
305            }
306
307            function scroll (selector) {
308                $(selector).bind('click', function(event) {
309                    event.preventDefault();
310                    let anchor = $(this).attr('href');
311                    $('html, body').stop().animate({
312                        scrollTop: $(anchor).offset().top - offset - 15
313                    });
314                });
315            }
316            scroll('a[href="#cfg-container"]');
317
318
319            $('#cfg-nav nav a').on('click', function() {
320                $('html, body').animate({
321                    scrollTop: $('#cfg-container').offset().top - offset - 15
322                });
323                let anchor = $(this).attr('href'),
324                    elOffset = $(anchor)[0].offsetTop;
325                $('#cfg-container .cfg-options').stop().animate({
326                    scrollTop: elOffset
327                });
328            });
329
330            $(document).on('scroll', function (e) {
331                let headerHeight = $('#jtl-nav-wrapper').outerHeight() + 10;
332                $('.cfg-position-details.cfg-layout-list #product-configuration-sidebar, ' +
333                    '.cfg-position-details.cfg-layout-list .cfg-group .cfg-group-info').css('top', headerHeight + 'px');
334            });
335        },
336
337        registerSimpleVariations: function($wrapper) {
338            var that = this;
339
340            $('.variations select', $wrapper).selectpicker({
341                iconBase: 'fa',
342                tickIcon: 'fa-check',
343                hideDisabled: true,
344                showTick: true
345            });
346
347            $('.simple-variations input[type="radio"]', $wrapper)
348                .on('change', function() {
349                    var val = $(this).val(),
350                        key = $(this).parent().data('key');
351                    $('.simple-variations [data-key="' + key + '"]').removeClass('active');
352                    $('.simple-variations [data-value="' + val + '"]').addClass('active');
353                    $(this).closest(".swatches").addClass("radio-selected");
354                });
355
356            $('.simple-variations input[type="radio"], .simple-variations select', $wrapper)
357                .each(function(i, item) {
358                    var $item   = $(item),
359                        wrapper = '#' + $item.closest('form').closest('div[data-wrapper="true"]').attr('id');
360
361                    $item.on('change', function () {
362                        that.variationPrice($(this), true, wrapper);
363                    });
364                });
365            $('.simple-variations input[type="text"]', $wrapper)
366                .each(function(i, item) {
367                    let $item   = $(item),
368                        wrapper = '#' + $item.closest('form').closest('div[data-wrapper="true"]').attr('id'),
369                        timeout = null;
370                    $item.on('keyup', function (e) {
371                        clearTimeout(timeout);
372                        let self = $(this);
373
374                        timeout = setTimeout(function () {
375                            that.variationPrice(self, true, wrapper);
376                        }, 500);
377                    });
378                });
379        },
380
381        registerBulkPrices: function($wrapper) {
382            var $bulkPrice = $('.bulk-price', $wrapper),
383                that       = this,
384                $config    = $('#product-configurator');
385
386            if (($bulkPrice.length > 0 && $config.length === 0) || $('#product-list').length > 0) {
387                $('#quantity, [data-bulk="1"] .quantity', $wrapper)
388                    .each(function(i, item) {
389                        let $item   = $(item),
390                            wrapper = '#' + $item.closest('form').closest('div[data-wrapper="true"]').attr('id');
391
392                        $item.on('change', function () {
393                            that.variationPrice($(this), true, wrapper);
394                        });
395                        that.variationPrice($(this), true, wrapper);
396                    });
397            }
398        },
399
400        registerSwitchVariations: function($wrapper) {
401            var that = this;
402
403            $('.switch-variations input[type="radio"], .switch-variations select', $wrapper)
404                .each(function(i, item) {
405                    var $item   = $(item),
406                        /* niu switched*/
407                        /*wrapper = '#' + $item.closest('form').closest('div[id]').attr('id');*/
408                        wrapper = '#' + $item.closest('form').closest('div[data-wrapper="true"]').attr('id');
409
410                    $item.on('change', function () {
411                        that.variationSwitch($(this), false, wrapper);
412                    });
413                });
414
415            if (isTouchCapable()) {
416                $('.variations .swatches .variation', $wrapper)
417                    .on('mouseover', function() {
418                        $(this).trigger('click');
419                    });
420            }
421
422            // ie11 fallback
423            if (typeof document.body.style.msTransform === 'string') {
424                $('.variations label.variation', $wrapper)
425                    .on('click', function (e) {
426                        if (e.target.tagName === 'IMG') {
427                            $(this).trigger('click');
428                        }
429                    });
430            }
431        },
432
433        registerHoverVariations: function ($wrapper) {
434            let delay=300, setTimeoutConst;
435            $('.variations label.variation', $wrapper)
436                .on('mouseenter', function (e) {
437                    setTimeoutConst = setTimeout(function () {
438                        let $mainImage = $('[data-niu-lightbox-trigger]')
439                        let mainImageHeight = $mainImage.innerHe
439ight();
440                        let mainImageWidth = ($mainImage.innerWidth() || 593) + 'px';
441                        let target = $('.variation-image-preview.vt' + $(e.currentTarget).data('value'))
442                        let content = $('#content')
443                        target.addClass('show d-md-block')
444                        /*target.css('top', $(e.currentTarget).offset().top - $(e.currentTarget).closest('#content').position().top - mainImageHeight / 2 - 12);*/
445                        /*target.css('top', $(e.currentTarget).offset().top - $(e.currentTarget).closest('#content').position().top - mainImageHeight / 2 - 12);*/
446                        if($mainImage.offset().top - target.offset().top > 1){
447
448                        target.css('top', $mainImage.offset().top - target.offset().top + 'px');
449                        }
450                        target.css('width',mainImageWidth)
451                    }, delay)
452                })
453                .on('mouseleave', function (e) {
454                    clearTimeout(setTimeoutConst);
455                    $('.variation-image-preview.vt' + $(this).data('value')).removeClass('show d-md-block');
456                });
457
458            $('.variations .selectpicker')
459                .on('show.bs.select', function () {
460                    let selectPicker = $(this);
461                    $(this).parent().find('li .variation')
462                        .on('mouseenter', function (e) {
463                            setTimeoutConst = setTimeout(function () {
464                                let mainImageHeight = $('.js-gallery-images').innerHeight();
465                                let selectOptionValue = selectPicker.find('option').eq(
466                                    e.currentTarget.ariaPosInSet
467                                ).data("value");
468                                $('.variation-image-preview.vt' + selectOptionValue)
469                                    .addClass('show d-md-block')
470                                    .css('top', $(e.currentTarget).offset().top - $(e.currentTarget).closest('#content').position().top - mainImageHeight / 2 - 12);
471                            }, delay)
472                        })
473                        .on('mouseleave', function (e) {
474                            clearTimeout(setTimeoutConst);
475                            let selectOptionValue = selectPicker.find('option').eq(
476                                e.currentTarget.ariaPosInSet
477                            ).data("value");
478                            $('.variation-image-preview.vt' + selectOptionValue)
479                                .removeClass('show d-md-block');
480                    });
481                })
482                .on('hide.bs.select', function () {
483                    $(this).parent().find('li .variation').off('mouseenter mouseleave');
484                    $('.variation-image-preview').removeClass('show');
485                });
486        },
487
488        registerImageSwitch: function($wrapper) {
489            var that     = this,
490                imgSwitch,
491                gallery  = this.gallery;
492
493            if (gallery !== null) {
494                imgSwitch = function (context, temporary, force) {
495                    var $context = $(context),
496                        id       = $context.attr('data-key'),
497                        value    = $context.attr('data-value'),
498                        data     = $context.data('list'),
499                        title    = $context.attr('data-title');
500
501                    if (typeof temporary === 'undefined') {
502                        temporary = true;
503                    }
504
505                    if ((!$context.hasClass('active') || force) && !!data) {
506                        gallery.setItems([data], value);
507
508                        if (!temporary) {
509                            var items  = [data],
510                                stacks = gallery.getStacks();
511                            for (var s in stacks) {
512                                if (stacks.hasOwnProperty(s) && s.match(/^_[0-9a-zA-Z]*$/) && s !== '_' + id) {
513                                    items = $.merge(items, stacks[s]);
514                                }
515                            }
516
517                            gallery.setItems([data], '_' + id);
518                            gallery.setItems(items, '__');
519                            gallery.render('__');
520
521                            that.galleryIndex     = gallery.index;
522                            that.galleryLastIdent = gallery.ident;
523                        } else {
524                            gallery.render(value);
525                        }
526                    }
527                }
528            } else {
529                imgSwitch = function (context, temporary) {
530                    var $context = $(context),
531                        value    = $context.attr('data-value'),
532                        data     = $context.data('list'),
533                        title    = $context.attr('data-title');
534
535                    if (typeof temporary === 'undefined') {
536                        temporary = true;
537                    }
538
539                    if (!!data) {
540                        var $wrapper = $(context).closest('.product-wrapper'),
541                            $img     = $('.image-box img', $wrapper);
542                        if ($img.length === 1) {
543                            $img.attr('src', data.md.src);
544                            if (!temporary) {
545                                $img.data('src', data.md.src);
546                            }
547                        }
548                    }
549                };
550            }
551
552            $('.variations .bootstrap-select select', $wrapper)
553                .on('change', function() {
554                    var sel  = $(this).find('[value=' + this.value + ']'),
555                        cont = $(this).closest('.variations');
556
557                    if (cont.hasClass('simple-variations')) {
558                        imgSwitch(sel, false, false);
559                    } else {
560                        imgSwitch(sel, true, false);
561                    }
562                });
563
564            if (!isTouchCapable() || ResponsiveBootstrapToolkit.current() !== 'xs') {
565                $('.variations .bootstrap-select .dropdown-menu li', $wrapper)
566                    .on('hover', function () {
567                        var tmp_idx = parseInt($(this).attr('data-original-index')) + 1,
568                            rule    = 'select option:nth-child(' + tmp_idx + ')',
569                            sel     = $(this).closest('.bootstrap-select').find(rule);
570                        imgSwitch(sel);
571                    }, function () {
572                        var tmp_idx = parseInt($(this).attr('data-original-index')) + 1,
573                            rule    = 'select option:nth-child(' + tmp_idx + ')',
574                            sel     = $(this).closest('.bootstrap-select').find(rule),
575                            gallery = that.gallery,
576                            active;
577
578                        if (gallery !== null) {
579                            active = $(sel).find('.variation.active');
580                            gallery.render(that.galleryLastIdent);
581                            gallery.activate(that.galleryIndex);
582                        } else {
583                            var $wrapper = $(sel).closest('.product-wrapper'),
584                                $img     = $('.image-box img', $wrapper);
585                            if ($img.length === 1) {
586                                $img.attr('src', $img.data('src'));
587                            }
588                        }
589                    });
590            }
591
592            $('.variations.simple-variations .variation', $wrapper)
593                .on('click', function () {
594                    imgSwitch(this, false);
595                });
596
597            if (!isTouchCapable() || ResponsiveBootstrapToolkit.current() !== 'xs') {
598                $('.variations .variation', $wrapper)
599                    .on('hover', function () {
600                        imgSwitch(this);
601                    }, function () {
602                        var sel     = $(this).closest('.variation'),
603                            gallery = that.gallery;
604
605                        if (gallery !== null) {
606                            gallery.render(that.galleryLastIdent);
607                            gallery.activate(that.galleryIndex);
608                        } else {
609                            var $wrapper = $(sel).closest('.product-wrapper'),
610                                $img     = $('.image-box img', $wrapper);
611                            if ($img.length === 1) {
612                                $img.attr('src', $img.data('src'));
613                            }
614                        }
615                    });
616            }
617        },
618
619        registerImageHover: function($wrapper) {
620            $('.product-list .productbox-hover:not(.focus), .product-list .productbox-show-variations:not(.focus)',
621                $wrapper).on('mouseenter focusin', function () {
622                $(this).closest('.product-list').find('.focus').removeClass('focus');
623            });
624            $('.productbox-show-variations', $wrapper).on('mouseenter focusin', function () {
625                let collapse = $(this).find('.productbox-variations>.collapse')
626
627                $(this).addClass('focus');
628                $(collapse).collapse('show');
629            });
630            $('.productlist-page-nav', $wrapper).on('focusin', function () {
631                $('.productbox-show-variations.focus', $wrapper).removeClass('focus');
632            });
633            $('.productbox-show-variations', $wrapper).on(' mouseleave', function () {
634                let collapse = $(this).not('.focus').find('.productbox-variations>.collapse')
635                let box = $(this)
636
637                box.removeClass('focus');
638                if (collapse.length === 1) {
639                    box.addClass('transition');
640                    $(collapse).collapse('hide');
641                    $(collapse).on('hidden.bs.collapse', function () {
642                        box.removeClass('transition');
643                    });
644                }
645            });
646            $('.is-mobile .show-variation-collapse a').on('click', function (e) {
647                if (!$(this).closest('.show-variation-collapse').find('.collapse').hasClass('show')) {
648                    e.preventDefault();
649                }
650            });
651        },
652
653        registerFinish: function($wrapper) {
654            $('#jump-to-votes-tab', $wrapper).on('click', function () {
655                let $tabID = $('#content a[href="#tab-votes"]');
656                if ($tabID.length > 0) {
657                    $tabID.tab('show');
658                } else {
659                    $tabID = $('#tab-votes');
660                    $tabID.collapse('show');
661                }
662
663                $([document.documentElement, document.body]).animate({
664                    scrollTop: $tabID.offset().top
665                }, 200);
666            });
667
668            let $tabID = $('#product-tabs a[href="' + window.location.hash + '"]');
669            if ($tabID.length) {
670                $tabID.tab('show');
671                $([document.documentElement, document.body]).animate({
672                    scrollTop: $tabID.offset().top
673                }, 200);
674            }
675
676            if (this.isSingleArticle()) {
677                if ($('.switch-variations .form-group', $wrapper).length === 1) {
678                    var wrapper = '#' + $($wrapper).attr('id');
679                    this.variationSwitch($('.switch-variations', $wrapper), false, wrapper);
680                }
681            }
682            else {
683                var that = this;
684
685                $('.product-cell.hover-enabled')
686                    .on('click', function (event) {
687                        if (isTouchCapable() && ResponsiveBootstrapToolkit.current() !== 'xs') {
688                            var $this = $(this);
689
690                            if (!$this.hasClass('active')) {
691                                event.preventDefault();
692                                event.stopPropagation();
693                                $('.product-cell').removeClass('active');
694                                $this.addClass('active');
695                            }
696                        }
697                    })
698                    .on('mouseenter', function (event) {
699                        var $this = $(this),
700                            wrapper = '#' + $this.attr('id');
701
702                        if (!$this.data('varLoaded') && $('.switch-variations .form-group', $this).length === 1) {
703                            that.variationSwitch($('.switch-variations', $this), false, wrapper);
704                        }
705                        $this.data('varLoaded', true);
706                    });
707            }
708
709            this.registerProductActions($('#sidepanel_left'));
710            this.registerProductActions($('#footer'));
711            this.registerProductActions($('#shop-nav'));
712            this.registerProductActions($wrapper);
713            this.registerProductActions('#cart-form');
714            dzm.dispatcher.dispatch(dzm.events.jtl.article.checkVarkombiDependencies,null);
715
716        },
717
718        registerProductActions: function($wrapper) {
719            var that = this;
720
721            $('*[data-toggle="product-actions"] button', $wrapper)
722                .on('click', function(event) {
723                    var data = $(this.form).serializeObject();
724
725                    if ($wrapper === '#cart-form') {
726                        data.wlPos = $(this).data('wl-pos');
727                        data.a = $(this).data('product-id-wl');
728                    }
729
730                    if (that.handleProductAction(this, data)) {
731                        event.preventDefault();
732                    }
733                });
734            $('a[data-toggle="product-actions"]', $wrapper)
735                .on('click', function(event) {
736                    var data  = $(this).data('value');
737                    this.name = $(this).data('name');
738
739                    if (that.handleProductAction(this, data)) {
740                        event.preventDefault();
741                    }
742                });
743        },
744
745        loadModalArticle: function(url, wrapper, done, fail) {
746            var that       = this,
747                id         = wrapper.slice(1),
748                $modalBody = $('.modal-body', this.modalView);
749
750            $.ajax(url, {data: {'isAjax':1, 'quickView':1}})
751                .done(function(data) {
752                    var $html      = $('<div />').html(data);
753                    var $headerCSS = $html.find('link[type="text/css"]');
754                    var $headerJS  = $html.find('script[src][src!=""]');
755                    var content    = $html.find(that.options.modal.wrapper).html();
756
757                    $headerCSS.each(function (pos, item) {
758                        var $cssLink = $('head link[href="' + item.href + '"]');
759                        if ($cssLink.length === 0) {
760                            $('head').append('<link rel="stylesheet" type="text/css" href="' + item.href + '" >');
761                        }
762                    });
763
764                    $headerJS.each(function (pos, item) {
765                        if (typeof item.src !== 'undefined' && item.src.length > 0) {
766                            var $jsLink = $('head script[src="' + item.src + '"]');
767                            if ($jsLink.length === 0) {
768                                $('head').append('<script defer src="' + item.src + '" >');
769                            }
770                        }
771                    });
772
773                    $modalBody.html($('<div id="' + id + '" />').html(content));
774
775                    var $modal  = $modalBody.closest(".modal-dialog"),
776                        title   = $modal.find('.modal-body h1'),
777                        $config = $('#product-configurator', $modalBody);
778
779                    if ($config.length > 0) {
780                        // Configurator in child article!? Currently not supported!
781                        $config.remove();
782                        $.evo.extended().startSpinner($modalBody);
783                        location.href = url;
784                    }
785                    if (title.length > 0 && title.text().length > 0) {
786                        $modal.find('.modal-title').text(title.text());
787                        title.remove();
788                    }
789
790                    $('form', $modalBody).on('submit', function(event) {
791                        event.preventDefault();
792
793                        var $form = $(this);
794                        var data  = $form.serializeObject();
795                        if (data['VariKindArtikel']) {
796                            data['a'] = data['VariKindArtikel'];
797                        }
798
799                        $.evo.basket().addToBasket($form, data);
800                        that.modalView.modal('hide');
801                    });
802
803                    if (typeof done === 'function') {
804                        done();
805                    }
806                })
807                .fail(function() {
808                    if (typeof fail === 'function') {
809                        fail();
810                    }
811                })
812                .always(function() {
813                    $.evo.extended().stopSpinner();
814                });
815        },
816
817        addToComparelist: function(data, $action) {
818            var productId = parseInt(data[this.options.input.id]);
819            var childId = parseInt(data[this.options.input.childId]);
820            if (childId > 0) {
821                productId = childId;
822            }
823            if (productId > 0) {
824                var that = this;
825                $.evo.io().call('pushToComparelist', [productId], that, function(error, data) {
826                    if (error) {
827                        return;
828                    }
829
830                    var response = data.response;
831
832                    if (response) {
833                        switch (response.nType) {
834                            case 0: // error
835                                var errorlist = '<ul><li>' + response.cHints.join('</li><li>') + '</li></ul>';
836                                eModal.alert({
837                                    title: response.cTitle,
838                                    message: errorlist,
839                                    keyboard: true,
840                                    tabindex: -1,
841                                    buttons: false
842                                });
843                                break;
844                            case 1: // forwarding
845                                window.location.href = response.cLocation;
846                                break;
847                            case 2: // added to comparelist
848                                that.updateComparelist(response);
849                                break;
850                        }
851                    }
852                });
853
854                return true;
855            }
856
857            return false;
858        },
859
860        removeFromCompareList: function(data) {
861            /*niu differ between child and parent, so you can also remove from comparelist*/
862            var productId = parseInt(data[this.options.input.id]);
863            var childId = parseInt(data[this.options.input.childId]);
864            if (childId > 0) {
865                productId = childId;
866            }
867            if (productId > 0) {
868                var that = this;
869                $.evo.io().call('removeFromComparelist', [productId], that, function(error, data) {
870                    if (error) {
871                        return;
872                    }
873
874                    var response = data.response;
875
876                    if (response) {
877                        switch (response.nType) {
878                            case 0: // error
879                                var errorlist = '<ul><li>' + response.cHints.join('</li><li>') + '</li></ul>';
880                                eModal.alert({
881                                    title: response.cTitle,
882                                    message: errorlist,
883                                    keyboard: true,
884                                    tabindex: -1,
885                                    buttons: false
886                                });
887                                break;
888                            case 1: // forwarding
889                                window.location.href = response.cLocation;
890                                break;
891                            case 2: // removed from comparelist
892                                that.updateComparelist(response);
893                                break;
894                        }
895                    }
896                });
897
898                return true;
899            }
900
901            return false;
902        },
903
904        updateComparelist: function(data) {
905            var $badgeUpd = $(this.options.selector.navUpdateCompare);
906
907            var badge = $(data.navDropdown);
908            $badgeUpd.html(badge);
909            $(this.options.selector.navBadgeUpdateCompare).html(data.nCount);
910
911            if (data.nCount > 0) {
912                $(this.options.selector.navCompare).removeClass('d-none');
913            } else {
914                $(this.options.selector.navCompare).addClass('d-none');
915                $('#nav-comparelist-collapse').removeClass('show');
916            }
917            if (data.nCount > 1) {
918                $('#nav-comparelist-goto').removeClass('d-none');
919            } else {
920                $('#nav-comparelist-goto').addClass('d-none');
921            }
922            this.registerProductActions($('#shop-nav'));
923
924            if (data.productID) {
925                let $action = $('button[data-product-id-cl="' + data.productID + '"]')
926                $action.removeClass("on-list");
927                $action.next().removeClass("press");
928                $('.comparelist [data-product-id-cl="' + data.productID + '"]').remove();
929            }
930
931            for (var ind in data.cBoxContainer) {
932                var $list = $(this.options.selector.boxContainer+ind);
933
934                if ($list.length > 0) {
935                    if (data.cBoxContainer[ind].length) {
936                        var $boxContent = $(data.cBoxContainer[ind]);
937                        this.registerProductActions($boxContent);
938                        $list.replaceWith($boxContent).removeClass('d-none');
939                    } else {
940                        $list.html('').addClass('d-none');
941                    }
942                }
943            }
944        },
945
946        addToWishlist: function(data, $action) {
947            let productId = parseInt(data[this.options.input.id]),
948                childId = parseInt(data[this.options.input.childId]),
949                qty =  parseFloat(data[this.options.input.quantity]);
950            if (childId > 0) {
951                productId = childId;
952            }
953            if (isNaN(qty)) {
954                qty = 1;
955            }
956            if (productId > 0) {
957                var that = this;
958                $.evo.io().call('pushToWishlist', [productId, qty, data], that, function(error, data) {
959                    if (error) {
960                        $action.closest('form')[0].reportValidity();
961                        return;
962                    }
963                    if ($action.hasClass('action-tip-animation-b')) {
964                        $action.addClass("on-list");
965                        $action.next().addClass("press");
966                        $action.next().next().removeClass("press");
967                    }
968                    var response = data.response;
969
970                    if (response) {
971                        switch (response.nType) {
972                            case 0: // error
973                                var errorlist = '<ul><li>' + response.cHints.join('</li><li>') + '</li></ul>';
974                                eModal.alert({
975                                    title: response.cTitle,
976                                    message: errorlist,
977                                    keyboard: true,
978                                    tabindex: -1,
979                                    buttons: false
980                                });
981                                break;
982                            case 1: // forwarding
983                                window.location.href = response.cLocation;
984                                break;
985                            case 2: // added to wishlist
986                                that.updateWishlist(response);
987                                break;
988                        }
989                    }
990                });
991
992                return true;
993            }
994
995            return false;
996        },
997
998        removeFromWishList: function(data) {
999            var productId = parseInt(data[this.options.input.id]);
1000            if (productId > 0) {
1001                var that = this;
1002                $.evo.io().call('removeFromWishlist', [productId], that, function(error, data) {
1003                    if (error) {
1004                        return;
1005                    }
1006
1007                    var response = data.response;
1008
1009                    if (response) {
1010                        switch (response.nType) {
1011                            case 0: // error
1012                                var errorlist = '<ul><li>' + response.cHints.join('</li><li>') + '</li></ul>';
1013                                eModal.alert({
1014                                    title: response.cTitle,
1015                                    message: errorlist,
1016                                    keyboard: true,
1017                                    tabindex: -1,
1018                                    buttons: false
1019                                });
1020                                break;
1021                            case 1: // forwarding
1022                                window.location.href = response.cLocation;
1023                                break;
1024                            case 2: // removed from wishlist
1025                                that.updateWishlist(response);
1026                                break;
1027                        }
1028                    }
1029                });
1030
1031                return true;
1032            }
1033
1034            return false;
1035        },
1036
1037        updateWishlist: function(data) {
1038            var $navContainerWish = $(this.options.selector.navContainerWish);
1039            var $navBadgeWish = $(this.options.selector.navBadgeWish);
1040
1041            if (data.wlPosRemove) {
1042                let $action = $('button[data-wl-pos="' + data.wlPosRemove + '"]');
1043                $action.removeClass("on-list");
1044                $action.next().removeClass("press");
1045                $action.find('.wishlist-icon').addClass('far').removeClass('fas');
1046            }
1047            if (data.wlPosAdd) {
1048                let $action = $('button[data-product-id-wl="' + data.productID + '"]');
1049                $action.attr('data-wl-pos', data.wlPosAdd);
1050                $action.data('wl-pos', data.wlPosAdd);
1051                $action.closest('form').find('input[name="wlPos"]').val(data.wlPosAdd)
1052                $action.find('.wishlist-icon').addClass('fas').removeClass('far');
1053            }
1054            $.evo.io().call('updateWishlistDropdown', [$navContainerWish, $navBadgeWish], this, function(error, data) {
1055                if (error) {
1056                    return;
1057                }
1058                if (data.response.currentPosCount > 0) {
1059                    $navBadgeWish.removeClass('d-none');
1060                } else {
1061                    $navBadgeWish.addClass('d-none');
1062                }
1063                $navContainerWish.html(data.response.content);
1064                $navBadgeWish.html(data.response.currentPosCount);
1065                setClickableRow();
1066            });
1067
1068            for (var ind in data.cBoxContainer) {
1069                var $list = $(this.options.selector.boxContainerWish+ind);
1070                if ($list.length > 0) {
1071                    if (data.cBoxContainer[ind].length) {
1072                        var $boxContent = $(data.cBoxContainer[ind]);
1073                        this.registerProductActions($boxContent);
1074                        $list.replaceWith($boxContent).removeClass('d-none');
1075                    } else {
1076                        $list.html('').addClass('d-none');
1077                    }
1078                }
1079            }
1080        },
1081
1082        handleProductAction: function(action, data) {
1083            let $action = $(action);
1084            switch (action.name) {
1085                case this.options.action.compareList:
1086                    if ($action.hasClass('action-tip-animation-b')) {
1087                        if ($action.hasClass('on-list')) {
1088                            $action.removeClass("on-list");
1089                            $action.next().removeClass("press");
1090                            $action.next().next().addClass("press");
1091                            return this.removeFromCompareList(data);
1092                        } else {
1093                            $action.addClass("on-list");
1094                            $action.next().addClass("press");
1095                            $action.next().next().removeClass("press");
1096                            $(this.options.selector.navCompare).removeClass('d-none');
1097
1098                            let $moveTo = isMobileByBodyClass()
1099                                ? $('.wish-compare-animation-mobile #burger-menu')
1100                                : $('.wish-compare-animation-desktop #shop-nav-compare');
1101                            $.evo.article().moveItemAnimation($action, $moveTo);
1102
1103                            return this.addToComparelist(data, $action);
1104                        }
1105                    } else {
1106                        return this.addToComparelist(data, $action);
1107                    }
1108                case this.options.action.compareListRemove:
1109                    return this.removeFromCompareList(data);
1110                case this.options.action.wishList:
1111                    data[this.options.input.quantity] = $('input[data-product-id="' + data.a + '"]').val()
1112                        || $('#buy_form_'+data.a+' '+this.options.selector.quantity).val()
1113                        || $('#quantity').val();
1114                    if ($action.hasClass('on-list')) {
1115                        $action.removeClass("on-list");
1116                        $action.next().removeClass("press");
1117                        $action.next().next().addClass("press");
1118                        data.a = data.wlPos;
1119                        return this.removeFromWishList(data);
1120                    } else {
1121                        $action.addClass("on-list");
1122                        let $moveTo = isMobileByBodyClass()
1123                            ? $('.wish-compare-animation-mobile #burger-menu')
1124                            : $('.wish-compare-animation-desktop #shop-nav-wish');
1125                        $.evo.article().moveItemAnimation($action, $moveTo);
1126                        return this.addToWishlist(data, $action);
1127                    }
1128                case this.options.action.wishListRemove:
1129                    return this.removeFromWishList(data);
1130            }
1131
1132            return false;
1133        },
1134
1135        configurator: function(init) {
1136            if (this.isSingleArticle()) {
1137                var that      = this,
1138                    container = $('#cfg-container'),
1139                    sidebar   = $('#cfg-sticky-sidebar'),
1140                    width,
1141                    form;
1142
1143                if (container.length === 0) {
1144                    return;
1145                }
1146
1147                $.evo.extended().startSpinner(container);
1148
1149                $('#buy_form').find('*[data-selected="true"]')
1150                    .attr('checked', true)
1151                    .attr('selected', true)
1152                    .attr('data-selected', null);
1153
1154                form = $.evo.io().getFormValues('buy_form');
1155
1156                $.evo.io().call('buildConfiguration', [form], that, function (error, data) {
1157
1158                    var result,
1159                        i,
1160                        j,
1161                        item,
1162                        cBeschreibung,
1163                        quantityWrapper,
1164                        grp,
1165                        value,
1166                        enableQuantity,
1167                        nNetto,
1168                        quantityInput;
1169                    $('.js-start-configuration').prop('disabled', !(data.response.variationsSelected && data.response.inStock));
1170                    $('.js-choose-variations-wrapper').toggleClass('d-none', data.response.variationsSelected);
1171                    $('.js-cfg-group').each(function (i, item) {
1172                        let iconChecked     = $('a[href="#'+this.id+'"] .js-group-checked'),
1173                            badgeInfoDanger = 'alert-info';
1174                        if (data.response.invalidGroups && data.response.invalidGroups.includes($(this).data('id'))) {
1175                            iconChecked.addClass('d-none');
1176                            if ($(this).hasClass('visited')) {
1177                                badgeInfoDanger = 'alert-danger';
1178                            }
1179                            $(this).find('[data-niu-configurator-next-btn]').prop("disabled",true);
1180                            $(this).find('.js-group-badge-checked')
1181                                .removeClass('alert-success alert-info')
1182                                .addClass(badgeInfoDanger);
1183                        } else {
1184                            iconChecked.removeClass('d-none');
1185                            $(this).find('[data-niu-configurator-next-btn]').prop("disabled",false);
1186
1187                            $(this).find('.js-group-badge-checked')
1188                                .addClass('alert-success')
1189                                .removeClass('alert-danger alert-info');
1190                        }
1191                    });
1192                    $('.js-cfg-group-error').addClass('d-none').html('');
1193                    $.each(data.response.errorMessages, function (i, item) {
1194                        $('.js-cfg-group-error[data-id="' + item.group + '"]').removeClass('d-none').html(item.message);
1195                    });
1196                    let $summaryFinish = $('#cfg-tab-summary-finish');
1197                    if (data.response.valid) {
1198                        $('.js-cfg-validate').prop('disabled', false);
1199                        $summaryFinish.children().removeClass('disabled');
1200                        $summaryFinish.removeClass('disabled');
1201                    } else {
1202                        $('.js-cfg-validate').prop('disabled', true);
1203                        $summaryFinish.children().addClass('disabled');
1204                        $summaryFinish.addClass('disabled');
1205                    }
1206                    $.evo.extended().stopSpinner();
1207                    if (error) {
1208                        $.evo.error(data);
1209                        return;
1210                    }
1211                    result = data.response;
1212
1213                    if (!result.oKonfig_arr) {
1214                        $.evo.error('Missing configuration groups');
1215                        return;
1216                    }
1217
1218                    // global price
1219                    nNetto = result.nNettoPreise;
1220                    that.setPrice(result.fGesamtpreis[nNetto], result.cPreisLocalized[nNetto], result.cPreisString);
1221                    that.setStockInformation(result.cEstimatedDelivery);
1222
1223                    $('#content .summary').html(result.cTemplate);
1224                    $.evo.tooltips();
1225                    $.evo.extended()
1226                        .trigger('priceChanged', result);
1227                });
1228            }
1229        },
1230
1231        initConfigListeners: function () {
1232            $('.js-cfg-group').on('click', function () {
1233                $(this).addClass('visited');
1234            });
1235            $('#cfg-tab-summary-finish').on('click', function () {
1236                if (!$(this).hasClass('disabled')) {
1237                    $('#cfg-modal-tabs').find('.nav-link').removeClass('active');
1238                    $('#cfg-tab-summary').children().addClass('active');
1239                    $(this).children().removeClass('active');
1240                }
1241            });
1242            $('.js-cfg-group-collapse').on('click', function () {
1243                $(this).addClass('visited');
1244            });
1245        },
1246
1247        variationRefreshAll: function($wrapper) {
1248            $('.variations select', $wrapper).selectpicker('refresh');
1249            $.evo.initSliders()
1250        },
1251
1252        getConfigGroupQuantity: function (groupId) {
1253            return $('.cfg-group[data-id="' + groupId + '"] .quantity');
1254        },
1255
1256        getConfigGroupQuantityInput: function (groupId) {
1257            return $('.cfg-group[data-id="' + groupId + '"] .quantity input');
1258        },
1259
1260        getConfigGroupImage: function (groupId) {
1261            return $('.cfg-group[data-id="' + groupId + '"] .group-image img');
1262        },
1263
1264        setConfigItemImage: function (groupId, img) {
1265            $('.cfg-group[data-id="' + groupId + '"] .group-image img').attr('src', img).first();
1266        },
1267
1268        setConfigItemDescription: function (groupId, itemBeschreibung) {
1269            var groupItems                       = $('.cfg-group[data-id="' + groupId + '"] .group-items');
1270            var descriptionDropdownContent       = groupItems.find('#filter-collapsible_dropdown_' + groupId + '');
1271            var descriptionDropdownContentHidden = groupItems.find('.d-none');
1272            var descriptionCheckdioContent       = groupItems.find('div[id^="filter-collapsible_checkdio"]');
1273            var multiselect                      = groupItems.find('select').attr("multiple");
1274
1275            //  Bisher kein Content mit einer Beschreibung vorhanden, aber ein Artikel mit Beschreibung ausgewählt
1276            if (descriptionDropdownContentHidden.length > 0 && descriptionCheckdioContent.length === 0 && itemBeschreibung.length > 0 && multiselect !== "multiple") {
1277                groupItems.find('a[href="#filter-collapsible_dropdown_' + groupId + '"]').removeClass('d-none');
1278                descriptionDropdownContent.replaceWith('<div id="filter-collapsible_dropdown_' + groupId + '" class="collapse top10 panel-body">' + itemBeschreibung + '</div>');
1279                //  Bisher Content mit einer Beschreibung vorhanden, aber ein Artikel ohne Beschreibung ausgewählt
1280            } else if (descriptionDropdownContentHidden.length === 0 && descriptionCheckdioContent.length === 0 && itemBeschreibung.length === 0 && multiselect !== "multiple") {
1281                groupItems.find('a[href="#filter-collapsible_dropdown_' + groupId + '"]').addClass('d-none');
1282                descriptionDropdownContent.addClass('d-none');
1283                //  Bisher Content mit einer Beschreibung vorhanden und ein Artikel mit Beschreibung ausgewählt
1284            } else if (descriptionDropdownContentHidden.length === 0 && descriptionCheckdioContent.length === 0 && itemBeschreibung.length > 0 && multiselect !== "multiple") {
1285                descriptionDropdownContent.replaceWith('<div id="filter-collapsible_dropdown_' + groupId + '" class="collapse top10 panel-body">' + itemBeschreibung + '</div>');
1286            }
1287        },
1288
1289        setPrice: function(price, fmtPrice, priceLabel, wrapper) {
1290            var $wrapper = this.getWrapper(wrapper);
1291
1292            if (this.isSingleArticle()) {
1293                $('#product-offer .price', $wrapper).html(fmtPrice);
1294                $('#product-offer meta[itemprop="price"]', $wrapper).attr('content',price);
1295                if (priceLabel.length > 0) {
1296                    $('#product-offer .price_label', $wrapper).html(priceLabel);
1297                }
1298            } else {
1299                var $price = $('.price_wrapper', $wrapper);
1300
1301                $('.price span:first-child', $price).html(fmtPrice);
1302                if (priceLabel.length > 0) {
1303                    $('.price_label', $price).html(priceLabel);
1304                }
1305            }
1306
1307            $.evo.trigger('changed.article.price', { price: price });
1308        },
1309
1310        setStockInformation: function(cEstimatedDelivery, wrapper) {
1311            var $wrapper = this.getWrapper(wrapper);
1312
1313            /* niu switched to our classes */
1314            /*$('.delivery-status .estimated-delivery span', $wrapper).html(cEstimatedDelivery);*/
1315            $('.niu-estimated-delivery-wrapper .estimated_delivery span', $wrapper).html(cEstimatedDelivery);
1316        },
1317
1318        setStaffelPrice: function(prices, fmtPrices, wrapper) {
1319            var $wrapper   = this.getWrapper(wrapper),
1320                $container = $('#product-offer', $wrapper);
1321
1322            $.each(fmtPrices, function(index, value){
1323                $('.bulk-price-' + index + ' .bulk-price', $container).html(value);
1324            });
1325        },
1326
1327        setVPEPrice: function(fmtVPEPrice, VPEPrices, fmtVPEPrices, wrapper) {
1328            let $wrapper   = this.getWrapper(wrapper);
1329            if ($('#product-offer').length > 0) {
1330                $wrapper = $('#product-offer', $wrapper);
1331            }
1332
1333            $('.base-price .value', $wrapper).html(fmtVPEPrice);
1334            $.each(fmtVPEPrices, function(index, value){
1335                $('.bulk-price-' + index + ' .bulk-base-price', $wrapper).html(value);
1336            });
1337        },
1338
1339        /**
1340         * @deprecated since 4.05 - use setArticleWeight instead
1341         */
1342        setUnitWeight: function(UnitWeight, newUnitWeight) {
1343            $('#article-tabs .product-attributes .weight-unit').html(newUnitWeight);
1344        },
1345
1346        setArticleWeight: function(ArticleWeight, wrapper) {
1347            if (this.isSingleArticle()) {
1348                var $articleTabs = $('#article-tabs');
1349
1350                if ($.isArray(ArticleWeight)) {
1351                    $('.product-attributes .weight-unit', $articleTabs).html(ArticleWeight[0][1]);
1352                    $('.product-attributes .weight-unit-article', $articleTabs).html(ArticleWeight[1][1]);
1353                } else {
1354                    $('.product-attributes .weight-unit', $articleTabs).html(ArticleWeight);
1355                }
1356            } else {
1357                var $wrapper = this.getWrapper(wrapper);
1358
1359                if ($.isArray(ArticleWeight)) {
1360                    $('.attr-weight .value', $wrapper).html(ArticleWeight[0][1]);
1361                    $('.attr-weight.weight-unit-article .value', $wrapper).html(ArticleWeight[1][1]);
1362                } else {
1363                    $('.attr-weight .value', $wrapper).html(ArticleWeight);
1364                }
1365            }
1366
1367        },
1368
1369        setProductNumber: function(productNumber, wrapper) {
1370            var $wrapper = this.getWrapper(wrapper);
1371
1372            $('#product-offer span[itemprop="sku"]', $wrapper).html(productNumber);
1373        },
1374
1375        setArticleContent: function(id, variation, url, variations, wrapper) {
1376            var $wrapper  = this.getWrapper(wrapper),
1377                listStyle = $('#product-list-type').val();
1378
1379                if (listStyle === 'undefined') {
1380                    listStyle = $('#ed_list.active').length > 0 ? 'list' : 'gallery';
1381                }
1382
1383                $.evo.extended().startSpinner($wrapper);
1384
1385            if (this.modalShown) {
1386                this.loadModalArticle(url, wrapper,
1387                    function() {
1388                        var article = new ArticleClass();
1389                        article.register(wrapper);
1390                        $.evo.extended().stopSpinner();
1391                    },
1392                    function() {
1393                        $.evo.extended().stopSpinner();
1394                        $.evo.error('Error loading ' + url);
1395                    }
1396                );
1397            } else if (this.isSingleArticle()) {
1398                if($('#opc-startmenu').length > 0) {
1399                    return this.redirectToArticle(id, variation, url, variations, wrapper);
1400                }
1401
1402                $.evo.extended().loadContent(url, () => {
1403                    $.evo.extended().register();
1404                    $.evo.article().register(wrapper);
1405
1406                    $(variations).each(function (i, item) {
1407                        $.evo.article().variationSetVal(item.key, item.value, wrapper);
1408                    });
1409
1410                    if (document.location.href !== url) {
1411                        history.pushState({a: id, a2: variation, url: url, variations: variations}, "", url);
1412                    }
1413                    $.evo.extended().stopSpinner();
1414                }, function () {
1415                    $.evo.error('Error loading ' + url);
1416                    $.evo.extended().stopSpinner();
1417                }, false, wrapper);
1418            } else {
1419                $.evo.extended().loadContent(url + (url.indexOf('?') >= 0 ? '&' : '?') + 'isListStyle=' + listStyle, function (content) {
1420                    $.evo.article().register(wrapper);
1421
1422                    $('[data-toggle="basket-add"]', $(wrapper)).on('submit', function(event) {
1423                        event.preventDefault();
1424                        event.stopPropagation();
1425
1426                        var $form = $(this);
1427                        var data  = $form.serializeObject();
1428                        data['a'] = variation;
1429
1430                        $.evo.basket().addToBasket($form, data);
1431                    });
1432
1433                    $(variations).each(function (i, item) {
1434                        $.evo.article().variationSetVal(item.key, item.value, wrapper);
1435                    });
1436
1437                    $.evo.extended().stopSpinner();
1438                }, function () {
1439                    $.evo.error('Error loading ' + url);
1440                    $.evo.extended().stopSpinner();
1441                }, false, wrapper);
1442            }
1443        },
1444
1445        redirectToArticle: function(id, variation, url, variations, wrapper) {
1446            var $wrapper  = this.getWrapper(wrapper),
1447                listStyle = $('#product-list-type').val();
1448
1449            $.evo.extended().startSpinner($wrapper);
1450
1451            window.open(url, '_top');
1452
1453            $.evo.extended().stopSpinner($wrapper);
1454        },
1455
1456        variationResetAll: function(wrapper) {
1457            var $wrapper = this.getWrapper(wrapper);
1458
1459            $('.variation[data-value] input:checked', $wrapper).prop('checked', false);
1460            $('.variations select option', $wrapper).prop('selected', false);
1461            $('.variations select', $wrapper).selectpicker('refresh');
1462        },
1463
1464        variationDisableAll: function(wrapper) {
1465            let $wrapper = this.getWrapper(wrapper);
1466
1467            $('.swatches-selected', $wrapper).text('');
1468            $('[data-value].variation', $wrapper).each(function(i, item) {
1469                $(item)
1470                    .removeClass('active loading')
1471                    .addClass('not-available');
1472                $.evo.article()
1473                    .removeStockInfo($(item));
1474            });
1475        },
1476
1477        variationSetVal: function(key, value, wrapper) {
1478            var $wrapper = this.getWrapper(wrapper);
1479
1480            $('[data-key="' + key + '"]', $wrapper).val(value);
1481        },
1482
1483        variationEnable: function(key, value, wrapper) {
1484            var $wrapper = this.getWrapper(wrapper),
1485                $item    = $('[data-value="' + value + '"].variation', $wrapper);
1486
1487            $item.removeClass('not-available swatches-sold-out swatches-not-in-stock');
1488        },
1489
1490        showGalleryVariation: function(key, wrapper) {
1491            var $wrapper = this.getWrapper(wrapper),
1492                $item    = $('.variation-' + key, $wrapper);
1493
1494            $item.collapse();
1495        },
1496
1497        variationActive: function(key, value, def, wrapper) {
1498            var $wrapper = this.getWrapper(wrapper),
1499                $item    = $('[data-value="' + value + '"].variation', $wrapper);
1500            $item.addClass('active')
1501                .find('input')
1502                .prop('checked', true)
1503                .end()
1504                .prop('selected', true);
1505
1506            $('[data-id="'+key+'"].swatches-selected')
1507                .text($item.attr('data-original'));
1508        },
1509
1510        removeStockInfo: function($item) {
1511                var type = $item.attr('data-type'),
1512                    elem,
1513                    label,
1514                    wrapper;
1515
1516                switch (type) {
1517                    case 'option':
1518                        label = $item.data('content');
1519                        wrapper = $('<div />').append(label);
1520                        $(wrapper)
1521                            .find('.badge-not-available')
1522                            .remove();
1523                        label = $(wrapper).html();
1524                        $item.data('content', label)
1525                            .attr('data-content', label);
1526                        break;
1527                    case 'radio':
1528                        elem = $item.find('.badge-not-available');
1529                        if (elem.length === 1) {
1530                            $(elem).remove();
1531                        }
1532                        break;
1533                    case 'swatch':
1534                        $item.tooltip('dispose');
1535                        break;
1536                }
1537                $item.removeAttr('data-stock');
1538        },
1539
1540        variationInfo: function(value, status, note, notExists) {
1541            let $item = $('[data-value="' + value + '"].variation'),
1542                type = $item.attr('data-type'),
1543                text,
1544                content,
1545                $wrapper,
1546                label;
1547
1548            $item.attr('data-stock', _stock_info[status]);
1549
1550            switch (type) {
1551                case 'option':
1552                    text     = ' (' + note + ')';
1553                    content  = $item.data('content');
1554                    $wrapper = $('<div />');
1555
1556                    $wrapper.append(content);
1557                    $wrapper
1558                        .find('.badge-not-available')
1559                        .remove();
1560
1561                    label = $('<span />')
1562                        .addClass('badge badge-danger badge-not-available')
1563                        .text(' '+note);
1564
1565                    $wrapper.append(label);
1566
1567                    $item.data('content', $wrapper.html())
1568                        .attr('data-content', $wrapper.html());
1569
1570                    $item.closest('select')
1571                        .selectpicker('refresh');
1572                    break;
1573                case 'radio':
1574                    $item.find('.badge-not-available')
1575                        .remove();
1576
1577                    label = $('<span />')
1578                        .addClass('badge badge-danger badge-not-available')
1579                        .text(' '+note);
1580
1581                    $item.append(label);
1582                    break;
1583                case 'swatch':
1584                    if (!$item.hasClass('gall-preview')) {
1585                        $item.tooltip({
1586                            title: note,
1587                            trigger: 'hover',
1588                            container: 'body'
1589                        });
1590                    }
1591                    if (notExists) {
1592                        $item.addClass('swatches-not-in-stock');
1593                    } else {
1594                        $item.addClass('swatches-sold-out');
1595                    }
1596                    break;
1597            }
1598        },
1599
1600        variationSwitch: function($item, animation, wrapper) {
1601            if ($item) {
1602                var formID   = $item.closest('form').attr('id'),
1603                    $current = this.getCurrent($item),
1604                    key      = $current.data('key'),
1605                    value    = $current.data('value'),
1606                    io       = $.evo.io(),
1607                    args     = io.getFormValues(formID),
1608                    layout   = $('#product-list-type').val(),
1609                    $wrapper = this.getWrapper(wrapper);
1610
1611                if (animation) {
1612                    $.evo.extended().startSpinner();
1613                } else {
1614                    $('.updatingStockInfo', $wrapper).show();
1615                }
1616
1617                $('.tooltip.show').remove();
1618                args.wrapper = wrapper;
1619                args.layout  = layout;
1620
1621                $.evo.article()
1622                    .variationDispose(wrapper);
1623
1624                io.call('checkVarkombiDependencies', [args, key, value], $item, function (error, data) {
1625                    if (animation) {
1626                        $.evo.extended().stopSpinner();
1627                    }
1628                    $('.updatingStockInfo', $wrapper).hide();
1629                    if (error) {
1630                        $.evo.error('checkVarkombiDependencies');
1631                    }
1632                });
1633            }
1634        },
1635
1636        modalArticleDetail: function(item, wrapper)
1637        {
1638            let $item = $(item);
1639            let title = $item.data('title');
1640            let url   = $item.data('src');
1641
1642            if (typeof this.modalView === 'undefined' || this.modalView === null) {
1643                this.modalView = $(
1644                    '<div id="' + this.options.modal.id + '" class="modal fade" role="dialog" tabindex="-1" >' +
1645                    '   <div class="modal-dialog modal-lg">' +
1646                    '       <div class="modal-content">' +
1647                    '           <div class="modal-header">' +
1648                    '               <button type="button" class="x close" data-dismiss="modal"><i class="fa fa-times"></i></button>' +
1649                    '               <div class="modal-title h4">' + title + '</div>' +
1650                    '           </div>' +
1651                    '           <div class="modal-body">' +
1652                    '               <div id="' + wrapper.slice(1) + '" style="min-height:100px">' +
1653                    '<div class="jtl-spinner"><i class="fa fa-spinner fa-pulse"></i></div>' +
1654                    '               </div>' +
1655                    '           </div>' +
1656                    '       </div>' +
1657                    '   </div>' +
1658                    '</div>');
1659                this.modalView
1660                    .on('hidden.bs.modal', () => {
1661                        $('.modal-body', this.modalView)
1662                            .html('<div id="' + wrapper.slice(1) + '" style="min-height:100px" />');
1663                        $('.modal-title', this.modalView).html('');
1664                        this.modalView
1665                            .off('shown.bs.modal');
1666                        this.modalShown = false;
1667                    });
1668            } else {
1669                $('.modal-title', this.modalView).html(title);
1670                $('.modal-body', this.modalView)
1671                    .html('<div id="' + wrapper.slice(1) + '" style="min-height:100px">' +
1672                        '<div class="jtl-spinner"><i class="fa fa-spinner fa-pulse"></i></div></div>');
1673            }
1674
1675            this.modalView
1676                .on('shown.bs.modal', () => {
1677                    this.modalShown = true;
1678                    this.loadModalArticle(url, wrapper,
1679                        function() {
1680                            // no functionality needed in quickview
1681                            // var article = new ArticleClass();
1682                            // article.register(wrapper);
1683                            $.evo.extended().stopSpinner();
1684                            $('[data-toggle="popover"]', wrapper).popover({ html: true });
1685                            $('.product-image', wrapper).css('cursor', 'default');
1686                        },
1687                        function() {
1688                            $.evo.extended().stopSpinner();
1689                            $.evo.error('Error loading ' + params.url);
1690                        }
1691                    );
1692                })
1693                .modal('show');
1694        },
1695
1696        variationPrice: function($item, animation, wrapper) {
1697            var formID   = $item.closest('form').attr('id'),
1698                $wrapper = this.getWrapper(wrapper),
1699                io       = $.evo.io(),
1700                args     = io.getFormValues(formID);
1701
1702            if (animation) {
1703                $.evo.extended().startSpinner($wrapper);
1704            }
1705
1706            args.wrapper = wrapper;
1707            io.call('checkDependencies', [args], $(this), function (error, data) {
1708                let $action = $('button[data-product-id-wl="' + data.response.itemID + '"]');
1709                if (data.response.check > 0) {
1710                    $action.attr('data-wl-pos', data.response.check);
1711                    $action.data('wl-pos', data.response.check);
1712                    $action.closest('form').find('input[name="wlPos"]').val(data.response.check)
1713                    $action.addClass('on-list');
1714                } else {
1715                    $action.removeClass('on-list');
1716                }
1717
1718                if (animation) {
1719                    $.evo.extended().stopSpinner();
1720                }
1721                if (error) {
1722                    $.evo.error('checkDependencies');
1723                }
1724            });
1725        },
1726
1727        variationDispose: function(wrapper) {
1728            var $wrapper = this.getWrapper(wrapper);
1729
1730            $('[role="tooltip"]', $wrapper).remove();
1731        },
1732
1733        moveItemAnimation: function(item, moveTo) {
1734            if (!item.length || !moveTo.length || $(this).hasClass('on-list')) {
1735                return;
1736            }
1737            setTimeout(function() {
1738                let itemClone = item.clone()
1739                    .offset({
1740                        top: item.offset().top,
1741                        left: item.offset().left
1742                    }).css({
1743                        'opacity': '0.5',
1744                        'position': 'absolute',
1745                        'z-index': '10000'
1746                    })
1747                    .appendTo($('body'))
1748                    .animate({
1749                        'top': moveTo.offset().top + 5,
1750                        'left': moveTo.offset().left + 5,
1751                    }, 700);
1752
1753                itemClone.animate({
1754                    'width': 0,
1755                    'height': 0
1756                }, function () {
1757                    $(this).detach()
1758                });
1759            }, 0);
1760        },
1761
1762        initAbnahmeIntervallError: function() {
1763            let $intervallNotice = $('#intervall-notice');
1764            if ($intervallNotice.length > 0) {
1765                $('#quantity').on('change', function () {
1766                    let $step   = $(this).attr('step'),
1767                        diff    = Math.abs(($(this).val() % $step) - $step),
1768                        epsilon = 0.00000001;
1769                        $('#intervall-notice-danger').remove();
1770                    if (!(diff < epsilon || diff + epsilon > $step)) {
1771                        $('#quantity-grp').after('<div id="intervall-notice-danger" class="alert alert-danger mt-2">'
1772                            + $intervallNotice.html() + '</div>');
1773                    }
1774                });
1775            }
1776        }
1777    };
1778
1779    $v = new ArticleClass();
1780
1781    $(document).ready(function () {
1782        $v.onLoad();
1783        $v.register();
1784    });
1785
1786    $(window).on('resize',
1787        viewport.changed(function(){
1788            $v.configurator();
1789        })
1790    );
1791
1792    // PLUGIN DEFINITION
1793    // =================
1794    $.evo.article = function () {
1795       return $v;
1796    };
1797})(jQuery, document, window, ResponsiveBootstrapToolkit);

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.