1jQuery(document).ready(function($){ 2 3 $('.formlayer-form').on('submit', function(e){ 4 e.preventDefault(); 5 6 let $form = $(this); 7 $submit_Btn = $form.find('.formlayer-submit-btn'), 8 $status = $form.find('.formlayer-form-status'), 9 formId = $form.data('form-id'); 10 11 $submit_Btn.prop('disabled', true).addClass('loading'); 12 $status.html('').removeClass('formlayer-success-message formlayer-error-message'); 13 14 var formData = new FormData(this); 15 16 // Client-side Validation 17 var errors = []; 18 19 // Email Confirmation Match 20 $form.find('.formlayer-email-confirm').each(function(){ 21 var matchName = $(this).data('match'); 22 var originalVal = $form.find('input[name="' + matchName + '"]').val(); 23 if($(this).val() !== originalVal){ 24 errors.push('Emails do not match.'); 25 } 26 }); 27 28 // Digit Limit Validation 29 $form.find('input[type="number"][maxlength]').each(function(){ 30 var limit = parseInt($(this).attr('maxlength')); 31 if($(this).val().length > limit){ 32 errors.push('Value exceeds maximum digit limit of ' + limit); 33 } 34 }); 35 36 // URL Validation 37 $form.find('input[data-validate-url="1"]').each(function(){ 38 var val = $(this).val(); 39 if(val && !val.match(/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/)){ 40 errors.push('Please enter a valid URL.'); 41 } 42 }); 43 44 // URL HTTPS Only Validation 45 $form.find('input[data-https-only="1"]').each(function(){ 46 var val = $(this).val(); 47 if(val && !val.startsWith('https://')){ 48 errors.push('Only HTTPS URLs are allowed.'); 49 } 50 }); 51 52 if(errors.length > 0){ 53 $status.addClass('formlayer-error-message').html(errors.join('<br>')); 54 $submit_Btn.prop('disabled', false).removeClass('loading'); 55 return; 56 } 57 58 formData.append('action', 'formlayer_submit_form'); 59 formData.append('nonce', formlayer_data.nonce); 60 formData.append('form_id', formId); 61 62 $.ajax({ 63 url: formlayer_data.ajax_url, 64 method: 'POST', 65 data: formData, 66 processData: false, 67 contentType: false, 68 success: function(response){ 69 $submit_Btn.prop('disabled', false).removeClass('loading'); 70 71 if(response.success){ 72 var confirmation = response.data.settings || { type: 'message', message: 'Thank you! Your form has been submitted successfully.', hide_form: true }; 73 74 if(confirmation.type === 'redirect' && confirmation.redirect_url){ 75 $status.addClass('formlayer-success-message').html('Redirecting...'); 76 window.location.href = confirmation.redirect_url; 77 }else{ 78 if(confirmation.hide_form !== false){ 79 $form.find('.formlayer-form-fields-wrapper').hide(); 80 } 81 $form[0].reset(); 82 $status.addClass('formlayer-success-message').html(confirmation.message || 'Thank you! Your form has been submitted successfully.'); 83 } 84 }else{ 85 $status.addClass('formlayer-error-message').html(response.data.message || 'An error occurred.'); 86 } 87 }, 88 error: function(jqXHR, textStatus, errorThrown){ 89 $submit_Btn.prop('disabled', false).removeClass('loading'); 90 console.error('Submission error:', textStatus, errorThrown, jqXHR.responseText); 91 92 // User friendly message instead of technical parsererror 93 var msg = 'An unexpected error occurred. Please try again.'; 94 if(textStatus === 'timeout') msg = 'Request timed out. Please check your connection.'; 95 96 $status.addClass('formlayer-error-message').html(msg); 97 } 98 }); 99 }); 100 // Rating Field Interaction 101 $('.formlayer-rating .dashicons').on('click', function(){ 102 var value = $(this).data('value'); 103 var $container = $(this).closest('.formlayer-rating'); 104 $container.find('input').val(value); 105 $container.find('.dashicons').removeClass('active'); 106 $(this).addClass('active').prevAll().addClass('active'); 107 }); 108 109 $('.formlayer-rating .dashicons').on('mouseenter', function(){ 110 $(this).addClass('hover').prevAll().addClass('hover'); 111 $(this).nextAll().removeClass('hover'); 112 }).on('mouseleave', '.formlayer-rating .dashicons', function(){ 113 $('.formlayer-rating .dashicons').removeClass('hover'); 114 }); 115 116 // File & Image Upload Preview 117 $('.formlayer-file-real').on('change', function(e){ 118 let input = this, 119 $wrap = $(input).closest('.formlayer-field-wrap'), 120 $chosenName = $wrap.find('.formlayer-file-chosen-name'); 121 122 // Remove any existing preview container 123 $wrap.find('.formlayer-file-preview-container').remove(); 124 125 if (input.files && input.files[0]) { 126 let file = input.files[0]; 127 $chosenName.text(file.name); 128 129 // Create preview container 130 let $previewContainer = $(` 131 <div class="formlayer-file-preview-container" style="margin-top:10px; display:flex; align-items:center; gap:12px; padding:10px; border:1px dashed #ccc; border-radius:6px; background:#f9f9f9; max-width: 100%;"> 132 <img class="formlayer-file-preview-img" src="" style="width:60px; height:60px; border-radius:4px; display:none; object-fit:cover; border:1px solid #ddd; background:#fff;"> 133 <span class="formlayer-file-preview-icon dashicons dashicons-document" style="font-size:36px; width:36px; height:36px; display:none; color:#5525d6; line-height:36px;"></span> 134 <div style="display:flex; flex-direction:column; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-align:left; margin-right: auto;"> 135 <span class="formlayer-file-preview-name" style="font-size:13px; font-weight:600; color:#333; overflow:hidden; text-overflow:ellipsis; max-width: 200px;"></span> 136 <span class="formlayer-file-preview-size" style="font-size:11px;
136 color:#777; margin-top: 2px;"></span> 137 </div> 138 <span class="formlayer-file-preview-remove dashicons dashicons-no-alt" style="cursor:pointer; color:#999; font-size:20px; width:20px; height:20px; line-height:20px; text-align:center; transition:color 0.2s;" onmouseover="this.style.color='#d9534f'" onmouseout="this.style.color='#999'"></span> 139 </div> 140 `); 141 142 $previewContainer.find('.formlayer-file-preview-name').text(file.name); 143 144 // Format size 145 let sizeStr = (file.size / 1024).toFixed(1) + ' KB'; 146 if (file.size > 1024 * 1024) { 147 sizeStr = (file.size / (1024 * 1024)).toFixed(1) + ' MB'; 148 } 149 $previewContainer.find('.formlayer-file-preview-size').text(sizeStr); 150 151 // Show preview image if it's an image 152 if (file.type.match('image.*')) { 153 let reader = new FileReader(); 154 reader.onload = function(e) { 155 $previewContainer.find('.formlayer-file-preview-img').attr('src', e.target.result).show(); 156 } 157 reader.readAsDataURL(file); 158 } else { 159 $previewContainer.find('.formlayer-file-preview-icon').show(); 160 } 161 162 // Add click event for remove cross button 163 $previewContainer.find('.formlayer-file-preview-remove').on('click', function(){ 164 $(input).val(''); 165 $chosenName.text('No file chosen'); 166 $previewContainer.remove(); 167 }); 168 169 $wrap.append($previewContainer); 170 } else { 171 $chosenName.text('No file chosen'); 172 } 173 }); 174});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.