Refactor JS code: organize DOM & Ajax operations better

parent dd259f82
(function() { (function() {
var noticeTimer, noticeShow = false; // Возможные состояния:
var STATUS_ERROR = 1, // ошибка при запросе/разборе ответа
STATUS_INVALID = 2, // email некорректный
STATUS_LOADING = 3, // загрузка...
STATUS_NONE = 4, // проверка не выполнялась (поле не изменялось, например)
STATUS_SUCCESS = 5; // email корректный
// Возможные ошибки в адресе, значения констант - коды, присылаемые сервером
var ERROR_DNS_RECORDS_NOT_FOUND = 'dns_records_not_found', // нет такого домена
ERROR_DOMAIN_TYPO = 'typed_domain', // очепятка в домене
ERROR_WRONG_FORMAT = 'wrong_email_format', // некорректный формат
ERROR_EMPTY = 'empty', // пустой email
ERROR_UNKNOWN = 'unknown'; // неизвестная ошибка
// Виды сообщения сверху (notice)
var NOTICE_GREEN = 'green',
NOTICE_RED = 'red',
NOTICE_YELLOW = 'yellow';
// Варианты стилей для самого поля
var FIELD_LOADING = 'bg-loading',
FIELD_SUCCESS = 'bg-true',
FIELD_INVALID = 'bg-false';
var EMAIL_REGEX = /^([^@\s]+)@(([a-zA-Z0-9\_\-]+\.)+([a-zA-Z]{2}|aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|post|pro|tel|travel|xxx))$/;
// TODO: избавиться от глобального состояния, лучше для каждой
// формы иметь свой набор таких полей
var noticeTimer, emailInput, noticeShow = false, status = STATUS_NONE;
var lastNoticeType, lastNoticeMessage;
// Изменять ли стили самого поля
var modifyField;
function getEMail() // Проверяем сначала локально, потом на сервере, выставляем статус проверки
{ // Опционально - можно передать callback, принимающий результат (true/false)
var emailInput = $('.svcCheckEmail'); function checkEmailFull (email, callback) {
var _callback = function (result) {
if (callback) {
callback(result);
}
};
if (!email.length) {
setStatus(STATUS_NONE);
_callback(false);
return;
}
// Проверяем без отправки на сервер
if (!checkEmailLocal(email)) {
setStatus(STATUS_ERROR, getErrorMessage(ERROR_WRONG_FORMAT));
_callback(false);
return;
}
setStatus(STATUS_LOADING, 'Идёт проверка адреса e-mail, это может занять несколько секунд.');
checkEmailOnServer(email, function (error, result) {
if (error) {
console.error(error);
setStatus(STATUS_ERROR, 'Ошибка связи с сервером, проверка адреса не удалась.');
} else if (result.success) {
setStatus(STATUS_SUCCESS, 'Email адрес указан верно.');
setHash(result.hash);
_callback(true);
return;
} else {
setStatus(STATUS_INVALID, getErrorMessage(result.message));
}
_callback(false);
});
}
function checkEmailLocal (email) {
return email.length > 5 && EMAIL_REGEX.test(email);
}
// callback - функция с аргументами (error, result), где result - объект с полями
// success (булево) и message (строка, опционально)
// Если происходит ошибка запроса, то error будет задано, а result - нет.
// В случае успешного запроса - наоборот (см. "node-style callback")
function checkEmailOnServer (email, callback) {
// Проверяем на сервере
$.ajax({
url: '//eterfund.ru/api/email/svcCheckEmail.php',
type: 'GET',
data: {
email: email
},
error: function() {
callback(new Error('Ошибка связи с сервером'), null);
},
success: function(responseRawBody) {
try {
var responseJson = JSON.parse(responseRawBody);
if (responseJson.status === false) {
callback(null, {
message: responseJson.error,
success: false
});
} else {
callback(null, {
hash: responseJson.hash,
success: true
});
}
} catch (error) {
callback(error, null);
}
}
});
}
function closeNotice () {
if (noticeShow === true) {
clearTimeout(noticeTimer);
emailNotice.animate({ marginTop: '-=51px' }, 300);
noticeShow = false;
}
}
function getEMail() {
var email = emailInput.val(); var email = emailInput.val();
try { try {
email = email.trim(); email = email.trim();
} catch(e) { } catch (error) {
// // Trim недоступен в текущем браузере. Вернём как есть.
// TODO: исправить?
} }
return email; return email;
} }
function getErrorMessage (error) {
function closeNotice() { var defaultMessage = 'Введённый вами адрес недоступен. Пожалуйста, укажите корректный e-mail.';
if(noticeShow === true) { return {
clearTimeout(noticeTimer); 'dns_records_not_found': 'Проверьте e-mail, такой домен не обнаружен.',
emailNotice.animate({ marginTop: '-=51px' }, 300); 'typed_domain': 'Обнаружена опечатка в домене. Проверьте внимательно указанный вами e-mail.',
noticeShow = false; 'wrong_email_format': 'Что-то не так в написании адреса. Возможно, указаны лишние точки или пробелы.<br>Адрес должен иметь вид: <b>имя_пользователя@имя_домена</b> (например <b>somebody@example.com</b>)',
'check': 'Идёт проверка адреса e-mail, это может занять несколько секунд.',
'empty': 'Адрес email пустой. Необходимо ввести корректный адрес email.'
}[error] || defaultMessage;
}
function setFieldStyle (className) {
var classesToRemove = [FIELD_INVALID, FIELD_LOADING, FIELD_SUCCESS].join(' ');
emailInput.removeClass(classesToRemove).addClass(className);
}
function setHash (hash) {
// Во все инпуты с name=emailhash запишем hash
$('input[name="emailhash"]').val(hash);
}
function setStatus (_status, message) {
if (_status === STATUS_NONE) {
hideNotice();
} else {
var noticeType, fieldType;
switch (_status) {
case STATUS_LOADING:
noticeType = NOTICE_YELLOW;
fieldType = FIELD_LOADING;
break;
case STATUS_SUCCESS:
noticeType = NOTICE_GREEN;
fieldType = FIELD_SUCCESS;
break;
default:
noticeType = NOTICE_RED;
fieldType = FIELD_INVALID;
}
status = _status;
if (modifyField) {
setFieldStyle(fieldType);
}
showNotice(noticeType, message);
} }
} }
function showNotice(type, message) { function showNotice(type, message) {
if(!document.getElementById('svcCheckEmail_notice')) { if (!document.getElementById('svcCheckEmail_notice')) {
var notice = '<div id="svcCheckEmail_notice"><div class="notice_center_auto">'; var notice = '<div id="svcCheckEmail_notice"><div class="notice_center_auto">';
notice += '<div id="notice_text"></div>'; notice += '<div id="notice_text"></div>';
notice += '<div id="notice_close_btn" onclick="closeNotice();">&nbsp;</div>'; notice += '<div id="notice_close_btn">&nbsp;</div>';
notice += '</div></div>'; notice += '</div></div>';
emailNotice = $(notice); emailNotice = $(notice);
$('body').prepend(emailNotice); $('body').prepend(emailNotice);
} }
...@@ -36,9 +194,12 @@ ...@@ -36,9 +194,12 @@
$('#notice_text').html(message); $('#notice_text').html(message);
emailNotice.removeClass().addClass(type); emailNotice.removeClass().addClass(type);
$('#notice_close_btn').removeClass().addClass(type); $('#notice_close_btn').removeClass().addClass(type).click(closeNotice);
lastNoticeType = type;
lastNoticeMessage = message;
if(noticeShow === false) { if (noticeShow === false) {
emailNotice.animate({ marginTop: '+=51px' }, 300); emailNotice.animate({ marginTop: '+=51px' }, 300);
noticeShow = true; noticeShow = true;
} }
...@@ -49,32 +210,12 @@ ...@@ -49,32 +210,12 @@
noticeShow = false; noticeShow = false;
}, 7000); }, 7000);
} }
function showErrorNotice(error) // Повторить сообщение
{ function showSameNotice () {
var noticeText; showNotice(lastNoticeType, lastNoticeMessage);
switch (error) {
case 'dns_records_not_found':
noticeText = 'Проверьте e-mail, такой домен не обнаружен.';
break;
case 'typed_domain':
noticeText = 'Обнаружена опечатка в домене. Проверьте внимательно указанный вами e-mail.';
break;
case 'wrong_email_format':
noticeText = 'Что-то не так в написании адреса. Возможно, указаны лишние точки или пробелы.<br>Адрес должен иметь вид: <b>имя_пользователя@имя_домена</b> (например <b>somebody@example.com</b>)';
break;
// FIXME
case 'check':
noticeText = 'Идёт проверка адреса e-mail, это может занять несколько секунд.';
default:
// FIXME
noticeText = 'Введённый вами адрес недоступен. Пожалуйста, укажите корректный e-mail.';
break;
}
showNotice('red', noticeText);
} }
// Добавляем CSS и расставляем вызов // Добавляем CSS и расставляем вызов
$(function() { $(function() {
$('<link />').attr({ $('<link />').attr({
...@@ -83,118 +224,47 @@ ...@@ -83,118 +224,47 @@
href: '//eterfund.ru/api/email/svcCheckEmail.css' href: '//eterfund.ru/api/email/svcCheckEmail.css'
}).appendTo('head'); }).appendTo('head');
var prev_emailCheck, checkDoneStatus = 'empty'; // Значение во время предыдущей проверки
var emailInput = $('.svcCheckEmail'); var previousCheckValue;
emailInput = $('.svcCheckEmail');
modifyField = !emailInput.hasClass('svcCheckEmail-nostyle');
var emailNotice, emailForm = emailInput.closest('form'); var emailNotice, emailForm = emailInput.closest('form');
emailForm.submit(function() { emailForm.submit(function() {
if(getEMail() == '') { var email = getEMail();
if (email === '') {
setStatus(STATUS_ERROR, getErrorMessage(ERROR_EMPTY));
return false; return false;
} }
// FIXME
if(checkDoneStatus == 'empty') { if (status === STATUS_NONE) {
emailInput.blur(); // Если в момент сабмита проверка не выполнялась - выполним её,
// после чего сабмитнем форму, если всё хорошо
checkEmailFull(email, function (result) {
if (result) {
emailForm.submit();
}
});
return false;
} }
if(checkDoneStatus != 'done') { if (status !== STATUS_SUCCESS) {
showErrorNotice(checkDoneStatus); showSameNotice();
return false;
} }
if(checkDoneStatus == 'done') { return true;
closeNotice();
return true;
}
/* forbid send */
return false;
}); });
emailInput.blur(function() { emailInput.blur(function () {
var email = getEMail(); var email = getEMail();
var regex = /^([^@\s]+)@(([a-zA-Z0-9\_\-]+\.)+([a-zA-Z]{2}|aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|post|pro|tel|travel|xxx))$/;
emailInput.val(email); emailInput.val(email);
if (previousCheckValue === email) {
if(prev_emailCheck == email) {
return false;
}
prev_emailCheck = email;
checkDoneStatus = 'fail';
if(email.length == 0) {
if(noticeShow === true) {
clearTimeout(noticeTimer);
emailNotice.css({ marginTop: '-51px' });
noticeShow = false;
}
emailInput.removeClass('bg-loader').removeClass('bg-true').removeClass('bg-false');
return false; return false;
} }
previousCheckValue = email;
inputHeight = parseInt(emailInput.height()) + parseInt(emailInput.css('margin-top')) + parseInt(emailInput.css('margin-bottom'));
checkEmailFull(email);
showNotice('yellow', 'Идёт проверка адреса e-mail, это может занять несколько секунд.');
checkDoneStatus = 'check';
emailInput.removeClass('bg-true').removeClass('bg-false').addClass('bg-loader');
clearTimeout(noticeTimer);
// Проверяем без отправки на сервер
if(email.length < 5 || !regex.test(email)) {
checkDoneStatus = 'wrong_email_format';
showErrorNotice(checkDoneStatus);
emailInput.removeClass('bg-loader').addClass('bg-false');
return false;
}
// Проверяем на сервере
$.ajax({
url: '//eterfund.ru/api/email/svcCheckEmail.php',
type: 'GET',
data: {
email: email
},
error: function() {
showNotice('red', 'Ошибка связи с сервером, проверка адреса не удалась.');
emailInput.removeClass('bg-loader').addClass('bg-true');
// FIXME
checkDoneStatus = 'true';
},
success: function(response) {
try {
response = JSON.parse(response);
if(response.status === false) {
showErrorNotice(response.error);
emailInput.removeClass('bg-loader').addClass('bg-false');
checkDoneStatus = response.error;
}
else {
showNotice('green', 'Email адрес указан верно.');
emailInput.removeClass('bg-loader').addClass('bg-true');
document.CheckEmailHash = response.hash;
/* emailhash hidden field support */
els = document.getElementsByName('emailhash');
if (els.length)
els[0].value = response.hash;
checkDoneStatus = 'done';
}
// FIXME
} catch (e) {
showNotice('yellow', 'Не удалось проверить адрес e-mail.');
emailInput.removeClass('bg-loader').addClass('bg-true');
checkDoneStatus = 'done';
}
}
});
return true;
}); });
}); });
})(); })();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment