1 2 3jQuery( function( $ ) { 4 "use strict"; 5 6 if ( window?.wc?.blocksCheckout ) { 7 const { registerCheckoutFilters } = wc.blocksCheckout; 8 const { sprintf, __ } = wp.i18n; 9 10 const modifyItemName = ( defaultValue, extensions, args ) => { 11 if ( ! extensions?.iconic_sales_booster?.added_via_at_checkout_bump ) { 12 return defaultValue; 13 } 14 15 return sprintf( __( '(Offer) %s', 'kadence-shop-kit' ), defaultValue ); 16 }; 17 18 registerCheckoutFilters( 'iconic-sales-booster', { 19 itemName: modifyItemName, 20 } ); 21 } 22 23 $( document ).on( 'change', '[data-iconic-wsb-checkout-bump-trigger]', function() { 24 if ( ! $( this ).parents('[data-block-name="woocommerce/checkout"]').length ) { 25 return; 26 } 27 28 if (! wc?.blocksCheckout?.extensionCartUpdate) { 29 return; 30 } 31 32 const $fields = $( this ).siblings('input[type="hidden"]'); 33 34 const data = { 35 'bump-type': 'at-checkout', 36 'iconic-wsb-bump-id': $fields.filter('[name="iconic-wsb-bump-id"]').val(), 37 'iconic-wsb-checkout-bump-action': $( this ).prop( 'checked' ) ? 'add' : 'remove', 38 'iconic-wsb-checkout-product-id': $fields.filter('[name="iconic-wsb-checkout-product-id"]').val(), 39 'iconic-wsb-checkout-variation-id': $fields.filter('[name="iconic-wsb-checkout-variation-id"]').val(), 40 'iconic-wsb-checkout-variation-data': $fields.filter('[name="iconic-wsb-checkout-variation-data"]').val(), 41 } 42 43 $( '.wp-block-woocommerce-checkout' ).block( { 44 message: null, 45 overlayCSS: { 46 background: '#fff', 47 opacity: 0.6 48 } 49 } ); 50 51 wc.blocksCheckout.extensionCartUpdate( { 52 namespace: 'iconic-sales-booster', 53 data 54 } ) 55 .then(() => { 56 checkoutBumpVariableProduct.handleSwatchesLabel(); 57 checkoutBumpVariableProduct.handleOverlay(); 58 checkoutBumpVariableProduct.handleCheckbox(); 59 60 $( '.wp-block-woocommerce-checkout' ).unblock(); 61 }); 62 63 }); 64 65 wp.data.subscribe( 66 () => { 67 if ( ! wp.data.select('wc/store/checkout')?.isBeforeProcessing() ) { 68 return; 69 } 70 71 if ( ! $('[data-iconic-wsb-acb-modal]').length ) { 72 return; 73 } 74 75 wp.data.dispatch('wc/store/checkout').__internalSetIdle(); 76 77 $.magnificPopup.open({items: { 78 type: 'inline', 79 src: $('[data-iconic-wsb-acb-modal]') 80 }}) 81 82 }, 83 'wc/store/checkout' 84 ); 85 86 $( '[data-iconic-wsb-acb-add-to-cart-button]' ).on( 87 'click', 88 function( event ) { 89 if ( ! window?.wc?.blocksCheckout ) { 90 return; 91 } 92 93 event.preventDefault(); 94 95 const $fields = $( '.iconic-wsb-acb-fields input[type="hidden"]' ); 96 97 const data = { 98 'bump-type': 'after-checkout', 99 'iconic-wsb-acb-action': 'add', 100 'iconic-wsb-acb-bump-id': $fields.filter('[name="iconic-wsb-acb-bump-id"]').val(), 101 'iconic-wsb-acb-variation-id': $fields.filter('[name="iconic-wsb-acb-variation-id"]').val(), 102 'iconic-wsb-acb-variation-data': $fields.filter('[name="iconic-wsb-acb-variation-data"]').val(), 103 } 104 105 wc.blocksCheckout 106 .extensionCartUpdate( 107 { 108 namespace: 'iconic-sales-booster', 109 data 110 } 111 ) 112 .then(() => { 113 $.magnificPopup.close(); 114 $('[data-iconic-wsb-acb-modal]').remove(); 115 wp.data.dispatch('wc/store/checkout').__internalSetBeforeProcessing(); 116 }); 117 } 118 ); 119 120 $( '[data-iconic-wsb-acb-close-button]' ).on( 121 'click', 122 function( event ) { 123 if ( ! window?.wc?.blocksCheckout ) { 124 return; 125 } 126 127 event.preventDefault(); 128 $.magnificPopup.close(); 129 $('[data-iconic-wsb-acb-modal]').remove(); 130 wp.data.dispatch('wc/store/checkout')?.__internalSetBeforeProcessing(); 131 } 132 ); 133 134 /** 135 * Trigger add offered product to order 136 */ 137 $( document ).on( 'change', '[data-iconic-wsb-checkout-bump-trigger]', function() { 138 var actionTypeInput = $( '[name=iconic-wsb-checkout-bump-action]' ); 139 var bumpInForm = true; 140 var bumpWrapper = $(this).closest( '.iconic-wsb-checkout-bump' ); 141 142 // If the hook is outside of the form, make sure it still works. 143 if ( ! $(this).closest('form.checkout').length ) { 144 bumpInForm = false; 145 } 146 147 if ( ! $( this ).prop( 'checked' ) ) { 148 actionTypeInput.val( 'remove' ); 149 } else { 150 actionTypeInput.val( 'add' ); 151 152 if ( ! bumpInForm ) {
153 bumpWrapper.find( 'input[name="iconic-wsb-bump-id"]' ).clone().appendTo( 'form.checkout' ); 154 bumpWrapper.find( 'input[name="iconic-wsb-checkout-bump-action"]' ).clone().appendTo( 'form.checkout' ); 155 bumpWrapper.find( 'input[name="iconic-wsb-checkout-product-id"]' ).clone().appendTo( 'form.checkout' ); 156 bumpWrapper.find( 'input[name="iconic-wsb-checkout-variation-id"]' ).clone().appendTo( 'form.checkout' ); 157 bumpWrapper.find( 'input[name="iconic-wsb-checkout-variation-data"]' ).clone().appendTo( 'form.checkout' ); 158 } 159 } 160 161 $( 'body' ).trigger( 'update_checkout' ); 162 163 // If we are removing, we need to wait for the form to finish posting. 164 if ( ! $( this ).prop( 'checked' ) && ! bumpInForm ) { 165 setTimeout( function() { 166 $( 'form.checkout input[name="iconic-wsb-bump-id"]' ).remove(); 167 $( 'form.checkout input[name="iconic-wsb-checkout-bump-action"]' ).remove(); 168 $( 'form.checkout input[name="iconic-wsb-checkout-product-id"]' ).remove(); 169 $( 'form.checkout input[name="iconic-wsb-checkout-variation-id"]' ).remove(); 170 $( 'form.checkout input[name="iconic-wsb-checkout-variation-data"]' ).remove(); 171 }, 500 ); 172 } 173 } ); 174 175 /** 176 * After checkout bump 177 * @constructor 178 */ 179 var AfterCheckoutBump = function() { 180 this.isBumpShowed = false; 181 this.isFormSubmited = false; 182 183 this.init = function() { 184 this.$checkoutForm = $( 'form.checkout' ); 185 this.container = '[data-iconic-wsb-acb-modal]'; 186 this.$bumpModal = $( this.container ); 187 this.$addToCartButton = $( '[data-iconic-wsb-acb-add-to-cart-button]' ); 188 this.$closeButton = $( '[data-iconic-wsb-acb-close-button]' ); 189 this.actionInputSelector = '[name=iconic-wsb-acb-action]'; 190 this.$form = $( '.iconic-wsb-after-checkout-bump-form' ); 191 this.variation_dropdown = ".iconic-wsb-checkout-modal__select"; 192 this.variationHandler = new IconicVariationHandler(this.$form, this.container, this.onVariationFound.bind( this ) , this.onVariationNotFound.bind( this ) ); 193 var self = this; 194 195 // If suitable order bump exists 196 if ( this.$bumpModal.length > 0 ) { 197 198 this.$checkoutForm.on( 'checkout_place_order.orderBump', this.openModal.bind( this ) ); 199 this.$closeButton.on( 'click', this.close.bind( this ) ); 200 201 this.$addToCartButton.on( 'click', (function( e ) { 202 e.preventDefault(); 203 this.addToCartBump(); 204 }).bind( this ) ); 205 206 $(this.container).on("change", this.variation_dropdown, this.variationHandler.getVariation.bind( this.variationHandler ) ); 207 $( '.wsb_select_readonly option:not(:selected)' ).prop( 'disabled', true ); 208 209 } 210 211 //to make compatible with WooCommerce Attribute Swatches plugin 212 this.$form.addClass("variations_form"); 213 this.$form.data("product_variations", false); 214 }; 215 216 this.close = function() { 217 $.magnificPopup.close(); 218 this.$checkoutForm.submit(); 219 }; 220 221 this.addToCartBump = function() { 222 $( this.actionInputSelector ).val( 'add' ); 223 224 this.$checkoutForm.trigger( 'update_checkout' ); 225 226 this.$checkoutForm.off( 'checkout_place_order.orderBump', this.openModal.bind( this ) ); 227 228 $( document ).ajaxComplete( ( function ( event, xhr, settings ) { 229 230 // ensure this is the update_order_review AJAX request. 231 if ( ! settings.url.includes( "update_order_review" ) ) { 232 return; 233 } 234 235 if ( this.isFormSubmited === true ) { 236 return; 237 } 238 239 this.isFormSubmited = true; 240 241 this.$checkoutForm.submit(); 242 }).bind( this ) ); 243 244 $.magnificPopup.close(); 245 }; 246 247 this.openModal = function() { 248 // Check if we have the modal element. 249 if ( ! $( this.container ).length ) { 250 return; 251 } 252 253 if ( this.isBumpShowed === true ) { 254 return true; 255 } 256 257 this.variationHandler.getVariation(); 258 259 var modalConfig = { 260 items: { 261 src: this.$bumpModal, 262 type: 'inline', 263 } 264 }; 265 266 modalConfig = Object.assign( 267 modalConfig, 268 Object( iconic_wsb_frontend_vars && iconic_wsb_frontend_vars.modal_options ) 269 ); 270 271 $.magnificPopup.open(modalConfig); 272 273 this.isBumpShowed = true; 274 275 return false; 276 }; 277 278 this.onVariationFound = function( variation ) { 279 this.$addToCartButton.attr( "disabled", false );
280 this.$form.find(".iconic-wsb-checkout-modal-unavailable_msg").hide(); 281 this.$form.find(".iconic-wsb-modal-product-offer__price").html( variation.price_html ); 282 $("[name='iconic-wsb-acb-variation-id']").val( variation.variation_id ); 283 }; 284 285 this.onVariationNotFound = function() { 286 this.$addToCartButton.attr( "disabled", true ); 287 this.$form.find( ".iconic-wsb-checkout-modal-unavailable_msg" ).slideDown( 200 ); 288 this.$form.find(".iconic-wsb-modal-product-offer__price").html(""); 289 $("[name='iconic-wsb-acb-variation-id']").val( "" ); 290 }; 291 }; 292 293 var CheckoutBumpVariableProduct = function() { 294 295 this.allVariationSelectedFlag = null; 296 this.$attributeFields = null; 297 this.$woocommerceWrapper = $( '.page.woocommerce-checkout, [data-block-name="woocommerce/checkout"]' ); 298 this.container = ".iconic-wsb-checkout-bump"; 299 this.variation_dropdown = ".iconic-wsb-checkout-bump__select"; 300 301 /** 302 * Initialize 303 */ 304 this.init = function () { 305 var self = this; 306 self.variationHandler = new IconicVariationHandler(self.$woocommerceWrapper, this.container, this.onVariationFound.bind( self ), this.onVariationNotFound.bind( self ) ); 307 308 $(self.$woocommerceWrapper).on("change", this.variation_dropdown, this.variationHandler.getVariation.bind( this.variationHandler ) ); 309 $(self.$woocommerceWrapper).on("change", this.variation_dropdown, this.handleCheckbox.bind(this) ); 310 311 self.product_type = self.$woocommerceWrapper.find( ".iconic-wsb-checkout-bump" ).data( "product_type" ); 312 313 if( self.product_type === "variable" ) { 314 315 if ( self.$woocommerceWrapper.find( ".iconic-wsb-checkout-bump__select" ).length ) { 316 self.$woocommerceWrapper.find( ".iconic-wsb-checkout-bump__header-checkbox" ).attr( "disabled", !self.variationHandler.checkAllSelects.bind( self.variationHandler ) ); 317 } 318 319 self.handleSwatchesLabel(); 320 self.handleOverlay(); 321 self.handleCheckbox(); 322 } 323 324 $( document.body ).on( 'updated_checkout', function() { 325 326 self.product_type = self.$woocommerceWrapper.find( ".iconic-wsb-checkout-bump" ).data( "product_type" ); 327 328 if( self.product_type === "variable" ) { 329 330 if ( self.$woocommerceWrapper.find( "[name=iconic-wsb-checkout-variation-id]" ).length && $( "[name=iconic-wsb-checkout-variation-id]" ).val() === '' ) { 331 self.variationHandler.getVariation( false ); //need to run getVariation after updated_checkout has been triggered 332 } 333 334 if ( self.$woocommerceWrapper.find( ".iconic-wsb-checkout-bump__select" ).length ) { 335 self.$woocommerceWrapper.find( ".iconic-wsb-checkout-bump__header-checkbox" ).attr( "disabled", !self.variationHandler.checkAllSelects.bind( self.variationHandler ) ); 336 } 337 338 self.handleSwatchesLabel(); 339 self.handleOverlay(); 340 self.handleCheckbox(); 341 } 342 343 $('.wsb_select_readonly option:not(:selected)').prop('disabled', true); 344 }); 345 346 //to make compatible with WooCommerce Attribute Swatches plugin 347 this.$woocommerceWrapper.addClass( "variations_form" ); 348 this.$woocommerceWrapper.data( "product_variations" , false ); 349 350 // handle order bump outside of form.checkout 351 if ( ! $('form.checkout .iconic-wsb-checkout-bump').length ) { 352 if ( $('.iconic-wsb-checkout-bump__header-checkbox').prop('checked') ) { 353 this.$woocommerceWrapper.find( 'input[name="iconic-wsb-bump-id"]' ).clone().appendTo( 'form.checkout' ); 354 this.$woocommerceWrapper.find( 'input[name="iconic-wsb-checkout-bump-action"]' ).clone().appendTo( 'form.checkout' ); 355 this.$woocommerceWrapper.find( 'input[name="iconic-wsb-checkout-product-id"]' ).clone().appendTo( 'form.checkout' ); 356 this.$woocommerceWrapper.find( 'input[name="iconic-wsb-checkout-variation-id"]' ).clone().appendTo( 'form.checkout' ); 357 this.$woocommerceWrapper.find( 'input[name="iconic-wsb-checkout-variation-data"]' ).clone().appendTo( 'form.checkout' ); 358 } 359 } 360 361 setTimeout(() => { 362 /** 363 * Set the value of the `data-value` attribute to the `value` attribute. 364 * 365 * When using the Checkou block, the `value` attribute is removed so 366 * we re-add by copying the data from `data-value`. 367 */ 368 $('.iconic-wsb-variation__select.iconic-wsb-checkout-bump__select option').each(function() { 369 $( this ).attr( 'value', $( this ).attr('data-value') || '' ); 370 }); 371 }, 700); 372 }; 373 374 375 /** 376 * 1)Hides unavailable variation message 2) Enables the 'Add to cart' checkbox 377 */ 378 this.onVariationFound = function (variation) { 379 this.$woocommerceWrapper.find("[data-iconic-wsb-checkout-bump-trigger]").attr("disabled", false);
380 this.$woocommerceWrapper.find(".iconic-wsb-checkou-bump_unavailable_msg").hide(); 381 }; 382 383 /** 384 * 1)Shows unavailable variation message 2) Disables the 'Add to cart' checkbox 385 */ 386 this.onVariationNotFound = function() { 387 this.$woocommerceWrapper.find("[data-iconic-wsb-checkout-bump-trigger]").attr("disabled", true); 388 this.$woocommerceWrapper.find(".iconic-wsb-checkou-bump_unavailable_msg").slideDown(200); 389 390 }; 391 392 /** 393 * Show/Hide overlay to prevent user from changing the variation after the product has been added to cart. 394 */ 395 this.handleOverlay = function() { 396 var isInCart = this.$woocommerceWrapper.find( "[data-iconic-wsb-checkout-bump-trigger]" ).prop( "checked" ); 397 if ( isInCart ) { 398 this.$woocommerceWrapper.find( ".iconic-wsb-checkout-bump" ).addClass( "iconic-wsb-checkout-bump__overlay_active" ); 399 this.$woocommerceWrapper.find( ".iconic-wsb-checkout-bump__overlay" ).show(); 400 } 401 else { 402 this.$woocommerceWrapper.find( ".iconic-wsb-checkout-bump" ).removeClass("iconic-wsb-checkout-bump__overlay_active"); 403 this.$woocommerceWrapper.find( ".iconic-wsb-checkout-bump__overlay" ).hide(); 404 } 405 }; 406 407 /** 408 * If Woocomerce Attributes Swatches plugin is enabled then makes sure that lables for attributes are visible 409 */ 410 this.handleSwatchesLabel = function() { 411 if( this.$woocommerceWrapper.find(".iconic-was-swatches").length ) { 412 this.$woocommerceWrapper.find(".iconic-wsb-variation__select").each(function () { 413 var val = jQuery(this).val(); 414 if ( val ) { 415 var $row = jQuery( this ).closest( "tr" ); 416 var html = $row.find( "td.label label .iconic-was-chosen-attribute" ).html(); 417 if ( html && html.trim() === "" ) { 418 var new_html = $row.find( ".iconic-was-swatch--selected" ).data( "attribute-value-name" ); 419 $row.find( "td.label label .iconic-was-chosen-attribute" ).html( new_html ); 420 } 421 } 422 }); 423 } 424 }; 425 426 /** 427 * Enable or disable 'data-iconic-wsb-checkout-bump-trigger' checkbox 428 */ 429 this.handleCheckbox = function() { 430 var $checkbox = this.$woocommerceWrapper.find("[data-iconic-wsb-checkout-bump-trigger]"); 431 //1) If: $checkbox is checked then user should be able to uncheck it, hence always enable it. Else: if any of the attributes are not selected, then disable $checkox 432 if ( $checkbox.prop("checked") ) { 433 $checkbox.attr( "disabled" , false ); 434 } 435 else { 436 this.$woocommerceWrapper.find( "[data-iconic-wsb-checkout-bump-trigger]" ).attr( "disabled", ! this.variationHandler.checkAllSelects() ); 437 } 438 }; 439 440 }; 441 442 var afterCheckoutBump = new AfterCheckoutBump(); 443 var checkoutBumpVariableProduct = new CheckoutBumpVariableProduct(); 444 445 /** 446 * Clear After Add to Cart fragments on Checkout page. 447 * 448 * @returns void 449 */ 450 function clear_after_add_to_cart_fragment_on_checkout_page() { 451 if ( ! iconic_wsb_frontend_vars?.is_checkout ) { 452 return; 453 } 454 455 const fragment_name = wc_cart_fragments_params?.fragment_name; 456 457 if ( ! fragment_name || 'string' !== typeof fragment_name ) { 458 return; 459 } 460 461 let fragments = sessionStorage.getItem( fragment_name ); 462 463 if ( ! fragments ) { 464 return; 465 } 466 467 fragments = JSON.parse( fragments ); 468 469 fragments['.iconic_wsb_after_add_to_cart_popup_placeholder'] = undefined; 470 471 sessionStorage.setItem( 472 wc_cart_fragments_params.fragment_name, 473 JSON.stringify( fragments ) 474 ); 475 } 476 477 $( document ).ready( function() { 478 checkoutBumpVariableProduct.init(); 479 afterCheckoutBump.init(); 480 481 clear_after_add_to_cart_fragment_on_checkout_page(); 482 483 if ( $( '[data-block-name="woocommerce/checkout"]' ).length ) { 484 return; 485 } 486 487 $( document ).on( 'updated_checkout', function( event, data ) { 488 if ( ! data.fragments || ! data.fragments['.iconic-wsb-modal'] ) { 489 return; 490 } 491 492 var refreshedAfterCheckoutBump = new AfterCheckoutBump(); 493 494 refreshedAfterCheckoutBump.init(); 495 }) 496 } ); 497 498} ); 499 500jQuery( function( $ ) { 501 "use strict"; 502 503 /** 504 * After add to cart bump 505 * @constructor 506 */ 507 var AfterAddToCartBump = function() { 508 this.init = function() { 509 this.$bumpModal = $( '[data-iconic-wsb-acc-modal-bump]' ); 510 this.$closeButton = $( '[data-iconic-wsb-close-aac-modal]' ); 511 this.$variation_wrap = jQuery( this.$bumpModal.selector + ' .single_variation_wrap' ); 512 513 // If order bump modal exists 514 if ( this.$bumpModal.length > 0 ) { 515 516 this.$closeButton.on( 'click', this.close.bind( this ) ); 517 this.$variation_wrap.on( 'show_variation', this.changeVariationImage ); 518 519 this.openModal(); 520 } 521 }; 522 523 this.changeVariationImage = function( event, variation ) { 524 if ( variation.image.thumb_src !== undefined ) { 525 var $image = $( this ).closest( '[data-iconic-wsb-acc-modal-bump-offer-product]' ).find( '[data-iconic-wsb-acc-modal-bamp-offer-image]' ).find( 'img' ); 526 $image.attr( 'srcset', '' ); 527 $image.attr( 'src', variation.image.thumb_src ); 528 } 529 }; 530 531 this.close = function() { 532 $.magnificPopup.close(); 533 $( '[data-iconic-wsb-acc-modal-bump]' ).remove(); 534 }; 535 536 this.openModal = function() { 537 var modalConfig = { 538 items: { 539 src: this.$bumpModal, 540 type: 'inline', 541 } 542 }; 543 544 modalConfig = Object.assign( 545 modalConfig, 546 Object( iconic_wsb_frontend_vars && iconic_wsb_frontend_vars.modal_options ) 547 ); 548 549 $.magnificPopup.open(modalConfig); 550 $('[data-iconic-wsb-acc-modal-bump]').fadeIn(100); 551 }; 552 }; 553 554 /** 555 * Handles all the events and actions for FBT module 556 */ 557 var FrequentlyBoughTogether = function() { 558 559 this.init = function() { 560 $( '.variations_form' ).on( 'found_variation', this.variationChangeHandle.bind( this ) ); 561 562 $( '.iconic-wsb-bump-product__select' ).change( function( e ) { 563 this.toggleButtonStatus.bind( this )(); 564 this.updateTotalPrice.bind( this )(); 565 this.fetchVariationPrice.bind( e.target )(); 566 this.updateAttributeData.bind( e.target )(); 567 }.bind( this ) ); 568 569 $( '.iconic-wsb-bump-product__checkbox' ).change( function() { 570 this.updateTotalPrice(); 571 this.toggleButtonStatus(); 572 }.bind( this ) ); 573 574 this.toggleButtonStatus(); 575 this.addToCartAjax(); 576 this.toggleProductImages(); 577 this.disableFormSubmitForDisabledButton(); 578 }; 579 580 /** 581 * Saves the attribute's data as JSON in hidden fields. Is called when FBT dropdown is changed. 582 */ 583 this.updateAttributeData = function() { 584 var product_id = $( this ).data( "product_id" ), 585 attributes = $( this ).find( "option:selected" ).data( "attributes" ), 586 attributes_str = typeof attributes === 'object' ? JSON.stringify( attributes ) : attributes; 587 588 $( "[name='iconic-wsb-bump-product_attributes-" + product_id + "']" ).val( attributes_str ); 589 }; 590 591 /** 592 * Disable "Add Selected to Cart" button when 593 * either variation is not selected for any variable products 594 * or no products are checked 595 */ 596 this.toggleButtonStatus = function() { 597 // Check if variations are selected 598 var variableSelectFlag = true; 599 $( '.iconic-wsb-product-bumps__list-item' ).each( function() { 600 if ( $( this ).find( ".iconic-wsb-bump-product__checkbox" ).prop( "checked" ) ) { 601 var $select = $( this ).find( ".iconic-wsb-bump-product__select" ); 602 if ( $select.length && ! $select.val() ) { 603 variableSelectFlag = false;
604 } 605 } 606 } ); 607 608 // check if atleast one product is checked 609 var selectedProductsCount = $( '.iconic-wsb-bump-product__checkbox:checked' ).length; 610 611 if ( variableSelectFlag && selectedProductsCount ) { 612 $( ".iconic-wsb-product-bumps__button" ).removeClass( "disabled" ); 613 } else { 614 $( ".iconic-wsb-product-bumps__button" ).addClass( "disabled" ); 615 } 616 }; 617 618 /** 619 * Disable form submit when the button is disabled ( variations needs to be selected ) 620 */ 621 this.disableFormSubmitForDisabledButton = function() { 622 623 /** 624 * As we have multiple submit buttons on the form. Here we are saving 625 * the button which was clicked. This data will be used in form submit event. 626 */ 627 $( 'form.cart' ).click( function( e ) { 628 $(this).data( 'clicked', $( e.target ) ); 629 }); 630 631 $( 'form.cart' ).submit( function( e ) { 632 // Only prevent form submit when clicked on "Add selected to cart" button. 633 if( $(this).data('clicked').is( "[data-bump-product-form-submit]" ) ) { 634 if( $(this).find( '.iconic-wsb-product-bumps__button' ).hasClass( "disabled" ) ) { 635 e.preventDefault(); 636 return false; 637 } 638 } 639 } ); 640 641 $( '.iconic-wsb-product-bumps__button' ).click( function() { 642 if( $( this ).hasClass( "disabled" ) ) { 643 alert( iconic_wsb_frontend_vars.i18n.disabled_add_to_cart ); 644 } 645 } ); 646 }; 647 648 /** 649 * Fetch price for the selected variation 650 */ 651 this.fetchVariationPrice = function() { 652 653 var data = { 654 action: 'iconic_wsb_get_variation_price', 655 variation_id: jQuery( this ).val(), 656 _ajax_nonce: iconic_wsb_frontend_vars.nonce 657 }; 658 659 var self = this; 660 661 const selector = $( '.variations_form' ).length ? '.variations_form' : '.iconic-wsb-product-bumps'; 662 663 $( selector ).block( { message: null, overlayCSS: { background: '#fff', opacity: 0.6 } } ); 664 665 jQuery.post( iconic_wsb_frontend_vars.ajax_url, data, function( response ) { 666 $( selector ).unblock(); 667 668 if ( !response.success ) { 669 return; 670 } 671 672 jQuery( self ).siblings( ".iconic-wsb-bump-product__price" ).html( response.data.variation_price_html ); 673 } ); 674 675 }; 676 677 /** 678 * Fetches and shows the total price of selected products 679 */ 680 this.updateTotalPrice = function() { 681 var product_ids = []; 682 683 //collect all product IDs in product_ids 684 $( ".iconic-wsb-product-bumps__list-item" ).each( function() { 685 if ( $( this ).find( ".iconic-wsb-bump-product__checkbox" ).is( ":checked" ) ) { 686 if ( $( this ).data( "product_type" ) === "variable" ) { 687 var parent_id = parseInt( $( this ).data( "product_id" ) ), 688 variation_value = parseInt( $( this ).find( ".iconic-wsb-bump-product__select" ).val() ), 689 id = variation_value > 0 ? variation_value : parent_id; 690 691 product_ids.push( id ); 692 } else { 693 product_ids.push( $( this ).data( "product_id" ) ); 694 } 695 } 696 } ); 697 698 var data = { 699 action: 'iconic_wsb_fbt_get_products_price', 700 product_ids: product_ids, 701 offer_product_id: $( "[name='iconic-wsb-fbt-this-product']" ).val(), 702 _ajax_nonce: iconic_wsb_frontend_vars.nonce 703 }; 704 705 var $variation_form = $( '.iconic-wsb-product-bumps' ).parents( '.variations_form' ); 706 707 $variation_form.block( { message: null, overlayCSS: { background: '#fff', opacity: 0.6 } } ); 708 709 $.post( iconic_wsb_frontend_vars.ajax_url, data, function( data ) { 710 $( ".iconic-wsb-product-bumps__total-price-amount" ).html( data.html ); 711 $variation_form.unblock(); 712 } ); 713 714 }; 715 716 /** 717 * Responsible for selecting the right option from the Dropdown under 718 * "Add Selected to Cart" when user changes attributes. 719 */ 720 this.variationChangeHandle = function( e, variation_data ) { 721 this.variationId = variation_data.variation_id; 722 this.currentProductId = $( "form.cart" ).data( "product_id" ); 723 if ( this.variationId && $( ".iconic-wsb-bump-product__select--" + this.currentProductId ).length ) { 724 var $select = $( ".iconic-wsb-bump-product__select--" + this.currentProductId ); 725 726 //gather all the Single product attributes in `currentProductAttributes` 727 var currentProductAttributes = {}; 728 $( "form.cart .variations select" ).each( function() { 729 currentProductAttributes[ $( this ).data( "attribute_name" ) ] = $( this ).find( "option:selected" ).text(); 730 } ); 731 732 //find the matching 'option in the dropdown' 733 var matchIndex = 0; 734 $( ".iconic-wsb-bump-product__select--" + this.currentProductId + " option" ).each( function( optionIndex ) { 735 var $option = $( this ); 736 var optionAttribute = $option.data( "attributes" ); 737 var matchFlag = true; 738 var attribute; 739 for ( attribute in currentProductAttributes ) { 740 if ( optionAttribute && optionAttribute[ attribute ]['label'] === currentProductAttributes[ attribute ] ) { 741 //ok 742 } else { 743 matchFlag = false;
744 } 745 } 746 if ( matchFlag ) { 747 matchIndex = optionIndex; 748 $select.find( "option" ).eq( matchIndex ).prop( 'selected', true ); 749 $select.change(); 750 } 751 } ); 752 } 753 }; 754 755 /** 756 * Adds products to the cart with AJAX rather than page reload, when AJAX setting is enabled 757 */ 758 this.addToCartAjax = function() { 759 $( document.body ).on( 'click', '[data-bump-product-form-submit]', function( e ) { 760 var $button = $( this ); 761 762 if ( $button.prop( 'disabled' ) || $button.hasClass( 'disabled' ) || '1' !== iconic_wsb_frontend_vars.fbt_use_ajax ) { 763 return; 764 } 765 766 var $bumps = $button.closest( '.iconic-wsb-product-bumps' ), 767 $form = $button.closest( 'form.cart' ), 768 bumpInForm = true, 769 $product_id = $button.data( 'product-id' ); 770 771 // If the bump is not within the form. 772 if ( ! $form.length ) { 773 bumpInForm = false; 774 $form = $( 'form.cart' ); 775 776 // If form is not on a product page. 777 if ( ! $form.length ) { 778 $form = $( document.createElement( 'form' ) ); 779 $( '.iconic-wsb-product-bumps' ).clone().appendTo( $form ); 780 } else { 781 // Copy the hidden field to the form. 782 $bumps.find( 'input[name="iconic-wsb-fbt-this-product"]' ).clone().appendTo( 'form.cart' ); 783 784 // Loop checked items and add those as hidden fields to the form. 785 $bumps.find( '.iconic-wsb-bump-product__checkbox:checked' ).each( function() { 786 var element = $( document.createElement( 'input' ) ); 787 element.attr( 'type', 'hidden' ); 788 element.attr( 'name', $( this ).attr( 'name') ); 789 element.val( $( this ).val() ); 790 element.attr( 'class', $( this ).attr( 'class') ); 791 element.appendTo( $form ); 792 793 var select = $( this ).closest( 'label' ).find( 'select[name^="iconic-wsb-products-add-to-cart-variation-"]' ); 794 if ( select.length ) { 795 var element = $( document.createElement( 'input' ) ); 796 element.attr( 'type', 'hidden' ); 797 element.attr( 'name', select.attr( 'name') ); 798 element.attr( 'class', select.attr( 'class') ); 799 element.val( select.val() ); 800 element.data( select.data() ); 801 element.appendTo( $form ); 802 } else { 803 $( this ).closest( 'label' ).find( 'input[name^="iconic-wsb-products-add-to-cart-variation-"]').clone().appendTo( $form ); 804 } 805 806 $( this ).closest( 'label' ).find( 'input[name^="iconic-wsb-bump-product_attributes-"]').clone().appendTo( $form ); 807 }); 808 } 809 } 810 811 e.preventDefault(); 812 813 $bumps.block( { message: null, overlayCSS: { background: '#fff', opacity: 0.6 } } ); 814 $button.prop( "disabled", true ); 815 816 // Clear messages. 817 $( '.woocommerce-notices-wrapper' ).html( '' ); 818 819 $.ajax( { 820 type: 'POST', 821 url: wc_add_to_cart_params.ajax_url, 822 data: $form.serialize() + "&iconic-wsb-add-selected=1&action=iconic_wsb_fbt_add_to_cart&post_id=" + $product_id, 823 success: function( result ) { 824 $button.text( iconic_wsb_frontend_vars.i18n.success ); 825 826 // Show notice. 827 var notice_class = result.success ? 'woocommerce-message' : 'woocommerce-error'; 828 $( '.woocommerce-notices-wrapper' ).append( '<div class="' + notice_class + '">' + result.message + '</div>' ); 829 jQuery.scroll_to_notices( $(".woocommerce-notices-wrapper") ); 830 $bumps.unblock(); 831 832 // Redirect to cart if set in Woocommerce settings. 833 if ( wc_add_to_cart_params.cart_redirect_after_add === "yes" ) { 834 window.location = wc_add_to_cart_params.cart_url; 835 } else { 836 $( document.body ).trigger( 'added_to_cart', [result.fragments, result.cart_hash] ); 837 } 838 }, 839 error: function() { 840 $button.text( iconic_wsb_frontend_vars.i18n.error ); 841 $bumps.unblock(); 842 }, 843 complete: function() { 844 setTimeout( function() { 845 $button.prop( "disabled", false ).text( iconic_wsb_frontend_vars.i18n.add_selected ); 846 847 // If the bump was not in the form, clean it up. 848 if ( ! bumpInForm ) { 849 $( 'form.cart input[name="iconic-wsb-fbt-this-product"]' ).remove(); 850 $( 'form.cart .iconic-wsb-bump-product__checkbox' ).remove(); 851 $( 'form.cart input[name^="iconic-wsb-bump-product_attributes-"]').remove(); 852 $( 'form.cart select[name^="iconic-wsb-products-add-to-cart-variation-"]').remove(); 853 } 854 }, 3000 ); 855 } 856 } ); 857 } ); 858 }; 859 860 /** 861 * Toggle the related thumbnail when checkbox for a product is deselected. 862 */ 863 this.toggleProductImages = function() { 864 $( '.iconic-wsb-bump-product__checkbox' ).change( function() { 865 var $checkbox = $( this ), 866 $list_item = $checkbox.closest( '.iconic-wsb-product-bumps__list-item' ), 867 $bumps = $checkbox.closest( '.iconic-wsb-product-bumps' ), 868 id = $checkbox.val(), 869 $images_wrapper = $( '.iconic-wsb-product-bumps__images' ), 870 $images = $( '.iconic-wsb-product-bumps__image' ); 871 872 if ( !$checkbox.is( ':checked' ) ) { 873 $list_item.addClass( 'iconic-wsb-product-bumps__list-item--faded' ); 874 $( '.iconic-wsb-product-bumps__image[data-product-id=' + id + ']' ).hide(); 875 } else { 876 $list_item.removeClass( 'iconic-wsb-product-bumps__list-item--faded' ); 877 $( '.iconic-wsb-product-bumps__image[data-product-id=' + id + ']' ).show(); 878 } 879 880 // Remove plus on last visible item. 881 var $last_visible = $bumps.find( '.iconic-wsb-product-bumps__image:visible:last' ); 882 883 $images.removeClass( 'iconic-wsb-product-bumps__image--no-plus' ); 884 $last_visible.addClass( 'iconic-wsb-product-bumps__image--no-plus' ); 885 886 // Hide section if no images visible. 887 var toggle_images = ! $images_wrapper.is( ':visible' ) || 0 < $last_visible.length; 888 $images_wrapper.toggle( toggle_images ); 889 } ); 890 891 $( '.iconic-wsb-bump-product__checkbox' ).trigger('change') 892 }; 893 }; 894 895 var afterAddToCartBump = new AfterAddToCartBump(); 896 var frequentlyBoughTogether = new FrequentlyBoughTogether(); 897 898 $( document ).ready( function() { 899 afterAddToCartBump.init(); 900 frequentlyBoughTogether.init(); 901 } ); 902 903 $( document ).on('added_to_cart', function( e, fragments ) { 904 if ( 905 ! fragments || 906 ! window.wc_cart_fragments_params || 907 ! wc_cart_fragments_params.fragment_name 908 ) { 909 return; 910 } 911 912 afterAddToCartBump.init(); 913 914 // Delete from fragments 915 fragments['.iconic_wsb_after_add_to_cart_popup_placeholder'] = undefined; 916 fragments['.woocommerce-notices-wrapper'] = undefined; 917 918 sessionStorage.setItem( 919 wc_cart_fragments_params.fragment_name, 920 JSON.stringify( fragments ) 921 ); 922 }); 923} ); 924 925"use strict"; 926 927/** 928 * Reusable utility to handles the dropdown changes for the variation dropdowns. 929 * 1. Fetches the variation price when all dropdowns are selected 930 * 2. Saves attributes data in hidden fields 'iconic-wsb-acb-variation-data' or 'iconic-wsb-checkout-variation-data' 931 * 3. Shows and Hides spinner while AJAX 932 * 933 * @param {Object} form The jQuery instance of the form where variation dropdowns reside 934 * @param {str} container_selector selector string for the containing div 935 * @param {Function} onVariationFound callback function to be called when the variation is purchasable 936 * @param {Function} onVariationNotFound callback function to be called when the variation is not purchasable 937 */ 938var IconicVariationHandler = function (form, container_selector, onVariationFound, onVariationNotFound ) { 939 this.$form = form; 940 this.container_selector = container_selector; 941 942 this.getVariation = function() { 943 var self = this, 944 $variationIdField = self.$form.find( ".iconic-wsb__variation_id" ); 945 946 if ( $variationIdField.length <= 0 ) { 947 return; 948 } 949 950 if ( self.checkAllSelects() ) { 951
952 self.$attributeFields = jQuery( self.container_selector ).find( '.iconic-wsb-variation__select' ); 953 var attributes = self.getChosenAttributes(); 954 var currentAttributes = attributes.data; 955 //TODO: Make this more generic. 956 if ( self.$form.hasClass("iconic-wsb-after-checkout-bump-form") ) { 957 jQuery("[name='iconic-wsb-acb-variation-data']").val(JSON.stringify(currentAttributes)); 958 } 959 else { 960 jQuery("[name='iconic-wsb-checkout-variation-data']").val(JSON.stringify(currentAttributes)); 961 } 962 currentAttributes.product_id = parseInt( jQuery( self.container_selector ).find( ".iconic-wsb__product_id" ).val() ); 963 currentAttributes.action = "iconic_wsb_checkout_get_variation"; 964 currentAttributes.bump_id = jQuery( self.container_selector ).find( ".iconic-wsb__bump_id" ).val(); 965 currentAttributes._ajax_nonce = iconic_wsb_frontend_vars.nonce; 966 self.showLoader(); 967 self.xhr = jQuery.ajax( { 968 url: iconic_wsb_frontend_vars.ajax_url, 969 type: 'POST', 970 data: currentAttributes, 971 success: function( variation ) { 972 if ( variation ) { 973 self.$form.find( "#iconic-wsb-checkout-bump-variation" ).val( variation.variation_id ); 974 self.$form.find( ".iconic-wsb-checkout-bump__price_span" ).html( variation.price_html ); 975 if ( !variation.is_purchasable || !variation.is_in_stock || !variation.variation_is_visible ) { 976 onVariationNotFound(); 977 $variationIdField.val( "" ); 978 } else { 979 onVariationFound( variation ); 980 $variationIdField.val( variation.variation_id ); 981 } 982 } else { 983 onVariationNotFound(); 984 $variationIdField.val( "" ); 985 } 986 self.hideLoader(); 987 }, 988 complete: function() { 989 self.hideLoader(); 990 } 991 } ); 992 993 self.$form.find( "[data-iconic-wsb-acb-add-to-cart-button] , [data-iconic-wsb-checkout-bump-trigger]" ).attr( "disabled", false ); 994 } else { 995 self.$form.find( "[data-iconic-wsb-acb-add-to-cart-button], [data-iconic-wsb-checkout-bump-trigger]" ).attr( "disabled", true ); 996 } 997 }; 998 999 /** 1000 * Checks all the variation dropdowns. 1001 * @returns boolean. Returns true iff all attribute dropdowns have a selected value. Returns false even is a single attribute dropdown doesnt has a value. 1002 */ 1003 this.checkAllSelects = function() { 1004 var self = this; 1005 self.allVariationSelectedFlag = true;
1006 jQuery( self.container_selector ).find( ".iconic-wsb-variation__select" ).each( function() { 1007 if ( jQuery( this ).val() ) { 1008 jQuery( this ).closest( "tr" ).removeClass( "iconic-wsb-variation-tr-valdation-error" ); 1009 } else { 1010 self.allVariationSelectedFlag = false; 1011 jQuery( this ).closest( "tr" ).addClass( "iconic-wsb-variation-tr-valdation-error" ); 1012 } 1013 } ); 1014 return self.allVariationSelectedFlag; 1015 }; 1016 1017 /** 1018 * Get chosen attributes from form. 1019 * @return array 1020 */ 1021 this.getChosenAttributes = function() { 1022 var data = {}; 1023 var count = 0; 1024 var chosen = 0; 1025 1026 this.$attributeFields.each( function() { 1027 var attribute_name = jQuery( this ).data( 'attribute_name' ) || jQuery( this ).attr( 'name' ); 1028 var value = jQuery( this ).val() || ''; 1029 1030 if ( value.length > 0 ) { 1031 chosen ++; 1032 } 1033 1034 count ++; 1035 data[ attribute_name ] = value; 1036 } ); 1037 1038 return { 1039 'count': count, 1040 'chosenCount': chosen, 1041 'data': data 1042 }; 1043 }; 1044 1045 /** 1046 * Show spinner/loader for ajax. 1047 */ 1048 this.showLoader = function() { 1049 this.$form.block( { 1050 message: null, 1051 overlayCSS: { 1052 background: '#fff', 1053 opacity: 0.6 1054 } 1055 } ); 1056 }; 1057 1058 /** 1059 * used in conjection to showLoader() to hide the spinner/loader 1060 */ 1061 this.hideLoader = function() { 1062 this.$form.unblock(); 1063 }; 1064 1065};
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.