1jQuery(document).ready(function () { 2 const formData = new FormData(); 3 let form = { 4 // initial all variables and create methods 5 contactForm: document.querySelector('#contact-form'), 6 7 validation: new JustValidate('#contact-form', { 8 errorLabelCssClass: ['form-error-text'], 9 errorFieldCssClass: ['form-error-field'], 10 }), 11 12 frontFormHeader: document.querySelector('.contact-form__header'), 13 frontFormWrap: document.querySelector('.contact-form__wrap'), 14 contactSubmit: document.querySelector('#contact-submit'), 15 16 17 overlaySuccess: document.querySelector('.contact-form-response--success'), 18 overlayError: document.querySelector('.contact-form-response--error'), 19 20 fieldsFormData: [ 21 { 22 'fieldQuery': '.input-name', 23 'fieldName': 'contactName', 24 'rules': { 25 'required': true, 26 'minLength': 2, 27 'maxLength': 30, 28 }, 29 }, 30 { 31 'fieldQuery': '.input-email', 32 'fieldName': 'contactEmail', 33 'rules': { 34 'required': true, 35 'email': true, 36 } 37 }, 38 { 39 'fieldQuery': '.input-comments', 40 'fieldName': 'contactComments', 41 'rules': { 42 'minLength': 3, 43 'required': true 44 } 45 }, 46 { 47 'fieldQuery': '.input-terms', 48 'fieldName': 'contactTerms', 49 'rules': { 50 'required': true 51 } 52 }, 53 ], 54 55 phone: jQuery('#contactPhone'), 56 MAX_PHONE_LENGTH: 14, 57 58 file: document.querySelector('#contactFiles'), 59 fileList: [], 60 fileListSizes: 0, 61 MAX_FILE_COUNT: 6, 62 MAX_FILE_SIZE: 30000000, 63 64 freezeOnSubmit: function () { 65 form.contactSubmit.setAttribute('disabled', true); 66 form.contactSubmit.textContent = 'Sending... Please, wait'; 67 }, 68 69 onFormSentOverlay: function (status) { 70 if(status === "success"){ 71 form.overlaySuccess.style.display = 'flex'; 72 } else { 73 form.overlayError.style.display = 'flex'; 74 } 75 form.contactForm.style.display = 'none'; 76 if (form.frontFormHeader) { 77 form.frontFormHeader.style.display = 'none'; 78 } 79 }, 80 81 resetForm: function () { 82 form.contactForm.reset(); 83 }, 84 85 initialForm: function () { 86 form.contactSubmit.disabled = false; 87 /* 88 just-validate docs 89 https://just-validate.dev/docs/intro 90 */ 91 92 //validate other fields from fieldsFormData 93 form.fieldsFormData.map((item) => { 94 if (document.querySelector(item.fieldQuery)) { 95 let rule = Object.entries(item.rules).map(([key, value]) => { 96 return { 97 "rule": key, 98 "value": value 99 } 100 }) 101 form.validation.addField(item.fieldQuery, rule); 102 } 103 }); 104 //validate file 105 if (form.file) { 106 form.fileInitial(); 107 form.validation.addField('.input-files', [ 108 { 109 rule: 'maxSizes', 110 validator: () => { 111 if (form.fileListSizes > form.MAX_FILE_SIZE) { 112 return false 113 } 114 return true 115 }, 116 errorMessage: `The total size of files should not exceed 30 MB.` 117 }, 118 { 119 rule: 'maxCount', 120 validator: () => { 121 if (form.fileList.length > form.MAX_FILE_COUNT) { 122 return false 123 } 124 return true 125 }, 126 errorMessage: `Maximum number of files is ${form.MAX_FILE_COUNT}.` 127 }, 128 ]); 129 form.file.addEventListener('change', function (e) { 130 const targetFiles = e.target.files; 131 for (let i = 0; i < targetFiles.length; i++) { 132 const file = targetFiles[i]; 133 form.fileList = [...form.fileList, file]; 134 form.renderFileItem(); 135 } 136 }); 137 } 138 //validate phone 139 if (form.phone.length) { 140 form.phoneInit(); 141 form.pressOnlyDigits(); 142 form.validation.addField('.input-phone', [ 143 { 144 rule: 'minLength', 145 value: 8, 146 errorMessage: `Phone number is too short`, 147 }, 148 { 149 rule: 'maxLength', 150 value: 12, 151 errorMessage: 'Phone number is too long', 152 }, 153 ]); 154 } 155 }, 156 157 appendFormData: function () { 158 form.fieldsFormData.map(function (field) { 159 const fieldValue = jQuery(field.fieldQuery).val(); 160 if (fieldValue) { 161 formData.delete(field.fieldName); 162 formData.append(field.fieldName, fieldValue); 163 } 164 }); 165 if (jQuery(form.phone).val() && jQuery(form.phone).val().length >= 8) { 166 let 167 callbackPhone, 168 callbackPhoneCode = jQuery(form.phone).siblings('.iti__flag-container').find('.iti__selected-dial-code').text(); 169 callbackPhone = `${callbackPhoneCode} ${jQuery(form.phone).val()}`; 170 formData.append('contactPhone', callbackPhone); 171 } 172 }, 173 174 fileInitial: function () { 175 let fileItems = document.createElement('div'); 176 fileItems.className = 'contact-file__wrap'; 177 form.file.parentNode.parentNode.append(fileItems); 178 form.fileItemsWrap = document.querySelector(`.${fileItems.className}`); 179 }, 180 181 insertFileItem: function (fileInputWrap, fileName) { 182 const fileItem = document.createElement('div'); 183 fileItem.className = 'file__item'; 184 let btnDelete = document.createElement('span'); 185 btnDelete.className = 'file__delete'; 186 btnDelete.textContent = 'X'; 187 fileItem.innerHTML = `<span class="file__box">${fileName}</span>`;
188 fileItem.append(btnDelete) 189 fileInputWrap.append(fileItem); 190 btnDelete.addEventListener('click', function (e) { 191 form.removeUploadedFile(e.target); 192 }) 193 }, 194 195 getFileName: function (fileItem) { 196 let fileName = fileItem.name; 197 // cut long file name 198 if (fileName.length > form.cutBorder) { 199 fileName = fileName.substring(0, form.cutBorder); 200 fileName = fileName + '...'; 201 } 202 form.insertFileItem(form.fileItemsWrap, fileName); 203 form.fileListSizes += fileItem.size; 204 }, 205 206 renderFileItem: function () { 207 document.querySelectorAll('.file__item').forEach(element => { 208 element.remove(); 209 }); 210 formData.delete('userFiles[]'); 211 form.fileListSizes = 0; 212 for (let i = 0; i < form.fileList.length; i++) { 213 formData.append('userFiles[]', form.fileList[i]); 214 form.getFileName(form.fileList[i]); 215 } 216 }, 217 218 removeUploadedFile: function (currentFileDeleteBtn) { 219 const fileItems = Array.from(document.querySelectorAll('.file__delete')); 220 const fileItemIndex = fileItems.indexOf(currentFileDeleteBtn); 221 delete form.fileList[fileItemIndex]; 222 form.fileList = form.fileList.filter(item => item !== false); 223 form.renderFileItem(); 224 form.validation.revalidateField('.input-files'); 225 }, 226 227 phoneInit: function () { 228 form.phone.intlTelInput({ 229 initialCountry: 'auto', 230 geoIpLookup: function (success) { 231 jQuery.get( 232 'https://ipinfo.io', 233 function () { }, 'jsonp').always(function (resp) { 234 let countryCode = (resp && resp.country) ? resp.country : 'us'; 235 success(countryCode); 236 }); 237 }, 238 separateDialCode: true, 239 //utilsScript: '/wp-content/plugins/form-feedback-smtp/js/utils.js' 240 }); 241 }, 242 243 pressOnlyDigits: function () { 244 form.phone.on('keypress keyup blur', function (event) { 245 jQuery(this).val(jQuery(this).val().replace(/[^\d].+/, '')); 246 if ((event.which < 48 || event.which > 57) || (jQuery(this).val().length > form.MAX_PHONE_LENGTH)) { 247 event.preventDefault(); 248 } 249 }); 250 }, 251 } 252 253 let initialFormPromise = new Promise(function (resolve, reject) { 254 if (form.validation.form) { 255 resolve(); 256 } else { 257 reject(); 258 } 259 }); 260 261 initialFormPromise. 262 then(function () { 263 form.initialForm(); 264 }). 265 catch(function (error) { 266 console.log(error); 267 }); 268 269 form.validation.onSuccess(() => { 270 form.appendFormData(); 271 form.freezeOnSubmit(); 272 fetch('/wp-content/plugins/form-feedback-smtp/send.php', { 273 method: 'POST', 274 body: formData, 275 enctype: 'multipart/form-data' 276 }) 277 // base promise - server response 278 .then((response) => { 279 // check for response type: text (not JSON data) 280 let contentType = response.headers.get('content-type'); 281 if (contentType.includes('text/html')) { 282 // promise return text data 283 response.text() 284 // text-data promise - check for server feedback message 285 .then(function (serverMessage) { 286 console.log(serverMessage) 287 // on success response - look at "/wp-content/plugins/form-feedback/form-feedback.php" 288 if (serverMessage === 'Message has been sent') { 289 form.onFormSentOverlay("success"); 290 // on error response 291 } else { 292 form.onFormSentOverlay("error"); 293 } 294 }); 295 } 296 }) 297 .catch(() => { 298 form.onFormSentOverlay("error"); 299 }) 300 .finally(() => { 301 form.resetForm(); 302 }); 303 }); 304});
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.