1/*global konteData*/ 2var konte = konte || {}; 3 4(function( $ ) { 5 'use strict'; 6 7 /** 8 * The main function to init the theme 9 */ 10 konte.init = function() { 11 this.data = konteData || {}; 12 13 this.preloader(); 14 15 this.focusSearchField(); 16 this.instantSearch(); 17 this.ajaxSearch(); 18 this.toggleListDropdown(); 19 this.addWishlistCounter(); 20 this.toggleHamburgerScreen(); 21 this.toggleHamburgerMenu(); 22 this.toggleVerticalMenu(); 23 this.toggleOffCanvas(); 24 this.calculateMenuAccessibleArea(); 25 this.toggleModals(); 26 this.loadMorePosts(); 27 this.fetchPostTotalShare(); 28 29 this.featuredContentCarousel(); 30 this.postsSliderWidget(); 31 this.stickySidebar(); 32 33 this.closeTopbar(); 34 this.stickyHeader(); 35 this.pageHeaderHeight(); 36 this.scrollDown(); 37 38 this.closeWCMessages(); 39 this.productQuantityButtons(); 40 this.singleProductAjaxAddToCart(); 41 this.stickyAddToCart(); 42 this.cartPanel(); 43 this.reviewProduct(); 44 this.productLightBox(); 45 this.toggleProductTabs(); 46 this.productVariationSwatches(); 47 this.relatedProductsCarousel(); 48 this.productGalleryCarousel(); 49 this.productGalleryThumbnailCarousel(); 50 51 this.singleProductV1(); 52 this.singleProductV2(); 53 this.singleProductV3(); 54 this.singleProductV4(); 55 this.singleProductV5(); 56 this.singleProductV6(); 57 this.singleProductV7(); 58 59 this.formFieldFocus(); 60 this.loginTabs(); 61 this.loginPanel(); 62 this.loginPanelAuthenticate(); 63 64 this.productsMasonry(); 65 this.productsCarousel(); 66 this.productThumbnailsSlider(); 67 this.productThumbnailZoom(); 68 this.productQuickView(); 69 this.emptyQuickViewOnClose(); 70 this.autoCloseQuickView(); 71 this.loadMoreProducts(); 72 73 this.productsQuickSearch(); 74 this.productsTools(); 75 this.cartWidget(); 76 this.shopNotifications(); 77 78 this.pageTemplateSplit(); 79 this.videoBackground(); 80 81 this.pageTemplateFlexPosts(); 82 this.stickyScrollDown(); 83 this.stickySocials(); 84 this.openShareLinks(); 85 86 this.popup(); 87 88 this.fixVCRowsWithVerticalHeader(); 89 // this.responsiveVideos(); 90 this.mobileMenu(); 91 this.responsiveProductGallery(); 92 this.responsiveProductV3(); 93 94 this.portfolioMasonry(); 95 this.portfolioFilter(); 96 97 this.backToTop(); 98 this.lazyLoadImages(); 99 this.supportJetpackLazyLoadImagesOnProductGallery(); 100 101 this.updateCheckout(); 102 this.mainMenuTabs(); 103 104 $( document.body ).trigger( 'konte_initialized', this ); 105 }; 106 107 /** 108 * Update checkout after fragments updated 109 */ 110 konte.updateCheckout = function() { 111 if ( ! $( document.body ).hasClass( 'woocommerce-checkout' ) ) { 112 return; 113 } 114 115 $( document.body ).on( 'wc_fragments_loaded wc_fragments_refreshed', function() { 116 $( document.body ).trigger( 'update_checkout' ); 117 }); 118 } 119 120 /** 121 * Open quick links when focus on search field 122 */ 123 konte.focusSearchField = function() { 124 $( '.header-search .search-field' ).on( 'focus', function() { 125 var $quicklinks = $( this ).closest( '.header-search' ).find( '.quick-links' ); 126 127 if ( $quicklinks.length ) { 128 $quicklinks.addClass( 'open' ); 129 } 130 131 $( this ).addClass( 'focused' ).closest( '.header-search' ).addClass( 'input-focused' ); 132 } ); 133 134 $( document.body ).on( 'click', 'div', function( event ) { 135 var $target = $( event.target ); 136 137 if ( $target.is( '.header-search' ) || $target.closest( '.header-search' ).length ) { 138 return; 139 } 140 141 var $headerSearch = $( '.header-search' ); 142 143 $headerSearch.removeClass( 'input-focused' ); 144 $( '.quick-links', $headerSearch ).removeClass( 'open' ); 145 $( '.search-field', $headerSearch ).removeClass( 'focused' ); 146 } ); 147 }; 148 149 /** 150 * Instance search in the search modal. 151 */ 152 konte.instantSearch = function() { 153 var xhr = null, 154 term = '', 155 searchCache = {}, 156 debounceTimeout = null, 157 $modal = $( '#search-modal' ), 158 $header = $modal.find( '.modal-header' ), 159 $content = $modal.find( '.modal-content' ), 160 $form = $modal.find( 'form' ),
161 $search = $form.find( 'input.search-field' ), 162 $result = $modal.find( '.search-result' ), 163 $button = $result.find( '.view-more a' ), 164 $quicklinks = $modal.find( '.quick-links' ), 165 post_type = $modal.find( 'input[name=post_type]' ).val(); 166 167 if ( !$modal.length ) { 168 return; 169 } 170 171 // Focus on the search field when search modal opened 172 $( document.body ).on( 'konte_modal_opened', function( event, target ) { 173 if ( target.is( '#search-modal' ) ) { 174 $search.focus(); 175 } 176 } ); 177 178 new PerfectScrollbar( $result.find( '.searched-items' ).get( 0 ), { 179 suppressScrollX: true 180 } ); 181 182 $modal.on( 'keyup', '.search-field', function( e ) { 183 var valid = false; 184 185 if ( typeof e.which === 'undefined' ) { 186 valid = true; 187 } else if ( typeof e.which === 'number' && e.which > 0 ) { 188 valid = !e.ctrlKey && !e.metaKey && !e.altKey; 189 } 190 191 if ( !valid ) { 192 return; 193 } 194 195 // if ( xhr ) { 196 // xhr.abort(); 197 // } 198 199 $quicklinks.fadeOut( 400 ); 200 201 if ( debounceTimeout ) { 202 clearTimeout( debounceTimeout ); 203 } 204 205 debounceTimeout = setTimeout( function() { 206 search(); 207 }, 800 ); 208 } ).on( 'click', '.search-reset', function() { 209 if ( xhr ) { 210 xhr.abort(); 211 } 212 213 $quicklinks.fadeIn( 400 ); 214 $modal.addClass( 'reset' ); 215 $result.fadeOut( function() { 216 $modal.removeClass( 'searching searched search-found search-not-found invalid-length reset' ); 217 $content.removeAttr( 'style' ); 218 } ); 219 } ).on( 'focusout', '.search-field', function() { 220 if ( $search.val().length < 2 ) { 221 $quicklinks.fadeIn( 400 ); 222 $result.fadeOut( function() { 223 $modal.removeClass( 'searching searched search-found search-not-found invalid-length' ); 224 $content.removeAttr( 'style' ); 225 } ); 226 } 227 } ); 228 229 /** 230 * Private function for searching products 231 */ 232 function search() { 233 var keyword = $search.val(), 234 key = keyword; 235 236 if ( term === keyword ) { 237 return; 238 } 239 240 term = keyword; 241 242 if ( keyword.length < 2 ) { 243 $modal.removeClass( 'searched searching search-found search-not-found' ); 244 return; 245 } 246 247 var url = $form.attr( 'action' ) + '?' + $form.serialize(); 248 249 $( '.view-more-results', $result ).slideUp( 10 ); 250 $modal.removeClass( 'search-found search-not-found searched' ).addClass( 'searching' ); 251 252 if ( key in searchCache ) { 253 showResult( searchCache[key] ); 254 } else { 255 xhr = $.post( url, 256 { 257 search_columns: 6, 258 konte_search_nonce: konte.data.product_search_nonce 259 }, 260 function( response ) { 261 if ( ! response ) { 262 $modal.removeClass( 'searching' ); 263 return; 264 } 265 266 var $primary = $( '#primary', response ); 267 268 if ( 'product' === post_type ) { 269 var $products = $( 'ul.products', $primary ); 270 271 if ( $products.length ) { 272 // Cache 273 searchCache[key] = { 274 found: true, 275 items: $products, 276 url : url 277 }; 278 } else { 279 // Cache 280 searchCache[key] = { 281 found: false, 282 text : $( '.woocommerce-info', $primary ).text() 283 }; 284 } 285 } else { 286 var $posts = $( '#main article', $primary ); 287 288 if ( $posts.length ) { 289 $posts.addClass( 'col-md-4' ); 290 291 searchCache[key] = { 292 found: true, 293 items: $( '<div class="posts row" />' ).append( $posts ), 294 url : url 295 }; 296 } else { 297 searchCache[key] = { 298 found: false, 299 text : $( '.no-results .nothing-found-message', $primary ).text() 300 }; 301 } 302 } 303 304 showResult( searchCache[key] ); 305 }, 'html' ); 306 } 307 } 308 309 /** 310 * Private function for showing the search result 311 * 312 * @param result 313 */ 314 function showResult( result ) { 315 var extraClass = 'product' === post_type ? 'woocommerce' : '', 316 $container = $result.find( '.searched-items' ); 317 318 $modal.removeClass( 'searching' ); 319 $content.css( 'top', $header.outerHeight() + 65 ); 320 321 if ( result.found ) { 322 var grid = result.items.clone(), 323 items = grid.children(); 324 325 $modal.addClass( 'search-found' ); 326 $button.attr( 'href', result.url ); 327 328 $container 329 .addClass( extraClass ) 330 .html( grid ) 331 .append( $result.find( '.view-more' ).clone() ); 332 333 // Init zoom/slider thumbnail 334 if ( 'product' === post_type ) { 335 $( document.body ).trigger( 'konte_loaded_products', [items] ); 336 } 337 338 // Add animation class 339 for ( var index = 0; index < items.length; index++ ) { 340 $( items[index] ).css( 'animation-delay', index * 100 + 'ms' ); 341 } 342 343 items.addClass( 'animated konteFadeInUp' ); 344 $container.find( '.view-more' ).css( 'animation-delay', ++index * 100 + 'ms' ).addClass( 'animated konteFadeInUp' ); 345 $result.slideDown(); 346 } else { 347 $modal.addClass( 'search-not-found' ); 348 349 $container.removeClass( extraClass ).html( $( '<div class="not-found" />' ).text( result.text ) ); 350 $button.attr( 'href', '#' ); 351 352 $result.slideDown(); 353 } 354 355 $modal.addClass( 'searched' ); 356 $( document.body ).trigger( 'konte_lazy_load_images' ); 357 } 358 }; 359 360 /** 361 * Ajax search for header search from. 362 */ 363 konte.ajaxSearch = function() { 364 if ( ! konte.data.header_search_ajax ) { 365 return; 366 } 367 368 var debounceTimeout = null, 369 cachedResults = {}; 370 371 // Create the results container. 372 $( '<div class="header-search__results" />' ).insertAfter( '.header-search form' ); 373 374 $( '.header-search input[name="s"]' ).on( 'input', function() { 375 var $input = $( this ), 376 $search = $input.closest( '.header-search' ), 377 $results = $search.find( '.header-search__results' ), 378 term = $input.val(); 379 380 if ( ! term ) { 381 if ( debounceTimeout ) { 382 clearTimeout( debounceTimeout ); 383 } 384 385 $search.removeClass( 'ajax-loading' ); 386 $results.html( '' ); 387 $search.removeClass( 'show-results' ); 388 return; 389 } 390 391 if ( cachedResults[ term ] ) { 392 $results.html( cachedResults[ term ] ); 393 $search.addClass( 'show-results' ); 394 return; 395 } 396 397 if ( debounceTimeout ) { 398 clearTimeout( debounceTimeout ); 399 } 400 401 debounceTimeout = setTimeout( function() {
402 var data = $input.closest( 'form' ).serializeArray(); 403 404 data.push( {name: 'action', value: 'konte_header_search'} ); 405 406 $.ajax( { 407 type : 'POST', 408 url : konte.data.ajax_url, 409 data : data, 410 beforeSend: function() { 411 $search.addClass( 'ajax-loading' ); 412 }, 413 success: function( response ) { 414 if ( ! response.success ) { 415 return; 416 } 417 418 cachedResults[ term ] = response.data; 419 420 if ( response.data ) { 421 $results.html( response.data ); 422 $search.addClass( 'show-results' ); 423 } else { 424 $results.html( '' ); 425 $search.removeClass( 'show-results' ); 426 } 427 }, 428 complete: function() { 429 $search.removeClass( 'ajax-loading' ); 430 }, 431 dataType: 'json' 432 } ); 433 }, 800 ); 434 } ); 435 } 436 437 /** 438 * Toggle list dropdown 439 */ 440 konte.toggleListDropdown = function() { 441 442 $( document.body ).on( 'click', '.list-dropdown ul li', function() { 443 var $selected = $( this ); 444 445 $selected.closest( '.list-dropdown' ).removeClass( 'open' ).find( '.current .selected' ).text( $selected.find( '.name' ).text() ); 446 } ); 447 448 if ( 'ontouchstart' in document.documentElement ) { 449 $( document.body ).on( 'click', '.list-dropdown .current', function( event ) { 450 event.preventDefault(); 451 452 $( this ).closest( '.list-dropdown' ).toggleClass( 'open' ); 453 } ).on( 'click', '.list-dropdown ul li', function() { 454 var $selected = $( this ); 455 456 $selected.closest( '.list-dropdown' ).removeClass( 'open' ).find( '.current .selected' ).text( $selected.find( '.name' ).text() ); 457 } ).on( 'click', function( event ) { 458 var $target = $( event.target ); 459 460 if ( $target.is( '.list-dropdown' ) || $target.closest( '.list-dropdown' ).length ) { 461 return; 462 } 463 464 $( '.list-dropdown' ).removeClass( 'open' ); 465 } ); 466 } 467 }; 468 469 /** 470 * Add wishlist counter to the Account navigation 471 */ 472 konte.addWishlistCounter = function() { 473 $( '.woocommerce-MyAccount-navigation-link--wishlist, .account-link--wishlist' ) 474 .append( '<span class="counter wishlist-counter">' + konte.data.wishlist_count + '</span>' ); 475 }; 476 477 /** 478 * Calculate accessible area of main navigation's submenu 479 */ 480 konte.calculateMenuAccessibleArea = function() { 481 $( '.main-navigation', '#masthead' ).each( function() { 482 var $menu = $( this ), 483 $firstItem = $menu.children( 'ul' ).children( 'li:first' ), 484 accessibleGap = ( $firstItem.height() - $firstItem.children( 'a ' ).height() ) / 2; 485 486 $menu.css( { '--submenu-offset': accessibleGap.toString() + 'px' } ); 487 } ); 488 }; 489 490 /** 491 * Toggle hamburger full-screen 492 */ 493 konte.toggleHamburgerScreen = function() { 494 $( document.body ).on( 'click', '.header-hamburger', function( event ) { 495 event.preventDefault(); 496 497 var $el = $( this ), 498 $screen = $( '#' + $el.data( 'target' ) ); 499 500 if ( !$screen.length ) { 501 return; 502 } 503 504 var $menu = $( '#fullscreen-menu', $screen ), 505 $widgets = $( '.filter-widgets', $screen ), 506 $socials = $( '.social-icons', $screen ), 507 $currency = $( '.currency', $screen ), 508 $language = $( '.language', $screen ), 509 step = 100, 510 count = 0; 511 512 // Add animation if enabled. 513 if ( !$screen.hasClass( 'content-animation-none' ) ) { 514 if ( $screen.hasClass( 'content-animation-fade' ) ) { 515 step = 160; 516 } 517 518 if ( $menu.length && !$menu.data( 'delay' ) ) { 519 $( '.menu > li', $menu ).each( function() { 520 $( this ).css( 'animation-delay', count * step + 'ms' ); 521 count++; 522 } ); 523 524 $menu.data( 'delay', count ); 525 } else if ( $widgets.length && !$widgets.data( 'delay' ) ) { 526 $( '.widget', $widgets ).each( function() { 527 $( this ).css( 'animation-delay', count * step + 'ms' ); 528 count++; 529 } ); 530 531 $widgets.data( 'delay', count ); 532 } 533 534 count = 1; 535 if ( $socials.length && !$socials.data( 'delay' ) ) { 536 $( '.menu > li', $socials ).each( function() { 537 $( this ).css( 'animation-delay', count * step + 'ms' ); 538 count++; 539 } ); 540 541 $socials.data( 'delay', count ); 542 } 543 544 if ( $currency.length && !$currency.data( 'delay' ) ) { 545 $currency.css( 'animation-delay', count * step + 'ms' ); 546 $currency.data( 'delay', count ); 547 count++; 548 } 549 550 if ( $language.length && !$language.data( 'delay' ) ) { 551 $language.css( 'animation-delay', count * step + 'ms' ); 552 $language.data( 'delay', count ); 553 count++; 554 } 555 } 556 557 $screen.fadeToggle( function() { 558 $( '.hamburger-menu', $screen ).addClass( 'active' ); 559 } ); 560 $screen.addClass( 'open' ); 561 } ).on( 'click', '#hamburger-fullscreen .button-close', function( event ) { 562 event.stopPropagation(); 563 564 var $el = $( this ), 565 $screen = $( '#hamburger-fullscreen' ); 566 567 $el.removeClass( 'active' ); 568 $screen.removeClass( 'open' ); 569 570 setTimeout( function() { 571 $screen.fadeOut(); 572 }, 420 ); 573 } ); 574 575 // Init scrollbar for full screen menu. 576 if ( typeof PerfectScrollbar !== 'undefined' ) { 577 var $hamburgerScreen = $( '#hamburger-fullscreen' ); 578 579 if ( $hamburgerScreen.length ) { 580 new PerfectScrollbar( $( '.hamburger-screen-content', $hamburgerScreen ).get( 0 ) ); 581 } 582 } 583 }; 584 585 /** 586 * Toggle sub-menu inside hamburger screen 587 */ 588 konte.toggleHamburgerMenu = function() { 589 var $menu = $( '#fullscreen-menu' ); 590 591 if ( !$menu.length ) { 592 return; 593 } 594 595 // Open when click 596 if ( $menu.hasClass( 'click-open' ) ) { 597 $menu.on( 'click', '.menu li.menu-item-has-children > a', function( event ) { 598 event.preventDefault(); 599 600 var $item = $( this ).parent(); 601 602 $item.toggleClass( 'active' ).siblings().removeClass( 'active' ).children( 'ul' ).removeClass( 'open' ); 603 $item.children( 'ul' ).toggleClass( 'open' ); 604 605 // If this is sub-menu item 606 if ( $item.closest( 'ul' ).hasClass( 'sub-menu' ) ) { 607 $item.children( 'ul' ).slideToggle();
608 $item.siblings().find( 'ul' ).slideUp(); 609 } 610 } ); 611 } 612 }; 613 614 /** 615 * Toggle sub-menu of vertical header 616 */ 617 konte.toggleVerticalMenu = function() { 618 var $menu = $( '.header-vertical .main-navigation' ); 619 620 if ( ! $menu.length ) { 621 return; 622 } 623 624 var dropdown = $menu.children( '.menu' ).hasClass( 'nav-menu--submenu-slidedown' ); 625 626 // Open when click 627 $menu.on( 'click', 'li.menu-item-has-children > a', function( event ) { 628 var $item = $( this ).parent(); 629 630 $item.toggleClass( 'active' ).siblings().removeClass( 'active' ).children( 'ul' ).removeClass( 'open' ); 631 $item.children( 'ul' ).toggleClass( 'open' ); 632 633 // If this is sub-menu item 634 if ( dropdown || $item.closest( 'ul' ).hasClass( 'sub-menu' ) ) { 635 $item.children( 'ul' ).slideToggle(); 636 $item.siblings().find( 'ul' ).slideUp(); 637 638 event.preventDefault(); 639 } 640 } ); 641 }; 642 643 /** 644 * Toggle off-screen panels 645 */ 646 konte.toggleOffCanvas = function() { 647 $( document.body ).on( 'click', '[data-toggle="off-canvas"]', function( event ) { 648 var target = '#' + $( this ).data( 'target' ); 649 650 if ( $( target ).hasClass( 'open' ) ) { 651 konte.closeOffCanvas( target ); 652 } else if ( konte.openOffCanvas( target ) ) { 653 event.preventDefault(); 654 } 655 } ).on( 'click', '.offscreen-panel .button-close, .offscreen-panel .backdrop', function( event ) { 656 event.preventDefault(); 657 658 konte.closeOffCanvas( this ); 659 } ).on( 'keyup', function ( e ) { 660 if ( e.keyCode === 27 ) { 661 konte.closeOffCanvas(); 662 } 663 } ); 664 }; 665 666 /** 667 * Open off canvas panel. 668 * @param string target Target selector. 669 */ 670 konte.openOffCanvas = function( target ) { 671 var $target = $( target ); 672 673 if ( !$target.length ) { 674 return false; 675 } 676 677 $target.fadeIn(); 678 $target.addClass( 'open' ); 679 680 $( document.body ).addClass( 'offcanvas-opened ' + $target.attr( 'id' ) + '-opened' ).trigger( 'konte_off_canvas_opened', [$target] ); 681 682 return true; 683 } 684 685 /** 686 * Close off canvas panel. 687 * @param DOM target 688 */ 689 konte.closeOffCanvas = function( target ) { 690 if ( !target ) { 691 $( '.offscreen-panel' ).each( function() { 692 var $panel = $( this ); 693 694 if ( ! $panel.hasClass( 'open' ) ) { 695 return; 696 } 697 698 $panel.removeClass( 'open' ).fadeOut(); 699 $( document.body ).removeClass( $panel.attr( 'id' ) + '-opened' ); 700 } ); 701 } else { 702 target = $( target ).closest( '.offscreen-panel' ); 703 target.removeClass( 'open' ).fadeOut(); 704 705 $( document.body ).removeClass( target.attr( 'id' ) + '-opened' ); 706 } 707 708 $( document.body ).removeClass( 'offcanvas-opened' ).trigger( 'konte_off_canvas_closed', [target] ); 709 } 710 711 /** 712 * Toggle modals. 713 */ 714 konte.toggleModals = function() { 715 $( document.body ).on( 'click', '[data-toggle="modal"]', function( event ) { 716 var target = '#' + $( this ).data( 'target' ); 717 718 if ( $( target ).hasClass( 'open' ) ) { 719 konte.closeModal( target ); 720 } else if ( konte.openModal( target ) ) { 721 event.preventDefault(); 722 } 723 } ).on( 'click', '.modal .button-close, .modal .backdrop', function( event ) { 724 event.preventDefault(); 725 726 konte.closeModal( this ); 727 } ).on( 'keyup', function ( e ) { 728 if ( e.keyCode === 27 ) { 729 konte.closeModal(); 730 } 731 } ); 732 }; 733 734 /** 735 * Open a modal. 736 * 737 * @param string target 738 */ 739 konte.openModal = function( target ) { 740 var $target = $( target ); 741 742 if ( !$target.length ) { 743 return false; 744 } 745 746 $target.fadeIn(); 747 $target.addClass( 'open' ); 748 749 $( document.body ).addClass( 'modal-opened ' + $target.attr( 'id' ) + '-opened' ).trigger( 'konte_modal_opened', [$target] ); 750 751 return true; 752 } 753 754 /** 755 * Close a modal. 756 * 757 * @param string target 758 */ 759 konte.closeModal = function( target ) { 760 if ( !target ) { 761 $( '.modal' ).removeClass( 'open' ).fadeOut(); 762 763 $( '.modal' ).each( function() { 764 var $modal = $( this ); 765 766 if ( ! $modal.hasClass( 'open' ) ) { 767 return; 768 } 769 770 $modal.removeClass( 'open' ).fadeOut(); 771 $( document.body ).removeClass( $modal.attr( 'id' ) + '-opened' ); 772 } ); 773 } else { 774 target = $( target ).closest( '.modal' ); 775 target.removeClass( 'open' ).fadeOut(); 776 777 $( document.body ).removeClass( target.attr( 'id' ) + '-opened' ); 778 } 779
780 $( document.body ).removeClass( 'modal-opened' ).trigger( 'konte_modal_closed', [target] ); 781 } 782 783 /** 784 * Initialize the featured content carousel 785 */ 786 konte.featuredContentCarousel = function() { 787 var $featured = $( '#featured-content-carousel' ), 788 options = { 789 rtl : !! konte.data.rtl, 790 prevArrow: '<span class="slick-prev slick-arrow svg-icon icon-left icon-small"><svg width="16" height="16"><use xlink:href="#left"></use></svg></span>', 791 nextArrow: '<span class="slick-next slick-arrow svg-icon icon-right icon-small"><svg width="16" height="16"><use xlink:href="#right"></use></svg></span>' 792 }; 793 794 if ( !$featured.length ) { 795 return; 796 } 797 798 if ( $featured.hasClass( 'carousel' ) ) { 799 options.infinite = false; 800 options.slidesToShow = 3; 801 options.slidesToScroll = 3; 802 options.responsive = [ 803 { 804 breakpoint: 991, 805 settings : { 806 slidesToShow : 2, 807 slidesToScroll: 2 808 } 809 }, 810 { 811 breakpoint: 767, 812 settings : { 813 slidesToShow : 1, 814 slidesToScroll: 1 815 } 816 } 817 ]; 818 819 // Lazy load 820 $featured.on( 'init reInit breakpoint', function( event, slick ) { 821 slick.$slides.each( function() { 822 loadBackgroundImage( this ); 823 } ); 824 } ); 825 } else { 826 if ( 'fade' === $featured.data( 'effect' ) ) { 827 options.fade = true; 828 } 829 830 // Lazy load 831 $featured.on( 'beforeChange', function( event, slick, currentSlide, nextSlide ) { 832 loadBackgroundImage( slick.$slides.get( nextSlide ) ); 833 } ); 834 835 $featured.on( 'init reInit breakpoint', function( event, slick ) { 836 loadBackgroundImage( slick.$slides.get( slick.currentSlide ) ); 837 } ); 838 } 839 840 $featured.slick( options ); 841 842 /** 843 * Load background image 844 */ 845 function loadBackgroundImage( el ) { 846 var $el = $( el ).find( '.featured-item' ); 847 848 if ( $el.data( 'lazy' ) ) { 849 $el.css( 'background-image', 'url(' + $el.data( 'lazy' ) + ')' ); 850 } 851 852 $el.data( 'lazy_loaded', true ).removeClass( 'loading' ); 853 } 854 }; 855 856 /** 857 * Ajax load more posts. 858 */ 859 konte.loadMorePosts = function() { 860 if ( $( document.body ).hasClass( 'page-template-flex-posts' ) ) { 861 return; 862 } 863 864 $( document.body ).on( 'click', '.navigation.next-posts-navigation a', function( event ) { 865 event.preventDefault(); 866 867 var $el = $( this ), 868 $navigation = $el.closest( '.navigation' ), 869 url = $el.attr( 'href' ); 870 871 if ( $el.hasClass( 'loading' ) ) { 872 return; 873 } 874 875 $el.addClass( 'loading' ); 876 877 $.get( url, function( response ) { 878 var $content = $( '#main', response ), 879 $posts = $( '.hentry', $content ), 880 $nav = $( '.next-posts-navigation', $content ); 881 882 $posts.each( function( index, post ) { 883 $( post ).css( 'animation-delay', index * 100 + 'ms' ); 884 } ); 885 886 // Check if posts are wrapped or not. 887 if ( $navigation.prev( '.posts-wrapper' ).length ) { 888 $posts.appendTo( $navigation.prev( '.posts-wrapper' ) ); 889 } else { 890 $posts.insertBefore( $navigation ); 891 } 892 893 $posts.addClass( 'animated konteFadeInUp' ); 894 895 if ( $nav.length ) { 896 $el.replaceWith( $( 'a', $nav ) ); 897 } else { 898 $el.removeClass( 'loading' ); 899 $navigation.fadeOut(); 900 } 901 902 if ( $navigation.hasClass( 'next-projects-navigation' ) ) { 903 if ( konte.data.portfolio_nav_ajax_url_change ) { 904 window.history.pushState( null, '', url ); 905 } 906 } else if ( konte.data.blog_nav_ajax_url_change ) { 907 window.history.pushState( null, '', url ); 908 } 909 910 $( document.body ).trigger( 'konte_posts_loaded', [$posts, true] ); 911 } ); 912 } ); 913 }; 914 915 /** 916 * Fetch total share from ShareThis API. 917 */ 918 konte.fetchPostTotalShare = function() { 919 $( '.total-shares.fetching:visible' ).each( function() { 920 var $share = $( this ), 921 post_id = $share.data( 'post_id' ); 922 923 if ( !post_id ) { 924 return; 925 } 926 927 $.post( konte.data.ajax_url, { 928 action : 'konte_get_total_shares', 929 post_id: post_id, 930 security: konte.data.share_nonce 931 }, function( response ) { 932 $share.removeClass( 'fetching' ); 933 934 if ( response.success ) { 935 $( '.count', $share ).html( response.data ); 936 } 937 } ); 938 } ); 939 }; 940 941 /** 942 * Initialize posts slider widget 943 */ 944 konte.postsSliderWidget = function() { 945 $( '.posts-slider-widget .posts-slider' ).slick( { 946 rtl : !! konte.data.rtl, 947 adaptiveHeight: true, 948 autoplay : true, 949 autoplaySpeed : 3000, 950 prevArrow : '<span class="slick-prev slick-arrow svg-icon icon-left icon-small"><svg width="16" height="16"><use xlink:href="#left"></use></svg></span>', 951 nextArrow : '<span class="slick-next slick-arrow svg-icon icon-right icon-small"><svg width="16" height="16"><use xlink:href="#right"></use></svg></span>' 952 } ); 953 }; 954 955 /** 956 * Make the sidebar sticky 957 */ 958 konte.stickySidebar = function() { 959 if ( $.fn.stick_in_parent && $( window ).width() > 767 ) { 960 $( '#secondary.sticky-sidebar' ).stick_in_parent(); 961 } 962 963 // Recalculate after cart widget loaded via ajax. 964 $( document.body ).on( 'wc_fragments_refreshed post-load konte_products_loaded', function() { 965 $( document.body ).trigger( 'sticky_kit:recalc' ); 966 } ); 967 }; 968 969 /** 970 * Close the topbar 971 */ 972 konte.closeTopbar = function() { 973 $( document.body ).on( 'click', '.close-topbar', function( event ) { 974 event.preventDefault(); 975
976 $( '#topbar' ).slideUp(); 977 } ); 978 }; 979 980 /** 981 * Sticky header 982 */ 983 konte.stickyHeader = function () { 984 if ( !konte.data.sticky_header || 'none' === konte.data.sticky_header ) { 985 return; 986 } 987 988 var $window = $( window ), 989 $header = $( '#masthead' ), 990 $sticker = $header, 991 $topbar = $( '#topbar' ), 992 offset = 0; 993 994 if ( $header.hasClass( 'header-v10' ) ) { 995 $sticker = $header.find( '.header-main .header-right-items' ); 996 } 997 998 if ( ! $sticker.length ) { 999 return; 1000 } 1001 1002 if ( $topbar.length ) { 1003 offset += $topbar.outerHeight(); 1004 } 1005 1006 if ( 'smart' === konte.data.sticky_header ) { 1007 offset += $topbar.length ? 0 : $sticker.outerHeight(); 1008 1009 var stickyHeader = new Headroom( $sticker.get(0), { 1010 offset: offset 1011 }); 1012 1013 stickyHeader.init(); 1014 } else { 1015 sticky( offset ); 1016 1017 $window.on( 'scroll', function() { 1018 sticky( offset ); 1019 } ); 1020 } 1021 1022 /** 1023 * Private function for sticky header 1024 */ 1025 function sticky( topSpacing ) { 1026 if ( $sticker.hasClass( 'sticky--ignore' ) ) { 1027 return; 1028 } 1029 1030 topSpacing = topSpacing ? topSpacing : 0; 1031 1032 if ( $window.scrollTop() > topSpacing ) { 1033 $sticker.addClass( 'sticky' ); 1034 } else { 1035 $sticker.removeClass( 'sticky' ); 1036 } 1037 } 1038 }; 1039 1040 /** 1041 * Correct the page header's height. 1042 */ 1043 konte.pageHeaderHeight = function() { 1044 var $pageHeader = $( '.page .page-header.full-height' ); 1045 1046 if ( !$pageHeader.length ) { 1047 return; 1048 } 1049 1050 var $topbar = $( '#topbar' ), 1051 $header = $( '#masthead' ), 1052 height = $( window ).height(); 1053 1054 if ( $topbar.length ) { 1055 height -= $topbar.outerHeight(); 1056 } 1057 1058 if ( !$header.hasClass( 'transparent' ) ) { 1059 height -= $header.outerHeight(); 1060 1061 $pageHeader.css( 'marginTop', '-' + $( '#content' ).css( 'paddingTop' ) ); 1062 } 1063 1064 if ( $pageHeader.hasClass( 'title-front' ) ) { 1065 $pageHeader.height( height ); 1066 } else { 1067 $pageHeader.find( '.entry-thumbnail' ).height( height ); 1068 } 1069 }; 1070 1071 /** 1072 * Scroll down when clicing on the anchor 1073 */ 1074 konte.scrollDown = function() { 1075 $( document.body ).on( 'click', '.scroll', function( event ) { 1076 event.preventDefault(); 1077 1078 var offset = $( this ).parent().next().offset().top; 1079 1080 $( 'html, body' ).animate( {scrollTop: offset} ); 1081 } ); 1082 }; 1083 1084 /** 1085 * Make WC message closeable. 1086 */ 1087 konte.closeWCMessages = function() { 1088 $( document.body ).on( 'click', '.woocommerce-message .close-message, .woocommerce-error .close-message, .woocommerce-info .close-message', function( event ) { 1089 event.preventDefault(); 1090 1091 $( this ).closest( 'div' ).fadeOut(); 1092 } ); 1093 1094 $( document.body ).on( 'click', '.wc-block-components-notice-banner__close', function( event ) { 1095 event.preventDefault(); 1096 1097 $( this ).closest( '.wc-block-components-notice-banner' ).fadeOut(); 1098 } ); 1099 }; 1100 1101 /** 1102 * Increase/decrease product quantity 1103 */ 1104 konte.productQuantityButtons = function() { 1105 $( document.body ).on( 'click', '.quantity .increase, .quantity .decrease', function( event ) { 1106 event.preventDefault(); 1107 1108 var $this = $( this ), 1109 $qty = $this.siblings( '.qty' ), 1110 current = parseFloat( $qty.val() ), 1111 min = parseFloat( $qty.attr( 'min' ) ), 1112 max = parseFloat( $qty.attr( 'max' ) ), 1113 step = parseFloat( $qty.attr( 'step' ) ); 1114 1115 current = current ? current : 0; 1116 min = min ? min : 0; 1117 max = max ? max : current + 1; 1118 step = step ? step : 1; 1119 1120 if ( $this.hasClass( 'decrease' ) && current > min ) { 1121 $qty.val( current - step ); 1122 $qty.trigger( 'change' ); 1123 } 1124 if ( $this.hasClass( 'increase' ) && current < max ) { 1125 $qty.val( current + step ); 1126 $qty.trigger( 'change' ); 1127 } 1128 } ); 1129 }; 1130 1131 /** 1132 * Using Ajax for add to cart button on single product page. 1133 */ 1134 konte.singleProductAjaxAddToCart = function() { 1135 if ( '1' !== konte.data.product_ajax_addtocart ) { 1136 return; 1137 } 1138 1139 $( document.body ).on( 'submit', 'form.cart', function( event ) { 1140 var $form = $( this ); 1141 1142 if ( $form.closest( 'div.product' ).hasClass( 'product-type-external' ) || $form.data( 'with_ajax' ) ) { 1143 return; 1144 } 1145 1146 event.preventDefault(); 1147 1148 var $button = $form.find( '.single_add_to_cart_button' ), 1149 formData = new FormData( this ); 1150 1151 // Prevent double-add by remove the param 'add-to-cart'. 1152 if ( formData.has( 'add-to-cart' ) ) { 1153 formData.delete( 'add-to-cart' ); 1154 } 1155
1156 // Then we will rename it in the ajax handler function. 1157 formData.append( 'konte-add-to-cart', $form.find( '[name="add-to-cart"]' ).val() ); 1158 1159 // Ajax. 1160 $.ajax( { 1161 url: woocommerce_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'konte_ajax_add_to_cart' ), 1162 data: formData, 1163 method: 'POST', 1164 contentType: false, 1165 processData: false, 1166 beforeSend: function() { 1167 $button.removeClass( 'added' ).addClass( 'loading disabled' ).prop( 'disabled', true ); 1168 }, 1169 complete: function( response ) { 1170 $button.removeClass( 'loading disabled' ).addClass( 'added' ).prop( 'disabled', false ); 1171 1172 response = response.responseJSON; 1173 1174 if ( ! response ) { 1175 return; 1176 } 1177 1178 // Reload on error. 1179 if ( response.error && response.product_url ) { 1180 window.location = response.product_url; 1181 return; 1182 } 1183 1184 // If success, trigger events. 1185 var $notices = $( response.fragments.notices_html ), 1186 isAdded = $notices.hasClass( 'woocommerce-message' ) || $notices.hasClass( 'is-success' ); 1187 1188 if ( isAdded ) { 1189 // Trigger the default event to refresh fragments. 1190 $( document.body ).trigger( 'added_to_cart', [ response.fragments, response.cart_hash, $button ] ); 1191 1192 // Trigger the fragment refresh event manually if necessary. 1193 if ( 'undefined' === typeof wc_add_to_cart_params ) { 1194 $( document.body ).trigger( 'wc_fragment_refresh' ); 1195 } 1196 } 1197 1198 // Display new notices (alert bar). 1199 if ( konte.data.cart_open_after_added !== '1' || ! isAdded ) { 1200 konte.displayAlertBar( response.fragments.notices_html ); 1201 } 1202 1203 // Redirect to cart option. 1204 if ( 'undefined' !== typeof wc_add_to_cart_params && wc_add_to_cart_params.cart_redirect_after_add === 'yes' ) { 1205 window.location = wc_add_to_cart_params.cart_url; 1206 return; 1207 } 1208 }, 1209 error: function() { 1210 // Try to submit the form without ajax on errors. 1211 $form.data( 'with_ajax', false ).trigger( 'submit' ); 1212 } 1213 } ); 1214 } ); 1215 }; 1216 1217 /** 1218 * Display alert bar at bottom 1219 * 1220 * @param {String} message 1221 * @param {Number} duration Set to 0 to permanently display the alert 1222 */ 1223 konte.displayAlertBar = function( message, duration ) { 1224 if ( ! message ) { 1225 return; 1226 } 1227 1228 if ( typeof duration !== "number" ) { 1229 duration = 5000; 1230 } 1231 1232 if ( ! konte.alertTimeout ) { 1233 konte.alertTimeout = null; 1234 } 1235 1236 // Prepare the alert bar. 1237 var $alert = $( '#konte-woocommerce-alert' ); 1238 1239 if ( ! $alert.length ) { 1240 $alert = $( '<div id="konte-woocommerce-alert" class="konte-woocommerce-alert"></div>' ); 1241 $( document.body ).append( $alert ); 1242 } 1243 1244 // Show. 1245 $alert.html( message ); 1246 1247 setTimeout( function() { 1248 $alert.addClass( 'active' ); 1249 }, 100 ); 1250 1251 // Close alert bar on button click. 1252 $alert.one( 'click', '.close-message, .wc-block-components-notice-banner__close', function( e ) { 1253 e.preventDefault(); 1254 1255 $alert.removeClass( 'active' ); 1256 } ); 1257 1258 // Auto close. 1259 if ( duration ) { 1260 // Auto hide the alert bar after 5 seconds. 1261 clearTimeout( konte.alertTimeout ); 1262 1263 konte.alertTimeout = setTimeout( function() { 1264 $alert.removeClass( 'active' ); 1265 }, duration ); 1266 } 1267 } 1268 1269 /** 1270 * Init sticky cart form. 1271 * 1272 * @todo Support bundled products. 1273 */ 1274 konte.stickyAddToCart = function() { 1275 var $sticky = $( '.sticky-cart-form' ); 1276 1277 if ( ! $sticky.length ) { 1278 return; 1279 } 1280 1281 // Remove wishlist and share buttons. 1282 $sticky.find( '.add-to-wishlist-button, .wcboost-wishlist-button, .wcboost-products-compare-button, .product-share' ).remove(); 1283 1284 var $forms = $( 'form.cart', $sticky.closest( 'div.product' ) ), 1285 $originalForm = $forms.first(), 1286 $image = $sticky.find( '.sticky-cart-form__product-image img' ), 1287 $price = $sticky.find( '.sticky-cart-form__product-summary .price' ), 1288 $stickyHeader = $( '#masthead' ), 1289 stickyPosition = $sticky.data( 'position' ), 1290 offset = 0, 1291 doingSync = false; 1292 1293 if ( $stickyHeader.hasClass( 'header-v10' ) ) { 1294 $stickyHeader = $stickyHeader.find( '.header-main .header-right-items' ); 1295 } 1296 1297 if ( konte.data.sticky_header && 'none' !== konte.data.sticky_header ) { 1298 offset = $stickyHeader.height(); 1299 } 1300 1301 // Handle add-to-cart variations of 2 forms. 1302 $forms 1303 .on( 'reset_data', function() { 1304 $image.attr( 'src', $image.data( 'o_src' ) );
1305 $price.show().siblings( '.variation-price, .stock' ).remove(); 1306 } ) 1307 .on( 'found_variation', function( event, variation ) { 1308 if ( variation.image && variation.image.gallery_thumbnail_src && variation.image.gallery_thumbnail_src.length > 1 ) { 1309 $image.attr( 'src', variation.image.gallery_thumbnail_src ); 1310 } 1311 1312 if ( variation.availability_html && variation.availability_html.length ) { 1313 $price.hide().siblings( '.stock, .variation-price' ).remove(); 1314 $price.after( variation.availability_html ); 1315 } else { 1316 $price.siblings( '.stock' ).remove(); 1317 1318 if ( variation.price_html && variation.price_html.length ) { 1319 $price.hide().siblings( '.variation-price' ).remove(); 1320 $price.after( $( variation.price_html ).addClass( 'variation-price' ) ); 1321 } 1322 } 1323 } ) 1324 // Sync inputs' value. 1325 .on( 'change', ':input', function() { 1326 // Avoid infinite loop. 1327 if ( doingSync ) { 1328 return; 1329 } 1330 1331 doingSync = true; 1332 1333 var $currentForm = $( this ).closest( 'form.cart' ), 1334 $targetForm = $forms.not( $currentForm ); 1335 1336 $targetForm.find( ':input[name="' + this.name + '"]' ).val( this.value ).trigger( 'change' ); 1337 1338 doingSync = false; 1339 } ); 1340 1341 // Scroll to the grouped products form. 1342 $sticky.on( 'click', '.grouped_form .single_add_to_cart_button, .bundle_form .single_add_to_cart_button', function() { 1343 $( 'html, body' ).animate( { scrollTop: $originalForm.offset().top - offset }, 800 ); 1344 1345 return false; 1346 } ).on( 'click', '.sticky-cart-form__mobile-button', function( event ) { 1347 event.preventDefault(); 1348 1349 if ( this.dataset.product_type === 'simple' || this.dataset.product_type === 'grouped' || this.dataset.product_type === 'external' ) { 1350 $sticky.find( '.single_add_to_cart_button' ).trigger( 'click' ); 1351 } else { 1352 $( 'html, body' ).animate( { scrollTop: $originalForm.offset().top - offset }, 800 ); 1353 } 1354 } ); 1355 1356 // Handle the scroll event. 1357 var lastKnownScrollPosition = window.scrollY, 1358 ticking = false, 1359 rAF = window.requestAnimationFrame || 1360 window.webkitRequestAnimationFrame || 1361 window.mozRequestAnimationFrame || 1362 window.msRequestAnimationFrame || 1363 window.oRequestAnimationFrame; 1364 1365 var checkFormVisibility = function( position ) { 1366 if ( position >= ( $originalForm.offset().top + $originalForm.height() - offset ) ) { 1367 $sticky.attr( 'aria-hidden', false ).removeClass( 'sticky-cart-form--unpin' ).addClass( 'sticky-cart-form--pin' ); 1368 document.body.classList.add( 'sticky-cart-form-pinned-' + stickyPosition ); 1369 1370 if ( 'top' === $sticky.data( 'position' ) && konte.data.sticky_header && 'none' !== konte.data.sticky_header ) { 1371 $stickyHeader.addClass( 'sticky--ignore' ); 1372 } 1373 } else { 1374 $sticky.attr( 'aria-hidden', true ).removeClass( 'sticky-cart-form--pin' ).addClass( 'sticky-cart-form--unpin' ); 1375 document.body.classList.remove( 'sticky-cart-form-pinned-' + stickyPosition ); 1376 1377 if ( 'top' === $sticky.data( 'position' ) && konte.data.sticky_header && 'none' !== konte.data.sticky_header ) { 1378 $stickyHeader.removeClass( 'sticky--ignore' ); 1379 } 1380 } 1381 }; 1382 1383 // Check and toggle the sticky add-to-cart form on scroll. 1384 document.addEventListener( 'scroll', function() { 1385 lastKnownScrollPosition = window.scrollY; 1386 1387 if ( ! ticking ) { 1388 rAF( function() { 1389 checkFormVisibility( lastKnownScrollPosition ); 1390 ticking = false; 1391 } ); 1392 1393 ticking = true; 1394 } 1395 } ); 1396 1397 rAF( function() { 1398 checkFormVisibility( lastKnownScrollPosition ); 1399 ticking = false; 1400 } ); 1401 1402 // Adds extra space to the bottom if the sticky add-to-cart form at bottom. 1403 if ( 'bottom' === $sticky.data( 'position' ) ) { 1404 $( '#colophon' ).css( 'margin-bottom', $sticky.outerHeight() ); 1405 } 1406 } 1407 1408 /** 1409 * Automactically open the cart panel after a product added to cart. 1410 * Disable window scrollbar when cart panel opened. 1411 */ 1412 konte.cartPanel = function() { 1413 var $panel = $( '#cart-panel' ); 1414 1415 if ( !$panel.length ) { 1416 return; 1417 } 1418 1419 // Scrollbar for cart panel. 1420 if ( typeof PerfectScrollbar !== 'undefined' ) { 1421 new PerfectScrollbar( $panel.find( '.panel-content' ).get( 0 ) ); 1422 } 1423 1424 if ( '1' === konte.data.cart_open_after_added ) { 1425 $( document.body ).on( 'added_to_cart', function() { 1426 if ( $( '#cart-panel' ).hasClass( 'open' ) ) { 1427 return; 1428 } 1429 1430 konte.closeOffCanvas( false ); 1431 // Queue for opening cart panel, to avoid removing class `.offcanvas-opened`. 1432 setTimeout( function() { 1433 konte.openOffCanvas( '#cart-panel' ); 1434 }, 0 ); 1435 } ); 1436 } 1437 }; 1438 1439 /** 1440 * Handle product reviews 1441 */ 1442 konte.reviewProduct = function() { 1443 setTimeout( function() { 1444 $( '#respond p.stars a' ).prepend( '<span class="svg-icon icon-star"><svg><use xlink:href="#star"></use></svg></span>' ); 1445 }, 100 ); 1446 1447 $( document.body ) 1448 .on( 'click', '.add-review', function( event ) { 1449 event.preventDefault(); 1450 1451 var $reviews = $( this ).closest( '#reviews' ); 1452 1453 $( '#review_form_wrapper', $reviews ).fadeIn(); 1454 $( '#comments', $reviews ).fadeOut(); 1455 } ).on( 'click', '.cancel-review a', function( event ) { 1456 event.preventDefault(); 1457 1458 var $reviews = $( this ).closest( '#reviews' ); 1459 1460 $( '#review_form_wrapper', $reviews ).fadeOut(); 1461 $( '#comments', $reviews ).fadeIn(); 1462 } ); 1463 1464 $( '#review_form' ) 1465 .on( 'focus', 'input, textarea', function() { 1466 $( this ).parent().addClass( 'focused' ); 1467 } ) 1468 .on( 'blur', 'input, textarea', function() { 1469 if ( $( this ).val() === '' ) { 1470 $( this ).parent().removeClass( 'focused' ); 1471 } 1472 } )
1473 .find( 'input, textarea' ).each( function() { 1474 if ( $( this ).val() !== '' ) { 1475 $( this ).parent().addClass( 'focused' ); 1476 } 1477 } ); 1478 }; 1479 1480 /** 1481 * Toggle product tabs 1482 */ 1483 konte.toggleProductTabs = function() { 1484 var $product = $( 'div.product' ); 1485 1486 if ( $product.hasClass( 'layout-v6' ) || $product.hasClass( 'layout-v7' ) ) { 1487 return; 1488 } 1489 1490 $( document.body ) 1491 .off( 'click', '.woocommerce-tabs.panels-offscreen .wc-tabs li a, .woocommerce-tabs.panels-offscreen ul.tabs li a' ) 1492 .on( 'click', '.woocommerce-tabs.panels-offscreen .wc-tabs li a', function( event ) { 1493 event.preventDefault(); 1494 1495 var $el = $( this ), 1496 $wrapper = $el.closest( '.wc-tabs-wrapper, .woocommerce-tabs' ), 1497 $tabs = $wrapper.find( '.wc-tabs, ul.tabs' ), 1498 $panels = $wrapper.find( '.panels' ), 1499 $target = $wrapper.find( $el.attr( 'href' ) ); 1500 1501 $tabs.find( 'li' ).removeClass( 'active' ); 1502 $el.closest( 'li' ).addClass( 'active' ); 1503 $panels.find( '.panel' ).show(); 1504 $panels.fadeIn(); 1505 $target.addClass( 'open' ); 1506 1507 $( document.body ).addClass( 'offcanvas-opened' ); 1508 } ) 1509 .on( 'click', '.woocommerce-tabs .backdrop, .woocommerce-tabs .button-close', function( event ) { 1510 event.preventDefault(); 1511 1512 var $wrapper = $( this ).closest( '.wc-tabs-wrapper, .woocommerce-tabs' ), 1513 $panels = $wrapper.find( '.panels' ), 1514 $opened = $panels.find( '.panel.open' ); 1515 1516 $opened.removeClass( 'open' ); 1517 $wrapper.find( '.tabs' ).children( 'li' ).removeClass( 'active' ); 1518 $panels.fadeOut(); 1519 1520 // Close the review form 1521 if ( $opened.is( '#tab-reviews' ) ) { 1522 $opened.find( '#review_form_wrapper' ).fadeOut(); 1523 $opened.find( '#comments' ).fadeIn(); 1524 } 1525 1526 $( document.body ).removeClass( 'offcanvas-opened' ); 1527 } ) 1528 .on( 'keyup', function( e ) { 1529 if ( e.keyCode === 27 ) { 1530 var $wrapper = $( '.wc-tabs-wrapper, .woocommerce-tabs' ), 1531 $panels = $wrapper.find( '.panels' ), 1532 $opened = $panels.find( '.panel.open' ); 1533 1534 $opened.removeClass( 'open' ); 1535 $wrapper.find( '.tabs' ).children( 'li' ).removeClass( 'active' ); 1536 $panels.fadeOut(); 1537 1538 // Close the review form 1539 if ( $opened.is( '#tab-reviews' ) ) { 1540 $opened.find( '#review_form_wrapper' ).fadeOut(); 1541 $opened.find( '#comments' ).fadeIn(); 1542 } 1543 1544 $( document.body ).removeClass( 'offcanvas-opened' ); 1545 } 1546 } ); 1547 1548 // Remove active tab. 1549 $product.find( '.wc-tabs, ul.tabs' ).first().find( 'li.active' ).removeClass( 'active' ); 1550 1551 // Auto open targeted tab (by hash). 1552 if ( window.location.hash ) { 1553 var $tabLink = $product.find( '.wc-tabs, ul.tabs' ).first().find( 'li a[href="' + window.location.hash + '"]' ); 1554 1555 if ( $tabLink.length ) { 1556 $tabLink.trigger( 'click' ); 1557 } 1558 } 1559 }; 1560 1561 /** 1562 * Make product full width 1563 */ 1564 konte.productFullWidth = function( $product ) { 1565 var $window = $( window ); 1566 1567 // Set width of product 1568 changeProductWidth(); 1569 1570 $window.on( 'resize', function() { 1571 changeProductWidth(); 1572 } ); 1573 1574 /** 1575 * Change the product width 1576 */ 1577 function changeProductWidth() { 1578 var width = $window.width(); 1579 1580 width -= konte.getVerticalHeaderWidth(); 1581 1582 $product.width( width ); 1583 1584 if ( konte.data.rtl ) { 1585 $product.css( 'marginRight', -width/2 ); 1586 } else { 1587 $product.css( 'marginLeft', -width/2 ); 1588 } 1589 } 1590 }; 1591 1592 /** 1593 * Open product image lightbox when click on the zoom image 1594 */ 1595 konte.productLightBox = function() { 1596 if ( typeof wc_single_product_params === 'undefined' || wc_single_product_params.photoswipe_enabled !== '1' ) { 1597 return; 1598 } 1599 1600 $( '.woocommerce-product-gallery' ).on( 'click', '.zoomImg', function() { 1601 if ( wc_single_product_params.flexslider_enabled ) { 1602 $( this ).closest( '.woocommerce-product-gallery' ).children( '.woocommerce-product-gallery__trigger' ).trigger( 'click' ); 1603 } else { 1604 $( this ).prev( 'a' ).trigger( 'click' ); 1605 } 1606 } ); 1607 }; 1608 1609 /** 1610 * Set the product background similar to product gallery images 1611 */ 1612 konte.productBackgroundFromGallery = function( $product ) { 1613 if ( typeof BackgroundColorTheif == 'undefined' ) { 1614 return; 1615 } 1616 1617 var $gallery = $product.find( '.woocommerce-product-gallery' ), 1618 $image = $gallery.find( '.wp-post-image' ),
1619 imageColor = new BackgroundColorTheif(); 1620 1621 // Change background base on main image. 1622 $image.one( 'load', function() { 1623 setTimeout( function() { 1624 changeProductBackground( $image.get( 0 ) ); 1625 }, 100 ); 1626 } ).each( function() { 1627 this.crossOrigin = 'Anonymous'; 1628 1629 if ( this.complete ) { 1630 $( this ).trigger( 'load' ); 1631 } 1632 } ); 1633 1634 // Change background when slider change. 1635 setTimeout( function() { 1636 var slider = $gallery.data( 'flexslider' ); 1637 1638 if ( !slider ) { 1639 return; 1640 } 1641 1642 slider.vars.before = function( slider ) { 1643 setTimeout( function() { 1644 changeProductBackground( slider.slides.filter( '.flex-active-slide' ).find( 'a img' ).get( 0 ) ); 1645 }, 150 ); 1646 }; 1647 }, 150 ); 1648 1649 // Support Jetpack images lazy loads. 1650 $gallery.on( 'jetpack-lazy-loaded-image', '.wp-post-image', function() { 1651 $( this ).one( 'load', function() { 1652 changeProductBackground( this ); 1653 } ); 1654 } ); 1655 1656 // Change background when variation changed 1657 $gallery.on( 'woocommerce_gallery_reset_slide_position', function() { 1658 changeProductBackground( $image.get( 0 ) ); 1659 } ); 1660 1661 /** 1662 * Change product backgound color 1663 */ 1664 function changeProductBackground( image ) { 1665 // Stop if this image is not loaded. 1666 if ( image.src === '' ) { 1667 return; 1668 } 1669 1670 if ( image.classList.contains( 'jetpack-lazy-image' ) ) { 1671 if ( ! image.dataset['lazyLoaded'] ) { 1672 return; 1673 } 1674 } 1675 1676 var rgb = imageColor.getBackGroundColor( image ); 1677 $product.get( 0 ).style.backgroundColor = 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')'; 1678 } 1679 } 1680 1681 /** 1682 * Add extra script for product variation swatches. 1683 * This function will run after plugin swatches did. 1684 */ 1685 konte.productVariationSwatches = function() { 1686 $( document.body ).on( 'tawcvs_initialized', function() { 1687 var $form = $( '.variations_form' ); 1688 1689 konte.modifyVariationSwatches( $form ); 1690 } ); 1691 }; 1692 1693 /** 1694 * Modify the product gallery carousel 1695 */ 1696 konte.productGalleryCarousel = function() { 1697 var $product = $( 'div.product' ); 1698 1699 if ( !$product.length ) { 1700 return; 1701 } 1702 1703 var $gallery = $( '.woocommerce-product-gallery', $product ); 1704 1705 if ( ! $gallery.length ) { 1706 return; 1707 } 1708 1709 setTimeout( function() { 1710 $gallery.each( function() { 1711 konte.addIndexToCarouselControlNav( this ); 1712 } ) 1713 }, 100 ); 1714 }; 1715 1716 /** 1717 * Appends a span to the product gallery carousel control nav 1718 */ 1719 konte.addIndexToCarouselControlNav = function( carousel ) { 1720 $( '.flex-control-nav > li', carousel ).each( function( index, el ) { 1721 $( el ).append( $( '<span class="flex-nav-index"/>' ).text( index + 1 ) ); 1722 } ); 1723 } 1724 1725 /** 1726 * Special functions for product layout v1. 1727 * Set product background color for single product page. 1728 * Set height of product summary equal to the gallery's. 1729 */ 1730 konte.singleProductV1 = function() { 1731 var $product = $( 'div.product.layout-v1' ); 1732 1733 if ( !$product.length ) { 1734 return; 1735 } 1736 1737 // Make product fullwidth 1738 konte.productFullWidth( $product ); 1739 1740 // Set top padding of product 1741 $product.css( {paddingTop: $( '#masthead' ).height()} ); 1742 1743 // Change background color 1744 if ( !$product.hasClass( 'background-set' ) && konte.data.product_auto_background === '1' ) { 1745 try { 1746 konte.productBackgroundFromGallery( $product ); 1747 } catch ( e ) { 1748 console.warn( e ); 1749 } 1750 } 1751 1752 var $gallery = $( '.woocommerce-product-gallery', $product ); 1753 1754 // Fix slider's height on resize. Do not know why the default handler of Flexslider not working. 1755 $( window ).on( 'resize', function() { 1756 var slider = $gallery.data( 'flexslider' ); 1757 1758 if ( slider ) { 1759 setTimeout( function() { 1760 var setHeight = $( '.woocommerce-product-gallery__image:eq(0)', $gallery ).height(); 1761 1762 $gallery.height( setHeight ); 1763 }, 100 ); 1764 } 1765 1766 // Update the top padding. 1767 $product.css( {paddingTop: $( '#masthead' ).height()} ); 1768 } ); 1769 }; 1770 1771 /** 1772 * Special functions for product layout v2. 1773 * Enable zooming for gallery thumbnails. 1774 * Make the summary sticky. 1775 */ 1776 konte.singleProductV2 = function() { 1777 var $product = $( 'div.product.layout-v2' ); 1778 1779 if ( !$product.length ) { 1780 return; 1781 } 1782 1783 var $window = $( window ), 1784 $summary = $product.find( '.summary' ), 1785 summarySticky = false;
1786 1787 // Make product fullwidth 1788 konte.productFullWidth( $product ); 1789 1790 // Init zoom for product gallery images 1791 if ( '1' === konte.data.product_image_zoom ) { 1792 $product.find( '.woocommerce-product-gallery .woocommerce-product-gallery__image' ).each( function() { 1793 konte.zoomSingleProductImage( this ); 1794 } ); 1795 } 1796 1797 // Sticky summary 1798 if ( $.fn.stick_in_parent && konte.data.product_sticky_summary && konte.data.product_summary_sticky_mode == 'advanced' ) { 1799 $summary.on( 'sticky_kit:bottom', function() { 1800 $( this ).parent().css( 'position', 'static' ); 1801 } ); 1802 1803 stickySummary(); 1804 1805 $window.on( 'resize', stickySummary ); 1806 } 1807 1808 /** 1809 * Sticky summary 1810 */ 1811 function stickySummary() { 1812 var options = {}; 1813 1814 if ( konte.data.sticky_header === 'normal' ) { 1815 var offset = $('#masthead').height(), 1816 $topbar = $( '#topbar' ); 1817 1818 if ( $topbar.length ) { 1819 offset += $topbar.height(); 1820 } 1821 1822 options = { 1823 recalc_every: 1, 1824 offset_top: offset 1825 } 1826 } 1827 1828 if ( $window.width() > 991 ) { 1829 if ( ! summarySticky ) { 1830 $summary.stick_in_parent( options ); 1831 } 1832 summarySticky = true; 1833 } else { 1834 $summary.trigger( 'sticky_kit:detach' ); 1835 summarySticky = false; 1836 } 1837 } 1838 } 1839 1840 /** 1841 * Special functions for product layout v3. 1842 * Change the height of product gallery. 1843 */ 1844 konte.singleProductV3 = function() { 1845 var $product = $( 'div.product.layout-v3' ); 1846 1847 if ( !$product.length ) { 1848 return; 1849 } 1850 1851 var $header = $( '#masthead' ); 1852 1853 // Set top padding of product 1854 $product.css( {paddingTop: $header.height()} ); 1855 $( '.product-toolbar' ).css( {top: $header.height()} ); 1856 1857 // Change background color 1858 if ( !$product.hasClass( 'background-set' ) && konte.data.product_auto_background === '1' ) { 1859 konte.productBackgroundFromGallery( $product ); 1860 } 1861 1862 // Set gallery height 1863 $( '.woocommerce-product-gallery__wrapper .woocommerce-product-gallery__image:eq(0) .wp-post-image' ).one( 'load', setGalleryHeight ); 1864 1865 setTimeout( function() { 1866 setGalleryHeight(); 1867 }, 200 ); 1868 1869 $( window ).on( 'resize', setGalleryHeight ); 1870 1871 /** 1872 * Set gallery height 1873 */ 1874 function setGalleryHeight() { 1875 var height = $( window ).height() - $header.outerHeight() - $( '#colophon' ).outerHeight() + 19, 1876 $topbar = $( '#topbar' ), 1877 $footer = $( '.footer-main' ); 1878 1879 if ( $topbar.length ) { 1880 height -= $topbar.outerHeight(); 1881 } 1882 1883 if ( $footer.length ) { 1884 height -= parseFloat( $footer.css( 'padding-top' ) ); 1885 } 1886 1887 $product.find( '.woocommerce-product-gallery' ).css( { 1888 maxHeight: height, 1889 height : height 1890 } ); 1891 } 1892 } 1893 1894 /** 1895 * Special functions for product layout v4. 1896 */ 1897 konte.singleProductV4 = function() { 1898 var $product = $( 'div.product.layout-v4' ); 1899 1900 if ( !$product.length ) { 1901 return; 1902 } 1903 1904 // Quantity dropdown. 1905 if ( 'dropdown' === konte.data.product_quantity_input_style ) { 1906 $product.find( '.summary .quantity .qty' ).quantityDropdown(); 1907 } 1908 } 1909 1910 /** 1911 * Special functions for product layout v5. 1912 */ 1913 konte.singleProductV5 = function() { 1914 var $product = $( 'div.product.layout-v5' ), 1915 $summary = $product.find( '.summary' ), 1916 $summaryInner = $summary.children( '.summary-inner' ), 1917 $window = $( window ), 1918 headerHeight = $( '#masthead' ).height(), 1919 summarySticky = false; 1920 1921 if ( !$product.length ) { 1922 return; 1923 } 1924 1925 // Make product fullwidth 1926 productWidth(); 1927 1928 $window.on( 'resize', function() { 1929 productWidth(); 1930 } ); 1931 1932 // Set top padding of product 1933 $summary.css( {paddingTop: headerHeight} ); 1934 1935 // Init zoom for product gallery thumbnails 1936 if ( konte.data.product_image_zoom ) { 1937 $product.find( '.product-gallery-thumbnails .woocommerce-product-gallery__image' ).each( function() { 1938 konte.zoomSingleProductImage( this ); 1939 } ); 1940 } 1941 1942 // Sticky summary 1943 if ( $.fn.stick_in_parent && konte.data.product_sticky_summary && konte.data.product_summary_sticky_mode == 'advanced' ) { 1944 $summaryInner.css( 'max-height', $window.height() - headerHeight ); 1945 1946 $summaryInner 1947 .on( 'sticky_kit:bottom', function() { 1948 $( this ).closest( '.product-gallery-summary' ).addClass( 'summary-sticky-bottom' ); 1949 } ) 1950 .on( 'sticky_kit:unbottom', function() { 1951 $( this ).closest( '.product-gallery-summary' ).removeClass( 'summary-sticky-bottom' ); 1952 } ); 1953 1954 setTimeout( function() { 1955 stickySummary(); 1956 }, 100 ); 1957 1958 $window.on( 'resize', stickySummary ); 1959 } 1960 1961 /** 1962 * Set product width 1963 */ 1964 function productWidth() { 1965 var width = $window.width(), 1966 bonus = width > 1440 ? 60 : 0; 1967 1968 width -= konte.getVerticalHeaderWidth(); 1969 1970 $product.width( width ); 1971 1972 if ( konte.data.rtl ) { 1973 $product.css( 'margin-right', -width / 2 ); 1974 $summary.css( 'padding-left', width / 2 - $( '.konte-container' ).width() / 2 + bonus ); 1975 } else { 1976 $product.css( 'margin-left', -width / 2 ); 1977 $summary.css( 'padding-right', width / 2 - $( '.konte-container' ).width() / 2 + bonus ); 1978 } 1979 } 1980 1981 /** 1982 * Sticky summary 1983 */ 1984 function stickySummary() { 1985 var options = { parent: $product.get(0) }; 1986 1987 if (konte.data.sticky_header === 'normal') { 1988 var offset = $('#masthead').height(), 1989 $topbar = $('#topbar'); 1990 1991 if ($topbar.length) { 1992 offset += $topbar.height(); 1993 } 1994 1995 options = { 1996 recalc_every: 1, 1997 offset_top: offset, 1998 parent: $product.get(0) 1999 } 2000 } 2001 2002 if ( $window.width() > 991 ) { 2003 if ( ! summarySticky ) { 2004 $summaryInner.stick_in_parent( options ); 2005 } 2006 summarySticky = true; 2007 } else { 2008 $summaryInner.trigger( 'sticky_kit:detach' ); 2009 summarySticky = false;
2010 } 2011 } 2012 }; 2013 2014 /** 2015 * Special functions for product layout v6. 2016 */ 2017 konte.singleProductV6 = function() { 2018 var $product = $( 'div.product.layout-v6' ); 2019 2020 if ( !$product.length ) { 2021 return; 2022 } 2023 }; 2024 2025 /** 2026 * Special functions for product layout v7. 2027 */ 2028 konte.singleProductV7 = function() { 2029 var $product = $( 'div.product.layout-v7' ); 2030 2031 if ( !$product.length ) { 2032 return; 2033 } 2034 }; 2035 2036 /** 2037 * Init the carousel for product gallery thumbnails 2038 * 2039 * @param {Object} options 2040 */ 2041 konte.productGalleryThumbnailCarousel = function( options ) { 2042 var $product = $( 'div.product' ); 2043 2044 if ( ! $product.length ) { 2045 return; 2046 } 2047 2048 var $gallery = $( '.woocommerce-product-gallery', $product ), 2049 $thumbnails = $gallery.find( '.flex-control-thumbs' ), 2050 options = { 2051 rtl : !! konte.data.rtl, 2052 vertical : false, 2053 verticalSwiping: false, 2054 swipeToSlide : true, 2055 touchThreshold : 100, 2056 infinite : false, 2057 slidesToShow : 4, 2058 slidesToScroll : 1, 2059 prevArrow : '<span class="slick-prev slick-arrow svg-icon icon-left icon-small"><svg width="16" height="16"><use xlink:href="#left"></use></svg></span>', 2060 nextArrow : '<span class="slick-next slick-arrow svg-icon icon-right icon-small"><svg width="16" height="16"><use xlink:href="#right"></use></svg></span>' 2061 }; 2062 2063 if ( $product.hasClass( 'layout-v4' ) ) { 2064 options.vertical = true, 2065 options.verticalSwiping = true; 2066 } else if ( $product.hasClass( 'layout-v6' ) ) { 2067 options.vertical = true, 2068 options.verticalSwiping = true; 2069 } else if ( $product.hasClass( 'layout-v7' ) ) { 2070 options.adaptiveHeight = true; 2071 } 2072 2073 var isVertical = options.vertical ? true : false; 2074 2075 if ( $gallery.hasClass( 'woocommerce-product-gallery--mobile-nav-dots' ) ) { 2076 options.responsive = [ 2077 { 2078 breakpoint: 991, 2079 settings: 'unslick' 2080 } 2081 ]; 2082 } else if ( $gallery.hasClass( 'woocommerce-product-gallery--mobile-nav-thumbnails' ) ) { 2083 options.mobileFirst = true; 2084 options.responsive = [ 2085 { 2086 breakpoint: 0, 2087 settings: { 2088 variableWidth : true, 2089 vertical : false, 2090 verticalSwiping: false, 2091 } 2092 } 2093 ]; 2094 2095 var desktopOptions = { 2096 breakpoint: 992, 2097 settings: {} 2098 } 2099 2100 if ( $gallery.hasClass( 'woocommerce-product-gallery--nav-thumbnails' ) ) { 2101 desktopOptions.settings = { 2102 vertical: options.vertical, 2103 verticalSwiping: options.verticalSwiping 2104 }; 2105 2106 delete options.vertical; 2107 delete options.verticalSwiping; 2108 } else { 2109 desktopOptions.settings = 'unslick'; 2110 } 2111 2112 options.responsive.push( desktopOptions ); 2113 } 2114 2115 var initGalleryThumbsCarousel = function() { 2116 var slidesToShow = 0; 2117 2118 if ( isVertical ) { 2119 // On mobile vertical carousel is not used. 2120 if ( options.mobileFirst && window.innerWidth < 992 ) { 2121 slidesToShow = parseInt( $gallery.width() / ( $thumbnails.find( 'li:eq(0) > img' ).width() + 10 ) ); 2122 } else { 2123 slidesToShow = parseInt( $gallery.height() / ( $thumbnails.find( 'li:eq(0) > img' ).height() ) ); 2124 } 2125 } else { 2126 slidesToShow = parseInt( $gallery.width() / ( $thumbnails.find( 'li:eq(0)' ).width() + 10 ) ); 2127 } 2128 2129 if ( ! options.mobileFirst || window.innerWidth >= 992 || ! isVertical ) { 2130 options.slidesToShow = slidesToShow; 2131 } 2132 2133 if ( ! $thumbnails.hasClass( 'slick-initialized' ) && slidesToShow && $thumbnails.children().length > slidesToShow ) { 2134 $thumbnails.slick( options ); 2135 } 2136 }; 2137 2138 setTimeout( function() { 2139 // To make sure FlexSlider is initialized. 2140 if ( ! $thumbnails.length ) { 2141 $gallery = $( '.woocommerce-product-gallery', $product ); 2142 $thumbnails = $gallery.find( '.flex-control-thumbs' ); 2143 } 2144 2145 var firstThumb = $thumbnails.children().first().find( 'img' ).get( 0 ); 2146 2147 if ( ! firstThumb ) { 2148 return; 2149 } 2150 2151 if ( firstThumb.complete ) { 2152 initGalleryThumbsCarousel(); 2153 } else { 2154 firstThumb.addEventListener( 'load', initGalleryThumbsCarousel ); 2155 } 2156 }, 200 ); 2157 2158 $( window ).on( 'resize', function() { 2159 // With some product layouts, the gallery is replaced by a clone. 2160 // Have to update the variable accordingly to the replacement. 2161 // See more: konte.responsiveProductGallery() 2162 setTimeout( function() { 2163 if ( ! $.contains( document.documentElement, $thumbnails.get(0) ) ) { 2164 $gallery = $( '.woocommerce-product-gallery', $product ); 2165 $thumbnails = $gallery.find( '.flex-control-thumbs' ); 2166 } 2167
2168 initGalleryThumbsCarousel(); 2169 }, 200 ); 2170 } ); 2171 } 2172 2173 /** 2174 * Init slider for product gallery on mobile. 2175 */ 2176 konte.responsiveProductGallery = function() { 2177 if ( konte.data.product_gallery_slider || ! $.fn.wc_product_gallery ) { 2178 return; 2179 } 2180 2181 var $window = $( window ), 2182 $product = $( '.woocommerce div.product' ), 2183 default_flexslider_enabled = false, 2184 default_flexslider_options = {}; 2185 2186 if ( ! $product.length ) { 2187 return; 2188 } 2189 2190 var $gallery = $( '.woocommerce-product-gallery', $product ), 2191 $originalGallery = $gallery.clone(), 2192 sliderActive = $gallery.find( '.flex-viewport' ).length; 2193 2194 $originalGallery.children( '.woocommerce-product-gallery__trigger' ).remove(); 2195 2196 // Turn off events then we init them again later. 2197 $originalGallery.off(); 2198 2199 if ( typeof wc_single_product_params !== undefined ) { 2200 default_flexslider_enabled = wc_single_product_params.flexslider_enabled; 2201 default_flexslider_options = wc_single_product_params.flexslider; 2202 } 2203 2204 initProductGallery(); 2205 $window.on( 'resize', initProductGallery ); 2206 2207 // Init product gallery 2208 function initProductGallery() { 2209 if ( $window.width() > 991 ) { 2210 if ( ! sliderActive ) { 2211 return; 2212 } 2213 2214 if ( typeof wc_single_product_params !== undefined ) { 2215 wc_single_product_params.flexslider_enabled = default_flexslider_enabled; 2216 wc_single_product_params.flexslider = default_flexslider_options; 2217 } 2218 2219 // Destroy is not supported at this moment. 2220 $gallery.replaceWith( $originalGallery.clone() ); 2221 $gallery = $( '.woocommerce-product-gallery', $product ); 2222 2223 $gallery.each( function() { 2224 $( this ).wc_product_gallery(); 2225 } ); 2226 2227 $( 'form.variations_form select', $product ).trigger( 'change' ); 2228 2229 // Init zoom for product gallery images 2230 if ( '1' === konte.data.product_image_zoom && $product.hasClass( 'layout-v2' ) ) { 2231 $gallery.find( '.woocommerce-product-gallery__image' ).each( function() { 2232 konte.zoomSingleProductImage( this ); 2233 } ); 2234 } 2235 2236 sliderActive = false; 2237 } else { 2238 if ( sliderActive ) { 2239 return; 2240 } 2241 2242 if ( typeof wc_single_product_params !== undefined ) { 2243 wc_single_product_params.flexslider_enabled = true; 2244 // wc_single_product_params.flexslider.controlNav = true; 2245 } 2246 2247 $gallery.replaceWith( $originalGallery.clone() ); 2248 $gallery = $( '.woocommerce-product-gallery', $product ); 2249 2250 // Support Jetpack lazy load. 2251 $( document.body ).trigger( 'konte_lazy_load_images' ); 2252 2253 setTimeout( function() { 2254 $gallery.each( function() { 2255 $( this ).wc_product_gallery(); 2256 2257 konte.addIndexToCarouselControlNav( this ); 2258 } ); 2259 }, 100 ); 2260 2261 $( 'form.variations_form select', $product ).trigger( 'change' ); 2262 2263 sliderActive = true; 2264 } 2265 } 2266 }; 2267 2268 /** 2269 * Related & ppsell products carousel. 2270 */ 2271 konte.relatedProductsCarousel = function() { 2272 if ( typeof Swiper === 'undefined' ) { 2273 return; 2274 } 2275 2276 var $related = $( '.products.related, .products.upsells' ); 2277 2278 if ( ! $related.length ) { 2279 return; 2280 } 2281 2282 var $products = $related.find( 'ul.products' ); 2283 2284 $products.wrap( '<div class="konte-swiper-container swiper-container linked-products-carousel" style="opacity: 0;"></div>' ); 2285 $products.after( '<div class="swiper-pagination"></div>' ); 2286 $products.addClass( 'swiper-wrapper' ); 2287 $products.find( 'li.product' ).addClass( 'swiper-slide' ); 2288 2289 var carousel = new Swiper( '.linked-products-carousel', { 2290 loop : false, 2291 slidesPerView : 1, 2292 slidesPerGroup: 1, 2293 spaceBetween : 40, 2294 speed : 800, 2295 watchOverflow : true, 2296 pagination : { 2297 el : '.swiper-pagination', 2298 type : 'bullets', 2299 clickable : true, 2300 renderBullet: function( index, className ) { 2301 return '<span class="' + className + '"><span></span></span>'; 2302 } 2303 }, 2304 on : { 2305 init: function() { 2306 this.$el.css( 'opacity', 1 ); 2307 } 2308 }, 2309 breakpoints : { 2310 360: { 2311 spaceBetween : 20, 2312 slidesPerView : 2, 2313 slidesPerGroup: 2 2314 }, 2315 768: { 2316 spaceBetween : 20, 2317 slidesPerView : 2, 2318 slidesPerGroup: 2 2319 }, 2320 992 : { 2321 slidesPerView : 3, 2322 slidesPerGroup: 3 2323 }, 2324 1200: { 2325 slidesPerView : 4, 2326 slidesPerGroup: 4 2327 } 2328 } 2329 } ); 2330 }; 2331 2332 /** 2333 * Zoom an image. 2334 * Copy from WooCommerce single-product.js file. 2335 */ 2336 konte.zoomSingleProductImage = function( zoomTarget ) { 2337 if ( typeof wc_single_product_params == 'undefined' || !$.fn.zoom ) { 2338 return; 2339 } 2340 2341 var $target = $( zoomTarget ), 2342 width = $target.width(), 2343 zoomEnabled = false;
2344 2345 $target.each( function( index, target ) { 2346 var $image = $( target ).find( 'img' ); 2347 2348 if ( $image.data( 'large_image_width' ) > width ) { 2349 zoomEnabled = true; 2350 return false; 2351 } 2352 } ); 2353 2354 // Only zoom if the img is larger than its container. 2355 if ( zoomEnabled ) { 2356 var zoom_options = $.extend( { 2357 touch: false 2358 }, wc_single_product_params.zoom_options ); 2359 2360 if ( 'ontouchstart' in document.documentElement ) { 2361 zoom_options.on = 'click'; 2362 } 2363 2364 $target.trigger( 'zoom.destroy' ); 2365 $target.zoom( zoom_options ); 2366 } 2367 } 2368 2369 /** 2370 * Add class to .form-row when inputs are focused. 2371 */ 2372 konte.formFieldFocus = function() { 2373 $( document.body ) 2374 .on( 'focus', '.form-row .input-text, .wpcf7-form-control', function() { 2375 $( this ).parent().addClass( 'focused' ); 2376 2377 if ( $( this ).is( '.wpcf7-form-control' ) ) { 2378 $( this ).closest( 'label' ).addClass( 'focused' ); 2379 } else { 2380 $( this ).closest( '.form-row' ).addClass( 'focused' ); 2381 } 2382 } ) 2383 .on( 'blur', '.form-row .input-text, .wpcf7-form-control', function() { 2384 if ( $( this ).val() === '' ) { 2385 if ( $( this ).is( '.wpcf7-form-control' ) ) { 2386 $( this ).closest( 'label' ).removeClass( 'focused' ); 2387 } else { 2388 $( this ).closest( '.form-row' ).removeClass( 'focused' ); 2389 } 2390 } 2391 } ) 2392 .find( '.form-row .input-text, .wpcf7-form-control' ).each( function() { 2393 if ( $( this ).val() != '' ) { 2394 if ( $( this ).is( '.wpcf7-form-control' ) ) { 2395 $( this ).closest( 'label' ).addClass( 'focused' ); 2396 } else { 2397 $( this ).closest( '.form-row' ).addClass( 'focused' ); 2398 } 2399 } 2400 } ); 2401 }; 2402 2403 /** 2404 * Login & register tabs. 2405 */ 2406 konte.loginTabs = function() { 2407 $( document.body ).on( 'click', '.login-tabs-nav .tab-nav', function( event ) { 2408 event.preventDefault(); 2409 2410 var $tab = $( this ), 2411 $panels = $tab.parent().siblings( '.u-columns' ); 2412 2413 if ( $tab.hasClass( 'active' ) ) { 2414 return; 2415 } 2416 2417 $tab.addClass( 'active' ).siblings().removeClass( 'active' ); 2418 $panels.children().eq( $tab.index() ).addClass( 'active' ).siblings().removeClass( 'active' ); 2419 } ); 2420 }; 2421 2422 /** 2423 * Toggle register/login form in the login panel. 2424 */ 2425 konte.loginPanel = function() { 2426 $( document.body ) 2427 .on( 'click', '#login-panel .create-account', function( event ) { 2428 event.preventDefault(); 2429 2430 $( this ).closest( 'form.login' ).fadeOut( function() { 2431 $( this ).next( 'form.register' ).fadeIn(); 2432 } ); 2433 } ).on( 'click', '#login-panel a.login', function( event ) { 2434 event.preventDefault(); 2435 2436 $( this ).closest( 'form.register' ).fadeOut( function() { 2437 $( this ).prev( 'form.login' ).fadeIn(); 2438 } ); 2439 } ).on( 'click', '[data-toggle="off-canvas"][data-target="login-panel"]', function() { 2440 $( '#login-panel' ).find( 'form' ).hide().filter( '.login' ).show(); 2441 } ); 2442 }; 2443 2444 /** 2445 * Ajax login before refresh page 2446 */ 2447 konte.loginPanelAuthenticate = function() { 2448 $( '#login-panel' ).on( 'submit', 'form.login', function authenticate( event ) { 2449 var username = $( 'input[name=username]', this ).val(), 2450 password = $( 'input[name=password]', this ).val(), 2451 remember = $( 'input[name=rememberme]', this ).is( ':checked' ), 2452 nonce = $( 'input[name=woocommerce-login-nonce]', this ).val(), 2453 $button = $( '[type=submit]', this ), 2454 $form = $( this ), 2455 $box = $form.next( '.woocommerce-error' ); 2456 2457 if ( ! username ) { 2458 $( 'input[name=username]', this ).focus(); 2459 2460 return false; 2461 } 2462 2463 if ( ! password ) { 2464 $( 'input[name=password]', this ).focus(); 2465 2466 return false; 2467 } 2468 2469 $form.find( '.woocommerce-error' ).remove(); 2470 2471 if ( $form.data( 'validated' ) ) { 2472 return true; 2473 } 2474 2475 $button.html( '<span class="spinner"></span>' ); 2476 2477 if ( $box.length ) { 2478 $box.fadeOut(); 2479 } 2480 2481 $.post( 2482 konte.data.ajax_url, 2483 { 2484 action: 'konte_login_authenticate', 2485 security: nonce, 2486 username: username, 2487 password: password, 2488 remember: remember 2489 }, 2490 function( response ) { 2491 if ( ! response.success ) { 2492 if ( ! $box.length ) { 2493 $box = $( '<div class="woocommerce-error" role="alert"/>' ); 2494 2495 $box.append( '<span class="svg-icon icon-error size-normal message-icon"><svg role="img"><use href="#error" xlink:href="#error"></use></svg></span>' ) 2496 .append( '<ul class="error-message" />' ) 2497 .append( '<span class="svg-icon icon-close size-normal close-message"><svg role="img"><use href="#close" xlink:href="#close"></use></svg></span>' ); 2498 2499 $box.hide().prependTo( $form ); 2500 } 2501 2502 $box.find( '.error-message' ).html( '<li>' + response.data + '</li>' ); 2503 $box.fadeIn(); 2504 $button.html( $button.attr( 'value' ) ); 2505 } else { 2506 $form.data( 'validated', true ).submit(); 2507 $button.html( $button.data( 'signed' ) ); 2508 } 2509 } 2510 ); 2511 2512 event.preventDefault(); 2513 } ).on( 'click', '.woocommerce-error .close-message', function() { 2514 // Remove the error message to fix the layout issue. 2515 $( this ).closest( '.woocommerce-error' ).fadeOut( function() { 2516 $( this ).remove(); 2517 } ); 2518 2519 return false;
2520 } ); 2521 }; 2522 2523 /** 2524 * Initialize masonry layout for the shop page. 2525 */ 2526 konte.productsMasonry = function() { 2527 var $container = $( 'ul.products.layout-masonry' ), 2528 $window = $( window ); 2529 2530 if ( !$.fn.masonry || !$container.length ) { 2531 return; 2532 } 2533 2534 $container.on( 'layoutComplete', layoutMasonry ); 2535 2536 initMansonry(); 2537 2538 $window.on( 'resize', initMansonry ); 2539 2540 $( document.body ).on( 'post-load konte_products_loaded', function( event, products, appended ) { 2541 if ( $window.width() < 992 ) { 2542 return; 2543 } 2544 2545 if ( appended ) { 2546 $container.masonry( 'appended', products ).masonry(); 2547 } else { 2548 $container = $( 'ul.products.layout-masonry' ); 2549 2550 $container.on( 'layoutComplete', layoutMasonry ); 2551 2552 initMansonry(); 2553 } 2554 } ); 2555 2556 /** 2557 * Init masonry layout 2558 */ 2559 function initMansonry() { 2560 if ( $container.children().length <= 1 ) { 2561 return; 2562 } 2563 2564 if ( $window.width() < 992 ) { 2565 $container.each( function() { 2566 var $this = $( this ); 2567 2568 if ( $this.hasClass( 'masonry' ) ) { 2569 $this.masonry( 'destroy' ); 2570 } 2571 } ); 2572 } else { 2573 $container.each( function() { 2574 var $this = $( this ), 2575 options = { 2576 itemSelector: 'li.product', 2577 columnWidth: 'li.product:nth-child(2)', 2578 percentPosition: true, 2579 transitionDuration: 0, 2580 isRTL: !! konte.data.rtl 2581 }; 2582 2583 if ( ! $this.hasClass( 'masonry' ) ) { 2584 $this.masonry( options ); 2585 2586 $this.imagesLoaded().progress( function() { 2587 $this.masonry( 'layout' ); 2588 } ); 2589 } 2590 } ); 2591 } 2592 } 2593 2594 /** 2595 * Change the masonry layout as the design. 2596 */ 2597 function layoutMasonry() { 2598 var prop = konte.data.rtl ? 'right' : 'left'; 2599 2600 $container 2601 .children( ':nth-child(10n+1), :nth-child(10n+6), :nth-child(10n+9)' ) 2602 .css( prop, '0' ) 2603 .end() 2604 .children( ':nth-child(10n+2), :nth-child(10n+4)' ) 2605 .css( prop, '50%' ) 2606 .end() 2607 .children( ':nth-child(10n+3), :nth-child(10n+5), :nth-child(10n+8), :nth-child(10n)' ) 2608 .css( prop, '75%' ) 2609 .end() 2610 .children( ':nth-child(10n+7)' ) 2611 .css( prop, '25%' ); 2612 } 2613 }; 2614 2615 /** 2616 * Proudcts carousel layout. 2617 */ 2618 konte.productsCarousel = function() { 2619 var $container = $( '.products-carousel' ); 2620 2621 if ( !$container.length ) { 2622 return; 2623 } 2624 2625 $container.find( 'ul.products li.product' ).addClass( 'swiper-slide' ); 2626 2627 var carousel = new Swiper( '.products-carousel', { 2628 loop : false, 2629 slidesPerView: 1, 2630 spaceBetween : 40, 2631 scrollbar : { 2632 el : '.swiper-scrollbar', 2633 hide : false, 2634 draggable: true 2635 }, 2636 on : { 2637 init: function() { 2638 $container.css( 'opacity', 1 ); 2639 } 2640 }, 2641 breakpoints : { 2642 360 : { 2643 slidesPerView: 2 2644 }, 2645 992 : { 2646 slidesPerView: 3 2647 }, 2648 1200: { 2649 slidesPerView: 4 2650 } 2651 } 2652 } ); 2653 2654 var xhr; 2655 2656 carousel.on( 'reachEnd', function() { 2657 var $nav = $( '.woocommerce-navigation.ajax-navigation' ); 2658 2659 if ( !$nav.length ) { 2660 return; 2661 } 2662 2663 if ( xhr ) { 2664 return; 2665 } 2666 2667 var loadingHolder = document.createElement( 'li' ); 2668 2669 $( loadingHolder ) 2670 .addClass( 'swiper-slide loading-placeholder' ) 2671 .css( {height: carousel.height - 140} ) 2672 .append( '<span class="spinner"></span>' ); 2673 2674 carousel.appendSlide( loadingHolder ); 2675 carousel.update(); 2676 2677 xhr = $.get( $nav.find( 'a' ).attr( 'href' ), function( response ) { 2678 var $content = $( '#main', response ), 2679 $list = $( 'ul.products', $content ), 2680 $products = $list.children(), 2681 $newNav = $( '.woocommerce-navigation.ajax-navigation', $content ); 2682 2683 if ( $newNav.length ) { 2684 $nav.find( 'a' ).replaceWith( $( 'a', $newNav ) ); 2685 } else { 2686 $nav.fadeOut( function() { 2687 $nav.remove(); 2688 } ); 2689 } 2690 2691 $( loadingHolder ).remove(); 2692 $products.css( {opacity: 0} ); 2693
2694 carousel.appendSlide( $products.addClass( 'swiper-slide' ).get() ); 2695 carousel.update(); 2696 2697 $products.animate( {opacity: 1} ); 2698 xhr = false; 2699 2700 $( document.body ).trigger( 'konte_products_loaded', [$products, true] ); 2701 } ); 2702 } ); 2703 }; 2704 2705 /** 2706 * Product thumbnails slider. 2707 */ 2708 konte.productThumbnailsSlider = function() { 2709 var options = { 2710 slidesToShow : 1, 2711 slidesToScroll: 1, 2712 infinite : false, 2713 lazyLoad : 'ondemand', 2714 dots : false, 2715 swipe : false, 2716 rtl : !! konte.data.rtl, 2717 prevArrow : '<span class="slick-prev slick-arrow svg-icon icon-left icon-small"><svg width="16" height="16"><use xlink:href="#left"></use></svg></span>', 2718 nextArrow : '<span class="slick-next slick-arrow svg-icon icon-right icon-small"><svg width="16" height="16"><use xlink:href="#right"></use></svg></span>' 2719 } 2720 2721 if ( konte.data.rtl ) { 2722 $( '.product-thumbnails--slider' ).attr( 'dir', 'rtl' ); 2723 } 2724 2725 $( '.product-thumbnails--slider' ).slick( options ); 2726 2727 // Filter plugins. 2728 $( document.body ).on( 'post-load', function() { 2729 if ( konte.data.rtl ) { 2730 $( '.product-thumbnails--slider', 'ul.products.hover-slider' ).attr( 'dir', 'rtl' ); 2731 } 2732 2733 $( '.product-thumbnails--slider', 'ul.products.hover-slider' ).slick( options ); 2734 } ) 2735 2736 // Ajax product loaded. 2737 $( document.body ).on( 'konte_products_loaded', function( event, products ) { 2738 if ( konte.data.rtl ) { 2739 $( '.product-thumbnails--slider', products ).attr( 'dir', 'rtl' ); 2740 } 2741 2742 $( '.product-thumbnails--slider', products ).slick( options ); 2743 } ); 2744 }; 2745 2746 /** 2747 * Product thumbnail zoom. 2748 */ 2749 konte.productThumbnailZoom = function() { 2750 $( '.product-thumbnail-zoom' ).each( function() { 2751 var $el = $( this ); 2752 2753 $el.zoom( { 2754 url: $el.attr( 'data-zoom_image' ) 2755 } ); 2756 } ); 2757 2758 // Filter plugins. 2759 $( document.body ).on( 'post-load', function() { 2760 $( '.product-thumbnail-zoom', 'ul.products.hover-zoom' ).each( function() { 2761 var $el = $( this ); 2762 2763 $el.zoom( { 2764 url: $el.attr( 'data-zoom_image' ) 2765 } ); 2766 } ); 2767 } ); 2768 2769 // Ajax product loaded. 2770 $( document.body ).on( 'konte_products_loaded', function( event, products ) { 2771 $( '.product-thumbnail-zoom', products ).each( function() { 2772 var $el = $( this ); 2773 2774 $el.zoom( { 2775 url: $el.attr( 'data-zoom_image' ) 2776 } ); 2777 } ); 2778 } ); 2779 }; 2780 2781 /** 2782 * Quick view modal. 2783 */ 2784 konte.productQuickView = function() { 2785 $( document.body ).on( 'click', '.quick_view_button', function( event ) { 2786 event.preventDefault(); 2787 2788 var $el = $( this ), 2789 product_id = $el.data( 'product_id' ), 2790 $target = $( '#' + $el.data( 'target' ) ), 2791 $container = $target.find( '.woocommerce' ), 2792 ajax_url = woocommerce_params ? woocommerce_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'product_quick_view' ) : konte.data.ajax_url; 2793 2794 $target.addClass( 'loading' ); 2795 $container.find( '.product' ).html( '' ); 2796 2797 $.post( 2798 ajax_url, 2799 { 2800 action : 'konte_get_product_quickview', 2801 product_id: product_id, 2802 security : konte.data.product_quickview_nonce 2803 }, 2804 function( response ) { 2805 $container.find( '.product' ).replaceWith( response.data ); 2806 2807 if ( response.success ) { 2808 update_quickview(); 2809 2810 if ( 'modal' == $el.data( 'toggle' ) ) { 2811 update_quickview_modal(); 2812 } else { 2813 update_quickview_panel(); 2814 } 2815 } 2816 2817 $target.removeClass( 'loading' ); 2818 2819 $( document.body ).trigger( 'konte_product_quickview_loaded', [response, product_id, konte] ); 2820 } 2821 ).fail( function() { 2822 window.location.herf = $el.attr( 'href' ); 2823 } ); 2824 2825 /** 2826 * Update quick view common elements. 2827 */ 2828 function update_quickview() { 2829 var $product = $container.find( '.product' ), 2830 $gallery = $product.find( '.woocommerce-product-gallery' ), 2831 $variations = $product.find( '.variations_form' ); 2832 2833 // Prevent clicking on gallery image link. 2834 $gallery.on( 'click', '.woocommerce-product-gallery__image a', function( event ) { 2835 event.preventDefault(); 2836 } ); 2837 2838 // Init flex slider. 2839 if ( $gallery.find( '.woocommerce-product-gallery__image' ).length > 1 ) { 2840 $gallery.flexslider( { 2841 selector : '.woocommerce-product-gallery__wrapper > .woocommerce-product-gallery__image', 2842 animation : 'slide', 2843 animationLoop : false, 2844 animationSpeed: 500, 2845 controlNav : true, 2846 directionNav : true, 2847 prevText : '<span class="svg-icon icon-left icon-small"><svg width="16" height="16"><use xlink:href="#left"></use></svg></span>', 2848 nextText : '<span class="svg-icon icon-right icon-small"><svg width="16" height="16"><use xlink:href="#right"></use></svg></span>', 2849 slideshow : false, 2850 rtl : !! konte.data.rtl, 2851 start : function() { 2852 $gallery.css( 'opacity', 1 ); 2853 }, 2854 } ); 2855 } else { 2856 $gallery.css( 'opacity', 1 ); 2857 } 2858 2859 // Make videos responsive. 2860 $product.find( '.summary iframe' ).wrap( '<figure class="wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper"/></div>' ); 2861 2862 // Variations form. 2863 if ( $variations.length ) { 2864 $variations.wc_variation_form().find( '.variations select:eq(0)' ).change(); 2865 2866 if ( $gallery.data( 'flexslider' ) ) { 2867 $variations.on( 'reset_image found_variation', function() { 2868 $gallery.flexslider( 0 ); 2869 } ); 2870 } 2871 2872 if ( $.fn.tawcvs_variation_swatches_form ) { 2873 $variations.tawcvs_variation_swatches_form(); 2874 konte.modifyVariationSwatches( $variations ); 2875 } 2876 2877 $( document.body ).trigger( 'init_variation_swatches' ); 2878 } 2879 } 2880 2881 /** 2882 * Update quick view modal's special elements. 2883 */ 2884 function update_quickview_modal() { 2885 var $product = $container.find( '.product' ), 2886 $gallery = $product.find( '.woocommerce-product-gallery' ); 2887 2888 // Force height for images 2889 $gallery.find( 'img' ).css( 'height', $product.outerHeight() ); 2890 2891 if ( konte.data.product_quickview_auto_background && !$product.hasClass( 'background-set' ) ) { 2892 try { 2893 $product.imagesLoaded( function() {
2894 konte.productBackgroundFromGallery( $product ); 2895 } ); 2896 } catch ( e ) { 2897 console.warn( e ); 2898 } 2899 } 2900 2901 if ( typeof PerfectScrollbar !== 'undefined' ) { 2902 new PerfectScrollbar( $product.find( '.summary' ).get( 0 ) ); 2903 } 2904 } 2905 2906 /** 2907 * Update quick view panel's special elements. 2908 */ 2909 function update_quickview_panel() { 2910 if ( typeof PerfectScrollbar !== 'undefined' ) { 2911 new PerfectScrollbar( $container.find( '.product' ).get( 0 ) ); 2912 } 2913 } 2914 } ); 2915 }; 2916 2917 /** 2918 * Empty the quickview modal/panel on close to prevent sound of videos, 2919 * or any unexpected effects. 2920 */ 2921 konte.emptyQuickViewOnClose = function() { 2922 $( document.body ).on( 'konte_off_canvas_closed konte_modal_closed', function( event, target ) { 2923 var $quickview = $( target ); 2924 2925 if ( ! $quickview.is( '#quick-view-modal' ) && ! $quickview.is( '#quick-view-panel' ) ) { 2926 return; 2927 } 2928 2929 $quickview.find( '.product' ).html( '' ); 2930 } ); 2931 }; 2932 2933 /** 2934 * Auto-close the quick-view on successful product add to cart. 2935 */ 2936 konte.autoCloseQuickView = function() { 2937 $( document.body ).on( 'added_to_cart', function() { 2938 if ( '1' === konte.data.product_quickview_auto_close || '1' === konte.data.cart_open_after_added ) { 2939 konte.closeOffCanvas( '#quick-view-modal' ); 2940 konte.closeModal( '#quick-view-modal' ); 2941 } 2942 } ); 2943 }; 2944 2945 /** 2946 * Modify variation swatches script. 2947 * 2948 * @param $form 2949 */ 2950 konte.modifyVariationSwatches = function( $form ) { 2951 // Remove class "swatches-support" if there is no swatches in this product 2952 var hasSwatches = false; 2953 2954 if ( $form.find( '.tawcvs-swatches' ).length ) { 2955 hasSwatches = true; 2956 } 2957 2958 if ( ! hasSwatches ) { 2959 $form.removeClass( 'swatches-support' ); 2960 } 2961 2962 // Change alert style 2963 $form.off( 'tawcvs_no_matching_variations' ); 2964 $form.on( 'tawcvs_no_matching_variations', function( event ) { 2965 event.preventDefault(); 2966 2967 $form.find( '.woocommerce-variation.single_variation' ).show(); 2968 if ( typeof wc_add_to_cart_variation_params !== 'undefined' ) { 2969 $form.find( '.single_variation' ).stop( true, true ).slideDown().html( '<p class="invalid-variation-combination">' + wc_add_to_cart_variation_params.i18n_no_matching_variations_text + '</p>' ); 2970 } 2971 } ); 2972 }; 2973 2974 /** 2975 * Ajax load more products. 2976 */ 2977 konte.loadMoreProducts = function() { 2978 // Handles click load more button. 2979 $( document.body ).on( 'click', '.woocommerce-navigation.ajax-navigation a', function( event ) { 2980 event.preventDefault(); 2981 2982 var $el = $( this ); 2983 2984 if ( $el.hasClass( 'loading' ) ) { 2985 return; 2986 } 2987 2988 $el.addClass( 'loading' ); 2989 2990 loadProducts( $( this ) ); 2991 } ); 2992 2993 // Infinite scroll. 2994 if ( $( document.body ).hasClass( 'woocommerce-nav-infinite' ) ) { 2995 var waiting = false, 2996 endScrollHandle; 2997 2998 $( window ).on( 'scroll', function() { 2999 if ( waiting ) { 3000 return; 3001 } 3002 3003 waiting = true; 3004 3005 // clear previous scheduled endScrollHandle 3006 clearTimeout( endScrollHandle ); 3007 3008 infiniteScoll(); 3009 3010 setTimeout( function() { 3011 waiting = false; 3012 }, 100 ); 3013 3014 // schedule an extra execution of infiniteScoll() after 200ms 3015 // in case the scrolling stops in next 100ms. 3016 endScrollHandle = setTimeout( function() { 3017 waiting = false; 3018 infiniteScoll(); 3019 }, 200 ); 3020 } ); 3021 } 3022 3023 /** 3024 * Infinite scroll handler. 3025 */ 3026 function infiniteScoll() { 3027 var $navigation = $( '.woocommerce-navigation.ajax-navigation' ), 3028 $button = $( 'a', $navigation ); 3029 3030 // When almost reach to the navigation. 3031 if ( konte.isVisible( $navigation ) && $button.length && !$button.hasClass( 'loading' ) ) { 3032 $button.addClass( 'loading' ); 3033 3034 loadProducts( $button, function( respond ) { 3035 $button = $navigation.find( 'a' ); 3036 } ); 3037 } 3038 } 3039 3040 /** 3041 * Ajax load products. 3042 * 3043 * @param jQuery $el Button element. 3044 * @param function callback The callback function. 3045 */ 3046 function loadProducts( $el, callback ) { 3047 var $nav = $el.closest( '.woocommerce-navigation' ), 3048 url = $el.attr( 'href' ); 3049 3050 $.get( url, function( response ) { 3051 var $content = $( '#main', response ), 3052 $list = $( 'ul.products', $content ), 3053 $products = $list.children(), 3054 $newNav = $( '.woocommerce-navigation.ajax-navigation', $content ); 3055 3056 $products.each( function( index, product ) { 3057 $( product ).css( 'animation-delay', index * 100 + 'ms' ); 3058 } ); 3059 3060 $products.appendTo( $nav.siblings( 'ul.products' ).not('.product-categories').last() ); 3061 $products.addClass( 'animated konteFadeInUp' ); 3062 3063 if ( $newNav.length ) { 3064 $el.replaceWith( $( 'a', $newNav ) ); 3065 } else { 3066 $nav.fadeOut( function() { 3067 $nav.remove(); 3068 } ); 3069 } 3070 3071 if ( 'function' === typeof callback ) { 3072 callback( response ); 3073 } 3074 3075 $( document.body ).trigger( 'konte_products_loaded', [$products, true] ); 3076 3077 if ( konte.data.shop_nav_ajax_url_change ) { 3078 window.history.pushState( null, '', url ); 3079 } 3080 } ); 3081 } 3082 }; 3083 3084 /** 3085 * Check if an element is in view-port or not 3086 * 3087 * @param jQuery el Targe element to check. 3088 * @return boolean 3089 */ 3090 konte.isVisible = function( el ) { 3091 if ( el instanceof jQuery ) { 3092 el = el[0]; 3093 } 3094 3095 if ( ! el ) { 3096 return false;
3097 } 3098 3099 var rect = el.getBoundingClientRect(); 3100 3101 return rect.bottom > 0 && 3102 rect.right > 0 && 3103 rect.left < (window.innerWidth || document.documentElement.clientWidth) && 3104 rect.top < (window.innerHeight || document.documentElement.clientHeight); 3105 }; 3106 3107 /** 3108 * Proudcts quick search. 3109 */ 3110 konte.productsQuickSearch = function() { 3111 var $form = $( '.products-quick-search-form' ); 3112 3113 if ( $.fn.select2 ) { 3114 $form.find( 'select' ).select2( { 3115 dir : konte.data.rtl ? 'rtl' : 'ltr', 3116 width : 'auto', 3117 minimumResultsForSearch: -1, 3118 dropdownCssClass : 'products-quick-search-options', 3119 dropdownParent : $( '.products-quick-search-form' ) 3120 } ).on( 'change', function() { 3121 $form.addClass( 'changed' ); 3122 } ); 3123 } 3124 3125 $form.find( 'select' ).on( 'change', function() { 3126 $form.addClass( 'changed' ); 3127 } ); 3128 3129 $form.on( 'submit', function( event ) { 3130 event.preventDefault(); 3131 3132 var $container = $( 'ul.products.main-products' ), 3133 $inputs = $form.find( ':input:not(:checkbox):not(:button)' ), 3134 url = $form.attr( 'action' ), 3135 separator = url.indexOf( '?' ) !== -1 ? '&' : '?', 3136 params = $inputs.filter( function() { 3137 return $( this ).val() != 0; 3138 } ).serialize(); 3139 3140 if ( params ) { 3141 url += separator + params; 3142 } 3143 3144 if ( $container.hasClass( 'layout-carousel' ) ) { 3145 window.location.href = url; 3146 return false; 3147 } 3148 3149 if ( !$container.length ) { 3150 $container = $( '<ul class="products"/>' ); 3151 $form.closest( '.products-toolbar' ).siblings( '.woocommerce-info' ).replaceWith( $container ); 3152 } 3153 3154 $form.addClass( 'filtering' ); 3155 $form.find( 'select' ).prop( 'disabled', true ); 3156 $container.addClass( 'loading' ).append( '<li class="loading-screen"><span class="spinner"></span></li>' ); 3157 3158 $( document.body ).trigger( 'konte_quick_search_products_before_send_request', $container ); 3159 3160 $.get( url, function( response ) { 3161 var $html = $( response ), 3162 $products = $html.find( '#main ul.products' ), 3163 $pagination = $container.next( 'nav' ); 3164 3165 if ( !$products.length ) { 3166 $products = $html.find( '#main .woocommerce-info' ); 3167 $( '.products-tools' ).addClass( 'out' ); 3168 3169 $pagination.fadeOut(); 3170 $container.replaceWith( $products ); 3171 } else { 3172 var $nav = $products.next( 'nav' ), 3173 $order = $( 'form.woocommerce-ordering' ); 3174 3175 if ( $nav.length ) { 3176 if ( $pagination.length ) { 3177 $pagination.replaceWith( $nav ).fadeIn(); 3178 } else { 3179 $container.after( $nav ); 3180 } 3181 } else { 3182 $pagination.fadeOut(); 3183 } 3184 3185 // Modify the ordering form. 3186 $inputs.each( function() { 3187 var $input = $( this ), 3188 name = $input.attr( 'name' ), 3189 value = $input.val(); 3190 3191 if ( name === 'orderby' ) { 3192 return; 3193 } 3194 3195 $order.find( 'input[name="' + name + '"]' ).remove(); 3196 3197 if ( value !== '' && value != 0 ) { 3198 $( '<input type="hidden" name="' + name + '">' ).val( value ).appendTo( $order ); 3199 } 3200 } ); 3201 3202 // Replace the column selector. 3203 $( '.products-toolbar .columns-switcher' ).replaceWith( $html.find( '.products-toolbar .columns-switcher' ) ); 3204 3205 // Replace result count. 3206 $( '.products-toolbar .woocommerce-result-count' ).replaceWith( $html.find( '.products-toolbar .woocommerce-result-count' ) ); 3207 3208 // Replace tabs. 3209 $( '.products-toolbar .products-tabs' ).replaceWith( $html.find( '.products-toolbar .products-tabs' ) ); 3210 3211 // Show the toolbar. 3212 $( '.products-tools' ).removeClass( 'out' ); 3213 3214 $products.children().each( function( index, product ) { 3215 $( product ).css( 'animation-delay', index * 100 + 'ms' ); 3216 } ); 3217 3218 $container.replaceWith( $products ); 3219 3220 $products.find( 'li.product' ).addClass( 'animated konteFadeInUp' ); 3221 3222 $( document.body ).trigger( 'konte_products_loaded', [$products.children(), false] ); 3223 } 3224 3225 $form.removeClass( 'changed filtering' ); 3226 $form.find( 'select' ).prop( 'disabled', false ); 3227 window.history.pushState( null, '', url ); 3228 3229 $( document.body ).trigger( 'konte_products_quick_search_request_success', [$products.children()] ); 3230 } ); 3231 } ); 3232 }; 3233 3234 /** 3235 * Handle products tools events. 3236 */ 3237 konte.productsTools = function() { 3238 var $window = $( window ), 3239 $tools = $( '.products-tools' ); 3240 3241 // Products ordering. 3242 if ( $.fn.select2 ) { 3243 $tools.find( '.woocommerce-ordering select' ).select2( { 3244 dir : konte.data.rtl ? 'rtl' : 'ltr', 3245 width : 'auto', 3246 minimumResultsForSearch: -1, 3247 dropdownCssClass : 'products-ordering', 3248 dropdownParent : $tools.find( '.woocommerce-ordering' ) 3249 } ); 3250 } 3251 3252 // Products filter. 3253 var $filter = $tools.find( '#products-filter' ); 3254 3255 if ( $filter.length && $filter.hasClass( 'dropdown-panel' ) ) { 3256 setDropdownFilterPosition(); 3257 3258 $window.on( 'resize', setDropdownFilterPosition ); 3259 } 3260 3261 // Toggle products filter. 3262 $( document.body ).on( 'click', '.products-tools .toggle-filters[data-toggle="dropdown"]', function( event ) { 3263 event.preventDefault(); 3264 3265 $( $( this ).attr( 'href' ) ).fadeToggle( function() { 3266 $( this ).toggleClass( 'open' ); 3267 } ); 3268 } ).on( 'click', '.products-filter.dropdown-panel .button-close', function( event ) { 3269 event.preventDefault(); 3270 3271 $( this ).closest( '.products-filter' ).fadeOut( function() { 3272 $( this ).removeClass( 'open' ); 3273 } ); 3274 } ); 3275 3276 // Auto close filter when runing ajax. 3277 $( document.body ).on( 'konte_products_filter_before_send_request konte_products_filter_reseted', function() { 3278 if ( $filter.hasClass( 'offscreen-panel' ) ) { 3279 konte.closeOffCanvas( $filter ); 3280 } else { 3281 $filter.fadeOut( function() { 3282 $filter.removeClass( 'open' ); 3283 } ); 3284 } 3285 } ); 3286 3287 // Remove filtered field; 3288 $( '.products-tools .products-filter-toggle' ).on( 'click', 'a.remove-filtered', function( event ) { 3289 event.preventDefault(); 3290 3291 var $el = $( this ); 3292 3293 $( '.products-filter__activated a.remove-filtered[data-name="' + $el.data( 'name' ) + '"][data-value="' + $el.data( 'value' ) + '"]', '#products-filter' ).trigger( 'click' ); 3294 $el.remove(); 3295 } ); 3296 3297 // Update filtered fields. 3298 if ( $filter.hasClass( 'dropdown-panel' ) ) { 3299 displayFilteredField( null, null ); 3300 $( document.body ).on( 'konte_products_filter_widget_updated', displayFilteredField ); 3301 } 3302 3303 /** 3304 * Display filtered fields. 3305 */ 3306 function displayFilteredField( event, form ) { 3307 var $widget = form ? $( form ).closest( '.products-filter-widget' ) : $( '.products-filter-widget', '#products-filter' ); 3308 3309 if ( ! $widget.length ) { 3310 return; 3311 } 3312 3313 var $toggle = $( '.products-tools .products-filter-toggle' ); 3314 3315 $toggle.find( '.remove-filtered' ).remove(); 3316 $widget.find( '.products-filter__activated a.remove-filtered' ).clone().appendTo( $toggle ); 3317 } 3318 3319 /** 3320 * Set the correct position of dropdown filter. 3321 */ 3322 function setDropdownFilterPosition() { 3323 var $sidebar = $( '#secondary' ), 3324 windowWidth = $window.width(); 3325 3326 if ( windowWidth >= 992 ) { 3327 windowWidth -= konte.getVerticalHeaderWidth(); 3328 } 3329 3330 $filter.width( windowWidth ); 3331 3332 // Check if there is a sidebar 3333 var prop = 'margin-left'; 3334 var value = -windowWidth / 2; 3335 3336 if ( konte.data.rtl ) { 3337 prop = 'margin-right'; 3338 } 3339 3340 if ( windowWidth >= 992 ) { 3341 if ( $sidebar.length ) { 3342 if ( $( document.body ).hasClass( 'sidebar-left' ) ) { 3343 value = konte.data.rtl ? value + ($sidebar.outerWidth() / 2) : value - ($sidebar.outerWidth() / 2); 3344 } else { 3345 value = konte.data.rtl ? value - ($sidebar.outerWidth() / 2) : value + ($sidebar.outerWidth() / 2); 3346 } 3347 3348 $filter.css( prop, value ); 3349 } else { 3350 $filter.css( prop, value ); 3351 } 3352 } else { 3353 $filter.css( prop, value ); 3354 } 3355 } 3356 }; 3357 3358 /** 3359 * Make the cart widget more flexible. 3360 */ 3361 konte.cartWidget = function() { 3362 if ( typeof woocommerce_params === 'undefined' ) { 3363 $( '.woocommerce-mini-cart-item .quantity .qty' ).prop( 'disabled', true ); 3364 3365 $( document.body ).on( 'wc_fragments_refreshed removed_from_cart', function() { 3366 $( '.woocommerce-mini-cart-item .quantity .qty' ).prop( 'disabled', true ); 3367 } ); 3368 3369 return; 3370 } 3371 3372 var options = { 3373 onChange: function( data ) { 3374 var $row = data.$quantity.closest( '.woocommerce-mini-cart-item' ), 3375 key = $row.find( 'a.remove' ).data( 'cart_item_key' ), 3376 nonce = $row.find( '.woocommerce-mini-cart-item__qty' ).data( 'nonce' ), 3377 ajax_url = woocommerce_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'update_cart_item' ); 3378 3379 if ( $.fn.block ) { 3380 $row.block( { 3381 message : null, 3382 overlayCSS: { 3383 opacity : 0.6, 3384 background: '#fff' 3385 } 3386 } ); 3387 } 3388 3389 $.post( 3390 ajax_url, { 3391 cart_item_key: key, 3392 qty: data.current, 3393 security: nonce 3394 }, function( response ) { 3395 if ( !response || !response.fragments ) { 3396 return; 3397 } 3398 3399 if ( $.fn.unblock ) { 3400 $row.unblock(); 3401 } 3402 3403 $( document.body ).trigger( 'added_to_cart', [response.fragments, response.cart_hash] ); 3404 3405 // Trigger the fragment refresh event manually if necessary. 3406 if ( 'undefined' === typeof wc_add_to_cart_params ) { 3407 $( document.body ).trigger( 'wc_fragment_refresh' ); 3408 } 3409 }, 'json' ).fail( function() { 3410 if ( $.fn.unblock ) { 3411 $row.unblock(); 3412 } 3413 3414 return; 3415 } ); 3416 } 3417 }; 3418 3419 if ( $.fn.quantityDropdown ) { 3420 $( '.woocommerce-mini-cart-item .quantity .qty' ).quantityDropdown( options ); 3421 3422 $( document.body ).on( 'wc_fragments_refreshed wc_fragments_loaded removed_from_cart added_to_cart', function() { 3423 $( '.woocommerce-mini-cart-item .quantity .qty' ).quantityDropdown( options ); 3424 } ); 3425 } 3426 }; 3427 3428 /** 3429 * Display a notification 3430 */ 3431 konte.shopNotifications = function() { 3432 if ( ! $.fn.notify ) { 3433 return; 3434 } 3435 3436 $.notify.addStyle( 'konte', { 3437 html: '<div><span class="svg-icon icon-success size-normal message-icon"><svg role="img"><use href="#success" xlink:href="#success"></use></svg></span><span data-notify-text/></div>' 3438 }); 3439 3440 if ( konte.data.added_to_cart_notice ) { 3441 $( document.body ).on( 'added_to_cart', function() { 3442 $.notify( konte.data.added_to_cart_message, { 3443 position: konte.data.rtl ? 'top left' : 'top right', 3444 autoHideDelay: 2000,
3445 className: 'success', 3446 style: 'konte', 3447 showAnimation: 'fadeIn', 3448 hideAnimation: 'fadeOut' 3449 } ); 3450 } ); 3451 } 3452 3453 if ( konte.data.added_to_wishlist_notice ) { 3454 $( document.body ).on( 'added_to_wishlist', function() { 3455 $.notify( konte.data.added_to_wishlist_message, { 3456 autoHideDelay: 2000, 3457 className: 'success', 3458 style: 'konte', 3459 showAnimation: 'fadeIn', 3460 hideAnimation: 'fadeOut' 3461 } ); 3462 } ); 3463 } 3464 }; 3465 3466 /** 3467 * Scripts for page template "split.php" 3468 */ 3469 konte.pageTemplateSplit = function() { 3470 if ( !$( document.body ).hasClass( 'page-template-split' ) ) { 3471 return; 3472 } 3473 3474 var $window = $( window ), 3475 $topbar = $( '#topbar' ), 3476 ps = null; 3477 3478 // Scrollbar. 3479 if ( $window.width() >= 992 ) { 3480 ps = new PerfectScrollbar( $( '.split-page-content .entry-content' ).get( 0 ) ); 3481 } 3482 3483 // Full height. 3484 $window.on( 'resize', function() { 3485 $( '.split-page.page' ).height( fullHeight() ); 3486 3487 if ( $window.width() < 992 ) { 3488 if ( ps ) { 3489 ps.destroy(); 3490 } 3491 3492 ps = null; 3493 } else { 3494 ps = new PerfectScrollbar( $( '.split-page-content .entry-content' ).get( 0 ) ); 3495 } 3496 } ); 3497 3498 $( '.split-page.page' ).height( fullHeight() ); 3499 3500 /** 3501 * Get the windown height. 3502 */ 3503 function fullHeight() { 3504 var height = $window.height(); 3505 3506 if ( $topbar.length ) { 3507 height -= $topbar.outerHeight(); 3508 } 3509 3510 return height; 3511 } 3512 }; 3513 3514 /** 3515 * Youtube video background. 3516 */ 3517 konte.videoBackground = function() { 3518 var $player = $( '.video-background' ); 3519 3520 if ( !$player.length ) { 3521 return; 3522 } 3523 3524 var player = null; 3525 var $screen = $player.parent(); 3526 3527 // Scale video function definition moved up 3528 var scaleVideo = function() { 3529 if (!player || !player.setSize || typeof player.setSize !== 'function') { 3530 return; 3531 } 3532 3533 var width = $screen.width(), 3534 pWidth, 3535 height = $screen.height(), 3536 pHeight, 3537 ratio = 16 / 9, 3538 $iframe = $screen.find('.video-background'); 3539 3540 try { 3541 if (width / ratio < height) { 3542 pWidth = Math.ceil(height * ratio); 3543 player.setSize(pWidth, height); 3544 $iframe.css({ 3545 left: (width - pWidth) / 2, 3546 top : 0 3547 }); 3548 } else { 3549 pHeight = Math.ceil(width / ratio); 3550 player.setSize(width, pHeight); 3551 $iframe.css({ 3552 left: 0, 3553 top : (height - pHeight) / 2 3554 }); 3555 } 3556 } catch (e) { 3557 console.warn('Failed to scale video:', e); 3558 } 3559 }; 3560 3561 // Initialize player function 3562 var initPlayer = function() { 3563 var mute = $player.data('mute'); 3564 3565 player = new YT.Player($player.attr('id'), { 3566 videoId: $player.data('video_id'), 3567 events: { 3568 'onReady': function(event) { 3569 // Add a small delay before scaling 3570 setTimeout(function() { 3571 scaleVideo(); 3572 $screen.find('.video-background').css('opacity', 1); 3573 3574 event.target.mute(); 3575 event.target.playVideo(); 3576 }, 100); 3577 }, 3578 'onStateChange': function(event) { 3579 if (event.data === YT.PlayerState.ENDED) { 3580 event.target.playVideo(); 3581 } 3582 } 3583 }, 3584 playerVars: { 3585 autoplay: 1, 3586 loop: 1, 3587 mute: 1, 3588 autohide: 1, 3589 modestbranding: 0, 3590 rel: 0, 3591 showinfo: 0, 3592 controls: 0, 3593 disablekb: 1, 3594 enablejsapi: 1, 3595 iv_load_policy: 3, 3596 playsinline: 1 3597 } 3598 }); 3599 }; 3600 3601 // Debounced resize handler 3602 var resizeTimeout; 3603 $(window).on('resize', function() { 3604 clearTimeout(resizeTimeout); 3605 resizeTimeout = setTimeout(scaleVideo, 150); 3606 }); 3607 3608 // Better YouTube API loading handling 3609 if (typeof YT === 'undefined' || typeof YT.Player === 'undefined') { 3610 // Create global callback 3611 window.onYouTubeIframeAPIReady = function() { 3612 initPlayer(); 3613 }; 3614 3615 // Load YouTube API 3616 var tag = document.createElement('script'); 3617 tag.src = 'https://www.youtube.com/iframe_api'; 3618 var firstScriptTag = document.getElementsByTagName('script')[0]; 3619 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 3620 } else { 3621 // If API is already loaded, initialize directly 3622 initPlayer(); 3623 } 3624 }; 3625 3626 /** 3627 * Init masonry layout for template Flex Posts. 3628 */ 3629 konte.pageTemplateFlexPosts = function() { 3630 var $posts = $( '#flex-posts' ), 3631 $window = $( window ); 3632 3633 if ( !$posts.length || !$.fn.masonry ) { 3634 return; 3635 } 3636 3637 // Init masonry layout 3638 var options = { 3639 itemSelector: '.flex_post', 3640 percentPosition: true, 3641 transitionDuration: 0, 3642 isRTL: !! konte.data.rtl 3643 }; 3644 3645 // Add class left-item and right-item 3646 $posts.on( 'layoutComplete', function( event ) { 3647 var $items = $posts.children(); 3648 3649 if ( konte.data.rtl ) { 3650 $items.filter( function() { 3651 return parseInt( $( this ).get( 0 ).style.right ) === 0; 3652 } ).removeClass( 'left-item' ).addClass( 'right-item' ); 3653 3654 $items.filter( function() { 3655 return $( this ).get( 0 ).style.right === '50%'; 3656 } ).removeClass( 'right-item' ).addClass( 'left-item' ); 3657 } else { 3658 $items.filter( function() { 3659 return parseInt( $( this ).get( 0 ).style.left ) === 0; 3660 } ).removeClass( 'right-item' ).addClass( 'left-item' ); 3661 3662 $items.filter( function() { 3663 return $( this ).get( 0 ).style.left === '50%'; 3664 } ).removeClass( 'left-item' ).addClass( 'right-item' ); 3665 } 3666 } ); 3667 3668 initFlexPostsMasonry(); 3669 3670 $window.on( 'resize', initFlexPostsMasonry ); 3671
3672 // Support Jetpack lazy loads. 3673 var layoutHandle; 3674 3675 $posts.on( 'jetpack-lazy-loaded-image', 'img', function() { 3676 if ( ! $posts.hasClass( 'masonry' ) ) { 3677 initFlexPostsMasonry(); 3678 } 3679 3680 clearTimeout( layoutHandle ); 3681 3682 layoutHandle = setTimeout( function() { 3683 $posts.masonry( 'layout' ); 3684 }, 100 ); 3685 } ); 3686 3687 // Ajax load more posts 3688 $( 'body.page-template-flex-posts' ).on( 'click', '.navigation.next-posts-navigation a', function( event ) { 3689 event.preventDefault(); 3690 3691 var $el = $( this ), 3692 url = $el.attr( 'href' ); 3693 3694 if ( $el.hasClass( 'loading' ) ) { 3695 return; 3696 } 3697 3698 $el.addClass( 'loading' ); 3699 3700 $.get( url, function( response ) { 3701 var $content = $( '#main', response ), 3702 $_posts = $( '.flex_post', $content ), 3703 $nav = $( '.next-posts-navigation', $content ); 3704 3705 $_posts.addClass( 'animated' ).appendTo( $posts ); 3706 ; 3707 $posts.masonry( 'appended', $_posts ).masonry(); 3708 3709 $_posts.imagesLoaded().progress( function() { 3710 $posts.masonry( 'layout' ); 3711 } ); 3712 3713 if ( $nav.length ) { 3714 $el.replaceWith( $( 'a', $nav ) ); 3715 } else { 3716 $el.removeClass( 'loading' ).closest( '.next-posts-navigation' ).fadeOut(); 3717 } 3718 3719 window.history.pushState( null, '', url ); 3720 3721 if ( typeof trigger !== undefined ) { 3722 $_posts.attr( 'data-scroll', '' ); 3723 trigger.bind( $_posts.get() ); 3724 } 3725 3726 $( document.body ).trigger( 'konte_flex_posts_loaded', [$_posts] ); 3727 } ); 3728 } ); 3729 3730 if ( typeof ScrollTrigger !== undefined ) { 3731 $posts.children().attr( 'data-scroll', '' ).addClass( 'animated' ); 3732 3733 var trigger = new ScrollTrigger( { 3734 toggle: { 3735 visible: 'konteFadeInUp', 3736 hidden : '' 3737 }, 3738 offset: { 3739 x: 0, 3740 y: -20 3741 }, 3742 once : true 3743 }, document.body, window ); 3744 } 3745 3746 /** 3747 * Init flex posts masonry 3748 */ 3749 function initFlexPostsMasonry() { 3750 if ( $window.width() >= 992 ) { 3751 if ( $posts.hasClass( 'masonry' ) ) { 3752 return; 3753 } 3754 3755 $posts.masonry( options ); 3756 3757 // Layout Masonry after each image loads. 3758 $posts.imagesLoaded().progress( function() { 3759 $posts.masonry( 'layout' ); 3760 } ); 3761 } else { 3762 if ( ! $posts.hasClass( 'masonry' ) ) { 3763 return; 3764 } 3765 3766 $posts.masonry( 'destroy' ); 3767 } 3768 } 3769 }; 3770 3771 /** 3772 * Scroll down arrow sticky. 3773 * This arrow appears on flex posts template and portfolio page. 3774 */ 3775 konte.stickyScrollDown = function() { 3776 var $window = $( window ), 3777 $arrow = $( '.sticky-scrolldown' ), 3778 waiting = false, 3779 endScrollHandle, 3780 offset = $( '#masthead' ).height(); 3781 3782 if ( !$arrow.length ) { 3783 return; 3784 } 3785 3786 $arrow.on( 'click', function() { 3787 $( 'html, body' ).animate( {scrollTop: $window.scrollTop() + $window.height()}, 800 ); 3788 } ); 3789 3790 toggleArrow(); 3791 3792 $window.on( 'scroll', function() { 3793 if ( waiting ) { 3794 return; 3795 } 3796 3797 if ( $window.width() < 1440 ) { 3798 return; 3799 } 3800 3801 waiting = true; 3802 3803 // clear previous scheduled endScrollHandle 3804 clearTimeout( endScrollHandle ); 3805 3806 toggleArrow(); 3807 3808 setTimeout( function() { 3809 waiting = false; 3810 }, 100 ); 3811 3812 // schedule an extra execution of toggleArrow() after 200ms 3813 // in case the scrolling stops in next 100ms. 3814 endScrollHandle = setTimeout( function() { 3815 waiting = false; 3816 toggleArrow(); 3817 }, 200 ); 3818 } ); 3819 3820 /** 3821 * Toggle social icons on footer. 3822 */ 3823 function toggleArrow() { 3824 if ( $window.scrollTop() >= offset ) { 3825 $arrow.fadeOut(); 3826 } else { 3827 $arrow.fadeIn(); 3828 } 3829 } 3830 }; 3831 3832 /** 3833 * Sticky social icon on page template Flex Posts. 3834 */ 3835 konte.stickySocials = function() { 3836 var $footer = $( '#colophon' ), 3837 $socials = $( '#sticky-socials' ), 3838 $window = $( window ), 3839 waiting = false, 3840 endScrollHandle; 3841 3842 if ( !$socials.length ) { 3843 return; 3844 } 3845 3846 toggleSocials(); 3847 3848 $window.on( 'scroll', function() { 3849 if ( waiting ) { 3850 return; 3851 } 3852 3853 if ( $window.width() < 1440 ) { 3854 return; 3855 } 3856 3857 waiting = true; 3858 3859 // clear previous scheduled endScrollHandle 3860 clearTimeout( endScrollHandle ); 3861 3862 toggleSocials(); 3863 3864 setTimeout( function() { 3865 waiting = false; 3866 }, 100 ); 3867 3868 // schedule an extra execution of toggleSocials() after 200ms 3869 // in case the scrolling stops in next 100ms. 3870 endScrollHandle = setTimeout( function() { 3871 waiting = false;
3872 toggleSocials(); 3873 }, 200 ); 3874 } ); 3875 3876 /** 3877 * Toggle social icons on footer. 3878 */ 3879 function toggleSocials() { 3880 if ( $window.scrollTop() + $window.height() >= $footer.offset().top - 200 ) { 3881 $socials.fadeOut(); 3882 } else { 3883 $socials.fadeIn(); 3884 } 3885 } 3886 }; 3887 3888 /** 3889 * Open share links in a new popup window 3890 */ 3891 konte.openShareLinks = function() { 3892 var $window = $( window ); 3893 3894 $( document.body ).on( 'click', '.social-share-link', function( event ) { 3895 if ( $window.width() <= 1024 ) { 3896 return; 3897 } 3898 3899 event.preventDefault(); 3900 3901 popupShare( $( this ).attr( 'href' ), '', 500, 550 ); 3902 } ); 3903 3904 /** 3905 * Open new window at middle of screen 3906 */ 3907 function popupShare( url, title, w, h ) { 3908 // Fixes dual-screen position 3909 var dualScreenLeft = window.screenLeft != undefined ? window.screenLeft : window.screenX, 3910 dualScreenTop = window.screenTop != undefined ? window.screenTop : window.screenY, 3911 3912 width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width, 3913 height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height, 3914 3915 systemZoom = width / window.screen.availWidth, 3916 left = (width - w) / 2 / systemZoom + dualScreenLeft, 3917 top = (height - h) / 2 / systemZoom + dualScreenTop; 3918 3919 var newWindow = window.open(url, title, 'scrollbars=yes, width=' + w / systemZoom + ', height=' + h / systemZoom + ', top=' + top + ', left=' + left); 3920
3921 // Puts focus on the newWindow 3922 if ( window.focus ) { 3923 newWindow.focus(); 3924 } 3925 } 3926 }; 3927 3928 /** 3929 * Fix full width row of WPB with vertical header. 3930 */ 3931 konte.fixVCRowsWithVerticalHeader = function() { 3932 if ( !$( document.body ).hasClass( 'header-vertical' ) ) { 3933 return; 3934 } 3935 3936 $( document ).on( 'vc-full-width-row-single', function( event, data ) { 3937 var width = konte.getVerticalHeaderWidth(); 3938 3939 data.el.css( { 3940 width: data.width - width, 3941 left : data.offset + width 3942 } ); 3943 3944 if ( konte.data.rtl ) { 3945 data.el.css( { 3946 right: data.offset + width 3947 } ); 3948 } else { 3949 data.el.css( { 3950 left: data.offset + width 3951 } ); 3952 } 3953 } ); 3954 }; 3955 3956 /** 3957 * Get the width of vertical header. 3958 */ 3959 konte.getVerticalHeaderWidth = function() { 3960 var width = 0; 3961 3962 if ( $( document.body ).hasClass( 'header-vertical' ) ) { 3963 var $header = $( '#masthead' ); 3964 3965 if ( $header.hasClass( 'header-v10' ) ) { 3966 $header = $header.find( '.header-main .header-left-items' ); 3967 } 3968 3969 if ( $header.is( ':visible' ) ) { 3970 width = $header.outerWidth(); 3971 } 3972 3973 return width; 3974 } 3975 3976 return width; 3977 }; 3978 3979 /** 3980 * Responsive video 3981 */ 3982 konte.responsiveVideos = function() { 3983 if ( !$.fn.fitVids ) { 3984 return; 3985 } 3986 3987 $( '.entry-content' ).fitVids(); 3988 }; 3989 3990 /** 3991 * Open popup. 3992 */ 3993 konte.popup = function() { 3994 if ( ! konte.data.popup ) { 3995 return; 3996 } 3997 3998 var days = parseInt( konte.data.popup_frequency ), 3999 delay = parseInt( konte.data.popup_visible_delay ); 4000 4001 if ( days > 0 && document.cookie.match( /^(.*;)?\s*konte_popup\s*=\s*[^;]+(.*)?$/ ) ) { 4002 return; 4003 } 4004 4005 delay = Math.max( delay, 0 ); 4006 delay = 'delay' === konte.data.popup_visible ? delay : 0; 4007 4008 $( window ).on( 'load', function() { 4009 setTimeout( function() { 4010 konte.openModal( '#popup-modal' ); 4011 }, delay * 1000 ); 4012 } ); 4013 4014 $( document.body ).on( 'konte_modal_closed', function( event, modal ) { 4015 if ( !$( modal ).closest( '.modal' ).hasClass( 'popup-modal' ) ) { 4016 return; 4017 } 4018 4019 var date = new Date(), 4020 value = date.getTime(); 4021 4022 date.setTime( date.getTime() + (days * 24 * 60 * 60 * 1000) ); 4023 4024 document.cookie = 'konte_popup=' + value + ';expires=' + date.toGMTString() + ';path=/'; 4025 } ); 4026 4027 // Support close popup with a helper class. 4028 $( document.body ).on( 'click', '.popup-modal .close-popup-trigger', function() { 4029 konte.closeModal( '.popup-modal' ); 4030 } ); 4031 }; 4032 4033 /** 4034 * Preloader. 4035 */ 4036 konte.preloader = function() { 4037 var $preloader = $( '#preloader' ); 4038 4039 if ( ! $preloader.length ) { 4040 return; 4041 } 4042 4043 var ignorePreloader = false;
4044 4045 $( document.body ).on( 'click', 'a[href^=mailto], a[href^=tel]', function() { 4046 ignorePreloader = true; 4047 } ); 4048 4049 $( window ).on( 'beforeunload', function( event ) { 4050 if ( ! ignorePreloader ) { 4051 $preloader.fadeIn(); 4052 } 4053 4054 ignorePreloader = false; 4055 } ); 4056 4057 setTimeout( function() { 4058 $preloader.fadeOut(); 4059 }, 200 ); 4060 4061 window.onpageshow = function( event ) { 4062 if ( event.persisted ) { 4063 setTimeout( function() { 4064 $preloader.fadeOut(); 4065 }, 200 ); 4066 } 4067 }; 4068 }; 4069 4070 /** 4071 * Handle mobile menu toggle. 4072 */ 4073 konte.mobileMenu = function() { 4074 var $mobileMenu = $( '#mobile-menu' ); 4075 4076 $mobileMenu.find( '' ) 4077 4078 // Add class 'open' to current menu item. 4079 $mobileMenu.find( '.menu > .menu-item-has-children, .menu > li > ul > .menu-item-has-children' ).filter( function() { 4080 return $( this ).hasClass( 'current-menu-item' ) || $( this ).hasClass( 'current-menu-ancestor' ); 4081 } ).addClass( 'open' ); 4082 4083 // Toggle submenu. 4084 $mobileMenu.on( 'click', '.menu-item-has-children > a', function( event ) { 4085 var $li = $( this ).parent(); 4086 4087 if ( $li.hasClass( 'open' ) && $li.hasClass( 'clicked' ) && '#' !== $( this ).attr( 'href' ) ) { 4088 return true; 4089 } 4090 4091 event.stopPropagation(); 4092 event.preventDefault(); 4093 4094 $li.addClass( 'clicked' ); 4095 4096 $li.toggleClass( 'open' ).children( 'ul' ).slideToggle(); 4097 $li.siblings( '.open' ).removeClass( 'open clicked' ).children( 'ul' ).slideUp(); 4098 } ).on( 'click', '.menu-item-has-children > .toggle', function( event ) { 4099 event.stopPropagation(); 4100 event.preventDefault(); 4101 4102 var $li = $( this ).parent(); 4103 4104 $li.toggleClass( 'open' ).children( 'ul' ).slideToggle(); 4105 $li.siblings( '.open' ).removeClass( 'open' ).children( 'ul' ).slideUp(); 4106 } ); 4107 4108 // Close other panels. 4109 $mobileMenu.on( 'click', '[data-toggle="off-canvas"], [data-toggle="modal"]', function() { 4110 if ( 'mobile-menu' !== $( this ).data( 'target' ) ) { 4111 konte.closeModal(); 4112 konte.closeOffCanvas(); 4113 } 4114 } ); 4115 }; 4116 4117 /** 4118 * Responsive for single product v3. 4119 */ 4120 konte.responsiveProductV3 = function() { 4121 var $window = $( window ), 4122 $product = $( '.woocommerce div.product.layout-v3' ); 4123 4124 if ( !$product.length ) { 4125 return; 4126 } 4127 4128 updateLayout(); 4129 4130 $window.on( 'resize', updateLayout ); 4131 4132 // Change tabs position 4133 function updateLayout() { 4134 if ( $window.width() < 1200 ) { 4135 $( '.woocommerce-product-cart form.cart', $product ).insertBefore( $( '.summary > .product_meta', $product ) ); 4136 } else { 4137 $( '.summary > form.cart', $product ).appendTo( $( '.woocommerce-product-cart', $product ) ); 4138 } 4139 } 4140 } 4141 4142 /** 4143 * Portfolio mansonry 4144 */ 4145 konte.portfolioMasonry = function() { 4146 var $portfolio = $( '.portfolio-projects--masonry' ); 4147 4148 if ( ! $portfolio.length || ! $.fn.masonry ) { 4149 return; 4150 } 4151 4152 // Init masonry layout 4153 var $window = $( window ), 4154 options = { 4155 itemSelector: '.portfolio', 4156 percentPosition: true, 4157 transitionDuration: 0, 4158 isRTL: !! konte.data.rtl 4159 }; 4160 4161 initPortfolioMasonry(); 4162 4163 $window.on( 'resize', initPortfolioMasonry ); 4164 4165 // Layout items when using ajax load. 4166 $( document.body ).on( 'konte_posts_loaded', function( event, $posts, append ) { 4167 if ( $window.width() < 767 ) { 4168 return; 4169 } 4170 4171 if ( append ) { 4172 $portfolio.masonry( 'appended', $posts ); 4173 } else { 4174 $portfolio.masonry( 'reloadItems' ); 4175 } 4176 4177 setTimeout( function() { 4178 $portfolio.masonry( 'layout' ); 4179 }, $posts.length * 50 + 50 ); 4180 4181 $posts.imagesLoaded().progress( function() { 4182 $portfolio.masonry( 'layout' ); 4183 } ); 4184 } ); 4185 4186 // Support Jetpack lazy loads. 4187 var layoutHandle; 4188 4189 $portfolio.on( 'jetpack-lazy-loaded-image', 'img', function() { 4190 if ( ! $portfolio.hasClass( 'masonry' ) ) { 4191 initPortfolioMasonry(); 4192 } 4193 4194 clearTimeout( layoutHandle ); 4195 4196 layoutHandle = setTimeout( function() { 4197 $portfolio.masonry( 'layout' ); 4198 }, 100 ); 4199 } ); 4200 4201 /** 4202 * Init portfolio masonry 4203 */ 4204 function initPortfolioMasonry() { 4205 if ( $window.width() >= 767 ) { 4206 if ( $portfolio.hasClass( 'masonry' ) ) { 4207 $portfolio.masonry( 'layout' ); 4208 } 4209 4210 $portfolio.masonry( options ); 4211 4212 // Layout Masonry after each image loads. 4213 $portfolio.imagesLoaded().progress( function() { 4214 $portfolio.masonry( 'layout' ); 4215 } ); 4216 } else { 4217 if ( ! $portfolio.hasClass( 'masonry' ) ) { 4218 return; 4219 } 4220 4221 $portfolio.masonry( 'destroy' ); 4222 } 4223 } 4224 }; 4225 4226 /** 4227 * Ajax filter portfolio 4228 */ 4229 konte.portfolioFilter = function() { 4230 var $filter = $( '.portfolio-filter' ), 4231 $portfolio = $( '.portfolio-projects' ), 4232 $nav = $portfolio.siblings( '.navigation' ); 4233 4234 if ( ! $filter.length || ! $portfolio.length ) { 4235 return; 4236 } 4237 4238 $filter.on( 'click', 'a', function( event ) { 4239 event.preventDefault(); 4240 4241 var $link = $( this ), 4242 $active = $link.siblings( '.active' ), 4243 url = $link.attr( 'href' ); 4244 4245 if ( $link.hasClass( 'active' ) ) { 4246 return; 4247 } 4248 4249 $link.addClass( 'active' ); 4250 $active.removeClass( 'active' ); 4251 4252 $portfolio.fadeIn().addClass( 'loading' ).append( '<div class="loading-screen"><span class="spinner"></span></div>' ); 4253 4254 $.get( url, function( response ) { 4255 var $_portfolio = $( '.portfolio-projects', response ), 4256 $_projects = $( '.hentry', $_portfolio ), 4257 $_nav = $_portfolio.siblings( '.navigation' ); 4258 4259 $portfolio.html( '' ).removeClass( 'loading' ); 4260 4261 // If there is no project. 4262 if ( ! $_portfolio.length ) { 4263 $portfolio.fadeOut(); 4264 $nav.fadeOut(); 4265 4266 return; 4267 } 4268 4269 $_projects.each( function( index, project ) { 4270 $( project ).css( 'animation-delay', index * 100 + 'ms' ); 4271 } ); 4272 4273 $portfolio.append( $_projects ); 4274 4275 $_projects.addClass( 'animated konteFadeInUp' ); 4276 4277 if ( $_nav.length ) { 4278 if ( $nav.length ) { 4279 $nav.html( $_nav.html() ).fadeIn(); 4280 } else { 4281 $portfolio.after( $_nav ); 4282 $nav = $_nav; 4283 } 4284 } else { 4285 $nav.fadeOut(); 4286 } 4287 4288 window.history.pushState( null, '', url ); 4289 $( document.body ).trigger( 'konte_posts_loaded', [$_projects, false] ); 4290 } ).fail( function() { 4291 $link.removeClass( 'active' ); 4292 $active.addClass( 'active' ); 4293 4294 $portfolio.children( '.loading-screen' ).remove(); 4295 $portfolio.removeClass( 'loading' ); 4296 } ); 4297 } ); 4298 }; 4299 4300 /** 4301 * Back to top icon 4302 */ 4303 konte.backToTop = function () { 4304 var $button = $( '#gotop' ), 4305 $window = $( window ), 4306 waiting = false, 4307 endScrollHandle; 4308 4309 $button.on( 'click', function ( e ) { 4310 e.preventDefault(); 4311 4312 $( 'html, body' ).animate( {scrollTop: 0}, 800 ); 4313 } ); 4314 4315 if ( $button.length ) { 4316 toggleButton(); 4317 4318 $window.on( 'scroll', function() { 4319 if ( waiting ) { 4320 return; 4321 } 4322 4323 waiting = true; 4324 4325 // clear previous scheduled endScrollHandle 4326 clearTimeout( endScrollHandle ); 4327 4328 toggleButton(); 4329 4330 setTimeout( function() { 4331 waiting = false;
4332 }, 100 ); 4333 4334 // schedule an extra execution of toggleArrow() after 200ms 4335 // in case the scrolling stops in next 100ms. 4336 endScrollHandle = setTimeout( function() { 4337 waiting = false; 4338 toggleButton(); 4339 }, 200 ); 4340 } ); 4341 } 4342 4343 /** 4344 * Toggle the button when scrolling 4345 */ 4346 function toggleButton() { 4347 if ( $window.scrollTop() < $window.height() * 1.5 ) { 4348 $button.fadeOut(); 4349 } else { 4350 $button.fadeIn(); 4351 } 4352 } 4353 }; 4354 4355 /** 4356 * Support lazy load events 4357 */ 4358 konte.lazyLoadImages = function() { 4359 var lazyLoadImagesEvent; 4360 4361 $( document.body ).on( 'post-load konte_posts_loaded konte_products_loaded konte_products_quick_search_request_success konte_flex_posts_loaded konte_product_quickview_loaded konte_lazy_load_images', function() { 4362 try { 4363 lazyLoadImagesEvent = new Event( 'jetpack-lazy-images-load', { 4364 bubbles: true, 4365 cancelable: true 4366 } ); 4367 } catch ( e ) { 4368 lazyLoadImagesEvent = document.createEvent( 'Event' ) 4369 lazyLoadImagesEvent.initEvent( 'jetpack-lazy-images-load', true, true ); 4370 } 4371 4372 setTimeout( function() { 4373 document.body.dispatchEvent( lazyLoadImagesEvent ); 4374 }, 100 ); 4375 } ); 4376 }; 4377 4378 /** 4379 * Update the height of product gallery with Jetpack lazy loads. 4380 */ 4381 konte.supportJetpackLazyLoadImagesOnProductGallery = function() { 4382 $( 'div.product' ).each( function() { 4383 var $product = $( this ); 4384 4385 if ( $product.hasClass( 'layout-v2' ) || $product.hasClass( 'layout-v5' ) ) { 4386 return; 4387 } 4388 4389 // Trigger resize event after main image loads to correct the gallery size. 4390 $( '.woocommerce-product-gallery', $product ).one( 'jetpack-lazy-loaded-image load', '.wp-post-image', function() { 4391 var $image = $( this ); 4392 4393 if ( $image ) { 4394 setTimeout( function() { 4395 var setHeight = $image.closest( '.woocommerce-product-gallery__image' ).height(); 4396 var $viewport = $image.closest( '.flex-viewport' ); 4397 4398 if ( ! $viewport.length ) { 4399 $viewport = $image.closest( '.woocommerce-product-gallery' ); 4400 } 4401 4402 if ( setHeight && $viewport.length ) { 4403 $viewport.height( setHeight ); 4404 } 4405 }, 100 ); 4406 } 4407 } ); 4408 } ); 4409 4410 } 4411 4412 /** 4413 * Support mega menu tabs. 4414 */ 4415 konte.mainMenuTabs = function() { 4416 $( '.main-navigation' ).on( 'click', '.menu-item--tab, .menu-item--tab a', function( event ) { 4417 event.preventDefault(); 4418 event.stopPropagation(); 4419 4420 var $tab = $( this ).closest( '.menu-item--tab' ); 4421 4422 if ( $tab.hasClass( 'active' ) ) { 4423 return; 4424 } 4425 4426 $tab.addClass( 'active' ).attr( 'aria-selected', 'true' ).siblings().removeClass( 'active' ).attr( 'aria-selected', 'false' ); 4427 4428 $tab.closest( '.menu-item-mega' ).find( '#' + $tab.attr( 'aria-controls' ) ).addClass( 'active' ).siblings().removeClass( 'active' ); 4429 } ); 4430 } 4431 4432 /** 4433 * Fire when document ready 4434 */ 4435 $( function() { 4436 konte.init(); 4437 } ); 4438})( 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.