1jQuery( document ).ready( function ( $ ) { 2 setShippingAddressNoticeVisibility( true ); 3 4 $( document ).on( 5 'change', 6 '.woocommerce_subscription_gifting_checkbox[type="checkbox"]', 7 function ( e, eventContext ) { 8 if ( $( this ).is( ':checked' ) ) { 9 $( this ) 10 .closest( '.wcsg_add_recipient_fields_container' ) 11 .find( '.wcsg_add_recipient_fields' ) 12 .slideDown( 250, function () { 13 if ( 14 typeof eventContext === 'undefined' || 15 eventContext !== 'pageload' 16 ) { 17 $( this ) 18 .find( '.recipient_email' ) 19 .trigger( 'focus' ); 20 } 21 } ); 22 23 const shipToDifferentAddressCheckbox = $( document ).find( 24 '#ship-to-different-address-checkbox' 25 ); 26 if ( ! shipToDifferentAddressCheckbox.is( ':checked' ) ) { 27 shipToDifferentAddressCheckbox.click(); 28 } 29 setShippingAddressNoticeVisibility( false ); 30 } else { 31 $( this ) 32 .closest( '.wcsg_add_recipient_fields_container' ) 33 .find( '.wcsg_add_recipient_fields' ) 34 .slideUp( 250 ); 35 36 const recipientEmailElement = $( this ) 37 .closest( '.wcsg_add_recipient_fields_container' ) 38 .find( '.recipient_email' ); 39 recipientEmailElement.val( '' ); 40 setShippingAddressNoticeVisibility( true ); 41 42 if ( $( 'form.checkout' ).length !== 0 ) { 43 // Trigger the event to update the checkout after the recipient field has been cleared. 44 updateCheckout(); 45 } 46 } 47 } 48 ); 49 50 /** 51 * Handles showing and hiding the gifting checkbox on variable subscription products. 52 */ 53 function hideGiftingCheckbox() { 54 $( '.woocommerce_subscription_gifting_checkbox[type="checkbox"]' ) 55 .prop( 'checked', false ) 56 .trigger( 'change' ); 57 $( '.wcsg_add_recipient_fields_container' ).hide(); 58 } 59 60 // When a variation is found, show the gifting checkbox if it's enabled for the variation, otherwise hide it. 61 $( document ).on( 'found_variation', function ( event, variationData ) { 62 if ( variationData.gifting ) { 63 $( '.wcsg_add_recipient_fields_container' ).show(); 64 return; 65 } 66 67 hideGiftingCheckbox(); 68 } ); 69 70 // When the data is reset, hide the gifting checkbox. 71 $( document ).on( 'reset_data', hideGiftingCheckbox ); 72 73 /** 74 * Handles recipient e-mail inputs on the cart page. 75 */ 76 const cart = { 77 init: function () { 78 $( document ).on( 79 'submit', 80 'div.woocommerce > form', 81 this.set_update_cart_as_clicked 82 ); 83 84 // We need to make sure our callback is hooked before WC's. 85 const handlers = $._data( document, 'events' ); 86 if ( typeof handlers.submit !== 'undefined' ) { 87 handlers.submit.unshift( handlers.submit.pop() ); 88 } 89 }, 90 91 set_update_cart_as_clicked: function ( evt ) { 92 const $form = $( evt.target ); 93 // eslint-disable-next-line no-restricted-globals 94 const $submit = $( document.activeElement ); 95 96 // If we're not on the cart page exit. 97 if ( $form.find( 'table.shop_table.cart' ).length === 0 ) { 98 return; 99 } 100 101 // If the recipient email element is the active element, the clicked button is the update cart button. 102 if ( $submit.is( 'input.recipient_email' ) ) { 103 $( ':input[type="submit"][name="update_cart"]' ).attr( 104 'clicked', 105 'true' 106 ); 107 } 108 }, 109 }; 110 cart.init(); 111 112 /** 113 * Email validation function 114 * 115 * @param {string} email - The email to validate 116 * @return {boolean} - Whether the email is valid 117 */ 118 function isValidEmail( email ) { 119 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 120 return emailRegex.test( email ); 121 } 122 123 /** 124 * Validate all recipient emails and return overall validation status 125 * 126 * @param {boolean} showErrors - Whether to show validation errors 127 * @return {boolean} - Whether all emails are valid 128 */ 129 function validateAllRecipientEmails( showErrors = true ) { 130 const $allEmailFields = $( '.recipient_email' ); 131 let allValid = true; 132 133 // Check each email field 134 $allEmailFields.each( function () { 135 const $emailField = $( this ); 136 const $giftingCheckbox = $( this ) 137 .closest( '.wcsg_add_recipient_fields_container' ) 138 .find( '.woocommerce_subscription_gifting_checkbox' ); 139 const email = $emailField.val().trim(); 140 141 if ( ! $giftingCheckbox.is( ':checked' ) ) { 142 return; 143 } 144 145 // Check if email format is valid 146 if ( ! isValidEmail( email ) ) { 147 if ( showErrors ) { 148 showValidationErrorForEmailField( $emailField ); 149 } 150 allValid = false;
151 } 152 } ); 153 154 // Control update cart button state 155 const $updateCartButton = $( 156 '.woocommerce-cart-form :input[type="submit"][name="update_cart"]' 157 ); 158 159 if ( $updateCartButton.length ) { 160 $updateCartButton.prop( 'disabled', ! allValid ); 161 } 162 163 return allValid; 164 } 165 166 /** 167 * Validate recipient email and show error if invalid 168 * 169 * @param {jQuery} $emailField - The email input field jQuery object 170 * @return {boolean} - Whether the email is valid 171 */ 172 function validateRecipientEmail( $emailField ) { 173 const email = $emailField.val().trim(); 174 175 hideValidationErrorForEmailField( $emailField ); 176 177 // Check if email format is valid 178 if ( ! isValidEmail( email ) ) { 179 showValidationErrorForEmailField( $emailField ); 180 181 // Only validate all emails and update button state on cart and checkout shortcode pages. 182 if ( isShortcodeCartOrCheckoutPage() ) { 183 validateAllRecipientEmails(); 184 } 185 return false; 186 } 187 188 // Only validate all emails and update button state on cart and checkout shortcode pages. 189 if ( isShortcodeCartOrCheckoutPage() ) { 190 validateAllRecipientEmails(); 191 } 192 return true; 193 } 194 195 /** 196 * Handle add to cart button click with email validation 197 */ 198 $( document ).on( 199 'click', 200 '.single_add_to_cart_button, .add_to_cart_button', 201 function ( e ) { 202 // Check if we're on a product page with gifting enabled 203 const $giftingContainer = $( 204 '.wcsg_add_recipient_fields_container' 205 ); 206 if ( $giftingContainer.length === 0 ) { 207 return; // No gifting on this page 208 } 209 210 // Check if gifting checkbox is checked 211 const $giftingCheckbox = $giftingContainer.find( 212 '.woocommerce_subscription_gifting_checkbox' 213 ); 214 if ( ! $giftingCheckbox.is( ':checked' ) ) { 215 return; // Gifting not enabled for this item 216 } 217 218 // Get the recipient email field 219 const $emailField = $giftingContainer.find( '.recipient_email' ); 220 if ( $emailField.length === 0 ) { 221 return; // No email field found 222 } 223 224 // Validate the email 225 if ( ! validateRecipientEmail( $emailField ) ) { 226 e.preventDefault(); 227 e.stopPropagation(); 228 229 // Focus on the email field 230 $emailField.focus(); 231 return false; 232 } 233 } 234 ); 235 236 /** 237 * Real-time email validation on input 238 */ 239 $( document ).on( 'blur', '.recipient_email', function () { 240 const $emailField = $( this ); 241 validateRecipientEmail( $emailField ); 242 } ); 243 244 /** 245 * Clear error styling when user starts typing 246 */ 247 $( document ).on( 'input', '.recipient_email', function () { 248 const $emailField = $( this ); 249 250 hideValidationErrorForEmailField( $emailField ); 251 } ); 252 253 /******************************************* 254 * Update checkout on input changed events * 255 *******************************************/ 256 let updateTimer; 257 258 $( document ).on( 'change', '.recipient_email', function () { 259 if ( $( 'form.checkout' ).length === 0 ) { 260 return; 261 } 262 263 if ( validateAllRecipientEmails() ) { 264 updateCheckout(); 265 } 266 } ); 267 268 $( document ).on( 'keyup', '.recipient_email', function ( e ) { 269 const code = e.keyCode || e.which || 0; 270 271 if ( $( 'form.checkout' ).length === 0 || code === 9 ) { 272 return true; 273 } 274 275 const currentRecipient = $( this ).val(); 276 const originalRecipient = $( this ).attr( 'data-recipient' ); 277 resetCheckoutUpdateTimer(); 278 279 // If the recipient has changed since last load, mark the element as needing an update. 280 if ( currentRecipient !== originalRecipient ) { 281 $( this ).addClass( 'wcsg_needs_update' ); 282 // Only set timer if all emails are valid 283 if ( validateAllRecipientEmails( false ) ) { 284 updateTimer = setTimeout( updateCheckout, 1500 ); 285 } 286 } else { 287 $( this ).removeClass( 'wcsg_needs_update' ); 288 } 289 } ); 290 291 function updateCheckout() { 292 resetCheckoutUpdateTimer(); 293 $( '.recipient_email' ).removeClass( 'wcsg_needs_update' ); 294 $( document.body ).trigger( 'update_checkout' ); 295 } 296 297 function resetCheckoutUpdateTimer() { 298 clearTimeout( updateTimer ); 299 } 300 301 function setShippingAddressNoticeVisibility( hide = true ) { 302 const notice = $( 'form.checkout' ) 303 .find( '.woocommerce-shipping-fields' ) 304 .find( '.woocommerce-info' ); 305 306 if ( ! notice.length ) { 307 return; 308 } 309 310 if ( hide ) { 311 notice.css( { display: 'none' } ); 312 } else { 313 notice.css( { display: '' } ); 314 } 315 } 316 317 function isShortcodeCartOrCheckoutPage() { 318 return ( 319 $( 'form.woocommerce-cart-form' ).length > 0 || 320 $( 'form.woocommerce-checkout' ).length > 0 321 ); 322 } 323 324 function showValidationErrorForEmailField( $emailField ) { 325 $emailField.addClass( 'wcsg-email-error' ); 326 $emailField 327 .closest( '.wcsg_add_recipient_fields' )
328 .find( '.wc-shortcode-components-validation-error' ) 329 .show(); 330 } 331 332 function hideValidationErrorForEmailField( $emailField ) { 333 $emailField.removeClass( 'wcsg-email-error' ); 334 $emailField 335 .closest( '.wcsg_add_recipient_fields' ) 336 .find( '.wc-shortcode-components-validation-error' ) 337 .hide(); 338 } 339 340 // Triggers 341 $( '.woocommerce_subscription_gifting_checkbox[type="checkbox"]' ).trigger( 342 'change', 343 'pageload' 344 ); 345 346 // Validate all recipient emails on page load to set initial button state 347 $( document ).ready( function () { 348 setTimeout( function () { 349 // Only run validation on cart and checkout shortcode pages 350 if ( isShortcodeCartOrCheckoutPage() ) { 351 validateAllRecipientEmails(); 352 } 353 }, 1000 ); 354 } ); 355} );
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.