parsley-rails 1.1.10.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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -0
- data/Rakefile +1 -0
- data/lib/parsley-rails.rb +8 -0
- data/lib/parsley-rails/version.rb +5 -0
- data/parsley-rails.gemspec +17 -0
- data/update.sh +31 -0
- data/vendor/assets/javascripts/parsley.extend.js +53 -0
- data/vendor/assets/javascripts/parsley.i18n.cy.js +39 -0
- data/vendor/assets/javascripts/parsley.i18n.de.js +37 -0
- data/vendor/assets/javascripts/parsley.i18n.es.js +37 -0
- data/vendor/assets/javascripts/parsley.i18n.fi.js +40 -0
- data/vendor/assets/javascripts/parsley.i18n.fr.js +40 -0
- data/vendor/assets/javascripts/parsley.i18n.id.js +40 -0
- data/vendor/assets/javascripts/parsley.i18n.is.js +32 -0
- data/vendor/assets/javascripts/parsley.i18n.nl.js +37 -0
- data/vendor/assets/javascripts/parsley.i18n.no.js +32 -0
- data/vendor/assets/javascripts/parsley.i18n.pl.js +40 -0
- data/vendor/assets/javascripts/parsley.i18n.pt_br.js +32 -0
- data/vendor/assets/javascripts/parsley.i18n.ru.js +35 -0
- data/vendor/assets/javascripts/parsley.i18n.vn.js +36 -0
- data/vendor/assets/javascripts/parsley.js +1276 -0
- metadata +69 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
2
|
+
|
3
|
+
(function ($) {
|
4
|
+
window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, {
|
5
|
+
messages: {
|
6
|
+
// parsley //////////////////////////////////////
|
7
|
+
defaultMessage: "Þetta gildi virðist vera ógilt."
|
8
|
+
, type: {
|
9
|
+
email: "Þetta ætti að vera gilt netfang."
|
10
|
+
, url: "Þetta ætti að vera gild vefslóð."
|
11
|
+
, urlstrict: "Þetta ætti að vera gild vefslóð."
|
12
|
+
, number: "Þetta ætti að vera gild tala."
|
13
|
+
, digits: "Þetta ætti að innihalda tölur."
|
14
|
+
, dateIso: "Þetta ætti að vera gild dagsetning (ÁÁÁÁ-MM-DD)."
|
15
|
+
, alphanum: "Þetta ætti að vera innihalda tölur og bókstafi."
|
16
|
+
}
|
17
|
+
, notnull: "Þetta gildi ætti ekki að vera autt."
|
18
|
+
, notblank: "Þetta gildi ætti ekki að vera tómt."
|
19
|
+
, required: "Þetta gildi er nauðsynlegt að fylla út."
|
20
|
+
, regexp: "Þetta gildi virðist vera ógilt."
|
21
|
+
, min: "Þetta gildi ætti að vera stærra en %s."
|
22
|
+
, max: "Þetta gildi ætti að vera minna en %s."
|
23
|
+
, range: "Þetta gildi ætti að vera milli %s og %s."
|
24
|
+
, minlength: "Þetta gildi er of stutt. Það ætti að innihalda %s stafi eða fleiri."
|
25
|
+
, maxlength: "Þetta gildi er of langt. Það ætti að innihalda %s stafi eða færri."
|
26
|
+
, rangelength: "Þetta gildi er ógilt. Það ætti að vera %s-%s stafir að lengd."
|
27
|
+
, equalto: "Þetta gildi ætti að vera eins."
|
28
|
+
|
29
|
+
// parsley.extend ///////////////////////////////
|
30
|
+
}
|
31
|
+
});
|
32
|
+
}(window.jQuery || window.Zepto));
|
@@ -0,0 +1,37 @@
|
|
1
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
2
|
+
|
3
|
+
(function ($) {
|
4
|
+
window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, {
|
5
|
+
messages: {
|
6
|
+
// parsley //////////////////////////////////////
|
7
|
+
defaultMessage: "Deze waarde lijkt onjuist."
|
8
|
+
, type: {
|
9
|
+
email: "Dit lijkt geen geldig e-mail adres te zijn."
|
10
|
+
, url: "Dit lijkt geen geldige URL te zijn."
|
11
|
+
, urlstrict: "Dit is geen geldige URL."
|
12
|
+
, number: "Deze waarde moet een nummer zijn."
|
13
|
+
, digits: "Deze waarde moet numeriek zijn."
|
14
|
+
, dateIso: "Deze waarde moet een datum in het volgende formaat zijn: (YYYY-MM-DD)."
|
15
|
+
, alphanum: "Deze waarde moet alfanumeriek zijn."
|
16
|
+
}
|
17
|
+
, notnull: "Deze waarde mag niet leeg zijn."
|
18
|
+
, notblank: "Deze waarde mag niet leeg zijn."
|
19
|
+
, required: "Dit veld is verplicht"
|
20
|
+
, regexp: "Deze waarde lijkt onjuist te zijn."
|
21
|
+
, min: "Deze waarde mag niet lager zijn dan %s."
|
22
|
+
, max: "Deze waarde mag niet groter zijn dan %s."
|
23
|
+
, range: "Deze waarde moet tussen %s en %s liggen."
|
24
|
+
, minlength: "Deze tekst is te kort. Deze moet uit minimaal %s karakters bestaan."
|
25
|
+
, maxlength: "Deze waarde is te lang. Deze mag maximaal %s karakters lang zijn."
|
26
|
+
, rangelength: "Deze waarde moet tussen %s en %s karakters lang zijn."
|
27
|
+
, equalto: "Deze waardes moeten identiek zijn."
|
28
|
+
|
29
|
+
// parsley.extend ///////////////////////////////
|
30
|
+
, minwords: "Deze waarde moet minstens %s woorden bevatten."
|
31
|
+
, maxwords: "Deze waarde mag maximaal %s woorden bevatten."
|
32
|
+
, rangewords: "Deze waarde moet tussen de %s en %s woorden bevatten."
|
33
|
+
, greaterthan: "Deze waarde moet groter dan %s zijn."
|
34
|
+
, lessthan: "Deze waarde moet kleiner dan %s zijn."
|
35
|
+
}
|
36
|
+
});
|
37
|
+
}(window.jQuery || window.Zepto));
|
@@ -0,0 +1,32 @@
|
|
1
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
2
|
+
|
3
|
+
(function ($) {
|
4
|
+
window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, {
|
5
|
+
messages: {
|
6
|
+
// parsley //////////////////////////////////////
|
7
|
+
defaultMessage: "Denne verdien er ikke gyldig."
|
8
|
+
, type: {
|
9
|
+
email: "Denne verdien må være en gyldig e-post."
|
10
|
+
, url: "Denne verdien må være en gyldig nettadresse."
|
11
|
+
, urlstrict: "Denne verdien må være en gyldig nettadresse."
|
12
|
+
, number: "Denne verdien må være et gyldig tall."
|
13
|
+
, digits: "Denne verdien må være tall."
|
14
|
+
, dateIso: "Denne verdien må være en gyldig dato (YYYY-MM-DD)."
|
15
|
+
, alphanum: "Denne verdien må være alfanumerisk(tall eller bokstaver)."
|
16
|
+
}
|
17
|
+
, notnull: "Denne verdien kan ikke være tom."
|
18
|
+
, notblank: "Denne verdien kan ikke være blank."
|
19
|
+
, required: "Dette feltet er obligatorisk."
|
20
|
+
, regexp: "Denne verdien er ikke gyldig."
|
21
|
+
, min: "Denne verdien må være større enn %s."
|
22
|
+
, max: "Denne verdien må være mindre enn %s."
|
23
|
+
, range: "Denne verdien må være mellom %s og %s."
|
24
|
+
, minlength: "Denne verdien er for kort. Den må være minst %s tegn."
|
25
|
+
, maxlength: "Denne verdien er for lang. Den må ikke være lenger enn %s tegn."
|
26
|
+
, rangelength: "Denne verdien har feil lengde. Lengden må være mellom %s og %s tegn."
|
27
|
+
, equalto: "Denne verdien må være lik."
|
28
|
+
|
29
|
+
// parsley.extend ///////////////////////////////
|
30
|
+
}
|
31
|
+
});
|
32
|
+
}(window.jQuery || window.Zepto));
|
@@ -0,0 +1,40 @@
|
|
1
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
2
|
+
|
3
|
+
(function ($) {
|
4
|
+
window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, {
|
5
|
+
messages: {
|
6
|
+
// parsley ////////PL/by/Tymek///////////////////
|
7
|
+
defaultMessage: "Wartość wygląda na nieprawidłową"
|
8
|
+
, type: {
|
9
|
+
email: "Wpisz poprawny adres e-mail"
|
10
|
+
, url: "Wpisz poprawny adres URL"
|
11
|
+
, urlstrict: "Wpisz poprawny adres URL"
|
12
|
+
, number: "Wpisz poprawną liczbę"
|
13
|
+
, digits: "Dozwolone jedynie cyfry"
|
14
|
+
, dateIso: "Wpisz poprawny format daty (RRRR-MM-DD)"
|
15
|
+
, alphanum: "Dozwolone jedynie znaki alfanumeryczne"
|
16
|
+
}
|
17
|
+
, notnull: "Wartość musi być różna od zera"
|
18
|
+
, notblank: "Pole nie może pozostać puste"
|
19
|
+
, required: "Pole wymagane"
|
20
|
+
, regexp: "Wartość wygląda na nieprawidłową"
|
21
|
+
, min: "Wartość powinna być większa od %s"
|
22
|
+
, max: "Wartość powinna być mniejsza od %s"
|
23
|
+
, range: "Wartość powinna być większa od %s i mniejsza od %s"
|
24
|
+
, minlength: "Ilość znaków powinna wynosić %s lub więcej"
|
25
|
+
, maxlength: "Ilość znaków powinna wynosić %s lub mniej"
|
26
|
+
, rangelength: "Ilość znaków powinna wynosić od %s do %s"
|
27
|
+
, mincheck: "Wybierz %s lub więcej opcji"
|
28
|
+
, maxcheck: "Wybierz %s lub mniej opcji"
|
29
|
+
, rangecheck: "Wybierz od %s do %s opcji"
|
30
|
+
, equalto: "Wartość musi być identyczna"
|
31
|
+
|
32
|
+
// parsley.extend ///////////////////////////////
|
33
|
+
, minwords: "Wpisz więcej niż %s wyrazów"
|
34
|
+
, maxwords: "Wartość nie może przekraczać %s wyrazów"
|
35
|
+
, rangewords: "Wartość musi zawierać od %s do %s wyrazów"
|
36
|
+
, greaterthan: "Wartość musi być większa niż %s"
|
37
|
+
, lessthan: "Wartość musi być mniejsza niż %s"
|
38
|
+
}
|
39
|
+
});
|
40
|
+
}(window.jQuery || window.Zepto));
|
@@ -0,0 +1,32 @@
|
|
1
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
2
|
+
|
3
|
+
(function ($) {
|
4
|
+
window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, {
|
5
|
+
messages: {
|
6
|
+
defaultMessage: "Este valor parece estar inválido."
|
7
|
+
, type: {
|
8
|
+
email: "Este valor deve ser um e-mail válido."
|
9
|
+
, url: "Este valor deve ser uma URL válida."
|
10
|
+
, urlstrict: "Este valor deve ser uma URL válida."
|
11
|
+
, number: "Este valor deve ser um número válido."
|
12
|
+
, digits: "Este valor deve ser um dígito válido."
|
13
|
+
, dateIso: "Este valor deve ser uma data válida (YYYY-MM-DD)."
|
14
|
+
, alphanum: "Este valor deve ser alfanumérico."
|
15
|
+
}
|
16
|
+
, notnull: "Este valor não deve ser nulo."
|
17
|
+
, notblank: "Este valor não deve ser branco."
|
18
|
+
, required: "Este valor é obrigatório."
|
19
|
+
, regexp: "Este valor parece estar inválido."
|
20
|
+
, min: "Este valor deve ser maior que %s."
|
21
|
+
, max: "Este valor deve ser menor que %s."
|
22
|
+
, range: "Este valor deve estar entre %s e %s."
|
23
|
+
, minlength: "Este valor é muito pequeno. Ele deve ter %s caracteres ou mais."
|
24
|
+
, maxlength: "Este valor é muito grande. Ele deve ter %s caracteres ou menos."
|
25
|
+
, rangelength: "O tamanho deste valor é inválido. Ele deve possuir entre %s e %s caracteres."
|
26
|
+
, equalto: "Este valor deve ser o mesmo."
|
27
|
+
, minwords: "Este valor deve possuir no mínimo %s palavras."
|
28
|
+
, maxwords: "Este valor deve possuir no máximo %s palavras."
|
29
|
+
, rangewords: "Este valor deve possuir entre %s e %s palavras."
|
30
|
+
}
|
31
|
+
});
|
32
|
+
}(window.jQuery || window.Zepto));
|
@@ -0,0 +1,35 @@
|
|
1
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
2
|
+
|
3
|
+
(function ($) {
|
4
|
+
window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, {
|
5
|
+
messages: {
|
6
|
+
// parsley //////////////////////////////////////
|
7
|
+
defaultMessage: "Поле заполнено некорректно."
|
8
|
+
, type: {
|
9
|
+
email: "Поле должно быть адресом электронной почты."
|
10
|
+
, url: "Поле должно быть ссылкой на сайт."
|
11
|
+
, urlstrict: "Поле должно быть ссылкой на сайт."
|
12
|
+
, number: "Поле должно быть числом."
|
13
|
+
, digits: "Поле должно содержать только цифры."
|
14
|
+
, dateIso: "Поле должно быть датой в формате (ГГГГ-ММ-ДД)."
|
15
|
+
, alphanum: "Поле должно содержать только цифры и буквы"
|
16
|
+
}
|
17
|
+
, notnull: "Поле должно быть не нулевым."
|
18
|
+
, notblank: "Поле не должно быть пустым."
|
19
|
+
, required: "Поле обязательно для заполнения."
|
20
|
+
, regexp: "Поле заполнено некорректно."
|
21
|
+
, min: "Значение поля должно быть больше %s."
|
22
|
+
, max: "Значение поля должно быть меньше %s."
|
23
|
+
, range: "Значение поля должно быть между %s и %s."
|
24
|
+
, minlength: "В поле должно быть минимум %s символов(а)."
|
25
|
+
, maxlength: "В поле должно быть не больше %s символов(а)."
|
26
|
+
, rangelength: "В поле должно быть от %s до %s символов(а)."
|
27
|
+
, mincheck: "Необходимо выбрать не менее %s пунктов(а)."
|
28
|
+
, maxcheck: "Необходимо выбрать не более %s пунктов(а)."
|
29
|
+
, rangecheck: "Необходимо выбрать от %s до %s пунктов."
|
30
|
+
, equalto: "Значения полей должны быть одинаковыми."
|
31
|
+
|
32
|
+
// parsley.extend ///////////////////////////////
|
33
|
+
}
|
34
|
+
});
|
35
|
+
}(window.jQuery || window.Zepto));
|
@@ -0,0 +1,36 @@
|
|
1
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
2
|
+
|
3
|
+
(function ($) {
|
4
|
+
window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, {
|
5
|
+
messages: {
|
6
|
+
// parsley //////////////////////////////////////
|
7
|
+
defaultMessage: "Thông tin này không hợp lệ."
|
8
|
+
, type: {
|
9
|
+
email: "Email không hợp lệ."
|
10
|
+
, url: "Url không hợp lệ."
|
11
|
+
, urlstrict: "Yêu cầu nhập địa chỉ url."
|
12
|
+
, number: "Yêu cầu nhập giá trị kiểu số."
|
13
|
+
, digits: "Yêu cầu nhập vào các chữ số."
|
14
|
+
, dateIso: "Yêu cầu nhập ngày tháng theo chuẩn sau (YYYY-MM-DD)."
|
15
|
+
, alphanum: "Yêu cầu nhập chữ cái hoặc chữ số."
|
16
|
+
}
|
17
|
+
, notnull: "Thông tin này chưa nhập."
|
18
|
+
, notblank: "Thông tin này không được để trống."
|
19
|
+
, required: "Thông tin này là bắt buộc."
|
20
|
+
, regexp: "Thông tin này không hợp lệ."
|
21
|
+
, min: "Giá trị này phải lớn hơn %s."
|
22
|
+
, max: "Giá trị này phải nhỏ hơn %s."
|
23
|
+
, range: "Giá trị này phải nằm trong khoảng từ %s đến %s."
|
24
|
+
, minlength: "Chuỗi nhập vào quá ngắn. Yêu cầu tối thiểu %s ký tự."
|
25
|
+
, maxlength: "Chuỗi nhập vào quá dài. Yêu cầu tối đa %s ký tự."
|
26
|
+
, rangelength: "Chuỗi nhập vào không hợp lệ. Yêu cầu độ dài trong khoảng từ %s đến %s ký tự."
|
27
|
+
, mincheck: "Không được chọn ít hơn %s lựa chọn."
|
28
|
+
, maxcheck: "Không được chọn nhiều hơn %s lựa chọn."
|
29
|
+
, rangecheck: "Phải chọn trong khoảng từ %s đến %s lựa chọn."
|
30
|
+
, equalto: "Giá trị phải trùng khớp."
|
31
|
+
|
32
|
+
// parsley.extend ///////////////////////////////
|
33
|
+
}
|
34
|
+
});
|
35
|
+
}(window.jQuery || window.Zepto));
|
36
|
+
|
@@ -0,0 +1,1276 @@
|
|
1
|
+
/*
|
2
|
+
* Parsley.js allows you to verify your form inputs frontend side, without writing a line of javascript. Or so..
|
3
|
+
*
|
4
|
+
* Author: Guillaume Potier - @guillaumepotier
|
5
|
+
*/
|
6
|
+
|
7
|
+
!function ($) {
|
8
|
+
|
9
|
+
'use strict';
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Validator class stores all constraints functions and associated messages.
|
13
|
+
* Provides public interface to add, remove or modify them
|
14
|
+
*
|
15
|
+
* @class Validator
|
16
|
+
* @constructor
|
17
|
+
*/
|
18
|
+
var Validator = function ( options ) {
|
19
|
+
/**
|
20
|
+
* Error messages
|
21
|
+
*
|
22
|
+
* @property messages
|
23
|
+
* @type {Object}
|
24
|
+
*/
|
25
|
+
this.messages = {
|
26
|
+
defaultMessage: "This value seems to be invalid."
|
27
|
+
, type: {
|
28
|
+
email: "This value should be a valid email."
|
29
|
+
, url: "This value should be a valid url."
|
30
|
+
, urlstrict: "This value should be a valid url."
|
31
|
+
, number: "This value should be a valid number."
|
32
|
+
, digits: "This value should be digits."
|
33
|
+
, dateIso: "This value should be a valid date (YYYY-MM-DD)."
|
34
|
+
, alphanum: "This value should be alphanumeric."
|
35
|
+
}
|
36
|
+
, notnull: "This value should not be null."
|
37
|
+
, notblank: "This value should not be blank."
|
38
|
+
, required: "This value is required."
|
39
|
+
, regexp: "This value seems to be invalid."
|
40
|
+
, min: "This value should be greater than %s."
|
41
|
+
, max: "This value should be lower than %s."
|
42
|
+
, range: "This value should be between %s and %s."
|
43
|
+
, minlength: "This value is too short. It should have %s characters or more."
|
44
|
+
, maxlength: "This value is too long. It should have %s characters or less."
|
45
|
+
, rangelength: "This value length is invalid. It should be between %s and %s characters long."
|
46
|
+
, mincheck: "You must select at least %s choices."
|
47
|
+
, maxcheck: "You must select %s choices or less."
|
48
|
+
, rangecheck: "You must select between %s and %s choices."
|
49
|
+
, equalto: "This value should be the same."
|
50
|
+
},
|
51
|
+
|
52
|
+
this.init( options );
|
53
|
+
};
|
54
|
+
|
55
|
+
Validator.prototype = {
|
56
|
+
|
57
|
+
constructor: Validator
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Validator list. Built-in validators functions
|
61
|
+
*
|
62
|
+
* @property validators
|
63
|
+
* @type {Object}
|
64
|
+
*/
|
65
|
+
, validators: {
|
66
|
+
notnull: function ( val ) {
|
67
|
+
return val.length > 0;
|
68
|
+
}
|
69
|
+
|
70
|
+
, notblank: function ( val ) {
|
71
|
+
return null !== val && '' !== val.replace( /^\s+/g, '' ).replace( /\s+$/g, '' );
|
72
|
+
}
|
73
|
+
|
74
|
+
// Works on all inputs. val is object for checkboxes
|
75
|
+
, required: function ( val ) {
|
76
|
+
|
77
|
+
// for checkboxes and select multiples. Check there is at least one required value
|
78
|
+
if ( 'object' === typeof val ) {
|
79
|
+
for ( var i in val ) {
|
80
|
+
if ( this.required( val[ i ] ) ) {
|
81
|
+
return true;
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
return false;
|
86
|
+
}
|
87
|
+
|
88
|
+
return this.notnull( val ) && this.notblank( val );
|
89
|
+
}
|
90
|
+
|
91
|
+
, type: function ( val, type ) {
|
92
|
+
var regExp;
|
93
|
+
|
94
|
+
switch ( type ) {
|
95
|
+
case 'number':
|
96
|
+
regExp = /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/;
|
97
|
+
break;
|
98
|
+
case 'digits':
|
99
|
+
regExp = /^\d+$/;
|
100
|
+
break;
|
101
|
+
case 'alphanum':
|
102
|
+
regExp = /^\w+$/;
|
103
|
+
break;
|
104
|
+
case 'email':
|
105
|
+
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])))$/i;
|
106
|
+
break;
|
107
|
+
case 'url':
|
108
|
+
val = new RegExp( '(https?|s?ftp|git)', 'i' ).test( val ) ? val : 'http://' + val;
|
109
|
+
/* falls through */
|
110
|
+
case 'urlstrict':
|
111
|
+
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;
|
112
|
+
break;
|
113
|
+
case 'dateIso':
|
114
|
+
regExp = /^(\d{4})\D?(0[1-9]|1[0-2])\D?([12]\d|0[1-9]|3[01])$/;
|
115
|
+
break;
|
116
|
+
default:
|
117
|
+
return false;
|
118
|
+
}
|
119
|
+
|
120
|
+
// test regExp if not null
|
121
|
+
return '' !== val ? regExp.test( val ) : false;
|
122
|
+
}
|
123
|
+
|
124
|
+
, regexp: function ( val, regExp ) {
|
125
|
+
return new RegExp( regExp, 'i' ).test( val );
|
126
|
+
}
|
127
|
+
|
128
|
+
, minlength: function ( val, min ) {
|
129
|
+
return val.length >= min;
|
130
|
+
}
|
131
|
+
|
132
|
+
, maxlength: function ( val, max ) {
|
133
|
+
return val.length <= max;
|
134
|
+
}
|
135
|
+
|
136
|
+
, rangelength: function ( val, arrayRange ) {
|
137
|
+
return this.minlength( val, arrayRange[ 0 ] ) && this.maxlength( val, arrayRange[ 1 ] );
|
138
|
+
}
|
139
|
+
|
140
|
+
, min: function ( val, min ) {
|
141
|
+
return Number( val ) >= min;
|
142
|
+
}
|
143
|
+
|
144
|
+
, max: function ( val, max ) {
|
145
|
+
return Number( val ) <= max;
|
146
|
+
}
|
147
|
+
|
148
|
+
, range: function ( val, arrayRange ) {
|
149
|
+
return val >= arrayRange[ 0 ] && val <= arrayRange[ 1 ];
|
150
|
+
}
|
151
|
+
|
152
|
+
, equalto: function ( val, elem, self ) {
|
153
|
+
self.options.validateIfUnchanged = true;
|
154
|
+
|
155
|
+
return val === $( elem ).val();
|
156
|
+
}
|
157
|
+
|
158
|
+
, remote: function ( val, url, self ) {
|
159
|
+
var result = null
|
160
|
+
, data = {}
|
161
|
+
, dataType = {};
|
162
|
+
|
163
|
+
data[ self.$element.attr( 'name' ) ] = val;
|
164
|
+
|
165
|
+
if ( 'undefined' !== typeof self.options.remoteDatatype ) {
|
166
|
+
dataType = { dataType: self.options.remoteDatatype };
|
167
|
+
}
|
168
|
+
|
169
|
+
var manage = function ( isConstraintValid, message ) {
|
170
|
+
// remove error message because ajax response message could change depending on the sent value !
|
171
|
+
self.removeError( 'remote' );
|
172
|
+
|
173
|
+
self.updtConstraint( { name: 'remote', isValid: isConstraintValid }, message );
|
174
|
+
self.manageValidationResult();
|
175
|
+
};
|
176
|
+
|
177
|
+
// transform string response into object
|
178
|
+
var handleResponse = function ( response ) {
|
179
|
+
if ( 'object' === typeof response ) {
|
180
|
+
return response;
|
181
|
+
}
|
182
|
+
|
183
|
+
try {
|
184
|
+
response = $.parseJSON( response );
|
185
|
+
} catch ( err ) {}
|
186
|
+
|
187
|
+
return response;
|
188
|
+
}
|
189
|
+
|
190
|
+
var manageErrorMessage = function ( response ) {
|
191
|
+
return 'object' === typeof response && null !== response ? ( 'undefined' !== typeof response.error ? response.error : ( 'undefined' !== typeof response.message ? response.message : null ) ) : null;
|
192
|
+
}
|
193
|
+
|
194
|
+
$.ajax( $.extend( {}, {
|
195
|
+
url: url
|
196
|
+
, data: data
|
197
|
+
, async: self.async
|
198
|
+
, method: self.options.remoteMethod || 'GET'
|
199
|
+
, success: function ( response ) {
|
200
|
+
response = handleResponse( response );
|
201
|
+
manage( 1 === response || true === response || ( 'object' === typeof response && null !== response && 'undefined' !== typeof response.success ), manageErrorMessage( response )
|
202
|
+
);
|
203
|
+
}
|
204
|
+
, error: function ( response ) {
|
205
|
+
response = handleResponse( response );
|
206
|
+
manage( false, manageErrorMessage( response ) );
|
207
|
+
}
|
208
|
+
}, dataType ) );
|
209
|
+
|
210
|
+
if ( self.async ) {
|
211
|
+
manage( result );
|
212
|
+
}
|
213
|
+
|
214
|
+
return result;
|
215
|
+
}
|
216
|
+
|
217
|
+
/**
|
218
|
+
* Aliases for checkboxes constraints
|
219
|
+
*/
|
220
|
+
, mincheck: function ( obj, val ) {
|
221
|
+
return this.minlength( obj, val );
|
222
|
+
}
|
223
|
+
|
224
|
+
, maxcheck: function ( obj, val ) {
|
225
|
+
return this.maxlength( obj, val);
|
226
|
+
}
|
227
|
+
|
228
|
+
, rangecheck: function ( obj, arrayRange ) {
|
229
|
+
return this.rangelength( obj, arrayRange );
|
230
|
+
}
|
231
|
+
}
|
232
|
+
|
233
|
+
/*
|
234
|
+
* Register custom validators and messages
|
235
|
+
*/
|
236
|
+
, init: function ( options ) {
|
237
|
+
var customValidators = options.validators
|
238
|
+
, customMessages = options.messages;
|
239
|
+
|
240
|
+
var key;
|
241
|
+
for ( key in customValidators ) {
|
242
|
+
this.addValidator(key, customValidators[ key ]);
|
243
|
+
}
|
244
|
+
|
245
|
+
for ( key in customMessages ) {
|
246
|
+
this.addMessage(key, customMessages[ key ]);
|
247
|
+
}
|
248
|
+
}
|
249
|
+
|
250
|
+
/**
|
251
|
+
* Replace %s placeholders by values
|
252
|
+
*
|
253
|
+
* @method formatMesssage
|
254
|
+
* @param {String} message Message key
|
255
|
+
* @param {Mixed} args Args passed by validators functions. Could be string, number or object
|
256
|
+
* @return {String} Formatted string
|
257
|
+
*/
|
258
|
+
, formatMesssage: function ( message, args ) {
|
259
|
+
|
260
|
+
if ( 'object' === typeof args ) {
|
261
|
+
for ( var i in args ) {
|
262
|
+
message = this.formatMesssage( message, args[ i ] );
|
263
|
+
}
|
264
|
+
|
265
|
+
return message;
|
266
|
+
}
|
267
|
+
|
268
|
+
return 'string' === typeof message ? message.replace( new RegExp( '%s', 'i' ), args ) : '';
|
269
|
+
}
|
270
|
+
|
271
|
+
/**
|
272
|
+
* Add / override a validator in validators list
|
273
|
+
*
|
274
|
+
* @method addValidator
|
275
|
+
* @param {String} name Validator name. Will automatically bindable through data-name=''
|
276
|
+
* @param {Function} fn Validator function. Must return {Boolean}
|
277
|
+
*/
|
278
|
+
, addValidator: function ( name, fn ) {
|
279
|
+
this.validators[ name ] = fn;
|
280
|
+
}
|
281
|
+
|
282
|
+
/**
|
283
|
+
* Add / override error message
|
284
|
+
*
|
285
|
+
* @method addMessage
|
286
|
+
* @param {String} name Message name. Will automatically be binded to validator with same name
|
287
|
+
* @param {String} message Message
|
288
|
+
*/
|
289
|
+
, addMessage: function ( key, message, type ) {
|
290
|
+
|
291
|
+
if ( 'undefined' !== typeof type && true === type ) {
|
292
|
+
this.messages.type[ key ] = message;
|
293
|
+
return;
|
294
|
+
}
|
295
|
+
|
296
|
+
// custom types messages are a bit tricky cuz' nested ;)
|
297
|
+
if ( 'type' === key ) {
|
298
|
+
for ( var i in message ) {
|
299
|
+
this.messages.type[ i ] = message[ i ];
|
300
|
+
}
|
301
|
+
|
302
|
+
return;
|
303
|
+
}
|
304
|
+
|
305
|
+
this.messages[ key ] = message;
|
306
|
+
}
|
307
|
+
};
|
308
|
+
|
309
|
+
/**
|
310
|
+
* ParsleyField class manage each form field inside a validated Parsley form.
|
311
|
+
* Returns if field valid or not depending on its value and constraints
|
312
|
+
* Manage field error display and behavior, event triggers and more
|
313
|
+
*
|
314
|
+
* @class ParsleyField
|
315
|
+
* @constructor
|
316
|
+
*/
|
317
|
+
var ParsleyField = function ( element, options, type ) {
|
318
|
+
this.options = options;
|
319
|
+
this.Validator = new Validator( options );
|
320
|
+
this.init( element, type || 'ParsleyField' );
|
321
|
+
};
|
322
|
+
|
323
|
+
ParsleyField.prototype = {
|
324
|
+
|
325
|
+
constructor: ParsleyField
|
326
|
+
|
327
|
+
/**
|
328
|
+
* Set some properties, bind constraint validators and validation events
|
329
|
+
*
|
330
|
+
* @method init
|
331
|
+
* @param {Object} element
|
332
|
+
* @param {Object} options
|
333
|
+
*/
|
334
|
+
, init: function ( element, type ) {
|
335
|
+
this.type = type;
|
336
|
+
this.isValid = true;
|
337
|
+
this.element = element;
|
338
|
+
this.validatedOnce = false;
|
339
|
+
this.$element = $( element );
|
340
|
+
this.val = this.$element.val();
|
341
|
+
this.isRequired = false;
|
342
|
+
this.constraints = [];
|
343
|
+
|
344
|
+
// overriden by ParsleyItemMultiple if radio or checkbox input
|
345
|
+
if ( 'undefined' === typeof this.isRadioOrCheckbox ) {
|
346
|
+
this.isRadioOrCheckbox = false;
|
347
|
+
this.hash = this.generateHash();
|
348
|
+
this.errorClassHandler = this.options.errors.classHandler( element, this.isRadioOrCheckbox ) || this.$element;
|
349
|
+
}
|
350
|
+
|
351
|
+
// error ul dom management done only once at init
|
352
|
+
this.ulErrorManagement();
|
353
|
+
|
354
|
+
// bind some html5 properties
|
355
|
+
this.bindHtml5Constraints();
|
356
|
+
|
357
|
+
// bind validators to field
|
358
|
+
this.addConstraints();
|
359
|
+
|
360
|
+
// bind parsley events if validators have been registered
|
361
|
+
if ( this.constraints.length ) {
|
362
|
+
this.bindValidationEvents();
|
363
|
+
}
|
364
|
+
}
|
365
|
+
|
366
|
+
, setParent: function ( elem ) {
|
367
|
+
this.$parent = $( elem );
|
368
|
+
}
|
369
|
+
|
370
|
+
, getParent: function () {
|
371
|
+
return this.$parent;
|
372
|
+
}
|
373
|
+
|
374
|
+
/**
|
375
|
+
* Bind some extra html5 types / validators
|
376
|
+
*
|
377
|
+
* @private
|
378
|
+
* @method bindHtml5Constraints
|
379
|
+
*/
|
380
|
+
, bindHtml5Constraints: function () {
|
381
|
+
// add html5 required support + class required support
|
382
|
+
if ( this.$element.hasClass( 'required' ) || this.$element.attr( 'required' ) ) {
|
383
|
+
this.options.required = true;
|
384
|
+
}
|
385
|
+
|
386
|
+
// add html5 supported types & options
|
387
|
+
if ( 'undefined' !== typeof this.$element.attr( 'type' ) && new RegExp( this.$element.attr( 'type' ), 'i' ).test( 'email url number range' ) ) {
|
388
|
+
this.options.type = this.$element.attr( 'type' );
|
389
|
+
|
390
|
+
// number and range types could have min and/or max values
|
391
|
+
if ( new RegExp( this.options.type, 'i' ).test( 'number range' ) ) {
|
392
|
+
this.options.type = 'number';
|
393
|
+
|
394
|
+
// double condition to support jQuery and Zepto.. :(
|
395
|
+
if ( 'undefined' !== typeof this.$element.attr( 'min' ) && this.$element.attr( 'min' ).length ) {
|
396
|
+
this.options.min = this.$element.attr( 'min' );
|
397
|
+
}
|
398
|
+
|
399
|
+
if ( 'undefined' !== typeof this.$element.attr( 'max' ) && this.$element.attr( 'max' ).length ) {
|
400
|
+
this.options.max = this.$element.attr( 'max' );
|
401
|
+
}
|
402
|
+
}
|
403
|
+
}
|
404
|
+
}
|
405
|
+
|
406
|
+
/**
|
407
|
+
* Attach field validators functions passed through data-api
|
408
|
+
*
|
409
|
+
* @private
|
410
|
+
* @method addConstraints
|
411
|
+
*/
|
412
|
+
, addConstraints: function () {
|
413
|
+
for ( var constraint in this.options ) {
|
414
|
+
var addConstraint = {};
|
415
|
+
addConstraint[ constraint ] = this.options[ constraint ];
|
416
|
+
this.addConstraint( addConstraint, true );
|
417
|
+
}
|
418
|
+
}
|
419
|
+
|
420
|
+
/**
|
421
|
+
* Dynamically add a new constraint to a field
|
422
|
+
*
|
423
|
+
* @method addConstraint
|
424
|
+
* @param {Object} constraint { name: requirements }
|
425
|
+
*/
|
426
|
+
, addConstraint: function ( constraint, doNotUpdateValidationEvents ) {
|
427
|
+
for ( var name in constraint ) {
|
428
|
+
name = name.toLowerCase();
|
429
|
+
|
430
|
+
if ( 'function' === typeof this.Validator.validators[ name ] ) {
|
431
|
+
this.constraints.push( {
|
432
|
+
name: name
|
433
|
+
, requirements: constraint[ name ]
|
434
|
+
, isValid: null
|
435
|
+
} );
|
436
|
+
|
437
|
+
if ( name === 'required' ) {
|
438
|
+
this.isRequired = true;
|
439
|
+
}
|
440
|
+
|
441
|
+
this.addCustomConstraintMessage( name );
|
442
|
+
}
|
443
|
+
}
|
444
|
+
|
445
|
+
// force field validation next check and reset validation events
|
446
|
+
if ( 'undefined' === typeof doNotUpdateValidationEvents ) {
|
447
|
+
this.bindValidationEvents();
|
448
|
+
}
|
449
|
+
}
|
450
|
+
|
451
|
+
/**
|
452
|
+
* Dynamically update an existing constraint to a field.
|
453
|
+
* Simple API: { name: requirements }
|
454
|
+
*
|
455
|
+
* @method updtConstraint
|
456
|
+
* @param {Object} constraint
|
457
|
+
*/
|
458
|
+
, updateConstraint: function ( constraint, message ) {
|
459
|
+
for ( var name in constraint ) {
|
460
|
+
this.updtConstraint( { name: name, requirements: constraint[ name ], isValid: null }, message );
|
461
|
+
}
|
462
|
+
}
|
463
|
+
|
464
|
+
/**
|
465
|
+
* Dynamically update an existing constraint to a field.
|
466
|
+
* Complex API: { name: name, requirements: requirements, isValid: boolean }
|
467
|
+
*
|
468
|
+
* @method updtConstraint
|
469
|
+
* @param {Object} constraint
|
470
|
+
*/
|
471
|
+
, updtConstraint: function ( constraint, message ) {
|
472
|
+
for ( var i in this.constraints ) {
|
473
|
+
if ( this.constraints[ i ].name === constraint.name ) {
|
474
|
+
this.constraints[ i ] = $.extend( true, this.constraints[ i ], constraint );
|
475
|
+
if ( 'string' === typeof message ) {
|
476
|
+
this.Validator.messages[ this.constraints[ i ].name ] = message ;
|
477
|
+
}
|
478
|
+
}
|
479
|
+
}
|
480
|
+
|
481
|
+
// force field validation next check and reset validation events
|
482
|
+
this.bindValidationEvents();
|
483
|
+
}
|
484
|
+
|
485
|
+
/**
|
486
|
+
* Dynamically remove an existing constraint to a field.
|
487
|
+
*
|
488
|
+
* @method removeConstraint
|
489
|
+
* @param {String} constraintName
|
490
|
+
*/
|
491
|
+
, removeConstraint: function ( constraintName ) {
|
492
|
+
var constraintName = constraintName.toLowerCase()
|
493
|
+
, updatedConstraints = [];
|
494
|
+
|
495
|
+
for ( var constraint in this.constraints ) {
|
496
|
+
if ( this.constraints[ constraint ].name !== constraintName ) {
|
497
|
+
updatedConstraints.push( this.constraints[ constraint ] );
|
498
|
+
}
|
499
|
+
}
|
500
|
+
|
501
|
+
if ( constraintName === 'required' ) {
|
502
|
+
this.isRequired = false;
|
503
|
+
}
|
504
|
+
|
505
|
+
this.constraints = updatedConstraints;
|
506
|
+
|
507
|
+
// if there are no more constraint, destroy parsley instance for this field
|
508
|
+
if ( updatedConstraints.length === 0 ) {
|
509
|
+
// in a form context, remove item from parent
|
510
|
+
if ( 'ParsleyForm' === typeof this.getParent() ) {
|
511
|
+
this.getParent().removeItem( this.$element );
|
512
|
+
return;
|
513
|
+
}
|
514
|
+
|
515
|
+
this.destroy();
|
516
|
+
return;
|
517
|
+
}
|
518
|
+
|
519
|
+
this.bindValidationEvents();
|
520
|
+
}
|
521
|
+
|
522
|
+
/**
|
523
|
+
* Add custom constraint message, passed through data-API
|
524
|
+
*
|
525
|
+
* @private
|
526
|
+
* @method addCustomConstraintMessage
|
527
|
+
* @param constraint
|
528
|
+
*/
|
529
|
+
, addCustomConstraintMessage: function ( constraint ) {
|
530
|
+
// custom message type data-type-email-message -> typeEmailMessage | data-minlength-error => minlengthMessage
|
531
|
+
var customMessage = constraint
|
532
|
+
+ ( 'type' === constraint && 'undefined' !== typeof this.options[ constraint ] ? this.options[ constraint ].charAt( 0 ).toUpperCase() + this.options[ constraint ].substr( 1 ) : '' )
|
533
|
+
+ 'Message';
|
534
|
+
|
535
|
+
if ( 'undefined' !== typeof this.options[ customMessage ] ) {
|
536
|
+
this.Validator.addMessage( 'type' === constraint ? this.options[ constraint ] : constraint, this.options[ customMessage ], 'type' === constraint );
|
537
|
+
}
|
538
|
+
}
|
539
|
+
|
540
|
+
/**
|
541
|
+
* Bind validation events on a field
|
542
|
+
*
|
543
|
+
* @private
|
544
|
+
* @method bindValidationEvents
|
545
|
+
*/
|
546
|
+
, bindValidationEvents: function () {
|
547
|
+
// this field has validation events, that means it has to be validated
|
548
|
+
this.isValid = null;
|
549
|
+
this.$element.addClass( 'parsley-validated' );
|
550
|
+
|
551
|
+
// remove eventually already binded events
|
552
|
+
this.$element.off( '.' + this.type );
|
553
|
+
|
554
|
+
// alaways bind keyup event, for better UX when a field is invalid
|
555
|
+
var triggers = ( !this.options.trigger ? '' : this.options.trigger + ' ' )
|
556
|
+
+ ( new RegExp( 'key', 'i' ).test( this.options.trigger ) ? '' : 'keyup' );
|
557
|
+
|
558
|
+
// force add 'change' event if async remote validator here to have result before form submitting
|
559
|
+
if ( this.options.remote ) {
|
560
|
+
triggers += new RegExp( 'change', 'i' ).test( triggers ) ? '' : ' change';
|
561
|
+
}
|
562
|
+
|
563
|
+
this.$element.on( ( triggers + ' ' ).split( ' ' ).join( '.' + this.type + ' ' ), false, $.proxy( this.eventValidation, this ) );
|
564
|
+
}
|
565
|
+
|
566
|
+
/**
|
567
|
+
* Hash management. Used for ul error
|
568
|
+
*
|
569
|
+
* @method generateHash
|
570
|
+
* @returns {String} 5 letters unique hash
|
571
|
+
*/
|
572
|
+
, generateHash: function () {
|
573
|
+
return 'parsley-' + ( Math.random() + '' ).substring( 2 );
|
574
|
+
}
|
575
|
+
|
576
|
+
/**
|
577
|
+
* Public getHash accessor
|
578
|
+
*
|
579
|
+
* @method getHash
|
580
|
+
* @returns {String} hash
|
581
|
+
*/
|
582
|
+
, getHash: function () {
|
583
|
+
return this.hash;
|
584
|
+
}
|
585
|
+
|
586
|
+
/**
|
587
|
+
* Returns field val needed for validation
|
588
|
+
* Special treatment for radio & checkboxes
|
589
|
+
*
|
590
|
+
* @method getVal
|
591
|
+
* @returns {String} val
|
592
|
+
*/
|
593
|
+
, getVal: function () {
|
594
|
+
return this.$element.val();
|
595
|
+
}
|
596
|
+
|
597
|
+
/**
|
598
|
+
* Called when validation is triggered by an event
|
599
|
+
* Do nothing if val.length < this.options.validationMinlength
|
600
|
+
*
|
601
|
+
* @method eventValidation
|
602
|
+
* @param {Object} event jQuery event
|
603
|
+
*/
|
604
|
+
, eventValidation: function ( event ) {
|
605
|
+
var val = this.getVal();
|
606
|
+
|
607
|
+
// do nothing on keypress event if not explicitely passed as data-trigger and if field has not already been validated once
|
608
|
+
if ( event.type === 'keyup' && !/keyup/i.test( this.options.trigger ) && !this.validatedOnce ) {
|
609
|
+
return true;
|
610
|
+
}
|
611
|
+
|
612
|
+
// start validation process only if field has enough chars and validation never started
|
613
|
+
if ( !this.isRadioOrCheckbox && val.length < this.options.validationMinlength && !this.validatedOnce ) {
|
614
|
+
return true;
|
615
|
+
}
|
616
|
+
|
617
|
+
this.validate( true, false );
|
618
|
+
}
|
619
|
+
|
620
|
+
/**
|
621
|
+
* Return if field verify its constraints
|
622
|
+
*
|
623
|
+
* @method isValid
|
624
|
+
* @return {Boolean} Is field valid or not
|
625
|
+
*/
|
626
|
+
, isFieldValid: function () {
|
627
|
+
return this.validate( false, false );
|
628
|
+
}
|
629
|
+
|
630
|
+
/**
|
631
|
+
* Validate a field & display errors
|
632
|
+
*
|
633
|
+
* @method validate
|
634
|
+
* @param {Boolean} errorBubbling set to false if you just want isValid boolean without error bubbling next to fields
|
635
|
+
* @param {Boolean} async if false, wait ajax calls returns
|
636
|
+
* @return {Boolean} Is field valid or not
|
637
|
+
*/
|
638
|
+
, validate: function ( errorBubbling, async ) {
|
639
|
+
var val = this.getVal()
|
640
|
+
, isValid = null;
|
641
|
+
|
642
|
+
// reset Parsley validation if onFieldValidate returns true, or if field is empty and not required
|
643
|
+
if ( this.options.listeners.onFieldValidate( this.element, this ) || ( '' === val && !this.isRequired ) ) {
|
644
|
+
this.reset();
|
645
|
+
return null;
|
646
|
+
}
|
647
|
+
|
648
|
+
// do not validate a field already validated and unchanged !
|
649
|
+
if ( !this.needsValidation( val ) ) {
|
650
|
+
return this.isValid;
|
651
|
+
}
|
652
|
+
|
653
|
+
this.errorBubbling = 'undefined' !== typeof errorBubbling ? errorBubbling : true;
|
654
|
+
this.async = 'undefined' !== typeof async ? async : true;
|
655
|
+
|
656
|
+
isValid = this.applyValidators();
|
657
|
+
|
658
|
+
if ( this.errorBubbling ) {
|
659
|
+
this.manageValidationResult();
|
660
|
+
}
|
661
|
+
|
662
|
+
return isValid;
|
663
|
+
}
|
664
|
+
|
665
|
+
/**
|
666
|
+
* Check if value has changed since previous validation
|
667
|
+
*
|
668
|
+
* @method needsValidation
|
669
|
+
* @param value
|
670
|
+
* @return {Boolean}
|
671
|
+
*/
|
672
|
+
, needsValidation: function ( val ) {
|
673
|
+
if ( !this.options.validateIfUnchanged && this.isValid !== null && this.val === val && this.validatedOnce ) {
|
674
|
+
return false;
|
675
|
+
}
|
676
|
+
|
677
|
+
this.val = val;
|
678
|
+
return this.validatedOnce = true;
|
679
|
+
}
|
680
|
+
|
681
|
+
/**
|
682
|
+
* Loop through every fields validators
|
683
|
+
* Adds errors after unvalid fields
|
684
|
+
*
|
685
|
+
* @method applyValidators
|
686
|
+
* @return {Mixed} {Boolean} If field valid or not, null if not validated
|
687
|
+
*/
|
688
|
+
, applyValidators: function () {
|
689
|
+
var isValid = null;
|
690
|
+
|
691
|
+
for ( var constraint = 0; constraint < this.constraints.length; constraint++ ) {
|
692
|
+
var result = this.Validator.validators[ this.constraints[ constraint ].name ]( this.val, this.constraints[ constraint ].requirements, this );
|
693
|
+
|
694
|
+
if ( false === result ) {
|
695
|
+
isValid = false;
|
696
|
+
this.constraints[ constraint ].isValid = isValid;
|
697
|
+
} else if ( true === result ) {
|
698
|
+
this.constraints[ constraint ].isValid = true;
|
699
|
+
isValid = false !== isValid;
|
700
|
+
}
|
701
|
+
}
|
702
|
+
|
703
|
+
return isValid;
|
704
|
+
}
|
705
|
+
|
706
|
+
/**
|
707
|
+
* Fired when all validators have be executed
|
708
|
+
* Returns true or false if field is valid or not
|
709
|
+
* Display errors messages below faild fields
|
710
|
+
* Adds parsley-success or parsley-error class on fields
|
711
|
+
*
|
712
|
+
* @method manageValidationResult
|
713
|
+
* @return {Boolean} Is field valid or not
|
714
|
+
*/
|
715
|
+
, manageValidationResult: function () {
|
716
|
+
var isValid = null;
|
717
|
+
|
718
|
+
for ( var constraint = 0; constraint < this.constraints.length; constraint++ ) {
|
719
|
+
if ( false === this.constraints[ constraint ].isValid ) {
|
720
|
+
this.manageError( this.constraints[ constraint ] );
|
721
|
+
isValid = false;
|
722
|
+
} else if ( true === this.constraints[ constraint ].isValid ) {
|
723
|
+
this.removeError( this.constraints[ constraint ].name );
|
724
|
+
isValid = false !== isValid;
|
725
|
+
}
|
726
|
+
}
|
727
|
+
|
728
|
+
this.isValid = isValid;
|
729
|
+
|
730
|
+
if ( true === this.isValid ) {
|
731
|
+
this.removeErrors();
|
732
|
+
this.errorClassHandler.removeClass( this.options.errorClass ).addClass( this.options.successClass );
|
733
|
+
this.options.listeners.onFieldSuccess( this.element, this.constraints, this );
|
734
|
+
return true;
|
735
|
+
} else if ( false === this.isValid ) {
|
736
|
+
this.errorClassHandler.removeClass( this.options.successClass ).addClass( this.options.errorClass );
|
737
|
+
this.options.listeners.onFieldError( this.element, this.constraints, this );
|
738
|
+
return false;
|
739
|
+
}
|
740
|
+
|
741
|
+
return isValid;
|
742
|
+
}
|
743
|
+
|
744
|
+
/**
|
745
|
+
* Manage ul error Container
|
746
|
+
*
|
747
|
+
* @private
|
748
|
+
* @method ulErrorManagement
|
749
|
+
*/
|
750
|
+
, ulErrorManagement: function () {
|
751
|
+
this.ulError = '#' + this.hash;
|
752
|
+
this.ulTemplate = $( this.options.errors.errorsWrapper ).attr( 'id', this.hash ).addClass( 'parsley-error-list' );
|
753
|
+
}
|
754
|
+
|
755
|
+
/**
|
756
|
+
* Remove li / ul error
|
757
|
+
*
|
758
|
+
* @method removeError
|
759
|
+
* @param {String} constraintName Method Name
|
760
|
+
*/
|
761
|
+
, removeError: function ( constraintName ) {
|
762
|
+
var liError = this.ulError + ' .' + constraintName;
|
763
|
+
|
764
|
+
this.options.animate ? $( liError ).fadeOut( this.options.animateDuration, function () { $( this ).remove() } ) : $( liError ).remove();
|
765
|
+
|
766
|
+
// remove li error, and ul error if no more li inside
|
767
|
+
if ( this.ulError && $( this.ulError ).children().length === 0 ) {
|
768
|
+
this.removeErrors();
|
769
|
+
}
|
770
|
+
}
|
771
|
+
|
772
|
+
/**
|
773
|
+
* Add li error
|
774
|
+
*
|
775
|
+
* @method addError
|
776
|
+
* @param {Object} { minlength: "error message for minlength constraint" }
|
777
|
+
*/
|
778
|
+
, addError: function ( error ) {
|
779
|
+
for ( var constraint in error ) {
|
780
|
+
var liTemplate = $( this.options.errors.errorElem ).addClass( constraint );
|
781
|
+
|
782
|
+
$( this.ulError ).append( this.options.animate ? $( liTemplate ).text( error[ constraint ] ).hide().fadeIn( this.options.animateDuration ) : $( liTemplate ).text( error[ constraint ] ) );
|
783
|
+
}
|
784
|
+
}
|
785
|
+
|
786
|
+
/**
|
787
|
+
* Remove all ul / li errors
|
788
|
+
*
|
789
|
+
* @method removeErrors
|
790
|
+
*/
|
791
|
+
, removeErrors: function () {
|
792
|
+
this.options.animate ? $( this.ulError ).fadeOut( this.options.animateDuration, function () { $( this ).remove(); } ) : $( this.ulError ).remove();
|
793
|
+
}
|
794
|
+
|
795
|
+
/**
|
796
|
+
* Remove ul errors and parsley error or success classes
|
797
|
+
*
|
798
|
+
* @method reset
|
799
|
+
*/
|
800
|
+
, reset: function () {
|
801
|
+
this.isValid = null;
|
802
|
+
this.removeErrors();
|
803
|
+
this.errorClassHandler.removeClass( this.options.successClass ).removeClass( this.options.errorClass );
|
804
|
+
return this;
|
805
|
+
}
|
806
|
+
|
807
|
+
/**
|
808
|
+
* Add li / ul errors messages
|
809
|
+
*
|
810
|
+
* @method manageError
|
811
|
+
* @param {Object} constraint
|
812
|
+
*/
|
813
|
+
, manageError: function ( constraint ) {
|
814
|
+
// display ulError container if it has been removed previously (or never shown)
|
815
|
+
if ( !$( this.ulError ).length ) {
|
816
|
+
this.manageErrorContainer();
|
817
|
+
}
|
818
|
+
|
819
|
+
// TODO: refacto error name w/ proper & readable function
|
820
|
+
var constraintName = constraint.name
|
821
|
+
, liClass = false !== this.options.errorMessage ? 'custom-error-message' : constraintName
|
822
|
+
, liError = {}
|
823
|
+
, message = false !== this.options.errorMessage ? this.options.errorMessage : ( constraint.name === 'type' ?
|
824
|
+
this.Validator.messages[ constraintName ][ constraint.requirements ] : ( 'undefined' === typeof this.Validator.messages[ constraintName ] ?
|
825
|
+
this.Validator.messages.defaultMessage : this.Validator.formatMesssage( this.Validator.messages[ constraintName ], constraint.requirements ) ) );
|
826
|
+
|
827
|
+
// add liError if not shown. Do not add more than once custom errorMessage if exist
|
828
|
+
if ( !$( this.ulError + ' .' + liClass ).length ) {
|
829
|
+
liError[ liClass ] = message;
|
830
|
+
this.addError( liError );
|
831
|
+
}
|
832
|
+
}
|
833
|
+
|
834
|
+
/**
|
835
|
+
* Create ul error container
|
836
|
+
*
|
837
|
+
* @method manageErrorContainer
|
838
|
+
*/
|
839
|
+
, manageErrorContainer: function () {
|
840
|
+
var errorContainer = this.options.errors.container( this.element, this.isRadioOrCheckbox )
|
841
|
+
, ulTemplate = this.options.animate ? this.ulTemplate.show() : this.ulTemplate;
|
842
|
+
|
843
|
+
if ( 'undefined' !== typeof errorContainer ) {
|
844
|
+
$( errorContainer ).append( ulTemplate );
|
845
|
+
return;
|
846
|
+
}
|
847
|
+
|
848
|
+
!this.isRadioOrCheckbox ? this.$element.after( ulTemplate ) : this.$element.parent().after( ulTemplate );
|
849
|
+
}
|
850
|
+
|
851
|
+
/**
|
852
|
+
* Add custom listeners
|
853
|
+
*
|
854
|
+
* @param {Object} { listener: function () {} }, eg { onFormSubmit: function ( isValid, event, focus ) { ... } }
|
855
|
+
*/
|
856
|
+
, addListener: function ( object ) {
|
857
|
+
for ( var listener in object ) {
|
858
|
+
this.options.listeners[ listener ] = object[ listener ];
|
859
|
+
}
|
860
|
+
}
|
861
|
+
|
862
|
+
/**
|
863
|
+
* Destroy parsley field instance
|
864
|
+
*
|
865
|
+
* @private
|
866
|
+
* @method destroy
|
867
|
+
*/
|
868
|
+
, destroy: function () {
|
869
|
+
this.$element.removeClass( 'parsley-validated' );
|
870
|
+
this.errorClassHandler.removeClass( this.options.errorClass ).removeClass( this.options.successClass );
|
871
|
+
this.reset().$element.off( '.' + this.type ).removeData( this.type );
|
872
|
+
}
|
873
|
+
};
|
874
|
+
|
875
|
+
/**
|
876
|
+
* ParsleyFieldMultiple override ParsleyField for checkbox and radio inputs
|
877
|
+
* Pseudo-heritance to manage divergent behavior from ParsleyItem in dedicated methods
|
878
|
+
*
|
879
|
+
* @class ParsleyFieldMultiple
|
880
|
+
* @constructor
|
881
|
+
*/
|
882
|
+
var ParsleyFieldMultiple = function ( element, options, type ) {
|
883
|
+
this.initMultiple( element, options );
|
884
|
+
this.inherit( element, options );
|
885
|
+
this.Validator = new Validator( options );
|
886
|
+
|
887
|
+
// call ParsleyField constructor
|
888
|
+
this.init( element, type || 'ParsleyFieldMultiple' );
|
889
|
+
};
|
890
|
+
|
891
|
+
ParsleyFieldMultiple.prototype = {
|
892
|
+
|
893
|
+
constructor: ParsleyFieldMultiple
|
894
|
+
|
895
|
+
/**
|
896
|
+
* Set some specific properties, call some extra methods to manage radio / checkbox
|
897
|
+
*
|
898
|
+
* @method init
|
899
|
+
* @param {Object} element
|
900
|
+
* @param {Object} options
|
901
|
+
*/
|
902
|
+
, initMultiple: function ( element, options ) {
|
903
|
+
this.element = element;
|
904
|
+
this.$element = $( element );
|
905
|
+
this.group = options.group || false;
|
906
|
+
this.hash = this.getName();
|
907
|
+
this.siblings = this.group ? '[data-group="' + this.group + '"]' : 'input[name="' + this.$element.attr( 'name' ) + '"]';
|
908
|
+
this.isRadioOrCheckbox = true;
|
909
|
+
this.isRadio = this.$element.is( 'input[type=radio]' );
|
910
|
+
this.isCheckbox = this.$element.is( 'input[type=checkbox]' );
|
911
|
+
this.errorClassHandler = options.errors.classHandler( element, this.isRadioOrCheckbox ) || this.$element.parent();
|
912
|
+
}
|
913
|
+
|
914
|
+
/**
|
915
|
+
* Set specific constraints messages, do pseudo-heritance
|
916
|
+
*
|
917
|
+
* @private
|
918
|
+
* @method inherit
|
919
|
+
* @param {Object} element
|
920
|
+
* @param {Object} options
|
921
|
+
*/
|
922
|
+
, inherit: function ( element, options ) {
|
923
|
+
var clone = new ParsleyField( element, options );
|
924
|
+
|
925
|
+
for ( var property in clone ) {
|
926
|
+
if ( 'undefined' === typeof this[ property ] ) {
|
927
|
+
this[ property ] = clone [ property ];
|
928
|
+
}
|
929
|
+
}
|
930
|
+
}
|
931
|
+
|
932
|
+
/**
|
933
|
+
* Set specific constraints messages, do pseudo-heritance
|
934
|
+
*
|
935
|
+
* @method getName
|
936
|
+
* @returns {String} radio / checkbox hash is cleaned 'name' or data-group property
|
937
|
+
*/
|
938
|
+
, getName: function () {
|
939
|
+
if ( this.group ) {
|
940
|
+
return 'parsley-' + this.group;
|
941
|
+
}
|
942
|
+
|
943
|
+
if ( 'undefined' === typeof this.$element.attr( 'name' ) ) {
|
944
|
+
throw "A radio / checkbox input must have a data-group attribute or a name to be Parsley validated !";
|
945
|
+
}
|
946
|
+
|
947
|
+
return 'parsley-' + this.$element.attr( 'name' ).replace( /(:|\.|\[|\])/g, '' );
|
948
|
+
}
|
949
|
+
|
950
|
+
/**
|
951
|
+
* Special treatment for radio & checkboxes
|
952
|
+
* Returns checked radio or checkboxes values
|
953
|
+
*
|
954
|
+
* @method getVal
|
955
|
+
* @returns {String} val
|
956
|
+
*/
|
957
|
+
, getVal: function () {
|
958
|
+
if ( this.isRadio ) {
|
959
|
+
return $( this.siblings + ':checked' ).val() || '';
|
960
|
+
}
|
961
|
+
|
962
|
+
if ( this.isCheckbox ) {
|
963
|
+
var values = [];
|
964
|
+
|
965
|
+
$( this.siblings + ':checked' ).each( function () {
|
966
|
+
values.push( $( this ).val() );
|
967
|
+
} );
|
968
|
+
|
969
|
+
return values;
|
970
|
+
}
|
971
|
+
}
|
972
|
+
|
973
|
+
/**
|
974
|
+
* Bind validation events on a field
|
975
|
+
*
|
976
|
+
* @private
|
977
|
+
* @method bindValidationEvents
|
978
|
+
*/
|
979
|
+
, bindValidationEvents: function () {
|
980
|
+
// this field has validation events, that means it has to be validated
|
981
|
+
this.isValid = null;
|
982
|
+
this.$element.addClass( 'parsley-validated' );
|
983
|
+
|
984
|
+
// remove eventually already binded events
|
985
|
+
this.$element.off( '.' + this.type );
|
986
|
+
|
987
|
+
// alaways bind keyup event, for better UX when a field is invalid
|
988
|
+
var self = this
|
989
|
+
, triggers = ( !this.options.trigger ? '' : this.options.trigger + ' ' )
|
990
|
+
+ ( new RegExp( 'change', 'i' ).test( this.options.trigger ) ? '' : 'change' );
|
991
|
+
|
992
|
+
// bind trigger event on every siblings
|
993
|
+
$( this.siblings ).each(function () {
|
994
|
+
$( this ).on( triggers.split( ' ' ).join( '.' + self.type + ' ' ), false, $.proxy( self.eventValidation, self ) );
|
995
|
+
} )
|
996
|
+
}
|
997
|
+
|
998
|
+
/**
|
999
|
+
* Called when validation is triggered by an event
|
1000
|
+
* Do nothing if never validated. validate on change otherwise
|
1001
|
+
*
|
1002
|
+
* @method eventValidation
|
1003
|
+
* @param {Object} event jQuery event
|
1004
|
+
*/
|
1005
|
+
, eventValidation: function ( event ) {
|
1006
|
+
// start validation process only if field has enough chars and validation never started
|
1007
|
+
if ( !this.validatedOnce ) {
|
1008
|
+
return true;
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
this.validate( true, false );
|
1012
|
+
}
|
1013
|
+
};
|
1014
|
+
|
1015
|
+
/**
|
1016
|
+
* ParsleyForm class manage Parsley validated form.
|
1017
|
+
* Manage its fields and global validation
|
1018
|
+
*
|
1019
|
+
* @class ParsleyForm
|
1020
|
+
* @constructor
|
1021
|
+
*/
|
1022
|
+
var ParsleyForm = function ( element, options, type ) {
|
1023
|
+
this.init( element, options, type || 'parsleyForm' );
|
1024
|
+
};
|
1025
|
+
|
1026
|
+
ParsleyForm.prototype = {
|
1027
|
+
|
1028
|
+
constructor: ParsleyForm
|
1029
|
+
|
1030
|
+
/* init data, bind jQuery on() actions */
|
1031
|
+
, init: function ( element, options, type ) {
|
1032
|
+
this.type = type;
|
1033
|
+
this.items = [];
|
1034
|
+
this.$element = $( element );
|
1035
|
+
this.options = options;
|
1036
|
+
var self = this;
|
1037
|
+
|
1038
|
+
this.$element.find( options.inputs ).each( function () {
|
1039
|
+
self.addItem( this );
|
1040
|
+
});
|
1041
|
+
|
1042
|
+
this.$element.on( 'submit.' + this.type , false, $.proxy( this.validate, this ) );
|
1043
|
+
}
|
1044
|
+
|
1045
|
+
/**
|
1046
|
+
* Add custom listeners
|
1047
|
+
*
|
1048
|
+
* @param {Object} { listener: function () {} }, eg { onFormSubmit: function ( isValid, event, focus ) { ... } }
|
1049
|
+
*/
|
1050
|
+
, addListener: function ( object ) {
|
1051
|
+
for ( var listener in object ) {
|
1052
|
+
if ( new RegExp( 'Field' ).test( listener ) ) {
|
1053
|
+
for ( var item = 0; item < this.items.length; item++ ) {
|
1054
|
+
this.items[ item ].addListener( object );
|
1055
|
+
}
|
1056
|
+
} else {
|
1057
|
+
this.options.listeners[ listener ] = object[ listener ];
|
1058
|
+
}
|
1059
|
+
}
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
/**
|
1063
|
+
* Adds a new parsleyItem child to ParsleyForm
|
1064
|
+
*
|
1065
|
+
* @method addItem
|
1066
|
+
* @param elem
|
1067
|
+
*/
|
1068
|
+
, addItem: function ( elem ) {
|
1069
|
+
if ( $( elem ).is( this.options.excluded ) ) {
|
1070
|
+
return false;
|
1071
|
+
}
|
1072
|
+
|
1073
|
+
var ParsleyField = $( elem ).parsley( this.options );
|
1074
|
+
ParsleyField.setParent( this );
|
1075
|
+
|
1076
|
+
this.items.push( ParsleyField );
|
1077
|
+
}
|
1078
|
+
|
1079
|
+
/**
|
1080
|
+
* Removes a parsleyItem child from ParsleyForm
|
1081
|
+
*
|
1082
|
+
* @method removeItem
|
1083
|
+
* @param elem
|
1084
|
+
* @return {Boolean}
|
1085
|
+
*/
|
1086
|
+
, removeItem: function ( elem ) {
|
1087
|
+
var parsleyItem = $( elem ).parsley();
|
1088
|
+
|
1089
|
+
// identify & remove item if same Parsley hash
|
1090
|
+
for ( var i = 0; i < this.items.length; i++ ) {
|
1091
|
+
if ( this.items[ i ].hash === parsleyItem.hash ) {
|
1092
|
+
this.items[ i ].destroy();
|
1093
|
+
this.items.splice( i, 1 );
|
1094
|
+
return true;
|
1095
|
+
}
|
1096
|
+
}
|
1097
|
+
|
1098
|
+
return false;
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
/**
|
1102
|
+
* Process each form field validation
|
1103
|
+
* Display errors, call custom onFormSubmit() function
|
1104
|
+
*
|
1105
|
+
* @method validate
|
1106
|
+
* @param {Object} event jQuery Event
|
1107
|
+
* @return {Boolean} Is form valid or not
|
1108
|
+
*/
|
1109
|
+
, validate: function ( event ) {
|
1110
|
+
var isValid = true;
|
1111
|
+
this.focusedField = false;
|
1112
|
+
|
1113
|
+
for ( var item = 0; item < this.items.length; item++ ) {
|
1114
|
+
if ( 'undefined' !== typeof this.items[ item ] && false === this.items[ item ].validate() ) {
|
1115
|
+
isValid = false;
|
1116
|
+
|
1117
|
+
if ( !this.focusedField && 'first' === this.options.focus || 'last' === this.options.focus ) {
|
1118
|
+
this.focusedField = this.items[ item ].$element;
|
1119
|
+
}
|
1120
|
+
}
|
1121
|
+
}
|
1122
|
+
|
1123
|
+
// form is invalid, focus an error field depending on focus policy
|
1124
|
+
if ( this.focusedField && !isValid ) {
|
1125
|
+
this.focusedField.focus();
|
1126
|
+
}
|
1127
|
+
|
1128
|
+
this.options.listeners.onFormSubmit( isValid, event, this );
|
1129
|
+
|
1130
|
+
return isValid;
|
1131
|
+
}
|
1132
|
+
|
1133
|
+
/**
|
1134
|
+
* Remove all errors ul under invalid fields
|
1135
|
+
*
|
1136
|
+
* @method removeErrors
|
1137
|
+
*/
|
1138
|
+
, removeErrors: function () {
|
1139
|
+
for ( var item = 0; item < this.items.length; item++ ) {
|
1140
|
+
this.items[ item ].parsley( 'reset' );
|
1141
|
+
}
|
1142
|
+
}
|
1143
|
+
|
1144
|
+
/**
|
1145
|
+
* destroy Parsley binded on the form and its fields
|
1146
|
+
*
|
1147
|
+
* @method destroy
|
1148
|
+
*/
|
1149
|
+
, destroy: function () {
|
1150
|
+
for ( var item = 0; item < this.items.length; item++ ) {
|
1151
|
+
this.items[ item ].destroy();
|
1152
|
+
}
|
1153
|
+
|
1154
|
+
this.$element.off( '.' + this.type ).removeData( this.type );
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
/**
|
1158
|
+
* reset Parsley binded on the form and its fields
|
1159
|
+
*
|
1160
|
+
* @method reset
|
1161
|
+
*/
|
1162
|
+
, reset: function () {
|
1163
|
+
for ( var item = 0; item < this.items.length; item++ ) {
|
1164
|
+
this.items[ item ].reset();
|
1165
|
+
}
|
1166
|
+
}
|
1167
|
+
};
|
1168
|
+
|
1169
|
+
/**
|
1170
|
+
* Parsley plugin definition
|
1171
|
+
* Provides an interface to access public Validator, ParsleyForm and ParsleyField functions
|
1172
|
+
*
|
1173
|
+
* @class Parsley
|
1174
|
+
* @constructor
|
1175
|
+
* @param {Mixed} Options. {Object} to configure Parsley or {String} method name to call a public class method
|
1176
|
+
* @param {Function} Callback function
|
1177
|
+
* @return {Mixed} public class method return
|
1178
|
+
*/
|
1179
|
+
$.fn.parsley = function ( option, fn ) {
|
1180
|
+
var options = $.extend( true, {}, $.fn.parsley.defaults, 'undefined' !== typeof window.ParsleyConfig ? window.ParsleyConfig : {}, option, this.data() )
|
1181
|
+
, newInstance = null;
|
1182
|
+
|
1183
|
+
function bind ( self, type ) {
|
1184
|
+
var parsleyInstance = $( self ).data( type );
|
1185
|
+
|
1186
|
+
// if data never binded or we want to clone a build (for radio & checkboxes), bind it right now!
|
1187
|
+
if ( !parsleyInstance ) {
|
1188
|
+
switch ( type ) {
|
1189
|
+
case 'parsleyForm':
|
1190
|
+
parsleyInstance = new ParsleyForm( self, options, 'parsleyForm' );
|
1191
|
+
break;
|
1192
|
+
case 'parsleyField':
|
1193
|
+
parsleyInstance = new ParsleyField( self, options, 'parsleyField' );
|
1194
|
+
break;
|
1195
|
+
case 'parsleyFieldMultiple':
|
1196
|
+
parsleyInstance = new ParsleyFieldMultiple( self, options, 'parsleyFieldMultiple' );
|
1197
|
+
break;
|
1198
|
+
default:
|
1199
|
+
return;
|
1200
|
+
}
|
1201
|
+
|
1202
|
+
$( self ).data( type, parsleyInstance );
|
1203
|
+
}
|
1204
|
+
|
1205
|
+
// here is our parsley public function accessor
|
1206
|
+
if ( 'string' === typeof option && 'function' === typeof parsleyInstance[ option ] ) {
|
1207
|
+
var response = parsleyInstance[ option ]( fn );
|
1208
|
+
|
1209
|
+
return 'undefined' !== typeof response ? response : $( self );
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
return parsleyInstance;
|
1213
|
+
}
|
1214
|
+
|
1215
|
+
// if a form elem is given, bind all its input children
|
1216
|
+
if ( $( this ).is( 'form' ) ) {
|
1217
|
+
newInstance = bind ( $( this ), 'parsleyForm' );
|
1218
|
+
|
1219
|
+
// if it is a Parsley supported single element, bind it too, except inputs type hidden
|
1220
|
+
// add here a return instance, cuz' we could call public methods on single elems with data[ option ]() above
|
1221
|
+
} else if ( $( this ).is( options.inputs ) && !$( this ).is( options.excluded ) ) {
|
1222
|
+
newInstance = bind( $( this ), !$( this ).is( 'input[type=radio], input[type=checkbox]' ) ? 'parsleyField' : 'parsleyFieldMultiple' );
|
1223
|
+
}
|
1224
|
+
|
1225
|
+
return 'function' === typeof fn ? fn() : newInstance;
|
1226
|
+
};
|
1227
|
+
|
1228
|
+
$.fn.parsley.Constructor = ParsleyForm;
|
1229
|
+
|
1230
|
+
/**
|
1231
|
+
* Parsley plugin configuration
|
1232
|
+
*
|
1233
|
+
* @property $.fn.parsley.defaults
|
1234
|
+
* @type {Object}
|
1235
|
+
*/
|
1236
|
+
$.fn.parsley.defaults = {
|
1237
|
+
// basic data-api overridable properties here..
|
1238
|
+
inputs: 'input, textarea, select' // Default supported inputs.
|
1239
|
+
, excluded: 'input[type=hidden], :disabled' // Do not validate input[type=hidden] & :disabled.
|
1240
|
+
, trigger: false // $.Event() that will trigger validation. eg: keyup, change..
|
1241
|
+
, animate: true // fade in / fade out error messages
|
1242
|
+
, animateDuration: 300 // fadein/fadout ms time
|
1243
|
+
, focus: 'first' // 'fist'|'last'|'none' which error field would have focus first on form validation
|
1244
|
+
, validationMinlength: 3 // If trigger validation specified, only if value.length > validationMinlength
|
1245
|
+
, successClass: 'parsley-success' // Class name on each valid input
|
1246
|
+
, errorClass: 'parsley-error' // Class name on each invalid input
|
1247
|
+
, errorMessage: false // Customize an unique error message showed if one constraint fails
|
1248
|
+
, validators: {} // Add your custom validators functions
|
1249
|
+
, messages: {} // Add your own error messages here
|
1250
|
+
|
1251
|
+
//some quite advanced configuration here..
|
1252
|
+
, validateIfUnchanged: false // false: validate once by field value change
|
1253
|
+
, errors: {
|
1254
|
+
classHandler: function ( elem, isRadioOrCheckbox ) {} // specify where parsley error-success classes are set
|
1255
|
+
, container: function ( elem, isRadioOrCheckbox ) {} // specify an elem where errors will be **apened**
|
1256
|
+
, errorsWrapper: '<ul></ul>' // do not set an id for this elem, it would have an auto-generated id
|
1257
|
+
, errorElem: '<li></li>' // each field constraint fail in an li
|
1258
|
+
}
|
1259
|
+
, listeners: {
|
1260
|
+
onFieldValidate: function ( elem, ParsleyForm ) { return false; } // Executed on validation. Return true to ignore field validation
|
1261
|
+
, onFormSubmit: function ( isFormValid, event, ParsleyForm ) {} // Executed once on form validation
|
1262
|
+
, onFieldError: function ( elem, constraints, ParsleyField ) {} // Executed when a field is detected as invalid
|
1263
|
+
, onFieldSuccess: function ( elem, constraints, ParsleyField ) {} // Executed when a field passes validation
|
1264
|
+
}
|
1265
|
+
};
|
1266
|
+
|
1267
|
+
/* PARSLEY auto-bind DATA-API + Global config retrieving
|
1268
|
+
* =================================================== */
|
1269
|
+
$( window ).on( 'load', function () {
|
1270
|
+
$( '[data-validate="parsley"]' ).each( function () {
|
1271
|
+
$( this ).parsley();
|
1272
|
+
} );
|
1273
|
+
} );
|
1274
|
+
|
1275
|
+
// This plugin works with jQuery or Zepto (with data extension built for Zepto.)
|
1276
|
+
}(window.jQuery || window.Zepto);
|