parsley-rails 1.1.18.0 → 1.2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/parsley-rails/version.rb +1 -1
- data/vendor/assets/javascripts/parsley.extend.js +113 -76
- data/vendor/assets/javascripts/parsley.i18n.cs.js +7 -7
- data/vendor/assets/javascripts/parsley.i18n.cy.js +1 -2
- data/vendor/assets/javascripts/parsley.i18n.it.js +1 -1
- data/vendor/assets/javascripts/parsley.i18n.no.js +8 -8
- data/vendor/assets/javascripts/parsley.i18n.ru.js +2 -2
- data/vendor/assets/javascripts/parsley.i18n.vn.js +1 -2
- data/vendor/assets/javascripts/parsley.js +480 -304
- data/vendor/assets/javascripts/parsley.l10n.es.js +157 -132
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f4d0c0d9261762aa5ac043ab0e05123dddf0234
|
4
|
+
data.tar.gz: 068a8f50f49b2e1d0c43d31fda81852c3323ef9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 760f5fdda70bc1ec7cef59e6ae8f10a62f98b34d9770348ee46da1fd912bf31e9405592e0af59629d9f5e257e62b48b53e9709415fa0b82dbae6f392a6cf5b4d
|
7
|
+
data.tar.gz: 50a8cad8e8164b386afe55334783b1c499127d1f8f0e548e3657ce589676b65b57416852e9ebb31ea59355fd1e9581132586cf5af259e04410c19d0273c961f0
|
@@ -3,98 +3,135 @@ window.ParsleyConfig = window.ParsleyConfig || {};
|
|
3
3
|
(function ($) {
|
4
4
|
window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, {
|
5
5
|
validators: {
|
6
|
-
minwords: function (
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
minwords: function () {
|
7
|
+
return {
|
8
|
+
validate: function ( val, nbWords ) {
|
9
|
+
val = val.replace( /(^\s*)|(\s*$)/gi, "" );
|
10
|
+
val = val.replace( /[ ]{2,}/gi, " " );
|
11
|
+
val = val.replace( /\n /, "\n" );
|
12
|
+
val = val.split(' ').length;
|
13
|
+
|
14
|
+
return val >= nbWords;
|
15
|
+
}
|
16
|
+
, priority: 32
|
17
|
+
}
|
13
18
|
}
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
, maxwords : function () {
|
20
|
+
return {
|
21
|
+
validate: function ( val, nbWords ) {
|
22
|
+
val = val.replace( /(^\s*)|(\s*$)/gi, "" );
|
23
|
+
val = val.replace( /[ ]{2,}/gi, " " );
|
24
|
+
val = val.replace( /\n /, "\n" );
|
25
|
+
val = val.split(' ').length;
|
26
|
+
|
27
|
+
return val <= nbWords;
|
28
|
+
}
|
29
|
+
, priority: 32
|
30
|
+
}
|
22
31
|
}
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
32
|
+
, rangewords: function () {
|
33
|
+
var that = this;
|
34
|
+
return {
|
35
|
+
validate: function ( val, arrayRange) {
|
36
|
+
return that.minwords().validate( val, arrayRange[0] ) && that.maxwords().validate( val, arrayRange[1] );
|
37
|
+
}
|
38
|
+
, priority: 32
|
39
|
+
}
|
31
40
|
}
|
41
|
+
, greaterthan: function () {
|
42
|
+
return {
|
43
|
+
validate: function ( val, elem, self ) {
|
44
|
+
self.options.validateIfUnchanged = true;
|
32
45
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
46
|
+
return new Number(val) > new Number($( elem ).val());
|
47
|
+
}
|
48
|
+
, priority: 32
|
49
|
+
}
|
37
50
|
}
|
51
|
+
, lessthan: function () {
|
52
|
+
return {
|
53
|
+
validate: function ( val, elem, self ) {
|
54
|
+
self.options.validateIfUnchanged = true;
|
38
55
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
56
|
+
return new Number(val) < new Number($( elem ).val());
|
57
|
+
}
|
58
|
+
, priority: 32
|
59
|
+
}
|
43
60
|
}
|
44
|
-
|
45
|
-
|
46
|
-
|
61
|
+
, beforedate: function () {
|
62
|
+
return {
|
63
|
+
validate: function ( val, elem, self) {
|
64
|
+
return Date.parse(val) < Date.parse($(elem).val());
|
65
|
+
}
|
66
|
+
, priority: 32
|
67
|
+
}
|
47
68
|
}
|
48
|
-
|
49
|
-
|
50
|
-
|
69
|
+
, afterdate: function () {
|
70
|
+
return {
|
71
|
+
validate: function ( val, elem, self) {
|
72
|
+
return Date.parse($(elem).val()) < Date.parse(val);
|
73
|
+
}
|
74
|
+
, priority: 32
|
75
|
+
}
|
51
76
|
}
|
77
|
+
, inlist: function () {
|
78
|
+
return {
|
79
|
+
validate: function ( val, list, self ) {
|
80
|
+
var delimiter = self.options.inlistDelimiter || ',';
|
81
|
+
var listItems = (list + "").split(new RegExp("\\s*\\" + delimiter + "\\s*"));
|
52
82
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
return (listItems.indexOf(val.trim()) !== -1);
|
83
|
+
return (listItems.indexOf(val.trim()) !== -1);
|
84
|
+
}
|
85
|
+
, priority: 32
|
86
|
+
}
|
58
87
|
}
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
88
|
+
, luhn: function () {
|
89
|
+
return {
|
90
|
+
validate: function ( val, elem, self) {
|
91
|
+
val = val.replace(/[ -]/g, '');
|
92
|
+
var digit, n, sum, _j, _len1, _ref2;
|
93
|
+
sum = 0;
|
94
|
+
_ref2 = val.split('').reverse();
|
95
|
+
for (n = _j = 0, _len1 = _ref2.length; _j < _len1; n = ++_j) {
|
96
|
+
digit = _ref2[n];
|
97
|
+
digit = +digit;
|
98
|
+
if (n % 2) {
|
99
|
+
digit *= 2;
|
100
|
+
if (digit < 10) {
|
101
|
+
sum += digit;
|
102
|
+
} else {
|
103
|
+
sum += digit - 9;
|
104
|
+
}
|
105
|
+
} else {
|
106
|
+
sum += digit;
|
107
|
+
}
|
74
108
|
}
|
75
|
-
|
76
|
-
sum += digit;
|
109
|
+
return sum % 10 === 0;
|
77
110
|
}
|
111
|
+
, priority: 32
|
78
112
|
}
|
79
|
-
return sum % 10 === 0;
|
80
113
|
}
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
114
|
+
, americandate: function () {
|
115
|
+
return {
|
116
|
+
validate: function ( val, elem, self) {
|
117
|
+
if ( !/^([01]?[0-9])[\.\/-]([0-3]?[0-9])[\.\/-]([0-9]{4}|[0-9]{2})$/.test( val ) ) {
|
118
|
+
return false;
|
119
|
+
}
|
120
|
+
var parts = val.split(/[.\/-]+/);
|
121
|
+
var day = parseInt(parts[1], 10);
|
122
|
+
var month = parseInt(parts[0], 10);
|
123
|
+
var year = parseInt(parts[2], 10);
|
124
|
+
if ( year == 0 || month == 0 || month > 12 ) {
|
125
|
+
return false;
|
126
|
+
}
|
127
|
+
var monthLength = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
|
128
|
+
if ( year % 400 == 0 || ( year % 100 != 0 && year % 4 == 0 ) ) {
|
129
|
+
monthLength[1] = 29;
|
130
|
+
}
|
131
|
+
return day > 0 && day <= monthLength[month - 1];
|
132
|
+
}
|
133
|
+
, priority: 32
|
96
134
|
}
|
97
|
-
return day > 0 && day <= monthLength[month - 1];
|
98
135
|
}
|
99
136
|
}
|
100
137
|
, messages: {
|
@@ -25,9 +25,9 @@ window.ParsleyConfig = window.ParsleyConfig || {};
|
|
25
25
|
, minlength: "Tato položka je příliš krátká. Musí mít %s nebo více znaků."
|
26
26
|
, maxlength: "Tato položka je příliš dlouhá. Musí mít %s nebo méně znaků."
|
27
27
|
, rangelength: "Tato položka je mimo rozsah. Musí být rozmezí %s a %s znaků."
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
, mincheck: "Je nutné vybrat nejméně %s možností."
|
29
|
+
, maxcheck: "Je nutné vybrat nejvýše %s možností."
|
30
|
+
, rangecheck: "Je nutné vybrat %s až %s možností."
|
31
31
|
, equalto: "Tato položka by měla být stejná."
|
32
32
|
|
33
33
|
// parsley.extend ///////////////////////////////
|
@@ -36,10 +36,10 @@ window.ParsleyConfig = window.ParsleyConfig || {};
|
|
36
36
|
, rangewords: "Tato položka musí obsahovat %s až %s slov."
|
37
37
|
, greaterthan: "Tato položka musí být větší než %s."
|
38
38
|
, lessthan: "Tato položka musí být menší než %s."
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
, beforedate: "Toto datum musí být před %s."
|
40
|
+
, afterdate: "Toto datum musí být po %s."
|
41
|
+
, luhn: "Tato hodnota by měla projít Luhnovým testem."
|
42
|
+
, americandate: "Toto datum by mělo být ve formátu MM/DD/YYYY."
|
43
43
|
}
|
44
44
|
});
|
45
45
|
}(window.jQuery || window.Zepto));
|
@@ -25,7 +25,6 @@ window.ParsleyConfig = window.ParsleyConfig || {};
|
|
25
25
|
, maxlength: "Mae'r gwerth hwn yn rhy hir. Dylai fod yna %s neu llai o lythrennau"
|
26
26
|
, rangelength: "Mae'r gwerth hyd yn annilys. Dylai fod yna rhwng %s a %s o lythrennau"
|
27
27
|
, equalto: "Dylai'r gwerth hwn fod yr un fath."
|
28
|
-
|
29
28
|
|
30
29
|
// parsley.extend ///////////////////////////////
|
31
30
|
, minwords: "Dylai'r gwerth hwn cynnwys o leiaf %s gair."
|
@@ -36,4 +35,4 @@ window.ParsleyConfig = window.ParsleyConfig || {};
|
|
36
35
|
|
37
36
|
}
|
38
37
|
});
|
39
|
-
}(window.jQuery || window.Zepto));
|
38
|
+
}(window.jQuery || window.Zepto));
|
@@ -32,7 +32,7 @@ window.ParsleyConfig = window.ParsleyConfig || {};
|
|
32
32
|
, rangewords: "Questo valore deve contenere tra %s e %s parole."
|
33
33
|
, greaterthan: "Questo valore deve essere maggiore di %s."
|
34
34
|
, lessthan: "Questo valore deve essere minore di %s."
|
35
|
-
|
35
|
+
, beforedate: "Questa data deve essere anteriore al %s."
|
36
36
|
, afterdate: "Questa data deve essere posteriore al %s."
|
37
37
|
, luhn: "Questo valore deve superare il test di Luhn."
|
38
38
|
}
|
@@ -31,14 +31,14 @@ window.ParsleyConfig = window.ParsleyConfig || {};
|
|
31
31
|
, equalto: "Denne verdien må være lik."
|
32
32
|
|
33
33
|
// parsley.extend ///////////////////////////////
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
, minwords: "Denne verdien må inneholde minst %s ord."
|
35
|
+
, maxwords: "Denne verdien kan ikke inneholde mer enn %s ord."
|
36
|
+
, rangewords: "Denne verdien må ha mellom %s og %s ord."
|
37
|
+
, greaterthan: "Denne verdien må være større enn %s."
|
38
|
+
, lessthan: "Denne verdien må være mindre enn %s."
|
39
|
+
, beforedate: "Datoen må være før %s."
|
40
|
+
, afterdate: "Datoen må være etter %s."
|
41
|
+
, americandate: "Datoen må være på gyldig format (MM/DD/YYYY)."
|
42
42
|
}
|
43
43
|
});
|
44
44
|
}(window.jQuery || window.Zepto));
|
@@ -12,8 +12,8 @@ window.ParsleyConfig = window.ParsleyConfig || {};
|
|
12
12
|
, number: "Поле должно быть числом."
|
13
13
|
, digits: "Поле должно содержать только цифры."
|
14
14
|
, dateIso: "Поле должно быть датой в формате (ГГГГ-ММ-ДД)."
|
15
|
-
, alphanum: "Поле должно содержать только цифры и
|
16
|
-
, phone: "Поле должно содержать корректный номер
|
15
|
+
, alphanum: "Поле должно содержать только цифры и буквы."
|
16
|
+
, phone: "Поле должно содержать корректный номер телефона."
|
17
17
|
}
|
18
18
|
, notnull: "Поле должно быть не нулевым."
|
19
19
|
, notblank: "Поле не должно быть пустым."
|
@@ -4,7 +4,7 @@ window.ParsleyConfig = window.ParsleyConfig || {};
|
|
4
4
|
window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, {
|
5
5
|
messages: {
|
6
6
|
// parsley //////////////////////////////////////
|
7
|
-
|
7
|
+
defaultMessage: "Thông tin này không hợp lệ."
|
8
8
|
, type: {
|
9
9
|
email: "Email không hợp lệ."
|
10
10
|
, url: "Url không hợp lệ."
|
@@ -33,4 +33,3 @@ window.ParsleyConfig = window.ParsleyConfig || {};
|
|
33
33
|
}
|
34
34
|
});
|
35
35
|
}(window.jQuery || window.Zepto));
|
36
|
-
|
@@ -64,170 +64,232 @@
|
|
64
64
|
* @type {Object}
|
65
65
|
*/
|
66
66
|
, validators: {
|
67
|
-
notnull: function (
|
68
|
-
return
|
67
|
+
notnull: function () {
|
68
|
+
return {
|
69
|
+
validate: function ( val ) {
|
70
|
+
return val.length > 0;
|
71
|
+
}
|
72
|
+
, priority: 2
|
73
|
+
}
|
69
74
|
}
|
70
|
-
|
71
|
-
|
72
|
-
|
75
|
+
, notblank: function () {
|
76
|
+
return {
|
77
|
+
validate: function ( val ) {
|
78
|
+
return 'string' === typeof val && '' !== val.replace( /^\s+/g, '' ).replace( /\s+$/g, '' );
|
79
|
+
}
|
80
|
+
, priority: 2
|
81
|
+
}
|
73
82
|
}
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
+
, required: function () {
|
84
|
+
var that = this;
|
85
|
+
return {
|
86
|
+
validate: function ( val ) {
|
87
|
+
// for checkboxes and select multiples. Check there is at least one required value
|
88
|
+
if ( 'object' === typeof val ) {
|
89
|
+
for ( var i in val ) {
|
90
|
+
if ( that.required().validate( val[ i ] ) ) {
|
91
|
+
return true;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
return false;
|
83
96
|
}
|
84
|
-
}
|
85
97
|
|
86
|
-
|
98
|
+
return that.notnull().validate( val ) && that.notblank().validate( val );
|
99
|
+
}
|
100
|
+
, priority: 512
|
87
101
|
}
|
88
|
-
|
89
|
-
return this.notnull( val ) && this.notblank( val );
|
90
102
|
}
|
103
|
+
, type: function () {
|
104
|
+
return {
|
105
|
+
validate: function ( val, type ) {
|
106
|
+
var regExp;
|
107
|
+
|
108
|
+
switch ( type ) {
|
109
|
+
case 'number':
|
110
|
+
regExp = /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/;
|
111
|
+
break;
|
112
|
+
case 'digits':
|
113
|
+
regExp = /^\d+$/;
|
114
|
+
break;
|
115
|
+
case 'alphanum':
|
116
|
+
regExp = /^\w+$/;
|
117
|
+
break;
|
118
|
+
case 'email':
|
119
|
+
regExp = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))){2,6}$/i;
|
120
|
+
break;
|
121
|
+
case 'url':
|
122
|
+
val = new RegExp( '(https?|s?ftp|git)', 'i' ).test( val ) ? val : 'http://' + val;
|
123
|
+
/* falls through */
|
124
|
+
case 'urlstrict':
|
125
|
+
regExp = /^(https?|s?ftp|git):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
|
126
|
+
break;
|
127
|
+
case 'dateIso':
|
128
|
+
regExp = /^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])$/;
|
129
|
+
break;
|
130
|
+
case 'phone':
|
131
|
+
regExp = /^((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,5})|(\(?\d{2,6}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}$/;
|
132
|
+
break;
|
133
|
+
default:
|
134
|
+
return false;
|
135
|
+
}
|
91
136
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
case 'number':
|
97
|
-
regExp = /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/;
|
98
|
-
break;
|
99
|
-
case 'digits':
|
100
|
-
regExp = /^\d+$/;
|
101
|
-
break;
|
102
|
-
case 'alphanum':
|
103
|
-
regExp = /^\w+$/;
|
104
|
-
break;
|
105
|
-
case 'email':
|
106
|
-
regExp = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))){2,6}$/i;
|
107
|
-
break;
|
108
|
-
case 'url':
|
109
|
-
val = new RegExp( '(https?|s?ftp|git)', 'i' ).test( val ) ? val : 'http://' + val;
|
110
|
-
/* falls through */
|
111
|
-
case 'urlstrict':
|
112
|
-
regExp = /^(https?|s?ftp|git):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
|
113
|
-
break;
|
114
|
-
case 'dateIso':
|
115
|
-
regExp = /^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])$/;
|
116
|
-
break;
|
117
|
-
case 'phone':
|
118
|
-
regExp = /^((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,5})|(\(?\d{2,6}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}$/;
|
119
|
-
break;
|
120
|
-
default:
|
121
|
-
return false;
|
137
|
+
// test regExp if not null
|
138
|
+
return '' !== val ? regExp.test( val ) : false;
|
139
|
+
}
|
140
|
+
, priority: 256
|
122
141
|
}
|
123
|
-
|
124
|
-
// test regExp if not null
|
125
|
-
return '' !== val ? regExp.test( val ) : false;
|
126
142
|
}
|
127
|
-
|
128
|
-
|
129
|
-
|
143
|
+
, regexp: function () {
|
144
|
+
return {
|
145
|
+
validate: function ( val, regExp, self ) {
|
146
|
+
return new RegExp( regExp, self.options.regexpFlag || '' ).test( val );
|
147
|
+
}
|
148
|
+
, priority: 64
|
149
|
+
}
|
130
150
|
}
|
131
|
-
|
132
|
-
|
133
|
-
|
151
|
+
, minlength: function () {
|
152
|
+
return {
|
153
|
+
validate: function ( val, min ) {
|
154
|
+
return val.length >= min;
|
155
|
+
}
|
156
|
+
, priority: 32
|
157
|
+
}
|
134
158
|
}
|
135
|
-
|
136
|
-
|
137
|
-
|
159
|
+
, maxlength: function () {
|
160
|
+
return {
|
161
|
+
validate: function ( val, max ) {
|
162
|
+
return val.length <= max;
|
163
|
+
}
|
164
|
+
, priority: 32
|
165
|
+
}
|
138
166
|
}
|
139
|
-
|
140
|
-
|
141
|
-
return
|
167
|
+
, rangelength: function () {
|
168
|
+
var that = this;
|
169
|
+
return {
|
170
|
+
validate: function ( val, arrayRange ) {
|
171
|
+
return that.minlength().validate( val, arrayRange[ 0 ] ) && that.maxlength().validate( val, arrayRange[ 1 ] );
|
172
|
+
}
|
173
|
+
, priority: 32
|
174
|
+
}
|
142
175
|
}
|
143
|
-
|
144
|
-
|
145
|
-
|
176
|
+
, min: function () {
|
177
|
+
return {
|
178
|
+
validate: function ( val, min ) {
|
179
|
+
return Number( val ) >= min;
|
180
|
+
}
|
181
|
+
, priority: 32
|
182
|
+
}
|
146
183
|
}
|
147
|
-
|
148
|
-
|
149
|
-
|
184
|
+
, max: function () {
|
185
|
+
return {
|
186
|
+
validate: function ( val, max ) {
|
187
|
+
return Number( val ) <= max;
|
188
|
+
}
|
189
|
+
, priority: 32
|
190
|
+
}
|
150
191
|
}
|
151
|
-
|
152
|
-
|
153
|
-
return
|
192
|
+
, range: function () {
|
193
|
+
var that = this;
|
194
|
+
return {
|
195
|
+
validate: function ( val, arrayRange ) {
|
196
|
+
return that.min().validate( val, arrayRange[ 0 ] ) && that.max().validate( val, arrayRange[ 1 ] );
|
197
|
+
}
|
198
|
+
, priority: 32
|
199
|
+
}
|
154
200
|
}
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
201
|
+
, equalto: function () {
|
202
|
+
return {
|
203
|
+
validate: function ( val, elem, self ) {
|
204
|
+
self.options.validateIfUnchanged = true;
|
205
|
+
return val === $( elem ).val();
|
206
|
+
}
|
207
|
+
, priority: 64
|
208
|
+
}
|
160
209
|
}
|
210
|
+
, remote: function () {
|
211
|
+
return {
|
212
|
+
validate: function ( val, url, self ) {
|
213
|
+
var result = null
|
214
|
+
, data = {}
|
215
|
+
, dataType = {};
|
161
216
|
|
162
|
-
|
163
|
-
var result = null
|
164
|
-
, data = {}
|
165
|
-
, dataType = {};
|
217
|
+
data[ self.$element.attr( 'name' ) ] = val;
|
166
218
|
|
167
|
-
|
219
|
+
if ( 'undefined' !== typeof self.options.remoteDatatype )
|
220
|
+
dataType = { dataType: self.options.remoteDatatype };
|
168
221
|
|
169
|
-
|
170
|
-
|
171
|
-
|
222
|
+
var manage = function ( isConstraintValid, message ) {
|
223
|
+
// remove error message if we got a server message, different from previous message
|
224
|
+
if ( 'undefined' !== typeof message && 'undefined' !== typeof self.Validator.messages.remote && message !== self.Validator.messages.remote ) {
|
225
|
+
$( self.UI.ulError + ' .remote' ).remove();
|
226
|
+
}
|
172
227
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
$( self.ulError + ' .remote' ).remove();
|
177
|
-
}
|
178
|
-
|
179
|
-
self.updtConstraint( { name: 'remote', valid: isConstraintValid }, message );
|
180
|
-
self.manageValidationResult();
|
181
|
-
};
|
228
|
+
self.updtConstraint( { name: 'remote', valid: isConstraintValid }, message );
|
229
|
+
self.manageValidationResult();
|
230
|
+
};
|
182
231
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
232
|
+
// transform string response into object
|
233
|
+
var handleResponse = function ( response ) {
|
234
|
+
if ( 'object' === typeof response ) {
|
235
|
+
return response;
|
236
|
+
}
|
188
237
|
|
189
|
-
|
190
|
-
|
191
|
-
|
238
|
+
try {
|
239
|
+
response = $.parseJSON( response );
|
240
|
+
} catch ( err ) {}
|
192
241
|
|
193
|
-
|
194
|
-
|
242
|
+
return response;
|
243
|
+
}
|
195
244
|
|
196
|
-
|
197
|
-
|
198
|
-
|
245
|
+
var manageErrorMessage = function ( response ) {
|
246
|
+
return 'object' === typeof response && null !== response ? ( 'undefined' !== typeof response.error ? response.error : ( 'undefined' !== typeof response.message ? response.message : null ) ) : null;
|
247
|
+
}
|
199
248
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
249
|
+
$.ajax( $.extend( {}, {
|
250
|
+
url: url
|
251
|
+
, data: data
|
252
|
+
, type: self.options.remoteMethod || 'GET'
|
253
|
+
, success: function ( response ) {
|
254
|
+
response = handleResponse( response );
|
255
|
+
manage( 1 === response || true === response || ( 'object' === typeof response && null !== response && 'undefined' !== typeof response.success ), manageErrorMessage( response )
|
256
|
+
);
|
257
|
+
}
|
258
|
+
, error: function ( response ) {
|
259
|
+
response = handleResponse( response );
|
260
|
+
manage( false, manageErrorMessage( response ) );
|
261
|
+
}
|
262
|
+
}, dataType ) );
|
263
|
+
|
264
|
+
return result;
|
212
265
|
}
|
213
|
-
|
214
|
-
|
215
|
-
return result;
|
266
|
+
, priority: 64
|
267
|
+
}
|
216
268
|
}
|
217
269
|
|
218
270
|
/**
|
219
271
|
* Aliases for checkboxes constraints
|
220
272
|
*/
|
221
|
-
, mincheck: function (
|
222
|
-
|
273
|
+
, mincheck: function () {
|
274
|
+
var that = this;
|
275
|
+
return {
|
276
|
+
validate: function ( obj, val ) { return that.minlength().validate( obj, val ) }
|
277
|
+
, priority: 32
|
278
|
+
}
|
223
279
|
}
|
224
|
-
|
225
|
-
|
226
|
-
return
|
280
|
+
, maxcheck: function () {
|
281
|
+
var that = this;
|
282
|
+
return {
|
283
|
+
validate: function ( obj, val ) { return that.maxlength().validate( obj, val ) }
|
284
|
+
, priority: 32
|
285
|
+
}
|
227
286
|
}
|
228
|
-
|
229
|
-
|
230
|
-
return
|
287
|
+
, rangecheck: function () {
|
288
|
+
var that = this;
|
289
|
+
return {
|
290
|
+
validate: function ( obj, arrayRange ) { return that.rangelength().validate( obj, arrayRange ) }
|
291
|
+
, priority: 32
|
292
|
+
}
|
231
293
|
}
|
232
294
|
}
|
233
295
|
|
@@ -236,9 +298,9 @@
|
|
236
298
|
*/
|
237
299
|
, init: function ( options ) {
|
238
300
|
var customValidators = options.validators
|
239
|
-
, customMessages = options.messages
|
301
|
+
, customMessages = options.messages
|
302
|
+
, key;
|
240
303
|
|
241
|
-
var key;
|
242
304
|
for ( key in customValidators ) {
|
243
305
|
this.addValidator(key, customValidators[ key ]);
|
244
306
|
}
|
@@ -274,7 +336,7 @@
|
|
274
336
|
*
|
275
337
|
* @method addValidator
|
276
338
|
* @param {String} name Validator name. Will automatically bindable through data-name=''
|
277
|
-
* @param {Function} fn Validator function. Must return {
|
339
|
+
* @param {Function} fn Validator function. Must return { validator: fn(), priority: int }
|
278
340
|
*/
|
279
341
|
, addValidator: function ( name, fn ) {
|
280
342
|
this.validators[ name ] = fn;
|
@@ -307,6 +369,147 @@
|
|
307
369
|
}
|
308
370
|
};
|
309
371
|
|
372
|
+
var ParsleyUI = function ( ParsleyInstance ) {
|
373
|
+
this.init( ParsleyInstance );
|
374
|
+
};
|
375
|
+
|
376
|
+
ParsleyUI.prototype = {
|
377
|
+
|
378
|
+
constructor: ParsleyUI
|
379
|
+
|
380
|
+
, init: function ( ParsleyInstance ) {
|
381
|
+
this.ParsleyInstance = ParsleyInstance;
|
382
|
+
this.hash = ParsleyInstance.hash;
|
383
|
+
this.options = this.ParsleyInstance.options;
|
384
|
+
this.errorClassHandler = this.options.errors.classHandler( this.ParsleyInstance.element, this.ParsleyInstance.isRadioOrCheckbox ) || this.ParsleyInstance.$element;
|
385
|
+
this.ulErrorManagement();
|
386
|
+
}
|
387
|
+
|
388
|
+
/**
|
389
|
+
* Manage ul error Container
|
390
|
+
*
|
391
|
+
* @private
|
392
|
+
* @method ulErrorManagement
|
393
|
+
*/
|
394
|
+
, ulErrorManagement: function () {
|
395
|
+
this.ulError = '#' + this.hash;
|
396
|
+
this.ulTemplate = $( this.options.errors.errorsWrapper ).attr( 'id', this.hash ).addClass( 'parsley-error-list' );
|
397
|
+
}
|
398
|
+
|
399
|
+
/**
|
400
|
+
* Remove li / ul error
|
401
|
+
*
|
402
|
+
* @method removeError
|
403
|
+
* @param {String} constraintName Method Name
|
404
|
+
*/
|
405
|
+
, removeError: function ( constraintName ) {
|
406
|
+
var liError = this.ulError + ' .' + constraintName
|
407
|
+
, that = this;
|
408
|
+
|
409
|
+
this.options.animate ? $( liError ).fadeOut( this.options.animateDuration, function () {
|
410
|
+
$( this ).remove();
|
411
|
+
|
412
|
+
if ( that.ulError && $( that.ulError ).children().length === 0 ) {
|
413
|
+
that.removeErrors();
|
414
|
+
} } ) : $( liError ).remove();
|
415
|
+
}
|
416
|
+
|
417
|
+
/**
|
418
|
+
* Add li error
|
419
|
+
*
|
420
|
+
* @method addError
|
421
|
+
* @param {Object} { minlength: "error message for minlength constraint" }
|
422
|
+
*/
|
423
|
+
, addError: function ( error ) {
|
424
|
+
for ( var constraint in error ) {
|
425
|
+
var liTemplate = $( this.options.errors.errorElem ).addClass( constraint );
|
426
|
+
|
427
|
+
$( this.ulError ).append( this.options.animate ? $( liTemplate ).html( error[ constraint ] ).hide().fadeIn( this.options.animateDuration ) : $( liTemplate ).html( error[ constraint ] ) );
|
428
|
+
}
|
429
|
+
}
|
430
|
+
|
431
|
+
/**
|
432
|
+
* Remove all ul / li errors
|
433
|
+
*
|
434
|
+
* @method removeErrors
|
435
|
+
*/
|
436
|
+
, removeErrors: function () {
|
437
|
+
this.options.animate ? $( this.ulError ).fadeOut( this.options.animateDuration, function () { $( this ).remove(); } ) : $( this.ulError ).remove();
|
438
|
+
}
|
439
|
+
|
440
|
+
/**
|
441
|
+
* Remove ul errors and parsley error or success classes
|
442
|
+
*
|
443
|
+
* @method reset
|
444
|
+
*/
|
445
|
+
, reset: function () {
|
446
|
+
this.ParsleyInstance.valid = null;
|
447
|
+
this.removeErrors();
|
448
|
+
this.ParsleyInstance.validatedOnce = false;
|
449
|
+
this.errorClassHandler.removeClass( this.options.successClass ).removeClass( this.options.errorClass );
|
450
|
+
|
451
|
+
for ( var constraint in this.constraints ) {
|
452
|
+
this.constraints[ constraint ].valid = null;
|
453
|
+
}
|
454
|
+
|
455
|
+
return this;
|
456
|
+
}
|
457
|
+
|
458
|
+
/**
|
459
|
+
* Add li / ul errors messages
|
460
|
+
*
|
461
|
+
* @method manageError
|
462
|
+
* @param {Object} constraint
|
463
|
+
*/
|
464
|
+
, manageError: function ( constraint ) {
|
465
|
+
// display ulError container if it has been removed previously (or never shown)
|
466
|
+
if ( !$( this.ulError ).length ) {
|
467
|
+
this.manageErrorContainer();
|
468
|
+
}
|
469
|
+
|
470
|
+
// TODO: refacto properly
|
471
|
+
// if required constraint but field is not null, do not display
|
472
|
+
if ( 'required' === constraint.name && null !== this.ParsleyInstance.getVal() && this.ParsleyInstance.getVal().length > 0 ) {
|
473
|
+
return;
|
474
|
+
// if empty required field and non required constraint fails, do not display
|
475
|
+
} else if ( this.ParsleyInstance.isRequired && 'required' !== constraint.name && ( null === this.ParsleyInstance.getVal() || 0 === this.ParsleyInstance.getVal().length ) ) {
|
476
|
+
this.removeError( constraint.name );
|
477
|
+
return;
|
478
|
+
}
|
479
|
+
|
480
|
+
// TODO: refacto error name w/ proper & readable function
|
481
|
+
var constraintName = constraint.name
|
482
|
+
, liClass = false !== this.options.errorMessage ? 'custom-error-message' : constraintName
|
483
|
+
, liError = {}
|
484
|
+
, message = false !== this.options.errorMessage ? this.options.errorMessage : ( constraint.name === 'type' ?
|
485
|
+
this.ParsleyInstance.Validator.messages[ constraintName ][ constraint.requirements ] : ( 'undefined' === typeof this.ParsleyInstance.Validator.messages[ constraintName ] ?
|
486
|
+
this.ParsleyInstance.Validator.messages.defaultMessage : this.ParsleyInstance.Validator.formatMesssage( this.ParsleyInstance.Validator.messages[ constraintName ], constraint.requirements ) ) );
|
487
|
+
|
488
|
+
// add liError if not shown. Do not add more than once custom errorMessage if exist
|
489
|
+
if ( !$( this.ulError + ' .' + liClass ).length ) {
|
490
|
+
liError[ liClass ] = message;
|
491
|
+
this.addError( liError );
|
492
|
+
}
|
493
|
+
}
|
494
|
+
|
495
|
+
/**
|
496
|
+
* Create ul error container
|
497
|
+
*
|
498
|
+
* @method manageErrorContainer
|
499
|
+
*/
|
500
|
+
, manageErrorContainer: function () {
|
501
|
+
var errorContainer = this.options.errorContainer || this.options.errors.container( this.element, this.ParsleyInstance.isRadioOrCheckbox )
|
502
|
+
, ulTemplate = this.options.animate ? this.ulTemplate.show() : this.ulTemplate;
|
503
|
+
|
504
|
+
if ( 'undefined' !== typeof errorContainer ) {
|
505
|
+
$( errorContainer ).append( ulTemplate );
|
506
|
+
return;
|
507
|
+
}
|
508
|
+
|
509
|
+
!this.ParsleyInstance.isRadioOrCheckbox ? this.ParsleyInstance.$element.after( ulTemplate ) : this.ParsleyInstance.$element.parent().after( ulTemplate );
|
510
|
+
}
|
511
|
+
};
|
512
|
+
|
310
513
|
/**
|
311
514
|
* ParsleyField class manage each form field inside a validated Parsley form.
|
312
515
|
* Returns if field valid or not depending on its value and constraints
|
@@ -317,7 +520,6 @@
|
|
317
520
|
*/
|
318
521
|
var ParsleyField = function ( element, options, type ) {
|
319
522
|
this.options = options;
|
320
|
-
this.Validator = new Validator( options );
|
321
523
|
|
322
524
|
// if type is ParsleyFieldMultiple, just return this. used for clone
|
323
525
|
if ( type === 'ParsleyFieldMultiple' ) {
|
@@ -345,6 +547,7 @@
|
|
345
547
|
this.validatedOnce = false;
|
346
548
|
this.$element = $( element );
|
347
549
|
this.val = this.$element.val();
|
550
|
+
this.Validator = new Validator( this.options );
|
348
551
|
this.isRequired = false;
|
349
552
|
this.constraints = {};
|
350
553
|
|
@@ -352,11 +555,10 @@
|
|
352
555
|
if ( 'undefined' === typeof this.isRadioOrCheckbox ) {
|
353
556
|
this.isRadioOrCheckbox = false;
|
354
557
|
this.hash = this.generateHash();
|
355
|
-
this.errorClassHandler = this.options.errors.classHandler( element, this.isRadioOrCheckbox ) || this.$element;
|
356
558
|
}
|
357
559
|
|
358
560
|
// error ul dom management done only once at init
|
359
|
-
this.
|
561
|
+
this.UI = new ParsleyUI( this );
|
360
562
|
|
361
563
|
// bind some html5 properties
|
362
564
|
this.bindHtml5Constraints();
|
@@ -425,7 +627,7 @@
|
|
425
627
|
for ( var constraint in this.options ) {
|
426
628
|
var addConstraint = {};
|
427
629
|
addConstraint[ constraint ] = this.options[ constraint ];
|
428
|
-
this.addConstraint( addConstraint, true );
|
630
|
+
this.addConstraint( addConstraint, true, false );
|
429
631
|
}
|
430
632
|
}
|
431
633
|
|
@@ -435,7 +637,7 @@
|
|
435
637
|
* @method addConstraint
|
436
638
|
* @param {Object} constraint { name: requirements }
|
437
639
|
*/
|
438
|
-
, addConstraint: function ( constraint, doNotUpdateValidationEvents ) {
|
640
|
+
, addConstraint: function ( constraint, doNotUpdateValidationEvents, sort ) {
|
439
641
|
for ( var name in constraint ) {
|
440
642
|
name = name.toLowerCase();
|
441
643
|
|
@@ -601,7 +803,11 @@
|
|
601
803
|
* @returns {String} val
|
602
804
|
*/
|
603
805
|
, getVal: function () {
|
604
|
-
|
806
|
+
if ('undefined' !== typeof this.$element.domApi()[ 'value' ]) {
|
807
|
+
return this.$element.domApi()[ 'value' ];
|
808
|
+
}
|
809
|
+
|
810
|
+
return this.$element.val();
|
605
811
|
}
|
606
812
|
|
607
813
|
/**
|
@@ -683,9 +889,14 @@
|
|
683
889
|
return null;
|
684
890
|
}
|
685
891
|
|
892
|
+
// do not validate excluded fields
|
893
|
+
if ( this.$element.is( this.options.excluded ) ) {
|
894
|
+
return null;
|
895
|
+
}
|
896
|
+
|
686
897
|
// reset Parsley validation if onFieldValidate returns true, or if field is empty and not required
|
687
898
|
if ( this.options.listeners.onFieldValidate( this.element, this ) || ( '' === val && !this.isRequired ) ) {
|
688
|
-
this.reset();
|
899
|
+
this.UI.reset();
|
689
900
|
return null;
|
690
901
|
}
|
691
902
|
|
@@ -730,23 +941,25 @@
|
|
730
941
|
var valid = null;
|
731
942
|
|
732
943
|
for ( var constraint in this.constraints ) {
|
733
|
-
var result = this.Validator.validators[ this.constraints[ constraint ].name ]( this.val, this.constraints[ constraint ].requirements, this );
|
944
|
+
var result = this.Validator.validators[ this.constraints[ constraint ].name ]().validate( this.val, this.constraints[ constraint ].requirements, this );
|
734
945
|
|
735
946
|
if ( false === result ) {
|
736
947
|
valid = false;
|
737
948
|
this.constraints[ constraint ].valid = valid;
|
738
|
-
this.options.listeners.onFieldError( this.element, this.constraints, this );
|
739
949
|
} else if ( true === result ) {
|
740
950
|
this.constraints[ constraint ].valid = true;
|
741
951
|
valid = false !== valid;
|
742
|
-
|
743
|
-
// if onFieldSuccess returns (bool) false, consider that field si invalid
|
744
|
-
if (false === this.options.listeners.onFieldSuccess( this.element, this.constraints, this )) {
|
745
|
-
valid = false;
|
746
|
-
}
|
747
952
|
}
|
748
953
|
}
|
749
954
|
|
955
|
+
// listeners' ballet
|
956
|
+
if (false === valid) {
|
957
|
+
this.options.listeners.onFieldError( this.element, this.constraints, this );
|
958
|
+
} else if (true === valid && false === this.options.listeners.onFieldSuccess( this.element, this.constraints, this )) {
|
959
|
+
// if onFieldSuccess returns (bool) false, consider that field si invalid
|
960
|
+
valid = false;
|
961
|
+
}
|
962
|
+
|
750
963
|
return valid;
|
751
964
|
}
|
752
965
|
|
@@ -760,14 +973,16 @@
|
|
760
973
|
* @return {Boolean} Is field valid or not
|
761
974
|
*/
|
762
975
|
, manageValidationResult: function () {
|
763
|
-
var valid = null
|
976
|
+
var valid = null
|
977
|
+
, errors = [];
|
764
978
|
|
765
979
|
for ( var constraint in this.constraints ) {
|
766
980
|
if ( false === this.constraints[ constraint ].valid ) {
|
767
|
-
|
981
|
+
errors.push( this.constraints[ constraint ]);
|
982
|
+
// this.UI.manageError( this.constraints[ constraint ] );
|
768
983
|
valid = false;
|
769
984
|
} else if ( true === this.constraints[ constraint ].valid ) {
|
770
|
-
this.removeError( this.constraints[ constraint ].name );
|
985
|
+
this.UI.removeError( this.constraints[ constraint ].name );
|
771
986
|
valid = false !== valid;
|
772
987
|
}
|
773
988
|
}
|
@@ -775,149 +990,38 @@
|
|
775
990
|
this.valid = valid;
|
776
991
|
|
777
992
|
if ( true === this.valid ) {
|
778
|
-
this.removeErrors();
|
779
|
-
this.errorClassHandler.removeClass( this.options.errorClass ).addClass( this.options.successClass );
|
993
|
+
this.UI.removeErrors();
|
994
|
+
this.UI.errorClassHandler.removeClass( this.options.errorClass ).addClass( this.options.successClass );
|
995
|
+
|
780
996
|
return true;
|
781
997
|
} else if ( false === this.valid ) {
|
782
|
-
|
998
|
+
if ( true === this.options.priorityEnabled ) {
|
999
|
+
var maxPriority = 0, constraint;
|
1000
|
+
for ( var i = 0; i < errors.length; i++ )
|
1001
|
+
if ( this.Validator.validators[ errors[ i ].name ]().priority > maxPriority )
|
1002
|
+
constraint = errors[ i ];
|
1003
|
+
this.UI.manageError( constraint );
|
1004
|
+
} else {
|
1005
|
+
for ( var i = 0; i < errors.length; i++ )
|
1006
|
+
this.UI.manageError( errors[ i ] );
|
1007
|
+
}
|
1008
|
+
|
1009
|
+
this.UI.errorClassHandler.removeClass( this.options.successClass ).addClass( this.options.errorClass );
|
783
1010
|
return false;
|
784
1011
|
}
|
785
1012
|
|
786
1013
|
// remove li error, and ul error if no more li inside
|
787
|
-
if ( this.ulError && $( this.ulError ).children().length === 0 ) {
|
788
|
-
this.removeErrors();
|
1014
|
+
if ( this.UI.ulError && $( this.ulError ).children().length === 0 ) {
|
1015
|
+
this.UI.removeErrors();
|
789
1016
|
}
|
790
1017
|
|
791
1018
|
return valid;
|
792
1019
|
}
|
793
1020
|
|
794
|
-
/**
|
795
|
-
* Manage ul error Container
|
796
|
-
*
|
797
|
-
* @private
|
798
|
-
* @method ulErrorManagement
|
799
|
-
*/
|
800
|
-
, ulErrorManagement: function () {
|
801
|
-
this.ulError = '#' + this.hash;
|
802
|
-
this.ulTemplate = $( this.options.errors.errorsWrapper ).attr( 'id', this.hash ).addClass( 'parsley-error-list' );
|
803
|
-
}
|
804
|
-
|
805
|
-
/**
|
806
|
-
* Remove li / ul error
|
807
|
-
*
|
808
|
-
* @method removeError
|
809
|
-
* @param {String} constraintName Method Name
|
810
|
-
*/
|
811
|
-
, removeError: function ( constraintName ) {
|
812
|
-
var liError = this.ulError + ' .' + constraintName
|
813
|
-
, that = this;
|
814
|
-
|
815
|
-
this.options.animate ? $( liError ).fadeOut( this.options.animateDuration, function () {
|
816
|
-
$( this ).remove();
|
817
|
-
|
818
|
-
if ( that.ulError && $( that.ulError ).children().length === 0 ) {
|
819
|
-
that.removeErrors();
|
820
|
-
} } ) : $( liError ).remove();
|
821
|
-
}
|
822
|
-
|
823
|
-
/**
|
824
|
-
* Add li error
|
825
|
-
*
|
826
|
-
* @method addError
|
827
|
-
* @param {Object} { minlength: "error message for minlength constraint" }
|
828
|
-
*/
|
829
|
-
, addError: function ( error ) {
|
830
|
-
for ( var constraint in error ) {
|
831
|
-
var liTemplate = $( this.options.errors.errorElem ).addClass( constraint );
|
832
|
-
|
833
|
-
$( this.ulError ).append( this.options.animate ? $( liTemplate ).html( error[ constraint ] ).hide().fadeIn( this.options.animateDuration ) : $( liTemplate ).html( error[ constraint ] ) );
|
834
|
-
}
|
835
|
-
}
|
836
|
-
|
837
|
-
/**
|
838
|
-
* Remove all ul / li errors
|
839
|
-
*
|
840
|
-
* @method removeErrors
|
841
|
-
*/
|
842
|
-
, removeErrors: function () {
|
843
|
-
this.options.animate ? $( this.ulError ).fadeOut( this.options.animateDuration, function () { $( this ).remove(); } ) : $( this.ulError ).remove();
|
844
|
-
}
|
845
|
-
|
846
|
-
/**
|
847
|
-
* Remove ul errors and parsley error or success classes
|
848
|
-
*
|
849
|
-
* @method reset
|
850
|
-
*/
|
851
|
-
, reset: function () {
|
852
|
-
this.valid = null;
|
853
|
-
this.removeErrors();
|
854
|
-
this.validatedOnce = false;
|
855
|
-
this.errorClassHandler.removeClass( this.options.successClass ).removeClass( this.options.errorClass );
|
856
|
-
|
857
|
-
for ( var constraint in this.constraints ) {
|
858
|
-
this.constraints[ constraint ].valid = null;
|
859
|
-
}
|
860
|
-
|
861
|
-
return this;
|
862
|
-
}
|
863
|
-
|
864
|
-
/**
|
865
|
-
* Add li / ul errors messages
|
866
|
-
*
|
867
|
-
* @method manageError
|
868
|
-
* @param {Object} constraint
|
869
|
-
*/
|
870
|
-
, manageError: function ( constraint ) {
|
871
|
-
// display ulError container if it has been removed previously (or never shown)
|
872
|
-
if ( !$( this.ulError ).length ) {
|
873
|
-
this.manageErrorContainer();
|
874
|
-
}
|
875
|
-
|
876
|
-
// TODO: refacto properly
|
877
|
-
// if required constraint but field is not null, do not display
|
878
|
-
if ( 'required' === constraint.name && null !== this.getVal() && this.getVal().length > 0 ) {
|
879
|
-
return;
|
880
|
-
// if empty required field and non required constraint fails, do not display
|
881
|
-
} else if ( this.isRequired && 'required' !== constraint.name && ( null === this.getVal() || 0 === this.getVal().length ) ) {
|
882
|
-
return;
|
883
|
-
}
|
884
|
-
|
885
|
-
// TODO: refacto error name w/ proper & readable function
|
886
|
-
var constraintName = constraint.name
|
887
|
-
, liClass = false !== this.options.errorMessage ? 'custom-error-message' : constraintName
|
888
|
-
, liError = {}
|
889
|
-
, message = false !== this.options.errorMessage ? this.options.errorMessage : ( constraint.name === 'type' ?
|
890
|
-
this.Validator.messages[ constraintName ][ constraint.requirements ] : ( 'undefined' === typeof this.Validator.messages[ constraintName ] ?
|
891
|
-
this.Validator.messages.defaultMessage : this.Validator.formatMesssage( this.Validator.messages[ constraintName ], constraint.requirements ) ) );
|
892
|
-
|
893
|
-
// add liError if not shown. Do not add more than once custom errorMessage if exist
|
894
|
-
if ( !$( this.ulError + ' .' + liClass ).length ) {
|
895
|
-
liError[ liClass ] = message;
|
896
|
-
this.addError( liError );
|
897
|
-
}
|
898
|
-
}
|
899
|
-
|
900
|
-
/**
|
901
|
-
* Create ul error container
|
902
|
-
*
|
903
|
-
* @method manageErrorContainer
|
904
|
-
*/
|
905
|
-
, manageErrorContainer: function () {
|
906
|
-
var errorContainer = this.options.errorContainer || this.options.errors.container( this.element, this.isRadioOrCheckbox )
|
907
|
-
, ulTemplate = this.options.animate ? this.ulTemplate.show() : this.ulTemplate;
|
908
|
-
|
909
|
-
if ( 'undefined' !== typeof errorContainer ) {
|
910
|
-
$( errorContainer ).append( ulTemplate );
|
911
|
-
return;
|
912
|
-
}
|
913
|
-
|
914
|
-
!this.isRadioOrCheckbox ? this.$element.after( ulTemplate ) : this.$element.parent().after( ulTemplate );
|
915
|
-
}
|
916
|
-
|
917
1021
|
/**
|
918
1022
|
* Add custom listeners
|
919
1023
|
*
|
920
|
-
* @param {Object} { listener: function () {} }, eg {
|
1024
|
+
* @param {Object} { listener: function () {} }, eg { onFormValidate: function ( valid, event, focus ) { ... } }
|
921
1025
|
*/
|
922
1026
|
, addListener: function ( object ) {
|
923
1027
|
for ( var listener in object ) {
|
@@ -933,7 +1037,8 @@
|
|
933
1037
|
*/
|
934
1038
|
, destroy: function () {
|
935
1039
|
this.$element.removeClass( 'parsley-validated' );
|
936
|
-
this.reset()
|
1040
|
+
this.UI.reset();
|
1041
|
+
this.$element.off( '.' + this.type ).removeData( this.type );
|
937
1042
|
}
|
938
1043
|
};
|
939
1044
|
|
@@ -969,7 +1074,7 @@
|
|
969
1074
|
this.$element = $( element );
|
970
1075
|
this.group = options.group || false;
|
971
1076
|
this.hash = this.getName();
|
972
|
-
this.siblings = this.group ? '[
|
1077
|
+
this.siblings = this.group ? '[parsley-group="' + this.group + '"]' : 'input[name="' + this.$element.attr( 'name' ) + '"]';
|
973
1078
|
this.isRadioOrCheckbox = true;
|
974
1079
|
this.isRadio = this.$element.is( 'input[type=radio]' );
|
975
1080
|
this.isCheckbox = this.$element.is( 'input[type=checkbox]' );
|
@@ -1006,7 +1111,7 @@
|
|
1006
1111
|
}
|
1007
1112
|
|
1008
1113
|
if ( 'undefined' === typeof this.$element.attr( 'name' ) ) {
|
1009
|
-
throw "A radio / checkbox input must have a
|
1114
|
+
throw "A radio / checkbox input must have a parsley-group attribute or a name to be Parsley validated !";
|
1010
1115
|
}
|
1011
1116
|
|
1012
1117
|
return 'parsley-' + this.$element.attr( 'name' ).replace( /(:|\.|\[|\])/g, '' );
|
@@ -1097,7 +1202,7 @@
|
|
1097
1202
|
/**
|
1098
1203
|
* Add custom listeners
|
1099
1204
|
*
|
1100
|
-
* @param {Object} { listener: function () {} }, eg {
|
1205
|
+
* @param {Object} { listener: function () {} }, eg { onFormValidate: function ( valid, event, focus ) { ... } }
|
1101
1206
|
*/
|
1102
1207
|
, addListener: function ( object ) {
|
1103
1208
|
for ( var listener in object ) {
|
@@ -1152,7 +1257,7 @@
|
|
1152
1257
|
|
1153
1258
|
/**
|
1154
1259
|
* Process each form field validation
|
1155
|
-
* Display errors, call custom
|
1260
|
+
* Display errors, call custom onFormValidate() function
|
1156
1261
|
*
|
1157
1262
|
* @method validate
|
1158
1263
|
* @param {Object} event jQuery Event
|
@@ -1174,13 +1279,29 @@
|
|
1174
1279
|
|
1175
1280
|
// form is invalid, focus an error field depending on focus policy
|
1176
1281
|
if ( this.focusedField && !valid ) {
|
1177
|
-
|
1282
|
+
// Scroll smoothly
|
1283
|
+
if ( this.options.scrollDuration > 0 ) {
|
1284
|
+
var that = this,
|
1285
|
+
top = this.focusedField.offset().top - $( window ).height() / 2; // Center the window on the field
|
1286
|
+
|
1287
|
+
$( 'html, body' ).animate( {
|
1288
|
+
scrollTop: top
|
1289
|
+
},
|
1290
|
+
this.options.scrollDuration,
|
1291
|
+
function () {
|
1292
|
+
that.focusedField.focus();
|
1293
|
+
}
|
1294
|
+
);
|
1295
|
+
// Just focus on the field and let the browser do the rest
|
1296
|
+
} else {
|
1297
|
+
this.focusedField.focus();
|
1298
|
+
}
|
1178
1299
|
}
|
1179
1300
|
|
1180
|
-
// if
|
1181
|
-
var
|
1182
|
-
if ('undefined' !== typeof
|
1183
|
-
return
|
1301
|
+
// if onFormValidate returns (bool) false, form won't be submitted, even if valid
|
1302
|
+
var onFormValidate = this.options.listeners.onFormValidate( valid, event, this );
|
1303
|
+
if ('undefined' !== typeof onFormValidate) {
|
1304
|
+
return onFormValidate;
|
1184
1305
|
}
|
1185
1306
|
|
1186
1307
|
return valid;
|
@@ -1227,7 +1348,7 @@
|
|
1227
1348
|
*/
|
1228
1349
|
, reset: function () {
|
1229
1350
|
for ( var item = 0; item < this.items.length; item++ ) {
|
1230
|
-
this.items[ item ].reset();
|
1351
|
+
this.items[ item ].UI.reset();
|
1231
1352
|
}
|
1232
1353
|
}
|
1233
1354
|
};
|
@@ -1243,7 +1364,7 @@
|
|
1243
1364
|
* @return {Mixed} public class method return
|
1244
1365
|
*/
|
1245
1366
|
$.fn.parsley = function ( option, fn ) {
|
1246
|
-
var options = $.extend( true, {}, $.fn.parsley.defaults, 'undefined' !== typeof window.ParsleyConfig ? window.ParsleyConfig : {}, option, this.
|
1367
|
+
var options = $.extend( true, {}, $.fn.parsley.defaults, 'undefined' !== typeof window.ParsleyConfig ? window.ParsleyConfig : {}, option, this.domApi() )
|
1247
1368
|
, newInstance = null;
|
1248
1369
|
|
1249
1370
|
function bind ( self, type ) {
|
@@ -1279,12 +1400,12 @@
|
|
1279
1400
|
}
|
1280
1401
|
|
1281
1402
|
// if a form elem is given, bind all its input children
|
1282
|
-
if ( $( this ).is( 'form' ) ||
|
1403
|
+
if ( $( this ).is( 'form' ) || 'undefined' !== typeof $( this ).domApi()[ 'bind' ] ) {
|
1283
1404
|
newInstance = bind ( $( this ), 'parsleyForm' );
|
1284
1405
|
|
1285
1406
|
// if it is a Parsley supported single element, bind it too, except inputs type hidden
|
1286
1407
|
// add here a return instance, cuz' we could call public methods on single elems with data[ option ]() above
|
1287
|
-
} else if ( $( this ).is( options.inputs )
|
1408
|
+
} else if ( $( this ).is( options.inputs ) ) {
|
1288
1409
|
newInstance = bind( $( this ), !$( this ).is( 'input[type=radio], input[type=checkbox]' ) ? 'parsleyField' : 'parsleyFieldMultiple' );
|
1289
1410
|
}
|
1290
1411
|
|
@@ -1293,6 +1414,67 @@
|
|
1293
1414
|
|
1294
1415
|
$.fn.parsley.Constructor = ParsleyForm;
|
1295
1416
|
|
1417
|
+
/* PARSLEY auto-binding
|
1418
|
+
* =================================================== */
|
1419
|
+
$( window ).on( 'load', function () {
|
1420
|
+
$( '[parsley-validate]' ).each( function () {
|
1421
|
+
$( this ).parsley();
|
1422
|
+
} );
|
1423
|
+
} );
|
1424
|
+
|
1425
|
+
/* PARSLEY DOM API
|
1426
|
+
* =================================================== */
|
1427
|
+
$.fn.domApi = function () {
|
1428
|
+
var obj = {};
|
1429
|
+
$.each( this[0].attributes, function () {
|
1430
|
+
if ( this.specified && /^parsley-/i.test( this.name ) ) {
|
1431
|
+
obj[ camelize( this.name.replace( 'parsley-', '' ) ) ] = deserializeValue( this.value );
|
1432
|
+
}
|
1433
|
+
} );
|
1434
|
+
|
1435
|
+
return obj;
|
1436
|
+
};
|
1437
|
+
|
1438
|
+
// Zepto deserializeValue function
|
1439
|
+
// "true" => true
|
1440
|
+
// "false" => false
|
1441
|
+
// "null" => null
|
1442
|
+
// "42" => 42
|
1443
|
+
// "42.5" => 42.5
|
1444
|
+
// JSON => parse if valid
|
1445
|
+
// String => self
|
1446
|
+
var deserializeValue = function( value ) {
|
1447
|
+
var num
|
1448
|
+
try {
|
1449
|
+
return value ?
|
1450
|
+
value == "true" ||
|
1451
|
+
( value == "false" ? false :
|
1452
|
+
value == "null" ? null :
|
1453
|
+
!isNaN( num = Number( value ) ) ? num :
|
1454
|
+
/^[\[\{]/.test( value ) ? $.parseJSON( value ) :
|
1455
|
+
value )
|
1456
|
+
: value;
|
1457
|
+
} catch ( e ) {
|
1458
|
+
return value;
|
1459
|
+
}
|
1460
|
+
};
|
1461
|
+
|
1462
|
+
// Zepto camelize function
|
1463
|
+
var camelize = function ( str ) {
|
1464
|
+
return str.replace( /-+(.)?/g, function ( match, chr ) {
|
1465
|
+
return chr ? chr.toUpperCase() : '';
|
1466
|
+
} )
|
1467
|
+
};
|
1468
|
+
|
1469
|
+
// Zepto dasherize function
|
1470
|
+
var dasherize = function ( str ) {
|
1471
|
+
return str.replace( /::/g, '/' )
|
1472
|
+
.replace( /([A-Z]+)([A-Z][a-z])/g, '$1_$2' )
|
1473
|
+
.replace( /([a-z\d])([A-Z])/g, '$1_$2' )
|
1474
|
+
.replace( /_/g, '-' )
|
1475
|
+
.toLowerCase()
|
1476
|
+
};
|
1477
|
+
|
1296
1478
|
/**
|
1297
1479
|
* Parsley plugin configuration
|
1298
1480
|
*
|
@@ -1301,11 +1483,13 @@
|
|
1301
1483
|
*/
|
1302
1484
|
$.fn.parsley.defaults = {
|
1303
1485
|
// basic data-api overridable properties here..
|
1304
|
-
inputs: 'input, textarea, select'
|
1486
|
+
inputs: 'input, textarea, select' // Default supported inputs.
|
1305
1487
|
, excluded: 'input[type=hidden], input[type=file], :disabled' // Do not validate input[type=hidden] & :disabled.
|
1488
|
+
, priorityEnabled: true // Will display only one error at the time depending on validators priorities
|
1306
1489
|
, trigger: false // $.Event() that will trigger validation. eg: keyup, change..
|
1307
1490
|
, animate: true // fade in / fade out error messages
|
1308
1491
|
, animateDuration: 300 // fadein/fadout ms time
|
1492
|
+
, scrollDuration: 500 // Duration in ms time of the window scroll when focusing on invalid field (0 = no scroll)
|
1309
1493
|
, focus: 'first' // 'fist'|'last'|'none' which error field would have focus first on form validation
|
1310
1494
|
, validationMinlength: 3 // If trigger validation specified, only if value.length > validationMinlength
|
1311
1495
|
, successClass: 'parsley-success' // Class name on each valid input
|
@@ -1325,19 +1509,11 @@
|
|
1325
1509
|
}
|
1326
1510
|
, listeners: {
|
1327
1511
|
onFieldValidate: function ( elem, ParsleyForm ) { return false; } // Executed on validation. Return true to ignore field validation
|
1328
|
-
,
|
1512
|
+
, onFormValidate: function ( isFormValid, event, ParsleyForm ) {} // Executed once on form validation. Return (bool) false to block submit, even if valid
|
1329
1513
|
, onFieldError: function ( elem, constraints, ParsleyField ) {} // Executed when a field is detected as invalid
|
1330
1514
|
, onFieldSuccess: function ( elem, constraints, ParsleyField ) {} // Executed when a field passes validation
|
1331
1515
|
}
|
1332
1516
|
};
|
1333
1517
|
|
1334
|
-
/* PARSLEY auto-bind DATA-API + Global config retrieving
|
1335
|
-
* =================================================== */
|
1336
|
-
$( window ).on( 'load', function () {
|
1337
|
-
$( '[data-validate="parsley"]' ).each( function () {
|
1338
|
-
$( this ).parsley();
|
1339
|
-
} );
|
1340
|
-
} );
|
1341
|
-
|
1342
1518
|
// This plugin works with jQuery or Zepto (with data extension built for Zepto.)
|
1343
|
-
}(window.jQuery || window.Zepto);
|
1519
|
+
} ( window.jQuery || window.Zepto );
|