| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327 |
- /* global wpforms_settings, grecaptcha, hcaptcha, wpformsRecaptchaCallback, wpforms_validate, wpforms_datepicker, wpforms_timepicker, Mailcheck, Choices, WPFormsPasswordField, WPFormsEntryPreview, punycode, tinyMCE */
- 'use strict';
- var wpforms = window.wpforms || ( function( document, window, $ ) {
- var app = {
- /**
- * Start the engine.
- *
- * @since 1.2.3
- */
- init: function() {
- // Document ready.
- $( app.ready );
- // Page load.
- $( window ).on( 'load', function() {
- // In the case of jQuery 3.+, we need to wait for a ready event first.
- if ( typeof $.ready.then === 'function' ) {
- $.ready.then( app.load );
- } else {
- app.load();
- }
- } );
- app.bindUIActions();
- app.bindOptinMonster();
- },
- /**
- * Document ready.
- *
- * @since 1.2.3
- */
- ready: function() {
- // Clear URL - remove wpforms_form_id.
- app.clearUrlQuery();
- // Set user identifier.
- app.setUserIndentifier();
- app.loadValidation();
- app.loadDatePicker();
- app.loadTimePicker();
- app.loadInputMask();
- app.loadSmartPhoneField();
- app.loadPayments();
- app.loadMailcheck();
- app.loadChoicesJS();
- // Randomize elements.
- $( '.wpforms-randomize' ).each( function() {
- var $list = $( this ),
- $listItems = $list.children();
- while ( $listItems.length ) {
- $list.append( $listItems.splice( Math.floor( Math.random() * $listItems.length ), 1 )[0] );
- }
- } );
- // Unlock pagebreak navigation.
- $( '.wpforms-page-button' ).prop( 'disabled', false );
- $( document ).trigger( 'wpformsReady' );
- },
- /**
- * Page load.
- *
- * @since 1.2.3
- */
- load: function() {
- },
- //--------------------------------------------------------------------//
- // Initializing
- //--------------------------------------------------------------------//
- /**
- * Remove wpforms_form_id from URL.
- *
- * @since 1.5.2
- */
- clearUrlQuery: function() {
- var loc = window.location,
- query = loc.search;
- if ( query.indexOf( 'wpforms_form_id=' ) !== -1 ) {
- query = query.replace( /([&?]wpforms_form_id=[0-9]*$|wpforms_form_id=[0-9]*&|[?&]wpforms_form_id=[0-9]*(?=#))/, '' );
- history.replaceState( {}, null, loc.origin + loc.pathname + query );
- }
- },
- /**
- * Load jQuery Validation.
- *
- * @since 1.2.3
- */
- loadValidation: function() {
- // Only load if jQuery validation library exists.
- if ( typeof $.fn.validate !== 'undefined' ) {
- // jQuery Validation library will not correctly validate
- // fields that do not have a name attribute, so we use the
- // `wpforms-input-temp-name` class to add a temporary name
- // attribute before validation is initialized, then remove it
- // before the form submits.
- $( '.wpforms-input-temp-name' ).each( function( index, el ) {
- var random = Math.floor( Math.random() * 9999 ) + 1;
- $( this ).attr( 'name', 'wpf-temp-' + random );
- } );
- // Prepend URL field contents with http:// if user input doesn't contain a schema.
- $( '.wpforms-validate input[type=url]' ).change( function() {
- var url = $( this ).val();
- if ( ! url ) {
- return false;
- }
- if ( url.substr( 0, 7 ) !== 'http://' && url.substr( 0, 8 ) !== 'https://' ) {
- $( this ).val( 'http://' + url );
- }
- } );
- $.validator.messages.required = wpforms_settings.val_required;
- $.validator.messages.url = wpforms_settings.val_url;
- $.validator.messages.email = wpforms_settings.val_email;
- $.validator.messages.number = wpforms_settings.val_number;
- // Payments: Validate method for Credit Card Number.
- if ( typeof $.fn.payment !== 'undefined' ) {
- $.validator.addMethod( 'creditcard', function( value, element ) {
- //var type = $.payment.cardType(value);
- var valid = $.payment.validateCardNumber( value );
- return this.optional( element ) || valid;
- }, wpforms_settings.val_creditcard );
- // @todo validate CVC and expiration
- }
- // Validate method for file extensions.
- $.validator.addMethod( 'extension', function( value, element, param ) {
- param = 'string' === typeof param ? param.replace( /,/g, '|' ) : 'png|jpe?g|gif';
- return this.optional( element ) || value.match( new RegExp( '\\.(' + param + ')$', 'i' ) );
- }, wpforms_settings.val_fileextension );
- // Validate method for file size.
- $.validator.addMethod( 'maxsize', function( value, element, param ) {
- var maxSize = param,
- optionalValue = this.optional( element ),
- i, len, file;
- if ( optionalValue ) {
- return optionalValue;
- }
- if ( element.files && element.files.length ) {
- i = 0;
- len = element.files.length;
- for ( ; i < len; i++ ) {
- file = element.files[i];
- if ( file.size > maxSize ) {
- return false;
- }
- }
- }
- return true;
- }, wpforms_settings.val_filesize );
- // Validate email addresses.
- $.validator.methods.email = function( value, element ) {
- // Test email on the multiple @ and spaces:
- // - no spaces allowed in the local and domain parts
- // - only one @ after the local part allowed
- var structureTest = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test( value );
- // Test emails on the multiple dots:
- // - start and finish with dot not allowed
- // - two dots in a row not allowed
- var dotsTest = /^(?!\.)(?!.*?\.\.).*[^.]$/.test( value );
- return this.optional( element ) || ( structureTest && dotsTest );
- };
- // Validate email by allowlist/blocklist.
- $.validator.addMethod( 'restricted-email', function( value, element ) {
- var validator = this,
- $el = $( element ),
- $field = $el.closest( '.wpforms-field' ),
- $form = $el.closest( '.wpforms-form' ),
- isValid = 'pending';
- if ( ! $el.val().length ) {
- return true;
- }
- this.startRequest( element );
- $.post( {
- url: wpforms_settings.ajaxurl,
- type: 'post',
- async: false,
- data: {
- 'action': 'wpforms_restricted_email',
- 'form_id': $form.data( 'formid' ),
- 'field_id': $field.data( 'field-id' ),
- 'email': $el.val(),
- },
- dataType: 'json',
- success: function( response ) {
- var errors = {};
- isValid = response.success && response.data;
- if ( isValid ) {
- validator.resetInternals();
- validator.toHide = validator.errorsFor( element );
- validator.showErrors();
- } else {
- errors[ element.name ] = wpforms_settings.val_email_restricted;
- validator.showErrors( errors );
- }
- validator.stopRequest( element, isValid );
- },
- } );
- return isValid;
- }, wpforms_settings.val_email_restricted );
- // Validate confirmations.
- $.validator.addMethod( 'confirm', function( value, element, param ) {
- return value === $( element ).closest( '.wpforms-field' ).find( 'input:first-child' ).val();
- }, wpforms_settings.val_confirm );
- // Validate required payments.
- $.validator.addMethod( 'required-payment', function( value, element ) {
- return app.amountSanitize( value ) > 0;
- }, wpforms_settings.val_requiredpayment );
- // Validate 12-hour time.
- $.validator.addMethod( 'time12h', function( value, element ) {
- return this.optional( element ) || /^((0?[1-9]|1[012])(:[0-5]\d){1,2}(\ ?[AP]M))$/i.test( value );
- }, wpforms_settings.val_time12h );
- // Validate 24-hour time.
- $.validator.addMethod( 'time24h', function( value, element ) {
- return this.optional( element ) || /^(([0-1]?[0-9])|([2][0-3])):([0-5]?[0-9])(\ ?[AP]M)?$/i.test( value );
- }, wpforms_settings.val_time24h );
- // Validate time limits.
- $.validator.addMethod( 'time-limit', function( value, element ) { // eslint-disable-line complexity
- var $input = $( element ),
- minTime = $input.data( 'min-time' ),
- maxTime = $input.data( 'max-time' ),
- isRequired = $input.prop( 'required' ),
- isLimited = typeof minTime !== 'undefined';
- if ( ! isLimited ) {
- return true;
- }
- if ( ! isRequired && app.empty( value ) ) {
- return true;
- }
- if ( app.compareTimesGreaterThan( maxTime, minTime ) ) {
- return app.compareTimesGreaterThan( value, minTime ) && app.compareTimesGreaterThan( maxTime, value );
- }
- return ( app.compareTimesGreaterThan( value, minTime ) && app.compareTimesGreaterThan( value, maxTime ) ) ||
- ( app.compareTimesGreaterThan( minTime, value ) && app.compareTimesGreaterThan( maxTime, value ) );
- }, function( params, element ) {
- var $input = $( element ),
- minTime = $input.data( 'min-time' ),
- maxTime = $input.data( 'max-time' );
- // Replace `00:**pm` with `12:**pm`.
- minTime = minTime.replace( /^00:([0-9]{2})pm$/, '12:$1pm' );
- maxTime = maxTime.replace( /^00:([0-9]{2})pm$/, '12:$1pm' );
- // Properly format time: add space before AM/PM, make uppercase.
- minTime = minTime.replace( /(am|pm)/g, ' $1' ).toUpperCase();
- maxTime = maxTime.replace( /(am|pm)/g, ' $1' ).toUpperCase();
- return wpforms_settings.val_time_limit
- .replace( '{minTime}', minTime )
- .replace( '{maxTime}', maxTime );
- } );
- // Validate checkbox choice limit.
- $.validator.addMethod( 'check-limit', function( value, element ) {
- var $ul = $( element ).closest( 'ul' ),
- $checked = $ul.find( 'input[type="checkbox"]:checked' ),
- choiceLimit = parseInt( $ul.attr( 'data-choice-limit' ) || 0, 10 );
- if ( 0 === choiceLimit ) {
- return true;
- }
- return $checked.length <= choiceLimit;
- }, function( params, element ) {
- var choiceLimit = parseInt( $( element ).closest( 'ul' ).attr( 'data-choice-limit' ) || 0, 10 );
- return wpforms_settings.val_checklimit.replace( '{#}', choiceLimit );
- } );
- // Validate Smart Phone Field.
- if ( typeof $.fn.intlTelInput !== 'undefined' ) {
- $.validator.addMethod( 'smart-phone-field', function( value, element ) {
- if ( value.match( /[^\d()\-+\s]/ ) ) {
- return false;
- }
- return this.optional( element ) || $( element ).intlTelInput( 'isValidNumber' );
- }, wpforms_settings.val_phone );
- }
- // Validate Input Mask minimum length.
- $.validator.addMethod( 'empty-blanks', function( value, element ) {
- if ( typeof $.fn.inputmask === 'undefined' ) {
- return true;
- }
- return ! ( value.indexOf( element.inputmask.opts.placeholder ) + 1 );
- }, wpforms_settings.val_empty_blanks );
- // Validate Payment item value on zero.
- $.validator.addMethod( 'required-positive-number', function( value, element ) {
- return app.amountSanitize( value ) > 0;
- }, wpforms_settings.val_number_positive );
- // Validate US Phone Field.
- $.validator.addMethod( 'us-phone-field', function( value, element ) {
- if ( value.match( /[^\d()\-+\s]/ ) ) {
- return false;
- }
- return this.optional( element ) || value.replace( /[^\d]/g, '' ).length === 10;
- }, wpforms_settings.val_phone );
- // Validate International Phone Field.
- $.validator.addMethod( 'int-phone-field', function( value, element ) {
- if ( value.match( /[^\d()\-+\s]/ ) ) {
- return false;
- }
- return this.optional( element ) || value.replace( /[^\d]/g, '' ).length > 0;
- }, wpforms_settings.val_phone );
- // Validate password strength.
- $.validator.addMethod( 'password-strength', function( value, element ) {
- return WPFormsPasswordField.passwordStrength( value, element ) >= Number( $( element ).data( 'password-strength-level' ) );
- }, wpforms_settings.val_password_strength );
- // Finally load jQuery Validation library for our forms.
- $( '.wpforms-validate' ).each( function() {
- var form = $( this ),
- formID = form.data( 'formid' ),
- properties;
- // TODO: cleanup this BC with wpforms_validate.
- if ( typeof window['wpforms_' + formID] !== 'undefined' && window['wpforms_' + formID].hasOwnProperty( 'validate' ) ) {
- properties = window['wpforms_' + formID].validate;
- } else if ( typeof wpforms_validate !== 'undefined' ) {
- properties = wpforms_validate;
- } else {
- properties = {
- errorClass: 'wpforms-error',
- validClass: 'wpforms-valid',
- ignore: ':hidden:not(textarea.wp-editor-area), .wpforms-conditional-hide textarea.wp-editor-area',
- errorPlacement: function( error, element ) {
- if ( app.isLikertScaleField( element ) ) {
- element.closest( 'table' ).hasClass( 'single-row' ) ?
- element.closest( '.wpforms-field' ).append( error ) :
- element.closest( 'tr' ).find( 'th' ).append( error );
- } else if ( app.isWrappedField( element ) ) {
- element.closest( '.wpforms-field' ).append( error );
- } else if ( app.isDateTimeField( element ) ) {
- app.dateTimeErrorPlacement( element, error );
- } else if ( app.isFieldInColumn( element ) ) {
- element.parent().append( error );
- } else {
- error.insertAfter( element );
- }
- },
- highlight: function( element, errorClass, validClass ) {
- var $element = $( element ),
- $field = $element.closest( '.wpforms-field' ),
- inputName = $element.attr( 'name' );
- if ( 'radio' === $element.attr( 'type' ) || 'checkbox' === $element.attr( 'type' ) ) {
- $field.find( 'input[name="' + inputName + '"]' ).addClass( errorClass ).removeClass( validClass );
- } else {
- $element.addClass( errorClass ).removeClass( validClass );
- }
- $field.addClass( 'wpforms-has-error' );
- },
- unhighlight: function( element, errorClass, validClass ) {
- var $element = $( element ),
- $field = $element.closest( '.wpforms-field' ),
- inputName = $element.attr( 'name' );
- if ( 'radio' === $element.attr( 'type' ) || 'checkbox' === $element.attr( 'type' ) ) {
- $field.find( 'input[name="' + inputName + '"]' ).addClass( validClass ).removeClass( errorClass );
- } else {
- $element.addClass( validClass ).removeClass( errorClass );
- }
- $field.removeClass( 'wpforms-has-error' );
- },
- submitHandler: function( form ) {
- var $form = $( form ),
- $submit = $form.find( '.wpforms-submit' ),
- altText = $submit.data( 'alt-text' ),
- recaptchaID = $submit.get( 0 ).recaptchaID;
- if ( $form.data( 'token' ) && 0 === $( '.wpforms-token', $form ).length ) {
- $( '<input type="hidden" class="wpforms-token" name="wpforms[token]" />' )
- .val( $form.data( 'token' ) )
- .appendTo( $form );
- }
- $submit.prop( 'disabled', true );
- $form.find( '#wpforms-field_recaptcha-error' ).remove();
- // Display processing text.
- if ( altText ) {
- $submit.text( altText );
- }
- if ( ! app.empty( recaptchaID ) || recaptchaID === 0 ) {
- // Form contains invisible reCAPTCHA.
- grecaptcha.execute( recaptchaID ).then( null, function( reason ) {
- reason = ( null === reason ) ? '' : '<br>' + reason;
- $form.find( '.wpforms-recaptcha-container' ).append( '<label id="wpforms-field_recaptcha-error" class="wpforms-error"> ' + wpforms_settings.val_recaptcha_fail_msg + reason + '</label>' );
- $submit.prop( 'disabled', false );
- } );
- return false;
- }
- // Remove name attributes if needed.
- $( '.wpforms-input-temp-name' ).removeAttr( 'name' );
- app.formSubmit( $form );
- },
- invalidHandler: function( event, validator ) {
- if ( typeof validator.errorList[0] !== 'undefined' ) {
- app.scrollToError( $( validator.errorList[0].element ) );
- }
- },
- onkeyup: function( element, event ) {
- // This code is copied from JQuery Validate 'onkeyup' method with only one change: 'wpforms-novalidate-onkeyup' class check.
- var excludedKeys = [ 16, 17, 18, 20, 35, 36, 37, 38, 39, 40, 45, 144, 225 ];
- if ( $( element ).hasClass( 'wpforms-novalidate-onkeyup' ) ) {
- return; // Disable onkeyup validation for some elements (e.g. remote calls).
- }
- if ( 9 === event.which && '' === this.elementValue( element ) || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {
- return;
- } else if ( element.name in this.submitted || element.name in this.invalid ) {
- this.element( element );
- }
- },
- onfocusout: function( element ) {
- // This code is copied from JQuery Validate 'onfocusout' method with only one change: 'wpforms-novalidate-onkeyup' class check.
- var validate = false;
- if ( $( element ).hasClass( 'wpforms-novalidate-onkeyup' ) && ! element.value ) {
- validate = true; // Empty value error handling for elements with onkeyup validation disabled.
- }
- if ( ! this.checkable( element ) && ( element.name in this.submitted || ! this.optional( element ) ) ) {
- validate = true;
- }
- if ( validate ) {
- this.element( element );
- }
- },
- onclick: function( element ) {
- var validate = false,
- type = ( element || {} ).type,
- $el = $( element );
- if ( [ 'checkbox', 'radio' ].indexOf( type ) > -1 ) {
- if ( $el.hasClass( 'wpforms-likert-scale-option' ) ) {
- $el = $el.closest( 'tr' );
- } else {
- $el = $el.closest( '.wpforms-field' );
- }
- $el.find( 'label.wpforms-error' ).remove();
- validate = true;
- }
- if ( validate ) {
- this.element( element );
- }
- },
- };
- }
- form.validate( properties );
- } );
- }
- },
- /**
- * Is field inside column.
- *
- * @since 1.6.3
- *
- * @param {jQuery} element current form element.
- *
- * @returns {boolean} true/false.
- */
- isFieldInColumn: function( element ) {
- return element.parent().hasClass( 'wpforms-one-half' ) ||
- element.parent().hasClass( 'wpforms-two-fifths' ) ||
- element.parent().hasClass( 'wpforms-one-fifth' );
- },
- /**
- * Is datetime field.
- *
- * @since 1.6.3
- *
- * @param {jQuery} element current form element.
- *
- * @returns {boolean} true/false.
- */
- isDateTimeField: function( element ) {
- return element.hasClass( 'wpforms-timepicker' ) ||
- element.hasClass( 'wpforms-datepicker' ) ||
- ( element.is( 'select' ) && element.attr( 'class' ).match( /date-month|date-day|date-year/ ) );
- },
- /**
- * Is field wrapped in some container.
- *
- * @since 1.6.3
- *
- * @param {jQuery} element current form element.
- *
- * @returns {boolean} true/false.
- */
- isWrappedField: function( element ) { // eslint-disable-line complexity
- return 'checkbox' === element.attr( 'type' ) ||
- 'radio' === element.attr( 'type' ) ||
- 'range' === element.attr( 'type' ) ||
- 'select' === element.is( 'select' ) ||
- element.parent().hasClass( 'iti' ) ||
- element.hasClass( 'wpforms-validation-group-member' ) ||
- element.hasClass( 'choicesjs-select' ) ||
- element.hasClass( 'wpforms-net-promoter-score-option' );
- },
- /**
- * Is likert scale field.
- *
- * @since 1.6.3
- *
- * @param {jQuery} element current form element.
- *
- * @returns {boolean} true/false.
- */
- isLikertScaleField: function( element ) {
- return element.hasClass( 'wpforms-likert-scale-option' );
- },
- /**
- * Print error message into date time fields.
- *
- * @since 1.6.3
- *
- * @param {jQuery} element current form element.
- * @param {string} error Error message.
- */
- dateTimeErrorPlacement: function( element, error ) {
- var $wrapper = element.closest( '.wpforms-field-row-block, .wpforms-field-date-time' );
- if ( $wrapper.length ) {
- if ( ! $wrapper.find( 'label.wpforms-error' ).length ) {
- $wrapper.append( error );
- }
- } else {
- element.closest( '.wpforms-field' ).append( error );
- }
- },
- /**
- * Load jQuery Date Picker.
- *
- * @since 1.2.3
- */
- loadDatePicker: function() {
- // Only load if jQuery datepicker library exists.
- if ( typeof $.fn.flatpickr !== 'undefined' ) {
- $( '.wpforms-datepicker-wrap' ).each( function() {
- var element = $( this ),
- $input = element.find( 'input' ),
- form = element.closest( '.wpforms-form' ),
- formID = form.data( 'formid' ),
- fieldID = element.closest( '.wpforms-field' ).data( 'field-id' ),
- properties;
- if ( typeof window['wpforms_' + formID + '_' + fieldID] !== 'undefined' && window['wpforms_' + formID + '_' + fieldID].hasOwnProperty( 'datepicker' ) ) {
- properties = window['wpforms_' + formID + '_' + fieldID].datepicker;
- } else if ( typeof window['wpforms_' + formID] !== 'undefined' && window['wpforms_' + formID].hasOwnProperty( 'datepicker' ) ) {
- properties = window['wpforms_' + formID].datepicker;
- } else if ( typeof wpforms_datepicker !== 'undefined' ) {
- properties = wpforms_datepicker;
- } else {
- properties = {
- disableMobile: true,
- };
- }
- // Redefine locale only if user doesn't do that manually and we have the locale.
- if (
- ! properties.hasOwnProperty( 'locale' ) &&
- typeof wpforms_settings !== 'undefined' &&
- wpforms_settings.hasOwnProperty( 'locale' )
- ) {
- properties.locale = wpforms_settings.locale;
- }
- properties.wrap = true;
- properties.dateFormat = $input.data( 'date-format' );
- if ( $input.data( 'disable-past-dates' ) === 1 ) {
- properties.minDate = 'today';
- }
- var limitDays = $input.data( 'limit-days' ),
- weekDays = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ];
- if ( limitDays && limitDays !== '' ) {
- limitDays = limitDays.split( ',' );
- properties.disable = [ function( date ) {
- var limitDay;
- for ( var i in limitDays ) {
- limitDay = weekDays.indexOf( limitDays[ i ] );
- if ( limitDay === date.getDay() ) {
- return false;
- }
- }
- return true;
- } ];
- }
- // Toggle clear date icon.
- properties.onChange = function( selectedDates, dateStr, instance ) {
- var display = dateStr === '' ? 'none' : 'block';
- element.find( '.wpforms-datepicker-clear' ).css( 'display', display );
- };
- element.flatpickr( properties );
- } );
- }
- },
- /**
- * Load jQuery Time Picker.
- *
- * @since 1.2.3
- */
- loadTimePicker: function() {
- // Only load if jQuery timepicker library exists.
- if ( typeof $.fn.timepicker !== 'undefined' ) {
- $( '.wpforms-timepicker' ).each( function() {
- var element = $( this ),
- form = element.closest( '.wpforms-form' ),
- formID = form.data( 'formid' ),
- fieldID = element.closest( '.wpforms-field' ).data( 'field-id' ),
- properties;
- if (
- typeof window['wpforms_' + formID + '_' + fieldID] !== 'undefined' &&
- window['wpforms_' + formID + '_' + fieldID].hasOwnProperty( 'timepicker' )
- ) {
- properties = window['wpforms_' + formID + '_' + fieldID].timepicker;
- } else if (
- typeof window['wpforms_' + formID] !== 'undefined' &&
- window['wpforms_' + formID].hasOwnProperty( 'timepicker' )
- ) {
- properties = window['wpforms_' + formID].timepicker;
- } else if ( typeof wpforms_timepicker !== 'undefined' ) {
- properties = wpforms_timepicker;
- } else {
- properties = {
- scrollDefault: 'now',
- forceRoundTime: true,
- };
- }
- element.timepicker( properties );
- } );
- }
- },
- /**
- * Load jQuery input masks.
- *
- * @since 1.2.3
- */
- loadInputMask: function() {
- // Only load if jQuery input mask library exists.
- if ( typeof $.fn.inputmask === 'undefined' ) {
- return;
- }
- $( '.wpforms-masked-input' ).inputmask();
- },
- /**
- * Load smart phone field.
- *
- * @since 1.5.2
- */
- loadSmartPhoneField: function() {
- // Only load if library exists.
- if ( typeof $.fn.intlTelInput === 'undefined' ) {
- return;
- }
- var inputOptions = {};
- // Determine the country by IP if no GDPR restrictions enabled.
- if ( ! wpforms_settings.gdpr ) {
- inputOptions.geoIpLookup = app.currentIpToCountry;
- }
- // Try to kick in an alternative solution if GDPR restrictions are enabled.
- if ( wpforms_settings.gdpr ) {
- var lang = this.getFirstBrowserLanguage(),
- countryCode = lang.indexOf( '-' ) > -1 ? lang.split( '-' ).pop() : '';
- }
- // Make sure the library recognizes browser country code to avoid console error.
- if ( countryCode ) {
- var countryData = window.intlTelInputGlobals.getCountryData();
- countryData = countryData.filter( function( country ) {
- return country.iso2 === countryCode.toLowerCase();
- } );
- countryCode = countryData.length ? countryCode : '';
- }
- // Set default country.
- inputOptions.initialCountry = wpforms_settings.gdpr && countryCode ? countryCode : 'auto';
- $( '.wpforms-smart-phone-field' ).each( function( i, el ) {
- var $el = $( el );
- // Hidden input allows to include country code into submitted data.
- inputOptions.hiddenInput = $el.closest( '.wpforms-field-phone' ).data( 'field-id' );
- inputOptions.utilsScript = wpforms_settings.wpforms_plugin_url + 'pro/assets/js/vendor/jquery.intl-tel-input-utils.js';
- $el.intlTelInput( inputOptions );
- // For proper validation, we should preserve the name attribute of the input field.
- // But we need to modify original input name not to interfere with a hidden input.
- $el.attr( 'name', 'wpf-temp-' + $el.attr( 'name' ) );
- // Add special class to remove name attribute before submitting.
- // So, only the hidden input value will be submitted.
- $el.addClass( 'wpforms-input-temp-name' );
- // Instantly update a hidden form input with a correct data.
- // Previously "blur" only was used, which is broken in case Enter was used to submit the form.
- $el.on( 'blur input', function() {
- if ( $el.intlTelInput( 'isValidNumber' ) || ! app.empty( window.WPFormsEditEntry ) ) {
- $el.siblings( 'input[type="hidden"]' ).val( $el.intlTelInput( 'getNumber' ) );
- }
- } );
- } );
- // Update hidden input of the `Smart` phone field to be sure the latest value will be submitted.
- $( '.wpforms-form' ).on( 'wpformsBeforeFormSubmit', function() {
- $( this ).find( '.wpforms-smart-phone-field' ).trigger( 'input' );
- } );
- },
- /**
- * Payments: Do various payment-related tasks on load.
- *
- * @since 1.2.6
- */
- loadPayments: function() {
- // Update Total field(s) with latest calculation.
- $( '.wpforms-payment-total' ).each( function( index, el ) {
- app.amountTotal( this );
- } );
- // Credit card validation.
- if ( typeof $.fn.payment !== 'undefined' ) {
- $( '.wpforms-field-credit-card-cardnumber' ).payment( 'formatCardNumber' );
- $( '.wpforms-field-credit-card-cardcvc' ).payment( 'formatCardCVC' );
- }
- },
- /**
- * Load mailcheck.
- *
- * @since 1.5.3
- */
- loadMailcheck: function() {
- // Skip loading if `wpforms_mailcheck_enabled` filter return false.
- if ( ! wpforms_settings.mailcheck_enabled ) {
- return;
- }
- // Only load if library exists.
- if ( typeof $.fn.mailcheck === 'undefined' ) {
- return;
- }
- if ( wpforms_settings.mailcheck_domains.length > 0 ) {
- Mailcheck.defaultDomains = Mailcheck.defaultDomains.concat( wpforms_settings.mailcheck_domains );
- }
- if ( wpforms_settings.mailcheck_toplevel_domains.length > 0 ) {
- Mailcheck.defaultTopLevelDomains = Mailcheck.defaultTopLevelDomains.concat( wpforms_settings.mailcheck_toplevel_domains );
- }
- // Mailcheck suggestion.
- $( document ).on( 'blur', '.wpforms-field-email input', function() {
- var $input = $( this ),
- id = $input.attr( 'id' );
- $input.mailcheck( {
- suggested: function( $el, suggestion ) {
- if ( suggestion.address.match( /^xn--/ ) ) {
- suggestion.full = punycode.toUnicode( decodeURI( suggestion.full ) );
- var parts = suggestion.full.split( '@' );
- suggestion.address = parts[0];
- suggestion.domain = parts[1];
- }
- if ( suggestion.domain.match( /^xn--/ ) ) {
- suggestion.domain = punycode.toUnicode( decodeURI( suggestion.domain ) );
- }
- var address = decodeURI( suggestion.address ).replaceAll( /[<>'"()/\\|:;=@%&\s]/ig, '' ).substr( 0, 64 ),
- domain = decodeURI( suggestion.domain ).replaceAll( /[<>'"()/\\|:;=@%&+_\s]/ig, '' );
- suggestion = '<a href="#" class="mailcheck-suggestion" data-id="' + id + '" title="' + wpforms_settings.val_email_suggestion_title + '">' + address + '@' + domain + '</a>';
- suggestion = wpforms_settings.val_email_suggestion.replace( '{suggestion}', suggestion );
- $el.closest( '.wpforms-field' ).find( '#' + id + '_suggestion' ).remove();
- $el.parent().append( '<label class="wpforms-error mailcheck-error" id="' + id + '_suggestion">' + suggestion + '</label>' );
- },
- empty: function() {
- $( '#' + id + '_suggestion' ).remove();
- },
- } );
- } );
- // Apply Mailcheck suggestion.
- $( document ).on( 'click', '.wpforms-field-email .mailcheck-suggestion', function( e ) {
- var $suggestion = $( this ),
- $field = $suggestion.closest( '.wpforms-field' ),
- id = $suggestion.data( 'id' );
- e.preventDefault();
- $field.find( '#' + id ).val( $suggestion.text() );
- $suggestion.parent().remove();
- } );
- },
- /**
- * Load Choices.js library for all Modern style Dropdown fields (<select>).
- *
- * @since 1.6.1
- */
- loadChoicesJS: function() {
- // Loads if function exists.
- if ( typeof window.Choices !== 'function' ) {
- return;
- }
- $( '.wpforms-field-select-style-modern .choicesjs-select, .wpforms-field-payment-select .choicesjs-select' ).each( function( idx, el ) {
- var args = window.wpforms_choicesjs_config || {},
- searchEnabled = $( el ).data( 'search-enabled' );
- args.searchEnabled = 'undefined' !== typeof searchEnabled ? searchEnabled : true;
- args.callbackOnInit = function() {
- var self = this,
- $element = $( self.passedElement.element ),
- $input = $( self.input.element ),
- sizeClass = $element.data( 'size-class' );
- // Remove hidden attribute and hide `<select>` like a screen-reader text.
- // It's important for field validation.
- $element
- .removeAttr( 'hidden' )
- .addClass( self.config.classNames.input + '--hidden' );
- // Add CSS-class for size.
- if ( sizeClass ) {
- $( self.containerOuter.element ).addClass( sizeClass );
- }
- /**
- * If a multiple select has selected choices - hide a placeholder input.
- * We use custom styles like `.screen-reader-text` for it,
- * because it avoids an issue with closing a dropdown.
- */
- if ( $element.prop( 'multiple' ) ) {
- // On init event.
- if ( self.getValue( true ).length ) {
- $input.addClass( self.config.classNames.input + '--hidden' );
- }
- }
- // On change event.
- $element.on( 'change', function() {
- var validator;
- // Listen if multiple select has choices.
- if ( $element.prop( 'multiple' ) ) {
- self.getValue( true ).length > 0 ? $input.addClass( self.config.classNames.input + '--hidden' ) : $input.removeClass( self.config.classNames.input + '--hidden' );
- }
- validator = $element.closest( 'form' ).data( 'validator' );
- if ( ! validator ) {
- return;
- }
- validator.element( $element );
- } );
- };
- args.callbackOnCreateTemplates = function() {
- var self = this,
- $element = $( self.passedElement.element );
- return {
- // Change default template for option.
- option: function( item ) {
- var opt = Choices.defaults.templates.option.call( this, item );
- // Add a `.placeholder` class for placeholder option - it needs for WPForm CL.
- if ( 'undefined' !== typeof item.placeholder && true === item.placeholder ) {
- opt.classList.add( 'placeholder' );
- }
- // Add a `data-amount` attribute for payment dropdown.
- // It will be copy from a Choices.js `data-custom-properties` attribute.
- if ( $element.hasClass( 'wpforms-payment-price' ) && 'undefined' !== typeof item.customProperties && null !== item.customProperties ) {
- opt.dataset.amount = item.customProperties;
- }
- return opt;
- },
- };
- };
- // Save choicesjs instance for future access.
- $( el ).data( 'choicesjs', new Choices( el, args ) );
- } );
- },
- //--------------------------------------------------------------------//
- // Binds.
- //--------------------------------------------------------------------//
- /**
- * Element bindings.
- *
- * @since 1.2.3
- */
- bindUIActions: function() {
- // Pagebreak navigation.
- $( document ).on( 'click', '.wpforms-page-button', function( event ) {
- event.preventDefault();
- app.pagebreakNav( this );
- } );
- // Payments: Update Total field(s) when latest calculation.
- $( document ).on( 'change input', '.wpforms-payment-price', function() {
- app.amountTotal( this, true );
- } );
- // Payments: Restrict user input payment fields.
- $( document ).on( 'input', '.wpforms-payment-user-input', function() {
- var $this = $( this ),
- amount = $this.val();
- $this.val( amount.replace( /[^0-9.,]/g, '' ) );
- } );
- // Payments: Sanitize/format user input amounts.
- $( document ).on( 'focusout', '.wpforms-payment-user-input', function() {
- var $this = $( this ),
- amount = $this.val();
- if ( ! amount ) {
- return amount;
- }
- var sanitized = app.amountSanitize( amount ),
- formatted = app.amountFormat( sanitized );
- $this.val( formatted );
- } );
- // Payments: Update Total field(s) when conditionals are processed.
- $( document ).on( 'wpformsProcessConditionals', function( e, el ) {
- app.amountTotal( el, true );
- } );
- // Rating field: hover effect.
- $( '.wpforms-field-rating-item' ).hover(
- function() {
- $( this ).parent().find( '.wpforms-field-rating-item' ).removeClass( 'selected hover' );
- $( this ).prevAll().addBack().addClass( 'hover' );
- },
- function() {
- $( this ).parent().find( '.wpforms-field-rating-item' ).removeClass( 'selected hover' );
- $( this ).parent().find( 'input:checked' ).parent().prevAll().addBack().addClass( 'selected' );
- }
- );
- // Rating field: toggle selected state.
- $( document ).on( 'change', '.wpforms-field-rating-item input', function() {
- var $this = $( this ),
- $wrap = $this.closest( '.wpforms-field-rating-items' ),
- $items = $wrap.find( '.wpforms-field-rating-item' );
- $items.removeClass( 'hover selected' );
- $this.parent().prevAll().addBack().addClass( 'selected' );
- } );
- // Rating field: preselect the selected rating (from dynamic/fallback population).
- $( function() {
- $( '.wpforms-field-rating-item input:checked' ).change();
- } );
- // Checkbox/Radio/Payment checkbox: make labels keyboard-accessible.
- $( document ).on( 'keypress', '.wpforms-image-choices-item label', function( event ) {
- var $this = $( this ),
- $field = $this.closest( '.wpforms-field' );
- if ( $field.hasClass( 'wpforms-conditional-hide' ) ) {
- event.preventDefault();
- return false;
- }
- // Cause the input to be clicked when clicking the label.
- if ( 13 === event.which ) {
- $( '#' + $this.attr( 'for' ) ).click();
- }
- } );
- // IE: Click on the `image choice` image should trigger the click event on the input (checkbox or radio) field.
- if ( window.document.documentMode ) {
- $( document ).on( 'click', '.wpforms-image-choices-item img', function() {
- $( this ).closest( 'label' ).find( 'input' ).click();
- } );
- }
- $( document ).on( 'change', '.wpforms-field-checkbox input, .wpforms-field-radio input, .wpforms-field-payment-multiple input, .wpforms-field-payment-checkbox input, .wpforms-field-gdpr-checkbox input', function( event ) {
- var $this = $( this ),
- $field = $this.closest( '.wpforms-field' );
- if ( $field.hasClass( 'wpforms-conditional-hide' ) ) {
- event.preventDefault();
- return false;
- }
- switch ( $this.attr( 'type' ) ) {
- case 'radio':
- $this.closest( 'ul' ).find( 'li' ).removeClass( 'wpforms-selected' ).find( 'input[type=radio]' ).removeProp( 'checked' );
- $this
- .prop( 'checked', true )
- .closest( 'li' ).addClass( 'wpforms-selected' );
- break;
- case 'checkbox':
- if ( $this.is( ':checked' ) ) {
- $this.closest( 'li' ).addClass( 'wpforms-selected' );
- $this.prop( 'checked', true );
- } else {
- $this.closest( 'li' ).removeClass( 'wpforms-selected' );
- $this.prop( 'checked', false );
- }
- break;
- }
- } );
- // Upload fields: Check combined file size.
- $( document ).on( 'change', '.wpforms-field-file-upload input[type=file]:not(".dropzone-input")', function() {
- var $this = $( this ),
- $uploads = $this.closest( 'form.wpforms-form' ).find( '.wpforms-field-file-upload input:not(".dropzone-input")' ),
- totalSize = 0,
- postMaxSize = Number( wpforms_settings.post_max_size ),
- errorMsg = '<div class="wpforms-error-container-post_max_size">' + wpforms_settings.val_post_max_size + '</div>',
- errorCntTpl = '<div class="wpforms-error-container">{errorMsg}</span></div>',
- $submitCnt = $this.closest( 'form.wpforms-form' ).find( '.wpforms-submit-container' ),
- $submitBtn = $submitCnt.find( 'button.wpforms-submit' ),
- $errorCnt = $submitCnt.prev();
- // Calculating totalSize.
- $uploads.each( function() {
- var $upload = $( this ),
- i = 0,
- len = $upload[0].files.length;
- for ( ; i < len; i++ ) {
- totalSize += $upload[0].files[i].size;
- }
- } );
- // Checking totalSize.
- if ( totalSize > postMaxSize ) {
- // Convert sizes to Mb.
- totalSize = Number( ( totalSize / 1048576 ).toFixed( 3 ) );
- postMaxSize = Number( ( postMaxSize / 1048576 ).toFixed( 3 ) );
- // Preparing error message.
- errorMsg = errorMsg.replace( /{totalSize}/, totalSize ).replace( /{maxSize}/, postMaxSize );
- // Output error message.
- if ( $errorCnt.hasClass( 'wpforms-error-container' ) ) {
- $errorCnt.find( '.wpforms-error-container-post_max_size' ).remove();
- $errorCnt.append( errorMsg );
- } else {
- $submitCnt.before( errorCntTpl.replace( /{errorMsg}/, errorMsg ) );
- }
- // Disable submit button.
- $submitBtn.prop( 'disabled', true );
- } else {
- // Remove error and release submit button.
- $errorCnt.find( '.wpforms-error-container-post_max_size' ).remove();
- $submitBtn.prop( 'disabled', false );
- }
- } );
- // Number Slider field: update hints.
- $( document ).on( 'change input', '.wpforms-field-number-slider input[type=range]', function( event ) {
- var hintEl = $( event.target ).siblings( '.wpforms-field-number-slider-hint' );
- hintEl.html( hintEl.data( 'hint' ).replace( '{value}', '<b>' + event.target.value + '</b>' ) );
- } );
- // Enter key event.
- $( document ).on( 'keydown', '.wpforms-form input', function( e ) {
- if ( e.keyCode !== 13 ) {
- return;
- }
- var $t = $( this ),
- $page = $t.closest( '.wpforms-page' );
- if ( $page.length === 0 ) {
- return;
- }
- if ( [ 'text', 'tel', 'number', 'email', 'url', 'radio', 'checkbox' ].indexOf( $t.attr( 'type' ) ) < 0 ) {
- return;
- }
- if ( $t.hasClass( 'wpforms-datepicker' ) ) {
- $t.flatpickr( 'close' );
- }
- e.preventDefault();
- if ( $page.hasClass( 'last' ) ) {
- $page.closest( '.wpforms-form' ).find( '.wpforms-submit' ).click();
- return;
- }
- $page.find( '.wpforms-page-next' ).click();
- } );
- // Allow only numbers, minus and decimal point to be entered into the Numbers field.
- $( document ).on( 'keypress', '.wpforms-field-number input', function( e ) {
- return /^[-0-9.]+$/.test( String.fromCharCode( e.keyCode || e.which ) );
- } );
- },
- /**
- * Entry preview field callback for a page changing.
- *
- * @since 1.6.9
- * @deprecated 1.7.0
- *
- * @param {Event} event Event.
- * @param {int} currentPage Current page.
- * @param {jQuery} $form Current form.
- */
- entryPreviewFieldPageChange: function( event, currentPage, $form ) {
- console.warn( 'WARNING! Obsolete function called. Function wpforms.entryPreviewFieldPageChange has been deprecated, please use the WPFormsEntryPreview.pageChange function instead!' );
- WPFormsEntryPreview.pageChange( event, currentPage, $form );
- },
- /**
- * Update the entry preview fields on the page.
- *
- * @since 1.6.9
- * @deprecated 1.7.0
- *
- * @param {int} currentPage Current page.
- * @param {jQuery} $form Current form.
- */
- entryPreviewFieldUpdate: function( currentPage, $form ) {
- console.warn( 'WARNING! Obsolete function called. Function wpforms.entryPreviewFieldUpdate has been deprecated, please use the WPFormsEntryPreview.update function instead!' );
- WPFormsEntryPreview.update( currentPage, $form );
- },
- /**
- * Scroll to and focus on the field with error.
- *
- * @since 1.5.8
- *
- * @param {jQuery} $el Form, container or input element jQuery object.
- */
- scrollToError: function( $el ) {
- if ( $el.length === 0 ) {
- return;
- }
- // Look for a field with an error inside an $el.
- var $field = $el.find( '.wpforms-field.wpforms-has-error' );
- // Look outside in not found inside.
- if ( $field.length === 0 ) {
- $field = $el.closest( '.wpforms-field' );
- }
- if ( $field.length === 0 ) {
- return;
- }
- var offset = $field.offset();
- if ( typeof offset === 'undefined' ) {
- return;
- }
- app.animateScrollTop( offset.top - 75, 750 ).done( function() {
- var $error = $field.find( '.wpforms-error' ).first();
- if ( typeof $error.focus === 'function' ) {
- $error.focus();
- }
- } );
- },
- /**
- * Update Pagebreak navigation.
- *
- * @since 1.2.2
- *
- * @param {jQuery} el jQuery element object.
- */
- pagebreakNav: function( el ) {
- var $this = $( el ),
- valid = true,
- action = $this.data( 'action' ),
- page = $this.data( 'page' ),
- page2 = page,
- next = page + 1,
- prev = page - 1,
- $form = $this.closest( '.wpforms-form' ),
- $page = $form.find( '.wpforms-page-' + page ),
- $submit = $form.find( '.wpforms-submit-container' ),
- $indicator = $form.find( '.wpforms-page-indicator' ),
- $reCAPTCHA = $form.find( '.wpforms-recaptcha-container' ),
- pageScroll = false;
- app.saveTinyMCE();
- // Page scroll.
- // TODO: cleanup this BC with wpform_pageScroll.
- if ( false === window.wpforms_pageScroll ) {
- pageScroll = false;
- } else if ( ! app.empty( window.wpform_pageScroll ) ) {
- pageScroll = window.wpform_pageScroll;
- } else {
- pageScroll = $indicator.data( 'scroll' ) !== 0 ? 75 : false;
- }
- // Toggling between the pages.
- if ( 'next' === action ) {
- // Validate.
- if ( typeof $.fn.validate !== 'undefined' ) {
- $page.find( ':input' ).each( function( index, el ) {
- // Skip input fields without `name` attribute, which could have fields.
- // E.g. `Placeholder` input for Modern dropdown.
- if ( ! $( el ).attr( 'name' ) ) {
- return;
- }
- if ( ! $( el ).valid() ) {
- valid = false;
- }
- } );
- // Scroll to first/top error on page.
- app.scrollToError( $page );
- }
- // Move to the next page.
- if ( valid ) {
- page2 = next;
- $this.trigger( 'wpformsBeforePageChange', [ page2, $form ] );
- $page.hide();
- var $nextPage = $form.find( '.wpforms-page-' + next );
- $nextPage.show();
- if ( $nextPage.hasClass( 'last' ) ) {
- $reCAPTCHA.show();
- $submit.show();
- }
- if ( pageScroll ) {
- // Scroll to top of the form.
- app.animateScrollTop( $form.offset().top - pageScroll, 750 );
- }
- $this.trigger( 'wpformsPageChange', [ page2, $form ] );
- }
- } else if ( 'prev' === action ) {
- // Move to the prev page.
- page2 = prev;
- $this.trigger( 'wpformsBeforePageChange', [ page2, $form ] );
- $page.hide();
- $form.find( '.wpforms-page-' + prev ).show();
- $reCAPTCHA.hide();
- $submit.hide();
- if ( pageScroll ) {
- // Scroll to the top of the form.
- app.animateScrollTop( $form.offset().top - pageScroll );
- }
- $this.trigger( 'wpformsPageChange', [ page2, $form ] );
- }
- if ( $indicator ) {
- var theme = $indicator.data( 'indicator' ),
- color = $indicator.data( 'indicator-color' );
- if ( 'connector' === theme || 'circles' === theme ) {
- $indicator.find( '.wpforms-page-indicator-page' ).removeClass( 'active' );
- $indicator.find( '.wpforms-page-indicator-page-' + page2 ).addClass( 'active' );
- $indicator.find( '.wpforms-page-indicator-page-number' ).removeAttr( 'style' );
- $indicator.find( '.active .wpforms-page-indicator-page-number' ).css( 'background-color', color );
- if ( 'connector' === theme ) {
- $indicator.find( '.wpforms-page-indicator-page-triangle' ).removeAttr( 'style' );
- $indicator.find( '.active .wpforms-page-indicator-page-triangle' ).css( 'border-top-color', color );
- }
- } else if ( 'progress' === theme ) {
- var $pageTitle = $indicator.find( '.wpforms-page-indicator-page-title' ),
- $pageSep = $indicator.find( '.wpforms-page-indicator-page-title-sep' ),
- totalPages = $form.find( '.wpforms-page' ).length,
- width = ( page2 / totalPages ) * 100;
- $indicator.find( '.wpforms-page-indicator-page-progress' ).css( 'width', width + '%' );
- $indicator.find( '.wpforms-page-indicator-steps-current' ).text( page2 );
- if ( $pageTitle.data( 'page-' + page2 + '-title' ) ) {
- $pageTitle.css( 'display', 'inline' ).text( $pageTitle.data( 'page-' + page2 + '-title' ) );
- $pageSep.css( 'display', 'inline' );
- } else {
- $pageTitle.css( 'display', 'none' );
- $pageSep.css( 'display', 'none' );
- }
- }
- }
- },
- /**
- * OptinMonster compatibility.
- *
- * Re-initialize after OptinMonster loads to accommodate changes that
- * have occurred to the DOM.
- *
- * @since 1.5.0
- */
- bindOptinMonster: function() {
- // OM v5.
- document.addEventListener( 'om.Campaign.load', function( event ) {
- app.ready();
- app.optinMonsterRecaptchaReset( event.detail.Campaign.data.id );
- } );
- // OM Legacy.
- $( document ).on( 'OptinMonsterOnShow', function( event, data, object ) {
- app.ready();
- app.optinMonsterRecaptchaReset( data.optin );
- } );
- },
- /**
- * Reset/recreate hCaptcha/reCAPTCHA v2 inside OptinMonster.
- *
- * @since 1.5.0
- * @since 1.6.4 Added hCaptcha support.
- *
- * @param {string} optinId OptinMonster ID.
- */
- optinMonsterRecaptchaReset: function( optinId ) {
- var $form = $( '#om-' + optinId ).find( '.wpforms-form' ),
- $captchaContainer = $form.find( '.wpforms-recaptcha-container' ),
- $captcha = $form.find( '.g-recaptcha' );
- if ( $form.length && $captcha.length ) {
- var captchaSiteKey = $captcha.attr( 'data-sitekey' ),
- captchaID = 'recaptcha-' + Date.now(),
- apiVar = $captchaContainer.hasClass( 'wpforms-is-hcaptcha' ) ? hcaptcha : grecaptcha;
- $captcha.remove();
- $captchaContainer.prepend( '<div class="g-recaptcha" id="' + captchaID + '" data-sitekey="' + captchaSiteKey + '"></div>' );
- apiVar.render(
- captchaID,
- {
- sitekey: captchaSiteKey,
- callback: function() {
- wpformsRecaptchaCallback( $( '#' + captchaID ) );
- },
- }
- );
- }
- },
- //--------------------------------------------------------------------//
- // Other functions.
- //--------------------------------------------------------------------//
- /**
- * Payments: Run amount calculation and update the Total field value.
- *
- * @since 1.2.3
- * @since 1.5.1 Added support for payment-checkbox field.
- *
- * @param {object} el jQuery DOM object.
- * @param {boolean} validate Whether to validate or not.
- */
- amountTotal: function( el, validate ) {
- validate = validate || false;
- var $form = $( el ).closest( '.wpforms-form' ),
- currency = app.getCurrency(),
- total = app.amountTotalCalc( $form ),
- totalFormatted,
- totalFormattedSymbol;
- totalFormatted = app.amountFormat( total );
- if ( 'left' === currency.symbol_pos ) {
- totalFormattedSymbol = currency.symbol + ' ' + totalFormatted;
- } else {
- totalFormattedSymbol = totalFormatted + ' ' + currency.symbol;
- }
- $form.find( '.wpforms-payment-total' ).each( function( index, el ) {
- if ( 'hidden' === $( this ).attr( 'type' ) || 'text' === $( this ).attr( 'type' ) ) {
- $( this ).val( totalFormattedSymbol );
- if ( 'text' === $( this ).attr( 'type' ) && validate && $form.data( 'validator' ) ) {
- $( this ).valid();
- }
- } else {
- $( this ).text( totalFormattedSymbol );
- }
- } );
- },
- /**
- * Payments: Calculate a total amount without formatting.
- *
- * @since 1.6.7.1
- *
- * @param {jQuery} $form Form element.
- *
- * @returns {number} Total amount.
- */
- amountTotalCalc: function( $form ) {
- var total = 0;
- $( '.wpforms-payment-price', $form ).each( function() {
- var amount = 0,
- $this = $( this ),
- type = $this.attr( 'type' );
- if ( $this.closest( '.wpforms-field-payment-single' ).hasClass( 'wpforms-conditional-hide' ) ) {
- return;
- }
- if ( type === 'text' || type === 'hidden' ) {
- amount = $this.val();
- } else if ( ( type === 'radio' || type === 'checkbox' ) && $this.is( ':checked' ) ) {
- amount = $this.data( 'amount' );
- } else if ( $this.is( 'select' ) && $this.find( 'option:selected' ).length > 0 ) {
- amount = $this.find( 'option:selected' ).data( 'amount' );
- }
- if ( ! app.empty( amount ) ) {
- amount = app.amountSanitize( amount );
- total = Number( total ) + Number( amount );
- }
- } );
- return total;
- },
- /**
- * Sanitize amount and convert to standard format for calculations.
- *
- * @since 1.2.6
- *
- * @param {string} amount Amount to sanitize.
- *
- * @returns {string} Sanitized amount.
- */
- amountSanitize: function( amount ) {
- var currency = app.getCurrency();
- amount = amount.toString().replace( /[^0-9.,]/g, '' );
- if ( currency.decimal_sep === ',' ) {
- if ( currency.thousands_sep === '.' && amount.indexOf( currency.thousands_sep ) !== -1 ) {
- amount = amount.replace( new RegExp( '\\' + currency.thousands_sep, 'g' ), '' );
- } else if ( currency.thousands_sep === '' && amount.indexOf( '.' ) !== -1 ) {
- amount = amount.replace( /\./g, '' );
- }
- amount = amount.replace( currency.decimal_sep, '.' );
- } else if ( currency.thousands_sep === ',' && ( amount.indexOf( currency.thousands_sep ) !== -1 ) ) {
- amount = amount.replace( new RegExp( '\\' + currency.thousands_sep, 'g' ), '' );
- }
- return app.numberFormat( amount, currency.decimals, '.', '' );
- },
- /**
- * Format amount.
- *
- * @since 1.2.6
- *
- * @param {string|number} amount Amount to format.
- *
- * @returns {string} Formatted amount.
- */
- amountFormat: function( amount ) {
- var currency = app.getCurrency();
- amount = String( amount );
- // Format the amount
- if ( ',' === currency.decimal_sep && ( amount.indexOf( currency.decimal_sep ) !== -1 ) ) {
- var sepFound = amount.indexOf( currency.decimal_sep ),
- whole = amount.substr( 0, sepFound ),
- part = amount.substr( sepFound + 1, amount.length - 1 );
- amount = whole + '.' + part;
- }
- // Strip , from the amount (if set as the thousands separator)
- if ( ',' === currency.thousands_sep && ( amount.indexOf( currency.thousands_sep ) !== -1 ) ) {
- amount = amount.replace( /,/g, '' );
- }
- if ( app.empty( amount ) ) {
- amount = 0;
- }
- return app.numberFormat( amount, currency.decimals, currency.decimal_sep, currency.thousands_sep );
- },
- /**
- * Get site currency settings.
- *
- * @since 1.2.6
- *
- * @returns {object} Currency data object.
- */
- getCurrency: function() {
- var currency = {
- code: 'USD',
- thousands_sep: ',',
- decimals: 2,
- decimal_sep: '.',
- symbol: '$',
- symbol_pos: 'left',
- };
- // Backwards compatibility.
- if ( typeof wpforms_settings.currency_code !== 'undefined' ) {
- currency.code = wpforms_settings.currency_code;
- }
- if ( typeof wpforms_settings.currency_thousands !== 'undefined' ) {
- currency.thousands_sep = wpforms_settings.currency_thousands;
- }
- if ( typeof wpforms_settings.currency_decimals !== 'undefined' ) {
- currency.decimals = wpforms_settings.currency_decimals;
- }
- if ( typeof wpforms_settings.currency_decimal !== 'undefined' ) {
- currency.decimal_sep = wpforms_settings.currency_decimal;
- }
- if ( typeof wpforms_settings.currency_symbol !== 'undefined' ) {
- currency.symbol = wpforms_settings.currency_symbol;
- }
- if ( typeof wpforms_settings.currency_symbol_pos !== 'undefined' ) {
- currency.symbol_pos = wpforms_settings.currency_symbol_pos;
- }
- return currency;
- },
- /**
- * Format number.
- *
- * @see http://locutus.io/php/number_format/
- *
- * @since 1.2.6
- *
- * @param {string} number Number to format.
- * @param {number} decimals How many decimals should be there.
- * @param {string} decimalSep What is the decimal separator.
- * @param {string} thousandsSep What is the thousands separator.
- *
- * @returns {string} Formatted number.
- */
- numberFormat: function( number, decimals, decimalSep, thousandsSep ) {
- number = ( number + '' ).replace( /[^0-9+\-Ee.]/g, '' );
- var n = ! isFinite( +number ) ? 0 : +number;
- var prec = ! isFinite( +decimals ) ? 0 : Math.abs( decimals );
- var sep = ( 'undefined' === typeof thousandsSep ) ? ',' : thousandsSep;
- var dec = ( 'undefined' === typeof decimalSep ) ? '.' : decimalSep;
- var s;
- var toFixedFix = function( n, prec ) {
- var k = Math.pow( 10, prec );
- return '' + ( Math.round( n * k ) / k ).toFixed( prec );
- };
- // @todo: for IE parseFloat(0.55).toFixed(0) = 0;
- s = ( prec ? toFixedFix( n, prec ) : '' + Math.round( n ) ).split( '.' );
- if ( s[0].length > 3 ) {
- s[0] = s[0].replace( /\B(?=(?:\d{3})+(?!\d))/g, sep );
- }
- if ( ( s[1] || '' ).length < prec ) {
- s[1] = s[1] || '';
- s[1] += new Array( prec - s[1].length + 1 ).join( '0' );
- }
- return s.join( dec );
- },
- /**
- * Empty check similar to PHP.
- *
- * @see http://locutus.io/php/empty/
- *
- * @since 1.2.6
- *
- * @param {mixed} mixedVar Variable to check.
- *
- * @returns {boolean} Whether the var is empty or not.
- */
- empty: function( mixedVar ) {
- var undef;
- var key;
- var i;
- var len;
- var emptyValues = [ undef, null, false, 0, '', '0' ];
- for ( i = 0, len = emptyValues.length; i < len; i++ ) {
- if ( mixedVar === emptyValues[i] ) {
- return true;
- }
- }
- if ( 'object' === typeof mixedVar ) {
- for ( key in mixedVar ) {
- if ( mixedVar.hasOwnProperty( key ) ) {
- return false;
- }
- }
- return true;
- }
- return false;
- },
- /**
- * Set cookie container user UUID.
- *
- * @since 1.3.3
- */
- setUserIndentifier: function() {
- if ( ( ( ! window.hasRequiredConsent && typeof wpforms_settings !== 'undefined' && wpforms_settings.uuid_cookie ) || ( window.hasRequiredConsent && window.hasRequiredConsent() ) ) && ! app.getCookie( '_wpfuuid' ) ) {
- // Generate UUID - http://stackoverflow.com/a/873856/1489528
- var s = new Array( 36 ),
- hexDigits = '0123456789abcdef',
- uuid;
- for ( var i = 0; i < 36; i++ ) {
- s[i] = hexDigits.substr( Math.floor( Math.random() * 0x10 ), 1 );
- }
- s[14] = '4';
- s[19] = hexDigits.substr( ( s[19] & 0x3 ) | 0x8, 1 );
- s[8] = s[13] = s[18] = s[23] = '-';
- uuid = s.join( '' );
- app.createCookie( '_wpfuuid', uuid, 3999 );
- }
- },
- /**
- * Create cookie.
- *
- * @since 1.3.3
- *
- * @param {string} name Cookie name.
- * @param {string} value Cookie value.
- * @param {string} days Whether it should expire and when.
- */
- createCookie: function( name, value, days ) {
- var expires = '';
- var secure = '';
- if ( wpforms_settings.is_ssl ) {
- secure = ';secure';
- }
- // If we have a days value, set it in the expiry of the cookie.
- if ( days ) {
- // If -1 is our value, set a session-based cookie instead of a persistent cookie.
- if ( '-1' === days ) {
- expires = '';
- } else {
- var date = new Date();
- date.setTime( date.getTime() + ( days * 24 * 60 * 60 * 1000 ) );
- expires = ';expires=' + date.toGMTString();
- }
- } else {
- expires = ';expires=Thu, 01 Jan 1970 00:00:01 GMT';
- }
- // Write the cookie.
- document.cookie = name + '=' + value + expires + ';path=/;samesite=strict' + secure;
- },
- /**
- * Retrieve cookie.
- *
- * @since 1.3.3
- *
- * @param {string} name Cookie name.
- *
- * @returns {string|null} Cookie value or null when it doesn't exist.
- */
- getCookie: function( name ) {
- var nameEQ = name + '=',
- ca = document.cookie.split( ';' );
- for ( var i = 0; i < ca.length; i++ ) {
- var c = ca[i];
- while ( ' ' === c.charAt( 0 ) ) {
- c = c.substring( 1, c.length );
- }
- if ( 0 === c.indexOf( nameEQ ) ) {
- return c.substring( nameEQ.length, c.length );
- }
- }
- return null;
- },
- /**
- * Delete cookie.
- *
- * @since 1.3.3
- *
- * @param {string} name Cookie name.
- */
- removeCookie: function( name ) {
- app.createCookie( name, '', -1 );
- },
- /**
- * Get user browser preferred language.
- *
- * @since 1.5.2
- *
- * @returns {string} Language code.
- */
- getFirstBrowserLanguage: function() {
- var nav = window.navigator,
- browserLanguagePropertyKeys = [ 'language', 'browserLanguage', 'systemLanguage', 'userLanguage' ],
- i,
- language;
- // Support for HTML 5.1 "navigator.languages".
- if ( Array.isArray( nav.languages ) ) {
- for ( i = 0; i < nav.languages.length; i++ ) {
- language = nav.languages[ i ];
- if ( language && language.length ) {
- return language;
- }
- }
- }
- // Support for other well known properties in browsers.
- for ( i = 0; i < browserLanguagePropertyKeys.length; i++ ) {
- language = nav[ browserLanguagePropertyKeys[ i ] ];
- if ( language && language.length ) {
- return language;
- }
- }
- return '';
- },
- /**
- * Asynchronously fetches country code using current IP
- * and executes a callback provided with a country code parameter.
- *
- * @since 1.5.2
- *
- * @param {Function} callback Executes once the fetch is completed.
- */
- currentIpToCountry: function( callback ) {
- var fallback = function() {
- $.get( 'https://ipapi.co/jsonp', function() {}, 'jsonp' )
- .always( function( resp ) {
- var countryCode = ( resp && resp.country ) ? resp.country : '';
- if ( ! countryCode ) {
- var lang = app.getFirstBrowserLanguage();
- countryCode = lang.indexOf( '-' ) > -1 ? lang.split( '-' ).pop() : '';
- }
- callback( countryCode );
- } );
- };
- $.get( 'https://geo.wpforms.com/v3/geolocate/json' )
- .done( function( resp ) {
- if ( resp && resp.country_iso ) {
- callback( resp.country_iso );
- } else {
- fallback();
- }
- } )
- .fail( function( resp ) {
- fallback();
- } );
- },
- /**
- * Form submit.
- *
- * @since 1.5.3
- *
- * @param {jQuery} $form Form element.
- */
- formSubmit: function( $form ) {
- // Form element was passed from vanilla JavaScript.
- if ( ! ( $form instanceof jQuery ) ) {
- $form = $( $form );
- }
- app.saveTinyMCE();
- $form.trigger( 'wpformsBeforeFormSubmit' );
- if ( $form.hasClass( 'wpforms-ajax-form' ) && typeof FormData !== 'undefined' ) {
- app.formSubmitAjax( $form );
- } else {
- app.formSubmitNormal( $form );
- }
- },
- /**
- * Normal form submit with page reload.
- *
- * @since 1.5.3
- *
- * @param {jQuery} $form Form element.
- */
- formSubmitNormal: function( $form ) {
- if ( ! $form.length ) {
- return;
- }
- var $submit = $form.find( '.wpforms-submit' ),
- recaptchaID = $submit.get( 0 ).recaptchaID;
- if ( ! app.empty( recaptchaID ) || recaptchaID === 0 ) {
- $submit.get( 0 ).recaptchaID = false;
- }
- $form.get( 0 ).submit();
- },
- /**
- * Reset form captcha.
- *
- * @since 1.5.3
- * @since 1.6.4 Added hCaptcha support.
- *
- * @param {jQuery} $form Form element.
- */
- resetFormRecaptcha: function( $form ) {
- if ( ! $form || ! $form.length ) {
- return;
- }
- if ( typeof hcaptcha === 'undefined' && typeof grecaptcha === 'undefined' ) {
- return;
- }
- var $captchaContainer = $form.find( '.wpforms-recaptcha-container' ),
- apiVar = $captchaContainer.hasClass( 'wpforms-is-hcaptcha' ) ? hcaptcha : grecaptcha,
- recaptchaID;
- // Check for invisible recaptcha first.
- recaptchaID = $form.find( '.wpforms-submit' ).get( 0 ).recaptchaID;
- // Check for hcaptcha/recaptcha v2, if invisible recaptcha is not found.
- if ( app.empty( recaptchaID ) && recaptchaID !== 0 ) {
- recaptchaID = $form.find( '.g-recaptcha' ).data( 'recaptcha-id' );
- }
- // Reset captcha.
- if ( ! app.empty( recaptchaID ) || recaptchaID === 0 ) {
- apiVar.reset( recaptchaID );
- }
- },
- /**
- * Console log AJAX error.
- *
- * @since 1.5.3
- *
- * @param {string} error Error text (optional).
- */
- consoleLogAjaxError: function( error ) {
- if ( error ) {
- console.error( 'WPForms AJAX submit error:\n%s', error ); // eslint-disable-line no-console
- } else {
- console.error( 'WPForms AJAX submit error' ); // eslint-disable-line no-console
- }
- },
- /**
- * Display form AJAX errors.
- *
- * @since 1.5.3
- *
- * @param {jQuery} $form Form element.
- * @param {object} errors Errors in format { general: { generalErrors }, field: { fieldErrors } }.
- */
- displayFormAjaxErrors: function( $form, errors ) {
- if ( 'string' === typeof errors ) {
- app.displayFormAjaxGeneralErrors( $form, errors );
- return;
- }
- errors = errors && ( 'errors' in errors ) ? errors.errors : null;
- if ( app.empty( errors ) || ( app.empty( errors.general ) && app.empty( errors.field ) ) ) {
- app.consoleLogAjaxError();
- return;
- }
- if ( ! app.empty( errors.general ) ) {
- app.displayFormAjaxGeneralErrors( $form, errors.general );
- }
- if ( ! app.empty( errors.field ) ) {
- app.displayFormAjaxFieldErrors( $form, errors.field );
- }
- },
- /**
- * Display form AJAX general errors that cannot be displayed using jQuery Validation plugin.
- *
- * @since 1.5.3
- *
- * @param {jQuery} $form Form element.
- * @param {object} errors Errors in format { errorType: errorText }.
- */
- displayFormAjaxGeneralErrors: function( $form, errors ) {
- if ( ! $form || ! $form.length ) {
- return;
- }
- if ( app.empty( errors ) ) {
- return;
- }
- // Safety net for random errors thrown by a third-party code. Should never be used intentionally.
- if ( 'string' === typeof errors ) {
- $form.find( '.wpforms-submit-container' ).before( '<div class="wpforms-error-container">' + errors + '</div>' );
- return;
- }
- $.each( errors, function( type, html ) {
- switch ( type ) {
- case 'header':
- $form.prepend( html );
- break;
- case 'footer':
- $form.find( '.wpforms-submit-container' ).before( html );
- break;
- case 'recaptcha':
- $form.find( '.wpforms-recaptcha-container' ).append( html );
- break;
- }
- } );
- },
- /**
- * Clear forms AJAX general errors that cannot be cleared using jQuery Validation plugin.
- *
- * @since 1.5.3
- *
- * @param {jQuery} $form Form element.
- */
- clearFormAjaxGeneralErrors: function( $form ) {
- $form.find( '.wpforms-error-container' ).remove();
- $form.find( '#wpforms-field_recaptcha-error' ).remove();
- },
- /**
- * Display form AJAX field errors using jQuery Validation plugin.
- *
- * @since 1.5.3
- *
- * @param {jQuery} $form Form element.
- * @param {object} errors Errors in format { fieldName: errorText }.
- */
- displayFormAjaxFieldErrors: function( $form, errors ) {
- if ( ! $form || ! $form.length ) {
- return;
- }
- if ( app.empty( errors ) ) {
- return;
- }
- var validator = $form.data( 'validator' );
- if ( ! validator ) {
- return;
- }
- validator.showErrors( errors );
- validator.focusInvalid();
- },
- /**
- * Submit a form using AJAX.
- *
- * @since 1.5.3
- *
- * @param {jQuery} $form Form element.
- *
- * @returns {JQueryXHR|JQueryDeferred} Promise like object for async callbacks.
- */
- formSubmitAjax: function( $form ) {
- if ( ! $form.length ) {
- return $.Deferred().reject(); // eslint-disable-line new-cap
- }
- var $container = $form.closest( '.wpforms-container' ),
- $spinner = $form.find( '.wpforms-submit-spinner' ),
- $confirmationScroll,
- formData,
- args;
- $container.css( 'opacity', 0.6 );
- $spinner.show();
- app.clearFormAjaxGeneralErrors( $form );
- formData = new FormData( $form.get( 0 ) );
- formData.append( 'action', 'wpforms_submit' );
- formData.append( 'page_url', window.location.href );
- args = {
- type : 'post',
- dataType : 'json',
- url : wpforms_settings.ajaxurl,
- data : formData,
- cache : false,
- contentType: false,
- processData: false,
- };
- args.success = function( json ) {
- if ( ! json ) {
- app.consoleLogAjaxError();
- return;
- }
- if ( json.data && json.data.action_required ) {
- $form.trigger( 'wpformsAjaxSubmitActionRequired', json );
- return;
- }
- if ( ! json.success ) {
- app.resetFormRecaptcha( $form );
- app.displayFormAjaxErrors( $form, json.data );
- $form.trigger( 'wpformsAjaxSubmitFailed', json );
- return;
- }
- $form.trigger( 'wpformsAjaxSubmitSuccess', json );
- if ( ! json.data ) {
- return;
- }
- if ( json.data.redirect_url ) {
- $form.trigger( 'wpformsAjaxSubmitBeforeRedirect', json );
- window.location = json.data.redirect_url;
- return;
- }
- if ( json.data.confirmation ) {
- $container.html( json.data.confirmation );
- $confirmationScroll = $container.find( 'div.wpforms-confirmation-scroll' );
- $container.trigger( 'wpformsAjaxSubmitSuccessConfirmation', json );
- if ( $confirmationScroll.length ) {
- app.animateScrollTop( $confirmationScroll.offset().top - 100 );
- }
- }
- };
- args.error = function( jqHXR, textStatus, error ) {
- app.consoleLogAjaxError( error );
- $form.trigger( 'wpformsAjaxSubmitError', [ jqHXR, textStatus, error ] );
- };
- args.complete = function( jqHXR, textStatus ) {
- // Do not make form active if the action is required.
- if ( jqHXR.responseJSON && jqHXR.responseJSON.data && jqHXR.responseJSON.data.action_required ) {
- return;
- }
- var $submit = $form.find( '.wpforms-submit' ),
- submitText = $submit.data( 'submit-text' );
- if ( submitText ) {
- $submit.text( submitText );
- }
- $submit.prop( 'disabled', false );
- $container.css( 'opacity', '' );
- $spinner.hide();
- $form.trigger( 'wpformsAjaxSubmitCompleted', [ jqHXR, textStatus ] );
- };
- $form.trigger( 'wpformsAjaxBeforeSubmit' );
- return $.ajax( args );
- },
- /**
- * Scroll to position with animation.
- *
- * @since 1.5.3
- *
- * @param {number} position Position (in pixels) to scroll to,
- * @param {number} duration Animation duration.
- * @param {Function} complete Function to execute after animation is complete.
- *
- * @returns {JQueryPromise} Promise object for async callbacks.
- */
- animateScrollTop: function( position, duration, complete ) {
- duration = duration || 1000;
- complete = typeof complete === 'function' ? complete : function() {};
- return $( 'html, body' ).animate( { scrollTop: parseInt( position, 10 ) }, { duration: duration, complete: complete } ).promise();
- },
- /**
- * Save tinyMCE.
- *
- * @since 1.7.0
- */
- saveTinyMCE: function() {
- if ( typeof tinyMCE !== 'undefined' ) {
- tinyMCE.triggerSave();
- }
- },
- /**
- * Check if object is a function.
- *
- * @deprecated 1.6.7
- *
- * @since 1.5.8
- *
- * @param {mixed} object Object to check if it is function.
- *
- * @returns {boolean} True if object is a function.
- */
- isFunction: function( object ) {
- return !! ( object && object.constructor && object.call && object.apply );
- },
- /**
- * Compare times.
- *
- * @since 1.7.1
- *
- * @param {string} time1 Time 1.
- * @param {string} time2 Time 2.
- *
- * @returns {boolean} True if time1 is greater than time2.
- */
- compareTimesGreaterThan: function( time1, time2 ) {
- // Properly format time: add space before AM/PM, make uppercase.
- time1 = time1.replace( /(am|pm)/g, ' $1' ).toUpperCase();
- time2 = time2.replace( /(am|pm)/g, ' $1' ).toUpperCase();
- var time1Date = Date.parse( '01 Jan 2021 ' + time1 ),
- time2Date = Date.parse( '01 Jan 2021 ' + time2 );
- return time1Date >= time2Date;
- },
- };
- return app;
- }( document, window, jQuery ) );
- // Initialize.
- wpforms.init();
|