1( function( $ ) { 2 3 $(document).ready( function() { 4 5 if ( ! leaky_paywall_stripe_registration_ajax.stripe_pk ) { 6 return; 7 } 8 9 let stripe = Stripe(leaky_paywall_stripe_registration_ajax.stripe_pk); 10 11 if ( leaky_paywall_stripe_registration_ajax.client_id ) { 12 stripe = Stripe(leaky_paywall_stripe_registration_ajax.stripe_pk, { stripeAccount: leaky_paywall_stripe_registration_ajax.client_id}); 13 } 14 15 let elements; 16 let billingAddress = null; 17 18 // Stripe Checkout 19 $('#checkout').click(function(e) { 20 e.preventDefault(); 21 $(this).text(leaky_paywall_stripe_registration_ajax.continue_text); 22 $("#leaky-paywall-registration-errors").html(""); 23 validateUserData(); 24 }); 25 26 // one time and recurring 27 $("#leaky-paywall-registration-next").click(function () { 28 $(this).text(leaky_paywall_stripe_registration_ajax.continue_text).prop('disabled', true); 29 $("#leaky-paywall-registration-errors").html(""); 30 validateUserData(); 31 }); 32 33 // Intercept Enter key during step 1 (account setup) â prevents native form submission 34 // which would bypass AJAX validation and fail server-side with no payment intent. 35 document.querySelector("#leaky-paywall-payment-form") && document.querySelector("#leaky-paywall-payment-form").addEventListener("submit", function(e) { 36 if ($(".leaky-paywall-form-account-setup-step").hasClass("active")) { 37 e.preventDefault(); 38 $("#leaky-paywall-registration-next").text(leaky_paywall_stripe_registration_ajax.continue_text); 39 $("#leaky-paywall-registration-errors").html(""); 40 validateUserData(); 41 } 42 }); 43 44 45 function validateUserData() { 46 47 $("#leaky-paywall-registration-errors").html(""); 48 49 const form_data = $("#leaky-paywall-payment-form").serialize(); 50 51 const data = { 52 action: "leaky_paywall_process_user_registration_validation", 53 form_data: form_data, 54 nonce: leaky_paywall_stripe_registration_ajax.register_nonce 55 }; 56 57 $.post(leaky_paywall_stripe_registration_ajax.ajaxurl, data, function (resp) { 58 59 if (resp.errors) { 60 $.each(resp.errors, function (i, value) { 61 $("#leaky-paywall-registration-errors").append( 62 "<p class='leaky-paywall-registration-error'>" + 63 value.message + 64 "</p>" 65 ); 66 $("#leaky-paywall-registration-next").text( leaky_paywall_stripe_registration_ajax.next_text ).prop('disabled', false); 67 $("#leaky-paywall-registration-errors").show(); 68 69 $("html, body").animate( 70 { 71 scrollTop: $(".leaky-paywall-registration-error").offset().top, 72 }, 73 1000 74 ); 75 }); 76 77 } else { 78 79 if ( resp.subscription_updated ) { 80 // Existing subscription was updated to new plan, submit form directly 81 let form$ = jQuery('#leaky-paywall-payment-form'); 82 form$.get(0).submit(); 83 } else if ( resp.session_id ) { 84 // stripe checkout 85 stripe.redirectToCheckout({ 86 sessionId: resp.session_id 87 }); 88 } else if (resp.pi_client) { 89 // one time payment 90 $("#payment-intent-client").val(resp.pi_client); 91 $("#payment-intent-id").val(resp.pi_id); 92 93 buildPaymentForm(resp.pi_client); 94 showPaymentForm(); 95 96 // Handle form submission. 97 document.querySelector("#leaky-paywall-payment-form").addEventListener("submit", handleSubmit); 98 99 } else if (resp.deferred_tax) { 100 // subscription with automatic tax â defer subscription creation until address is entered 101 $("#stripe-customer-id").val(resp.customer_id); 102 buildAddressOnly();
103 showPaymentForm(); 104 105 } else if (resp.customer_id) { 106 // subscription 107 $("#stripe-customer-id").val(resp.customer_id); 108 109 buildPaymentForm(resp.client_secret); 110 showPaymentForm(); 111 112 // Handle form submission. 113 document.querySelector("#leaky-paywall-payment-form").addEventListener("submit", handleSubmit); 114 115 } 116 117 } 118 119 }); 120 121 }; // end validate user data 122 123 let addressElementMounted = false; 124 125 function mountAddressElement( elementsInstance ) { 126 const addressElement = elementsInstance.create("address", { 127 mode: "billing", 128 }); 129 130 addressElement.mount("#address-element"); 131 addressElementMounted = true; 132 133 addressElement.on('change', (event) => { 134 if (event.complete) { 135 billingAddress = event.value; 136 $('input[name="lp_billing_name"]').val(billingAddress.name || ''); 137 $('input[name="lp_billing_line1"]').val(billingAddress.address.line1 || ''); 138 $('input[name="lp_billing_line2"]').val(billingAddress.address.line2 || ''); 139 $('input[name="lp_billing_city"]').val(billingAddress.address.city || ''); 140 $('input[name="lp_billing_state"]').val(billingAddress.address.state || ''); 141 $('input[name="lp_billing_postal_code"]').val(billingAddress.address.postal_code || ''); 142 $('input[name="lp_billing_country"]').val(billingAddress.address.country || ''); 143 144 if ( 'on' === leaky_paywall_stripe_registration_ajax.automatic_tax_enabled ) { 145 fetchTaxPreview(billingAddress.address); 146 } 147 } 148 }); 149 } 150 151 function buildAddressOnly() { 152 // For deferred tax flow: mount only the address element first, without a clientSecret. 153 var standaloneElements = stripe.elements(); 154 mountAddressElement( standaloneElements ); 155 } 156 157 function buildPaymentForm( clientSecret ) { 158 159 elements = stripe.elements({ clientSecret }); 160 161 const paymentElementOptions = { 162 layout: "tabs", 163 }; 164 165 const paymentElement = elements.create("payment", paymentElementOptions); 166 167 // Temporarily lock scroll position while Stripe Element mounts to prevent layout shift. 168 var scrollPos = $(window).scrollTop(); 169 paymentElement.mount("#payment-element"); 170 $(window).scrollTop(scrollPos); 171 172 if ( 'on' == leaky_paywall_stripe_registration_ajax.billing_address && !addressElementMounted ) { 173 mountAddressElement( elements ); 174 } 175 176 } 177 178 function showPaymentForm() { 179 180 setTimeout(() => { 181 $("#leaky-paywall-registration-errors").hide(); 182 $("#leaky-paywall-registration-next").remove(); 183 $(".leaky-paywall-registration-user-container").hide(); 184 $(".leaky-paywall-form-payment-setup-step").addClass("active"); 185 $(".leaky-paywall-form-account-setup-step").removeClass("active"); 186 187 $(".leaky-paywall-registration-payment-container").slideDown(); 188 189 if ( 'on' === leaky_paywall_stripe_registration_ajax.automatic_tax_enabled ) { 190 showInitialOrderSummary(); 191 } 192 193 $("html, body").animate( 194 { 195 scrollTop: $(".leaky-paywall-form-steps").offset().top, 196 }, 197 1000 198 ); 199 }, 500); 200 201 } 202 203 function showInitialOrderSummary() { 204 var price = $('input[name="level_price"]').val(); 205 var currency = $('input[name="currency"]').val() || 'USD'; 206 var formatter = formatCurrency(currency); 207 var subtotal = Math.round(parseFloat(price) * 100); 208 209 $('#lp-order-subtotal-amount').text(formatter(subtotal)); 210 $('#lp-order-tax-amount').text('â').addClass('lp-order-pending'); 211 $('#lp-order-total-amount').text('â'); 212 $('#lp-order-summary').slideDown(); 213 } 214 215 var taxPreviewRequest = null; 216 217 function fetchTaxPreview(address) { 218 var levelId = $('input[name="level_id"]').val(); 219 var customerId = $('#stripe-customer-id').val() || ''; 220 221 // Abort any in-flight request. 222 if ( taxPreviewRequest ) { 223 taxPreviewRequest.abort(); 224 } 225 226 $('#lp-order-tax-amount').text('Calculating...').addClass('lp-order-pending'); 227 $('#leaky-paywall-submit').prop('disabled', true); 228 229 taxPreviewRequest = $.ajax({ 230 url: leaky_paywall_stripe_registration_ajax.ajaxurl, 231 type: 'POST', 232 dataType: 'json', 233 data: { 234 action: 'leaky_paywall_stripe_tax_preview', 235 nonce: leaky_paywall_stripe_registration_ajax.tax_preview_nonce, 236 level_id: levelId, 237 customer_id: customerId, 238 line1: address.line1 || '', 239 city: address.city || '', 240 state: address.state || '', 241 postal_code: address.postal_code || '', 242 country: address.country || '' 243 }, 244 success: function(response) { 245 jQuery('#leaky-paywall-submit').prop('disabled', false); 246 if (response.success) { 247 var data = response.data; 248 var formatter = formatCurrency(data.currency); 249 jQuery('#lp-order-subtotal-amount').text(formatter(data.subtotal)); 250 jQuery('#lp-order-tax-amount').text(formatter(data.tax)).removeClass('lp-order-pending'); 251 jQuery('#lp-order-total-amount').text(formatter(data.total)); 252 253 // Build payment form now that subscription is created with tax. 254 if (data.client_secret && !jQuery('#payment-element .StripeElement, #payment-element iframe').length) { 255 buildPaymentForm(data.client_secret); 256 document.querySelector("#leaky-paywall-payment-form").addEventListener("submit", handleSubmit); 257 } 258 } else { 259 jQuery('#lp-order-tax-amount').text('$0.00').removeClass('lp-order-pending'); 260 } 261 }, 262 error: function(xhr, status, err) { 263 jQuery('#leaky-paywall-submit').prop('disabled', false); 264 jQuery('#lp-order-tax-amount').text('$0.00').removeClass('lp-order-pending'); 265 } 266 }); 267 } 268 269 function formatCurrency(currency) { 270 return function(amountInCents) { 271 return new Intl.NumberFormat(undefined, { 272 style: 'currency', 273 currency: currency 274 }).format(amountInCents / 100); 275 }; 276 } 277 278 279 async function handleSubmit(e) { 280 e.preventDefault(); 281 282 let subButton = document.getElementById('leaky-paywall-submit'); 283 let emailAddress = $('input[name="email_address"]').val(); 284 let isTrial = $('input[name="is_trial"]').val(); 285 let paymentMethod = $('input[name="payment_method"]:checked').val(); 286 287 if ( paymentMethod != 'stripe' ) { 288 let form$ = jQuery('#leaky-paywall-payment-form'); 289 form$.get(0).submit(); 290 return; 291 } 292 293 subButton.disabled = true; 294 subButton.innerHTML = leaky_paywall_stripe_registration_ajax.continue_text; 295 296 if ( isTrial ) { 297 const { error }
297 = await stripe.confirmSetup({ 298 elements, 299 confirmParams: { 300 return_url: leaky_paywall_stripe_registration_ajax.redirect_url, 301 }, 302 redirect: 'if_required' 303 }); 304 305 if ( error ) { 306 if (error.type === "card_error" || error.type === "validation_error") { 307 showMessage(error.message); 308 } else { 309 showMessage("An unexpected error occurred."); 310 } 311 resetSubButton(); 312 } else { 313 let form$ = jQuery('#leaky-paywall-payment-form'); 314 form$.get(0).submit(); 315 } 316 317 } else { 318 const { error, paymentIntent } = await stripe.confirmPayment({ 319 elements, 320 confirmParams: { 321 // Make sure to change this to your payment completion page 322 return_url: leaky_paywall_stripe_registration_ajax.redirect_url, 323 receipt_email: emailAddress, 324 }, 325 redirect: 'if_required' 326 }); 327 328 if (paymentIntent && paymentIntent.id) { 329 330 if ( paymentIntent.status == 'succeeded') { 331 let form$ = jQuery('#leaky-paywall-payment-form'); 332 form$.get(0).submit(); 333 } else { 334 resetSubButton(); 335 } 336 337 } 338 339 if ( error ) { 340 if (error.type === "card_error" || error.type === "validation_error") { 341 showMessage(error.message); 342 } else { 343 showMessage("An unexpected error occurred."); 344 } 345 resetSubButton(); 346 } 347 } 348 349 // This point will only be reached if there is an immediate error when 350 // confirming the payment. Otherwise, your customer will be redirected to 351 // your `return_url`. For some payment methods like iDEAL, your customer will 352 // be redirected to an intermediate site first to authorize the payment, then 353 // redirected to the `return_url`. 354 355 356 357 358 // setLoading(false); 359 } 360 361 function showMessage(messageText) { 362 const messageContainer = document.querySelector("#payment-message"); 363 364 messageContainer.classList.remove("hidden"); 365 messageContainer.textContent = messageText; 366 367 setTimeout(function () { 368 messageContainer.classList.add("hidden"); 369 messageContainer.textContent = ""; 370 }, 7000); 371 } 372 373 function resetSubButton() { 374 let subButton = document.getElementById('leaky-paywall-submit'); 375 subButton.disabled = false; 376 subButton.innerHTML = 'Subscribe'; 377 } 378 379 380 }); // doc ready 381 382})( 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.