form.js
722 lines
| 1 | /* globals jQuery, Give */ |
| 2 | ( function( $ ) { |
| 3 | const templateOptions = window.sequoiaTemplateOptions; |
| 4 | const $container = $( '.give-embed-form' ); |
| 5 | const $advanceButton = $( '.advance-btn', $container ); |
| 6 | const $backButton = $( '.back-btn' ); |
| 7 | const $navigatorTitle = $( '.give-form-navigator .title' ); |
| 8 | const $paymentGatewayContainer = $( '#give-payment-mode-select' ); |
| 9 | let gatewayAnimating = false; |
| 10 | |
| 11 | const navigator = { |
| 12 | currentStep: templateOptions.introduction.enabled === 'enabled' ? 0 : 1, |
| 13 | animating: false, |
| 14 | goToStep: ( step ) => { |
| 15 | // Adjust body height before animating step, to prevent choppy iframe resizing |
| 16 | // Compare next step to current step, and increase body height if next step is taller. |
| 17 | const nextStepHeight = steps[ step ].title ? $( steps[ step ].selector ).height() + 50 : $( steps[ step ].selector ).height(); |
| 18 | const currentStepHeight = steps[ navigator.currentStep ].title ? $( steps[ navigator.currentStep ].selector ).height() + 50 : $( steps[ navigator.currentStep ].selector ).height(); |
| 19 | if ( nextStepHeight > currentStepHeight ) { |
| 20 | $( '.give-form-templates' ).css( 'min-height', `${ nextStepHeight + 123 }px` ); |
| 21 | } else { |
| 22 | // Delay setting body height if next step is shorter than current step |
| 23 | setTimeout( function() { |
| 24 | $( '.give-form-templates' ).css( 'min-height', `${ nextStepHeight + 123 }px` ); |
| 25 | }, 200 ); |
| 26 | } |
| 27 | |
| 28 | $( '.step-tracker' ).removeClass( 'current' ); |
| 29 | $( '.step-tracker[data-step="' + step + '"]' ).addClass( 'current' ); |
| 30 | |
| 31 | if ( templateOptions.introduction.enabled === 'disabled' ) { |
| 32 | if ( $( '.step-tracker' ).length === 3 ) { |
| 33 | $( '.step-tracker' ).remove(); |
| 34 | } |
| 35 | |
| 36 | step = step > 0 ? step : 1; |
| 37 | if ( step === 1 ) { |
| 38 | $( '.back-btn', $container ).hide(); |
| 39 | } else { |
| 40 | $( '.back-btn', $container ).show(); |
| 41 | } |
| 42 | |
| 43 | $( '.give-form-navigator', $container ).addClass( 'nav-visible' ); |
| 44 | $( steps[ step ].selector ).css( 'padding-top', '50px' ); |
| 45 | } else if ( step === 0 ) { |
| 46 | $( '.give-form-navigator', $container ).removeClass( 'nav-visible' ); |
| 47 | $( steps[ step ].selector ).css( 'padding-top', '' ); |
| 48 | } else { |
| 49 | $( '.give-form-navigator', $container ).addClass( 'nav-visible' ); |
| 50 | $( steps[ step ].selector ).css( 'padding-top', '50px' ); |
| 51 | } |
| 52 | |
| 53 | if ( steps[ step ].title ) { |
| 54 | $navigatorTitle.text( steps[ step ].title ); |
| 55 | } |
| 56 | |
| 57 | const hide = steps.map( ( obj, index ) => { |
| 58 | if ( index === step || index === navigator.currentStep ) { |
| 59 | return null; |
| 60 | } |
| 61 | return obj.selector; |
| 62 | } ); |
| 63 | const hideSelector = hide.filter( Boolean ).join( ', ' ); |
| 64 | |
| 65 | $( hideSelector ).hide(); |
| 66 | |
| 67 | if ( navigator.currentStep !== step ) { |
| 68 | const directionClasses = 'slide-in-right slide-in-left slide-out-right slide-out-left'; |
| 69 | const outDirection = navigator.currentStep < step ? 'left' : 'right'; |
| 70 | const inDirection = navigator.currentStep < step ? 'right' : 'left'; |
| 71 | $( steps[ navigator.currentStep ].selector ).removeClass( directionClasses ).addClass( `slide-out-${ outDirection }` ); |
| 72 | $( steps[ step ].selector ).show().removeClass( directionClasses ).addClass( `slide-in-${ inDirection }` ); |
| 73 | } |
| 74 | navigator.currentStep = step; |
| 75 | setupTabOrder(); |
| 76 | |
| 77 | setTimeout( function() { |
| 78 | if ( steps[ navigator.currentStep ].firstFocus ) { |
| 79 | $( steps[ navigator.currentStep ].firstFocus ).focus(); |
| 80 | } |
| 81 | }, 200 ); |
| 82 | }, |
| 83 | init: () => { |
| 84 | steps.forEach( ( step ) => { |
| 85 | if ( step.setup !== undefined ) { |
| 86 | step.setup(); |
| 87 | } |
| 88 | $( step.selector ).css( 'position', 'absolute' ); |
| 89 | } ); |
| 90 | $advanceButton.on( 'click', function( e ) { |
| 91 | e.preventDefault(); |
| 92 | navigator.forward(); |
| 93 | } ); |
| 94 | $backButton.on( 'click', function( e ) { |
| 95 | e.preventDefault(); |
| 96 | navigator.back(); |
| 97 | } ); |
| 98 | $( '.step-tracker' ).on( 'click', function( e ) { |
| 99 | e.preventDefault(); |
| 100 | navigator.goToStep( parseInt( $( e.target ).attr( 'data-step' ) ) ); |
| 101 | } ); |
| 102 | setupHeightChangeCallback( function( height ) { |
| 103 | if ( gatewayAnimating === false ) { |
| 104 | $( '.form-footer' ).css( 'transition', 'margin-top 0.2s ease' ); |
| 105 | } else { |
| 106 | $( '.form-footer' ).css( 'transition', '' ); |
| 107 | } |
| 108 | $( '.form-footer' ).css( 'margin-top', `${ height }px` ); |
| 109 | } ); |
| 110 | navigator.goToStep( getInitialStep() ); |
| 111 | }, |
| 112 | back: () => { |
| 113 | const prevStep = navigator.currentStep !== 0 ? navigator.currentStep - 1 : 0; |
| 114 | navigator.goToStep( prevStep ); |
| 115 | navigator.currentStep = prevStep; |
| 116 | }, |
| 117 | forward: () => { |
| 118 | const nextStep = navigator.currentStep !== null ? navigator.currentStep + 1 : 1; |
| 119 | navigator.goToStep( nextStep ); |
| 120 | navigator.currentStep = nextStep; |
| 121 | }, |
| 122 | }; |
| 123 | |
| 124 | const steps = [ |
| 125 | { |
| 126 | id: 'introduction', |
| 127 | title: null, |
| 128 | selector: '.give-section.introduction', |
| 129 | label: templateOptions.introduction.donate_label, |
| 130 | showErrors: false, |
| 131 | tabOrder: [ |
| 132 | '.introduction .advance-btn', |
| 133 | '.step-tracker', |
| 134 | ], |
| 135 | }, |
| 136 | { |
| 137 | id: 'choose-amount', |
| 138 | title: templateOptions.payment_amount.header_label, |
| 139 | selector: '.give-section.choose-amount', |
| 140 | label: templateOptions.payment_amount.next_label, |
| 141 | showErrors: false, |
| 142 | tabOrder: [ |
| 143 | 'input.give-amount-top', |
| 144 | '.give-donation-levels-wrap button', |
| 145 | '.give-recurring-period', |
| 146 | '.give-recurring-donors-choice-period', |
| 147 | '.give_fee_mode_checkbox', |
| 148 | '.choose-amount .advance-btn', |
| 149 | '.step-tracker', |
| 150 | '.back-btn', |
| 151 | ], |
| 152 | firstFocus: '.give-default-level', |
| 153 | setup: () => { |
| 154 | // Dynamically set grid columns based on number of buttons |
| 155 | const buttonCount = $( '.give-donation-level-btn' ).length; |
| 156 | if ( buttonCount === 1 ) { |
| 157 | $( '.give-donation-levels-wrap' ).attr( 'style', 'display: none!important;' ); |
| 158 | } else if ( buttonCount % 2 === 0 && buttonCount < 6 ) { |
| 159 | $( '.give-donation-levels-wrap' ).css( 'grid-template-columns', 'repeat(2, minmax(0, 1fr))' ); |
| 160 | } |
| 161 | |
| 162 | $( '#give-amount' ).on( 'blur', function() { |
| 163 | if ( ! Give.form.fn.isValidDonationAmount( $( 'form' ) ) ) { |
| 164 | $( '.advance-btn' ).attr( 'disabled', true ); |
| 165 | } else { |
| 166 | $( '.advance-btn' ).attr( 'disabled', false ); |
| 167 | } |
| 168 | } ); |
| 169 | $( '.give-donation-level-btn' ).each( function() { |
| 170 | const hasTooltip = $( this ).attr( 'has-tooltip' ); |
| 171 | if ( hasTooltip ) { |
| 172 | return; |
| 173 | } |
| 174 | |
| 175 | const value = $( this ).attr( 'value' ); |
| 176 | const text = $( this ).text(); |
| 177 | const symbol = window.give_global_vars.currency_sign; |
| 178 | const position = window.give_global_vars.currency_pos; |
| 179 | |
| 180 | if ( value !== 'custom' ) { |
| 181 | const html = position === 'before' ? `<div class="currency currency--before">${ symbol }</div>${ value }` : `${ value }<div class="currency currency--after">${ symbol }</div>`; |
| 182 | $( this ).html( html ); |
| 183 | } |
| 184 | |
| 185 | // Setup string to check tooltip label ga |
| 186 | const compare = position === 'before' ? symbol + value : value + symbol; |
| 187 | // Setup tooltip unless for custom donation level, or if level label matches value |
| 188 | if ( value !== 'custom' && text !== compare ) { |
| 189 | const wrap = `<span class="give-tooltip hint--top hint--bounce ${ text.length < 50 ? 'narrow' : '' }" style="width: 100%" aria-label="${ text.length < 50 ? text : text.substr( 0, 50 ) + '...' }" rel="tooltip"></span>`; |
| 190 | $( this ).wrap( wrap ); |
| 191 | $( this ).attr( 'has-tooltip', true ); |
| 192 | } |
| 193 | } ); |
| 194 | }, |
| 195 | }, |
| 196 | { |
| 197 | id: 'payment', |
| 198 | title: templateOptions.payment_information.header_label, |
| 199 | label: templateOptions.payment_information.checkout_label, |
| 200 | selector: '.give-section.payment', |
| 201 | showErrors: true, |
| 202 | tabOrder: [ |
| 203 | '.payment input, .payment a, .payment button, .payment select, .payment multiselect, .payment textarea, .payment .button', |
| 204 | '.give-submit', |
| 205 | '.step-tracker', |
| 206 | '.back-btn', |
| 207 | ], |
| 208 | firstFocus: '#give-first', |
| 209 | setup: () => { |
| 210 | // Setup payment information screen |
| 211 | |
| 212 | $( '.give-section.payment' ).on( 'click', '.give-cancel-login, .give-checkout-register-cancel', clearLoginNotices ); |
| 213 | |
| 214 | // Show Sequoia loader on click/touchend |
| 215 | $( '.give-section.payment' ).on( 'click touchend', 'input[name="give_login_submit"]', function() { |
| 216 | //Override submit loader with Sequoia loader |
| 217 | $( 'input[name="give_login_submit"] + .give-loading-animation' ).removeClass( 'give-loading-animation' ).addClass( 'sequoia-loader spinning' ); |
| 218 | } ); |
| 219 | |
| 220 | // Remove purchase_loading text |
| 221 | window.give_global_vars.purchase_loading = ''; |
| 222 | |
| 223 | // Move errors |
| 224 | $( '.give_error' ).each( function() { |
| 225 | moveErrorNotice( $( this ) ); |
| 226 | } ); |
| 227 | |
| 228 | // Setup anonymouse donations opt-in event listeners |
| 229 | setupCheckbox( { |
| 230 | container: '#give-anonymous-donation-wrap label', |
| 231 | label: '#give-anonymous-donation-wrap label', |
| 232 | input: '#give-anonymous-donation', |
| 233 | } ); |
| 234 | |
| 235 | // Setup recurring donations opt-in event listeners |
| 236 | setupCheckbox( { |
| 237 | container: '.give-recurring-donors-choice', |
| 238 | label: '.give-recurring-donors-choice label', |
| 239 | input: 'input[name="give-recurring-period"]', |
| 240 | } ); |
| 241 | |
| 242 | // Setup fee recovery opt-in event listeners |
| 243 | setupCheckbox( { |
| 244 | container: '.give-fee-recovery-donors-choice', |
| 245 | label: '.give-fee-message-label-text', |
| 246 | input: 'input[name="give_fee_mode_checkbox"]', |
| 247 | } ); |
| 248 | |
| 249 | // Setup mailchimp opt-in event listeners |
| 250 | setupCheckbox( { |
| 251 | container: '.give-mailchimp-fieldset', |
| 252 | label: '.give-mc-message-text', |
| 253 | input: 'input[name="give_mailchimp_signup"]', |
| 254 | } ); |
| 255 | |
| 256 | // Setup constant contact opt-in event listeners |
| 257 | setupCheckbox( { |
| 258 | container: '.give-constant-contact-fieldset', |
| 259 | label: '.give-constant-contact-fieldset span', |
| 260 | input: 'input[name="give_constant_contact_signup"]', |
| 261 | } ); |
| 262 | |
| 263 | // Setup terms and conditions opt-in event listeners |
| 264 | setupCheckbox( { |
| 265 | container: '#give_terms_agreement', |
| 266 | label: '#give_terms_agreement label', |
| 267 | input: 'input[name="give_agree_to_terms"]', |
| 268 | } ); |
| 269 | |
| 270 | // Show Sequoia loader on click/touchend |
| 271 | $( 'body.give-form-templates' ).on( 'click touchend', 'form.give-form input[name="give-purchase"].give-submit', function() { |
| 272 | //Override submit loader with Sequoia loader |
| 273 | $( '#give-purchase-button + .give-loading-animation' ).removeClass( 'give-loading-animation' ).addClass( 'sequoia-loader' ); |
| 274 | |
| 275 | // Only show spinner if form is valid |
| 276 | if ( $( 'form' ).get( 0 ).checkValidity() ) { |
| 277 | $( '.sequoia-loader' ).addClass( 'spinning' ); |
| 278 | } |
| 279 | } ); |
| 280 | |
| 281 | // Go to choose amount step when donation maximum error is clicked |
| 282 | $( 'body.give-form-templates' ).on( 'click touchend', '#give_error_invalid_donation_maximum', function() { |
| 283 | // Go to choose amount step |
| 284 | navigator.goToStep( 1 ); |
| 285 | } ); |
| 286 | |
| 287 | // Go to choose amount step when invalid donation error is clicked |
| 288 | $( 'body.give-form-templates' ).on( 'click touchend', '#give_error_invalid_donation_amount', function() { |
| 289 | // Go to choose amount step |
| 290 | navigator.goToStep( 1 ); |
| 291 | } ); |
| 292 | |
| 293 | // Setup gateway icons |
| 294 | setupGatewayIcons(); |
| 295 | |
| 296 | const observer = new window.MutationObserver( function( mutations ) { |
| 297 | mutations.forEach( function( mutation ) { |
| 298 | if ( ! mutation.addedNodes ) { |
| 299 | return; |
| 300 | } |
| 301 | |
| 302 | for ( let i = 0; i < mutation.addedNodes.length; i++ ) { |
| 303 | // do things to your newly added nodes here |
| 304 | const node = mutation.addedNodes[ i ]; |
| 305 | |
| 306 | if ( $( node ).find( '.give_error' ).length > 0 ) { |
| 307 | moveErrorNotice( $( node ).find( '.give_error' ) ); |
| 308 | } |
| 309 | |
| 310 | if ( $( node ).children().hasClass( 'give_errors' ) && ! $( node ).parent().hasClass( 'donation-errors' ) ) { |
| 311 | $( node ).children( '.give_errors' ).each( function() { |
| 312 | const notice = $( this ); |
| 313 | moveErrorNotice( notice ); |
| 314 | } ); |
| 315 | } |
| 316 | |
| 317 | if ( $( node ).hasClass( 'give_errors' ) && ! $( node ).parent().hasClass( 'donation-errors' ) ) { |
| 318 | moveErrorNotice( $( node ) ); |
| 319 | $( '.sequoia-loader' ).removeClass( 'spinning' ); |
| 320 | } |
| 321 | |
| 322 | if ( $( node ).attr( 'id' ) === 'give_tributes_address_state' ) { |
| 323 | const placeholder = $( node ).attr( 'placeholder' ); |
| 324 | $( node ).prepend( `<option selected disabled>${ placeholder }</option>` ); |
| 325 | } |
| 326 | |
| 327 | if ( $( node ).attr( 'name' ) === 'give_tributes_address_state' && $( node ).attr( 'class' ).includes( 'give-input' ) ) { |
| 328 | $( node ).attr( 'placeholder', $( node ).siblings( 'label' ).text().trim() ); |
| 329 | } |
| 330 | |
| 331 | if ( $( node ).attr( 'id' ) && $( node ).attr( 'id' ).includes( 'give-checkout-login-register' ) ) { |
| 332 | $( '[id*="give-register-account-fields"]' ).on( 'click', handleFFMInput ); |
| 333 | } |
| 334 | |
| 335 | if ( $( node ).prop( 'tagName' ) && $( node ).prop( 'tagName' ).toLowerCase() === 'select' ) { |
| 336 | const placeholder = $( node ).attr( 'placeholder' ); |
| 337 | $( node ).prepend( `<option value="" disabled selected>${ placeholder }</option>` ); |
| 338 | } |
| 339 | } |
| 340 | } ); |
| 341 | } ); |
| 342 | |
| 343 | observer.observe( document.body, { |
| 344 | childList: true, |
| 345 | subtree: true, |
| 346 | attributes: false, |
| 347 | characterData: false, |
| 348 | } ); |
| 349 | }, |
| 350 | }, |
| 351 | ]; |
| 352 | |
| 353 | navigator.init(); |
| 354 | |
| 355 | // Check if only a single gateway is enabled |
| 356 | if ( $paymentGatewayContainer.length && $paymentGatewayContainer.css( 'display' ) !== 'none' ) { |
| 357 | // Move payment information section when document load. |
| 358 | moveFieldsUnderPaymentGateway( true ); |
| 359 | |
| 360 | // Move payment information section when gateway updated. |
| 361 | $( document ).on( 'give_gateway_loaded', function() { |
| 362 | setupTabOrder(); |
| 363 | moveFieldsUnderPaymentGateway( true ); |
| 364 | setupSelectInputs(); |
| 365 | $( '#give_purchase_form_wrap' ).slideDown( 200, function() { |
| 366 | gatewayAnimating = false; |
| 367 | } ); |
| 368 | } ); |
| 369 | $( document ).on( 'Give:onPreGatewayLoad', function() { |
| 370 | gatewayAnimating = true; |
| 371 | $( '#give_purchase_form_wrap' ).slideUp( 200 ); |
| 372 | } ); |
| 373 | |
| 374 | // Clear gateway related errors |
| 375 | $( document ).on( 'Give:onPreGatewayLoad', function() { |
| 376 | const persistedNotices = [ |
| 377 | 'give_error_test_mode', |
| 378 | ]; |
| 379 | |
| 380 | $( '.give_errors, .give_notices, .give_error' ).each( function() { |
| 381 | if ( ! persistedNotices.includes( $( this ).attr( 'id' ) ) ) { |
| 382 | $( this ).slideUp( 200, function() { |
| 383 | $( this ).remove(); |
| 384 | } ); |
| 385 | } |
| 386 | } ); |
| 387 | } ); |
| 388 | |
| 389 | // Refresh payment information section. |
| 390 | $( document ).on( 'give_gateway_loaded', refreshPaymentInformationSection ); |
| 391 | } else { |
| 392 | $( '#give_purchase_form_wrap' ).addClass( 'give-single-gateway-wrap' ); |
| 393 | setupSelectInputs(); |
| 394 | } |
| 395 | |
| 396 | /** |
| 397 | * Move error notices to error notice container at the top of the payment section |
| 398 | * @since 2.7.0 |
| 399 | * @param {node} node The error notice node to be moved |
| 400 | */ |
| 401 | function moveErrorNotice( node ) { |
| 402 | //If the error is inside stripe payment button, do nothing |
| 403 | if ( $( node ).parent().hasClass( 'give-stripe-payment-request-button' ) ) { |
| 404 | return; |
| 405 | } |
| 406 | |
| 407 | // First check if specific donation notice container has been set up |
| 408 | if ( $( '.donation-errors' ).length === 0 ) { |
| 409 | $( '.payment' ).prepend( '<div class="donation-errors"></div>' ); |
| 410 | } |
| 411 | |
| 412 | // If a specific notice does not already exist, proceed with moving the error |
| 413 | if ( typeof $( '.donation-errors' ).html() !== undefined && ! $( '.donation-errors' ).html().includes( $( node ).html() ) ) { |
| 414 | $( node ).appendTo( '.donation-errors' ); |
| 415 | } else { |
| 416 | // If the specific notice already exists, do not add it |
| 417 | $( node ).remove(); |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | /** |
| 422 | * Add listeners and starting states to FFM inputs |
| 423 | * @since 2.7.0 |
| 424 | */ |
| 425 | function setupFFMInputs() { |
| 426 | $( '#give-ffm-section' ).off( 'click', handleFFMInput ); |
| 427 | $( '[id*="give-register-account-fields"]' ).off( 'click', handleFFMInput ); |
| 428 | |
| 429 | $( '#give-ffm-section' ).on( 'click', handleFFMInput ); |
| 430 | $( '[id*="give-register-account-fields"]' ).on( 'click', handleFFMInput ); |
| 431 | |
| 432 | $( '#give-ffm-section input' ).each( function() { |
| 433 | switch ( $( this ).prop( 'type' ) ) { |
| 434 | case 'checkbox': { |
| 435 | if ( $( this ).prop( 'checked' ) ) { |
| 436 | $( this ).parent().addClass( 'checked' ); |
| 437 | } else { |
| 438 | $( this ).parent().removeClass( 'checked' ); |
| 439 | } |
| 440 | break; |
| 441 | } |
| 442 | case 'radio': { |
| 443 | if ( $( this ).prop( 'checked' ) ) { |
| 444 | $( this ).parent().addClass( 'selected' ); |
| 445 | } else { |
| 446 | $( this ).parent().removeClass( 'selected' ); |
| 447 | } |
| 448 | break; |
| 449 | } |
| 450 | } |
| 451 | } ); |
| 452 | } |
| 453 | |
| 454 | /** |
| 455 | * Move form field under payment gateway |
| 456 | * @since 2.7.0 |
| 457 | */ |
| 458 | function moveFieldsUnderPaymentGateway() { |
| 459 | // Check if donate fieldset area has been created, if not set it up below payment gateways |
| 460 | // This area is necessary for correctly placing various elements (fee recovery notice, newsletters, submit button, etc) |
| 461 | if ( $( '#donate-fieldset' ).length === 0 ) { |
| 462 | $( '#give-payment-mode-select' ).after( '<fieldset id="donate-fieldset"></fieldset>' ); |
| 463 | } |
| 464 | |
| 465 | // Elements to move into donate fieldset (located at bottom of form) |
| 466 | // The elements will appear in order of array |
| 467 | const donateFieldsetElements = [ |
| 468 | '.give-constant-contact-fieldset', |
| 469 | '.give-mailchimp-fieldset', |
| 470 | '#give_terms_agreement', |
| 471 | '.give-donation-submit', |
| 472 | ]; |
| 473 | |
| 474 | // Handle moving elements into donate fieldset |
| 475 | donateFieldsetElements.forEach( function( selector ) { |
| 476 | if ( $( `#donate-fieldset ${ selector }` ).length === 0 ) { |
| 477 | $( '#donate-fieldset' ).append( $( `#give_purchase_form_wrap ${ selector }` ) ); |
| 478 | } else if ( $( `#donate-fieldset ${ selector }` ).html() !== $( `#give_purchase_form_wrap ${ selector }` ).html() ) { |
| 479 | $( `#donate-fieldset ${ selector }` ).remove(); |
| 480 | $( '#donate-fieldset' ).append( $( `#give_purchase_form_wrap ${ selector }` ) ); |
| 481 | } else { |
| 482 | $( `#give_purchase_form_wrap ${ selector }` ).remove(); |
| 483 | } |
| 484 | } ); |
| 485 | |
| 486 | // Handle per-Gateway fee option |
| 487 | // If the fee recovery option wrapper is present, move it to the choose amount screen |
| 488 | if ( $( '#give_purchase_form_wrap fieldset[id*="give-fee-recovery-wrap"]' ).length !== 0 ) { |
| 489 | let checked = false; |
| 490 | if ( $( '.choose-amount fieldset[id*="give-fee-recovery-wrap"]' ).length !== 0 ) { |
| 491 | checked = $( 'input[name="give_fee_mode_checkbox"]' ).prop( 'checked' ); |
| 492 | $( '.choose-amount fieldset[id*="give-fee-recovery-wrap"]' ).remove(); |
| 493 | } |
| 494 | $( '.choose-amount' ).append( $( '#give_purchase_form_wrap fieldset[id*="give-fee-recovery-wrap"]' ) ); |
| 495 | $( 'input[name="give_fee_mode_checkbox"]' ).prop( 'checked', checked ); |
| 496 | } |
| 497 | |
| 498 | // Move purchase fields (credit card, billing, etc) |
| 499 | $( 'li.give-gateway-option-selected' ).after( $( '#give_purchase_form_wrap' ) ); |
| 500 | |
| 501 | // Add gateway class to fields wrapper, indicating which gateway is active |
| 502 | const gatewayClass = 'gateway-' + $( '.give-gateway-option-selected input' ).attr( 'value' ).replace( '_', '-' ); |
| 503 | $( '#give_purchase_form_wrap' ).attr( 'class', gatewayClass ); |
| 504 | |
| 505 | setupFFMInputs(); |
| 506 | setupInputIcons(); |
| 507 | } |
| 508 | |
| 509 | /** |
| 510 | * Refresh payment information section |
| 511 | * |
| 512 | * @since 2.7.0 |
| 513 | * @param {boolean} ev Event object |
| 514 | * @param {object} response Response object |
| 515 | * @param {number} formID Form ID |
| 516 | */ |
| 517 | function refreshPaymentInformationSection( ev, response, formID ) { |
| 518 | if ( navigator.currentStep === 2 ) { |
| 519 | $( '.give-form-templates' ).css( 'min-height', '' ); |
| 520 | } |
| 521 | |
| 522 | const $form = $( `#${ formID }` ); |
| 523 | |
| 524 | // This function will run only for embed donation form. |
| 525 | // Show payment information section fields. |
| 526 | if ( $form.parent().hasClass( 'give-embed-form' ) ) { |
| 527 | const data = { |
| 528 | action: 'give_cancel_login', |
| 529 | form_id: $form.find( '[name="give-form-id"]' ).val(), |
| 530 | }; |
| 531 | |
| 532 | // AJAX get the payment fields. |
| 533 | $.post( Give.fn.getGlobalVar( 'ajaxurl' ), data, function( postResponse ) { |
| 534 | $form.find( '[id^=give-checkout-login-register]' ).replaceWith( $.parseJSON( postResponse.fields ) ); |
| 535 | $form.find( '[id^=give-checkout-login-register]' ).css( { display: 'block' } ); |
| 536 | $form.find( '.give-submit-button-wrap' ).show(); |
| 537 | } ).done( function() { |
| 538 | // Trigger float-labels |
| 539 | window.give_fl_trigger(); |
| 540 | } ); |
| 541 | } |
| 542 | } |
| 543 | |
| 544 | function setupInputIcon( selector, icon ) { |
| 545 | $( selector ).each( function() { |
| 546 | if ( $( this ).html() !== '' && $( this ).html().includes( `<i class="fas fa-${ icon }"></i>` ) === false ) { |
| 547 | $( this ).prepend( `<i class="fas fa-${ icon }"></i>` ); |
| 548 | $( this ).children( 'input, selector' ).each( function() { |
| 549 | $( this ).attr( 'style', 'padding-left: 33px!important;' ); |
| 550 | } ); |
| 551 | } |
| 552 | } ); |
| 553 | } |
| 554 | |
| 555 | function setupInputIcons() { |
| 556 | setupInputIcon( '#give-first-name-wrap', 'user' ); |
| 557 | setupInputIcon( '#give-email-wrap', 'envelope' ); |
| 558 | setupInputIcon( '#give-company-wrap', 'building' ); |
| 559 | setupInputIcon( '#date_field-wrap', 'calendar-alt' ); |
| 560 | setupInputIcon( '#url_field-wrap', 'globe' ); |
| 561 | setupInputIcon( '#phone_field-wrap', 'phone' ); |
| 562 | setupInputIcon( '#give-phone-wrap', 'phone' ); |
| 563 | setupInputIcon( '#email_field-wrap', 'envelope' ); |
| 564 | } |
| 565 | |
| 566 | /** |
| 567 | * Setup tab order for elements in form |
| 568 | * |
| 569 | * @since 2.7.0 |
| 570 | */ |
| 571 | function setupTabOrder() { |
| 572 | $( 'select, button, input, textarea, multiselect, a' ).attr( 'tabindex', -1 ); |
| 573 | |
| 574 | const tabOrder = steps[ navigator.currentStep ].tabOrder; |
| 575 | tabOrder.forEach( ( selector, index ) => { |
| 576 | $( selector ).attr( 'tabindex', index + 1 ); |
| 577 | } ); |
| 578 | } |
| 579 | |
| 580 | /** |
| 581 | * Loop through gateway li elements and setup fontawesome icons |
| 582 | * |
| 583 | * @since 2.7.0 |
| 584 | */ |
| 585 | function setupGatewayIcons() { |
| 586 | $( '#give-gateway-radio-list li' ).each( function() { |
| 587 | const value = $( 'input', this ).val(); |
| 588 | let icon; |
| 589 | switch ( value ) { |
| 590 | case 'manual': |
| 591 | icon = 'fas fa-tools'; |
| 592 | break; |
| 593 | case 'offline': |
| 594 | icon = 'fas fa-wallet'; |
| 595 | break; |
| 596 | case 'paypal': |
| 597 | icon = 'fab fa-paypal'; |
| 598 | break; |
| 599 | case 'stripe': |
| 600 | icon = 'far fa-credit-card'; |
| 601 | break; |
| 602 | case 'stripe_checkout': |
| 603 | icon = 'far fa-credit-card'; |
| 604 | break; |
| 605 | case 'stripe_sepa': |
| 606 | icon = 'fas fa-university'; |
| 607 | break; |
| 608 | case 'stripe_ach': |
| 609 | icon = 'fas fa-university'; |
| 610 | break; |
| 611 | case 'stripe_ideal': |
| 612 | icon = 'fas fa-university'; |
| 613 | break; |
| 614 | case 'stripe_becs': |
| 615 | icon = 'fas fa-university'; |
| 616 | break; |
| 617 | case 'paypalpro_payflow': |
| 618 | icon = 'far fa-credit-card'; |
| 619 | break; |
| 620 | case 'stripe_google_pay': |
| 621 | icon = 'fab fa-google'; |
| 622 | break; |
| 623 | case 'stripe_apple_pay': |
| 624 | icon = 'fab fa-apple'; |
| 625 | break; |
| 626 | default: |
| 627 | icon = 'fas fa-hand-holding-heart'; |
| 628 | break; |
| 629 | } |
| 630 | $( this ).append( `<i class="${ icon }"></i>` ); |
| 631 | } ); |
| 632 | } |
| 633 | |
| 634 | /** |
| 635 | * Setup prominent checkboxes (that use persistent borders on select) |
| 636 | * |
| 637 | * @since 2.7.0 |
| 638 | * @param {object} args Argument object containing: container, label, input selectors |
| 639 | */ |
| 640 | function setupCheckbox( { container, label, input } ) { |
| 641 | // If checkbox is opted in by default, add border on load |
| 642 | if ( $( input ).prop( 'checked' ) === true ) { |
| 643 | $( container ).addClass( 'active' ); |
| 644 | } |
| 645 | |
| 646 | // Persist checkbox input border when selected |
| 647 | $( label ).on( 'click touchend', function( evt ) { |
| 648 | if ( container === label ) { |
| 649 | evt.stopPropagation(); |
| 650 | evt.preventDefault(); |
| 651 | } |
| 652 | $( container ).toggleClass( 'active' ); |
| 653 | } ); |
| 654 | } |
| 655 | |
| 656 | function setupHeightChangeCallback( callback ) { |
| 657 | let lastHeight = 0; |
| 658 | function checkHeightChange() { |
| 659 | const selector = $( steps[ navigator.currentStep ].selector ); |
| 660 | const changed = lastHeight !== $( selector ).outerHeight(); |
| 661 | if ( changed ) { |
| 662 | callback( $( selector ).outerHeight() ); |
| 663 | lastHeight = $( selector ).outerHeight(); |
| 664 | } |
| 665 | window.requestAnimationFrame( checkHeightChange ); |
| 666 | } |
| 667 | window.requestAnimationFrame( checkHeightChange ); |
| 668 | } |
| 669 | |
| 670 | /** |
| 671 | * Get initial step to show donor. |
| 672 | * |
| 673 | * @since 2.7.0 |
| 674 | * @returns {number} Step to start on |
| 675 | */ |
| 676 | function getInitialStep() { |
| 677 | return Give.fn.getParameterByName( 'showDonationProcessingError' ) || Give.fn.getParameterByName( 'showFailedDonationError' ) ? 2 : 0; |
| 678 | } |
| 679 | |
| 680 | /** |
| 681 | * Handle updating label classes for FFM radios and checkboxes |
| 682 | * |
| 683 | * @since 2.7.0 |
| 684 | * @param {object} evt Reference to FFM input element click event |
| 685 | */ |
| 686 | function handleFFMInput( evt ) { |
| 687 | if ( $( evt.target ).is( 'input' ) ) { |
| 688 | switch ( $( evt.target ).prop( 'type' ) ) { |
| 689 | case 'checkbox': { |
| 690 | $( evt.target ).parent().toggleClass( 'checked' ); |
| 691 | break; |
| 692 | } |
| 693 | case 'radio': { |
| 694 | $( evt.target ).parent().addClass( 'selected' ); |
| 695 | $( evt.target ).parent().siblings().removeClass( 'selected' ); |
| 696 | break; |
| 697 | } |
| 698 | } |
| 699 | } |
| 700 | } |
| 701 | |
| 702 | function clearLoginNotices() { |
| 703 | $( '#give_error_must_log_in' ).remove(); |
| 704 | } |
| 705 | |
| 706 | /** |
| 707 | * Setup select inputs |
| 708 | * |
| 709 | * @since 2.7.0 |
| 710 | */ |
| 711 | function setupSelectInputs() { |
| 712 | if ( $( 'select option[selected="selected"][value=""]' ).length > 0 ) { |
| 713 | $( 'select option[selected="selected"][value=""]' ).each( function() { |
| 714 | if ( $( this ).parent().siblings( 'label' ).length ) { |
| 715 | $( this ).text( $( this ).parent().siblings( 'label' ).text().replace( '*', '' ).trim() ); |
| 716 | $( this ).attr( 'disabled', true ); |
| 717 | } |
| 718 | } ); |
| 719 | } |
| 720 | } |
| 721 | }( jQuery ) ); |
| 722 |