1var wpcs_lightbox = null; 2var wpcs_form = null; 3var wpcs_orderbar = null; 4var wpcs_contact_form = null; 5var wpcs_compare = null; 6var wpcs_park = null; 7var wpcs_search_request = null; 8var wpcs_infinite_scroll = null; 9var wpcs_textsearch = null; 10var wpcs_form_elements = null; 11var wpcs_2slides = null; 12 13(function($) { 14 15 $(function() { 16 17 // init Filter Form 18 wpcs_form = new WPCSForm(); 19 20 // init Order Bar 21 if ($('.dxim_ff_order_bar').length > 0) wpcs_orderbar = new WPCSOrderbar(); 22 23 // init Contact Form 24 if ($('.wpcs_contact_form').length > 0) wpcs_contact_form = new WPCSContactForm(); 25 26 // init compare table 27 wpcs_compare = new WPCSCompare(); 28 29 // textsearch 30 //wpcs_textsearch = new WPCSTextSearch(); 31 32 // 33 wpcs_2slides = new WPCS2Slides(); 34 35 // init Search Request 36 wpcs_search_request = new WPCSSearchRequest(); 37 38 // lightbox 39 wpcs_lightbox = new WPCSLightbox(); 40 wpcsInitLightbox(); 41 42 // Park 43 wpcs_park = new WPCSPark(); 44 45 // 46 wpcs_infinite_scroll = new WPCSInfiniteScroll(); 47 48 // 49 wpcs_form_elements = new WPCSFormElements(); 50 51 // WPCSSticky init 52 $('.wpcs_sticky').each(function() { 53 new WPCSSticky(this); 54 }); 55 56 // WPCSScroller init 57 $('.wpcs_scroller').each(function() { 58 new WPCSScroller(this); 59 }); 60 61 // FilterSet buttons 62 new WPCSFilterSet(); 63 64 65 $('.dxim_vehicle_carousel').each(function() { 66 let carousel = this; 67 let title = 0; 68 let data = 0; 69 70 $('.vehicle-on-archive', carousel).each(function() { 71 if ($('.dxim_archive_specifics', this).height() > data) data = $('.dxim_archive_specifics', this).height(); 72 if ($('.title', this).height() > title) title = $('.title', this).height(); 73 }); 74 $('.vehicle-on-archive .title', carousel).css('height', title); 75 $('.vehicle-on-archive .dxim_archive_specifics', carousel).css('height', data); 76 77 }); 78 79 $('a.wpcs_toggle') 80 .click(function(e) { 81 e.preventDefault(); 82 let selector = $(this).data('div'); 83 $(selector).toggleClass('wpcs_hidden'); 84 }); 85 86 $('a.wpcs_toggle_visibility') 87 .click(function(e) { 88 e.preventDefault(); 89 let a = $(this); 90 let selector = a.data('div'); 91 a.toggleClass('active'); 92 if ($(selector).hasClass('wpcs_not_visible_mobile')) { 93 $(selector).removeClass('wpcs_not_visible_mobile'); 94 if ($('body').hasClass('wpcs_mobile')) $(selector).addClass('wpcs_not_visible'); 95 } 96 97 $(selector).toggleClass('wpcs_not_visible'); 98 }); 99 100 // init text searches 101 $('.wpcs_textsearch').each(function() { 102 new WPCSTextSearch(this); 103 }); 104 105 $('[data-wpcs-bind]').each(function() { 106 let selector = $(this).data('wpcs-bind'); 107 let amount = parseInt($(selector).data('amount')); 108 if (amount > 0) { 109 $(this) 110 .html(amount + " ") 111 .removeClass('wpcs_hidden'); 112 } 113 }); 114 115 // 116 add_body_classes() 117 118 }); // domready 119 120 /** 121 * 122 * @constructor 123 */ 124 function WPCS2Slides() { 125 126 this.__construct = function() { 127 $('.wpcs_2slides_container').each(function() { 128 let area_selector = $(this).data('area-selector'); 129 $(area_selector, this).hide(); 130 }); 131 132 $(document).on('click', '.wpcs_2slides_activate', function(e) { 133 e.preventDefault(); 134 let area = $(this).data('area'); 135 let slider = $(this).closest('.wpcs_2slides_container'); 136 let area_selector = slider.data('area-selector'); 137 slider.addClass('active'); 138 $(area_selector + '[data-area="' + area + '"]', slider).show(); 139 }); 140 141 $(document).on('click', '.wpcs_2slides_disable', function(e) { 142 e.preventDefault(); 143 let slider = $(this).closest('.wpcs_2slides_container'); 144 let area_selector = slider.data('area-selector'); 145 slider.removeClass('active'); 146 $(area_selector, slider).hide(); 147 }); 148 } 149 150 this.initItem = function(item) { 151 let area_selector = $(item).data('area-selector'); 152 $(area_selector, item).hide(); 153 } 154 155 this.__construct(); 156 157 } 158 159 160 /** 161 * 162 * @constructor 163 */ 164 function WPCSFormElements() { 165 166 var that = this; 167 168 this._construct = function() { 169 this.initWPCSSelect(); 170 } 171 172 this.initWPCSSelect = function() { 173 $('.wpcsselect.custom').each(function() { 174 let select = $(this); 175 select.wpcsselect({}); 176 }); 177 } 178 179 this._construct(); 180 } 181 182 183 function WPCSTextSearch(textsearch) { 184 185 var that = this; 186 187 this.textsearch = $(textsearch); 188 this.timeout = null; 189 this.loader = $('.wpcs_ajax_loader', this.textsearch); 190 this.textinput = $('.searchInput', this.textsearch); 191 this.close_btn = $('.wpcs_textsearch_reset_btn', this.textsearch); 192 this.results_div = null; 193 194 this._construct = function() { 195 196 let h = this.loader.height(); 197 this.loader.css('margin-top', Math.round(h / 2) * -1); 198 199 let h2 = this.close_btn.height(); 200 this.close_btn.css('margin-top', Math.round(h2 / 2) * -1); 201 202 let target = that.textsearch.data('target'); 203 204 // standard result div 205 this.results_div = $('.' + target, that.textsearch); 206 // target angabe für externen div => muss ID sein 207 if (this.results_div.length < 1) this.results_div = $('#' + target); 208 209 $(that.textinput).keyup(function() { 210 if (that.timeout !== null) window.clearTimeout(that.timeout); 211 212 let val = $(this).val(); 213 if (val.length < 3) return; 214 215 that.setCloseBtnState(); 216 217 that.timeout = window.setTimeout(that._doSearch, 700, val); 218 }); 219 220 this.close_btn.click(function(e) { 221 e.preventDefault(); 222 that.emptyList(); 223 that.textinput.val(""); 224 that.setCloseBtnState(); 225 226 }); 227 } 228 229 /** 230 * 231 * @param val 232 */ 233 this._doSearch = function(val) { 234 that.loader.show(); 235 that.close_btn.hide(); 236 let action = that.textsearch.data('type'); 237 let args = that.textsearch.data('params'); 238 239 $.ajax({
240 method: 'POST', 241 url: wpcs_ajax_url, 242 data: { action: action, searchstring: val, args: args }, 243 success: function(data) { 244 that.loader.hide(); 245 that.setCloseBtnState(); 246 247 if (data.status == "1") { 248 console.log(that.results_div); 249 that.results_div.html(data.html).fadeIn(100); 250 } else if (data.status == "0") { 251 that.emptyList(); 252 } 253 } 254 }); 255 } 256 257 this.emptyList = function() { 258 that.results_div.html(null).fadeOut(150); 259 } 260 261 this.setCloseBtnState = function() { 262 let val = that.textinput.val(); 263 if (val != "") that.close_btn.show(); 264 else that.close_btn.hide(); 265 } 266 267 this._construct(); 268 } 269 270 /** 271 * 272 * @constructor 273 */ 274 function WPCSInfiniteScroll() { 275 var that = this; 276 277 this.__construct = function() { 278 that._initButton(); 279 that._initInfiniteLoader(); 280 $(document).on("wpcs_ajax_form_submitted", that._checkButtonVisibility); 281 } 282 283 284 this._checkButtonVisibility = function() { 285 if ($('#wpcs_pagination_button').length < 1) return; 286 287 if (that._canLoadMore()) $('#wpcs_pagination_button').show(); 288 else $('#wpcs_pagination_button').hide(); 289 } 290 291 /** 292 * prüft ob nachlade button angezeigt werden darf 293 * @private 294 */ 295 this._canLoadMore = function() { 296 let current_page = parseInt($('#wpcs_hidden_wpcsp').val()); 297 if (current_page >= vehicle_list_properties.max_pages) return false; 298 else return true; 299 } 300 301 302 /** 303 * initialisiert button zum nachladen der ergebnisse 304 * @private 305 */ 306 this._initButton = function() { 307 $('#wpcs_pagination_button').click(function(e) { 308 e.preventDefault(); 309 that._loadVehicles(); 310 }); 311 } 312 313 /** 314 * 315 * @private 316 */ 317 this._initInfiniteLoader = function() { 318 if ($('#wpcs_vehicle_archive').data('infinite') != "1") return; 319 320 let timeout = null; 321 $(window).on("scroll", function() { 322 if (timeout != null) window.clearTimeout(timeout); 323 timeout = window.setTimeout(function() { 324 if ($('#wpcs_vehicle_archive .vehicle-on-archive').length < 1) return; 325 326 let element_pos = parseInt($('#wpcs_vehicle_archive .vehicle-on-archive').last().offset().top); 327 if (wpcs_form.is_loading || !that._canLoadMore()) return; 328 var scrollHeight = $(document).height(); 329 var scrollPos = $(window).height() + $(window).scrollTop(); 330 if (scrollPos >= element_pos) that._loadVehicles(); 331 }, 400); 332 }); 333 } 334 335 /** 336 * 337 * @private 338 */ 339 this._loadVehicles = function() { 340 let current_page = parseInt($('#wpcs_hidden_wpcsp').val()); 341 let new_page = current_page + 1; 342 $('#wpcs_hidden_wpcsp').val(new_page); 343 344 wpcs_form.submitAjax(1); 345 } 346 347 this.__construct(); 348 } 349 350 /** 351 * 352 * @constructor 353 */ 354 function WPCSSearchRequest() { 355 356 var that = this; 357 358 this.loader = $('.wpcs_ajax_loader[data-category=searchRequest]'); 359 360 this.__construct = function() { 361 this._initSaveSearch(); 362 this._initList(); 363 } 364 365 /** 366 * 367 * @param wrapper 368 * @private 369 */ 370 this._initSearch = function(sid) { 371 let wrapper = $('.wpcs_save_search_request_wrapper[data-sid="' + sid + '"]'); 372 $('.wpcs_save_search_request_btn', wrapper).click(function(e) { 373 e.preventDefault(); 374 var btn = $(this); 375 var spinner = $('.wpcs_icon_spinner', btn); 376 spinner.css('display', 'inline-block'); 377 378 let email = $('.wpcs_sr_email_input', wrapper); 379 let email_val = email.val(); 380 let privacy = $('input[name=wpcs_sr_privacy]', wrapper).is(':checked') ? 1 : 0; 381 382 $.ajax({
383 method: 'POST', 384 url: wpcs_ajax_url, 385 data: { action: 'wpcs_search_request', todo: 'addSearchRequest', email: email_val, privacy: privacy, formData: wpcs_form.serialize() }, 386 success: function(data) { 387 spinner.hide(); 388 389 if (data.error == "1") { 390 $('.status', wrapper).addClass('error').removeClass('success').html(data.msg); 391 } else { 392 $('.status', wrapper).addClass('success').removeClass('error').html(data.msg); 393 email.val(''); 394 } 395 } 396 }); 397 }); 398 399 $('.privacy_btn', wrapper).click(function(e) { 400 e.preventDefault(); 401 $('.wpcs_vsr_privacy_text', wrapper).slideToggle(); 402 }) 403 } 404 405 406 this._initSaveSearch = function() { 407 $('.wpcs_save_search_request_wrapper').each(function() { 408 let wrapper = this; 409 let sid = $(wrapper).data('sid'); 410 that._initSearch(sid); 411 }); 412 } 413 414 this._initList = function() { 415 $('#wpcs_vsq_list .wpcs_search_request').each(function() { 416 let wrapper = this; 417 $('.delete_btn', wrapper).click(function(e) { 418 e.preventDefault(); 419 let button = this; 420 let hash = $('#wpcs_vsq_list').data('hash'); 421 let time = $(wrapper).data('time'); 422 423 var spinner = $('.wpcs_icon_spinner', button); 424 if (spinner.length) spinner.css('display', 'inline-block'); 425 else that.loader.show(); 426 $('.delete_icon', button).hide(); 427 428 $.ajax({
429 method: 'POST', 430 url: wpcs_ajax_url, 431 data: { action: 'wpcs_search_request', todo: 'removeSearchRequest', hash: hash, time: time }, 432 success: function(data) { 433 if (spinner.length) spinner.hide(); 434 else that.loader.hide(); 435 $('.delete_icon', button).show(); 436 437 if (data.error == "1") { 438 alert(data.msg); 439 } else { 440 $(wrapper).remove(); 441 } 442 } 443 }); 444 }); 445 }); 446 } 447 448 this.__construct(); 449 450 } 451 452 /** 453 * 454 * @constructor 455 */ 456 function WPCSPark() { 457 458 var that = this; 459 460 this.vehicles_list_html = null; 461 this.vehicle_count = 0; 462 463 this.__construct = function() { 464 this._initToggleButtons() 465 this._initList(); 466 } 467 468 this._initList = function() { 469 $('#wpcs_vehicle_parked .vehicle').each(function() { 470 471 let vehicle = this; 472 let vehicle_id = $(this).attr('data-vehicle-id'); 473 474 $('.wpcs_park_remove_btn', vehicle).click(function(e) { 475 e.preventDefault(); 476 $('.wpcs_ajax_loader', vehicle).show(); 477 $.ajax({
478 method: 'POST', 479 url: wpcs_ajax_url, 480 data: { action: 'wpcs_park', todo: 'removeFromList', vehicle_id: vehicle_id }, 481 success: function(data) { 482 if (!data.error) { 483 that.vehicles_list_html = data.list; 484 that.vehicle_count = data.count; 485 that._setList(); 486 } 487 } 488 }); 489 }); 490 491 }); 492 } 493 494 this._initToggleButtons = function() { 495 $('.wpcs_park_toggle_btn').click(function(e) { 496 e.preventDefault(); 497 var btn = $(this); 498 var todo = $(this).hasClass('wpcs_is_parked') ? 'removeFromList' : 'addToList'; 499 var vehicle_id = $(this).attr('data-vehicle-id'); 500 var spinner = $('.wpcs_icon_spinner', btn); 501 spinner.css('display', 'inline-block'); 502 $.ajax({
503 method: 'POST', 504 url: wpcs_ajax_url, 505 data: { action: 'wpcs_park', todo: todo, vehicle_id: vehicle_id }, 506 success: function(data) { 507 spinner.hide(); 508 if (!data.error) { 509 btn.toggleClass('wpcs_is_parked'); 510 that.vehicles_list_html = data.list; 511 that.vehicle_count = data.count; 512 that._setList(); 513 } 514 } 515 }); 516 }); 517 } 518 519 /** 520 * 521 * @param vehicles 522 * @private 523 */ 524 this._setList = function() { 525 526 if (that.vehicles_list_html !== null) { 527 $('#wpcs_vehicle_parked .vehicles_wrapper').html(that.vehicles_list_html); 528 } 529 530 that._setButtonState(); 531 that._refreshCounter(); 532 that._initList(); 533 534 } 535 536 /** 537 * 538 * @param count 539 */ 540 this._refreshCounter = function() { 541 let element = $('.wpcs_count_vehicles_parked'); 542 element.html(that.vehicle_count); 543 544 // animation 545 element.each(function() { 546 this.classList.remove("wpcs_animated"); 547 this.offsetWidth; 548 this.classList.add('wpcs_animated'); 549 }); 550 551 } 552 553 /** 554 * 555 * @private 556 */ 557 this._setButtonState = function() { 558 if ($('#wpcs_vehicle_parked').length < 1) return; 559 560 $('.wpcs_park_toggle_btn').each(function() { 561 $(this).removeClass('wpcs_is_parked'); 562 }); 563 564 $('#wpcs_vehicle_parked .vehicle').each(function() { 565 let id = $(this).data('vehicle-id'); 566 $('.wpcs_park_toggle_btn[data-vehicle-id=' + id + ']').addClass('wpcs_is_parked'); 567 }); 568 } 569 570 /** 571 * 572 * @param vehicle_id 573 * @private 574 */ 575 this._removeFromList = function(vehicle_id) { 576 $('#wpcs_vehicle_parked .vehicle[data-vehicle-id=' + vehicle_id + ']').remove(); 577 } 578 579 this.__construct(); 580 } 581 582 583 /** 584 * 585 * @constructor 586 */ 587 function WPCSLightbox() { 588 var that = this; 589 this.gallery = $('#wpcs_vehicle_images_wrapper'); 590 this.current = 0; 591 this.lightbox = null; 592 593 /** 594 * 595 * @private 596 */ 597 this.__construct = function() { 598 599 if ($('#wpcs_vehicle_images_wrapper.wpcs_lightbox_enabled').length < 1) return; 600 601 602 $('#wpcs_vehicle_single_image_wrapper a.lightbox_opener').click(function(e) { 603 e.preventDefault(); 604 e.stopPropagation(); 605 that._open($('#wpcs_vehicle_single_image').attr('src')); 606 }); 607 }; 608 609 this._create = function() { 610 var html = ''; 611 612 html += '<div id="wpcs_lightbox">'; 613 html += '<div class="close"><span class="wpcs_icon dashicons dashicons-no-alt"></span></div>'; 614 html += '<div class="image_wrapper">'; 615 html += '<div class="arrow arrow_left"><span class="wpcs_icon dashicons dashicons-arrow-left-alt2"></span></div>'; 616 html += '<img id="wpcs_lightbox_image" alt="' + wpcs_lightbox_alt + '" src="" />'; 617 html += '<div class="arrow arrow_right"><span class="wpcs_icon dashicons dashicons-arrow-right-alt2"></span></div>'; 618 html += '</div>'; 619 html += '</div>'; 620 621 this.lightbox = $(html); 622 623 $('body').prepend(this.lightbox); 624 625 $('.arrow_right', this.lightbox).click(function() { that._next(); }); 626 $('.arrow_left', this.lightbox).click(function() { that._prev(); }); 627 $('.close', this.lightbox).click(function() { that._close(); }); 628 629 }; 630 631 632 this._next = function() { 633 this.current++; 634 if (this.current > wpcs_lightbox_sources.length - 1) this.current = 0; 635 this._change(wpcs_lightbox_sources[this.current]); 636 }; 637 638 this._prev = function() { 639 this.current--; 640 if (this.current < 0) this.current = wpcs_lightbox_sources.length - 1; 641 this._change(wpcs_lightbox_sources[this.current]); 642 }; 643 644 this._change = function(src) { 645 $('#wpcs_lightbox_image', this.lightbox).attr('src', src); 646 }; 647 648 649 this._open = function(src) { 650 if (this.lightbox == null) this._create(); 651 this._change(src); 652 this.lightbox.fadeIn(); 653 }; 654 655 656 this._close = function() { 657 this.lightbox.fadeOut(); 658 }; 659 660 if (this.gallery.length > 0) 661 this.__construct(); 662 663 } 664 665 /** 666 * Global lightbox â works on any page via data attributes. 667 * 668 * Trigger: any element with data-lightbox-source="<CSS selector>" 669 * data-lightbox-index="N" optional start index (default 0) 670 * data-lightbox-sync="gallery" sync with window._wpcsGallery while navigating 671 * 672 * The overlay (#wpcs-lightbox) is created once on first open if it doesn't exist yet.
673 */ 674 function wpcsInitLightbox() { 675 676 var overlay = null; 677 var lbSwiper = null; 678 var currentImgs = []; 679 var syncGallery = false; 680 681 function ensureOverlay() { 682 if (document.getElementById('wpcs-lightbox')) { 683 overlay = document.getElementById('wpcs-lightbox'); 684 return; 685 } 686 overlay = document.createElement('div'); 687 overlay.id = 'wpcs-lightbox'; 688 overlay.className = 'wpcs-lightbox'; 689 overlay.innerHTML = 690 '<div class="wpcs-lightbox__inner">' + 691 '<button class="wpcs-lightbox__close" aria-label="SchlieÃen">â</button>' + 692 '<div class="wpcs-lightbox__swiper swiper">' + 693 '<div class="swiper-wrapper"></div>' + 694 '</div>' + 695 '<div class="wpcs-lightbox__pagination swiper-pagination"></div>' + 696 '<button class="wpcs-lightbox__nav wpcs-lightbox__nav--prev" aria-label="Vorheriges Bild">' + 697 '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>' + 698 '</button>' + 699 '<button class="wpcs-lightbox__nav wpcs-lightbox__nav--next" aria-label="Nächstes Bild">' + 700 '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>' + 701 '</button>' + 702 '</div>'; 703 document.body.appendChild(overlay); 704 overlay.querySelector('.wpcs-lightbox__close').addEventListener('click', closeLightbox); 705 overlay.addEventListener('click', function(e) { if (e.target === overlay) closeLightbox(); }); 706 } 707 708 function buildSlides() { 709 var wrapper = overlay.querySelector('.swiper-wrapper'); 710 wrapper.innerHTML = ''; 711 currentImgs.forEach(function(el) { 712 var src = el.dataset.lightboxSrc || el.getAttribute('src'); 713 var slide = document.createElement('div'); 714 slide.className = 'swiper-slide'; 715 slide.innerHTML = '<img src="' + src + '" alt="">'; 716 wrapper.appendChild(slide); 717 }); 718 } 719 720 function openLightbox(imgs, index, sync) { 721 ensureOverlay(); 722 currentImgs = imgs; 723 syncGallery = !!sync; 724 725 buildSlides(); 726 727 if (lbSwiper) { lbSwiper.destroy(true, true); lbSwiper = null; } 728 729 overlay.classList.add('open'); 730 document.body.style.overflow = 'hidden'; 731 732 lbSwiper = new Swiper(overlay.querySelector('.swiper'), { 733 initialSlide : index || 0, 734 loop : currentImgs.length > 1, 735 keyboard : { enabled: true }, 736 navigation : { 737 nextEl: overlay.querySelector('.wpcs-lightbox__nav--next'), 738 prevEl: overlay.querySelector('.wpcs-lightbox__nav--prev'), 739 }, 740 pagination : { 741 el : overlay.querySelector('.wpcs-lightbox__pagination'), 742 type : 'fraction', 743 }, 744 on: { 745 slideChange: function() { 746 if (syncGallery && window._wpcsGallery) { 747 window._wpcsGallery.goTo(lbSwiper.realIndex); 748 } 749 } 750 } 751 }); 752 } 753 754 function closeLightbox() { 755 if (overlay) overlay.classList.remove('open'); 756 document.body.style.overflow = ''; 757 if (lbSwiper) { lbSwiper.destroy(true, true); lbSwiper = null; } 758 } 759 760 // Event delegation â works for dynamically rendered galleries too 761 document.addEventListener('click', function(e) { 762 var trigger = e.target.closest('[data-lightbox-source]'); 763 if (!trigger) return; 764 e.preventDefault(); 765 var imgs = Array.from(document.querySelectorAll(trigger.dataset.lightboxSource)) 766 .filter(function(img) { return !img.closest('.slick-cloned'); }); 767 if (!imgs.length) return; 768 var sync = trigger.dataset.lightboxSync === 'gallery'; 769 var index = sync && window._wpcsGallery 770 ? window._wpcsGallery.getCurrent() 771 : parseInt(trigger.dataset.lightboxIndex || '0', 10); 772 openLightbox(imgs, index, sync); 773 }); 774 775 document.addEventListener('keydown', function(e) { 776 if (!overlay || !overlay.classList.contains('open')) return; 777 if (e.key === 'Escape') closeLightbox(); 778 }); 779 } 780 781 /** 782 * 783 * @constructor 784 */ 785 function WPCSCompare() { 786 787 var that = this; 788 var table = null; 789 790 /** 791 * 792 * @private 793 */ 794 this.__construct = function() { 795 this.table = $('#wpcs_compare_table'); 796 this.vehicle_count = null; 797 798 // init compare table 799 if (this.table.length > 0) { 800 this.initSectionLinks(); 801 this.initRemoveBtn();
802 //this._setWidth(); 803 } 804 805 this._init_compare_buttons(); 806 }; 807 808 this._init_compare_buttons = function(collection) { 809 $('.wpcs_compare_toggle_btn', collection).click(function(e) { 810 e.preventDefault(); 811 var btn = $(this); 812 var todo = $(this).hasClass('wpcs_in_comparison') ? 'removeFromList' : 'addToList'; 813 var vehicle_id = $(this).attr('data-vehicle-id'); 814 var spinner = $('.wpcs_icon_spinner', btn); 815 spinner.css('display', 'inline-block'); 816 $.ajax({ 817 method: 'POST', 818 url: wpcs_ajax_url, 819 data: { action: 'wpcs_compare', todo: todo, vehicle_id: vehicle_id }, 820 success: function(data) { 821 spinner.hide(); 822 if (!data.error) { 823 btn.toggleClass('wpcs_in_comparison'); 824 that.vehicle_count = data.count; 825 that._refreshCounter(); 826 } 827 } 828 }); 829 }); 830 } 831 832 this._refreshCounter = function() { 833 let element = $('.wpcs_count_vehicles_compared'); 834 element.html(that.vehicle_count); 835 836 // animation 837 element.each(function() { 838 this.classList.remove("wpcs_animated"); 839 this.offsetWidth; 840 this.classList.add('wpcs_animated'); 841 }); 842 } 843 844 /** 845 * 846 */ 847 this.initSectionLinks = function() { 848 $('a.section_link', that.table).click(function(e) { 849 e.preventDefault(); 850 var rel = $(this).attr('rel'); 851 852 //$(this).parent().toggleClass('opened'); 853 $('tr[rel=' + rel + ']').toggleClass('wpcs_hidden'); 854 $(this).toggleClass('closed'); 855 }); 856 }; 857 858 /** 859 * 860 */ 861 this.initRemoveBtn = function() { 862 $('.wpcs_compare_table_remove_btn').click(function(e) { 863 e.preventDefault(); 864 var vehicle_id = $(this).attr('data-vehicle-id'); 865 var btn = this; 866 var spinner = $('.wpcs_icon_spinner', btn); 867 spinner.css('display', 'inline-block'); 868 869 $.ajax({
870 method: 'POST', 871 url: wpcs_ajax_url, 872 data: { action: 'wpcs_compare', todo: 'removeFromList', vehicle_id: vehicle_id }, 873 success: function(data) { 874 spinner.hide(); 875 if (!data.error) { 876 that._removeFromTable(vehicle_id); 877 } 878 } 879 }); 880 881 }); 882 }; 883 884 /** 885 * 886 * @private 887 */ 888 this._setWidth = function() { 889 var count = this._countCars() + 1; 890 var percent = 100 / count; 891 $('td', this.table).not('.header').css('width', percent + '%'); 892 }; 893 894 /** 895 * 896 * @param vehicle_id 897 * @private 898 */ 899 this._removeFromTable = function(vehicle_id) { 900 jQuery('td[data-vehicle-id=' + vehicle_id + ']', this.table).remove(); 901 902 var count = this._countCars(); 903 $('td.header', this.table).attr('colspan', count); 904 905 //this._setWidth(); 906 907 if (count == 1) { 908 //this.table.remove(); 909 $('#wpcs_vehicle_compare').html('<h3>Keine Fahrzeuge zum Vergleichen ausgewählt.</h3>'); 910 } 911 }; 912 913 /** 914 * 915 * @returns {number} 916 * @private 917 */ 918 this._countCars = function() { 919 var cars = $('td.header', this.table).first().attr('colspan') - 1; 920 return cars; 921 }; 922 923 /** 924 * 925 */ 926 this.__construct(); 927 } 928 929 930 /** 931 * 932 * @constructor 933 */ 934 function WPCSOrderbar() { 935 936 var that = this; 937 938 this.__construct = function() { 939 this.initOrderBar(); 940 }; 941 942 this.initOrderBar = function() { 943 $('.dxim_ff_order_bar a.dxim_set_order').click(function(e) { 944 e.preventDefault(); 945 946 var orderby = $(this).attr('data-orderby'); 947 var order = $('.dxim_ff_order_bar').attr('data-order'); 948 var new_order = (order == 'asc') ? 'desc' : 'asc'; 949 950 951 $('#dxim_orderby_hidden').val(orderby); 952 $('#dxim_order_hidden').val(new_order); 953 954 that.refresh(new_order, orderby); 955 956 wpcs_form.submit(); 957 }); 958 }; 959 960 this.refresh = function(order, orderby) { 961 $('.dxim_ff_order_bar').each(function() { 962 let bar = $(this); 963 bar.attr('data-order', order); 964 965 $('a.dxim_set_order', bar).each(function() { 966 var tmp_orderby = $(this).attr('data-orderby'); 967 if (tmp_orderby == orderby) $(this).addClass('current'); 968 else $(this).removeClass('current'); 969 }); 970 }); 971 972 } 973 974 this.__construct(); 975 976 } 977 978 function animateValue(obj, start, end, duration) { 979 let startTimestamp = null; 980 const step = (timestamp) => { 981 if (!startTimestamp) startTimestamp = timestamp; 982 const progress = Math.min((timestamp - startTimestamp) / duration, 1); 983 let value = Math.floor(progress * (end - start) + start); 984 $(obj).attr('data-value', value); 985 obj.innerHTML = value.toLocaleString('de-DE'); 986 if (progress < 1) { 987 window.requestAnimationFrame(step); 988 } 989 }; 990 window.requestAnimationFrame(step); 991 } 992 993 /** ---------------------------------------------------------------------------------- 994 * Filterform 995 * @constructor 996 */ 997 function WPCSForm() { 998 var that = this; 999 var ajax = false; 1000 1001 this.is_loading = false; 1002 this.isResetting = false; 1003 this.preFilterTimeout = null; 1004 this.scrollTopAfterSubmit = false; 1005 1006 this.keyUpDelay = null; 1007 1008 /** 1009 * 1010 * @returns {*|jQuery} 1011 */ 1012 this.serialize = function() {
1013 that._serializeMultipleCheckbox(); 1014 let formdata = $('.dxim_filter :input').serialize(); 1015 return formdata; 1016 } 1017 1018 /** 1019 * 1020 * @private 1021 */ 1022 this.__construct = function() { 1023 1024 if ($('#wpcs_vehicle_archive[data-ajax="1"]').length > 0) this.ajax = 1; 1025 1026 this.initWpcsSelect(); 1027 this.initCheckboxes(); 1028 this.initSlider(); 1029 this.initActiveFilters(); 1030 this.initRange(); 1031 this.initSubmit(); 1032 this.initColorSelect(); 1033 this.initPagination(); 1034 this.initMultipleCheckbox(); 1035 this.initTextField(); 1036 this.initLayoutSelector(); 1037 1038 $(document).on('wpcs_ajax_form_submitted', this.scrollTop); 1039 $(document).on('wpcs_reset_all_filters', function() { that.resetAllFilters(); }); 1040 $(document).on('click', '.wpcs_reset_all_filters_btn', function(e) { e.preventDefault(); that.resetAllFilters(); }); 1041 }; 1042 1043 this.scrollTop = function() { 1044 if (!that.scrollTopAfterSubmit) return; 1045 $([document.documentElement, document.body]).animate({ 1046 scrollTop: $(".wpcs_vehicles").offset().top 1047 }, 1000); 1048 that.scrollTopAfterSubmit = false; 1049 } 1050 1051 this._serializeMultipleCheckbox = function() { 1052 $('.wpcs_multiple_checkbox').each(function() { 1053 let wrapper = this; 1054 let hidden = $('.wpcs_element_value', wrapper); 1055 1056 let valueStr = ''; 1057 $('.wpcs_selectable.selected', wrapper).each(function(z) { 1058 if (z != 0) valueStr += ','; 1059 valueStr += $(this).data('value'); 1060 }); 1061 hidden.val(valueStr); 1062 }); 1063 } 1064 1065 this.resetMultipleCheckbox = function(filter) { 1066 $('.wpcs_multiple_checkbox[data-filter="' + filter + '"] .wpcs_selectable.selected').removeClass('selected'); 1067 } 1068 1069 this.initMultipleCheckbox = function() { 1070 $('.wpcs_multiple_checkbox').each(function() { 1071 let wrapper = this; 1072 $('.wpcs_selectable', wrapper).click(function() { 1073 $(this).toggleClass('selected'); 1074 that._preFilterAmount(); 1075 }); 1076 }); 1077 } 1078 1079 this.initRange = function() { 1080 if (typeof noUiSlider === 'undefined') return; 1081 $('.dxim_filter_range').each(function() { 1082 var slider_timeout = null; 1083 let slider_wrapper = $(this); 1084 let key = slider_wrapper.data('key'); 1085 let filter_1 = slider_wrapper.data('filter-1'); 1086 let filter_2 = slider_wrapper.data('filter-2'); 1087 let start_val = slider_wrapper.data('start'); 1088 let step = slider_wrapper.data('step'); 1089 let end_val = slider_wrapper.data('end'); 1090 let slider = document.getElementById('wpcs_fs_' + key); 1091 let range = wpcs_slider_ranges[key]; 1092 let unit = slider_wrapper.data('unit'); 1093 let label = slider_wrapper.data('label'); 1094 let formatting = parseInt(slider_wrapper.data('formatting')); 1095 1096 let input_1 = jQuery('#wpcs_fv_' + filter_1); 1097 let label_1 = jQuery('#wpcs_fl_' + filter_1); 1098 let input_2 = jQuery('#wpcs_fv_' + filter_2); 1099 let label_2 = jQuery('#wpcs_fl_' + filter_2); 1100 1101 let min_input = jQuery('.min_input', slider_wrapper); 1102 let max_input = jQuery('.max_input', slider_wrapper); 1103 1104 noUiSlider.create(slider, { 1105 start: [start_val, end_val], 1106 format: { 1107 to: function(value) { return Math.round(value); }, 1108 from: function(value) { return Math.round(value); } 1109 }, 1110 step: step, 1111 connect: true, 1112 range: range 1113 }); 1114 1115 slider.noUiSlider.on('update', function(values) { 1116 let val_min = values[0]; 1117 let val_max = values[1]; 1118 let html_min = val_min; 1119 let html_max = val_max;
1120 min_input.val(val_min); 1121 max_input.val(val_max); 1122 1123 if (val_min == range.min && val_max == range.max) { 1124 val_min = val_max = '#'; 1125 html_min = range.min; 1126 html_max = range.max; 1127 } 1128 1129 if (val_min == '#' && val_max == '#') slider_wrapper.addClass('inactive'); 1130 else slider_wrapper.removeClass('inactive'); 1131 1132 1133 input_1.val(val_min); 1134 input_2.val(val_max); 1135 1136 if (formatting > 0) { 1137 html_min = html_min.toLocaleString('de-DE'); 1138 html_max = html_max.toLocaleString('de-DE'); 1139 } 1140 1141 label_1.html(html_min + " " + unit); 1142 label_2.html(html_max + " " + unit); 1143 }); 1144 1145 slider.noUiSlider.on('set', function() { 1146 that._preFilterAmount(); 1147 }); 1148 1149 $('.min_input, .max_input', slider_wrapper).focus(function() { 1150 $(this).data('current-value', $(this).val()); 1151 $(this).val(""); 1152 }); 1153 1154 $('.min_input, .max_input', slider_wrapper).focusout(function() { 1155 let val = $(this).val(); 1156 if (val === "") $(this).val($(this).data('current-value')); 1157 slider.noUiSlider.set([min_input.val(), max_input.val()]); 1158 }); 1159 1160 $('.noUi-handle-upper', slider_wrapper).attr('aria-label', label + " gröÃter Wert"); 1161 $('.noUi-handle-lower', slider_wrapper).attr('aria-label', label + " kleinster Wert"); 1162 1163 }); 1164 1165 }; 1166 1167 this.initSlider = function() { 1168 if (typeof noUiSlider === 'undefined') return; 1169 $('.dxim_filter_slider').each(function() { 1170 let slider_timeout = null; 1171 let slider_wrapper = $(this); 1172 let key = slider_wrapper.attr('data-key'); 1173 let start_val = slider_wrapper.attr('data-start'); 1174 let default_value = slider_wrapper.data('default'); 1175 let unit = slider_wrapper.data('unit'); 1176 let formatting = parseInt(slider_wrapper.data('formatting')); 1177 let step = slider_wrapper.data('step'); 1178 let label = slider_wrapper.data('label'); 1179 let slider = document.getElementById('wpcs_fs_' + key); 1180 let range = wpcs_slider_ranges[key]; 1181 let input = jQuery('#wpcs_fv_' + key); 1182 let label_current = jQuery('#wpcs_fl_' + key + '_current'); 1183 let input_label = jQuery('.input_label', slider_wrapper); 1184 1185 noUiSlider.create(slider, { 1186 start: [start_val], 1187 connect: 'lower', 1188 range: range, 1189 step: step, 1190 }); 1191 1192 slider.noUiSlider.on('update', function(value) { 1193 let val = Math.round(value); 1194 let label = val; 1195 1196 input_label.val(val); 1197 1198 if (value == default_value) { 1199 val = '#'; 1200 label = default_value; 1201 } 1202 1203 if (formatting > 0) { 1204 label = label.toLocaleString('de-DE'); 1205 } 1206 1207 input.val(val); 1208 label_current.html(label + " " + unit); 1209 }); 1210 1211 slider.noUiSlider.on('set', function(value) { 1212 that._preFilterAmount(); 1213 }); 1214 1215 $('.input_label', slider_wrapper).focus(function() { 1216 $(this).data('current-value', $(this).val()); 1217 $(this).val(""); 1218 }); 1219 1220 $('.input_label', slider_wrapper).focusout(function() { 1221 let val = $(this).val(); 1222 //if(val === "" || val < range.min || val > range.max) { 1223 if (val === "") { 1224 $(this).val($(this).data('current-value')); 1225 val = $(this).val(); 1226 } 1227 slider.noUiSlider.set(val); 1228 }); 1229 1230 $('.noUi-handle-lower', slider_wrapper).attr('aria-label', "setze Wert für " + label); 1231 1232 }); 1233 }; 1234 1235 this.initColorSelect = function() { 1236 $('.wpcs_color_select').each(function() { 1237 let c = this; 1238 $('.color', c) 1239 .click(function() { 1240 let i = 0; 1241 let values = [] 1242 $(this).toggleClass('active'); 1243 $('.color', c).each(function() { 1244 if ($(this).hasClass('active')) { 1245 values[i] = $(this).data('key'); 1246 i++; 1247 } 1248 }); 1249 1250 $('.color_value', c).val(values.join(",")); 1251 that._preFilterAmount(); 1252 }) 1253 .keydown(function(e) { 1254 if (e.key === "Enter" || e.key === " ") { 1255 $(this).trigger('click'); 1256 } 1257 }); 1258 }); 1259 } 1260 1261 1262 this.initTextField = function() { 1263 $('.dxim_filter input[type=text]').keyup(function() { 1264 if (that.keyUpDelay !== null) window.clearTimeout(that.keyUpDelay); 1265 that.keyUpDelay = window.setTimeout(function() { 1266 that._preFilterAmount(); 1267 }, 800); 1268 }); 1269 } 1270 1271 1272 this.initLayoutSelector = function() { 1273 $('#wpcs_archive_layout_selector .button') 1274 .click(function() { 1275 $('#wpcs_archive_layout_selector .button').removeClass('active'); 1276 1277 let mode = $(this).data('type'); 1278 1279 $('#wpcs_archive_layout_selector input').val(mode); 1280 vehicle_list_properties.layout = mode; 1281 1282 $(this).addClass('active'); 1283 that.submit(); 1284 }) 1285 .keydown(function(e) { 1286 if (e.key === "Enter" || e.key === " ") $(this).trigger('click'); 1287 }); 1288 } 1289 1290 1291 this.initPagination = function() { 1292 // Vehicle-Archive-Pagination: Links mit data-wpcsp Attribut sind eindeutig 1293 // dem Fahrzeugarchiv zugeordnet (Hidden-Input #wpcs_hidden_wpcsp). 1294 // Theme-Archive (Angebote, Jobs) nutzen href="/page/N/" ohne data-wpcsp und 1295 // werden hier nicht abgefangen â sie navigieren normal. 1296 // Pagination steht im Markup ausserhalb von #wpcs_vehicle_ar
1296chive, daher 1297 // kein Container-Scope (sonst greift der Handler nie). 1298 $('.wpcs-pagination a[data-wpcsp]').off('click.wpcs-pagination').on('click.wpcs-pagination', function(e) { 1299 if ($('#wpcs_hidden_wpcsp').length === 0) return; // kein Vehicle-Filter-Form auf Seite 1300 e.preventDefault(); 1301 let wpcsp = $(this).data('wpcsp'); 1302 $('#wpcs_hidden_wpcsp').val(wpcsp); 1303 1304 that.scrollTopAfterSubmit = true; 1305 that.submit(); 1306 }); 1307 } 1308 1309 /** 1310 * 1311 */ 1312 this.initWpcsSelect = function() { 1313 $('.wpcsselect', '.dxim_filter').each(function() { 1314 let select = $(this); 1315 let field = select.data('field'); 1316 let dxim_filter = $('.dxim_filter[data-filter-name="' + field + '"]'); 1317 let load = dxim_filter.data('load'); 1318 let values = dxim_filter.data('values'); 1319 1320 if (select.hasClass('dxim_order_select')) { 1321 select.wpcsselect({ 1322 onSelect: function() { 1323 let val = $('.wpcs_select_value', select).val(); 1324 $('#dxim_order_hidden').val(val); 1325 if (that.ajax) that._preFilterAmount(); 1326 } 1327 }); 1328 } else if (select.hasClass('dxim_orderby_select')) { 1329 select.wpcsselect({ 1330 onSelect: function() { 1331 let val = $('.wpcs_select_value', select).val(); 1332 $('#dxim_orderby_hidden').val(val); 1333 if (that.ajax) that._preFilterAmount(); 1334 } 1335 }); 1336 } else { 1337 select.wpcsselect({ 1338 ajax: { 1339 url: wpcs_ajax_url, 1340 dataType: 'json', 1341 method: 'POST', 1342 data: function() { 1343 var query = { 1344 action: 'getData', 1345 field: field, 1346 load: load, 1347 values: values, 1348 init_ajax_data: 1, 1349 filterFormData: that.serialize(), 1350 }; 1351 return query; 1352 }, 1353 }, 1354 onSelect: function() { 1355 if (field === "make") { 1356 that.resetSelect("model"); 1357 } 1358 1359 if (that.preFilterTimeout !== null) window.clearTimeout(that.preFilterTimeout); 1360 that.preFilterTimeout = window.setTimeout(that._preFilterAmount, 800); 1361 } 1362 }); 1363 } 1364 1365 }); 1366 }; 1367 1368 this.initActiveFilters = function() { 1369 $('.wpcs_filterform_active_filters .active_filter').each(function() { 1370 let filter = this; 1371 let key = $(filter).data('key'); 1372 let type = $(filter).data('type'); 1373 1374 $('.reset', filter) 1375 .click(function() { 1376 if (type == "select") { 1377 that.resetSelect(key); 1378 that._resetPageNr(); 1379 that.submit(); 1380 } 1381 if (type == "checkbox") { 1382 that.resetCheckbox(key); 1383 that._resetPageNr(); 1384 that.submit(); 1385 } 1386 if (type == "multiple_checkbox") { 1387 that.resetMultipleCheckbox(key); 1388 that._resetPageNr(); 1389 that.submit(); 1390 } 1391 if (type == "text") {
1392 that.resetText(key); 1393 that._resetPageNr(); 1394 that.submit(); 1395 } 1396 if (type == "slider") { 1397 that.resetSlider(key); 1398 that._resetPageNr(); 1399 that.submit(); 1400 } 1401 if (type == "color") { 1402 that.resetColor(key); 1403 that._resetPageNr(); 1404 that.submit(); 1405 } 1406 1407 if (type == "custom") { $(document).trigger("wpcs_ajax_remove_filter", [key]); } 1408 1409 filter.remove(); 1410 }) 1411 .keydown(function(e) { 1412 if (e.key === "Enter" || e.key === " ") $(this).trigger('click'); 1413 }); 1414 1415 }); 1416 } 1417 1418 1419 /** 1420 * Vorschau beim Klick der Checkbox aktivieren 1421 */ 1422 this.initCheckboxes = function() { 1423 $('.dxim_filter input[type=checkbox]').click(function() { 1424 that._preFilterAmount(); 1425 }); 1426 }; 1427 1428 /** 1429 * Anzahl der Treffer Vorschau 1430 * @private 1431 */ 1432 this._preFilterAmount = function() { 1433 if (that.isResetting) return; 1434 1435 that._resetPageNr(); 1436 1437 if (that.ajax) { 1438 that.submitAjax(); 1439 } else { 1440 $.ajax({
1441 method: 'POST', 1442 url: wpcs_ajax_url, 1443 data: { action: 'getPreFilteredAmount', filterFormData: that.serialize(), init_ajax_data: 1 }, 1444 success: function(data) { 1445 that._refreshCounterValues(data); 1446 } 1447 }); 1448 } 1449 1450 }; 1451 1452 // 1453 this._refreshCounterValues = function(data) { 1454 let old_val = Math.round($('.wpcs_search_count').eq(0).attr('data-value')); 1455 $('.wpcs_search_count').each(function() { 1456 animateValue(this, old_val, data, 500); 1457 }); 1458 } 1459 1460 /** 1461 * Submit Form 1462 */ 1463 this.initSubmit = function() { 1464 1465 $('.dxim_filter_form_submit').click(function(e) { 1466 e.preventDefault(); 1467 1468 let target = $('#wpcs_vehicle_archive'); 1469 let redirect_url = $(this).attr('data-redirect'); 1470 let url = ''; 1471 1472 if (redirect_url != undefined && redirect_url != "") { 1473 url = redirect_url; 1474 that.ajax = false; 1475 } else { 1476 // zum archiv umleiten 1477 if (target.length < 1) url = wpcs_archive_url; 1478 // aktuelle Seite reload 1479 else url = wpcs_current_url; 1480 } 1481 1482 that.submit(url); 1483 }); 1484 1485 }; 1486 1487 /** 1488 * 1489 */ 1490 this.submit = function(force_url) { 1491 1492 if (that.ajax) { 1493 that.submitAjax(); 1494 return; 1495 } 1496 1497 let url = ''; 1498 if (!force_url) { 1499 //let target = $('.wpcs_vehicle_list.wpcs_vehicles'); 1500 let target = $('#wpcs_vehicle_archive'); 1501 // zum archiv umleiten 1502 if (target.length < 1) url = wpcs_archive_url; 1503 // aktuelle Seite reload 1504 else url = wpcs_current_url; 1505 } else url = force_url; 1506 1507 let data = that.serialize(); 1508 url += "?" + data; 1509 url += '#wpcs_vehicles'; 1510 window.location.href = url; 1511 } 1512 1513 /** 1514 * 1515 * @private 1516 */ 1517 this._resetPageNr = function() { 1518 // reset page id to 1 1519 $('#wpcs_hidden_wpcsp').val(1); 1520 } 1521 1522 /** 1523 * 1524 */ 1525 this.submitAjax = function(append = 0) { 1526 1527 vehicle_list_properties.append = append; 1528 1529 that.setLoadingState(); 1530 1531 $.ajax({
1532 method: 'POST', 1533 url: wpcs_ajax_url, 1534 data: { action: 'wpcs_fetchResults', filterFormData: that.serialize(), init_ajax_data: 1, vehicle_list_data: vehicle_list_properties }, 1535 success: function(json) { 1536 1537 let new_vehicles = $(json.vehicle_list_html); 1538 1539 // vehicles 1540 if (append > 0) { 1541 $('#wpcs_vehicle_archive .wpcs_vehicles_wrapper').append(new_vehicles); 1542 } else { 1543 $('#wpcs_vehicle_archive').replaceWith(new_vehicles); 1544 1545 // Seitenzeiger und max_pages explizit zurücksetzen â nicht auf Script-Ausführung 1546 // im ersetzten HTML verlassen (in manchen jQuery-Versionen unzuverlässig) 1547 $('#wpcs_hidden_wpcsp').val(1); 1548 if (json.max_pages !== undefined) vehicle_list_properties.max_pages = json.max_pages; 1549 1550 // pagination 1551 $('.wpcs-pagination, .dxim_pagination').replaceWith(json.pagination); 1552 that.initPagination(); 1553 1554 // active filters 1555 $('.wpcs_filterform_active_filters').replaceWith(json.active_filters); 1556 that.initActiveFilters(); 1557 1558 // refresh counters 1559 // $('.vehicle_count').html(json.count); 1560 that._refreshCounterValues(json.count); 1561 } 1562 1563 // disable loading state 1564 that.hideLoadingState(); 1565 1566 // 1567 wpcs_compare._init_compare_buttons(new_vehicles); 1568 1569 // 1570 wpcs_park._initToggleButtons(new_vehicles); 1571 1572 $(document).trigger("wpcs_ajax_form_submitted"); 1573 } 1574 }); 1575 1576 } 1577 1578 this.setLoadingState = function() { 1579 this.is_loading = true; 1580 $('.wpcs_ajax_loader[data-category=sync]').addClass('active'); 1581 } 1582 1583 this.hideLoadingState = function() { 1584 this.is_loading = false; 1585 $('.wpcs_ajax_loader[data-category=sync]').removeClass('active'); 1586 } 1587 1588 1589 this.resetSelect = function(key) { 1590 let obj = $('.wpcsselect[data-field=' + key + ']'); 1591 if (obj.length < 1) return; 1592 $('.wpcs_select_handle', obj).html(obj.data('nothing-selected')); 1593 $('.wpcs_select_value', obj).val(''); 1594 } 1595 1596 this.resetCheckbox = function(key) { 1597 let input = $('input[name=' + key + ']'); 1598 input.prop('checked', false); 1599 } 1600 1601 1602 this.resetText = function(key) { 1603 $('input[name=' + key + ']').val(''); 1604 } 1605 1606 this.resetSlider = function(key) { 1607 // Modern-Pfad: .wpcs-range-wrapper per data-key / data-filter-1 / data-filter-2 finden. 1608 // Im Modern-Mode existiert noUiSlider nicht â Range/Slider werden über native 1609 // range-Inputs gerendert. form-elements.js hängt Listener an, die beim input/change 1610 // die hidden-Inputs + visuelle Anzeige nachziehen. Reset â auf Min/Max setzen + Events. 1611 let $modernWrapper = $( 1612 '.wpcs-range-wrapper[data-key="' + key + '"], ' + 1613 '.wpcs-range-wrapper[data-filter-1="' + key + '"], ' + 1614 '.wpcs-range-wrapper[data-filter-2="' + key + '"]' 1615 ); 1616 if ($modernWrapper.length) { 1617 $modernWrapper.each(function() { 1618 let wrapper = this; 1619 let minInput = wrapper.querySelector('.wpcs-range-min'); 1620 let maxInput = wrapper.querySelector('.wpcs-range-max'); 1621 let numMin = wrapper.querySelector('.wpcs-range-number-min'); 1622 let numMax = wrapper.querySelector('.wpcs-range-number-max'); 1623 let rangeMin = parseInt(wrapper.getAttribute('data-min')); 1624 let rangeMax = parseInt(wrapper.getAttribute('data-max')); 1625 1626 if (minInput && maxInput) { 1627 minInput.value = minInput.min; 1628 maxInput.value = maxInput.max; 1629 } else if (minInput) { 1630 let wKey = wrapper.getAttribute('data-key') || ''; 1631 minInput.value = wKey.indexOf('_max') !== -1 ? minInput.max : minInput.min; 1632 } 1633 if (numMin) numMin.value = rangeMin; 1634 if (numMax) numMax.value = rangeMax; 1635 1636 // Events triggern, damit form-elements.js onInput (visuelles Update) 1637 // + onChange (Hidden-Inputs + preFilterAmount) ausführt. 1638 ['input', 'change'].forEach(function(evt) { 1639 if (minInput) minInput.dispatchEvent(new Event(evt, {bubbles: true})); 1640 if (maxInput) maxInput.dispatchEvent(new Event(evt, {bubbles: true})); 1641 }); 1642 }); 1643 return; 1644 } 1645 1646 // Legacy-Pfad (noUiSlider) 1647 if (typeof noUiSlider === 'undefined') return; 1648 let obj = $('#wpcs_fs_' + key); 1649 1650 // RANGE slider 1651 if (obj.length < 1) { 1652 let key2 = key.replace('_max', '').replace('_min', ''); 1653 let obj2 = $('#wpcs_fs_' + key2); 1654 if (obj2.length < 1) return; 1655 1656 const slider = obj2[0].noUiSlider; 1657 if (!slider) return; 1658 1659 if (window.wpcs_slider_ranges && window.wpcs_slider_ranges[key2]) { 1660 const { min, max } = window.wpcs_slider_ranges[key2]; 1661 slider.set([min, max]); 1662 } 1663 1664 return; 1665 } 1666 1667 // SINGLE slider (min or max) 1668 const slider = obj[0].noUiSlider; 1669 if (!slider) return; 1670 const range = window.wpcs_slider_ranges[key]; 1671 if (!range) return; 1672 1673 let value = key.endsWith('_min') ? range.min : range.max; 1674 slider.set(value); 1675 }; 1676 1677 1678 1679 1680 this.resetColor = function(key) { 1681 let obj = $('.dxim_filter[data-filter-name=' + key + '] .wpcs_color_select'); 1682 $('.color_value', obj).val(''); 1683 $('.color.active', obj).removeClass('active'); 1684 1685 } 1686 1687 this.resetAllFilters = function() { 1688 that.isResetting = true; 1689 1690 $('.dxim_filter[data-filter-name]').each(function() { 1691 let wrapper = $(this); 1692 // .attr() statt .data() â liest direkt aus dem HTML-Attribut, kein jQuery-Cache 1693 let key = wrapper.attr('data-filter-name'); 1694 let type = wrapper.attr('data-filter-type'); 1695 1696 if (type === 'select') { 1697 that.resetSelect(key); 1698 } else if (type === 'checkbox') { 1699 that.resetCheckbox(key); 1700 } else if (type === 'multiple_checkbox') { 1701 that.resetMultipleCheckbox(key); 1702 } else if (type === 'text') {
1703 that.resetText(key); 1704 } else if (type === 'color') { 1705 // direkt über wrapper â kein zweiter Selector-Lookup 1706 wrapper.find('.color_value').val(''); 1707 wrapper.find('.color.active').removeClass('active'); 1708 } else if (type === 'slider') { 1709 that.resetSlider(key); 1710 } else if (type === 'range') { 1711 let rangeEl = wrapper.find('.dxim_filter_range'); 1712 let filter1 = rangeEl.attr('data-filter-1'); 1713 let filter2 = rangeEl.attr('data-filter-2'); 1714 // direkt setzen â nicht auf noUiSlider update-Event warten 1715 if (filter1) $('#wpcs_fv_' + filter1).val('#'); 1716 if (filter2) $('#wpcs_fv_' + filter2).val('#'); 1717 // visuellen Reset trotzdem durchführen 1718 that.resetSlider(key + '_min'); 1719 } 1720 }); 1721 1722 that.isResetting = false; 1723 that._resetPageNr(); 1724 that.submit(); 1725 }; 1726 1727 // ---------------------------------------------------------- 1728 // setXxx â programmatic filter value setters (mirror of resetXxx) 1729 // Used by WPCSFilterSet AJAX mode to apply a filterset without page reload. 1730 // Call with isResetting = true around noUiSlider set() calls to suppress 1731 // intermediate _preFilterAmount triggers. 1732 // ---------------------------------------------------------- 1733 1734 // filterFormData: optional serialized filter string passed from applyFilterset so that 1735 // depends-fields (e.g. class=Car for category) are available server-side for label lookup. 1736 this.setSelect = function(key, value, filterFormData) { 1737 let obj = $('.dxim_filter[data-filter-name=' + key + '] .wpcsselect'); 1738 if (obj.length < 1) return; 1739 1740 if (!value) { that.resetSelect(key); return; } 1741 1742 // Set hidden value immediately so serialize() picks it up 1743 $('.wpcs_select_value', obj).val(value); 1744 $('.wpcs_select_delete', obj).show(); 1745 1746 // Show raw value immediately as fallback while fetching label 1747 $('.wpcs_select_handle', obj).text(value); 1748 1749 // Fetch human-readable label(s). load:'all' uses _getAll() callbacks which resolve 1750 // depends (e.g. classâcategory). filterFormData lets the server find the depends value. 1751 $.ajax({
1752 method: 'POST', 1753 url: wpcs_ajax_url, 1754 dataType: 'json', 1755 data: { action: 'getData', field: key, load: 'all', filterFormData: filterFormData || '' } 1756 }).done(function(data) { 1757 let selectedValues = value.split(','); 1758 let labels = []; 1759 1760 for (let index in data) { 1761 if (selectedValues.indexOf(String(data[index]['id'])) !== -1) { 1762 labels.push(data[index]['text']); 1763 } 1764 } 1765 1766 // Only update if the value hasn't changed in the meantime 1767 if ($('.wpcs_select_value', obj).val() !== value) return; 1768 1769 let handleText; 1770 if (labels.length === 0) handleText = value; // fallback: raw value 1771 else if (labels.length === 1) handleText = labels[0]; 1772 else handleText = labels.length + ' ausgewählt'; 1773 1774 $('.wpcs_select_handle', obj).html(handleText); 1775 }); 1776 }; 1777 1778 this.setCheckbox = function(key, value) { 1779 $('input[name=' + key + ']', '.dxim_filter').prop('checked', value === '1' || value === 'on'); 1780 }; 1781 1782 this.setText = function(key, value) { 1783 $('input[name=' + key + ']', '.dxim_filter').val(value); 1784 }; 1785 1786 this.setMultipleCheckbox = function(key, value) { 1787 let wrapper = $('.dxim_filter[data-filter-name=' + key + ']'); 1788 let vals = value ? value.split(',') : []; 1789 wrapper.find('.wpcs_element_value').val(value); 1790 wrapper.find('.wpcs_selectable').each(function() { 1791 $(this).toggleClass('selected', vals.indexOf(String($(this).data('value'))) !== -1); 1792 }); 1793 }; 1794 1795 this.setColor = function(key, value) { 1796 let obj = $('.dxim_filter[data-filter-name=' + key + '] .wpcs_color_select'); 1797 let vals = value ? value.split(',') : []; 1798 $('.color_value', obj).val(value); 1799 $('.color', obj).each(function() { 1800 $(this).toggleClass('active', vals.indexOf(String($(this).data('key'))) !== -1); 1801 }); 1802 }; 1803 1804 // Single slider: value is a number string 1805 this.setSlider = function(key, value) { 1806 let el = document.getElementById('wpcs_fs_' + key); 1807 if (!el || !el.noUiSlider) return; 1808 el.noUiSlider.set(parseFloat(value)); 1809 }; 1810 1811 // Range slider: key is wrapper's data-filter-name; pass null to keep current handle position 1812 this.setRange = function(key, minValue, maxValue) { 1813 let el = document.getElementById('wpcs_fs_' + key); 1814 if (!el || !el.noUiSlider) return; 1815 let cur = el.noUiSlider.get(); 1816 let newMin = (minValue !== null && minValue !== undefined) ? parseFloat(minValue) : parseFloat(cur[0]); 1817 let newMax = (maxValue !== null && maxValue !== undefined) ? parseFloat(maxValue) : parseFloat(cur[1]); 1818 el.noUiSlider.set([newMin, newMax]); 1819 }; 1820 1821 // Apply a full set of filterset params { key: value } to the filter form. 1822 // Resets all filters first, then sets each param, then submits via AJAX. 1823 this.applyFilterset = function(params) { 1824 // 1. Reset all filters silently 1825 that.isResetting = true; 1826 $('.dxim_filter[data-filter-name]').each(function() { 1827 let key = $(this).attr('data-filter-name'); 1828 let type = $(this).attr('data-filter-type'); 1829 if (type === 'select') that.resetSelect(key); 1830 else if (type === 'checkbox') that.resetCheckbox(key); 1831 else if (type === 'multiple_checkbox') that.resetMultipleCheckbox(key); 1832 else if (type === 'text') that.resetText(key); 1833 else if (type === 'color') that.resetColor(key); 1834 else if (type === 'slider') that.resetSlider(key); 1835 else if (type === 'range') that.resetSlider(key + '_min'); 1836 }); 1837 that._resetPageNr(); 1838 1839 // 2. Range sliders: params use filter-1/filter-2 keys (e.g. price_min, price_max), 1840 // not the wrapper's data-filter-name â match them to the right slider. 1841 let rangeHandled = {}; 1842 $('.dxim_filter[data-filter-type="range"]').each(function() { 1843 let key = $(this).attr('data-filter-name'); 1844 let rangeEl = $(this).find('.dxim_filter_range'); 1845 let f1 = rangeEl.attr('data-filter-1'); 1846 let f2 = rangeEl.attr('data-filter-2'); 1847 if (params[f1] === undefined && params[f2] === undefined) return; 1848 that.setRange( 1849 key, 1850 params[f1] !== undefined ? params[f1] : null, 1851 params[f2] !== undefined ? params[f2] : null 1852 ); 1853 if (f1) rangeHandled[f1] = true; 1854 if (f2) rangeHandled[f2] = true; 1855 }); 1856 1857 // 3. All other filter types 1858 // Build a filterFormData string from all params so that depends-fields 1859 // (e.g. class=Car) are available when fetching labels for dependent selects (e.g. category). 1860 let paramsFormData = Object.keys(params).map(function(k) { 1861 return encodeURIComponent(k) + '=' + encodeURIComponent(params[k]); 1862 }).join('&'); 1863 1864 $.each(params, function(key, value) { 1865 if (rangeHandled[key]) return; 1866 let w = $('.dxim_filter[data-filter-name="' + key + '"]'); 1867 if (w.length === 0) return; 1868 let type = w.attr('data-filter-type'); 1869 if (type === 'select') that.setSelect(key, value, paramsFormData); 1870 else if (type === 'checkbox') that.setCheckbox(key, value); 1871 else if (type === 'text') that.setText(key, value); 1872 else if (type === 'multiple_checkbox') that.setMultipleCheckbox(key, value); 1873 else if (type === 'color') that.setColor(key, value); 1874 else if (type === 'slider') that.setSlider(key, value); 1875 }); 1876 1877 that.isResetting = false; 1878 1879 // 4. Fetch results 1880 that.submitAjax(); 1881 }; 1882 1883 this.__construct(); 1884 } 1885 1886 1887 1888 /** 1889 * ----------------------------------------------------------- 1890 * Kontaktform 1891 * @constructor 1892 */ 1893 function WPCSContactForm() { 1894 1895 var that = this; 1896 this.form = null; 1897 this.spinner = null; 1898 1899 /** 1900 * 1901 * @private 1902 */ 1903 this.__construct = function() { 1904 1905 $('.wpcs_contact_form').each(function() { 1906 let form = this; 1907 that._initSubmit(form); 1908 that._initConditionalFields(form); 1909 that._initTimeSelects(form); 1910 that._initDateValidation(form); 1911 }); 1912 1913 }; 1914 1915 1916 /** 1917 * 1918 * @param form 1919 * @private 1920 */ 1921 this._setForm = function(form) { 1922 this.form = $(form); 1923 this.spinner = $('.wpcs_form_submit .wpcs_icon_spin', form); 1924 } 1925 1926 /** 1927 * 1928 * @param form 1929 * @private 1930 */ 1931 this._initSubmit = function(form) { 1932 $('.wpcs_form_submit', form).click(function(e) { 1933 e.preventDefault(); 1934 that._setForm(form); 1935 1936 if ($(this).hasClass('ga')) { 1937 grecaptcha.execute(wpcs_ga_public_key, { action: "submit" }).then(function(token) { 1938 that.sendForm(token); 1939 }); 1940 } else { 1941 that.sendForm(); 1942 } 1943 }); 1944 } 1945 1946 this.sendForm = function(token) { 1947 this.spinner.css('display', 'inline-block'); 1948 let redirect = $(this.form).data('redirect'); 1949 1950 // Disable inputs in hidden conditional fields/groups before serializing
1951 var $hiddenInputs = $('.wpcs_conditional_field.wpcs_hidden input, .wpcs_conditional_field.wpcs_hidden select, .wpcs_conditional_field.wpcs_hidden textarea', this.form); 1952 $hiddenInputs.prop('disabled', true); 1953 1954 var formData = that.form.serialize(); 1955 1956 // Re-enable inputs after serializing 1957 $hiddenInputs.prop('disabled', false); 1958 1959 $.ajax({ 1960 method: 'POST', 1961 url: wpcs_ajax_url, 1962 data: { action: 'wpcs_contactform', post: formData, token: token }, 1963 success: function(data) { 1964 that.spinner.hide(); 1965 that.unhighlightFormFields(); 1966 if (data.status === -1) that.highlightFormFields(data); 1967 else { 1968 that.form.parent().html(data.msg); 1969 if (redirect != "") window.location.href = redirect; 1970 } 1971 } 1972 }); 1973 }; 1974 1975 /** 1976 * 1977 */ 1978 this.unhighlightFormFields = function() { 1979 $('label', this.form).removeClass('required'); 1980 $('.wpcs-error-msg', this.form).hide(); 1981 }; 1982 1983 /** 1984 * 1985 * @param data 1986 */ 1987 this.highlightFormFields = function(data) { 1988 $('.wpcs-error-msg', this.form).fadeIn(); 1989 $(data.error).each(function() { 1990 $('label[rel=' + this + ']', this.form).addClass('required'); 1991 }); 1992 }; 1993 1994 this._initConditionalFields = function(form) { 1995 var $form = $(form); 1996 1997 // Legacy: handle old wpcs_conditional_group elements 1998 var groups = $('.wpcs_conditional_group', $form); 1999 2000 // New: handle wpcs_conditional_field elements with multiple conditions 2001 var conditionalFields = $('.wpcs_conditional_field', $form); 2002 2003 if (groups.length < 1 && conditionalFields.length < 1) return; 2004 2005 var checkConditions = function() { 2006 // Legacy group handling 2007 groups.each(function() { 2008 var $group = $(this); 2009 var condField = $group.data('condition-field'); 2010 var condValue = $group.data('condition-value'); 2011 var checked = $('input[name="' + condField + '[]"][value="' + condValue + '"]', $form).is(':checked'); 2012 if (checked) $group.removeClass('wpcs_hidden'); 2013 else $group.addClass('wpcs_hidden'); 2014 }); 2015 2016 // New: handle fields with multiple conditions (OR logic) 2017 conditionalFields.each(function() { 2018 var $field = $(this); 2019 var conditions = $field.data('conditions'); 2020 if (!conditions || !Array.isArray(conditions)) return; 2021 2022 var isVisible = false; 2023 2024 // Check if ANY condition is met (OR logic) 2025 for (var i = 0; i < conditions.length; i++) { 2026 var cond = conditions[i]; 2027 var triggerField = cond.field; 2028 var triggerValue = cond.value; 2029 2030 // Check checkbox inputs 2031 var checkboxChecked = $('input[name="' + triggerField + '[]"][value="' + triggerValue + '"]', $form).is(':checked'); 2032 2033 // Check select inputs (standard select) 2034 var selectValue = $('select[name="' + triggerField + '"]', $form).val(); 2035 var selectMatches = selectValue === triggerValue; 2036 2037 // Check hidden inputs (used by wpcsselect custom selects) 2038 var hiddenValue = $('input[type="hidden"][name="' + triggerField + '"]', $form).val(); 2039 var hiddenMatches = hiddenValue === triggerValue; 2040 2041 if (checkboxChecked || selectMatches || hiddenMatches) { 2042 isVisible = true; 2043 break; 2044 } 2045 } 2046 2047 if (isVisible) { 2048 $field.removeClass('wpcs_hidden'); 2049 } else { 2050 $field.addClass('wpcs_hidden'); 2051 } 2052 }); 2053 }; 2054 2055 $form.on('change', 'input[type="checkbox"], input[type="hidden"], select', checkConditions); 2056 checkConditions(); 2057 }; 2058 2059 this._initTimeSelects = function(form) { 2060 var $form = $(form); 2061 2062 // Find all time picker components 2063 $('.wpcs_time_picker', $form).each(function() { 2064 var $picker = $(this); 2065 var $input = $('.wpcs_time_input', $picker); 2066 var $hiddenField = $('.wpcs_time_value', $picker); 2067 var $dropdown = $('.wpcs_time_dropdown', $picker); 2068 var $hoursList = $('.wpcs_time_hours', $picker); 2069 var $minutesList = $('.wpcs_time_minutes', $picker); 2070 2071 var selectedHour = null; 2072 var selectedMinute = null; 2073 2074 // Open dropdown when clicking on input 2075 $input.on('click', function(e) { 2076 e.preventDefault(); 2077 e.stopPropagation(); 2078 // Close all other time pickers 2079 $('.wpcs_time_picker').not($picker).removeClass('wpcs_open'); 2080 $picker.toggleClass('wpcs_open'); 2081 }); 2082 2083 // Prevent dropdown from closing when clicking inside it 2084 $dropdown.on('click', function(e) { 2085 e.stopPropagation(); 2086 }); 2087 2088 // Hour selection 2089 $('.wpcs_time_option', $hoursList).on('click', function(e) { 2090 e.stopPropagation(); 2091 selectedHour = $(this).data('value'); 2092 $('.wpcs_time_option', $hoursList).removeClass('wpcs_active'); 2093 $(this).addClass('wpcs_active'); 2094 updateDisplay(); 2095 }); 2096 2097 // Minute selection 2098 $('.wpcs_time_option', $minutesList).on('click', function(e) { 2099 e.stopPropagation(); 2100 selectedMinute = $(this).data('value'); 2101 $('.wpcs_time_option', $minutesList).removeClass('wpcs_active'); 2102 $(this).addClass('wpcs_active'); 2103 updateDisplay(); 2104 }); 2105 2106 // Update display and hidden field 2107 var updateDisplay = function() { 2108 var displayHour = selectedHour !== null ? selectedHour : '--'; 2109 var displayMinute = selectedMinute !== null ? selectedMinute : '--';
2110 $input.val(displayHour + ':' + displayMinute); 2111 2112 // Only set hidden field value if both are selected 2113 if (selectedHour !== null && selectedMinute !== null) { 2114 $hiddenField.val(selectedHour + ':' + selectedMinute); 2115 } else { 2116 $hiddenField.val(''); 2117 } 2118 }; 2119 }); 2120 2121 // Close all time pickers when clicking outside (only register once) 2122 $(document).off('click.timepicker').on('click.timepicker', function(e) { 2123 if (!$(e.target).closest('.wpcs_time_picker').length) { 2124 $('.wpcs_time_picker').removeClass('wpcs_open'); 2125 } 2126 }); 2127 }; 2128 2129 /** 2130 * iOS Safari doesn't enforce min/max on date inputs 2131 * This adds JavaScript validation as a fallback 2132 */ 2133 this._initDateValidation = function(form) { 2134 var $form = $(form); 2135 2136 $('input[type="date"]', $form).on('change', function() { 2137 var $input = $(this); 2138 var value = $input.val(); 2139 var min = $input.attr('min'); 2140 var max = $input.attr('max'); 2141 2142 if (!value) return; 2143 2144 // Validate min 2145 if (min && value < min) { 2146 $input.val(min); 2147 } 2148 2149 // Validate max 2150 if (max && value > max) { 2151 $input.val(max); 2152 } 2153 }); 2154 }; 2155 2156 this.__construct(); 2157 } 2158 2159 function add_body_classes() { 2160 if (typeof wpcs_screen_width_mobile == "undefined" || typeof wpcs_screen_width_tablet == "undefined") return; 2161 2162 let w = $(this).width(); 2163 if (w <= wpcs_screen_width_mobile) $('body').addClass('wpcs_mobile').removeClass('wpcs_tablet').removeClass('wpcs_desktop'); 2164 else if (w <= wpcs_screen_width_tablet) $('body').removeClass('wpcs_mobile').addClass('wpcs_tablet').removeClass('wpcs_desktop'); 2165 else $('body').removeClass('wpcs_mobile').removeClass('wpcs_tablet').addClass('wpcs_desktop'); 2166 } 2167 2168 2169 $(window).resize(function() { 2170 add_body_classes(); 2171 }); 2172 2173 function WPCSScroller(scroller) { 2174 var that = this; 2175 this.scroller = scroller; 2176 2177 this.__construct = function() { 2178 $(this.scroller).on('scroll', that.updateClasses); 2179 $(window).on('resize', that.updateClasses); 2180 2181 this.updateClasses(); 2182 } 2183 2184 this.updateClasses = function() { 2185 2186 if (that.scroller.scrollLeft > 0) { 2187 that.scroller.classList.add('can_scroll_left'); 2188 } else { 2189 that.scroller.classList.remove('can_scroll_left'); 2190 } 2191 2192 if (that.scroller.scrollLeft < that.scroller.scrollWidth - that.scroller.clientWidth) { 2193 that.scroller.classList.add('can_scroll_right'); 2194 } else { 2195 that.scroller.classList.remove('can_scroll_right'); 2196 } 2197 } 2198 2199 this.__construct(); 2200 } 2201 2202 2203 function WPCSSticky(sticky) { 2204 2205 var that = this; 2206 this.sticky = $(sticky); 2207 this.width; 2208 2209 this.offsetStart; 2210 this.offsetStop; 2211 this.initialTop; 2212 2213 this.stickyStartObj; 2214 this.stickyStopObj; 2215 2216 this.__construct = function() { 2217 2218 this.stickyStartObj = $(this.sticky.data('sticky-start')); 2219 this.stickyStopObj = $(this.sticky.data('sticky-stop')); 2220 this.offsetStart = parseInt(this.sticky.data('sticky-start-offset')) || 0; 2221 this.offsetStop = parseInt(this.sticky.data('sticky-stop-offset')) || 0; 2222 2223 $(window).on('scroll', function() { that.update(); }); 2224 $(window).on('resize', function() { that.update(); }); 2225 2226 this.update(); 2227 } 2228 2229 this.update = function() { 2230 2231 if ($(window).width() < 1024) { 2232 that.setSticky(false); 2233 return; 2234 } 2235 2236 let stickyStart = this.stickyStartObj.length ? this.stickyStartObj.position().top + this.stickyStartObj.outerHeight() : 0; 2237 2238 if (!this.sticky.hasClass('isSticky')) this.initialTop = this.sticky.offset().top; 2239 let position = this.initialTop; 2240 var scrollTop = $(window).scrollTop(); 2241 let isSticky = false; 2242 let top = 0; 2243 2244 // calc start 2245 if ((scrollTop + stickyStart >= position)) { 2246 top = stickyStart + this.offsetStart; 2247 isSticky = true; 2248 } 2249 2250 // calc end 2251 if (isSticky && this.stickyStopObj.length > 0) { 2252 let check = this.sticky.outerHeight() + top + this.offsetStop; 2253 if ((this.stickyStopObj.offset().top - scrollTop <= check)) { 2254 isSticky = false; 2255 } 2256 } 2257 2258 // set sticky 2259 if (isSticky) this.setSticky(true, top); 2260 else this.setSticky(false) 2261 2262 } 2263
2264 this.setSticky = function(sticky, top = 0) { 2265 if (sticky) { 2266 this.sticky.css({ 2267 position: 'fixed', 2268 top: top + 'px', 2269 width: that.calcWidth() + 'px', 2270 }).addClass('isSticky'); 2271 } else { 2272 this.sticky.css({ 2273 position: 'initial', 2274 top: 'initial', 2275 width: 'auto', 2276 }).removeClass('isSticky'); 2277 } 2278 } 2279 2280 this.calcWidth = function() { 2281 this.sticky.css({ 2282 position: 'initial', 2283 width: 'auto' 2284 }); 2285 return this.sticky.width(); 2286 } 2287 2288 this.__construct(); 2289 } 2290 2291 // ------------------------------------------------------- 2292 // WPCSFilterSet â marks active button; AJAX mode applies filters without page reload 2293 // ------------------------------------------------------- 2294 function WPCSFilterSet() { 2295 2296 $(document).on('click', '.wpcs-filterset-btn', function (e) { 2297 var $btn = $(this); 2298 var isActive = $btn.hasClass('wpcs-filterset-active'); 2299 2300 if (!(wpcs_form && wpcs_form.ajax)) { 2301 // no AJAX: normal href navigation, just toggle active class 2302 $('.wpcs-filterset-btn').removeClass('wpcs-filterset-active'); 2303 if (!isActive) $btn.addClass('wpcs-filterset-active'); 2304 return; 2305 } 2306 2307 e.preventDefault(); 2308 2309 // Toggle: clicking an already-active filterset resets all filters 2310 if (isActive) { 2311 $('.wpcs-filterset-btn').removeClass('wpcs-filterset-active'); 2312 wpcs_form.resetAllFilters(); 2313 return; 2314 } 2315 2316 $('.wpcs-filterset-btn').removeClass('wpcs-filterset-active'); 2317 $btn.addClass('wpcs-filterset-active'); 2318 2319 // Parse query params from href into a plain object 2320 var href = $btn.attr('href') || ''; 2321 var qIdx = href.indexOf('?'); 2322 var params = {}; 2323 if (qIdx !== -1) { 2324 href.substring(qIdx + 1).split('&').forEach(function (part) { 2325 var eq = part.indexOf('='); 2326 if (eq > -1) { 2327 // + als %20 behandeln bevor decodeURIComponent â http_build_query kodiert Spaces als + 2328 var decode = function(s) { return decodeURIComponent(s.replace(/\+/g, '%20')); }; 2329 params[decode(part.substring(0, eq))] = decode(part.substring(eq + 1)); 2330 } 2331 }); 2332 } 2333 2334 wpcs_form.applyFilterset(params); 2335 }); 2336 } 2337 2338 2339})(jQuery); 2340 2341// ----------------------------------------------------------------------- 2342// Contact form file upload 2343// ----------------------------------------------------------------------- 2344(function($) { 2345 2346 function wpcsUploadFile(file, fieldKey, $wrapper) { 2347 var formData = new FormData(); 2348 formData.append('action', 'wpcs_contactform_file_upload'); 2349 formData.append('nonce', wpcs_contactform_upload_nonce); 2350 formData.append('file', file); 2351 2352 var $list = $wrapper.find('.wpcs-upload-list'); 2353 var $item = $('<li class="wpcs-upload-item">' + $('<span>').text(file.name).html() + ' <span class="wpcs-upload-status">...</span></li>'); 2354 $list.append($item); 2355 2356 $.ajax({
2357 url: wpcs_ajax_url, 2358 method: 'POST', 2359 data: formData, 2360 processData: false, 2361 contentType: false, 2362 success: function(resp) { 2363 if (resp.success) { 2364 $item.find('.wpcs-upload-status').text('â'); 2365 $wrapper.append('<input type="hidden" name="wpcs_uploads[' + fieldKey + '][]" value="' + resp.data.filename + '">'); 2366 var $remove = $('<span class="wpcs-upload-remove" style="cursor:pointer;margin-left:8px;color:#c00;" title="Entfernen">â</span>'); 2367 $remove.on('click', function() { 2368 $.post(wpcs_ajax_url, { action: 'wpcs_contactform_file_delete', nonce: wpcs_contactform_upload_nonce, filename: resp.data.filename }); 2369 $wrapper.find('input[value="' + resp.data.filename + '"]').remove(); 2370 $item.remove(); 2371 }); 2372 $item.append($remove); 2373 } else { 2374 $item.find('.wpcs-upload-status').text('Fehler: ' + (resp.data && resp.data.msg ? resp.data.msg : 'Upload fehlgeschlagen')); 2375 } 2376 }, 2377 error: function() { 2378 $item.find('.wpcs-upload-status').text('Upload fehlgeschlagen.'); 2379 } 2380 }); 2381 } 2382 2383 $(document).on('change', '.wpcs-file-input', function() { 2384 var $input = $(this); 2385 var $wrapper = $input.closest('.wpcs-file-upload-wrapper'); 2386 var fieldKey = $wrapper.data('field-key'); 2387 var maxFiles = parseInt($wrapper.data('max-files')) || 5; 2388 var files = this.files; 2389 2390 for (var i = 0; i < files.length; i++) { 2391 if ($wrapper.find('input[type="hidden"]').length >= maxFiles) { 2392 alert('Maximale Anzahl Dateien erreicht (' + maxFiles + ').'); 2393 break; 2394 } 2395 wpcsUploadFile(files[i], fieldKey, $wrapper); 2396 } 2397 2398 $input.val(''); 2399 }); 2400 2401})(jQuery);
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.