1/** 2 * ÐлаÑка-пÑедÑпÑеждение о заÑÑбежнÑÑ Ð¿Ð¾ÑÑовÑÑ ÑеÑвиÑÐ°Ñ Ð¿Ð¾Ð´ полем email (задаÑа #10501). 3 * 4 * ÐиÑего не блокиÑÑеÑ: не ÑÑÐ¾Ð³Ð°ÐµÑ submit, не ÑÑÐ°Ð²Ð¸Ñ is-invalid, не ÑÑаÑÑвÑÐµÑ Ð² 5 * валидаÑии из common/js/forms.js. ТолÑко показÑÐ²Ð°ÐµÑ Ð¸ пÑÑÑÐµÑ Ð¿Ð¾Ð´ÑказкÑ. 6 * 7 * ÐополнÑÑÑ Ð½Ñжно ТÐÐЬÐРдва ÑпиÑка ниже â FOREIGN_EMAIL_DOMAINS (ÑоÑное Ñовпадение) 8 * и FOREIGN_EMAIL_DOMAIN_FAMILIES (ÑеÑÐ²Ð¸Ñ Ð²Ð¼ÐµÑÑе Ñо вÑеми ÑегионалÑнÑми зонами). 9 * ÐÐ¾Ð³Ð¸ÐºÑ Ð¿Ñи ÑÑом пÑавиÑÑ Ð½Ðµ надо. 10 * 11 * РабоÑÐ°ÐµÑ Ð¿Ð¾ ÑÑÑÐ½Ð¾Ð¼Ñ ÑпиÑкÑ, а не по «вÑÑ, ÑÑо не .ru», ÑÑÐ¾Ð±Ñ Ð½Ðµ ÑÑгаÑÑÑÑ Ð½Ð° 12 * коÑпоÑаÑивнÑе Ð´Ð¾Ð¼ÐµÐ½Ñ ÐºÐ»Ð¸ÐµÐ½Ñов. ÐбÑабоÑÑики делегиÑÐ¾Ð²Ð°Ð½Ñ Ð½Ð° document, поÑÑÐ¾Ð¼Ñ 13 * полÑ, коÑоÑÑе поÑвÑÑÑÑ Ð² вÑÑÑÑке позже (попапÑ, новÑе ÑоÑмÑ), Ð¿Ð¾Ð´Ñ Ð²Ð°ÑÑваÑÑÑÑ Ñами. 14 */ 15(function () { 16 'use strict'; 17 18 // ТоÑное Ñовпадение домена поÑле @ (ÑегиÑÑÑ Ð½Ðµ важен). 19 var FOREIGN_EMAIL_DOMAINS = [ 20 'gmail.com', 'googlemail.com', 21 'outlook.com', 'hotmail.com', 'live.com', 'msn.com', 22 'yahoo.com', 'ymail.com', 'rocketmail.com', 23 'aol.com', 24 'icloud.com', 'me.com', 'mac.com', 25 'proton.me', 'protonmail.com', 'protonmail.ch', 'pm.me', 26 'gmx.com', 'gmx.net', 'gmx.de', 27 'zoho.com', 'zohomail.com', 28 'tutanota.com', 'tutanota.de', 'tuta.com', 'tuta.io', 29 'fastmail.com', 'fastmail.fm', 30 'mail.com' 31 ]; 32 33 // СеÑвиÑÑ, Ñ ÐºÐ¾ÑоÑÑÑ Ð¼Ð½Ð¾Ð³Ð¾ ÑегионалÑнÑÑ Ð·Ð¾Ð½: yahoo.co.uk, yahoo.fr, hotmail.de, 34 // outlook.com.br и Ñ.п. Совпадением ÑÑиÑаеÑÑÑ Â«<имÑ>.<зона>», где зона â ÑÑо 35 // 2-4 бÑÐºÐ²Ñ Ð¿Ð»ÑÑ Ð½ÐµÐ¾Ð±ÑзаÑелÑнÑй вÑоÑой ÑÑÐ¾Ð²ÐµÐ½Ñ (co.uk, com.br). ÐоÑпоÑаÑивнÑй 36 // домен вида live.company.ru под ÑÑо не попадаеÑ. 37 var FOREIGN_EMAIL_DOMAIN_FAMILIES = [ 38 'yahoo', 'hotmail', 'outlook', 'live', 'msn', 39 'gmx', 'aol', 'googlemail', 'icloud', 'proton', 'protonmail', 40 'tutanota', 'fastmail', 'zoho' 41 ]; 42 43 var NOTICE_TEXT = 'ÐиÑÑма на Gmail, Outlook, Yahoo и дÑÑгие заÑÑбежнÑе ÑеÑвиÑÑ ÑаÑÑо ' + 44 'пÑÐ¸Ñ Ð¾Ð´ÑÑ Ñ Ð·Ð°Ð´ÐµÑжкой или попадаÑÑ Ð² Ñпам. ÐÑли еÑÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ â ÑкажиÑе поÑÑÑ ' + 45 'на ЯндекÑе или Mail.ru, Ñак Ð²Ñ ÑоÑно полÑÑиÑе доÑÑÑÐ¿Ñ Ð¸ Ñек. ÐÑпÑавиÑÑ Ð·Ð°ÑÐ²ÐºÑ ' + 46 'Ñ ÑекÑÑим адÑеÑом Ñоже можно.'; 47 48 var NOTICE_CLASS = 'foreign-email-notice'; 49 var TYPING_DELAY_MS = 500; 50 51 if (window.foreignEmailNoticeInitialized) { 52 return; 53 } 54 window.foreignEmailNoticeInitialized = true; 55 56 var exactDomains = {}; 57 for (var i = 0; i < FOREIGN_EMAIL_DOMAINS.length; i++) { 58 exactDomains[FOREIGN_EMAIL_DOMAINS[i].toLowerCase()] = true; 59 } 60 61 var familyPattern = new RegExp( 62 '^(?:' + FOREIGN_EMAIL_DOMAIN_FAMILIES.join('|') + ')\\.[a-z]{2,4}(?:\\.[a-z]{2,3})?$' 63 ); 64 65 var noticeSeq = 0; 66 67 function injectStyles() { 68 var style = document.createElement('style'); 69 style.setAttribute('data-source', 'email-domain-notice'); 70 style.appendChild(document.createTextNode( 71 '.' + NOTICE_CLASS + '{' + 72 'display:flex;align-items:flex-start;box-sizing:border-box;' + 73 'width:100%;max-width:100%;margin:6px 0 0;padding:8px 10px;' + 74 'border:1px solid #ffe08a;border-radius:6px;background:#fff8e1;' + 75 'color:#5c4400;font-size:13px;line-height:1.35;text-align:left;' + 76 'font-weight:400;white-space:normal;' + 77 '}' + 78 '.' + NOTICE_CLASS + '__icon{flex:0 0 auto;margin-right:8px;font-weight:700;}' + 79 '.' + NOTICE_CLASS + '__text{flex:1 1 auto;min-width:0;word-wrap:break-word;overflow-wrap:break-word;}' + 80 '@media (max-width:576px){.' + NOTICE_CLASS + '{font-size:12px;padding:7px 9px;}}' 81 )); 82 (document.head || document.documentElement).appendChild(style); 83 } 84 85 function isEmailField(el) { 86 if (!el || el.tagName !== 'INPUT') { 87 return false;
88 } 89 var type = (el.getAttribute('type') || 'text').toLowerCase(); 90 if (type === 'email') { 91 return true; 92 } 93 if (type !== 'text') { 94 return false; 95 } 96 if ((' ' + (el.className || '') + ' ').indexOf(' form-email ') !== -1) { 97 return true; 98 } 99 var hint = ((el.getAttribute('name') || '') + ' ' + (el.id || '')).toLowerCase(); 100 return hint.indexOf('email') !== -1 || hint.indexOf('e-mail') !== -1; 101 } 102 103 function domainOf(value) { 104 var raw = String(value == null ? '' : value).trim().toLowerCase(); 105 var at = raw.lastIndexOf('@'); 106 if (at === -1) { 107 return ''; 108 } 109 var domain = raw.slice(at + 1).replace(/[.\s]+$/, ''); 110 return /^[a-z0-9-]+(?:\.[a-z0-9-]+)+$/.test(domain) ? domain : ''; 111 } 112 113 function isForeignDomain(domain) { 114 if (!domain) { 115 return false; 116 } 117 return exactDomains[domain] === true || familyPattern.test(domain); 118 } 119 120 function buildNotice() { 121 var box = document.createElement('div'); 122 box.className = NOTICE_CLASS; 123 box.setAttribute('role', 'status'); 124 box.id = NOTICE_CLASS + '-' + (++noticeSeq); 125 126 var icon = document.createElement('span'); 127 icon.className = NOTICE_CLASS + '__icon'; 128 icon.setAttribute('aria-hidden', 'true'); 129 icon.appendChild(document.createTextNode('!')); 130 131 var text = document.createElement('span'); 132 text.className = NOTICE_CLASS + '__text'; 133 text.appendChild(document.createTextNode(NOTICE_TEXT)); 134 135 box.appendChild(icon); 136 box.appendChild(text); 137 return box; 138 } 139 140 // Ðоле Ð¼Ð¾Ð¶ÐµÑ ÑÑоÑÑÑ Ð² Ñзкой bootstrap-колонке (ÑелеÑон | e-mail в одном .row, 141 // Ñм. online2/parts/index/form.html). Рколонке ÑиÑиной 170px плаÑка вÑÑÑгиваеÑÑÑ 142 // на 280px в вÑÑоÑÑ Ð¸ ÑаÑпиÑÐ°ÐµÑ ÑоÑмÑ, поÑÑÐ¾Ð¼Ñ Ð² Ñаком ÑлÑÑае ÑÑавим ÐµÑ Ð¿Ð¾Ð´ веÑÑ 143 // ÑÑд â она вÑÑ Ñавно оказÑваеÑÑÑ Ð¿ÑÑмо под полем, но на вÑÑ ÑиÑÐ¸Ð½Ñ ÑоÑмÑ. 144 // Ð Ñд Ñ ÐºÐ½Ð¾Ð¿ÐºÐ¾Ð¹ оÑпÑавки не ÑÑогаем, ÑÑÐ¾Ð±Ñ Ð¿Ð»Ð°Ñка не ÑÐµÑ Ð°Ð»Ð° под кнопкÑ. 145 function placeAfterRow(input) { 146 var node = input.parentNode; 147 while (node && node.nodeType === 1 && node !== document.body) { 148 if (node.className && /(^|\s)col(-[a-z0-9]+)*(\s|$)/.test(node.className)) { 149 var row = node.parentNode; 150 if (row && row.className && /(^|\s)row(\s|$)/.test(row.className) && 151 row.parentNode && !row.querySelector('button, input[type="submit"]')) { 152 return row; 153 } 154 return null; 155 } 156 node = node.parentNode; 157 } 158 return null; 159 } 160 161 function showNotice(input) { 162 var existing = input.foreignEmailNotice; 163 if (existing && existing.parentNode) { 164 return; 165 } 166 if (!input.parentNode) { 167 return; 168 } 169 var notice = buildNotice(); 170 var row = placeAfterRow(input); 171 if (row) { 172 row.parentNode.insertBefore(notice, row.nextSibling); 173 } else { 174 input.parentNode.insertBefore(notice, input.nextSibling); 175 } 176 input.foreignEmailNotice = notice; 177 if (!input.getAttribute('aria-describedby')) { 178 input.setAttribute('aria-describedby', notice.id); 179 } 180 } 181 182 function hideNotice(input) { 183 var notice = input.foreignEmailNotice; 184 if (notice && notice.parentNode) { 185 notice.parentNode.removeChild(notice); 186 } 187 input.foreignEmailNotice = null; 188 if (input.getAttribute('aria-describedby') && 189 input.getAttribute('aria-describedby').indexOf(NOTICE_CLASS + '-') === 0) { 190 input.removeAttribute('aria-describedby'); 191 } 192 } 193 194 function update(input) { 195 if (isForeignDomain(domainOf(input.value))) { 196 showNotice(input); 197 } else { 198 hideNotice(input); 199 } 200 } 201 202 function updateDelayed(input) { 203 if (input.foreignEmailNoticeTimer) { 204 clearTimeout(input.foreignEmailNoticeTimer); 205 } 206 input.foreignEmailNoticeTimer = setTimeout(function () { 207 input.foreignEmailNoticeTimer = null; 208 update(input); 209 }, TYPING_DELAY_MS); 210 } 211 212 function onImmediate(e) { 213 if (isEmailField(e.target)) { 214 if (e.target.foreignEmailNoticeTimer) { 215 clearTimeout(e.target.foreignEmailNoticeTimer); 216 e.target.foreignEmailNoticeTimer = null; 217 } 218 update(e.target); 219 } 220 } 221 222 function onTyping(e) { 223 if (isEmailField(e.target)) { 224 updateDelayed(e.target); 225 } 226 } 227 228 injectStyles(); 229 230 // Capture-Ñаза: ÑÑжие обÑабоÑÑики ÑоÑм иногда гаÑÑÑ Ð²ÑплÑÑие. 231 document.addEventListener('focusout', onImmediate, true); 232 document.addEventListener('change', onImmediate, true); 233 document.addEventListener('input', onTyping, true); 234})();
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.