I reproduced successfully the solution described here to add one progress bar to CF7. But my Contact Form 7 doesn't validate required fields and does't show any response message after one click on the submit button.

I tried to adapt the code in scripts.js (contact-form-7/includes/js/scripts.js) from Version 3.5.3 to the newer version 5.1

Here is the changed scripts.js:

( function( $ ) {

    'use strict';
        // start
        var progressbox  = jQuery('#progressbox');
        var progressbar     = jQuery('#progressbar');
        var statustxt   = jQuery('#statustxt');
        var submitbutton    = jQuery("#SubmitButton");
        var myform  = jQuery("#wpcf7-form");
        var output2  = jQuery("#output2");
        var completed   = '0%';
        //end

    if ( typeof wpcf7 === 'undefined' || wpcf7 === null ) {
        return;
    }

    wpcf7 = $.extend( {
        cached: 0,
        inputs: []
    }, wpcf7 );

    $( function() {
        wpcf7.supportHtml5 = ( function() {
            var features = {};
            var input = document.createElement( 'input' );

            features.placeholder = 'placeholder' in input;

            var inputTypes = [ 'email', 'url', 'tel', 'number', 'range', 'date' ];

            $.each( inputTypes, function( index, value ) {
                input.setAttribute( 'type', value );
                features[ value ] = input.type !== 'text';
            } );

            return features;
        } )();

        $( 'div.wpcf7 > form' ).each( function() {
            var $form = $( this );
            wpcf7.initForm( $form );

            if ( wpcf7.cached ) {
                wpcf7.refill( $form );
            }
        } );
    } );

    wpcf7.getId = function( form ) {
        return parseInt( $( 'input[name="_wpcf7"]', form ).val(), 10 );
    };

    wpcf7.initForm = function( form ) {
        var $form = $( form );

        $form.submit( function( event ) {
            if ( ! wpcf7.supportHtml5.placeholder ) {
                $( '[placeholder].placeheld', $form ).each( function( i, n ) {
                    $( n ).val( '' ).removeClass( 'placeheld' );
                } );
            }

            if ( typeof window.FormData === 'function' ) {
                wpcf7.submit( $form );
                event.preventDefault();
            }
        } );

        $( '.wpcf7-submit', $form ).after( '<span class="ajax-loader"></span>' );

        wpcf7.toggleSubmit( $form );

        $form.on( 'click', '.wpcf7-acceptance', function() {
            wpcf7.toggleSubmit( $form );
        } );

        // Exclusive Checkbox
        $( '.wpcf7-exclusive-checkbox', $form ).on( 'click', 'input:checkbox', function() {
            var name = $( this ).attr( 'name' );
            $form.find( 'input:checkbox[name="' + name + '"]' ).not( this ).prop( 'checked', false );
        } );

        // Free Text Option for Checkboxes and Radio Buttons
        $( '.wpcf7-list-item.has-free-text', $form ).each( function() {
            var $freetext = $( ':input.wpcf7-free-text', this );
            var $wrap = $( this ).closest( '.wpcf7-form-control' );

            if ( $( ':checkbox, :radio', this ).is( ':checked' ) ) {
                $freetext.prop( 'disabled', false );
            } else {
                $freetext.prop( 'disabled', true );
            }

            $wrap.on( 'change', ':checkbox, :radio', function() {
                var $cb = $( '.has-free-text', $wrap ).find( ':checkbox, :radio' );

                if ( $cb.is( ':checked' ) ) {
                    $freetext.prop( 'disabled', false ).focus();
                } else {
                    $freetext.prop( 'disabled', true );
                }
            } );
        } );

        // Placeholder Fallback
        if ( ! wpcf7.supportHtml5.placeholder ) {
            $( '[placeholder]', $form ).each( function() {
                $( this ).val( $( this ).attr( 'placeholder' ) );
                $( this ).addClass( 'placeheld' );

                $( this ).focus( function() {
                    if ( $( this ).hasClass( 'placeheld' ) ) {
                        $( this ).val( '' ).removeClass( 'placeheld' );
                    }
                } );

                $( this ).blur( function() {
                    if ( '' === $( this ).val() ) {
                        $( this ).val( $( this ).attr( 'placeholder' ) );
                        $( this ).addClass( 'placeheld' );
                    }
                } );
            } );
        }

        if ( wpcf7.jqueryUi && ! wpcf7.supportHtml5.date ) {
            $form.find( 'input.wpcf7-date[type="date"]' ).each( function() {
                $( this ).datepicker( {
                    dateFormat: 'yy-mm-dd',
                    minDate: new Date( $( this ).attr( 'min' ) ),
                    maxDate: new Date( $( this ).attr( 'max' ) )
                } );
            } );
        }

        if ( wpcf7.jqueryUi && ! wpcf7.supportHtml5.number ) {
            $form.find( 'input.wpcf7-number[type="number"]' ).each( function() {
                $( this ).spinner( {
                    min: $( this ).attr( 'min' ),
                    max: $( this ).attr( 'max' ),
                    step: $( this ).attr( 'step' )
                } );
            } );
        }

        // Character Count
        $( '.wpcf7-character-count', $form ).each( function() {
            var $count = $( this );
            var name = $count.attr( 'data-target-name' );
            var down = $count.hasClass( 'down' );
            var starting = parseInt( $count.attr( 'data-starting-value' ), 10 );
            var maximum = parseInt( $count.attr( 'data-maximum-value' ), 10 );
            var minimum = parseInt( $count.attr( 'data-minimum-value' ), 10 );

            var updateCount = function( target ) {
                var $target = $( target );
                var length = $target.val().length;
                var count = down ? starting - length : length;
                $count.attr( 'data-current-value', count );
                $count.text( count );

                if ( maximum && maximum < length ) {
                    $count.addClass( 'too-long' );
                } else {
                    $count.removeClass( 'too-long' );
                }

                if ( minimum && length < minimum ) {
                    $count.addClass( 'too-short' );
                } else {
                    $count.removeClass( 'too-short' );
                }
            };

            $( ':input[name="' + name + '"]', $form ).each( function() {
                updateCount( this );

                $( this ).keyup( function() {
                    updateCount( this );
                } );
            } );
        } );

        // URL Input Correction
        $form.on( 'change', '.wpcf7-validates-as-url', function() {
            var val = $.trim( $( this ).val() );

            if ( val
            && ! val.match( /^[a-z][a-z0-9.+-]*:/i )
            && -1 !== val.indexOf( '.' ) ) {
                val = val.replace( /^\/+/, '' );
                val = 'http://' + val;
            }

            $( this ).val( val );
        } );
    };

    wpcf7.submit = function( form ) {
        if ( typeof window.FormData !== 'function' ) {
            return;
        }

        var $form = $( form );

        $( '.ajax-loader', $form ).addClass( 'is-active' );

        wpcf7.clearResponse( $form );

        var formData = new FormData( $form.get( 0 ) );

        var detail = {
            id: $form.closest( 'div.wpcf7' ).attr( 'id' ),
            status: 'init',
            inputs: [],
            formData: formData
        };

        $.each( $form.serializeArray(), function( i, field ) {
            if ( '_wpcf7' == field.name ) {
                detail.contactFormId = field.value;
            } else if ( '_wpcf7_version' == field.name ) {
                detail.pluginVersion = field.value;
            } else if ( '_wpcf7_locale' == field.name ) {
                detail.contactFormLocale = field.value;
            } else if ( '_wpcf7_unit_tag' == field.name ) {
                detail.unitTag = field.value;
            } else if ( '_wpcf7_container_post' == field.name ) {
                detail.containerPostId = field.value;
            } else if ( field.name.match( /^_wpcf7_\w+_free_text_/ ) ) {
                var owner = field.name.replace( /^_wpcf7_\w+_free_text_/, '' );
                detail.inputs.push( {
                    name: owner + '-free-text',
                    value: field.value
                } );
            } else if ( field.name.match( /^_/ ) ) {
                // do nothing
            } else {
                detail.inputs.push( field );
            }
        } );

        wpcf7.triggerEvent( $form.closest( 'div.wpcf7' ), 'beforesubmit', detail );

        var ajaxSuccess = function( data, status, xhr, $form ) {
            detail.id = $( data.into ).attr( 'id' );
            detail.status = data.status;
            detail.apiResponse = data;

            var $message = $( '.wpcf7-response-output', $form );
            // start
            submitbutton.attr('disabled', ''); // disable upload button
            statustxt.empty();
            progressbox.slideDown(); //show progressbar
            progressbar.width(completed); //initial value 0% of progressbar
            statustxt.html(completed); //set status text
            statustxt.css('color','#000'); //initial color of status text
            //end

            // start
            uploadProgress: function(event, position, total, percentComplete) { //on progress
                progressbar.width(percentComplete + '%') //update progressbar percent complete
                statustxt.html(percentComplete + '%'); //update status text
                if(percentComplete>50) {
                    statustxt.css('color','#fff'); //change status text to white after 50%
                }
            },
            //end

            switch ( data.status ) {
                case 'validation_failed':
                    $.each( data.invalidFields, function( i, n ) {
                        $( n.into, $form ).each( function() {
                            wpcf7.notValidTip( this, n.message );
                            $( '.wpcf7-form-control', this ).addClass( 'wpcf7-not-valid' );
                            $( '[aria-invalid]', this ).attr( 'aria-invalid', 'true' );
                        } );
                    } );

                    $message.addClass( 'wpcf7-validation-errors' );
                    $form.addClass( 'invalid' );

                    wpcf7.triggerEvent( data.into, 'invalid', detail );
                    break;
                case 'acceptance_missing':
                    $message.addClass( 'wpcf7-acceptance-missing' );
                    $form.addClass( 'unaccepted' );

                    wpcf7.triggerEvent( data.into, 'unaccepted', detail );
                    break;
                case 'spam':
                    $message.addClass( 'wpcf7-spam-blocked' );
                    $form.addClass( 'spam' );

                    wpcf7.triggerEvent( data.into, 'spam', detail );
                    break;
                case 'aborted':
                    $message.addClass( 'wpcf7-aborted' );
                    $form.addClass( 'aborted' );

                    wpcf7.triggerEvent( data.into, 'aborted', detail );
                    break;
                case 'mail_sent':
                    $message.addClass( 'wpcf7-mail-sent-ok' );
                    $form.addClass( 'sent' );

                    wpcf7.triggerEvent( data.into, 'mailsent', detail );
                    break;
                case 'mail_failed':
                    $message.addClass( 'wpcf7-mail-sent-ng' );
                    $form.addClass( 'failed' );

                    wpcf7.triggerEvent( data.into, 'mailfailed', detail );
                    break;
                default:
                    var customStatusClass = 'custom-'
                        + data.status.replace( /[^0-9a-z]+/i, '-' );
                    $message.addClass( 'wpcf7-' + customStatusClass );
                    $form.addClass( customStatusClass );
            }

            wpcf7.refill( $form, data );

            wpcf7.triggerEvent( data.into, 'submit', detail );

            if ( 'mail_sent' == data.status ) {
                $form.each( function() {
                    this.reset();
                } );

                wpcf7.toggleSubmit( $form );
            }

            if ( ! wpcf7.supportHtml5.placeholder ) {
                $form.find( '[placeholder].placeheld' ).each( function( i, n ) {
                    $( n ).val( $( n ).attr( 'placeholder' ) );
                } );
            }

            $message.html( '' ).append( data.message ).slideDown( 'fast' );
            $message.attr( 'role', 'alert' );

            $( '.screen-reader-response', $form.closest( '.wpcf7' ) ).each( function() {
                var $response = $( this );
                $response.html( '' ).attr( 'role', '' ).append( data.message );

                if ( data.invalidFields ) {
                    var $invalids = $( '<ul></ul>' );

                    $.each( data.invalidFields, function( i, n ) {
                        if ( n.idref ) {
                            var $li = $( '<li></li>' ).append( $( '<a></a>' ).attr( 'href', '#' + n.idref ).append( n.message ) );
                        } else {
                            var $li = $( '<li></li>' ).append( n.message );
                        }

                        $invalids.append( $li );
                    } );

                    $response.append( $invalids );
                }

                $response.attr( 'role', 'alert' ).focus();
            } );
        };

        $.ajax( {
            type: 'POST',
            url: wpcf7.apiSettings.getRoute(
                '/contact-forms/' + wpcf7.getId( $form ) + '/feedback' ),
            data: formData,
            dataType: 'json',
            processData: false,
            contentType: false
        } ).done( function( data, status, xhr ) {
            ajaxSuccess( data, status, xhr, $form );
            $( '.ajax-loader', $form ).removeClass( 'is-active' );
        } ).fail( function( xhr, status, error ) {
            var $e = $( '<div class="ajax-error"></div>' ).text( error.message );
            $form.after( $e );
        } );
    };

    wpcf7.triggerEvent = function( target, name, detail ) {
        var $target = $( target );

        /* DOM event */
        var event = new CustomEvent( 'wpcf7' + name, {
            bubbles: true,
            detail: detail
        } );

        $target.get( 0 ).dispatchEvent( event );

        /* jQuery event */
        $target.trigger( 'wpcf7:' + name, detail );
        $target.trigger( name + '.wpcf7', detail ); // deprecated
    };

    wpcf7.toggleSubmit = function( form, state ) {
        var $form = $( form );
        var $submit = $( 'input:submit', $form );

        if ( typeof state !== 'undefined' ) {
            $submit.prop( 'disabled', ! state );
            return;
        }

        if ( $form.hasClass( 'wpcf7-acceptance-as-validation' ) ) {
            return;
        }

        $submit.prop( 'disabled', false );

        $( '.wpcf7-acceptance', $form ).each( function() {
            var $span = $( this );
            var $input = $( 'input:checkbox', $span );

            if ( ! $span.hasClass( 'optional' ) ) {
                if ( $span.hasClass( 'invert' ) && $input.is( ':checked' )
                || ! $span.hasClass( 'invert' ) && ! $input.is( ':checked' ) ) {
                    $submit.prop( 'disabled', true );
                    return false;
                }
            }
        } );
    };

    wpcf7.notValidTip = function( target, message ) {
        var $target = $( target );
        $( '.wpcf7-not-valid-tip', $target ).remove();
        $( '<span role="alert" class="wpcf7-not-valid-tip"></span>' )
            .text( message ).appendTo( $target );

        if ( $target.is( '.use-floating-validation-tip *' ) ) {
            var fadeOut = function( target ) {
                $( target ).not( ':hidden' ).animate( {
                    opacity: 0
                }, 'fast', function() {
                    $( this ).css( { 'z-index': -100 } );
                } );
            };

            $target.on( 'mouseover', '.wpcf7-not-valid-tip', function() {
                fadeOut( this );
            } );

            $target.on( 'focus', ':input', function() {
                fadeOut( $( '.wpcf7-not-valid-tip', $target ) );
            } );
        }
    };

    wpcf7.refill = function( form, data ) {
        var $form = $( form );

        var refillCaptcha = function( $form, items ) {
            $.each( items, function( i, n ) {
                $form.find( ':input[name="' + i + '"]' ).val( '' );
                $form.find( 'img.wpcf7-captcha-' + i ).attr( 'src', n );
                var match = /([0-9]+)\.(png|gif|jpeg)$/.exec( n );
                $form.find( 'input:hidden[name="_wpcf7_captcha_challenge_' + i + '"]' ).attr( 'value', match[ 1 ] );
            } );
        };

        var refillQuiz = function( $form, items ) {
            $.each( items, function( i, n ) {
                $form.find( ':input[name="' + i + '"]' ).val( '' );
                $form.find( ':input[name="' + i + '"]' ).siblings( 'span.wpcf7-quiz-label' ).text( n[ 0 ] );
                $form.find( 'input:hidden[name="_wpcf7_quiz_answer_' + i + '"]' ).attr( 'value', n[ 1 ] );
            } );
        };

        if ( typeof data === 'undefined' ) {
            $.ajax( {
                type: 'GET',
                url: wpcf7.apiSettings.getRoute(
                    '/contact-forms/' + wpcf7.getId( $form ) + '/refill' ),
                beforeSend: function( xhr ) {
                    var nonce = $form.find( ':input[name="_wpnonce"]' ).val();

                    if ( nonce ) {
                        xhr.setRequestHeader( 'X-WP-Nonce', nonce );
                    }
                },
                dataType: 'json'
            } ).done( function( data, status, xhr ) {
                if ( data.captcha ) {
                    refillCaptcha( $form, data.captcha );
                }

                if ( data.quiz ) {
                    refillQuiz( $form, data.quiz );
                }
            } );

        } else {
            if ( data.captcha ) {
                refillCaptcha( $form, data.captcha );
            }

            if ( data.quiz ) {
                refillQuiz( $form, data.quiz );
            }
        }
    };

    wpcf7.clearResponse = function( form ) {
        var $form = $( form );
        $form.removeClass( 'invalid spam sent failed' );
        $form.siblings( '.screen-reader-response' ).html( '' ).attr( 'role', '' );

        $( '.wpcf7-not-valid-tip', $form ).remove();
        $( '[aria-invalid]', $form ).attr( 'aria-invalid', 'false' );
        $( '.wpcf7-form-control', $form ).removeClass( 'wpcf7-not-valid' );

        $( '.wpcf7-response-output', $form )
            .hide().empty().removeAttr( 'role' )
            .removeClass( 'wpcf7-mail-sent-ok wpcf7-mail-sent-ng wpcf7-validation-errors wpcf7-spam-blocked' );
    };

    wpcf7.apiSettings.getRoute = function( path ) {
        var url = wpcf7.apiSettings.root;

        url = url.replace(
            wpcf7.apiSettings.namespace,
            wpcf7.apiSettings.namespace + path );

        return url;
    };

} )( jQuery );

