form validation with Parsley

This commit is contained in:
Jonathan Labreuille
2015-11-06 12:28:24 +01:00
parent cfdb886e88
commit 31305a04c0
13 changed files with 166 additions and 237 deletions

View File

@ -5,7 +5,7 @@
@require 'common' @require 'common'
@require 'modal' @require 'modal'
@require 'notice' @require 'notice'
@require 'validation_engine' @require 'parsley'
@require 'form_editor' @require 'form_editor'
@require 'listing' @require 'listing'

View File

@ -0,0 +1,27 @@
input.parsley-success,
select.parsley-success,
textarea.parsley-success
color #468847
background-color #DFF0D8
border 1px solid #D6E9C6
input.parsley-error,
select.parsley-error,
textarea.parsley-error
color #B94A48
background-color #F2DEDE
border 1px solid #EED3D7
.parsley-errors-list
margin 2px 0 3px
padding 0
list-style-type none
font-size 0.9em
line-height 0.9em
opacity 0
transition all .3s ease-in
-o-transition all .3s ease-in
-moz-transition all .3s ease-in
-webkit-transition all .3s ease-in
&.filled
opacity 1

View File

@ -0,0 +1,3 @@
@import 'nib'
@require 'parsley'

View File

@ -1,141 +0,0 @@
lesscss-percentage(n)
(n * 100)%
popupBg = rgb(0, 87, 154, 1)
popupTextColor = rgb(255, 255, 255, 1)
borderColor = rgb(255, 255, 255, 1)
borderWidth = 1px
popupFontSize = 12px
popupRadius = 0
popupShadowWidth = 2px
popupShadowColor = rgb(51, 51, 51, 1)
/* Z-INDEX */
.formError
z-index 990
.formError .formErrorContent
z-index 991
.formError .formErrorArrow
z-index 996
.ui-dialog .formError
z-index 5000
.ui-dialog .formError .formErrorContent
z-index 5001
.ui-dialog .formError .formErrorArrow
z-index 5006
.inputContainer
position relative
float left
.formError
position absolute
top 300px
left 300px
display block
cursor pointer
text-align left
.formError.inline
position relative
top 0
left 0
display inline-block
.ajaxSubmit
padding 20px
background #55ea55
border 1px solid #999
display none
.formError .formErrorContent
width 100%
background popupBg
position relative
color popupTextColor
min-width 120px
font-size popupFontSize
border borderWidth solid borderColor
box-shadow 0 0 popupShadowWidth popupShadowColor
-moz-box-shadow 0 0 popupShadowWidth popupShadowColor
-webkit-box-shadow 0 0 popupShadowWidth popupShadowColor
-o-box-shadow 0 0 popupShadowWidth popupShadowColor
padding 4px 10px 4px 10px
border-radius popupRadius
-moz-border-radius popupRadius
-webkit-border-radius popupRadius
-o-border-radius popupRadius
.formError.inline .formErrorContent
box-shadow none
-moz-box-shadow none
-webkit-box-shadow none
-o-box-shadow none
border none
border-radius 0
-moz-border-radius 0
-webkit-border-radius 0
-o-border-radius 0
.greenPopup .formErrorContent
background #33be40
.blackPopup .formErrorContent
background #393939
color #FFF
.formError .formErrorArrow
width 15px
margin -2px 0 0 13px
position relative
body[dir='rtl'] .formError .formErrorArrow, body.rtl .formError .formErrorArrow
margin -2px 13px 0 0
.formError .formErrorArrowBottom
box-shadow none
-moz-box-shadow none
-webkit-box-shadow none
-o-box-shadow none
margin 0px 0 0 12px
top 2px
.formError .formErrorArrow div
border-left borderWidth solid borderColor
border-right borderWidth solid borderColor
box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
-moz-box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
-webkit-box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
-o-box-shadow 0 ceil((popupShadowWidth / 3)) ceil((popupShadowWidth / 2)) lighten(popupShadowColor, 10%)
font-size 0px
height 1px
background popupBg
margin 0 auto
line-height 0
font-size 0
display block
.formError .formErrorArrowBottom div
box-shadow none
-moz-box-shadow none
-webkit-box-shadow none
-o-box-shadow none
.greenPopup .formErrorArrow div
background #33be40
.blackPopup .formErrorArrow div
background #393939
color #FFF
.formError .formErrorArrow .line10
width 13px
border none
.formError .formErrorArrow .line9
width 11px
border none
.formError .formErrorArrow .line8
width 11px
.formError .formErrorArrow .line7
width 9px
.formError .formErrorArrow .line6
width 7px
.formError .formErrorArrow .line5
width 5px
.formError .formErrorArrow .line4
width 3px
.formError .formErrorArrow .line3
width ceil((borderWidth / 2))
border-left borderWidth solid borderColor
border-right borderWidth solid borderColor
border-bottom 0 solid borderColor
.formError .formErrorArrow .line2
width 3px
border none
background borderColor
.formError .formErrorArrow .line1
width 1px
border none
background borderColor

