1import { serverReq, block, unblock, cleanFields, openModalSuccess, displayErrors, cleanErrors } from "./helpers.js"; 2import { formValidate } from '../popup.js'; 3 4const antispamFieldNames = ['rt_hp_bot', 'website', 'company', 'url']; 5const MIN_SUBMIT_DELAY_SEC = 2; 6 7function clearFormMessage(form) { 8 const box = form.querySelector('[data-form-status]'); 9 if (!box) { 10 return; 11 } 12 box.textContent = ''; 13 box.hidden = true; 14 box.style.display = 'none'; 15} 16 17function showFormMessage(form, message) { 18 if (!message) { 19 clearFormMessage(form); 20 return; 21 } 22 23 let box = form.querySelector('[data-form-status]'); 24 if (!box) { 25 box = document.createElement('div'); 26 box.dataset.formStatus = '1'; 27 box.className = 'popup__form-alert'; 28 box.setAttribute('role', 'alert'); 29 box.style.cssText = 'margin:12px 0 0;padding:10px 12px;font-size:14px;line-height:1.4;color:#c62828;background:#ffebee;border-radius:8px;'; 30 const submitBtn = form.querySelector('button[type="submit"]'); 31 if (submitBtn) { 32 submitBtn.parentNode.insertBefore(box, submitBtn); 33 } else { 34 form.appendChild(box); 35 } 36 } 37 38 box.textContent = message; 39 box.hidden = false; 40 box.style.display = 'block'; 41 box.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); 42} 43 44function getResponseErrorMessage(res) { 45 if (!res || typeof res !== 'object') { 46 return 'Ðе ÑдалоÑÑ Ð¾ÑпÑавиÑÑ ÑоÑмÑ. ÐопÑобÑйÑе еÑÑ Ñаз.'; 47 } 48 if (res.status) { 49 return String(res.status); 50 } 51 if (res.message) { 52 return String(res.message); 53 } 54 if (res.result === 'error') { 55 return 'Ðе ÑдалоÑÑ Ð¾ÑпÑавиÑÑ ÑоÑмÑ. ÐопÑобÑйÑе еÑÑ Ñаз.'; 56 } 57 return ''; 58} 59 60function setHiddenField(form, name, value) { 61 let input = form.querySelector(`input[name="${name}"]`); 62 if (!input) { 63 input = document.createElement('input'); 64 input.type = 'hidden'; 65 input.name = name; 66 form.appendChild(input); 67 } 68 input.value = value; 69} 70 71function ensureHoneypotFields(form) { 72 if (!form.querySelector('input[name="rt_hp_bot"]')) { 73 const wrap = document.createElement('div'); 74 wrap.className = 'hidden'; 75 wrap.setAttribute('aria-hidden', 'true'); 76 wrap.style.cssText = 'position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden;opacity:0;pointer-events:none;'; 77 wrap.innerHTML = antispamFieldNames.map((name) => ( 78 `<input type="text" name="${name}" value="" tabindex="-1" autocomplete="off">` 79 )).join(''); 80 form.prepend(wrap); 81 } 82} 83 84function markFormReady(form) { 85 ensureHoneypotFields(form); 86 if (!form.querySelector('input[name="rt_form_ts"]')?.value) { 87 setHiddenField(form, 'rt_form_ts', String(Math.floor(Date.now() / 1000))); 88 } 89} 90 91function ensureFormTiming(form) { 92 if (form.dataset.rtTimingReady === '1') { 93 return; 94 } 95 form.dataset.rtTimingReady = '1'; 96 const markTs = () => markFormReady(form); 97 form.addEventListener('focusin', markTs, { once: true }); 98 form.addEventListener('input', markTs, { once: true }); 99} 100 101function initPopupFormReady() { 102 document.addEventListener('click', (e) => { 103 const opener = e.target.closest('[data-fls-popup-open], [data-fls-popup-link]'); 104 if (!opener) { 105 return; 106 } 107 const popupId = opener.getAttribute('data-fls-popup-open') || opener.getAttribute('data-fls-popup-link'); 108 if (!popupId) { 109 return; 110 } 111 setTimeout(() => { 112 const popup = document.querySelector(`[data-fls-popup="${popupId}"]`); 113 if (!popup) { 114 return; 115 } 116 popup.querySelectorAll('form[data-submit="feedback"], form[data-submit="feedback_calc"]').forEach((form) => { 117 ensureFormTiming(form); 118 markFormReady(form); 119 }); 120 }, 100); 121 }); 122} 123 124async function waitForSubmitDelay(form) { 125 const ts = parseInt(form.querySelector('input[name="rt_form_ts"]')?.value || '0', 10); 126 if (!ts) { 127 return false; 128 } 129 const elapsed = Math.floor(Date.now() / 1000) - ts; 130 const need = MIN_SUBMIT_DELAY_SEC - elapsed; 131 if (need > 0) { 132 await new Promise((resolve) => setTimeout(resolve, need * 1000)); 133 } 134 return true; 135} 136 137function honeypotTriggered(formData) { 138 return !!(formData.get('rt_hp_bot') || formData.get('website') || formData.get('company') || formData.get('url')); 139} 140 141initPopupFormReady(); 142 143export const feedback = async (form) => { 144 if (form.dataset.rtSubmitting === '1') { 145 return; 146 } 147 form.dataset.rtSubmitting = '1'; 148 149 try { 150 ensureFormTiming(form); 151 markFormReady(form); 152 clearFormMessage(form); 153 cleanErrors(form); 154 155 if (formValidate.getErrors(form) > 0) { 156 showFormMessage(form, 'ÐÑовеÑÑÑе обÑзаÑелÑнÑе Ð¿Ð¾Ð»Ñ ÑоÑмÑ.'); 157 return; 158 } 159 160 const body = new FormData(form); 161 if (honeypotTriggered(body)) { 162 showFormMessage(form, 'Ðе ÑдалоÑÑ Ð¾ÑпÑавиÑÑ ÑоÑмÑ. ÐбновиÑе ÑÑÑаниÑÑ Ð¸ попÑобÑйÑе Ñнова.'); 163 return; 164 } 165 166 if (!form.querySelector('input[name="rt_form_ts"]')?.value) { 167 showFormMessage(form, 'ÐаполниÑе Ð¿Ð¾Ð»Ñ ÑоÑÐ¼Ñ Ð¸ попÑобÑйÑе Ñнова.'); 168 return; 169 } 170 171 await waitForSubmitDelay(form); 172 173 setHiddenField(form, 'rt_js_ok', '1'); 174 body.set('rt_js_ok', '1'); 175 body.set('rt_form_ts', form.querySelector('input[name="rt_form_ts"]').value); 176 177 const targetYandex = body.get('ya_target'); 178 const blockContainer = form.closest('._to_block'); 179 if (blockContainer) { 180 block(blockContainer); 181 } 182 183 const res = await serverReq(body, form.getAttribute('action')); 184 185 if (res.errors && Object.keys(res.errors).length > 0) { 186 displayErrors(form, res.errors); 187 const firstError = Object.values(res.errors).find(Boolean); 188 showFormMessage(form, firstError || 'ÐÑовеÑÑÑе Ð¿Ð¾Ð»Ñ ÑоÑмÑ.'); 189 return; 190 } 191 192 if (res.result === 'success' && res.popup_title) { 193 clearFormMessage(form); 194 openModalSuccess('popup-success', res.popup_title, res.popup_message); 195 cleanFields(form, ['inp-policy', 'form_type', 'url_refer', 'ya_target']); 196 if (targetYandex && typeof ym === 'function') { 197 ym(54157144, 'reachGoal', targetYandex); 198 } 199 return; 200 } 201 202 const errorMessage = getResponseErrorMessage(res); 203 if (errorMessage) { 204 showFormMessage(form, errorMessage); 205 } 206 } catch (e) {
207 showFormMessage(form, 'ÐÑибка оÑпÑавки. ÐопÑобÑйÑе еÑÑ Ñаз.'); 208 console.error(e); 209 } finally { 210 form.dataset.rtSubmitting = '0'; 211 const blockContainer = form.closest('._to_block'); 212 if (blockContainer) { 213 unblock(blockContainer); 214 } 215 } 216};
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.