1// ÐлобалÑнÑе пеÑеменнÑе Ð´Ð»Ñ ÑÑнкÑий 2var showModal; 3var hideModal; 4 5document.addEventListener("DOMContentLoaded", function () { 6 // ===== 1) ÐолÑÑение CSRF-Ñокена 7 function getCsrfToken(callback) { 8 fetch("/assets/php/csrf_token.php", { 9 method: "GET", 10 headers: { "X-Requested-With": "XMLHttpRequest" }, 11 credentials: "same-origin" 12 }) 13 .then((res) => { 14 if (!res.ok) throw new Error("ÐÑибка пÑи полÑÑении CSRF Ñокена"); 15 return res.text(); 16 }) 17 .then((token) => callback(token)) 18 .catch((err) => { 19 console.error("ÐÑибка CSRF:", err); 20 }); 21 } 22 23 // ===== 2) ÐодалÑное окно Ð´Ð»Ñ ÑезÑлÑÑаÑа 24 const modal = document.getElementById("modal"); 25 const modalMessage = document.getElementById("modal-message"); 26 const modalIcon = document.getElementById("modal-icon"); 27 const modalClose = modal ? modal.querySelector(".modal__close") : null; 28 29 // ÐпÑеделÑем глобалÑнÑÑ ÑÑнкÑÐ¸Ñ hideModal 30 hideModal = function () { 31 const modalElement = document.getElementById("modal"); 32 if (!modalElement) return; 33 modalElement.style.display = "none"; 34 modalElement.setAttribute("aria-hidden", "true"); 35 }; 36 37 // ÐпÑеделÑем глобалÑнÑÑ ÑÑнкÑÐ¸Ñ showModal 38 showModal = function (message, isSuccess = true) { 39 const modalElement = document.getElementById("modal"); 40 const modalMessageElement = document.getElementById("modal-message"); 41 const modalIconElement = document.getElementById("modal-icon"); 42 43 if (!modalElement || !modalMessageElement) { 44 console.error("ÐодалÑное окно не найдено на ÑÑÑаниÑе!"); 45 return; 46 } 47 48 modalMessageElement.textContent = message; 49 50 if (modalIconElement) { 51 const iconUrl = isSuccess 52 ? "/assets/img/icons/success-icon.svg" 53 : "/assets/img/icons/error-icon.svg"; 54 55 modalIconElement.src = iconUrl; 56 modalIconElement.style.display = "block"; 57 modalIconElement.alt = isSuccess ? "УÑÐ¿ÐµÑ " : "ÐÑибка"; 58 } 59 60 modalElement.style.display = "flex"; 61 modalElement.setAttribute("aria-hidden", "false"); 62 63 if (isSuccess) { 64 setTimeout(hideModal, 5000); 65 } 66 }; 67 68 if (modalClose) { 69 modalClose.addEventListener("click", hideModal); 70 } 71 72 window.addEventListener("click", (e) => { 73 if (modal && e.target === modal) { 74 hideModal(); 75 } 76 }); 77 78 // Close on Escape key 79 document.addEventListener("keydown", (e) => { 80 if (e.key === "Escape" && modal && modal.style.display === "flex") { 81 hideModal(); 82 } 83 }); 84 85 // ===== 3) ФÑнкÑÐ¸Ñ Ð´Ð»Ñ Ð¾ÑпÑавки ÑоÑÐ¼Ñ AJAX'ом 86 function handleFormSubmit(form, csrfToken) { 87 form.addEventListener("submit", (event) => { 88 event.preventDefault(); 89 90 // Disable submit button to prevent multiple submissions 91 const submitButton = form.querySelector('button[type="submit"]'); 92 let originalText = ""; 93 if (submitButton) { 94 submitButton.disabled = true; 95 originalText = submitButton.innerHTML; 96 submitButton.innerHTML = "<span>ÐÑпÑавка...</span>"; 97 } 98 99 const formData = new FormData(form); 100 101 // ÐÑли Ð½ÐµÑ csrf_token, допиÑем 102 if (!formData.has("csrf_token")) { 103 formData.append("csrf_token", csrfToken); 104 } 105 106 fetch("/assets/php/send.php", { 107 method: "POST", 108 body: formData, 109 headers: { "X-Requested-With": "XMLHttpRequest" } 110 }) 111 .then((response) => { 112 if (!response.ok) throw new Error("ÐÑибка пÑи оÑпÑавке"); 113 return response.text(); 114 }) 115 .then((data) => { 116 console.log("ÐÑÐ²ÐµÑ Ð¾Ñ ÑеÑвеÑа:", data); 117 if (data.includes("СообÑение оÑпÑавлено ÑÑпеÑно")) { 118 // ÐоказÑваем Ð¼Ð¾Ð´Ð°Ð»ÐºÑ Ñ ÑÑÐ¿ÐµÑ Ð¾Ð¼ 119 showModal( 120 "ÐаÑе ÑообÑение ÑÑпеÑно оÑпÑавлено! ÐÑ ÑвÑжемÑÑ Ñ Ð²Ð°Ð¼Ð¸ в ближайÑее вÑемÑ.", 121 true 122 ); 123 // СбÑÐ¾Ñ ÑоÑÐ¼Ñ 124 form.reset(); 125 126 // ÐÑли еÑÑÑ Ñайл (ФоÑма 2/3), ÑбÑаÑÑваем кнопки 127 const fileInput = form.querySelector('input[type="file"]'); 128 const fileText = form.querySelector(".contact-form-big__file-text"); 129 const fileRemoveButton = form.querySelector(".contact-form-big__file-remove"); 130 if (fileInput && fileText && fileRemoveButton) { 131 fileText.textContent = "ÐÑикÑепиÑÑ Ñайл"; 132 fileRemoveButton.style.display = "none"; 133 } 134 } else { 135 showModal("ÐÑибка пÑи оÑпÑавке: " + data, false); 136 } 137 }) 138 .catch((error) => { 139 console.error("ÐÑибка оÑпÑавки:", error); 140 showModal("ÐÑибка пÑи оÑпÑавке: " + error.message, false); 141 }) 142 .finally(() => { 143 // Re-enable submit button 144 if (submitButton) { 145 submitButton.disabled = false;
146 submitButton.innerHTML = originalText; 147 } 148 }); 149 }); 150 } 151 152 // ===== 4) ÐÐÐЦÐÐÐÐÐÐЦÐЯ ФÐÐ Ð 153 154 // 4.1) ФоÑма 1 (маленÑкаÑ), клаÑÑ .contact-form 155 const contactFormSmall = document.querySelector(".contact-form"); 156 if (contactFormSmall) { 157 const csrfInputSmall = contactFormSmall.querySelector('input[name="csrf_token"]'); 158 if (csrfInputSmall && csrfInputSmall.value.trim() === "") { 159 getCsrfToken((token) => { 160 csrfInputSmall.value = token; 161 handleFormSubmit(contactFormSmall, token); 162 }); 163 } else { 164 const existingToken = csrfInputSmall ? csrfInputSmall.value : ""; 165 handleFormSubmit(contactFormSmall, existingToken); 166 } 167 } 168 169 // 4.2) ФоÑма 2 (болÑÑаÑ), еÑли еÑÑÑ 170 const contactFormBig = document.querySelector(".contact-form-big:not(.contact-form-big--modal)"); 171 if (contactFormBig) { 172 const csrfInputBig = contactFormBig.querySelector('input[name="csrf_token"]'); 173 if (csrfInputBig && csrfInputBig.value.trim() === "") { 174 getCsrfToken((token) => { 175 csrfInputBig.value = token; 176 handleFormSubmit(contactFormBig, token); 177 }); 178 } else { 179 const existingToken = csrfInputBig ? csrfInputBig.value : ""; 180 handleFormSubmit(contactFormBig, existingToken); 181 } 182 } 183 184 // 4.3) ФоÑÐ¼Ñ 3 (болÑÑие, но модалÑнÑе) 185 const modalForms = document.querySelectorAll(".contact-form-big--modal"); 186 if (modalForms.length > 0) { 187 getCsrfToken((token) => { 188 modalForms.forEach((form) => { 189 const csrfInput = form.querySelector('input[name="csrf_token"]'); 190 if (csrfInput && csrfInput.value.trim() === "") { 191 csrfInput.value = token; 192 } 193 handleFormSubmit(form, token); 194 }); 195 }); 196 } 197 198 // ===== 5) ÐÑли нÑжно обÑабаÑÑваÑÑ Ð¿Ð¾Ð»Ðµ "ÐÑикÑепиÑÑ Ñайл" (Ð´Ð»Ñ Ð±Ð¾Ð»ÑÑÐ¸Ñ ÑоÑм) 199 function initFileField(form) { 200 const fileInput = form.querySelector('input[type="file"]'); 201 const fileRemoveButton = form.querySelector(".contact-form-big__file-remove"); 202 const fileText = form.querySelector(".contact-form-big__file-text"); 203 if (fileInput && fileRemoveButton && fileText) { 204 fileRemoveButton.style.display = "none"; 205 fileInput.addEventListener("change", () => { 206 if (fileInput.files.length > 0) { 207 fileText.textContent = fileInput.files[0].name; 208 fileRemoveButton.style.display = "inline-block"; 209 } else { 210 fileText.textContent = "ÐÑикÑепиÑÑ Ñайл"; 211 fileRemoveButton.style.display = "none"; 212 } 213 }); 214 fileRemoveButton.addEventListener("click", () => { 215 fileInput.value = ""; 216 fileText.textContent = "ÐÑикÑепиÑÑ Ñайл"; 217 fileRemoveButton.style.display = "none"; 218 }); 219 } 220 } 221 222 // ÐÑименÑем к обÑÑной болÑÑой ÑоÑме 223 if (contactFormBig) { 224 initFileField(contactFormBig); 225 } 226 // ÐÑименÑем к модалÑнÑм ÑоÑмам 227 modalForms.forEach((form) => { 228 initFileField(form); 229 }); 230});
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.