Начало
Форма обратной связи(обратного звонка итд) представляет собой форму, при отправке которой на почту владельца магазина приходит письмо с нужным сообщением. В данном случае мы будем рассматривать вариант с AJAX, работающий без перезагрузки страницы при отправке и валидацией некоторых полей.
Создадим сниппет под названием fast_recall и разместим его перед закрывающим тегом body в шаблоне layout.
Для валидации поля с номером телефона понадобится плагин maskedinput, нужно залить его в раздел “скрипты” в шаблоне. Качать тут.
В сниппет добавим html структуру формы:
<div class="form_shadow"> </div> <div class="recallmsg"> <a class="closemsg" href="#">×</a> <form id="feedback_form" class="contact" action="/client_account/feedback" method="post" role="form"> <div class="h3">Обратный звонок</div> <input type="text" name="feedback[name]" value="" class="required" placeholder="Имя" /> <input type="text" name="feedback[phone]" value="" class="required" placeholder="Телефон" /> <input type="hidden" name="feedback[from]" placeholder="E-mail" value="fast@call.com" /> <input type="hidden" name="feedback[subject]" value="Обратный звонок" /> <textarea name="feedback[content]" value="" class="required" placeholder="Комментарий"></textarea> <a href="#" class="bttn">Отправить</a> <div class="notifications"> </div> </form> </div> <script type="text/javascript" src="https://cdn.rawgit.com/jashkenas/coffeescript/master/extras/coffee-script.js"></script> <script type="text/javascript" src="{{'jquery.maskedinput.js'| asset_url}}"></script> <script type="text/coffeescript"> </script> <h2>Стили</h2> <p> Стили добавляются в зависимости от дизайна сайта или как нравится, вот пример: </p> <pre> <style> .form_shadow { position: fixed; width: 100%; height: 100%; background: rgba(0,0,0,0.4); display: none; z-index: 9998; top: 0px; left: 0px; } .closemsg { float: right; margin-top: -5px; font-size: 18px; } .recallmsg { position: fixed; top: 40%; left: 50%; transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%); -moz-transform: translate(-50%, -50%); z-index: 9999; display: none; background-color: #fff; padding: 25px; } .recallmsg .contact .h3 { font-size: 18px; line-height: 30px; color: #4D3535; text-transform: uppercase; margin-bottom: 10px; } .recallmsg .contact input, .contact button, .contact select, .contact textarea { padding: 6px; border: 1px solid #e9e9e9; color: #2e3a47; outline: none; } .recallmsg .contact input[type="text"], .contact input[type="email"], .contact input[type="number"], .contact textarea { padding: 7px; margin-left: 0px; margin-right: 0px; -webkit-border-radius: 0px; -moz-border-radius: 0px; -ms-border-radius: 0px; -o-border-radius: 0px; border-radius: 0px; appearance: none; -moz-appearance: none; -ms-appearance: none; -o-appearance: none; -webkit-appearance: none; -webkit-transition: all 0.15s linear 0s; transition: all 0.15s linear 0s; height: 40px; float: left; width: 310px; font-size: 15px; line-height: 40px; margin-bottom: 10px; } .recallmsg .contact .bttn { display: inline-block; margin-bottom: 0; text-align: center; vertical-align: middle; cursor: pointer; background-image: none; border: 1px solid transparent; white-space: nowrap; line-height: 1.428571429; border-radius: 4px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none; text-align: center; background-color: #4D3535; color: #FFFFFF; padding: 5px 20px; font-size: 12px; font-weight: 300; -webkit-border-radius: 3px; -moz-border-radius: 3px; -ms-border-radius: 3px; -o-border-radius: 3px; border-radius: 3px; width: auto; text-transform: uppercase; -webkit-transition: background-color 400ms linear; transition: background-color 400ms linear; height: auto; text-decoration: none !important; } .recallmsg .contact .bttn:hover { background: #de5648; } .recallmsg .contact .notifications { text-align: left; width: 400px; font-style: italic; color: red; margin-top: 10px; } .recallmsg .contact textarea { height: 100px; } </style>
Вспомогательные функции
Для валидации полей почты и телефона нам понадобятся 2 функции. Маска телефона и проверка e-mail на наличие характерной структуры с собакой и точкой. Вот они:
$ -> $("input[name='feedback[phone]']").mask '+7 (999) 999-9999' validateEmail = (email) -> re = /\S+@\S+\.\S+/ re.test email hideForm = (e) -> e.preventDefault(); $('.form_shadow').fadeOut() $('.recallmsg').hide()
Вызов формы
Форму обратной связи нужно открывать и закрывать, поэтому напишем в механику этого вызова, а так же добавим в ту ссылку по которой будет вызываться форма класс “recall_link”. Кроме этого заставим форму закрываться при клике на тень или крестик.
hideForm = (e) -> e.preventDefault(); $('.form_shadow').fadeOut() $('.recallmsg').hide() $('.recall_link').on 'click', (e) -> e.preventDefault(); $('.form_shadow').fadeIn() $('.recallmsg').show() $('.form_shadow').on 'click', (e) -> console.log 1 hideForm e $('.recallmsg .closemsg').on 'click', (e) -> hideForm e
Логика
При клике на кнопку отправить нужно запустить механизм валидации. Для начала проверим на наличие контента в полях с классом “required”, если они пустые, то ставим переменную is_error true, также меняем цвет этого поля на красный, чтобы сообщить об ошибке. Далее проверяем e-mail на то, что он действительно e-mail, если нет, то так же меняем значение соответствующей переменной и цвет поля на красный. Если is_error true, то выводим в блок нотификаций красное сообщение и выходим из функции, иначе отправляем форму в виде JSON через AJAX. Если на запрос приходит положительный ответ от сервера, пишем зелененьким о том, что все хорошо и обнуляем значение поля. На этом логика кончается.
$('.recallmsg').find('.bttn').on 'click', (e) -> e.preventDefault() is_error = false r = $(@).parent('form.contact') note = r.find('.notifications') r.find("input.required, textarea.required").each -> if @value == @defaultValue is_error = true $(@).css 'background', 'rgba(255, 0, 0, 0.2)' else $(@).css 'background', '#fff' email = r.find("input[name='feedback[from]']") console.log email if validateEmail email.val() email.css 'background', '#fff' else email.css 'background','rgba(255, 0, 0, 0.2)' is_error = true if is_error note.html 'Не все поля заполнены правильно!' note.css 'color','red' return $.ajax url: r.attr('action') + '.json' type: 'post' data: r.serialize() dataType: 'json' success: (response) -> if response.status == 'ok' note.html 'Сообщение отправлено!' note.css 'color','green' r.find("textarea[name='feedback[content]']").val('') r.find("input[name='feedback[phone]']").val('') r.find("input[name='feedback[subject]']").val('') r.find("input[name='feedback[from]']").val('') r.find("input[name='feedback[name]']").val('') else note.html 'Ошибка!' note.css 'color','red'
Результат
Теперь все работает. Форма должна выглядеть примерно так и все кнопочки должны нажиматься:
Полный вид сниппета:
<div class="form_shadow"> </div> <div class="recallmsg"> <a class="closemsg" href="#">×</a> <form id="feedback_form" class="contact" action="/client_account/feedback" method="post" role="form"> <div class="h3">Обратный звонок</div> <input type="text" name="feedback[name]" value="" class="required" placeholder="Имя" /> <input type="text" name="feedback[phone]" value="" class="required" placeholder="Телефон" /> <input type="hidden" name="feedback[from]" placeholder="E-mail" value="fast@call.com" /> <input type="hidden" name="feedback[subject]" value="Обратный звонок" /> <textarea name="feedback[content]" value="" class="required" placeholder="Комментарий"></textarea> <a href="#" class="bttn">Отправить</a> <div class="notifications"> </div> </form> </div> <script type="text/javascript" src="https://cdn.rawgit.com/jashkenas/coffeescript/master/extras/coffee-script.js"></script> <script type="text/javascript" src="{{'jquery.maskedinput.js'| asset_url}}"></script> <script type="text/coffeescript"> $ -> $("input[name='feedback[phone]']").mask '+7 (999) 999-9999' validateEmail = (email) -> re = /\S+@\S+\.\S+/ re.test email hideForm = (e) -> e.preventDefault(); $('.form_shadow').fadeOut() $('.recallmsg').hide() $('.recall_link').on 'click', (e) -> e.preventDefault(); $('.form_shadow').fadeIn() $('.recallmsg').show() $('.form_shadow').on 'click', (e) -> console.log 1 hideForm e $('.recallmsg .closemsg').on 'click', (e) -> hideForm e $('.recallmsg').find('.bttn').on 'click', (e) -> e.preventDefault() is_error = false r = $(@).parent('form.contact') note = r.find('.notifications') r.find("input.required, textarea.required").each -> if @value == @defaultValue is_error = true $(@).css 'background', 'rgba(255, 0, 0, 0.2)' else $(@).css 'background', '#fff' email = r.find("input[name='feedback[from]']") console.log email if validateEmail email.val() email.css 'background', '#fff' else email.css 'background','rgba(255, 0, 0, 0.2)' is_error = true if is_error note.html 'Не все поля заполнены правильно!' note.css 'color','red' return $.ajax url: r.attr('action') + '.json' type: 'post' data: r.serialize() dataType: 'json' success: (response) -> if response.status == 'ok' note.html 'Сообщение отправлено!' note.css 'color','green' r.find("textarea[name='feedback[content]']").val('') r.find("input[name='feedback[phone]']").val('') r.find("input[name='feedback[subject]']").val('') r.find("input[name='feedback[from]']").val('') r.find("input[name='feedback[name]']").val('') else note.html 'Ошибка!' note.css 'color','red' </script> <style> .form_shadow { position: fixed; width: 100%; height: 100%; background: rgba(0,0,0,0.4); display: none; z-index: 9998; top: 0px; left: 0px; } .closemsg { float: right; margin-top: -5px; font-size: 18px; } .recallmsg { position: fixed; top: 40%; left: 50%; transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%); -moz-transform: translate(-50%, -50%); z-index: 9999; display: none; background-color: #fff; padding: 25px; } .recallmsg .contact .h3 { font-size: 18px; line-height: 30px; color: #4D3535; text-transform: uppercase; margin-bottom: 10px; } .recallmsg .contact input, .contact button, .contact select, .contact textarea { padding: 6px; border: 1px solid #e9e9e9; color: #2e3a47; outline: none; } .recallmsg .contact input[type="text"], .contact input[type="email"], .contact input[type="number"], .contact textarea { padding: 7px; margin-left: 0px; margin-right: 0px; -webkit-border-radius: 0px; -moz-border-radius: 0px; -ms-border-radius: 0px; -o-border-radius: 0px; border-radius: 0px; appearance: none; -moz-appearance: none; -ms-appearance: none; -o-appearance: none; -webkit-appearance: none; -webkit-transition: all 0.15s linear 0s; transition: all 0.15s linear 0s; height: 40px; float: left; width: 310px; font-size: 15px; line-height: 40px; margin-bottom: 10px; } .recallmsg .contact .bttn { display: inline-block; margin-bottom: 0; text-align: center; vertical-align: middle; cursor: pointer; background-image: none; border: 1px solid transparent; white-space: nowrap; line-height: 1.428571429; border-radius: 4px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none; text-align: center; background-color: #4D3535; color: #FFFFFF; padding: 5px 20px; font-size: 12px; font-weight: 300; -webkit-border-radius: 3px; -moz-border-radius: 3px; -ms-border-radius: 3px; -o-border-radius: 3px; border-radius: 3px; width: auto; text-transform: uppercase; -webkit-transition: background-color 400ms linear; transition: background-color 400ms linear; height: auto; text-decoration: none !important; } .recallmsg .contact .bttn:hover { background: #de5648; } .recallmsg .contact .notifications { text-align: left; width: 400px; font-style: italic; color: red; margin-top: 10px; } .recallmsg .contact textarea { height: 100px; } </style>
Итог
Последним шагом может стать компиляция CoffeScript в Javascript, однако скрипт загружается в самом конце страницы и выполняется только по клику, поэтому сильно не замедлит страницу. Также, сам скрипт в последствии может быть подвергнут изменениям, могут меняться обязательные поля, текст письма итд. Поэтому, возможно стоит оставить как есть. Тем не менее, вот код сниппета, с JS вместо CS.