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 wrapper = '#' + $item.closest('form').closest('div[id]').attr('id'); 407 408 $item.on('change', function () { 409 that.variationSwitch($(this), false, wrapper); 410 }); 411 }); 412 413 if (isTouchCapable()) { 414 $('.variations .swatches .variation', $wrapper) 415 .on('mouseover', function() { 416 $(this).trigger('click'); 417 }); 418 } 419 420 // ie11 fallback 421 if (typeof document.body.style.msTransform === 'string') { 422 $('.variations label.variation', $wrapper) 423 .on('click', function (e) { 424 if (e.target.tagName === 'IMG') { 425 $(this).trigger('click'); 426 } 427 }); 428 } 429 }, 430 431 registerHoverVariations: function ($wrapper) { 432 let delay=300, setTimeoutConst; 433 $('.variations label.variation', $wrapper) 434 .on('mouseenter', function (e) { 435 setTimeoutConst = setTimeout(function () { 436 let mainImageHeight = $('.js-gallery-images').innerHeight(); 437 $('.variation-image-preview.vt' + $(e.currentTarget).data('value')).addClass('show d-md-block') 438 .css('top', $(e.currentTarget).offset().top - $(e.currentTarget).closest('#content').position().top - mainImageHeight / 2 - 12); 439 }, delay) 440 }) 441 .on('mouseleave', function (e) { 442 clearTimeout(setTimeoutConst); 443 $('.variation-image-preview.vt' + $(this).data('value')).removeClass('show d-md-block'); 444 }); 445 446 $('.variations .selectpicker') 447 .on('show.bs.select', function () { 448 let selectPicker = $(this); 449 $(this).parent().find('li .variation') 450 .on('mouseenter', function (e) { 451 setTimeoutConst = setTimeout(function () { 452 let mainImageHeight = $('.js-gallery-images').innerHeight(); 453 let selectOptionValue = selectPicker.find('option').eq( 454 e.currentTarget.ariaPosInSet 455 ).data("value"); 456 $('.variation-image-preview.vt' + selectOptionValue) 457 .addClass('show d-md-block') 458 .css('top', $(e.currentTarget).offset().top - $(e.currentTarget).closest('#content').position().top - mainImageHeight / 2 - 12); 459 }, delay) 460 }) 461 .on('mouseleave', function (e) { 462 clearTimeout(setTimeoutConst); 463 let selectOptionValue = selectPicker.find('option').eq( 464 e.currentTarget.ariaPosInSet 465 ).data("value"); 466 $('.variation-image-preview.vt' + selectOptionValue) 467 .removeClass('show d-md-block'); 468 }); 469 }) 470 .on('hide.bs.select', function () { 471 $(this).parent().find('li .variation').off('mouseenter mouseleave'); 472 $('.variation-image-preview').removeClass('show'); 473 }); 474 }, 475 476 registerImageSwitch: function($wrapper) { 477 var that = this, 478 imgSwitch, 479 gallery = this.gallery; 480 481 if (gallery !== null) { 482 imgSwitch = function (context, temporary, force) { 483 var $context = $(context), 484 id = $context.attr('data-key'), 485 value = $context.attr('data-value'), 486 data = $context.data('list'), 487 title = $context.attr('data-title'); 488 489 if (typeof temporary === 'undefined') { 490 temporary = true; 491 } 492 493 if ((!$context.hasClass('active') || force) && !!data) { 494 gallery.setItems([data], value); 495 496 if (!temporary) { 497 var items = [data], 498 stacks = gallery.getStacks(); 499 for (var s in stacks) { 500 if (stacks.hasOwnProperty(s) && s.match(/^_[0-9a-zA-Z]*$/) && s !== '_' + id) { 501 items = $.merge(items, stacks[s]); 502 } 503 } 504 505 gallery.setItems([data], '_' + id); 506 gallery.setItems(items, '__'); 507 gallery.render('__'); 508 509 that.galleryIndex = gallery.index; 510 that.galleryLastIdent = gallery.ident; 511 } else { 512 gallery.render(value); 513 } 514 } 515 } 516 } else { 517 imgSwitch = function (context, temporary) { 518 var $context = $(context), 519 value = $context.attr('data-value'), 520 data = $context.data('list'), 521 title = $context.attr('data-title'); 522 523 if (typeof temporary === 'undefined') { 524 temporary = true; 525 } 526 527 if (!!data) { 528 var $wrapper = $(context).closest('.product-wrapper'), 529 $img = $('.image-box img', $wrapper); 530 if ($img.length === 1) { 531 $img.attr('src', data.md.src); 532 if (!temporary) { 533 $img.data('src', data.md.src); 534 } 535 } 536 } 537 }; 538 } 539 540 $('.variations .bootstrap-select select', $wrapper) 541 .on('change', function() { 542 var sel = $(this).find('[value=' + this.value + ']'), 543 cont = $(this).closest('.variations'); 544 545 if (cont.hasClass('simple-variations')) { 546 imgSwitch(sel, false, false); 547 } else { 548 imgSwitch(sel, true, false); 549 } 550 }); 551 552 if (!isTouchCapable() || ResponsiveBootstrapToolkit.current() !== 'xs') { 553 $('.variations .bootstrap-select .dropdown-menu li', $wrapper) 554 .on('hover', function () { 555 var tmp_idx = parseInt($(this).attr('data-original-index')) + 1, 556 rule = 'select option:nth-child(' + tmp_idx + ')', 557 sel = $(this).closest('.bootstrap-select').find(rule); 558 imgSwitch(sel); 559 }, function () { 560 var tmp_idx = parseInt($(this).attr('data-original-index')) + 1, 561 rule = 'select option:nth-child(' + tmp_idx + ')', 562 sel = $(this).closest('.bootstrap-select').find(rule), 563 gallery = that.gallery, 564 active; 565 566 if (gallery !== null) { 567 active = $(sel).find('.variation.active'); 568 gallery.render(that.galleryLastIdent); 569 gallery.activate(that.galleryIndex); 570 } else { 571 var $wrapper = $(sel).closest('.product-wrapper'), 572 $img = $('.image-box img', $wrapper); 573 if ($img.length === 1) { 574 $img.attr('src', $img.data('src')); 575 } 576 } 577 }); 578 } 579 580 $('.variations.simple-variations .variation', $wrapper) 581 .on('click', function () { 582 imgSwitch(this, false); 583 }); 584 585 if (!isTouchCapable() || ResponsiveBootstrapToolkit.current() !== 'xs') { 586 $('.variations .variation', $wrapper) 587 .on('hover', function () { 588 imgSwitch(this); 589 }, function () { 590 var sel = $(this).closest('.variation'), 591 gallery = that.gallery; 592 593 if (gallery !== null) { 594 gallery.render(that.galleryLastIdent); 595 gallery.activate(that.galleryIndex); 596 } else { 597 var $wrapper = $(sel).closest('.product-wrapper'), 598 $img = $('.image-box img', $wrapper); 599 if ($img.length === 1) { 600 $img.attr('src', $img.data('src')); 601 } 602 } 603 }); 604 } 605 }, 606 607 registerImageHover: function($wrapper) { 608 const findCollapse = function(container) { 609 return container.find('.productbox-variations > .collapse, .productbox-variations > .collapsing'); 610 }; 611 612 const forceCompleteTransition = function(collapse) { 613 if (collapse.hasClass('collapsing')) { 614 collapse.trigger('bsTransitionEnd'); 615 } 616 }; 617 618 const reserveSpace = function(box) { 619 let $productWrapper = box.closest('.product-wrapper'); 620 let isLastInRow = $productWrapper.is(':last-child') 621 || $productWrapper.next('.product-wrapper').length === 0; 622 if (!isLastInRow) { 623 return; 624 } 625 // Only measure while the box is still in the normal flow. Once it is 626 // absolutely positioned (focus/transition) the wrapper collapses and 627 // would yield a near-zero height, so we fall back to the cached value. 628 let reserved = $productWrapper.data('reservedHeight'); 629 if (!box.hasClass('focus') && !box.hasClass('transition')) { 630 reserved = $productWrapper.outerHeight(); 631 $productWrapper.data('reservedHeight', reserved); 632 } 633 if (reserved) { 634 $productWrapper.css('min-height', reserved + 'px'); 635 } 636 }; 637 638 const closeProductboxVariations = function(box) { 639 let collapse = findCollapse(box); 640 let $productWrapper = box.closest('.product-wrapper'); 641 box.removeClass('focus'); 642 643 if (collapse.length === 1) { 644 forceCompleteTransition(collapse); 645 646 if (collapse.hasClass('show')) { 647 box.addClass('transition'); 648 collapse.collapse('hide'); 649 collapse.off('hidden.bs.collapse').one('hidden.bs.collapse', function () { 650 if (box.hasClass('focus')) { 651 return; 652 } 653 box.removeClass('transition'); 654 $productWrapper.css('min-height', ''); 655 }); 656 } else { 657 box.removeClass('transition'); 658
658 $productWrapper.css('min-height', ''); 659 } 660 } else { 661 $productWrapper.css('min-height', ''); 662 } 663 }; 664 665 $('.product-list .productbox-hover:not(.focus), .product-list .productbox-show-variations:not(.focus)', 666 $wrapper).on('mouseenter focusin', function () { 667 $(this).closest('.product-list').find('.focus').not(this).removeClass('focus'); 668 }); 669 $('.productbox-show-variations', $wrapper).on('mouseenter focusin', function () { 670 let $box = $(this); 671 let collapse = findCollapse($box); 672 673 let closeTimer = $box.data('closeTimer'); 674 if (closeTimer) { 675 clearTimeout(closeTimer); 676 $box.removeData('closeTimer'); 677 } 678 679 reserveSpace($box); 680 681 if (!$box.hasClass('focus')) { 682 $box.addClass('focus'); 683 forceCompleteTransition(collapse); 684 collapse.collapse('show'); 685 } 686 }); 687 $('.productlist-page-nav', $wrapper).on('focusin', function () { 688 $('.productbox-show-variations.focus', $wrapper).removeClass('focus'); 689 }); 690 $('.productbox-show-variations', $wrapper).on('mouseleave', function () { 691 let $box = $(this); 692 let closeTimer = setTimeout(function () { 693 $box.removeData('closeTimer'); 694 closeProductboxVariations($box); 695 }, 100); 696 $box.data('closeTimer', closeTimer); 697 }); 698 if (isTouchCapable()) { 699 $(document).on('touchstart', function (e) { 700 if (!$(e.target).closest('.productbox-show-variations').length) { 701 $('.productbox-show-variations.focus', $wrapper).each(function () { 702 closeProductboxVariations($(this)); 703 }); 704 } 705 }); 706 } 707 $('.is-mobile .show-variation-collapse a').on('click', function (e) { 708 if (!$(this).closest('.show-variation-collapse').find('.collapse').hasClass('show')) { 709 e.preventDefault(); 710 } 711 }); 712 }, 713 714 registerFinish: function($wrapper) { 715 let tabs = ['votes', 'guarantee'] 716 $.each(tabs, function(i, tab) { 717 $('#jump-to-' + tab + '-tab', $wrapper).on('click', function () { 718 let $tabID = $('#content a[href="#tab-' + tab + '"]'); 719 if ($tabID.length > 0) { 720 $tabID.tab('show'); 721 } else { 722 $tabID = $('#tab-' + tab); 723 $tabID.collapse('show'); 724 } 725 726 $([document.documentElement, document.body]).animate({ 727 scrollTop: $tabID.offset().top 728 }, 200); 729 }); 730 }); 731 let $tabID = $('#product-tabs a[href="' + window.location.hash + '"]'); 732 if ($tabID.length) { 733 $tabID.tab('show'); 734 $([document.documentElement, document.body]).animate({ 735 scrollTop: $tabID.offset().top 736 }, 200); 737 } 738 739 if (this.isSingleArticle()) { 740 if ($('.switch-variations .form-group', $wrapper).length === 1) { 741 var wrapper = '#' + $($wrapper).attr('id'); 742 this.variationSwitch($('.switch-variations', $wrapper), false, wrapper); 743 } 744 } 745 else { 746 var that = this; 747 748 $('.product-cell.hover-enabled') 749 .on('click', function (event) { 750 if (isTouchCapable() && ResponsiveBootstrapToolkit.current() !== 'xs') { 751 var $this = $(this); 752 753 if (!$this.hasClass('active')) { 754 event.preventDefault(); 755 event.stopPropagation(); 756 $('.product-cell').removeClass('active'); 757 $this.addClass('active'); 758 } 759 } 760 }) 761 .on('mouseenter', function (event) { 762 var $this = $(this), 763 wrapper = '#' + $this.attr('id'); 764 765 if (!$this.data('varLoaded') && $('.switch-variations .form-group', $this).length === 1) { 766 that.variationSwitch($('.switch-variations', $this), false, wrapper); 767 } 768 $this.data('varLoaded', true); 769 }); 770 } 771 772 this.registerProductActions($('#sidepanel_left')); 773 this.registerProductActions($('#footer')); 774 this.registerProductActions($('#shop-nav')); 775 this.registerProductActions($wrapper); 776 this.registerProductActions('#cart-form'); 777 }, 778 779 registerProductActions: function($wrapper) { 780 var that = this; 781 782 $('*[data-toggle="product-actions"] button', $wrapper) 783 .on('click', function(event) { 784 var data = $(this.form).serializeObject(); 785 786 if ($wrapper === '#cart-form') { 787 data.wlPos = $(this).data('wl-pos'); 788 data.a = $(this).data('product-id-wl'); 789 } 790 791 if (that.handleProductAction(this, data)) { 792 event.preventDefault(); 793 } 794 }); 795 $('a[data-toggle="product-actions"]', $wrapper) 796 .on('click', function(event) { 797 var data = $(this).data('value'); 798 this.name = $(this).data('name'); 799 800 if (that.handleProductAction(this, data)) { 801 event.preventDefault(); 802 } 803 }); 804 }, 805
806 loadModalArticle: function(url, wrapper, done, fail) { 807 var that = this, 808 id = wrapper.slice(1), 809 $modalBody = $('.modal-body', this.modalView); 810 811 $.ajax(url, {data: {'isAjax':1, 'quickView':1}}) 812 .done(function(data) { 813 var $html = $('<div />').html(data); 814 var $headerCSS = $html.find('link[type="text/css"]'); 815 var $headerJS = $html.find('script[src][src!=""]'); 816 var content = $html.find(that.options.modal.wrapper).html(); 817 818 $headerCSS.each(function (pos, item) { 819 var $cssLink = $('head link[href="' + item.href + '"]'); 820 if ($cssLink.length === 0) { 821 $('head').append('<link rel="stylesheet" type="text/css" href="' + item.href + '" >'); 822 } 823 }); 824 825 $headerJS.each(function (pos, item) { 826 if (typeof item.src !== 'undefined' && item.src.length > 0) { 827 var $jsLink = $('head script[src="' + item.src + '"]'); 828 if ($jsLink.length === 0) { 829 $('head').append('<script defer src="' + item.src + '" >'); 830 } 831 } 832 }); 833 834 $modalBody.html($('<div id="' + id + '" />').html(content)); 835 836 var $modal = $modalBody.closest(".modal-dialog"), 837 title = $modal.find('.modal-body h1'), 838 $config = $('#product-configurator', $modalBody); 839 840 if ($config.length > 0) { 841 // Configurator in child article!? Currently not supported! 842 $config.remove(); 843 $.evo.extended().startSpinner($modalBody); 844 location.href = url; 845 } 846 if (title.length > 0 && title.text().length > 0) { 847 $modal.find('.modal-title').text(title.text()); 848 title.remove(); 849 } 850 851 $('form', $modalBody).on('submit', function(event) { 852 event.preventDefault(); 853 854 var $form = $(this); 855 var data = $form.serializeObject(); 856 if (data['VariKindArtikel']) { 857 data['a'] = data['VariKindArtikel']; 858 } 859 860 $.evo.basket().addToBasket($form, data); 861 that.modalView.modal('hide'); 862 }); 863 864 if (typeof done === 'function') { 865 done(); 866 } 867 }) 868 .fail(function() { 869 if (typeof fail === 'function') { 870 fail(); 871 } 872 }) 873 .always(function() { 874 $.evo.extended().stopSpinner(); 875 }); 876 }, 877 878 addToComparelist: function(data, $action) { 879 var productId = parseInt(data[this.options.input.id]); 880 var childId = parseInt(data[this.options.input.childId]); 881 if (childId > 0) { 882 productId = childId; 883 } 884 if (productId > 0) { 885 var that = this; 886 $.evo.io().call('pushToComparelist', [productId], that, function(error, data) { 887 if (error) { 888 return; 889 } 890 891 var response = data.response; 892 893 if (response) { 894 switch (response.nType) { 895 case 0: // error 896 var errorlist = '<ul><li>' + response.cHints.join('</li><li>') + '</li></ul>'; 897 eModal.alert({ 898 title: response.cTitle, 899 message: errorlist, 900 keyboard: true, 901 tabindex: -1,
902 buttons: false 903 }); 904 break; 905 case 1: // forwarding 906 window.location.href = response.cLocation; 907 break; 908 case 2: // added to comparelist 909 that.updateComparelist(response); 910 break; 911 } 912 } 913 }); 914 915 return true; 916 } 917 918 return false; 919 }, 920 921 removeFromCompareList: function(data) { 922 var productId = parseInt(data[this.options.input.id]); 923 if (productId > 0) { 924 var that = this; 925 $.evo.io().call('removeFromComparelist', [productId], that, function(error, data) { 926 if (error) { 927 return; 928 } 929 930 var response = data.response; 931 932 if (response) { 933 switch (response.nType) { 934 case 0: // error 935 var errorlist = '<ul><li>' + response.cHints.join('</li><li>') + '</li></ul>'; 936 eModal.alert({ 937 title: response.cTitle, 938 message: errorlist, 939 keyboard: true, 940 tabindex: -1,
941 buttons: false 942 }); 943 break; 944 case 1: // forwarding 945 window.location.href = response.cLocation; 946 break; 947 case 2: // removed from comparelist 948 that.updateComparelist(response); 949 break; 950 } 951 } 952 }); 953 954 return true; 955 } 956 957 return false; 958 }, 959 960 updateComparelist: function(data) { 961 var $badgeUpd = $(this.options.selector.navUpdateCompare); 962 963 var badge = $(data.navDropdown); 964 $badgeUpd.html(badge); 965 $(this.options.selector.navBadgeUpdateCompare).html(data.nCount); 966 967 if (data.nCount > 0) { 968 $(this.options.selector.navCompare).removeClass('d-none'); 969 } else { 970 $(this.options.selector.navCompare).addClass('d-none'); 971 $('#nav-comparelist-collapse').removeClass('show'); 972 } 973 if (data.nCount > 1) { 974 $('#nav-comparelist-goto').removeClass('d-none'); 975 } else { 976 $('#nav-comparelist-goto').addClass('d-none'); 977 } 978 this.registerProductActions($('#shop-nav')); 979 980 if (data.productID) { 981 let $action = $('button[data-product-id-cl="' + data.productID + '"]') 982 $action.removeClass("on-list"); 983 $action.next().removeClass("press"); 984 $('.comparelist [data-product-id-cl="' + data.productID + '"]').remove(); 985 } 986 987 for (var ind in data.cBoxContainer) { 988 var $list = $(this.options.selector.boxContainer+ind); 989 990 if ($list.length > 0) { 991 if (data.cBoxContainer[ind].length) { 992 var $boxContent = $(data.cBoxContainer[ind]); 993 this.registerProductActions($boxContent); 994 $list.replaceWith($boxContent).removeClass('d-none'); 995 } else { 996 $list.html('').addClass('d-none'); 997 } 998 } 999 } 1000 }, 1001 1002 addToWishlist: function(data, $action) { 1003 let productId = parseInt(data[this.options.input.id]), 1004 childId = parseInt(data[this.options.input.childId]), 1005 qty = parseFloat(data[this.options.input.quantity]); 1006 if (childId > 0) { 1007 productId = childId; 1008 } 1009 if (isNaN(qty)) { 1010 qty = 1; 1011 } 1012 if (productId > 0) { 1013 var that = this; 1014 $.evo.io().call('pushToWishlist', [productId, qty, data], that, function(error, data) { 1015 if (error) { 1016 $action.closest('form')[0].reportValidity(); 1017 return; 1018 } 1019 if ($action.hasClass('action-tip-animation-b')) { 1020 $action.addClass("on-list"); 1021 $action.next().addClass("press"); 1022 $action.next().next().removeClass("press"); 1023 } 1024 var response = data.response; 1025 1026 if (response) { 1027 switch (response.nType) { 1028 case 0: // error 1029 var errorlist = '<ul><li>' + response.cHints.join('</li><li>') + '</li></ul>'; 1030 eModal.alert({ 1031 title: response.cTitle, 1032 message: errorlist, 1033 keyboard: true, 1034 tabindex: -1,
1035 buttons: false 1036 }); 1037 break; 1038 case 1: // forwarding 1039 window.location.href = response.cLocation; 1040 break; 1041 case 2: // added to wishlist 1042 that.updateWishlist(response); 1043 break; 1044 } 1045 } 1046 }); 1047 1048 return true; 1049 } 1050 1051 return false; 1052 }, 1053 1054 removeFromWishList: function(data) { 1055 var productId = parseInt(data[this.options.input.id]); 1056 if (productId > 0) { 1057 var that = this; 1058 $.evo.io().call('removeFromWishlist', [productId], that, function(error, data) { 1059 if (error) { 1060 return; 1061 } 1062 1063 var response = data.response; 1064 1065 if (response) { 1066 switch (response.nType) { 1067 case 0: // error 1068 var errorlist = '<ul><li>' + response.cHints.join('</li><li>') + '</li></ul>'; 1069 eModal.alert({ 1070 title: response.cTitle, 1071 message: errorlist, 1072 keyboard: true, 1073 tabindex: -1,
1074 buttons: false 1075 }); 1076 break; 1077 case 1: // forwarding 1078 window.location.href = response.cLocation; 1079 break; 1080 case 2: // removed from wishlist 1081 that.updateWishlist(response); 1082 break; 1083 } 1084 } 1085 }); 1086 1087 return true; 1088 } 1089 1090 return false; 1091 }, 1092 1093 updateWishlist: function(data) { 1094 var $navContainerWish = $(this.options.selector.navContainerWish); 1095 var $navBadgeWish = $(this.options.selector.navBadgeWish); 1096 1097 if (data.wlPosRemove) { 1098 let $action = $('button[data-wl-pos="' + data.wlPosRemove + '"]'); 1099 $action.removeClass("on-list"); 1100 $action.next().removeClass("press"); 1101 $action.find('.wishlist-icon').addClass('far').removeClass('fas'); 1102 } 1103 if (data.wlPosAdd) { 1104 let $action = $('button[data-product-id-wl="' + data.productID + '"]'); 1105 $action.attr('data-wl-pos', data.wlPosAdd); 1106 $action.data('wl-pos', data.wlPosAdd); 1107 $action.closest('form').find('input[name="wlPos"]').val(data.wlPosAdd) 1108 $action.find('.wishlist-icon').addClass('fas').removeClass('far'); 1109 } 1110 $.evo.io().call('updateWishlistDropdown', [$navContainerWish, $navBadgeWish], this, function(error, data) { 1111 if (error) { 1112 return; 1113 } 1114 if (data.response.currentPosCount > 0) { 1115 $navBadgeWish.removeClass('d-none'); 1116 } else { 1117 $navBadgeWish.addClass('d-none'); 1118 } 1119 $navContainerWish.html(data.response.content); 1120 $navBadgeWish.html(data.response.currentPosCount); 1121 setClickableRow(); 1122 }); 1123 1124 for (var ind in data.cBoxContainer) { 1125 var $list = $(this.options.selector.boxContainerWish+ind); 1126 if ($list.length > 0) { 1127 if (data.cBoxContainer[ind].length) { 1128 var $boxContent = $(data.cBoxContainer[ind]); 1129 this.registerProductActions($boxContent); 1130 $list.replaceWith($boxContent).removeClass('d-none'); 1131 } else { 1132 $list.html('').addClass('d-none'); 1133 } 1134 } 1135 } 1136 }, 1137 1138 handleProductAction: function(action, data) { 1139 let $action = $(action); 1140 switch (action.name) { 1141 case this.options.action.compareList: 1142 if ($action.hasClass('action-tip-animation-b')) { 1143 if ($action.hasClass('on-list')) { 1144 $action.removeClass("on-list"); 1145 $action.next().removeClass("press"); 1146 $action.next().next().addClass("press"); 1147 return this.removeFromCompareList(data); 1148 } else { 1149 $action.addClass("on-list"); 1150 $action.next().addClass("press"); 1151 $action.next().next().removeClass("press"); 1152 $(this.options.selector.navCompare).removeClass('d-none'); 1153 1154 let $moveTo = isMobileByBodyClass() 1155 ? $('.wish-compare-animation-mobile #burger-menu') 1156 : $('.wish-compare-animation-desktop #shop-nav-compare'); 1157 $.evo.article().moveItemAnimation($action, $moveTo); 1158 1159 return this.addToComparelist(data, $action); 1160 } 1161 } else { 1162 return this.addToComparelist(data, $action); 1163 } 1164 case this.options.action.compareListRemove: 1165 return this.removeFromCompareList(data); 1166 case this.options.action.wishList: 1167 data[this.options.input.quantity] = $('input[data-product-id="' + data.a + '"]').val() 1168 || $('#buy_form_'+data.a+' '+this.options.selector.quantity).val() 1169 || $('#quantity').val(); 1170 if ($action.hasClass('on-list')) { 1171 $action.removeClass("on-list"); 1172 $action.next().removeClass("press"); 1173 $action.next().next().addClass("press"); 1174 data.a = data.wlPos; 1175 return this.removeFromWishList(data); 1176 } else { 1177 $action.addClass("on-list"); 1178 let $moveTo = isMobileByBodyClass() 1179 ? $('.wish-compare-animation-mobile #burger-menu') 1180 : $('.wish-compare-animation-desktop #shop-nav-wish');
1181 $.evo.article().moveItemAnimation($action, $moveTo); 1182 return this.addToWishlist(data, $action); 1183 } 1184 case this.options.action.wishListRemove: 1185 return this.removeFromWishList(data); 1186 } 1187 1188 return false; 1189 }, 1190 1191 configurator: function(init) { 1192 if (this.isSingleArticle()) { 1193 var that = this, 1194 container = $('#cfg-container'), 1195 sidebar = $('#cfg-sticky-sidebar'), 1196 width, 1197 form; 1198 1199 if (container.length === 0) { 1200 return; 1201 } 1202 1203 $.evo.extended().startSpinner(container); 1204 1205 $('#buy_form').find('*[data-selected="true"]') 1206 .attr('checked', true) 1207 .attr('selected', true) 1208 .attr('data-selected', null); 1209 1210 form = $.evo.io().getFormValues('buy_form'); 1211 1212 $.evo.io().call('buildConfiguration', [form], that, function (error, data) { 1213 var result, 1214 i, 1215 j, 1216 item, 1217 cBeschreibung, 1218 quantityWrapper, 1219 grp, 1220 value, 1221 enableQuantity, 1222 nNetto, 1223 quantityInput; 1224 $('.js-start-configuration').prop('disabled', !(data.response.variationsSelected && data.response.inStock)); 1225 $('.js-choose-variations-wrapper').toggleClass('d-none', data.response.variationsSelected); 1226 $('.js-cfg-group').each(function (i, item) { 1227 let iconChecked = $('a[href="#'+this.id+'"] .js-group-checked'), 1228 badgeInfoDanger = 'alert-info'; 1229 if (data.response.invalidGroups && data.response.invalidGroups.includes($(this).data('id'))) { 1230 iconChecked.addClass('d-none'); 1231 if ($(this).hasClass('visited')) { 1232 badgeInfoDanger = 'alert-danger'; 1233 } 1234 $(this).find('.js-group-badge-checked') 1235 .removeClass('alert-success alert-info') 1236 .addClass(badgeInfoDanger); 1237 } else { 1238 iconChecked.removeClass('d-none'); 1239 $(this).find('.js-group-badge-checked') 1240 .addClass('alert-success') 1241 .removeClass('alert-danger alert-info'); 1242 } 1243 }); 1244 $('.js-cfg-group-error').addClass('d-none').html(''); 1245 $.each(data.response.errorMessages, function (i, item) { 1246 $('.js-cfg-group-error[data-id="' + item.group + '"]').removeClass('d-none').html(item.message); 1247 }); 1248 let $summaryFinish = $('#cfg-tab-summary-finish'); 1249 if (data.response.valid) { 1250 $('.js-cfg-validate').prop('disabled', false); 1251 $summaryFinish.children().removeClass('disabled'); 1252 $summaryFinish.removeClass('disabled'); 1253 } else { 1254 $('.js-cfg-validate').prop('disabled', true); 1255 $summaryFinish.children().addClass('disabled'); 1256 $summaryFinish.addClass('disabled'); 1257 } 1258 $.evo.extended().stopSpinner(); 1259 if (error) { 1260 $.evo.error(data); 1261 return; 1262 } 1263 result = data.response; 1264 1265 if (!result.oKonfig_arr) { 1266 $.evo.error('Missing configuration groups'); 1267 return; 1268 } 1269 1270 // global price 1271 nNetto = result.nNettoPreise; 1272 that.setPrice(result.fGesamtpreis[nNetto], result.cPreisLocalized[nNetto], result.cPreisString); 1273 if (result.fAlterPreis && result.cAlterPreisLocalized) { 1274 that.setOldPrice( 1275 result.fAlterPreis[nNetto], 1276 result.cAlterPreisLocalized[nNetto], 1277 result.nAlterPreisDiscountPercent || 0 1278 ); 1279 } 1280 that.setStockInformation(result.cEstimatedDelivery, undefined, result.Lageranzeige && result.Lageranzeige.nStatus, result.Lageranzeige && (result.Lageranzeige.AmpelText || '')); 1281 1282 $('#content .summary').html(result.cTemplate); 1283 $.evo.tooltips(); 1284 $.evo.extended() 1285 .trigger('priceChanged', result); 1286 }); 1287 } 1288 }, 1289 1290 initConfigListeners: function () { 1291 $('.js-cfg-group').on('click', function () { 1292 $(this).addClass('visited'); 1293 }); 1294 $('#cfg-tab-summary-finish').on('click', function () { 1295 if (!$(this).hasClass('disabled')) { 1296 $('#cfg-modal-tabs').find('.nav-link').removeClass('active'); 1297 $('#cfg-tab-summary').children().addClass('active'); 1298 $(this).children().removeClass('active'); 1299 } 1300 }); 1301 $('.js-cfg-group-collapse').on('click', function () { 1302 $(this).addClass('visited'); 1303 }); 1304 }, 1305 1306 variationRefreshAll: function($wrapper) { 1307 $('.variations select', $wrapper).selectpicker('refresh'); 1308 $.evo.initSliders() 1309 }, 1310 1311 getConfigGroupQuantity: function (groupId) { 1312 return $('.cfg-group[data-id="' + groupId + '"] .quantity'); 1313 }, 1314 1315 getConfigGroupQuantityInput: function (groupId) { 1316 return $('.cfg-group[data-id="' + groupId + '"] .quantity input'); 1317 }, 1318 1319 getConfigGroupImage: function (groupId) { 1320 return $('.cfg-group[data-id="' + groupId + '"] .group-image img'); 1321 }, 1322 1323 setConfigItemImage: function (groupId, img) { 1324 $('.cfg-group[data-id="' + groupId + '"] .group-image img').attr('src', img).first(); 1325 }, 1326 1327 setConfigItemDescription: function (groupId, itemBeschreibung) { 1328 var groupItems = $('.cfg-group[data-id="' + groupId + '"] .group-items'); 1329 var descriptionDropdownContent = groupItems.find('#filter-collapsible_dropdown_' + groupId + ''); 1330 var descriptionDropdownContentHidden = groupItems.find('.d-none'); 1331 var descriptionCheckdioContent = groupItems.find('div[id^="filter-collapsible_checkdio"]'); 1332 var multiselect = groupItems.find('select').attr("multiple"); 1333 1334 // Bisher kein Content mit einer Beschreibung vorhanden, aber ein Artikel mit Beschreibung ausgewählt 1335 if (descriptionDropdownContentHidden.length > 0 && descriptionCheckdioContent.length === 0 && itemBeschreibung.length > 0 && multiselect !== "multiple") { 1336 groupItems.find('a[href="#filter-collapsible_dropdown_' + groupId + '"]').removeClass('d-none'); 1337 descriptionDropdownContent.replaceWith('<div id="filter-collapsible_dropdown_' + groupId + '" class="collapse top10 panel-body">' + itemBeschreibung + '</div>'); 1338 // Bisher Content mit einer Beschreibung vorhanden, aber ein Artikel ohne Beschreibung ausgewählt 1339 } else if (descriptionDropdownContentHidden.length === 0 && descriptionCheckdioContent.length === 0 && itemBeschreibung.length === 0 && multiselect !== "multiple") { 1340 groupItems.find('a[href="#filter-collapsible_dropdown_' + groupId + '"]').addClass('d-none'); 1341 descriptionDropdownContent.addClass('d-none'); 1342 // Bisher Content mit einer Beschreibung vorhanden und ein Artikel mit Beschreibung ausgewählt 1343 } else if (descriptionDropdownContentHidden.length === 0 && descriptionCheckdioContent.length === 0 && itemBeschreibung.length > 0 && multiselect !== "multiple") { 1344 descriptionDropdownContent.replaceWith('<div id="filter-collapsible_dropdown_' + groupId + '" class="collapse top10 panel-body">' + itemBeschreibung + '</div>'); 1345 } 1346 }, 1347 1348 setPrice: function(price, fmtPrice, priceLabel, wrapper) { 1349 var $wrapper = this.getWrapper(wrapper); 1350 1351 if (this.isSingleArticle()) { 1352 $('#product-offer .price', $wrapper).html(fmtPrice); 1353 $('#product-offer meta[itemprop="price"]', $wrapper).attr('content',price); 1354 if (priceLabel.length > 0) { 1355 $('#product-offer .price_label', $wrapper).html(priceLabel); 1356 } 1357 } else { 1358 var $price = $('.price_wrapper', $wrapper); 1359 1360 $('.price span:first-child', $price).html(fmtPrice); 1361 if (priceLabel.length > 0) { 1362 $('.price_label', $price).html(priceLabel); 1363 } 1364 } 1365 1366 $.evo.trigger('changed.article.price', { price: price }); 1367 }, 1368 1369 setStockInformation: function(cEstimatedDelivery, wrapper, nStatus, ampelText) { 1370 let $wrapper = this.getWrapper(wrapper); 1371 let $span = $('.delivery-status .estimated-delivery span', $wrapper); 1372 1373 $span.html(cEstimatedDelivery); 1374 1375 if (typeof nStatus !== 'undefined' && nStatus !== false) { 1376 $span.removeClass('a0 a1 a2').addClass('a' + nStatus); 1377 1378 let $statusSpan = $('.delivery-status .status', $wrapper); 1379 $statusSpan.removeClass('status-0 status-1 status-2').addClass('status-' + nStatus); 1380 if (typeof ampelText !== 'undefined' && ampelText !== false && ampelText !== '') { 1381 let $icon = $statusSpan.find('.status-icon').detach(); 1382 $statusSpan.html(ampelText).prepend($icon); 1383 } 1384 } 1385 }, 1386 1387 setOldPrice: function(price, fmtPrice, discountPercent, wrapper) { 1388 let $wrapper = this.getWrapper(wrapper), 1389 $container = $('#product-offer', $wrapper); 1390 1391 if (this.isSingleArticle()) { 1392 let $oldPriceDetail = $('.old-price-dynamic', $container); 1393 if (price > 0 && fmtPrice.length > 0) { 1394 if ($oldPriceDetail.length > 0) { 1395 $oldPriceDetail.find('.old-price-value').html(fmtPrice); 1396 $oldPriceDetail.removeClass('d-none'); 1397 } else { 1398 let $staticOldPrice = $('.old-price-dynamic .old-price-value, .old-price .old-price-value', $container); 1399 if ($staticOldPrice.length > 0) { 1400 $staticOldPrice.html(fmtPrice); 1401 $staticOldPrice.closest('.old-price-dynamic, .old-price').removeClass('d-none'); 1402 } 1403 } 1404 if (discountPercent > 0) { 1405 $('.discount-dynamic .discount-percent', $container).html(discountPercent + '%'); 1406 $('.discount-dynamic', $container).removeClass('d-none'); 1407 } else { 1408 $('.discount-dynamic', $container).addClass('d-none'); 1409 } 1410 } else { 1411 $oldPriceDetail.addClass('d-none'); 1412 $('.discount-dynamic', $container).addClass('d-none'); 1413 $('.old-price-dynamic, .old-price', $container) 1414 .not('.old-price-dynamic') 1415 .addClass('d-none'); 1416 } 1417 } else { 1418 let $priceWrapper = $('.price_wrapper', $wrapper); 1419 let $oldPriceList = $('.old-price', $priceWrapper); 1420 if (price > 0 && fmtPrice.length > 0) { 1421 if ($oldPriceList.length > 0) { 1422 $oldPriceList.find('.old-price-value, .value').html(fmtPrice); 1423 $oldPriceList.removeClass('d-none'); 1424 } 1425 } else { 1426 $oldPriceList.addClass('d-none'); 1427 } 1428 } 1429 1430 $.evo.trigger('changed.article.oldprice', { price: price, discountPercent: discountPercent }); 1431 }, 1432 1433 setStaffelPrice: function(prices, fmtPrices, wrapper) { 1434 var $wrapper = this.getWrapper(wrapper), 1435 $container = $('#product-offer', $wrapper); 1436 1437 $.each(fmtPrices, function(index, value){ 1438 $('.bulk-price-' + index + ' .bulk-price', $container).html(value); 1439 }); 1440 }, 1441
1442 setVPEPrice: function(fmtVPEPrice, VPEPrices, fmtVPEPrices, wrapper) { 1443 let $wrapper = this.getWrapper(wrapper); 1444 if ($('#product-offer').length > 0) { 1445 $wrapper = $('#product-offer', $wrapper); 1446 } 1447 1448 $('.base-price .value', $wrapper).html(fmtVPEPrice); 1449 $.each(fmtVPEPrices, function(index, value){ 1450 $('.bulk-price-' + index + ' .bulk-base-price', $wrapper).html(value); 1451 }); 1452 }, 1453 1454 /** 1455 * @deprecated since 4.05 - use setArticleWeight instead 1456 */ 1457 setUnitWeight: function(UnitWeight, newUnitWeight) { 1458 $('#article-tabs .product-attributes .weight-unit').html(newUnitWeight); 1459 }, 1460 1461 setArticleWeight: function(ArticleWeight, wrapper) { 1462 if (this.isSingleArticle()) { 1463 var $articleTabs = $('#article-tabs'); 1464 1465 if ($.isArray(ArticleWeight)) { 1466 $('.product-attributes .weight-unit', $articleTabs).html(ArticleWeight[0][1]); 1467 $('.product-attributes .weight-unit-article', $articleTabs).html(ArticleWeight[1][1]); 1468 } else { 1469 $('.product-attributes .weight-unit', $articleTabs).html(ArticleWeight); 1470 } 1471 } else { 1472 var $wrapper = this.getWrapper(wrapper); 1473 1474 if ($.isArray(ArticleWeight)) { 1475 $('.attr-weight .value', $wrapper).html(ArticleWeight[0][1]); 1476 $('.attr-weight.weight-unit-article .value', $wrapper).html(ArticleWeight[1][1]); 1477 } else { 1478 $('.attr-weight .value', $wrapper).html(ArticleWeight); 1479 } 1480 } 1481 1482 }, 1483 1484 setProductNumber: function(productNumber, wrapper) { 1485 var $wrapper = this.getWrapper(wrapper); 1486 1487 $('#product-offer span[itemprop="sku"]', $wrapper).html(productNumber); 1488 }, 1489 1490 setArticleContent: function(id, variation, url, variations, wrapper) { 1491 var $wrapper = this.getWrapper(wrapper), 1492 listStyle = $('#product-list-type').val(); 1493 1494 if (listStyle === 'undefined') { 1495 listStyle = $('#ed_list.active').length > 0 ? 'list' : 'gallery'; 1496 } 1497 1498 $.evo.extended().startSpinner($wrapper); 1499 1500 if (this.modalShown) { 1501 this.loadModalArticle(url, wrapper, 1502 function() { 1503 var article = new ArticleClass(); 1504 article.register(wrapper); 1505 $.evo.extended().stopSpinner(); 1506 }, 1507 function() { 1508 $.evo.extended().stopSpinner(); 1509 $.evo.error('Error loading ' + url); 1510 } 1511 ); 1512 } else if (this.isSingleArticle()) { 1513 if($('#opc-startmenu').length > 0) { 1514 return this.redirectToArticle(id, variation, url, variations, wrapper); 1515 } 1516 1517 $.evo.extended().loadContent(url, () => { 1518 $.evo.extended().register(); 1519 $.evo.article().register(wrapper); 1520 1521 $(variations).each(function (i, item) { 1522 $.evo.article().variationSetVal(item.key, item.value, wrapper); 1523 }); 1524 1525 if (document.location.href !== url) { 1526 history.pushState({a: id, a2: variation, url: url, variations: variations}, "", url); 1527 } 1528 $.evo.extended().stopSpinner(); 1529 }, function () { 1530 $.evo.error('Error loading ' + url); 1531 $.evo.extended().stopSpinner(); 1532 }, false, wrapper); 1533 } else { 1534 $.evo.extended().loadContent(url + (url.indexOf('?') >= 0 ? '&' : '?') + 'isListStyle=' + listStyle, function (content) { 1535 $.evo.article().register(wrapper); 1536 1537 $('[data-toggle="basket-add"]', $(wrapper)).on('submit', function(event) { 1538 event.preventDefault(); 1539 event.stopPropagation(); 1540 1541 var $form = $(this); 1542 var data = $form.serializeObject(); 1543 data['a'] = variation; 1544 1545 $.evo.basket().addToBasket($form, data); 1546 }); 1547 1548 $(variations).each(function (i, item) {
1549 $.evo.article().variationSetVal(item.key, item.value, wrapper); 1550 }); 1551 1552 $.evo.extended().stopSpinner(); 1553 }, function () { 1554 $.evo.error('Error loading ' + url); 1555 $.evo.extended().stopSpinner(); 1556 }, false, wrapper); 1557 } 1558 }, 1559 1560 redirectToArticle: function(id, variation, url, variations, wrapper) { 1561 var $wrapper = this.getWrapper(wrapper), 1562 listStyle = $('#product-list-type').val(); 1563 1564 $.evo.extended().startSpinner($wrapper); 1565 1566 window.open(url, '_top'); 1567 1568 $.evo.extended().stopSpinner($wrapper); 1569 }, 1570 1571 variationResetAll: function(wrapper) { 1572 var $wrapper = this.getWrapper(wrapper); 1573 1574 $('.variation[data-value] input:checked', $wrapper).prop('checked', false); 1575 $('.variations select option', $wrapper).prop('selected', false); 1576 $('.variations select', $wrapper).selectpicker('refresh'); 1577 }, 1578 1579 variationDisableAll: function(wrapper) { 1580 let $wrapper = this.getWrapper(wrapper); 1581 1582 $('.swatches-selected', $wrapper).text(''); 1583 $('[data-value].variation', $wrapper).each(function(i, item) { 1584 $(item) 1585 .removeClass('active loading') 1586 .addClass('not-available'); 1587 $.evo.article() 1588 .removeStockInfo($(item)); 1589 }); 1590 }, 1591 1592 variationSetVal: function(key, value, wrapper) { 1593 var $wrapper = this.getWrapper(wrapper); 1594 1595 $('[data-key="' + key + '"]', $wrapper).val(value); 1596 }, 1597 1598 variationEnable: function(key, value, wrapper) { 1599 var $wrapper = this.getWrapper(wrapper), 1600 $item = $('[data-value="' + value + '"].variation', $wrapper); 1601 1602 $item.removeClass('not-available swatches-sold-out swatches-not-in-stock'); 1603 }, 1604 1605 showGalleryVariation: function(key, wrapper) { 1606 var $wrapper = this.getWrapper(wrapper), 1607 $item = $('.variation-' + key, $wrapper); 1608 1609 $item.collapse(); 1610 }, 1611 1612 variationActive: function(key, value, def, wrapper) { 1613 var $wrapper = this.getWrapper(wrapper), 1614 $item = $('[data-value="' + value + '"].variation', $wrapper); 1615 $item.addClass('active') 1616 .find('input') 1617 .prop('checked', true) 1618 .end() 1619 .prop('selected', true); 1620 1621 $('[data-id="'+key+'"].swatches-selected') 1622 .text($item.attr('data-original')); 1623 }, 1624 1625 removeStockInfo: function($item) { 1626 var type = $item.attr('data-type'), 1627 elem, 1628 label, 1629 wrapper; 1630 1631 switch (type) { 1632 case 'option': 1633 label = $item.data('content'); 1634 wrapper = $('<div />').append(label); 1635 $(wrapper) 1636 .find('.badge-not-available') 1637 .remove(); 1638 label = $(wrapper).html(); 1639 $item.data('content', label) 1640 .attr('data-content', label); 1641 break; 1642 case 'radio': 1643 elem = $item.find('.badge-not-available'); 1644 if (elem.length === 1) { 1645 $(elem).remove(); 1646 } 1647 break; 1648 case 'swatch': 1649 $item.tooltip('dispose'); 1650 break; 1651 } 1652 $item.removeAttr('data-stock'); 1653 }, 1654 1655 variationInfo: function(value, status, note, notExists) { 1656 let $item = $('[data-value="' + value + '"].variation'), 1657 type = $item.attr('data-type'), 1658 text, 1659 content, 1660 $wrapper, 1661 label; 1662 1663 $item.attr('data-stock', _stock_info[status]); 1664 1665 switch (type) { 1666 case 'option': 1667 text = ' (' + note + ')'; 1668 content = $item.data('content');
1669 $wrapper = $('<div />'); 1670 1671 $wrapper.append(content); 1672 $wrapper 1673 .find('.badge-not-available') 1674 .remove(); 1675 1676 label = $('<span />') 1677 .addClass('badge badge-danger badge-not-available') 1678 .text(' '+note); 1679 1680 $wrapper.append(label); 1681 1682 $item.data('content', $wrapper.html()) 1683 .attr('data-content', $wrapper.html()); 1684 1685 $item.closest('select') 1686 .selectpicker('refresh'); 1687 break; 1688 case 'radio': 1689 $item.find('.badge-not-available') 1690 .remove(); 1691 1692 label = $('<span />') 1693 .addClass('badge badge-danger badge-not-available') 1694 .text(' '+note); 1695 1696 $item.append(label); 1697 break; 1698 case 'swatch': 1699 if (!$item.hasClass('gall-preview')) { 1700 $item.tooltip({ 1701 title: note, 1702 trigger: 'hover', 1703 container: 'body' 1704 }); 1705 } 1706 if (notExists) { 1707 $item.addClass('swatches-not-in-stock'); 1708 } else { 1709 $item.addClass('swatches-sold-out'); 1710 } 1711 break; 1712 } 1713 }, 1714 1715 variationSwitch: function($item, animation, wrapper) { 1716 if ($item) { 1717 var formID = $item.closest('form').attr('id'), 1718 $current = this.getCurrent($item), 1719 key = $current.data('key'), 1720 value = $current.data('value'), 1721 io = $.evo.io(), 1722 args = io.getFormValues(formID), 1723 layout = $('#product-list-type').val(), 1724 $wrapper = this.getWrapper(wrapper); 1725 1726 if (animation) { 1727 $.evo.extended().startSpinner(); 1728 } else { 1729 $('.updatingStockInfo', $wrapper).show(); 1730 } 1731 1732 $('.tooltip.show').remove(); 1733 args.wrapper = wrapper; 1734 args.layout = layout; 1735 1736 $.evo.article() 1737 .variationDispose(wrapper); 1738 1739 io.call('checkVarkombiDependencies', [args, key, value], $item, function (error, data) { 1740 if (animation) { 1741 $.evo.extended().stopSpinner(); 1742 } 1743 $('.updatingStockInfo', $wrapper).hide(); 1744 if (error) { 1745 $.evo.error('checkVarkombiDependencies'); 1746 } 1747 }); 1748 } 1749 }, 1750 1751 modalArticleDetail: function(item, wrapper) 1752 { 1753 let $item = $(item); 1754 let title = $item.data('title'); 1755 let url = $item.data('src'); 1756 1757 if (typeof this.modalView === 'undefined' || this.modalView === null) { 1758 this.modalView = $( 1759 '<div id="' + this.options.modal.id + '" class="modal fade" role="dialog" tabindex="-1" >' + 1760 ' <div class="modal-dialog modal-lg">' + 1761 ' <div class="modal-content">' + 1762 ' <div class="modal-header">' + 1763 ' <button type="button" class="x close" data-dismiss="modal"><i class="fa fa-times"></i></button>' + 1764 ' <div class="modal-title h4">' + title + '</div>' + 1765 ' </div>' + 1766 ' <div class="modal-body">' + 1767 ' <div id="' + wrapper.slice(1) + '" style="min-height:100px">' + 1768 '<div class="jtl-spinner"><i class="fa fa-spinner fa-pulse"></i></div>' + 1769 ' </div>' + 1770 ' </div>' + 1771 ' </div>' + 1772 ' </div>' + 1773 '</div>'); 1774 this.modalView 1775 .on('hidden.bs.modal', () => { 1776 $('.modal-body', this.modalView) 1777 .html('<div id="' + wrapper.slice(1) + '" style="min-height:100px" />'); 1778 $('.modal-title', this.modalView).html(''); 1779 this.modalView 1780 .off('shown.bs.modal'); 1781 this.modalShown = false;
1782 }); 1783 } else { 1784 $('.modal-title', this.modalView).html(title); 1785 $('.modal-body', this.modalView) 1786 .html('<div id="' + wrapper.slice(1) + '" style="min-height:100px">' + 1787 '<div class="jtl-spinner"><i class="fa fa-spinner fa-pulse"></i></div></div>'); 1788 } 1789 1790 this.modalView 1791 .on('shown.bs.modal', () => { 1792 this.modalShown = true; 1793 this.loadModalArticle(url, wrapper, 1794 function() { 1795 // no functionality needed in quickview 1796 // var article = new ArticleClass(); 1797 // article.register(wrapper); 1798 $.evo.extended().stopSpinner(); 1799 $('[data-toggle="popover"]', wrapper).popover({ html: true }); 1800 $('.product-image', wrapper).css('cursor', 'default'); 1801 }, 1802 function() { 1803 $.evo.extended().stopSpinner(); 1804 $.evo.error('Error loading ' + params.url); 1805 } 1806 ); 1807 }) 1808 .modal('show'); 1809 }, 1810 1811 variationPrice: function($item, animation, wrapper) { 1812 var formID = $item.closest('form').attr('id'), 1813 $wrapper = this.getWrapper(wrapper), 1814 io = $.evo.io(), 1815 args = io.getFormValues(formID); 1816 1817 if (animation) { 1818 $.evo.extended().startSpinner($wrapper); 1819 } 1820 1821 args.wrapper = wrapper; 1822 io.call('checkDependencies', [args], $(this), function (error, data) { 1823 let $action = $('button[data-product-id-wl="' + data.response.itemID + '"]'); 1824 if (data.response.check > 0) { 1825 $action.attr('data-wl-pos', data.response.check); 1826 $action.data('wl-pos', data.response.check); 1827 $action.closest('form').find('input[name="wlPos"]').val(data.response.check) 1828 $action.addClass('on-list'); 1829 } else { 1830 $action.removeClass('on-list'); 1831 } 1832 1833 if (animation) { 1834 $.evo.extended().stopSpinner(); 1835 } 1836 if (error) { 1837 $.evo.error('checkDependencies'); 1838 } 1839 }); 1840 }, 1841 1842 variationDispose: function(wrapper) { 1843 var $wrapper = this.getWrapper(wrapper); 1844 1845 $('[role="tooltip"]', $wrapper).remove(); 1846 }, 1847 1848 moveItemAnimation: function(item, moveTo) { 1849 if (!item.length || !moveTo.length || $(this).hasClass('on-list')) { 1850 return; 1851 } 1852 setTimeout(function() { 1853 let itemClone = item.clone() 1854 .offset({ 1855 top: item.offset().top, 1856 left: item.offset().left 1857 }).css({ 1858 'opacity': '0.5', 1859 'position': 'absolute', 1860 'z-index': '10000' 1861 }) 1862 .appendTo($('body')) 1863 .animate({ 1864 'top': moveTo.offset().top + 5, 1865 'left': moveTo.offset().left + 5, 1866 }, 700); 1867 1868 itemClone.animate({ 1869 'width': 0, 1870 'height': 0 1871 }, function () { 1872 $(this).detach() 1873 }); 1874 }, 0); 1875 }, 1876 1877 initAbnahmeIntervallError: function() { 1878 let $intervallNotice = $('#intervall-notice'); 1879 if ($intervallNotice.length > 0) { 1880 $('#quantity').on('change', function () { 1881 let $step = $(this).attr('step'), 1882 diff = Math.abs(($(this).val() % $step) - $step), 1883 epsilon = 0.00000001; 1884 $('#intervall-notice-danger').remove(); 1885 if (!(diff < epsilon || diff + epsilon > $step)) { 1886 $('#quantity-grp').after('<div id="intervall-notice-danger" class="alert alert-danger mt-2">' 1887 + $intervallNotice.html() + '</div>'); 1888 } 1889 }); 1890 } 1891 } 1892 }; 1893 1894 $v = new ArticleClass(); 1895 1896 $(document).ready(function () { 1897 $v.onLoad(); 1898 $v.register(); 1899 }); 1900 1901 $(window).on('resize', 1902 viewport.changed(function(){ 1903 $v.configurator(); 1904 }) 1905 ); 1906 1907 // PLUGIN DEFINITION 1908 // ================= 1909 $.evo.article = function () { 1910 return $v; 1911 }; 1912})(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.