1/* global wc_stripe_payment_request_params, Stripe */ 2jQuery( function( $ ) { 3 'use strict'; 4 5 var stripe = Stripe( wc_stripe_payment_request_params.stripe.key, { 6 locale: wc_stripe_payment_request_params.stripe.locale 7 } ), 8 paymentRequestType; 9 10 /** 11 * Object to handle Stripe payment forms. 12 */ 13 var wc_stripe_payment_request = { 14 /** 15 * Get WC AJAX endpoint URL. 16 * 17 * @param {String} endpoint Endpoint. 18 * @return {String} 19 */ 20 getAjaxURL: function( endpoint ) { 21 return wc_stripe_payment_request_params.ajax_url 22 .toString() 23 .replace( '%%endpoint%%', 'wc_stripe_' + endpoint ); 24 }, 25 26 getCartDetails: function() { 27 var data = { 28 security: wc_stripe_payment_request_params.nonce.payment 29 }; 30 31 $.ajax( { 32 type: 'POST', 33 data: data, 34 url: wc_stripe_payment_request.getAjaxURL( 'get_cart_details' ), 35 success: function( response ) { 36 wc_stripe_payment_request.startPaymentRequest( response ); 37 } 38 } ); 39 }, 40 41 getAttributes: function() { 42 var select = $( '.variations_form' ).find( '.variations select' ), 43 data = {}, 44 count = 0, 45 chosen = 0; 46 47 select.each( function() { 48 var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' ); 49 var value = $( this ).val() || ''; 50 51 if ( value.length > 0 ) { 52 chosen ++; 53 } 54 55 count ++; 56 data[ attribute_name ] = value; 57 }); 58 59 return { 60 'count' : count, 61 'chosenCount': chosen, 62 'data' : data 63 }; 64 }, 65 66 processSource: function( source, paymentRequestType ) { 67 var data = wc_stripe_payment_request.getOrderData( source, paymentRequestType ); 68 69 return $.ajax( { 70 type: 'POST', 71 data: data, 72 dataType: 'json', 73 url: wc_stripe_payment_request.getAjaxURL( 'create_order' ) 74 } ); 75 }, 76 77 /** 78 * Get order data. 79 * 80 * @since 3.1.0 81 * @version 4.0.0 82 * @param {PaymentResponse} source Payment Response instance. 83 * 84 * @return {Object} 85 */ 86 getOrderData: function( evt, paymentRequestType ) { 87 var source = evt.source; 88 var email = source.owner.email; 89 var phone = source.owner.phone; 90 var billing = source.owner.address; 91 var name = source.owner.name; 92 var shipping = evt.shippingAddress; 93 var data = { 94 _wpnonce: wc_stripe_payment_request_params.nonce.checkout, 95 billing_first_name: null !== name ? name.split( ' ' ).slice( 0, 1 ).join( ' ' ) : '', 96 billing_last_name: null !== name ? name.split( ' ' ).slice( 1 ).join( ' ' ) : '', 97 billing_company: '', 98 billing_email: null !== email ? email : evt.payerEmail, 99 billing_phone: null !== phone ? phone : evt.payerPhone && evt.payerPhone.replace( '/[() -]/g', '' ), 100 billing_country: null !== billing ? billing.country : '', 101 billing_address_1: null !== billing ? billing.line1 : '', 102 billing_address_2: null !== billing ? billing.line2 : '', 103 billing_city: null !== billing ? billing.city : '', 104 billing_state: null !== billing ? billing.state : '', 105 billing_postcode: null !== billing ? billing.postal_code : '', 106 shipping_first_name: '', 107 shipping_last_name: '', 108 shipping_company: '', 109 shipping_country: '', 110 shipping_address_1: '', 111 shipping_address_2: '', 112 shipping_city: '', 113 shipping_state: '', 114 shipping_postcode: '', 115 shipping_method: [ null === evt.shippingOption ? null : evt.shippingOption.id ], 116 order_comments: '', 117 payment_method: 'stripe', 118 ship_to_different_address: 1, 119 terms: 1, 120 stripe_source: source.id, 121 payment_request_type: paymentRequestType 122 }; 123 124 if ( shipping ) { 125 data.shipping_first_name = shipping.recipient.split( ' ' ).slice( 0, 1 ).join( ' ' ); 126 data.shipping_last_name = shipping.recipient.split( ' ' ).slice( 1 ).join( ' ' ); 127 data.shipping_company = shipping.organization; 128 data.shipping_country = shipping.country; 129 data.shipping_address_1 = typeof shipping.addressLine[0] === 'undefined' ? '' : shipping.addressLine[0]; 130 data.shipping_address_2 = typeof shipping.addressLine[1] === 'undefined' ? '' : shipping.addressLine[1]; 131 data.shipping_city = shipping.city;
132 data.shipping_state = shipping.region; 133 data.shipping_postcode = shipping.postalCode; 134 } 135 136 return data; 137 }, 138 139 /** 140 * Generate error message HTML. 141 * 142 * @since 3.1.0 143 * @version 4.0.0 144 * @param {String} message Error message. 145 * @return {Object} 146 */ 147 getErrorMessageHTML: function( message ) { 148 return $( '<div class="woocommerce-error" />' ).text( message ); 149 }, 150 151 /** 152 * Display error messages. 153 * 154 * @since 4.8.0 155 * @param {Object} message DOM object with error message to display. 156 */ 157 displayErrorMessage: function( message ) { 158 $( '.woocommerce-error' ).remove(); 159 160 if ( wc_stripe_payment_request_params.is_product_page ) { 161 var element = $( '.product' ).first(); 162 element.before( message ); 163 164 $( 'html, body' ).animate({ 165 scrollTop: element.prev( '.woocommerce-error' ).offset().top 166 }, 600 ); 167 } else { 168 var $form = $( '.shop_table.cart' ).closest( 'form' ); 169 $form.before( message ); 170 $( 'html, body' ).animate({ 171 scrollTop: $form.prev( '.woocommerce-error' ).offset().top 172 }, 600 ); 173 } 174 }, 175 176 /** 177 * Abort payment and display error messages. 178 * 179 * @since 3.1.0 180 * @version 4.8.0 181 * @param {PaymentResponse} payment Payment response instance. 182 * @param {Object} message DOM object with error message to display. 183 */ 184 abortPayment: function( payment, message ) { 185 payment.complete( 'fail' ); 186 wc_stripe_payment_request.displayErrorMessage( message ); 187 }, 188 189 /** 190 * Complete payment. 191 * 192 * @since 3.1.0 193 * @version 4.0.0 194 * @param {PaymentResponse} payment Payment response instance. 195 * @param {String} url Order thank you page URL. 196 */ 197 completePayment: function( payment, url ) { 198 wc_stripe_payment_request.block(); 199 200 payment.complete( 'success' ); 201 202 // Success, then redirect to the Thank You page. 203 window.location = url; 204 }, 205 206 block: function() { 207 $.blockUI( { 208 message: null, 209 overlayCSS: { 210 background: '#fff', 211 opacity: 0.6 212 } 213 } ); 214 }, 215 216 /** 217 * Update shipping options. 218 * 219 * @param {Object} details Payment details. 220 * @param {PaymentAddress} address Shipping address. 221 */ 222 updateShippingOptions: function( details, address ) { 223 var data = { 224 security: wc_stripe_payment_request_params.nonce.shipping, 225 country: address.country, 226 state: address.region, 227 postcode: address.postalCode, 228 city: address.city, 229 address: typeof address.addressLine[0] === 'undefined' ? '' : address.addressLine[0], 230 address_2: typeof address.addressLine[1] === 'undefined' ? '' : address.addressLine[1], 231 payment_request_type: paymentRequestType, 232 is_product_page: wc_stripe_payment_request_params.is_product_page, 233 }; 234 235 return $.ajax( { 236 type: 'POST', 237 data: data, 238 url: wc_stripe_payment_request.getAjaxURL( 'get_shipping_options' ) 239 } ); 240 }, 241 242 /** 243 * Updates the shipping price and the total based on the shipping option. 244 * 245 * @param {Object} details The line items and shipping options. 246 * @param {String} shippingOption User's preferred shipping option to use for shipping price calculations. 247 */ 248 updateShippingDetails: function( details, shippingOption ) { 249 var data = { 250 security: wc_stripe_payment_request_params.nonce.update_shipping, 251 shipping_method: [ shippingOption.id ], 252 payment_request_type: paymentRequestType, 253 is_product_page: wc_stripe_payment_request_params.is_product_page, 254 }; 255 256 return $.ajax( { 257 type: 'POST', 258 data: data, 259 url: wc_stripe_payment_request.getAjaxURL( 'update_shipping_method' ) 260 } ); 261 }, 262 263 /** 264 * Adds the item to the cart and return cart details. 265 * 266 */ 267 addToCart: function() { 268 var product_id = $( '.single_add_to_cart_button' ).val(); 269 270 // Check if product is a variable product. 271 if ( $( '.single_variation_wrap' ).length ) { 272 product_id = $( '.single_variation_wrap' ).find( 'input[name="product_id"]' ).val(); 273 } 274 275 var data = { 276 security: wc_stripe_payment_request_params.nonce.add_to_cart, 277 product_id: product_id, 278 qty: $( '.quantity .qty' ).val(), 279 attributes: $( '.variations_form' ).length ? wc_stripe_payment_request.getAttributes().data : [] 280 }; 281 282 // add addons data to the POST body
283 var formData = $( 'form.cart' ).serializeArray(); 284 $.each( formData, function( i, field ) { 285 if ( /^addon-/.test( field.name ) ) { 286 if ( /\[\]$/.test( field.name ) ) { 287 var fieldName = field.name.substring( 0, field.name.length - 2); 288 if ( data[ fieldName ] ) { 289 data[ fieldName ].push( field.value ); 290 } else { 291 data[ fieldName ] = [ field.value ]; 292 } 293 } else { 294 data[ field.name ] = field.value; 295 } 296 } 297 } ); 298 299 return $.ajax( { 300 type: 'POST', 301 data: data, 302 url: wc_stripe_payment_request.getAjaxURL( 'add_to_cart' ) 303 } ); 304 }, 305 306 clearCart: function() { 307 var data = { 308 'security': wc_stripe_payment_request_params.nonce.clear_cart 309 }; 310 311 return $.ajax( { 312 type: 'POST', 313 data: data, 314 url: wc_stripe_payment_request.getAjaxURL( 'clear_cart' ), 315 success: function( response ) {} 316 } ); 317 }, 318 319 getRequestOptionsFromLocal: function() { 320 return { 321 total: wc_stripe_payment_request_params.product.total, 322 currency: wc_stripe_payment_request_params.checkout.currency_code, 323 country: wc_stripe_payment_request_params.checkout.country_code, 324 requestPayerName: true, 325 requestPayerEmail: true, 326 requestPayerPhone: wc_stripe_payment_request_params.checkout.needs_payer_phone, 327 requestShipping: wc_stripe_payment_request_params.product.requestShipping, 328 displayItems: wc_stripe_payment_request_params.product.displayItems 329 }; 330 }, 331 332 /** 333 * Starts the payment request 334 * 335 * @since 4.0.0 336 * @version 4.8.0 337 */ 338 startPaymentRequest: function( cart ) { 339 var paymentDetails, 340 options; 341 342 if ( wc_stripe_payment_request_params.is_product_page ) { 343 options = wc_stripe_payment_request.getRequestOptionsFromLocal(); 344 345 paymentDetails = options; 346 } else { 347 options = { 348 total: cart.order_data.total, 349 currency: cart.order_data.currency, 350 country: cart.order_data.country_code, 351 requestPayerName: true, 352 requestPayerEmail: true, 353 requestPayerPhone: wc_stripe_payment_request_params.checkout.needs_payer_phone, 354 requestShipping: cart.shipping_required ? true : false, 355 displayItems: cart.order_data.displayItems 356 }; 357 358 paymentDetails = cart.order_data; 359 } 360 361 // Puerto Rico (PR) is the only US territory/possession that's supported by Stripe. 362 // Since it's considered a US state by Stripe, we need to do some special mapping. 363 if ( 'PR' === options.country ) { 364 options.country = 'US'; 365 } 366 367 // Handle errors thrown by Stripe, so we don't break the product page 368 try { 369 var paymentRequest = stripe.paymentRequest( options ); 370 371 var elements = stripe.elements( { locale: wc_stripe_payment_request_params.button.locale } ); 372 var prButton = wc_stripe_payment_request.createPaymentRequestButton( elements, paymentRequest ); 373 374 // Check the availability of the Payment Request API first. 375 paymentRequest.canMakePayment().then( function( result ) { 376 if ( ! result ) { 377 return; 378 } 379 if ( result.applePay ) { 380 paymentRequestType = 'apple_pay'; 381 } else if ( result.googlePay ) { 382 paymentRequestType = 'google_pay'; 383 } else { 384 paymentRequestType = 'payment_request_api'; 385 } 386 387 wc_stripe_payment_request.attachPaymentRequestButtonEventListeners( prButton, paymentRequest ); 388 wc_stripe_payment_request.showPaymentRequestButton( prButton ); 389 } ); 390 391 // Possible statuses success, fail, invalid_payer_name, invalid_payer_email, invalid_payer_phone, invalid_shipping_address. 392 paymentRequest.on( 'shippingaddresschange', function( evt ) { 393 $.when( wc_stripe_payment_request.updateShippingOptions( paymentDetails, evt.shippingAddress ) ).then( function( response ) { 394 evt.updateWith( { status: response.result, shippingOptions: response.shipping_options, total: response.total, displayItems: response.displayItems } ); 395 } ); 396 } ); 397 398 paymentRequest.on( 'shippingoptionchange', function( evt ) { 399 $.when( wc_stripe_payment_request.updateShippingDetails( paymentDetails, evt.shippingOption ) ).then( function( response ) { 400 if ( 'success' === response.result ) { 401 evt.updateWith( { status: 'success', total: response.total, displayItems: response.displayItems } ); 402 } 403 404 if ( 'fail' === response.result ) { 405 evt.updateWith( { status: 'fail' } ); 406 } 407 } ); 408 } ); 409 410 paymentRequest.on( 'source', function( evt ) { 411 // Check if we allow prepaid cards.
412 if ( 'no' === wc_stripe_payment_request_params.stripe.allow_prepaid_card && 'prepaid' === evt.source.card.funding ) { 413 wc_stripe_payment_request.abortPayment( evt, wc_stripe_payment_request.getErrorMessageHTML( wc_stripe_payment_request_params.i18n.no_prepaid_card ) ); 414 } else { 415 $.when( wc_stripe_payment_request.processSource( evt, paymentRequestType ) ).then( function( response ) { 416 if ( 'success' === response.result ) { 417 wc_stripe_payment_request.completePayment( evt, response.redirect ); 418 } else { 419 wc_stripe_payment_request.abortPayment( evt, response.messages ); 420 } 421 } ); 422 } 423 } ); 424 } catch( e ) { 425 // Leave for troubleshooting 426 console.error( e ); 427 } 428 }, 429 430 getSelectedProductData: function() { 431 var product_id = $( '.single_add_to_cart_button' ).val(); 432 433 // Check if product is a variable product. 434 if ( $( '.single_variation_wrap' ).length ) { 435 product_id = $( '.single_variation_wrap' ).find( 'input[name="product_id"]' ).val(); 436 } 437 438 var addons = $( '#product-addons-total' ).data('price_data') || []; 439 var addon_value = addons.reduce( function ( sum, addon ) { return sum + addon.cost; }, 0 ); 440 441 var data = { 442 security: wc_stripe_payment_request_params.nonce.get_selected_product_data, 443 product_id: product_id, 444 qty: $( '.quantity .qty' ).val(), 445 attributes: $( '.variations_form' ).length ? wc_stripe_payment_request.getAttributes().data : [], 446 addon_value: addon_value, 447 }; 448 449 return $.ajax( { 450 type: 'POST', 451 data: data, 452 url: wc_stripe_payment_request.getAjaxURL( 'get_selected_product_data' ) 453 } ); 454 }, 455 456 /** 457 * Creates a wrapper around a function that ensures a function can not 458 * called in rappid succesion. The function can only be executed once and then agin after 459 * the wait time has expired. Even if the wrapper is called multiple times, the wrapped 460 * function only excecutes once and then blocks until the wait time expires. 461 * 462 * @param {int} wait Milliseconds wait for the next time a function can be executed. 463 * @param {function} func The function to be wrapped. 464 * @param {bool} immediate Overriding the wait time, will force the function to fire everytime. 465 * 466 * @return {function} A wrapped function with execution limited by the wait time. 467 */ 468 debounce: function( wait, func, immediate ) { 469 var timeout; 470 return function() { 471 var context = this, args = arguments; 472 var later = function() { 473 timeout = null; 474 if (!immediate) func.apply(context, args); 475 }; 476 var callNow = immediate && !timeout; 477 clearTimeout(timeout); 478 timeout = setTimeout(later, wait); 479 if (callNow) func.apply(context, args); 480 }; 481 }, 482 483 /** 484 * Creates stripe paymentRequest element or connects to custom button 485 * 486 * @param {object} elements Stripe elements instance. 487 * @param {object} paymentRequest Stripe paymentRequest object. 488 * 489 * @return {object} Stripe paymentRequest element or custom button jQuery element. 490 */ 491 createPaymentRequestButton: function( elements, paymentRequest ) { 492 var button; 493 if ( wc_stripe_payment_request_params.button.is_custom ) { 494 button = $( wc_stripe_payment_request_params.button.css_selector ); 495 if ( button.length ) { 496 // We fallback to default paymentRequest button if no custom button is found in the UI. 497 // Add flag to be sure that created button is custom button rather than fallback element. 498 button.data( 'isCustom', true ); 499 return button; 500 } 501 } 502 503 if ( wc_stripe_payment_request_params.button.is_branded ) { 504 if ( wc_stripe_payment_request.shouldUseGooglePayBrand() ) { 505 button = wc_stripe_payment_request.createGooglePayButton(); 506 // Add flag to be sure that created button is branded rather than fallback element. 507 button.data( 'isBranded', true ); 508 return button; 509 } else { 510 // Not implemented branded buttons default to Stripe's button 511 // Apple Pay buttons can also fall back to Stripe's button, as it's already branded 512 // Set button type to default or buy, depending on branded type, to avoid issues with Stripe 513 wc_stripe_payment_request_params.button.type = 'long' === wc_stripe_payment_request_params.button.branded_type ? 'buy' : 'default'; 514 } 515 } 516 517 return elements.create( 'paymentRequestButton', { 518 paymentRequest: paymentRequest, 519 style: { 520 paymentRequestButton: {
521 type: wc_stripe_payment_request_params.button.type, 522 theme: wc_stripe_payment_request_params.button.theme, 523 height: wc_stripe_payment_request_params.button.height + 'px', 524 }, 525 }, 526 } ); 527 }, 528 529 /** 530 * Checks if button is custom payment request button. 531 * 532 * @param {object} prButton Stripe paymentRequest element or custom jQuery element. 533 * 534 * @return {boolean} True when prButton is custom button jQuery element. 535 */ 536 isCustomPaymentRequestButton: function ( prButton ) { 537 return prButton && 'function' === typeof prButton.data && prButton.data( 'isCustom' ); 538 }, 539 540 isBrandedPaymentRequestButton: function ( prButton ) { 541 return prButton && 'function' === typeof prButton.data && prButton.data( 'isBranded' ); 542 }, 543 544 shouldUseGooglePayBrand: function () { 545 var ua = window.navigator.userAgent.toLowerCase(); 546 var isChrome = /chrome/.test( ua ) && ! /edge|edg|opr|brave\//.test( ua ) && 'Google Inc.' === window.navigator.vendor; 547 // newer versions of Brave do not have the userAgent string 548 var isBrave = isChrome && window.navigator.brave; 549 return isChrome && ! isBrave; 550 }, 551 552 createGooglePayButton: function () { 553 var allowedThemes = [ 'dark', 'light', 'light-outline' ]; 554 var allowedTypes = [ 'short', 'long' ]; 555 556 var theme = wc_stripe_payment_request_params.button.theme; 557 var type = wc_stripe_payment_request_params.button.branded_type; 558 var locale = wc_stripe_payment_request_params.button.locale; 559 var height = wc_stripe_payment_request_params.button.height; 560 theme = allowedThemes.includes( theme ) ? theme : 'light'; 561 var gpaySvgTheme = 'dark' === theme ? 'dark' : 'light'; 562 type = allowedTypes.includes( type ) ? type : 'long'; 563 564 var button = $( '<button type="button" id="wc-stripe-branded-button" aria-label="Google Pay" class="gpay-button"></button>' ); 565 button.css( 'height', height + 'px' ); 566 button.addClass( theme + ' ' + type ); 567 if ( 'long' === type ) { 568 var url = 'https://www.gstatic.com/instantbuy/svg/' + gpaySvgTheme + '/' + locale + '.svg'; 569 var fallbackUrl = 'https://www.gstatic.com/instantbuy/svg/' + gpaySvgTheme + '/en.svg'; 570 // Check if locale GPay button exists, default to en if not 571 setBackgroundImageWithFallback( button, url, fallbackUrl ); 572 } 573 574 return button; 575 }, 576 577 attachPaymentRequestButtonEventListeners: function( prButton, paymentRequest ) { 578 // First, mark the body so we know a payment request button was used. 579 // This way error handling can any display errors in the most appropriate place. 580 prButton.on( 'click', function ( evt ) { 581 $( 'body' ).addClass( 'woocommerce-stripe-prb-clicked' ); 582 }); 583 584 // Then, attach specific handling for selected pages and button types 585 if ( wc_stripe_payment_request_params.is_product_page ) { 586 wc_stripe_payment_request.attachProductPageEventListeners( prButton, paymentRequest ); 587 } else { 588 wc_stripe_payment_request.attachCartPageEventListeners( prButton, paymentRequest ); 589 } 590 }, 591 592 attachProductPageEventListeners: function( prButton, paymentRequest ) { 593 var paymentRequestError = []; 594 var addToCartButton = $( '.single_add_to_cart_button' ); 595 596 prButton.on( 'click', function ( evt ) { 597 // If login is required for checkout, display redirect confirmation dialog. 598 if ( wc_stripe_payment_request_params.login_confirmation ) { 599 evt.preventDefault(); 600 displayLoginConfirmation( paymentRequestType ); 601 return; 602 } 603 604 // First check if product can be added to cart. 605 if ( addToCartButton.is( '.disabled' ) ) { 606 evt.preventDefault(); // Prevent showing payment request modal. 607 if ( addToCartButton.is( '.wc-variation-is-unavailable' ) ) { 608 window.alert( wc_add_to_cart_variation_params.i18n_unavailable_text ); 609 } else if ( addToCartButton.is( '.wc-variation-selection-needed' ) ) { 610 window.alert( wc_add_to_cart_variation_params.i18n_make_a_selection_text ); 611 } 612 return; 613 } 614 615 if ( 0 < paymentRequestError.length ) { 616 evt.preventDefault(); 617 window.alert( paymentRequestError ); 618 return; 619 } 620 621 wc_stripe_payment_request.addToCart(); 622 623 if ( wc_stripe_payment_request.isCustomPaymentRequestButton( prButton ) || wc_stripe_payment_request.isBrandedPaymentRequestButton( prButton ) ) { 624 evt.preventDefault(); 625 paymentRequest.show(); 626 } 627 }); 628 629 $( document.body ).on( 'wc_stripe_unblock_payment_request_button wc_stripe_enable_payment_request_button', function () { 630 wc_stripe_payment_request.unblockPaymentRequestButton(); 631 } ); 632 633 $( document.body ).on( 'wc_stripe_block_payment_request_button', function () { 634 wc_stripe_payment_request.blockPaymentRequestButton( 'wc_request_button_is_blocked' ); 635 } ); 636 637 $( document.body ).on( 'wc_stripe_disable_payment_request_button', function () { 638 wc_stripe_payment_request.blockPaymentRequestButton( 'wc_request_button_is_disabled' ); 639 } ); 640 641 $( document.body ).on( 'woocommerce_variation_has_changed', function () { 642 $( document.body ).trigger( 'wc_stripe_block_payment_request_button' ); 643 644 $.when( wc_stripe_payment_request.getSelectedProductData() ).then( function ( response ) { 645 $.when( 646 paymentRequest.update( { 647 total: response.total, 648 displayItems: response.displayItems, 649 } ) 650 ).then( function () { 651 $( document.body ).trigger( 'wc_stripe_unblock_payment_request_button' ); 652 } ); 653 }); 654 } ); 655 656 // Block the payment request button as soon as an "input" event is fired, to avoid sync issues 657 // when the customer clicks on the button before the debounced event is processed. 658 $( '.quantity' ).on( 'input', '.qty', function() { 659 $( document.body ).trigger( 'wc_stripe_block_payment_request_button' ); 660 } ); 661 662 $( '.quantity' ).on( 'input', '.qty', wc_stripe_payment_request.debounce( 250, function() { 663 $( document.body ).trigger( 'wc_stripe_block_payment_request_button' ); 664 paymentRequestError = []; 665 666 $.when( wc_stripe_payment_request.getSelectedProductData() ).then( function ( response ) { 667 if ( response.error ) { 668 paymentRequestError = [ response.error ]; 669 $( document.body ).trigger( 'wc_stripe_unblock_payment_request_button' ); 670 } else { 671 $.when( 672 paymentRequest.update( { 673 total: response.total, 674 displayItems: response.displayItems, 675 } ) 676 ).then( function () { 677 $( document.body ).trigger( 'wc_stripe_unblock_payment_request_button' ); 678 }); 679 } 680 } ); 681 })); 682 683 if ( $('.variations_form').length ) { 684 $( '.variations_form' ).on( 'found_variation.wc-variation-form', function ( evt, variation ) { 685 if ( variation.is_in_stock ) { 686 wc_stripe_payment_request.unhidePaymentRequestButton(); 687 } else { 688 wc_stripe_payment_request.hidePaymentRequestButton(); 689 } 690 } ); 691 } 692 }, 693 694 attachCartPageEventListeners: function ( prButton, paymentRequest ) { 695 prButton.on( 'click', function ( evt ) { 696 // If login is required for checkout, display redirect confirmation dialog. 697 if ( wc_stripe_payment_request_params.login_confirmation ) { 698 evt.preventDefault(); 699 displayLoginConfirmation( paymentRequestType ); 700 return; 701 } 702 703 if ( 704 wc_stripe_payment_request.isCustomPaymentRequestButton( 705 prButton 706 ) || 707 wc_stripe_payment_request.isBrandedPaymentRequestButton( 708 prButton 709 ) 710 ) { 711 evt.preventDefault(); 712 paymentRequest.show(); 713 } 714 } ); 715 }, 716 717 showPaymentRequestButton: function( prButton ) { 718 if ( wc_stripe_payment_request.isCustomPaymentRequestButton( prButton ) ) { 719 prButton.addClass( 'is-active' ); 720 $( '#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator' ).show(); 721 } else if ( wc_stripe_payment_request.isBrandedPaymentRequestButton( prButton ) ) { 722 $( '#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator' ).show(); 723 $( '#wc-stripe-payment-request-button' ).html( prButton ); 724 } else if ( $( '#wc-stripe-payment-request-button' ).length ) { 725 $( '#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator' ).show(); 726 prButton.mount( '#wc-stripe-payment-request-button' ); 727 } 728 }, 729 730 hidePaymentRequestButton: function () { 731 $( '#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator' ).hide(); 732 }, 733 734 unhidePaymentRequestButton: function () { 735 const stripe_wrapper = $( '#wc-stripe-payment-request-wrapper' ); 736 const stripe_separator = $( '#wc-stripe-payment-request-button-separator' ); 737 // If either element is hidden, ensure both show.
738 if ( stripe_wrapper.is(':hidden') || stripe_separator.is(':hidden') ) { 739 stripe_wrapper.show(); 740 stripe_separator.show(); 741 } 742 }, 743 744 blockPaymentRequestButton: function( cssClassname ) { 745 // check if element isn't already blocked before calling block() to avoid blinking overlay issues 746 // blockUI.isBlocked is either undefined or 0 when element is not blocked 747 if ( $( '#wc-stripe-payment-request-button' ).data( 'blockUI.isBlocked' ) ) { 748 return; 749 } 750 751 $( '#wc-stripe-payment-request-button' ) 752 .addClass( cssClassname ) 753 .block( { message: null } ); 754 }, 755 756 unblockPaymentRequestButton: function() { 757 $( '#wc-stripe-payment-request-button' ) 758 .removeClass( ['wc_request_button_is_blocked', 'wc_request_button_is_disabled'] ) 759 .unblock(); 760 }, 761 762 /** 763 * Initialize event handlers and UI state 764 * 765 * @since 4.0.0 766 * @version 4.0.0 767 */ 768 init: function() { 769 if ( wc_stripe_payment_request_params.is_product_page ) { 770 wc_stripe_payment_request.startPaymentRequest( '' ); 771 } else { 772 wc_stripe_payment_request.getCartDetails(); 773 } 774 775 }, 776 }; 777 778 wc_stripe_payment_request.init(); 779 780 // We need to refresh payment request data when total is updated. 781 $( document.body ).on( 'updated_cart_totals', function() { 782 wc_stripe_payment_request.init(); 783 } ); 784 785 // We need to refresh payment request data when total is updated. 786 $( document.body ).on( 'updated_checkout', function() { 787 wc_stripe_payment_request.init(); 788 } ); 789 790 function setBackgroundImageWithFallback( element, background, fallback ) { 791 element.css( 'background-image', 'url(' + background + ')' ); 792 // Need to use an img element to avoid CORS issues 793 var testImg = document.createElement("img"); 794 testImg.onerror = function () { 795 element.css( 'background-image', 'url(' + fallback + ')' ); 796 } 797 testImg.src = background; 798 } 799 800 // TODO: Replace this by `client/blocks/payment-request/login-confirmation.js` 801 // when we start using webpack to build this file. 802 function displayLoginConfirmation( paymentRequestType ) { 803 if ( ! wc_stripe_payment_request_params.login_confirmation ) { 804 return; 805 } 806 807 var message = wc_stripe_payment_request_params.login_confirmation.message; 808 809 // Replace dialog text with specific payment request type "Apple Pay" or "Google Pay". 810 if ( 'payment_request_api' !== paymentRequestType ) { 811 message = message.replace( 812 /\*\*.*?\*\*/, 813 'apple_pay' === paymentRequestType ? 'Apple Pay' : 'Google Pay' 814 ); 815 } 816 817 // Remove asterisks from string. 818 message = message.replace( /\*\*/g, '' ); 819 820 if ( confirm( message ) ) { 821 // Redirect to my account page. 822 window.location.href = wc_stripe_payment_request_params.login_confirmation.redirect_url; 823 } 824 } 825} );
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.