/*
 * Polyfill for Internet Explorer
 * See https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
 */
( function () {
    if ( typeof window.CustomEvent === "function" ) return false;

    function CustomEvent ( event, params ) {
        params = params || { bubbles: false, cancelable: false, detail: undefined };
        var evt = document.createEvent( 'CustomEvent' );
        evt.initCustomEvent( event,
            params.bubbles, params.cancelable, params.detail );
        return evt;
    }

    CustomEvent.prototype = window.Event.prototype;

    window.CustomEvent = CustomEvent;
} )();

The progessbar works very good, mails are sended, but if the upload reach 100% the ajax-loader is still spinnig and the success message does not appear.

Can someone help to get it working?

1 Answers

0
kubus1234 On

Yes, this is a wall of code. Sorry about this. I aded successfully the progressbox with workig progress process. See the code below. The issue now is, that the upload process is triggered before required field are validated. What can I do to validate the required field, before the upload starts? Any suggestions?

$.ajax( {
            type: 'POST',
            url: wpcf7.apiSettings.getRoute(
                '/contact-forms/' + wpcf7.getId( $form ) + '/feedback' ),
            data: formData,
            dataType: 'json',
            processData: false,
            contentType: false,


            // add progress box        
            beforeSend: function() { 
            progressbox.slideDown(); //show progressbar
            progressbar.width(completed); //initial value 0% of progressbar
            statustxt.html(completed); //set status text
            statustxt.css('color','#000'); //initial color of status text
            //e.preventDefault();
            },
            //end 

            // show upload process   
            xhr: function() {
            var xhr = new window.XMLHttpRequest();
            xhr.upload.addEventListener("progress", function(event) {
            if (event.lengthComputable) {
                var percentComplete = Math.round((event.loaded * 100) / event.total);
                //upload progress
                progressbar.width(percentComplete + '%') //update progressbar percent complete
                statustxt.html(percentComplete + '%'); //update status text  
                if(percentComplete>50) {
                    statustxt.css('color','#fff'); //change status text to white after 50% 
                }
            }
       }, false);



       return xhr;
    },
            //end           

        } ).done( function( data, status, xhr ) {
            ajaxSuccess( data, status, xhr, $form );
            $( '.ajax-loader', $form ).removeClass( 'is-active' );

            // hide progressbox
            myform.resetForm();  // reset form
            submitbutton.removeAttr('disabled'); //enable submit button
            progressbox.slideUp(); // hide progressbar
            //end 
        } ).fail( function( xhr, status, error ) {
            var $e = $( '<div class="ajax-error"></div>' ).text( error.message );
            $form.after( $e );
        } );
    };