1/** 2 * BOGO public side JS file. 3 * Free product selection functionality. 4 * 5 * @since 2.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 let attributes = {}; 18 const 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 25 const coupon_id = parent.closest( '.wbte_sc_bogo_products' ).attr( 'coupon' ); 26 27 if ( "" == $( this ).val() ) { 28 parent.find( 'input[name="variation_id"]' ).val( 0 ); 29 parent.find( 'input[name="wt_variation_options"]' ).val( JSON.stringify( attributes ) ); 30 return false; 31 } 32 33 let stop_checking = false; 34 $.each( 35 attributes, 36 function ( key, value ) { 37 if ( '' === value ) { 38 stop_checking = true; 39 return false; 40 } 41 } 42 ); 43 if ( stop_checking ) { /** Not every attributes selected. */ 44 return; 45 } 46 47 const product_id = parent.attr( 'product-id' ); 48 49 const data = { 50 'attributes' : attributes, 51 'product' : product_id, 52 '_wpnonce' : WTSmartCouponOBJ.nonces.public, 53 'coupon_id' : coupon_id 54 }; 55 56 $( '.wbte_sc_bogo_add_to_cart, .checkout-button' ).prop( 'disabled', true ).css( {'opacity':.5, 'cursor':'not-allowed'} ); 57 jQuery.ajax( 58 { 59 type: "POST", 60 async: true, 61 url: WTSmartCouponOBJ.wc_ajax_url + 'update_variation_id_on_choose', 62 data: data, 63 dataType: 'json', 64 success:function (response) { 65 const productList = parent.closest( '.wbte_sc_bogo_products' ); 66 if ( true === response.status ) { 67 parent.find( 'input[name="variation_id"]' ).val( response.variation_id ); 68 parent.find( 'input[name="wt_variation_options"]' ).val( JSON.stringify( attributes ) ); 69 parent.find('.wbte_sc_bogo_variation_error').remove(); 70 wbteScUpdateSelectedCount( productList ); 71 if ( response.img_url && '' !== response.img_url ) { 72 parent.find( '.wbte_product_image img' ).attr( 'src', response.img_url ); 73 } 74 if ( response.price && '' !== response.price && response.discount && '' !== response.discount ) { 75 parent.find( '.wbte_sc_bogo_product_price' ).html( response.price ); 76 parent.find( '.wbte_sc_bogo_product_discount_price' ).html( response.price - response.discount ); 77 } 78 if ( response.discount && '' !== response.discount ) { 79 parent.find( '.wbte_sc_bogo_product_discount_price' ).html( response.discount ); 80 } 81 } else { 82 wbteScUpdateSelectedCount( productList ); 83 parent.find( 'input[name="variation_id"]' ).val( 0 ); 84 85 if (false !== response.status_msg && "" !== response.status_msg.trim()) { /* check message was disabled or not */ 86 alert( response.status_msg ); 87 } 88 } 89 }, 90 error:function () { 91 parent.find( 'input[name="variation_id"]' ).val( 0 ); 92 $( '.wbte_sc_bogo_add_to_cart, .checkout-button' ).prop( 'disabled', false ).css( {'opacity':1, 'cursor':'pointer'} ); 93 $( '.wbte_get_away_product' ).css( {'opacity':1, 'cursor':'default'} ); 94 alert( WTSmartCouponOBJ.labels.error ); 95 } 96 } 97 ); 98 } 99 ); 100 101 $( document ).ready( function() { 102 103 /** Handle product selection */ 104 $( document ).on( 'click', '.wbte_get_away_product', function( e ) { 105 if ( $( e.target ).is( 'select, input, option' ) || $( e.target ).closest( 'select, input' ).length ) { 106 return; 107 } 108 109 const parent = $( this ); 110 const productList = parent.closest( '.wbte_sc_bogo_products' ); 111 const isAnyCondition = 'any' === productList.data( 'condition' ); 112 const totalQty = Number.parseInt( productList.closest( '.wbte_sc_bogo_giveaway_products_container' ).find( '.giveaway-title' ).attr( 'data-total-qty' ) ); 113 114 if ( '1' === parent.attr( 'data-is_purchasable' ) ) { 115 const currentSelectedQty = wbteScGetSelectedQuantityTotal( productList ); 116 117 if ( ! parent.hasClass( 'selected' ) ) { 118 if ( currentSelectedQty >= totalQty ) { 119 return; 120 } 121
122 parent.find( 'input[name="wbte_sc_bogo_quantity"]' ).val( 1 ); 123 124 if ( isAnyCondition ) { 125 /** For 'any' condition, deselect any previously selected product */ 126 productList.find( '.wbte_get_away_product.selected' ).each( function() { 127 $( this ).removeClass( 'selected' ); 128 } ); 129 130 parent.find( 'input[name="wbte_sc_bogo_quantity"]' ).val( totalQty ); 131 } 132 133 if ( 0 < parent.attr( 'data-free-qty-on-select' ) ) { 134 parent.find( 'input[name="wbte_sc_bogo_quantity"]' ).val( parent.attr( 'data-free-qty-on-select' ) ); 135 } 136 } 137 138 parent.toggleClass( 'selected' ); 139 140 const variation_id = parent.find( '[name="variation_id"]' ).val() || 0; 141 if ( 0 < parent.find( '.wbte_give_away_product_attr' ).length && ( '' === variation_id || '0' === variation_id ) ) { 142 143 parent.find( '.wbte_sc_bogo_variation_error' ).remove(); 144 145 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>'; 146 parent.find( '.wt_variations' ).after( errorHtml ); 147 } 148 149 if ( ! parent.hasClass( 'selected' ) ) { 150 parent.find( '.wbte_sc_bogo_variation_error' ).remove(); 151 } 152 153 updateDisabledState( productList, isAnyCondition ); 154 wbteScUpdateSelectedCount( productList ); 155 } 156 } ); 157 158 /** Handle quantity change */ 159 $( document ).on( 'change', 'input[name="wbte_sc_bogo_quantity"]', function() { 160 const input = $( this ); 161 const parent = input.closest( '.wbte_get_away_product' ); 162 const productList = parent.closest( '.wbte_sc_bogo_products' ); 163 const totalQty = Number.parseInt( productList.closest( '.wbte_sc_bogo_giveaway_products_container' ) 164 .find( '.giveaway-title' ).attr( 'data-total-qty' ) ); 165 166 let newQty = Number.parseInt( input.val() ) || 0; 167 const maxQty = Number.parseInt( input.attr( 'max' ) ) || 0; 168 169 /** First ensure we don't exceed individual product's max quantity */ 170 if ( newQty > maxQty ) { 171 newQty = maxQty; 172 input.val( newQty ); 173 } 174 175 /** Calculate total quantity excluding current product's quantity completely */ 176 let otherProductsQty = 0; 177 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() { 178 otherProductsQty += Number.parseInt( $( this ).val() ) || 0; 179 } ); 180 181 /** Ensure total quantity doesn't exceed limit */ 182 if ( ( otherProductsQty + newQty ) > totalQty ) { 183 newQty = totalQty - otherProductsQty; 184 input.val( newQty ); 185 } 186 187 /** Update selected state based on quantity */ 188 parent.toggleClass( 'selected', newQty > 0 ); 189 190 updateDisabledState( productList, 'any' === productList.data( 'condition' ) ); 191 wbteScUpdateSelectedCount( productList ); 192 } ); 193 194 function updateDisabledState( productList, isAnyCondition ) { 195 const totalQty = Number.parseInt( productList.closest( '.wbte_sc_bogo_giveaway_products_container' ) 196 .find( '.giveaway-title' ).attr( 'data-total-qty' ) ); 197 const currentQty = wbteScGetSelectedQuantityTotal( productList ); 198 199 productList.find( '.wbte_get_away_product' ).each( function() { 200 const product = $( this ); 201 if ( ! product.hasClass( 'selected' ) ) { 202 if ( isAnyCondition && 0 < productList.find( '.selected' ).length ) { 203 product.addClass( 'disabled' ); 204 } else { 205 product.toggleClass( 'disabled', currentQty >= totalQty ); 206 } 207 } 208 } ); 209 } 210 211 /** Add this handler after the existing click handlers */ 212 $( document ).on( 'click', '.wbte_sc_bogo_add_to_cart', function( e ) { 213 e.preventDefault(); 214 215 const productList = $( '.wbte_sc_bogo_products' ); 216 const selectedProducts = productList.find( '.wbte_get_away_product.selected' ); 217 218 if ( 0 === selectedProducts.length ) { 219 return; 220 } 221 222 let hasError = false; 223 const products = []; 224 225 $( '.wbte_sc_bogo_variation_error' ).remove(); 226 227 selectedProducts.each( function() { 228 const parent_obj = $( this ); 229 230 /** Check if product is purchasable */ 231 if ( '1' !== parent_obj.attr( 'data-is_purchasable' ) ) { 232 return; 233 } 234 235 /** Handle variation if exists */ 236 let variation_id = 0; 237 const variation_id_obj = parent_obj.find( '[name="variation_id"]' ); 238 if ( 0 < variation_id_obj.length ) { 239 if ( '' === variation_id_obj.val().trim() || '0' === variation_id_obj.val().trim() ) { 240 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>'; 241 parent_obj.find( '.wt_variations' ).after( errorHtml ); 242 hasError = true; 243 return false;
244 } 245 variation_id = variation_id_obj.val(); 246 } 247 248 const coupon_id = parent_obj.closest( '.wbte_sc_bogo_products' ).attr( 'coupon' ); 249 const product_id = parent_obj.attr( 'product-id' ); 250 const free_qty = parent_obj.find( 'input[name="wbte_sc_bogo_quantity"]' ).val() || 1; 251 const variation_attributes = parent_obj.find( 'input[name="wt_variation_options"]' ).length > 0 252 ? JSON.parse( parent_obj.find( 'input[name="wt_variation_options"]' ).val() ) 253 : ''; 254 255 if ( free_qty > 0 ) { 256 products.push( { 257 'product_id' : product_id, 258 'variation_id': variation_id, 259 'attributes' : variation_attributes, 260 'coupon_id' : coupon_id, 261 'free_qty' : free_qty 262 } ); 263 } 264 } ); 265 266 if ( hasError || 0 === products.length ) { 267 return; 268 } 269 270 const data = { 271 '_wpnonce': WTSmartCouponOBJ.nonces.public, 272 'products': products 273 }; 274 275 const html_back = $( this ).html(); 276 $( this ).html( WTSmartCouponOBJ.labels.please_wait ); 277 278 const all_btn_elm = $( '.wbte_sc_bogo_add_to_cart' ); 279 all_btn_elm.prop( 'disabled', true ); 280 281 if ( ! $( '.woocommerce-notices-wrapper' ).length ) { 282 $( '#main' ).prepend( '<div class="woocommerce-notices-wrapper"></div>' ); 283 } 284 285 $( '.woocommerce-notices-wrapper' ).html( '' ); 286 287 jQuery.ajax( { 288 type: 'POST', 289 async: true, 290 url: WTSmartCouponOBJ.wc_ajax_url + 'wbte_choose_multiple_free_products', 291 data: data, 292 success: function( response ) { 293 if ( response ) { 294 globalThis.location.replace(globalThis.location.href.split('#')[0]); 295 } else { 296 $( '.woocommerce-notices-wrapper' ).html( response ); 297 $( 'html, body' ).stop( true, true ).animate( { scrollTop: ( $( '.woocommerce-notices-wrapper' ).offset().top - 70 ) }, 500 ); 298 299 $( this ).html( html_back ); 300 all_btn_elm.prop( 'disabled', false ); 301 } 302 }, 303 error: function() { 304 $( this ).html( html_back ); 305 all_btn_elm.prop( 'disabled', false ); 306 alert( WTSmartCouponOBJ.labels.error ); 307 } 308 } ); 309 } ); 310 } ); 311 } 312); 313 314/** Update selected count */ 315const wbteScUpdateSelectedCount = ( function($){ 316 return function( productList ){ 317 const selectedQty = wbteScGetSelectedQuantityTotal( productList ); 318 const qtySpan = productList.closest( '.wbte_sc_bogo_giveaway_products_container' ) 319 .find( '.wbte_sc_bogo_products_selected_qty' ); 320 321 qtySpan.text( selectedQty ); 322 323 /** Disable/enable buttons based on selection */ 324 let totalSelectedQty = 0; 325 $( '.wbte_sc_bogo_products .wbte_get_away_product.selected' ).each( function() { 326 totalSelectedQty += Number.parseInt( $( this ).find( 'input[name="wbte_sc_bogo_quantity"]' ).val() ) || 0; 327 } ); 328 const button = $( '.wbte_sc_bogo_add_to_cart' ); 329 if ( totalSelectedQty > 0 && 0 === $( '.wbte_sc_bogo_variation_error' ).length ) { 330 button.prop( 'disabled', false ).css( { 'opacity': 1, 'cursor': 'pointer' } ); 331 } else { 332 button.prop( 'disabled', true ).css( { 'opacity': 0.5, 'cursor': 'not-allowed' } ); 333 } 334 } 335} )(jQuery); 336 337/** Calculate total selected quantity */ 338const wbteScGetSelectedQuantityTotal = ( function($){ 339 return function( productList ){ 340 let total = 0; 341 productList.find( 'input[name="wbte_sc_bogo_quantity"]' ).closest( '.wbte_get_away_product.selected' ).find( 'input[name="wbte_sc_bogo_quantity"]' ).each( function() { 342 total += Number.parseInt( $( this ).val() ) || 0; 343 } ); 344 return total; 345 } 346} )(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.