View File

@ -1,7 +1,14 @@
define('public', ['mailpoet', 'jquery', 'jquery-validation'], define([
function(MailPoet, $) { 'mailpoet',
'use strict'; 'jquery',
'parsleyjs'
],
function(
MailPoet,
jQuery,
Parsley
) {
jQuery(function($) {
function isSameDomain(url) { function isSameDomain(url) {
var link = document.createElement('a'); var link = document.createElement('a');
link.href = url; link.href = url;
@ -11,59 +18,61 @@ define('public', ['mailpoet', 'jquery', 'jquery-validation'],
$(function() { $(function() {
// setup form validation // setup form validation
$('form.mailpoet_form').each(function() { $('form.mailpoet_form').each(function() {
$(this).validate({ var form = $(this);
submitHandler: function(form) {
var data = $(form).serializeObject() || {};
// clear messages form.parsley().on('form:submit', function(parsley) {
$(form).find('.mailpoet_message').html('');
// check if we're on the same domain var data = form.serializeObject() || {};
if(isSameDomain(MailPoetForm.ajax_url) === false) {
// non ajax post request
return true;
} else {
// ajax request
MailPoet.Ajax.post({
url: MailPoetForm.ajax_url,
token: MailPoetForm.token,
endpoint: 'subscribers',
action: 'subscribe',
data: data,
onSuccess: function(response) {
if(response.result !== true) {
// errors
$.each(response.errors, function(index, error) {
$(form)
.find('.mailpoet_message')
.append('<p class="mailpoet_validate_error">'+
error+
'</p>');
});
} else {
// successfully subscribed
if(response.page !== undefined) {
// go to page
window.location.href = response.page;
} else if(response.message !== undefined) {
// display success message
$(form)
.find('.mailpoet_message')
.html('<p class="mailpoet_validate_success">'+
response.message+
'</p>');
}
// reset form // clear messages
$(form).trigger('reset'); form.find('.mailpoet_message').html('');
}
// check if we're on the same domain
if(isSameDomain(MailPoetForm.ajax_url) === false) {
// non ajax post request
return true;
} else {
// ajax request
MailPoet.Ajax.post({
url: MailPoetForm.ajax_url,
token: MailPoetForm.token,
endpoint: 'subscribers',
action: 'subscribe',
data: data
}).done(function(response) {
if(response.result !== true) {
// errors
$.each(response.errors, function(index, error) {
form
.find('.mailpoet_message')
.append('<p class="mailpoet_validate_error">'+
error+
'</p>');
});
} else {
// successfully subscribed
if(response.page !== undefined) {
// go to page
window.location.href = response.page;
} else if(response.message !== undefined) {
// display success message
form
.find('.mailpoet_message')
.html('<p class="mailpoet_validate_success">'+
response.message+
'</p>');
} }
});
} // reset form
return false; form.trigger('reset');
// reset validation
parsley.reset();
}
});
} }
return false;
}); });
}); });
}); });
} });
); });

43
composer.lock generated
View File

@ -160,16 +160,16 @@
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v5.2.13", "version": "v5.2.14",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git", "url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "45df3a88f7f46071e10d0b600f228d19f95911b3" "reference": "e774bc9152de85547336e22b8926189e582ece95"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/45df3a88f7f46071e10d0b600f228d19f95911b3", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/e774bc9152de85547336e22b8926189e582ece95",
"reference": "45df3a88f7f46071e10d0b600f228d19f95911b3", "reference": "e774bc9152de85547336e22b8926189e582ece95",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -180,7 +180,8 @@
"phpunit/phpunit": "4.7.*" "phpunit/phpunit": "4.7.*"
}, },
"suggest": { "suggest": {
"league/oauth2-client": "Needed for Gmail's XOAUTH2 authentication system" "league/oauth2-client": "Needed for XOAUTH2 authentication",
"league/oauth2-google": "Needed for Gmail XOAUTH2"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -216,7 +217,7 @@
} }
], ],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP", "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"time": "2015-09-14 09:18:12" "time": "2015-11-01 10:15:28"
}, },
{ {
"name": "phpseclib/phpseclib", "name": "phpseclib/phpseclib",
@ -456,16 +457,16 @@
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v1.23.0", "version": "v1.23.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig.git", "url": "https://github.com/twigphp/Twig.git",
"reference": "5868cd822fd6cf626d5f805439575f9c323cee2a" "reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/5868cd822fd6cf626d5f805439575f9c323cee2a", "url": "https://api.github.com/repos/twigphp/Twig/zipball/d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
"reference": "5868cd822fd6cf626d5f805439575f9c323cee2a", "reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -513,7 +514,7 @@
"keywords": [ "keywords": [
"templating" "templating"
], ],
"time": "2015-10-29 23:29:01" "time": "2015-11-05 12:49:06"
} }
], ],
"packages-dev": [ "packages-dev": [
@ -739,16 +740,16 @@
}, },
{ {
"name": "facebook/webdriver", "name": "facebook/webdriver",
"version": "1.0.2", "version": "1.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/facebook/php-webdriver.git", "url": "https://github.com/facebook/php-webdriver.git",
"reference": "fe1bbbc5dde804d08a8593f1d9d0d3b05f5c84f5" "reference": "d843e33fd19b49db5ac9daaef2610079daab0bad"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/fe1bbbc5dde804d08a8593f1d9d0d3b05f5c84f5", "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/d843e33fd19b49db5ac9daaef2610079daab0bad",
"reference": "fe1bbbc5dde804d08a8593f1d9d0d3b05f5c84f5", "reference": "d843e33fd19b49db5ac9daaef2610079daab0bad",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -778,7 +779,7 @@
"selenium", "selenium",
"webdriver" "webdriver"
], ],
"time": "2015-08-12 20:21:31" "time": "2015-11-01 20:09:34"
}, },
{ {
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",
@ -895,16 +896,16 @@
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "1.2.0", "version": "1.2.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/psr7.git", "url": "https://github.com/guzzle/psr7.git",
"reference": "4ef919b0cf3b1989523138b60163bbcb7ba1ff7e" "reference": "4d0bdbe1206df7440219ce14c972aa57cc5e4982"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/4ef919b0cf3b1989523138b60163bbcb7ba1ff7e", "url": "https://api.github.com/repos/guzzle/psr7/zipball/4d0bdbe1206df7440219ce14c972aa57cc5e4982",
"reference": "4ef919b0cf3b1989523138b60163bbcb7ba1ff7e", "reference": "4d0bdbe1206df7440219ce14c972aa57cc5e4982",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -949,7 +950,7 @@
"stream", "stream",
"uri" "uri"
], ],
"time": "2015-08-15 19:32:36" "time": "2015-11-03 01:34:55"
}, },
{ {
"name": "henrikbjorn/lurker", "name": "henrikbjorn/lurker",

View File

@ -37,6 +37,15 @@ class Widget {
} }
function setupDependencies() { function setupDependencies() {
wp_enqueue_style('mailpoet_public', Env::$assets_url.'/css/public.css');
wp_enqueue_script('mailpoet_vendor',
Env::$assets_url.'/js/vendor.js',
array(),
Env::$version,
true
);
wp_enqueue_script('mailpoet_public', wp_enqueue_script('mailpoet_public',
Env::$assets_url.'/js/public.js', Env::$assets_url.'/js/public.js',
array(), array(),
@ -58,6 +67,7 @@ class Widget {
Env::$version, Env::$version,
true true
); );
wp_enqueue_script('mailpoet_admin', wp_enqueue_script('mailpoet_admin',
Env::$assets_url.'/js/mailpoet.js', Env::$assets_url.'/js/mailpoet.js',
array(), array(),

View File

@ -3,24 +3,21 @@ namespace MailPoet\Form\Block;
abstract class Base { abstract class Base {
protected static function getInputValidation($block) { protected static function getInputValidation($block) {
return 'data-validation-engine="'.static::getInputValidationRules($block).'"';
}
protected static function getInputValidationRules($block) {
$rules = array(); $rules = array();
$is_required = false;
if($block['name'] === 'email') { if($block['id'] === 'email') {
$rules[] = 'required'; $is_required = true;
$rules[] = 'custom[email]'; $rules[] = 'custom[email]';
} }
if($block['name'] === 'list') { if($block['id'] === 'segments') {
$rules[] = 'required'; $is_required = true;
} }
if(isset($block['params']['required']) if(!empty($block['params']['required'])) {
&& (bool)$block['params']['required'] === true) { $is_required = true;
$rules[] = 'required';
} }
if(isset($block['params']['validate'])) { if(isset($block['params']['validate'])) {
@ -36,13 +33,19 @@ abstract class Base {
} }
// generate string if there is at least one rule to validate against // generate string if there is at least one rule to validate against
if(empty($rules)) { $validation = '';
return '';
} else { if(!empty($rules)) {
// make sure rules are not duplicated
$rules = array_unique($rules); $rules = array_unique($rules);
return 'validate['.join(',', $rules).']'; //return 'validate['.join(',', $rules).']';
// TODO: convert to Parsley format!
} }
if($is_required === true) {
$validation .= ' required';
}
return $validation;
} }
protected static function renderLabel($block) { protected static function renderLabel($block) {

View File

@ -4,13 +4,18 @@ namespace MailPoet\Form\Block;
class Input extends Base { class Input extends Base {
static function render($block) { static function render($block) {
$type = 'text';
if($block['id'] === 'email') {
$type = 'email';
}
$html = ''; $html = '';
$html .= '<p class="mailpoet_paragraph">'; $html .= '<p class="mailpoet_paragraph">';
$html .= static::renderLabel($block); $html .= static::renderLabel($block);
$html .= '<input type="text" class="mailpoet_input" '; $html .= '<input type="'.$type.'" class="mailpoet_input" ';
$html .= 'name="'.static::getFieldName($block).'" '; $html .= 'name="'.static::getFieldName($block).'" ';

View File

@ -82,11 +82,16 @@ class Subscribers {
$errors[] = __('This form does not exist.'); $errors[] = __('This form does not exist.');
} }
$segments = Segment::whereIn('id', (array)$data['segments'])->findMany(); if(empty($data['segments'])) {
unset($data['segments']);
if(empty($segments)) {
$errors[] = __('You need to select a list'); $errors[] = __('You need to select a list');
} else {
$segments = Segment::whereIn('id', (array)$data['segments'])->findMany();
if(empty($segments)) {
$errors[] = __('You need to select a list');
}
} }
unset($data['segments']);
$subscriber = false; $subscriber = false;
if(!empty($errors)) { if(!empty($errors)) {

View File

@ -21,10 +21,10 @@
"history": "^1.12.5", "history": "^1.12.5",
"html2canvas": "latest", "html2canvas": "latest",
"interact.js": "latest", "interact.js": "latest",
"jquery-validation": "^1.14.0",
"moment": "^2.10.3", "moment": "^2.10.3",
"napa": "^1.2.0", "napa": "^1.2.0",
"papaparse": "4.1.1", "papaparse": "4.1.1",
"parsley": "^0.1.0",
"react": "^0.14.1", "react": "^0.14.1",
"react-checkbox-group": "0.2.2", "react-checkbox-group": "0.2.2",
"react-dom": "^0.14.1", "react-dom": "^0.14.1",

View File

@ -10,8 +10,12 @@
<form <form
id="<%= form_id %>" id="<%= form_id %>"
method="post" method="post"
<#
action="<%= admin_url('admin-post.php?action=mailpoet_form_subscribe') | raw %>" action="<%= admin_url('admin-post.php?action=mailpoet_form_subscribe') | raw %>"
class="mailpoet_form mailpoet_form_<%= form_type %>" novalidate #>
class="mailpoet_form mailpoet_form_<%= form_type %>"
novalidate
data-parsley-validate
> >
<div class="mailpoet_message"></div> <div class="mailpoet_message"></div>

View File

@ -153,6 +153,9 @@ config.push(_.extend({}, baseConfig, {
'public.js' 'public.js'
] ]
}, },
/*plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'),
],*/
externals: { externals: {
'jquery': 'jQuery' 'jquery': 'jQuery'
} }