1/** 2 * BOGO public side JS file. 3 * Free product selection functionality. 4 * 5 * @since 3.0.0 6 * @package Wt_Smart_Coupon 7 */ 8 9jQuery( 10 function ($) { 11 "use strict"; 12 13 $( document ).on( 14 'change', 15 '.wbte_give_away_product_attr', 16 function () { 17 var attributes = {}; 18 var parent = $( this ).closest( '.wbte_get_away_product' ); 19 parent.find( '.wbte_give_away_product_attr' ).each( 20 function (index) { 21 attributes[$( this ).attr( 'data-attribute_name' )] = $( this ).val(); 22 } 23 ); 24 const coupon_id = parent.closest( '.wbte_sc_bogo_products' ).attr( 'coupon' ); 25 26 if ( "" == $( this ).val() ) { 27 parent.find( 'input[name="variation_id"]' ).val( 0 ); 28 parent.find( 'input[name="wt_variation_options"]' ).val( JSON.stringify( attributes ) ); 29 return false; 30 } 31 32 var stop_checking = false; 33 $.each( 34 attributes, 35 function ( key, value ) { 36 if ( value == '' ) { 37 stop_checking = true; 38 return false; 39 } 40 } 41 ); 42 if ( stop_checking ) { /** Not every attributes selected. */ 43 return; 44 } 45 46 var product_id = parent.attr( 'product-id' ); 47 48 var data = { 49 'attributes' : attributes, 50 'product' : product_id, 51 '_wpnonce' : WTSmartCouponOBJ.nonces.public, 52 'coupon_id' : coupon_id 53 }; 54 55 $( '.wbte_sc_bogo_add_to_cart, .checkout-button, .wbte_sc_bogo_proceed_checkout' ).prop( 'disabled', true ).css( {'opacity':.5, 'cursor':'not-allowed'} ); 56 jQuery.ajax( 57 { 58 type: "POST", 59 async: true, 60 url: WTSmartCouponOBJ.wc_ajax_url + 'update_variation_id_on_choose', 61 data: data, 62 dataType: 'json', 63 success:function (response) { 64 const productList = parent.closest( '.wbte_sc_bogo_products' ); 65 if ( true === response.status ) { 66 parent.find( 'input[name="variation_id"]' ).val( response.variation_id ); 67 parent.find( 'input[name="wt_variation_options"]' ).val( JSON.stringify( attributes ) ); 68 parent.find('.wbte_sc_bogo_variation_error').remove(); 69 wbteScUpdateSelectedCount( productList ); 70 if ( response.img_url && '' !== response.img_url ) { 71 parent.find( '.wbte_product_image img' ).attr( 'src', response.img_url ); 72 } 73 if ( response.price && '' !== response.price && response.discount && '' !== response.discount ) { 74 parent.find( '.wbte_sc_bogo_product_price' ).html( response.price ); 75 parent.find( '.wbte_sc_bogo_product_discount_price' ).html( response.price - response.discount ); 76 } 77 if ( response.discount && '' !== response.discount ) { 78 parent.find( '.wbte_sc_bogo_product_discount_price' ).html( response.discount ); 79 } 80 } else { 81 wbteScUpdateSelectedCount( productList ); 82 parent.find( 'input[name="variation_id"]' ).val( 0 ); 83 84 if (false !== response.status_msg && "" !== response.status_msg.trim()) { /* check message was disabled or not */ 85 alert( response.status_msg ); 86 } 87 } 88 }, 89 error:function () { 90 parent.find( 'input[name="variation_id"]' ).val( 0 ); 91 $( '.wbte_sc_bogo_add_to_cart, .checkout-button, .wbte_sc_bogo_proceed_checkout' ).prop( 'disabled', false ).css( {'opacity':1, 'cursor':'pointer'} ); 92 $( '.wbte_get_away_product' ).css( {'opacity':1, 'cursor':'default'} ); 93 alert( WTSmartCouponOBJ.labels.error ); 94 } 95 } 96 ); 97 } 98 ); 99 100 $( document ).ready( function() { 101 /** Show popup when clicking the button */ 102 $( document ).on( 'click', '.wbte_sc_bogo_popup_btn', function( e ) { 103 e.preventDefault(); 104 $( '.wbte_sc_giveaway_popup' ).fadeIn( 300 ); 105 $( 'body' ).addClass( 'wbte_sc_popup_open' ); 106 } ); 107 108 /** Close popup when clicking outside */ 109 $( document ).on( 'click', '.wbte_sc_giveaway_popup', function( e ) { 110 if ( $( e.target ).hasClass( 'wbte_sc_giveaway_popup' ) ) { 111 $( '.wbte_sc_giveaway_popup' ).fadeOut( 300 ); 112 $( 'body' ).removeClass( 'wbte_sc_popup_open' ); 113 } 114 } ); 115 116 /** Close popup when clicking close button */ 117 $( document ).on( 'click', '.wbte_sc_giveaway_popup_close', function( e ) { 118 e.preventDefault(); 119 $( '.wbte_sc_giveaway_popup' ).fadeOut( 300 ); 120 $( 'body' ).removeClass( 'wbte_sc_popup_open' ); 121 } ); 122 123 /** Handle product selection */ 124 $( document ).on( 'click', '.wbte_get_away_product', function( e ) { 125 if ( $( e.target ).is( 'select, input, option' ) || $( e.target ).closest( 'select, input' ).length ) { 126 return; 127 } 128 129 const parent = $( this ); 130 const productList = parent.closest( '.wbte_sc_bogo_products' ); 131 const isAnyCondition = 'any' === productList.data( 'condition' ); 132 const totalQty = Number.parseInt( productList.closest( '.wbte_sc_bogo_giveaway_products_container' ).find( '.giveaway-title' ).attr( 'data-total-qty' ) ); 133 134 if ( '1' === parent.attr( 'data-is_purchasable' ) ) { 135 const currentSelectedQty = wbteScGetSelectedQuantityTotal( productList ); 136 137 if ( ! parent.hasClass( 'selected' ) ) { 138 if ( currentSelectedQty >= totalQty ) { 139 return; 140 } 141
142 parent.find( 'input[name="wbte_sc_bogo_quantity"]' ).val( 1 ); 143 144 if ( isAnyCondition ) { 145 /** For 'any' condition, deselect any previously selected product */ 146 productList.find( '.wbte_get_away_product.selected' ).each( function() { 147 $( this ).removeClass( 'selected' ); 148 } ); 149 150 parent.find( 'input[name="wbte_sc_bogo_quantity"]' ).val( totalQty ); 151 } 152 153 if ( 0 < parent.attr( 'data-free-qty-on-select' ) ) { 154 parent.find( 'input[name="wbte_sc_bogo_quantity"]' ).val( parent.attr( 'data-free-qty-on-select' ) ); 155 } 156 157 } 158 159 parent.toggleClass( 'selected' ); 160 161 const variation_id = parent.find( '[name="variation_id"]' ).val() || 0; 162 if ( 0 < parent.find( '.wbte_give_away_product_attr' ).length && ( '' === variation_id || '0' === variation_id ) ) { 163 164 parent.find( '.wbte_sc_bogo_variation_error' ).remove(); 165 166 const errorHtml = '<div class="wbte_sc_bogo_variation_error" style="color: #dc3545; margin-top: 10px;"><i class="fas fa-exclamation-circle"></i> ' + WTSmartCouponOBJ.labels.choose_variation + '</div>'; 167 parent.find( '.wt_variations' ).after( errorHtml ); 168 } 169 170 if ( ! parent.hasClass( 'selected' ) ) { 171 parent.find( '.wbte_sc_bogo_variation_error' ).remove(); 172 } 173 174 updateDisabledState( productList, isAnyCondition ); 175 wbteScUpdateSelectedCount( productList ); 176 } 177 } ); 178 179 /** Handle quantity change */ 180 $( document ).on( 'change', 'input[name="wbte_sc_bogo_quantity"]', function() { 181 const input = $( this ); 182 const parent = input.closest( '.wbte_get_away_product' ); 183 const productList = parent.closest( '.wbte_sc_bogo_products' ); 184 const totalQty = Number.parseInt( productList.closest( '.wbte_sc_bogo_giveaway_products_container' ) 185 .find( '.giveaway-title' ).attr( 'data-total-qty' ) ); 186 187 let newQty = Number.parseInt( input.val() ) || 0; 188 const maxQty = Number.parseInt( input.attr( 'max' ) ) || 0; 189 190 /** First ensure we don't exceed individual product's max quantity */ 191 if ( newQty > maxQty ) { 192 newQty = maxQty; 193 input.val( newQty ); 194 } 195 196 /** Calculate total quantity excluding current product's quantity completely */ 197 let otherProductsQty = 0; 198 productList.find( 'input[name="wbte_sc_bogo_quantity"]' ).closest( '.wbte_get_away_product.selected' ).find( 'input[name="wbte_sc_bogo_quantity"]' ).not( input ).each( function() { 199 otherProductsQty += Number.parseInt( $( this ).val() ) || 0; 200 } ); 201 202 /** Ensure total quantity doesn't exceed limit */ 203 if ( ( otherProductsQty + newQty ) > totalQty ) { 204 newQty = totalQty - otherProductsQty; 205 input.val( newQty ); 206 } 207 208 /** Update selected state based on quantity */ 209 parent.toggleClass( 'selected', newQty > 0 ); 210 211 updateDisabledState( productList, 'any' === productList.data( 'condition' ) ); 212 wbteScUpdateSelectedCount( productList ); 213 } ); 214 215 function updateDisabledState( productList, isAnyCondition ) { 216 const totalQty = Number.parseInt( productList.closest( '.wbte_sc_bogo_giveaway_products_container' ) 217 .find( '.giveaway-title' ).attr( 'data-total-qty' ) ); 218 const currentQty = wbteScGetSelectedQuantityTotal( productList ); 219 220 productList.find( '.wbte_get_away_product' ).each( function() { 221 const product = $( this ); 222 if ( ! product.hasClass( 'selected' ) ) { 223 if ( isAnyCondition && 0 < productList.find( '.selected' ).length ) { 224 product.addClass( 'disabled' ); 225 } else { 226 product.toggleClass( 'disabled', currentQty >= totalQty ); 227 } 228 } 229 } ); 230 } 231 232 /** When adding product from details page, because of reload, the popup is not shown. */ 233 $('form.cart').on('submit', function() { 234 if( ! WTSmartCouponOBJ?.bogo_popup_ajax_required ) return; 235 sessionStorage.setItem( 'wbte_sc_bogo_shop_form_submitted', true ); 236 }); 237 238 /** 239 * Handle BOGO popup update response. 240 * 241 * @param {Object} response AJAX response. 242 * @param {Array} applied_bogo_coupons Previously applied BOGO coupons. 243 */ 244 function handleBogoPopupResponse( response, applied_bogo_coupons ) { 245 if ( response.has_free_products ) { 246 if ( $( '.wbte_sc_giveaway_popup' ).length ) { 247 $( '.wbte_sc_giveaway_popup, .wbte_sc_bogo_popup_btn' ).remove(); 248 } 249 $( 'body' ).append( response.button_html ); 250 251 let new_applied_bogo_coupons = response.applied_bogo_coupons; 252 253 if ( 254 ( Object.keys( applied_bogo_coupons ).length !== Object.keys( new_applied_bogo_coupons ).length ) 255 || ( sessionStorage.getItem( 'wbte_sc_bogo_shop_form_submitted' ) && Object.keys( new_applied_bogo_coupons ).length > 0 ) 256 ) { 257 258 wbte_sc_show_notice_on_popup( new_applied_bogo_coupons, applied_bogo_coupons, response.apply_msg ); 259 260 $( '.wbte_sc_bogo_popup_btn' ).addClass( 'expanded' ); 261 262 setTimeout( function() { 263 $( '.wbte_sc_bogo_popup_btn' ).removeClass( 'expanded' ); 264 }, 3000 ); 265 266 $( '.wbte_sc_bogo_popup_btn' ).trigger( 'click' ); 267 } 268 WTSmartCouponOBJ.applied_bogo_coupons = new_applied_bogo_coupons; 269 } else { 270 $( '.wbte_sc_giveaway_popup, .wbte_sc_bogo_popup_btn' ).remove(); 271 } 272 sessionStorage.removeItem( 'wbte_sc_bogo_shop_form_submitted' ); 273 } 274 275 /** Update popup visibility when cart changes */ 276 $( document.body ).on( 'added_to_cart removed_from_cart wc_fragments_refreshed', function() { 277 278 if( ! WTSmartCouponOBJ?.bogo_popup_ajax_required ) return; 279 280 let applied_bogo_coupons = WTSmartCouponOBJ.applied_bogo_coupons; 281 $.ajax( { 282 url: WTSmartCouponOBJ.wc_ajax_url + 'wbte_sc_show_bogo_popup', 283 type: 'POST', 284 data: { 285 _wpnonce: WTSmartCouponOBJ.nonces.public 286 }, 287 success: function( response ) { 288 handleBogoPopupResponse( response, applied_bogo_coupons ); 289 } 290 } ); 291 } ); 292 } ); 293 294 /** Add this handler after the existing click handlers */ 295 $( document ).on( 'click', '.wbte_sc_bogo_add_to_cart, .wbte_sc_bogo_proceed_checkout', function( e ) { 296 e.preventDefault(); 297 298 const productList = $( '.wbte_sc_bogo_products' ); 299 const selectedProducts = productList.find( '.wbte_get_away_product.selected' ); 300 const proceedCheckout = $( this ).hasClass( 'wbte_sc_bogo_proceed_checkout' ); 301 302 if ( 0 === selectedProducts.length ) { 303 return; 304 } 305 306 let hasError = false;
307 const products = []; 308 309 $( '.wbte_sc_bogo_variation_error' ).remove(); 310 311 selectedProducts.each( function() { 312 const parent_obj = $( this ); 313 314 /** Check if product is purchasable */ 315 if ( '1' !== parent_obj.attr( 'data-is_purchasable' ) ) { 316 return; 317 } 318 319 /** Handle variation if exists */ 320 let variation_id = 0; 321 const variation_id_obj = parent_obj.find( '[name="variation_id"]' ); 322 if ( 0 < variation_id_obj.length ) { 323 if ( '' === variation_id_obj.val().trim() || '0' === variation_id_obj.val().trim() ) { 324 const errorHtml = '<div class="wbte_sc_bogo_variation_error" style="color: #dc3545; margin-top: 10px;"><i class="fas fa-exclamation-circle"></i> ' + WTSmartCouponOBJ.labels.choose_variation + '</div>'; 325 parent_obj.find( '.wt_variations' ).after( errorHtml ); 326 hasError = true; 327 return false; 328 } 329 variation_id = variation_id_obj.val(); 330 } 331 332 const coupon_id = parent_obj.closest( '.wbte_sc_bogo_products' ).attr( 'coupon' ); 333 const product_id = parent_obj.attr( 'product-id' ); 334 const free_qty = parent_obj.find( 'input[name="wbte_sc_bogo_quantity"]' ).val(); 335 const triggered_item_key = parent_obj.attr( 'data-triggered-item-key' ); 336 const variation_attributes = parent_obj.find( 'input[name="wt_variation_options"]' ).length > 0 337 ? JSON.parse( parent_obj.find( 'input[name="wt_variation_options"]' ).val() ) 338 : ''; 339 340 if ( free_qty > 0 ) { 341 products.push( { 342 'product_id': product_id, 343 'variation_id': variation_id, 344 'attributes': variation_attributes, 345 'coupon_id': coupon_id, 346 'free_qty': free_qty, 347 'triggered_item_key': triggered_item_key 348 } ); 349 } 350 } ); 351 352 if ( hasError || 0 === products.length ) { 353 return; 354 } 355 356 const data = { 357 '_wpnonce': WTSmartCouponOBJ.nonces.public, 358 'products': products 359 }; 360 361 var html_back = $( this ).html(); 362 $( this ).html( WTSmartCouponOBJ.labels.please_wait ); 363 364 var all_btn_elms = $( '.wbte_sc_bogo_add_to_cart, .wbte_sc_bogo_proceed_checkout' ); 365 all_btn_elms.prop( 'disabled', true ); 366 367 if ( ! $( '.woocommerce-notices-wrapper' ).length ) { 368 $( '#main' ).prepend( '<div class="woocommerce-notices-wrapper"></div>' ); 369 } 370 371 $( '.woocommerce-notices-wrapper' ).html( '' ); 372 373 jQuery.ajax( { 374 type: 'POST', 375 async: true, 376 url: WTSmartCouponOBJ.wc_ajax_url + 'wbte_choose_multiple_free_products', 377 data: data, 378 success: function( response ) { 379 if ( response && response.success ) { 380 if ( proceedCheckout ) { 381 globalThis.location.href = WTSmartCouponOBJ.checkout_url; 382 } else { 383 globalThis.location.replace(globalThis.location.href.split('#')[0]); 384 } 385 } else { 386 $( '.woocommerce-notices-wrapper' ).html( response ); 387 $( 'html, body' ).stop( true, true ).animate( { scrollTop: ( $( '.woocommerce-notices-wrapper' ).offset().top - 70 ) }, 500 ); 388 389 $( this ).html( html_back ); 390 all_btn_elms.prop( 'disabled', false ); 391 } 392 }, 393 error: function() { 394 $( this ).html( html_back ); 395 all_btn_elms.prop( 'disabled', false ); 396 alert( WTSmartCouponOBJ.labels.error ); 397 } 398 } ); 399 } ); 400 } 401); 402 403/** Update selected count */ 404const wbteScUpdateSelectedCount = ( function($){ 405 return function( productList ){ 406 const selectedQty = wbteScGetSelectedQuantityTotal( productList ); 407 const qtySpan = productList.closest( '.wbte_sc_bogo_giveaway_products_container' ) 408 .find( '.wbte_sc_bogo_products_selected_qty' ); 409 410 qtySpan.text( selectedQty ); 411 412 /** Disable/enable buttons based on selection */ 413 let totalSelectedQty = 0; 414 $( '.wbte_sc_bogo_products .wbte_get_away_product.selected' ).each( function() { 415 totalSelectedQty += Number.parseInt( $( this ).find( 'input[name="wbte_sc_bogo_quantity"]' ).val() ) || 0; 416 } ); 417 const buttons = $( '.wbte_sc_bogo_add_to_cart, .wbte_sc_bogo_proceed_checkout' ); 418 if ( totalSelectedQty > 0 && 0 === $( '.wbte_sc_bogo_variation_error' ).length ) { 419 buttons.prop( 'disabled', false ).css( { 'opacity': 1, 'cursor': 'pointer' } ); 420 } else { 421 buttons.prop( 'disabled', true ).css( { 'opacity': 0.5, 'cursor': 'not-allowed' } ); 422 } 423 } 424} )(jQuery); 425 426/** Calculate total selected quantity */ 427const wbteScGetSelectedQuantityTotal = ( function($){ 428 return function( productList ){ 429 let total = 0;
430 productList.find( 'input[name="wbte_sc_bogo_quantity"]' ).closest( '.wbte_get_away_product.selected' ).find( 'input[name="wbte_sc_bogo_quantity"]' ).each( function() { 431 total += Number.parseInt( $( this ).val() ) || 0; 432 } ); 433 return total; 434 } 435} )(jQuery); 436 437const wbte_sc_get_notice_for_popup = ( function($){ 438 return function( bogo_name, apply_msg ){ 439 const applied_notice = '<div class="wc-block-components-notice-banner is-info" role="status">' + 440 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false">' + 441 '<path d="M12 3.2c-4.8 0-8.8 3.9-8.8 8.8 0 4.8 3.9 8.8 8.8 8.8 4.8 0 8.8-3.9 8.8-8.8 0-4.8-4-8.8-8.8-8.8zm0 16c-4 0-7.2-3.3-7.2-7.2C4.8 8 8 4.8 12 4.8s7.2 3.3 7.2 7.2c0 4-3.2 7.2-7.2 7.2zM11 17h2v-6h-2v6zm0-8h2V7h-2v2z"></path>' + 442 '</svg>' + 443 '<div class="wc-block-components-notice-banner__content">' + 444 apply_msg + 445 '</div>' + 446 '</div>'; 447 448 return applied_notice.replace( '{bogo_title}', bogo_name ); 449 } 450} )(jQuery); 451 452const wbte_sc_show_notice_on_popup = ( function($){ 453 return function( new_applied_bogo_coupons, applied_bogo_coupons, bogo_apply_msg ){ 454 let popup_coupons = {}; 455 456 for ( const key of Object.keys( new_applied_bogo_coupons ) ) { 457 if ( ! ( key in applied_bogo_coupons ) ) { 458 popup_coupons[ key ] = new_applied_bogo_coupons[ key ]; 459 } 460 } 461 462 for ( const key of Object.keys( popup_coupons ) ) { 463 let notice = wbte_sc_get_notice_for_popup( popup_coupons[ key ], bogo_apply_msg ); 464 $('.wbte_sc_giveaway_popup_body ul.wbte_sc_bogo_products[coupon="' + key + '"]').before(notice); 465 } 466 467 $( '.wbte_sc_giveaway_popup_content .wc-block-components-notice-banner' ).attr( 'style', 'padding: 10px !important' ); 468 } 469} )(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.