parsley-rails 1.2.4.0 → 2.0.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/README.md +6 -6
- data/lib/parsley-rails/version.rb +1 -1
- data/update.sh +6 -11
- data/vendor/assets/javascripts/parsley.i18n.bg.js +31 -41
- data/vendor/assets/javascripts/parsley.i18n.da.js +30 -40
- data/vendor/assets/javascripts/parsley.i18n.de.js +27 -35
- data/vendor/assets/javascripts/parsley.i18n.en.extra.js +6 -0
- data/vendor/assets/javascripts/parsley.i18n.en.js +30 -45
- data/vendor/assets/javascripts/parsley.i18n.es.js +29 -41
- data/vendor/assets/javascripts/parsley.i18n.fr.extra.js +6 -0
- data/vendor/assets/javascripts/parsley.i18n.fr.js +30 -41
- data/vendor/assets/javascripts/parsley.i18n.he.extra.js +6 -0
- data/vendor/assets/javascripts/parsley.i18n.he.js +31 -42
- data/vendor/assets/javascripts/parsley.i18n.id.js +30 -37
- data/vendor/assets/javascripts/parsley.i18n.it.extra.js +6 -0
- data/vendor/assets/javascripts/parsley.i18n.it.js +30 -37
- data/vendor/assets/javascripts/parsley.i18n.ja.js +30 -40
- data/vendor/assets/javascripts/parsley.i18n.nl.js +37 -41
- data/vendor/assets/javascripts/parsley.i18n.pl.js +33 -40
- data/vendor/assets/javascripts/parsley.i18n.pt-br.js +33 -0
- data/vendor/assets/javascripts/parsley.i18n.ru.js +38 -44
- data/vendor/assets/javascripts/parsley.i18n.sv.extra.js +6 -0
- data/vendor/assets/javascripts/parsley.i18n.sv.js +30 -42
- data/vendor/assets/javascripts/parsley.i18n.zh_cn.extra.js +6 -0
- data/vendor/assets/javascripts/parsley.i18n.zh_cn.js +30 -43
- data/vendor/assets/javascripts/parsley.js +2009 -1507
- data/vendor/assets/javascripts/parsley.remote.js +2351 -0
- metadata +16 -32
- data/vendor/assets/javascripts/parsley.extend.js +0 -167
- data/vendor/assets/javascripts/parsley.i18n.ar.js +0 -44
- data/vendor/assets/javascripts/parsley.i18n.ca.js +0 -40
- data/vendor/assets/javascripts/parsley.i18n.cs.js +0 -45
- data/vendor/assets/javascripts/parsley.i18n.cy.js +0 -38
- data/vendor/assets/javascripts/parsley.i18n.et.js +0 -46
- data/vendor/assets/javascripts/parsley.i18n.fa.js +0 -40
- data/vendor/assets/javascripts/parsley.i18n.fi.js +0 -40
- data/vendor/assets/javascripts/parsley.i18n.hr.js +0 -48
- data/vendor/assets/javascripts/parsley.i18n.hu.js +0 -44
- data/vendor/assets/javascripts/parsley.i18n.is.js +0 -32
- data/vendor/assets/javascripts/parsley.i18n.kr.js +0 -48
- data/vendor/assets/javascripts/parsley.i18n.lt.js +0 -40
- data/vendor/assets/javascripts/parsley.i18n.mn.js +0 -43
- data/vendor/assets/javascripts/parsley.i18n.no.js +0 -44
- data/vendor/assets/javascripts/parsley.i18n.pt_br.js +0 -42
- data/vendor/assets/javascripts/parsley.i18n.ro.js +0 -44
- data/vendor/assets/javascripts/parsley.i18n.th.js +0 -44
- data/vendor/assets/javascripts/parsley.i18n.tr.js +0 -48
- data/vendor/assets/javascripts/parsley.i18n.ua.js +0 -35
- data/vendor/assets/javascripts/parsley.i18n.vn.js +0 -35
- data/vendor/assets/javascripts/parsley.i18n.zh_tw.js +0 -39
- data/vendor/assets/javascripts/parsley.l10n.es.js +0 -183
@@ -1,40 +1,33 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
, maxwords: "Wpisz co najwyżej %s wyrazów"
|
35
|
-
, rangewords: "Wpisz od %s do %s wyrazów"
|
36
|
-
, greaterthan: "Podaj wartość większą od %s"
|
37
|
-
, lessthan: "Podaj wartość mniejszą od %s"
|
38
|
-
}
|
39
|
-
});
|
40
|
-
}(window.jQuery || window.Zepto));
|
1
|
+
// ParsleyConfig definition if not already set
|
2
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
3
|
+
window.ParsleyConfig.i18n = window.ParsleyConfig.i18n || {};
|
4
|
+
|
5
|
+
// Define then the messages
|
6
|
+
window.ParsleyConfig.i18n.pl = $.extend(window.ParsleyConfig.i18n.pl || {}, {
|
7
|
+
defaultMessage: "Wartość wygląda na nieprawidłową",
|
8
|
+
type: {
|
9
|
+
email: "Wpisz poprawny adres e-mail.",
|
10
|
+
url: "Wpisz poprawny adres URL.",
|
11
|
+
number: "Wpisz poprawną liczbę.",
|
12
|
+
integer: "Dozwolone jedynie liczby człkowite.",
|
13
|
+
digits: "Dozwolone jedynie cyfry.",
|
14
|
+
alphanum: "Dozwolone jedynie znaki alfanumeryczne."
|
15
|
+
},
|
16
|
+
notblank: "Pole nie może zostać puste",
|
17
|
+
required: "Pole jest wymagane.",
|
18
|
+
pattern: "Wartość wygląda na nieprawidłową.",
|
19
|
+
min: "Wartość powinna być większa od %s.",
|
20
|
+
max: "Wartość powinna być mniejsza od %s.",
|
21
|
+
range: "Wartość powinna być większa od %s i mniejsza od %s.",
|
22
|
+
minlength: "Ilość znaków powinna wynosić %s lub więcej.",
|
23
|
+
maxlength: "Ilość znaków powinna wynosić %s lub mniej.",
|
24
|
+
length: "Ilość znaków powinna wynosić od %s do %s.",
|
25
|
+
mincheck: "Musisz wybrać minimum %s opcji.",
|
26
|
+
maxcheck: "Możesz wybrać maksymalnie %s opcji.",
|
27
|
+
check: "Minimalnie możesz wybrać od %s do %s opcji",
|
28
|
+
equalto: "Wartości nie są identyczne"
|
29
|
+
});
|
30
|
+
|
31
|
+
// If file is loaded after Parsley main file, auto-load locale
|
32
|
+
if ('undefined' !== typeof window.ParsleyValidator)
|
33
|
+
window.ParsleyValidator.addCatalog('pl', window.ParsleyConfig.i18n.pl, true);
|
@@ -0,0 +1,33 @@
|
|
1
|
+
// ParsleyConfig definition if not already set
|
2
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
3
|
+
window.ParsleyConfig.i18n = window.ParsleyConfig.i18n || {};
|
4
|
+
|
5
|
+
// Define then the messages
|
6
|
+
window.ParsleyConfig.i18n['pt-br'] = $.extend(window.ParsleyConfig.i18n['pt-br'] || {}, {
|
7
|
+
defaultMessage: "This value seems to be invalid.",
|
8
|
+
type: {
|
9
|
+
email: "Esse campo deve ser um email válido.",
|
10
|
+
url: "Esse campo deve ser uma url válida.",
|
11
|
+
number: "Esse campo deve ser um número válido.",
|
12
|
+
integer: "Esse campo deve ser um inteiro válido.",
|
13
|
+
digits: "Esse campo deve conter apenas dígitos.",
|
14
|
+
alphanum: "Esse campo deve ser alfa numérico."
|
15
|
+
},
|
16
|
+
notblank: "Esse campo não pode ficar vazio.",
|
17
|
+
required: "Esse campo é obrigatório.",
|
18
|
+
pattern: "Esse campo parece estar inválido.",
|
19
|
+
min: "Esse campo deve ser maior ou igual a %s.",
|
20
|
+
max: "Esse campo deve ser menor ou igual a %s.",
|
21
|
+
range: "Esse campo deve estar entre %s e %s.",
|
22
|
+
minlength: "Esse campo é pequeno demais. Ele deveria ter %s characteres ou mais.",
|
23
|
+
maxlength: "Esse campo grande demais. Ele deveri ter %s characteres ou menos.",
|
24
|
+
length: "O tamanho desse campo é inválido. Ele deveria ter entre %s e %s characteres.",
|
25
|
+
mincheck: "Você deve escolher pelo menos %s opções.",
|
26
|
+
maxcheck: "Você deve escolher %s opções ou mais",
|
27
|
+
check: "Você deve escolher entre %s e %s opções.",
|
28
|
+
equalto: "Este valor deveria ser igual."
|
29
|
+
});
|
30
|
+
|
31
|
+
// If file is loaded after Parsley main file, auto-load locale
|
32
|
+
if ('undefined' !== typeof window.ParsleyValidator)
|
33
|
+
window.ParsleyValidator.addCatalog('pt-br', window.ParsleyConfig.i18n['pt-br'], true);
|
@@ -1,44 +1,38 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
, beforedate: "Дата должна быть до %s."
|
40
|
-
, afterdate: "Дата должна быть после %s."
|
41
|
-
, americandate: "В поле должна быть корректная дата в формате MM/DD/YYYY."
|
42
|
-
}
|
43
|
-
});
|
44
|
-
}(window.jQuery || window.Zepto));
|
1
|
+
//Parsley localization for Russian language
|
2
|
+
//Evgeni Makarov
|
3
|
+
//github.com/emakarov
|
4
|
+
|
5
|
+
|
6
|
+
// ParsleyConfig definition if not already set
|
7
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
8
|
+
window.ParsleyConfig.i18n = window.ParsleyConfig.i18n || {};
|
9
|
+
|
10
|
+
// Define then the messages
|
11
|
+
window.ParsleyConfig.i18n.ru = $.extend(window.ParsleyConfig.i18n.ru || {}, {
|
12
|
+
defaultMessage: "Некорректное значение.",
|
13
|
+
type: {
|
14
|
+
email: "Введите адрес электронной почты.",
|
15
|
+
url: "Введите URL адрес.",
|
16
|
+
number: "Введите число.",
|
17
|
+
integer: "Введите целое число.",
|
18
|
+
digits: "Введите только цифры.",
|
19
|
+
alphanum: "Введите буквенно-цифровое значение."
|
20
|
+
},
|
21
|
+
notblank: "Это поле должно быть заполнено.",
|
22
|
+
required: "Обязательное поле.",
|
23
|
+
pattern: "Это значение некорректно.",
|
24
|
+
min: "Это значение должно быть не менее чем %s.",
|
25
|
+
max: "Это значение должно быть не более чем %s.",
|
26
|
+
range: "Это значение должно быть в интервале от %s до %s.",
|
27
|
+
minlength: "Введите не менее %s символов.",
|
28
|
+
maxlength: "Введите не более %s символов.",
|
29
|
+
length: "Длина строки должна быть от %s до %s символов.",
|
30
|
+
mincheck: "Выберите не менее %s значений.",
|
31
|
+
maxcheck: "Выберите не более %s значений.",
|
32
|
+
check: "Выберите от %s до %s значений.",
|
33
|
+
equalto: "Это значение должно совпадать."
|
34
|
+
});
|
35
|
+
|
36
|
+
// If file is loaded after Parsley main file, auto-load locale
|
37
|
+
if ('undefined' !== typeof window.ParsleyValidator)
|
38
|
+
window.ParsleyValidator.addCatalog('ru', window.ParsleyConfig.i18n.ru, true);
|
@@ -1,45 +1,33 @@
|
|
1
|
-
|
2
|
-
* Swedish i18n.
|
3
|
-
*/
|
1
|
+
// ParsleyConfig definition if not already set
|
4
2
|
window.ParsleyConfig = window.ParsleyConfig || {};
|
3
|
+
window.ParsleyConfig.i18n = window.ParsleyConfig.i18n || {};
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
, maxcheck: "Maximalt %s värden får väljas."
|
32
|
-
, rangecheck: "Du måste göra minst %s och maximalt %s val."
|
33
|
-
, equalto: "Värdet måste vara lika."
|
5
|
+
// Define then the messages
|
6
|
+
window.ParsleyConfig.i18n.sv = $.extend(window.ParsleyConfig.i18n.sv || {}, {
|
7
|
+
defaultMessage: "Ogiltigt värde.",
|
8
|
+
type: {
|
9
|
+
email: "Ange en giltig e-postadress.",
|
10
|
+
url: "Ange en giltig URL.",
|
11
|
+
number: "Ange ett giltigt nummer.",
|
12
|
+
integer: "Ange ett heltal.",
|
13
|
+
digits: "Ange endast siffror.",
|
14
|
+
alphanum: "Ange endast bokstäver och siffror."
|
15
|
+
},
|
16
|
+
notblank: "Värdet får inte vara tomt.",
|
17
|
+
required: "Måste fyllas i.",
|
18
|
+
pattern: "Värdet är ej giltigt.",
|
19
|
+
min: "Värdet måste vara större än eller lika med %s.",
|
20
|
+
max: "Värdet måste vara mindre än eller lika med %s.",
|
21
|
+
range: "Värdet måste vara mellan %s och %s.",
|
22
|
+
minlength: "Värdet måste vara minst %s tecken.",
|
23
|
+
maxlength: "Värdet får maximalt innehålla %s tecken.",
|
24
|
+
length: "Värdet måste vara mellan %s och %s tecken.",
|
25
|
+
mincheck: "Minst %s val måste göras.",
|
26
|
+
maxcheck: "Maximalt %s val får göras.",
|
27
|
+
check: "Mellan %s och %s val måste göras.",
|
28
|
+
equalto: "Värdena måste vara lika."
|
29
|
+
});
|
34
30
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
, rangewords: "Fältet ska innehålla mellan %s och %s ord."
|
39
|
-
, greaterthan: "Värdet måste vara större än %s."
|
40
|
-
, lessthan: "Värdet måste vara mindre än %s."
|
41
|
-
, beforedate: "Datumet måste vara före %s."
|
42
|
-
, afterdate: "Datumet måste vara efter %s."
|
43
|
-
}
|
44
|
-
});
|
45
|
-
}(window.jQuery || window.Zepto));
|
31
|
+
// If file is loaded after Parsley main file, auto-load locale
|
32
|
+
if ('undefined' !== typeof window.ParsleyValidator)
|
33
|
+
window.ParsleyValidator.addCatalog('sv', window.ParsleyConfig.i18n.sv, true);
|
@@ -1,46 +1,33 @@
|
|
1
|
-
|
2
|
-
* /!\ This file is just an example template to create/update your own language file /!\
|
3
|
-
*/
|
4
|
-
|
1
|
+
// ParsleyConfig definition if not already set
|
5
2
|
window.ParsleyConfig = window.ParsleyConfig || {};
|
3
|
+
window.ParsleyConfig.i18n = window.ParsleyConfig.i18n || {};
|
6
4
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
, maxcheck: "你最多只能选择 %s 个选项"
|
33
|
-
, rangecheck: "你只能选择 %s 到 %s 个选项"
|
34
|
-
, equalto: "字段值应该和给定的值一样"
|
5
|
+
// Define then the messages
|
6
|
+
window.ParsleyConfig.i18n.zh_cn = $.extend(window.ParsleyConfig.i18n.zh_cn || {}, {
|
7
|
+
defaultMessage: "不正确的值",
|
8
|
+
type: {
|
9
|
+
email: "请输入一个有效的电子邮箱地址",
|
10
|
+
url: "请输入一个有效的链接",
|
11
|
+
number: "请输入正确的数字",
|
12
|
+
integer: "请输入正确的整数",
|
13
|
+
digits: "请输入正确的号码",
|
14
|
+
alphanum: "请输入字母或数字"
|
15
|
+
},
|
16
|
+
notblank: "请输入值",
|
17
|
+
required: "必填项",
|
18
|
+
pattern: "格式不正确",
|
19
|
+
min: "输入值请大于或等于 %s",
|
20
|
+
max: "输入值请小于或等于 %s",
|
21
|
+
range: "输入值应该在 %s 到 %s 之间",
|
22
|
+
minlength: "请输入至少 %s 个字符",
|
23
|
+
maxlength: "请输入至多 %s 个字符",
|
24
|
+
length: "字符长度应该在 %s 到 %s 之间",
|
25
|
+
mincheck: "请至少选择 %s 个选项",
|
26
|
+
maxcheck: "请选择不超过 %s 个选项",
|
27
|
+
check: "请选择 %s 到 %s 个选项",
|
28
|
+
equalto: "输入值不同"
|
29
|
+
});
|
35
30
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
, rangewords: "字段值应该有 %s 到 %s 个词"
|
40
|
-
, greaterthan: "字段值应该大于 %s"
|
41
|
-
, lessthan: "字段值应该小于 %s"
|
42
|
-
, beforedate: "字段值所表示的日期应该早于 %s."
|
43
|
-
, afterdate: "字段值所表示的日期应该晚于 %s."
|
44
|
-
}
|
45
|
-
});
|
46
|
-
}(window.jQuery || window.Zepto));
|
31
|
+
// If file is loaded after Parsley main file, auto-load locale
|
32
|
+
if ('undefined' !== typeof window.ParsleyValidator)
|
33
|
+
window.ParsleyValidator.addCatalog('zh_cn', window.ParsleyConfig.i18n.zh_cn, true);
|
@@ -1,1595 +1,2097 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
/*!
|
2
|
+
* Parsleyjs
|
3
|
+
* Guillaume Potier - <guillaume@wisembly.com>
|
4
|
+
* Version 2.0.0 - built Sat Apr 19 2014 17:29:18
|
5
|
+
* MIT Licensed
|
6
|
+
*
|
5
7
|
*/
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
, phone: "This value should be a valid phone number."
|
8
|
+
!(function($) {
|
9
|
+
var ParsleyUtils = {
|
10
|
+
// Parsley DOM-API
|
11
|
+
// returns object from dom attributes and values
|
12
|
+
// if attr is given, returns bool if attr present in DOM or not
|
13
|
+
attr: function ($element, namespace, checkAttr) {
|
14
|
+
var
|
15
|
+
attribute,
|
16
|
+
obj = {},
|
17
|
+
regex = new RegExp('^' + namespace, 'i');
|
18
|
+
if ('undefined' === typeof $element || 'undefined' === typeof $element[0])
|
19
|
+
return {};
|
20
|
+
for (var i in $element[0].attributes) {
|
21
|
+
attribute = $element[0].attributes[i];
|
22
|
+
if ('undefined' !== typeof attribute && null !== attribute && attribute.specified && regex.test(attribute.name)) {
|
23
|
+
if ('undefined' !== typeof checkAttr && new RegExp(checkAttr + '$', 'i').test(attribute.name))
|
24
|
+
return true;
|
25
|
+
obj[this.camelize(attribute.name.replace(namespace, ''))] = this.deserializeValue(attribute.value);
|
36
26
|
}
|
37
|
-
|
38
|
-
|
39
|
-
, required: "This value is required."
|
40
|
-
, regexp: "This value seems to be invalid."
|
41
|
-
, min: "This value should be greater than or equal to %s."
|
42
|
-
, max: "This value should be lower than or equal to %s."
|
43
|
-
, range: "This value should be between %s and %s."
|
44
|
-
, minlength: "This value is too short. It should have %s characters or more."
|
45
|
-
, maxlength: "This value is too long. It should have %s characters or less."
|
46
|
-
, rangelength: "This value length is invalid. It should be between %s and %s characters long."
|
47
|
-
, mincheck: "You must select at least %s choices."
|
48
|
-
, maxcheck: "You must select %s choices or less."
|
49
|
-
, rangecheck: "You must select between %s and %s choices."
|
50
|
-
, equalto: "This value should be the same."
|
27
|
+
}
|
28
|
+
return 'undefined' === typeof checkAttr ? obj : false;
|
51
29
|
},
|
52
|
-
|
53
|
-
|
30
|
+
setAttr: function ($element, namespace, attr, value) {
|
31
|
+
$element[0].setAttribute(this.dasherize(namespace + attr), String(value));
|
32
|
+
},
|
33
|
+
// Recursive object / array getter
|
34
|
+
get: function (obj, path) {
|
35
|
+
var
|
36
|
+
i = 0,
|
37
|
+
paths = (path || '').split('.');
|
38
|
+
while (this.isObject(obj) || this.isArray(obj)) {
|
39
|
+
obj = obj[paths[i++]];
|
40
|
+
if (i === paths.length)
|
41
|
+
return obj;
|
42
|
+
}
|
43
|
+
return undefined;
|
44
|
+
},
|
45
|
+
hash: function (length) {
|
46
|
+
return String(Math.random()).substring(2, length ? length + 2 : 9);
|
47
|
+
},
|
48
|
+
/** Third party functions **/
|
49
|
+
// Underscore isArray
|
50
|
+
isArray: function (mixed) {
|
51
|
+
return Object.prototype.toString.call(mixed) === '[object Array]';
|
52
|
+
},
|
53
|
+
// Underscore isObject
|
54
|
+
isObject: function (mixed) {
|
55
|
+
return mixed === Object(mixed);
|
56
|
+
},
|
57
|
+
// Zepto deserialize function
|
58
|
+
deserializeValue: function (value) {
|
59
|
+
var num;
|
60
|
+
try {
|
61
|
+
return value ?
|
62
|
+
value == "true" ||
|
63
|
+
(value == "false" ? false :
|
64
|
+
value == "null" ? null :
|
65
|
+
!isNaN(num = Number(value)) ? num :
|
66
|
+
/^[\[\{]/.test(value) ? $.parseJSON(value) :
|
67
|
+
value)
|
68
|
+
: value;
|
69
|
+
} catch (e) { return value; }
|
70
|
+
},
|
71
|
+
// Zepto camelize function
|
72
|
+
camelize: function (str) {
|
73
|
+
return str.replace(/-+(.)?/g, function(match, chr) {
|
74
|
+
return chr ? chr.toUpperCase() : '';
|
75
|
+
});
|
76
|
+
},
|
77
|
+
// Zepto dasherize function
|
78
|
+
dasherize: function (str) {
|
79
|
+
return str.replace(/::/g, '/')
|
80
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
|
81
|
+
.replace(/([a-z\d])([A-Z])/g, '$1_$2')
|
82
|
+
.replace(/_/g, '-')
|
83
|
+
.toLowerCase();
|
84
|
+
}
|
85
|
+
};
|
86
|
+
// All these options could be overriden and specified directly in DOM using
|
87
|
+
// `data-parsley-` default DOM-API
|
88
|
+
// eg: `inputs` can be set in DOM using `data-parsley-inputs="input, textarea"`
|
89
|
+
// eg: `data-parsley-stop-on-first-failing-constraint="false"`
|
90
|
+
var ParsleyDefaults = {
|
91
|
+
// ### General
|
92
|
+
// Default data-namespace for DOM API
|
93
|
+
namespace: 'data-parsley-',
|
94
|
+
// Supported inputs by default
|
95
|
+
inputs: 'input, textarea, select',
|
96
|
+
// Excluded inputs by default
|
97
|
+
excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]',
|
98
|
+
// Stop validating field on highest priority failing constraint
|
99
|
+
priorityEnabled: true,
|
100
|
+
// ### UI
|
101
|
+
// Enable\Disable error messages
|
102
|
+
uiEnabled: true,
|
103
|
+
// Key events threshold before validation
|
104
|
+
validationThreshold: 3,
|
105
|
+
// Focused field on form validation error. 'fist'|'last'|'none'
|
106
|
+
focus: 'first',
|
107
|
+
// `$.Event()` that will trigger validation. eg: `keyup`, `change`..
|
108
|
+
trigger: false,
|
109
|
+
// Class that would be added on every failing validation Parsley field
|
110
|
+
errorClass: 'parsley-error',
|
111
|
+
// Same for success validation
|
112
|
+
successClass: 'parsley-success',
|
113
|
+
// Return the `$element` that will receive these above success or error classes
|
114
|
+
// Could also be (and given directly from DOM) a valid selector like `'#div'`
|
115
|
+
classHandler: function (ParsleyField) {},
|
116
|
+
// Return the `$element` where errors will be appended
|
117
|
+
// Could also be (and given directly from DOM) a valid selector like `'#div'`
|
118
|
+
errorsContainer: function (ParsleyField) {},
|
119
|
+
// ul elem that would receive errors' list
|
120
|
+
errorsWrapper: '<ul class="parsley-errors-list"></ul>',
|
121
|
+
// li elem that would receive error message
|
122
|
+
errorTemplate: '<li></li>'
|
54
123
|
};
|
55
124
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
,
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
return that.notnull().validate( val ) && that.notblank().validate( val );
|
99
|
-
}
|
100
|
-
, priority: 512
|
101
|
-
}
|
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
|
-
}
|
136
|
-
|
137
|
-
// test regExp if not null
|
138
|
-
return '' !== val ? regExp.test( val ) : false;
|
139
|
-
}
|
140
|
-
, priority: 256
|
141
|
-
}
|
142
|
-
}
|
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
|
-
}
|
150
|
-
}
|
151
|
-
, minlength: function () {
|
152
|
-
return {
|
153
|
-
validate: function ( val, min ) {
|
154
|
-
return val.length >= min;
|
155
|
-
}
|
156
|
-
, priority: 32
|
157
|
-
}
|
158
|
-
}
|
159
|
-
, maxlength: function () {
|
160
|
-
return {
|
161
|
-
validate: function ( val, max ) {
|
162
|
-
return val.length <= max;
|
163
|
-
}
|
164
|
-
, priority: 32
|
165
|
-
}
|
166
|
-
}
|
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
|
-
}
|
175
|
-
}
|
176
|
-
, min: function () {
|
177
|
-
return {
|
178
|
-
validate: function ( val, min ) {
|
179
|
-
return Number( val ) >= min;
|
180
|
-
}
|
181
|
-
, priority: 32
|
182
|
-
}
|
183
|
-
}
|
184
|
-
, max: function () {
|
185
|
-
return {
|
186
|
-
validate: function ( val, max ) {
|
187
|
-
return Number( val ) <= max;
|
188
|
-
}
|
189
|
-
, priority: 32
|
190
|
-
}
|
191
|
-
}
|
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
|
-
}
|
200
|
-
}
|
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
|
-
}
|
209
|
-
}
|
210
|
-
, remote: function () {
|
211
|
-
return {
|
212
|
-
validate: function ( val, url, self ) {
|
213
|
-
var result = null
|
214
|
-
, data = {}
|
215
|
-
, dataType = {};
|
216
|
-
|
217
|
-
data[ self.$element.attr( 'name' ) ] = val;
|
218
|
-
|
219
|
-
if ( 'undefined' !== typeof self.options.remoteDatatype )
|
220
|
-
dataType = { dataType: self.options.remoteDatatype };
|
221
|
-
|
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
|
-
}
|
227
|
-
|
228
|
-
if (false === isConstraintValid) {
|
229
|
-
self.options.listeners.onFieldError( self.element, self.constraints, self );
|
230
|
-
} else if (true === isConstraintValid && false === self.options.listeners.onFieldSuccess( self.element, self.constraints, self )) {
|
231
|
-
// if onFieldSuccess returns (bool) false, consider that field is invalid
|
232
|
-
isConstraintValid = false;
|
233
|
-
}
|
234
|
-
|
235
|
-
self.updtConstraint( { name: 'remote', valid: isConstraintValid }, message );
|
236
|
-
self.manageValidationResult();
|
237
|
-
};
|
238
|
-
|
239
|
-
// transform string response into object
|
240
|
-
var handleResponse = function ( response ) {
|
241
|
-
if ( 'object' === typeof response ) {
|
242
|
-
return response;
|
243
|
-
}
|
244
|
-
|
245
|
-
try {
|
246
|
-
response = $.parseJSON( response );
|
247
|
-
} catch ( err ) {}
|
248
|
-
|
249
|
-
return response;
|
250
|
-
}
|
251
|
-
|
252
|
-
var manageErrorMessage = function ( response ) {
|
253
|
-
return 'object' === typeof response && null !== response ? ( 'undefined' !== typeof response.error ? response.error : ( 'undefined' !== typeof response.message ? response.message : null ) ) : null;
|
254
|
-
}
|
255
|
-
|
256
|
-
$.ajax( $.extend( {}, {
|
257
|
-
url: url
|
258
|
-
, data: data
|
259
|
-
, type: self.options.remoteMethod || 'GET'
|
260
|
-
, success: function ( response ) {
|
261
|
-
response = handleResponse( response );
|
262
|
-
manage( 1 === response || true === response || ( 'object' === typeof response && null !== response && 'undefined' !== typeof response.success ), manageErrorMessage( response )
|
263
|
-
);
|
264
|
-
}
|
265
|
-
, error: function ( response ) {
|
266
|
-
response = handleResponse( response );
|
267
|
-
manage( false, manageErrorMessage( response ) );
|
268
|
-
}
|
269
|
-
}, dataType ) );
|
270
|
-
|
271
|
-
return result;
|
272
|
-
}
|
273
|
-
, priority: 64
|
274
|
-
}
|
275
|
-
}
|
276
|
-
|
277
|
-
/**
|
278
|
-
* Aliases for checkboxes constraints
|
279
|
-
*/
|
280
|
-
, mincheck: function () {
|
281
|
-
var that = this;
|
282
|
-
return {
|
283
|
-
validate: function ( obj, val ) { return that.minlength().validate( obj, val ) }
|
284
|
-
, priority: 32
|
285
|
-
}
|
286
|
-
}
|
287
|
-
, maxcheck: function () {
|
288
|
-
var that = this;
|
289
|
-
return {
|
290
|
-
validate: function ( obj, val ) { return that.maxlength().validate( obj, val ) }
|
291
|
-
, priority: 32
|
292
|
-
}
|
293
|
-
}
|
294
|
-
, rangecheck: function () {
|
295
|
-
var that = this;
|
296
|
-
return {
|
297
|
-
validate: function ( obj, arrayRange ) { return that.rangelength().validate( obj, arrayRange ) }
|
298
|
-
, priority: 32
|
299
|
-
}
|
125
|
+
var ParsleyAbstract = function() {};
|
126
|
+
ParsleyAbstract.prototype = {
|
127
|
+
asyncSupport: false,
|
128
|
+
actualizeOptions: function () {
|
129
|
+
this.options = this.OptionsFactory.get(this);
|
130
|
+
return this;
|
131
|
+
},
|
132
|
+
// ParsleyValidator validate proxy function . Could be replaced by third party scripts
|
133
|
+
validateThroughValidator: function (value, constraints, priority) {
|
134
|
+
return window.ParsleyValidator.validate.apply(window.ParsleyValidator, [value, constraints, priority]);
|
135
|
+
},
|
136
|
+
// Subscribe an event and a handler for a specific field or a specific form
|
137
|
+
// If on a ParsleyForm instance, it will be attached to form instance and also
|
138
|
+
// To every field instance for this form
|
139
|
+
subscribe: function (name, fn) {
|
140
|
+
$.listenTo(this, name.toLowerCase(), fn);
|
141
|
+
return this;
|
142
|
+
},
|
143
|
+
// Same as subscribe above. Unsubscribe an event for field, or form + its fields
|
144
|
+
unsubscribe: function (name) {
|
145
|
+
$.unsubscribeTo(this, name.toLowerCase());
|
146
|
+
return this;
|
147
|
+
},
|
148
|
+
// Reset UI
|
149
|
+
reset: function () {
|
150
|
+
// Field case: just emit a reset event for UI
|
151
|
+
if ('ParsleyForm' !== this.__class__)
|
152
|
+
return $.emit('parsley:field:reset', this);
|
153
|
+
// Form case: emit a reset event for each field
|
154
|
+
for (var i = 0; i < this.fields.length; i++)
|
155
|
+
$.emit('parsley:field:reset', this.fields[i]);
|
156
|
+
$.emit('parsley:form:reset', this);
|
157
|
+
},
|
158
|
+
// Destroy Parsley instance (+ UI)
|
159
|
+
destroy: function () {
|
160
|
+
// Field case: emit destroy event to clean UI and then destroy stored instance
|
161
|
+
if ('ParsleyForm' !== this.__class__) {
|
162
|
+
this.$element.removeData('Parsley');
|
163
|
+
this.$element.removeData('ParsleyFieldMultiple');
|
164
|
+
$.emit('parsley:field:destroy', this);
|
165
|
+
return;
|
300
166
|
}
|
167
|
+
// Form case: destroy all its fields and then destroy stored instance
|
168
|
+
for (var i = 0; i < this.fields.length; i++)
|
169
|
+
this.fields[i].destroy();
|
170
|
+
this.$element.removeData('Parsley');
|
171
|
+
$.emit('parsley:form:destroy', this);
|
301
172
|
}
|
302
|
-
|
173
|
+
};
|
174
|
+
/*!
|
175
|
+
* validator.js
|
176
|
+
* Guillaume Potier - <guillaume@wisembly.com>
|
177
|
+
* Version 0.5.8 - built Sun Mar 16 2014 17:18:21
|
178
|
+
* MIT Licensed
|
179
|
+
*
|
180
|
+
*/
|
181
|
+
( function ( exports ) {
|
182
|
+
/**
|
183
|
+
* Validator
|
184
|
+
*/
|
185
|
+
var Validator = function ( options ) {
|
186
|
+
this.__class__ = 'Validator';
|
187
|
+
this.__version__ = '0.5.8';
|
188
|
+
this.options = options || {};
|
189
|
+
this.bindingKey = this.options.bindingKey || '_validatorjsConstraint';
|
190
|
+
return this;
|
191
|
+
};
|
192
|
+
Validator.prototype = {
|
193
|
+
constructor: Validator,
|
303
194
|
/*
|
304
|
-
*
|
195
|
+
* Validate string: validate( string, Assert, string ) || validate( string, [ Assert, Assert ], [ string, string ] )
|
196
|
+
* Validate object: validate( object, Constraint, string ) || validate( object, Constraint, [ string, string ] )
|
197
|
+
* Validate binded object: validate( object, string ) || validate( object, [ string, string ] )
|
305
198
|
*/
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
199
|
+
validate: function ( objectOrString, AssertsOrConstraintOrGroup, group ) {
|
200
|
+
if ( 'string' !== typeof objectOrString && 'object' !== typeof objectOrString )
|
201
|
+
throw new Error( 'You must validate an object or a string' );
|
202
|
+
// string / array validation
|
203
|
+
if ( 'string' === typeof objectOrString || _isArray(objectOrString) )
|
204
|
+
return this._validateString( objectOrString, AssertsOrConstraintOrGroup, group );
|
205
|
+
// binded object validation
|
206
|
+
if ( this.isBinded( objectOrString ) )
|
207
|
+
return this._validateBindedObject( objectOrString, AssertsOrConstraintOrGroup );
|
208
|
+
// regular object validation
|
209
|
+
return this._validateObject( objectOrString, AssertsOrConstraintOrGroup, group );
|
210
|
+
},
|
211
|
+
bind: function ( object, constraint ) {
|
212
|
+
if ( 'object' !== typeof object )
|
213
|
+
throw new Error( 'Must bind a Constraint to an object' );
|
214
|
+
object[ this.bindingKey ] = new Constraint( constraint );
|
215
|
+
return this;
|
216
|
+
},
|
217
|
+
unbind: function ( object ) {
|
218
|
+
if ( 'undefined' === typeof object._validatorjsConstraint )
|
219
|
+
return this;
|
220
|
+
delete object[ this.bindingKey ];
|
221
|
+
return this;
|
222
|
+
},
|
223
|
+
isBinded: function ( object ) {
|
224
|
+
return 'undefined' !== typeof object[ this.bindingKey ];
|
225
|
+
},
|
226
|
+
getBinded: function ( object ) {
|
227
|
+
return this.isBinded( object ) ? object[ this.bindingKey ] : null;
|
228
|
+
},
|
229
|
+
_validateString: function ( string, assert, group ) {
|
230
|
+
var result, failures = [];
|
231
|
+
if ( !_isArray( assert ) )
|
232
|
+
assert = [ assert ];
|
233
|
+
for ( var i = 0; i < assert.length; i++ ) {
|
234
|
+
if ( ! ( assert[ i ] instanceof Assert) )
|
235
|
+
throw new Error( 'You must give an Assert or an Asserts array to validate a string' );
|
236
|
+
result = assert[ i ].check( string, group );
|
237
|
+
if ( result instanceof Violation )
|
238
|
+
failures.push( result );
|
239
|
+
}
|
240
|
+
return failures.length ? failures : true;
|
241
|
+
},
|
242
|
+
_validateObject: function ( object, constraint, group ) {
|
243
|
+
if ( 'object' !== typeof constraint )
|
244
|
+
throw new Error( 'You must give a constraint to validate an object' );
|
245
|
+
if ( constraint instanceof Constraint )
|
246
|
+
return constraint.check( object, group );
|
247
|
+
return new Constraint( constraint ).check( object, group );
|
248
|
+
},
|
249
|
+
_validateBindedObject: function ( object, group ) {
|
250
|
+
return object[ this.bindingKey ].check( object, group );
|
318
251
|
}
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
252
|
+
};
|
253
|
+
Validator.errorCode = {
|
254
|
+
must_be_a_string: 'must_be_a_string',
|
255
|
+
must_be_an_array: 'must_be_an_array',
|
256
|
+
must_be_a_number: 'must_be_a_number',
|
257
|
+
must_be_a_string_or_array: 'must_be_a_string_or_array'
|
258
|
+
};
|
259
|
+
/**
|
260
|
+
* Constraint
|
261
|
+
*/
|
262
|
+
var Constraint = function ( data, options ) {
|
263
|
+
this.__class__ = 'Constraint';
|
264
|
+
this.options = options || {};
|
265
|
+
this.nodes = {};
|
266
|
+
if ( data ) {
|
267
|
+
try {
|
268
|
+
this._bootstrap( data );
|
269
|
+
} catch ( err ) {
|
270
|
+
throw new Error( 'Should give a valid mapping object to Constraint', err, data );
|
336
271
|
}
|
337
|
-
|
338
|
-
return 'string' === typeof message ? message.replace( new RegExp( '%s', 'i' ), args ) : '';
|
339
272
|
}
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
if (window.console && window.console.warn) {
|
362
|
-
window.console.warn( 'Validator `' + name + '` should have a priority. Default priority 32 given' );
|
273
|
+
return this;
|
274
|
+
};
|
275
|
+
Constraint.prototype = {
|
276
|
+
constructor: Constraint,
|
277
|
+
check: function ( object, group ) {
|
278
|
+
var result, failures = {};
|
279
|
+
// check all constraint nodes if strict validation enabled. Else, only object nodes that have a constraint
|
280
|
+
for ( var property in this.options.strict ? this.nodes : object ) {
|
281
|
+
if ( this.options.strict ? this.has( property, object ) : this.has( property ) ) {
|
282
|
+
result = this._check( property, object[ property ], group );
|
283
|
+
// check returned an array of Violations or an object mapping Violations
|
284
|
+
if ( ( _isArray( result ) && result.length > 0 ) || ( !_isArray( result ) && !_isEmptyObject( result ) ) )
|
285
|
+
failures[ property ] = result;
|
286
|
+
// in strict mode, get a violation for each constraint node not in object
|
287
|
+
} else if ( this.options.strict ) {
|
288
|
+
try {
|
289
|
+
// we trigger here a HaveProperty Assert violation to have uniform Violation object in the end
|
290
|
+
new Assert().HaveProperty( property ).validate( object );
|
291
|
+
} catch ( violation ) {
|
292
|
+
failures[ property ] = violation;
|
293
|
+
}
|
363
294
|
}
|
364
295
|
}
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
*
|
372
|
-
* @method addMessage
|
373
|
-
* @param {String} name Message name. Will automatically be binded to validator with same name
|
374
|
-
* @param {String} message Message
|
375
|
-
*/
|
376
|
-
, addMessage: function ( key, message, type ) {
|
377
|
-
|
378
|
-
if ( 'undefined' !== typeof type && true === type ) {
|
379
|
-
this.messages.type[ key ] = message;
|
380
|
-
return;
|
296
|
+
return _isEmptyObject(failures) ? true : failures;
|
297
|
+
},
|
298
|
+
add: function ( node, object ) {
|
299
|
+
if ( object instanceof Assert || ( _isArray( object ) && object[ 0 ] instanceof Assert ) ) {
|
300
|
+
this.nodes[ node ] = object;
|
301
|
+
return this;
|
381
302
|
}
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
for ( var i in message ) {
|
386
|
-
this.messages.type[ i ] = message[ i ];
|
387
|
-
}
|
388
|
-
|
389
|
-
return;
|
303
|
+
if ( 'object' === typeof object && !_isArray( object ) ) {
|
304
|
+
this.nodes[ node ] = object instanceof Constraint ? object : new Constraint( object );
|
305
|
+
return this;
|
390
306
|
}
|
391
|
-
|
392
|
-
|
307
|
+
throw new Error( 'Should give an Assert, an Asserts array, a Constraint', object );
|
308
|
+
},
|
309
|
+
has: function ( node, nodes ) {
|
310
|
+
nodes = 'undefined' !== typeof nodes ? nodes : this.nodes;
|
311
|
+
return 'undefined' !== typeof nodes[ node ];
|
312
|
+
},
|
313
|
+
get: function ( node, placeholder ) {
|
314
|
+
return this.has( node ) ? this.nodes[ node ] : placeholder || null;
|
315
|
+
},
|
316
|
+
remove: function ( node ) {
|
317
|
+
var _nodes = [];
|
318
|
+
for ( var i in this.nodes )
|
319
|
+
if ( i !== node )
|
320
|
+
_nodes[ i ] = this.nodes[ i ];
|
321
|
+
this.nodes = _nodes;
|
322
|
+
return this;
|
323
|
+
},
|
324
|
+
_bootstrap: function ( data ) {
|
325
|
+
if ( data instanceof Constraint )
|
326
|
+
return this.nodes = data.nodes;
|
327
|
+
for ( var node in data )
|
328
|
+
this.add( node, data[ node ] );
|
329
|
+
},
|
330
|
+
_check: function ( node, value, group ) {
|
331
|
+
// Assert
|
332
|
+
if ( this.nodes[ node ] instanceof Assert )
|
333
|
+
return this._checkAsserts( value, [ this.nodes[ node ] ], group );
|
334
|
+
// Asserts
|
335
|
+
if ( _isArray( this.nodes[ node ] ) )
|
336
|
+
return this._checkAsserts( value, this.nodes[ node ], group );
|
337
|
+
// Constraint -> check api
|
338
|
+
if ( this.nodes[ node ] instanceof Constraint )
|
339
|
+
return this.nodes[ node ].check( value, group );
|
340
|
+
throw new Error( 'Invalid node', this.nodes[ node ] );
|
341
|
+
},
|
342
|
+
_checkAsserts: function ( value, asserts, group ) {
|
343
|
+
var result, failures = [];
|
344
|
+
for ( var i = 0; i < asserts.length; i++ ) {
|
345
|
+
result = asserts[ i ].check( value, group );
|
346
|
+
if ( 'undefined' !== typeof result && true !== result )
|
347
|
+
failures.push( result );
|
348
|
+
// Some asserts (Collection for example) could return an object
|
349
|
+
// if ( result && ! ( result instanceof Violation ) )
|
350
|
+
// return result;
|
351
|
+
//
|
352
|
+
// // Vast assert majority return Violation
|
353
|
+
// if ( result instanceof Violation )
|
354
|
+
// failures.push( result );
|
355
|
+
}
|
356
|
+
return failures;
|
393
357
|
}
|
394
358
|
};
|
395
|
-
|
396
|
-
|
397
|
-
|
359
|
+
/**
|
360
|
+
* Violation
|
361
|
+
*/
|
362
|
+
var Violation = function ( assert, value, violation ) {
|
363
|
+
this.__class__ = 'Violation';
|
364
|
+
if ( ! ( assert instanceof Assert ) )
|
365
|
+
throw new Error( 'Should give an assertion implementing the Assert interface' );
|
366
|
+
this.assert = assert;
|
367
|
+
this.value = value;
|
368
|
+
if ( 'undefined' !== typeof violation )
|
369
|
+
this.violation = violation;
|
398
370
|
};
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
this.
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
this.ulError = '#' + this.hash;
|
420
|
-
this.ulTemplate = $( this.options.errors.errorsWrapper ).attr( 'id', this.hash ).addClass( 'parsley-error-list' );
|
421
|
-
}
|
422
|
-
|
423
|
-
/**
|
424
|
-
* Remove li / ul error
|
425
|
-
*
|
426
|
-
* @method removeError
|
427
|
-
* @param {String} constraintName Method Name
|
428
|
-
* @return ParsleyUI
|
429
|
-
*/
|
430
|
-
, removeError: function ( constraintName ) {
|
431
|
-
var liError = this.ulError + ' .' + constraintName
|
432
|
-
, that = this;
|
433
|
-
|
434
|
-
this.options.animate ? $( liError ).fadeOut( this.options.animateDuration, function () {
|
435
|
-
$( this ).remove();
|
436
|
-
|
437
|
-
if ( that.ulError && $( that.ulError ).children().length === 0 ) {
|
438
|
-
that.removeErrors();
|
439
|
-
} } ) : $( liError ).remove();
|
440
|
-
|
441
|
-
return this;
|
371
|
+
Violation.prototype = {
|
372
|
+
show: function () {
|
373
|
+
var show = {
|
374
|
+
assert: this.assert.__class__,
|
375
|
+
value: this.value
|
376
|
+
};
|
377
|
+
if ( this.violation )
|
378
|
+
show.violation = this.violation;
|
379
|
+
return show;
|
380
|
+
},
|
381
|
+
__toString: function () {
|
382
|
+
if ( 'undefined' !== typeof this.violation )
|
383
|
+
this.violation = '", ' + this.getViolation().constraint + ' expected was ' + this.getViolation().expected;
|
384
|
+
return this.assert.__class__ + ' assert failed for "' + this.value + this.violation || '';
|
385
|
+
},
|
386
|
+
getViolation: function () {
|
387
|
+
var constraint, expected;
|
388
|
+
for ( constraint in this.violation )
|
389
|
+
expected = this.violation[ constraint ];
|
390
|
+
return { constraint: constraint, expected: expected };
|
442
391
|
}
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
392
|
+
};
|
393
|
+
/**
|
394
|
+
* Assert
|
395
|
+
*/
|
396
|
+
var Assert = function ( group ) {
|
397
|
+
this.__class__ = 'Assert';
|
398
|
+
this.__parentClass__ = this.__class__;
|
399
|
+
this.groups = [];
|
400
|
+
if ( 'undefined' !== typeof group )
|
401
|
+
this.addGroup( group );
|
402
|
+
return this;
|
403
|
+
};
|
404
|
+
Assert.prototype = {
|
405
|
+
construct: Assert,
|
406
|
+
check: function ( value, group ) {
|
407
|
+
if ( group && !this.hasGroup( group ) )
|
408
|
+
return;
|
409
|
+
if ( !group && this.hasGroups() )
|
410
|
+
return;
|
411
|
+
try {
|
412
|
+
return this.validate( value, group );
|
413
|
+
} catch ( violation ) {
|
414
|
+
return violation;
|
456
415
|
}
|
457
|
-
|
416
|
+
},
|
417
|
+
hasGroup: function ( group ) {
|
418
|
+
if ( _isArray( group ) )
|
419
|
+
return this.hasOneOf( group );
|
420
|
+
// All Asserts respond to "Any" group
|
421
|
+
if ( 'Any' === group )
|
422
|
+
return true;
|
423
|
+
// Asserts with no group also respond to "Default" group. Else return false
|
424
|
+
if ( !this.hasGroups() )
|
425
|
+
return 'Default' === group;
|
426
|
+
return -1 !== this.groups.indexOf( group );
|
427
|
+
},
|
428
|
+
hasOneOf: function ( groups ) {
|
429
|
+
for ( var i = 0; i < groups.length; i++ )
|
430
|
+
if ( this.hasGroup( groups[ i ] ) )
|
431
|
+
return true;
|
432
|
+
return false;
|
433
|
+
},
|
434
|
+
hasGroups: function () {
|
435
|
+
return this.groups.length > 0;
|
436
|
+
},
|
437
|
+
addGroup: function ( group ) {
|
438
|
+
if ( _isArray( group ) )
|
439
|
+
return this.addGroups( group );
|
440
|
+
if ( !this.hasGroup( group ) )
|
441
|
+
this.groups.push( group );
|
458
442
|
return this;
|
459
|
-
}
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
* @return ParsleyUI
|
467
|
-
*/
|
468
|
-
, updateError: function ( error ) {
|
469
|
-
for ( var constraint in error ) {
|
470
|
-
if ( error[ constraint ] !== $( this.ulError + " > li." + constraint ).html() ) {
|
471
|
-
this.removeError( constraint ).addError( error );
|
472
|
-
}
|
473
|
-
}
|
474
|
-
|
443
|
+
},
|
444
|
+
removeGroup: function ( group ) {
|
445
|
+
var _groups = [];
|
446
|
+
for ( var i = 0; i < this.groups.length; i++ )
|
447
|
+
if ( group !== this.groups[ i ] )
|
448
|
+
_groups.push( this.groups[ i ] );
|
449
|
+
this.groups = _groups;
|
475
450
|
return this;
|
476
|
-
}
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
*
|
481
|
-
* @method removeErrors
|
482
|
-
* @return ParsleyUI
|
483
|
-
*/
|
484
|
-
, removeErrors: function () {
|
485
|
-
this.options.animate ? $( this.ulError ).fadeOut( this.options.animateDuration, function () { $( this ).remove(); } ) : $( this.ulError ).remove();
|
486
|
-
|
451
|
+
},
|
452
|
+
addGroups: function ( groups ) {
|
453
|
+
for ( var i = 0; i < groups.length; i++ )
|
454
|
+
this.addGroup( groups[ i ] );
|
487
455
|
return this;
|
488
|
-
}
|
489
|
-
|
456
|
+
},
|
490
457
|
/**
|
491
|
-
*
|
492
|
-
*
|
493
|
-
* @method reset
|
494
|
-
* @return ParsleyUI
|
458
|
+
* Asserts definitions
|
495
459
|
*/
|
496
|
-
|
497
|
-
this.
|
498
|
-
this.
|
499
|
-
this.
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
}
|
505
|
-
|
460
|
+
HaveProperty: function ( node ) {
|
461
|
+
this.__class__ = 'HaveProperty';
|
462
|
+
this.node = node;
|
463
|
+
this.validate = function ( object ) {
|
464
|
+
if ( 'undefined' === typeof object[ this.node ] )
|
465
|
+
throw new Violation( this, object, { value: this.node } );
|
466
|
+
return true;
|
467
|
+
};
|
506
468
|
return this;
|
507
|
-
}
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
// display ulError container if it has been removed previously (or never shown)
|
518
|
-
if ( !$( this.ulError ).length ) {
|
519
|
-
this.manageErrorContainer();
|
520
|
-
}
|
521
|
-
|
522
|
-
// TODO: refacto properly
|
523
|
-
// if required constraint but field is not null, do not display
|
524
|
-
if ( 'required' === constraint.name && null !== this.ParsleyInstance.getVal() && this.ParsleyInstance.getVal().length > 0 ) {
|
525
|
-
return this;
|
526
|
-
|
527
|
-
// if empty required field and non required constraint fails, do not display
|
528
|
-
} else if ( this.ParsleyInstance.isRequired && 'required' !== constraint.name && ( null === this.ParsleyInstance.getVal() || 0 === this.ParsleyInstance.getVal().length ) ) {
|
529
|
-
this.removeError( constraint.name );
|
530
|
-
|
531
|
-
return this;
|
532
|
-
}
|
533
|
-
|
534
|
-
// TODO: refacto error name w/ proper & readable function
|
535
|
-
var constraintName = constraint.name
|
536
|
-
, liClass = false !== this.options.errorMessage ? 'custom-error-message' : constraintName
|
537
|
-
, liError = {}
|
538
|
-
, message = false !== this.options.errorMessage ? this.options.errorMessage : ( constraint.name === 'type' ?
|
539
|
-
this.ParsleyInstance.Validator.messages[ constraintName ][ constraint.requirements ] : ( 'undefined' === typeof this.ParsleyInstance.Validator.messages[ constraintName ] ?
|
540
|
-
this.ParsleyInstance.Validator.messages.defaultMessage : this.ParsleyInstance.Validator.formatMesssage( this.ParsleyInstance.Validator.messages[ constraintName ], constraint.requirements ) ) );
|
541
|
-
|
542
|
-
liError[ liClass ] = message;
|
543
|
-
|
544
|
-
// add liError if not shown. update if already exist
|
545
|
-
!$( this.ulError + ' .' + liClass ).length ? this.addError( liError ) : this.updateError( liError );
|
546
|
-
|
469
|
+
},
|
470
|
+
Blank: function () {
|
471
|
+
this.__class__ = 'Blank';
|
472
|
+
this.validate = function ( value ) {
|
473
|
+
if ( 'string' !== typeof value )
|
474
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
|
475
|
+
if ( '' !== value.replace( /^\s+/g, '' ).replace( /\s+$/g, '' ) )
|
476
|
+
throw new Violation( this, value );
|
477
|
+
return true;
|
478
|
+
};
|
547
479
|
return this;
|
548
|
-
}
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
!this.ParsleyInstance.isRadioOrCheckbox ? this.ParsleyInstance.$element.after( ulTemplate ) : this.ParsleyInstance.$element.parent().after( ulTemplate );
|
566
|
-
|
480
|
+
},
|
481
|
+
Callback: function ( fn ) {
|
482
|
+
this.__class__ = 'Callback';
|
483
|
+
this.arguments = Array.prototype.slice.call( arguments );
|
484
|
+
if ( 1 === this.arguments.length )
|
485
|
+
this.arguments = [];
|
486
|
+
else
|
487
|
+
this.arguments.splice( 0, 1 );
|
488
|
+
if ( 'function' !== typeof fn )
|
489
|
+
throw new Error( 'Callback must be instanciated with a function' );
|
490
|
+
this.fn = fn;
|
491
|
+
this.validate = function ( value ) {
|
492
|
+
var result = this.fn.apply( this, [ value ].concat( this.arguments ) );
|
493
|
+
if ( true !== result )
|
494
|
+
throw new Violation( this, value, { result: result } );
|
495
|
+
return true;
|
496
|
+
};
|
567
497
|
return this;
|
568
|
-
}
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
// if type is ParsleyFieldMultiple, just return this. used for clone
|
583
|
-
if ( type === 'ParsleyFieldMultiple' ) {
|
498
|
+
},
|
499
|
+
Choice: function ( list ) {
|
500
|
+
this.__class__ = 'Choice';
|
501
|
+
if ( !_isArray( list ) && 'function' !== typeof list )
|
502
|
+
throw new Error( 'Choice must be instanciated with an array or a function' );
|
503
|
+
this.list = list;
|
504
|
+
this.validate = function ( value ) {
|
505
|
+
var list = 'function' === typeof this.list ? this.list() : this.list;
|
506
|
+
for ( var i = 0; i < list.length; i++ )
|
507
|
+
if ( value === list[ i ] )
|
508
|
+
return true;
|
509
|
+
throw new Violation( this, value, { choices: list } );
|
510
|
+
};
|
584
511
|
return this;
|
585
|
-
}
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
*/
|
601
|
-
, init: function ( element, type ) {
|
602
|
-
this.type = type;
|
603
|
-
this.valid = true;
|
604
|
-
this.element = element;
|
605
|
-
this.validatedOnce = false;
|
606
|
-
this.$element = $( element );
|
607
|
-
this.val = this.$element.val();
|
608
|
-
this.Validator = new Validator( this.options );
|
609
|
-
this.isRequired = false;
|
610
|
-
this.constraints = {};
|
611
|
-
|
612
|
-
// overriden by ParsleyItemMultiple if radio or checkbox input
|
613
|
-
if ( 'undefined' === typeof this.isRadioOrCheckbox ) {
|
614
|
-
this.isRadioOrCheckbox = false;
|
615
|
-
this.hash = this.generateHash();
|
616
|
-
}
|
617
|
-
|
618
|
-
// error ul dom management done only once at init
|
619
|
-
this.UI = new ParsleyUI( this );
|
620
|
-
|
621
|
-
// bind some html5 properties
|
622
|
-
if ( this.options.useHtml5Constraints ) {
|
623
|
-
this.bindHtml5Constraints();
|
624
|
-
}
|
625
|
-
|
626
|
-
// bind validators to field
|
627
|
-
this.addConstraints();
|
628
|
-
|
629
|
-
// bind parsley events if validators have been registered
|
630
|
-
if ( this.hasConstraints() ) {
|
631
|
-
this.bindValidationEvents();
|
632
|
-
}
|
633
|
-
}
|
634
|
-
|
635
|
-
, setParent: function ( elem ) {
|
636
|
-
this.$parent = $( elem );
|
637
|
-
}
|
638
|
-
|
639
|
-
, getParent: function () {
|
640
|
-
return this.$parent;
|
641
|
-
}
|
642
|
-
|
643
|
-
/**
|
644
|
-
* Bind some extra html5 types / validators
|
645
|
-
*
|
646
|
-
* @private
|
647
|
-
* @method bindHtml5Constraints
|
648
|
-
*/
|
649
|
-
, bindHtml5Constraints: function () {
|
650
|
-
// add html5 required support + class required support
|
651
|
-
if ( this.$element.hasClass( 'required' ) || this.$element.attr( 'required' ) ) {
|
652
|
-
this.options.required = true;
|
653
|
-
}
|
654
|
-
|
655
|
-
// add html5 supported types & options
|
656
|
-
var type = this.$element.attr( 'type' );
|
657
|
-
if ( 'undefined' !== typeof type && new RegExp( type, 'i' ).test( 'email url number range tel' ) ) {
|
658
|
-
this.options.type = 'tel' === type ? 'phone' : type;
|
659
|
-
|
660
|
-
// number and range types could have min and/or max values
|
661
|
-
if ( new RegExp( this.options.type, 'i' ).test( 'number range' ) ) {
|
662
|
-
this.options.type = 'number';
|
663
|
-
|
664
|
-
// double condition to support jQuery and Zepto.. :(
|
665
|
-
if ( 'undefined' !== typeof this.$element.attr( 'min' ) && this.$element.attr( 'min' ).length ) {
|
666
|
-
this.options.min = this.$element.attr( 'min' );
|
667
|
-
}
|
668
|
-
|
669
|
-
if ( 'undefined' !== typeof this.$element.attr( 'max' ) && this.$element.attr( 'max' ).length ) {
|
670
|
-
this.options.max = this.$element.attr( 'max' );
|
671
|
-
}
|
512
|
+
},
|
513
|
+
Collection: function ( constraint ) {
|
514
|
+
this.__class__ = 'Collection';
|
515
|
+
this.constraint = 'undefined' !== typeof constraint ? new Constraint( constraint ) : false;
|
516
|
+
this.validate = function ( collection, group ) {
|
517
|
+
var result, validator = new Validator(), count = 0, failures = {}, groups = this.groups.length ? this.groups : group;
|
518
|
+
if ( !_isArray( collection ) )
|
519
|
+
throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } );
|
520
|
+
for ( var i = 0; i < collection.length; i++ ) {
|
521
|
+
result = this.constraint ?
|
522
|
+
validator.validate( collection[ i ], this.constraint, groups ) :
|
523
|
+
validator.validate( collection[ i ], groups );
|
524
|
+
if ( !_isEmptyObject( result ) )
|
525
|
+
failures[ count ] = result;
|
526
|
+
count++;
|
672
527
|
}
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
528
|
+
return !_isEmptyObject( failures ) ? failures : true;
|
529
|
+
};
|
530
|
+
return this;
|
531
|
+
},
|
532
|
+
Count: function ( count ) {
|
533
|
+
this.__class__ = 'Count';
|
534
|
+
this.count = count;
|
535
|
+
this.validate = function ( array ) {
|
536
|
+
if ( !_isArray( array ) )
|
537
|
+
throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } );
|
538
|
+
var count = 'function' === typeof this.count ? this.count( array ) : this.count;
|
539
|
+
if ( isNaN( Number( count ) ) )
|
540
|
+
throw new Error( 'Count must be a valid interger', count );
|
541
|
+
if ( count !== array.length )
|
542
|
+
throw new Violation( this, array, { count: count } );
|
543
|
+
return true;
|
544
|
+
};
|
545
|
+
return this;
|
546
|
+
},
|
547
|
+
Email: function () {
|
548
|
+
this.__class__ = 'Email';
|
549
|
+
this.validate = function ( value ) {
|
550
|
+
var 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;
|
551
|
+
if ( 'string' !== typeof value )
|
552
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
|
553
|
+
if ( !regExp.test( value ) )
|
554
|
+
throw new Violation( this, value );
|
555
|
+
return true;
|
556
|
+
};
|
557
|
+
return this;
|
558
|
+
},
|
559
|
+
Eql: function ( eql ) {
|
560
|
+
this.__class__ = 'Eql';
|
561
|
+
if ( 'undefined' === typeof eql )
|
562
|
+
throw new Error( 'Equal must be instanciated with an Array or an Object' );
|
563
|
+
this.eql = eql;
|
564
|
+
this.validate = function ( value ) {
|
565
|
+
var eql = 'function' === typeof this.eql ? this.eql( value ) : this.eql;
|
566
|
+
if ( !expect.eql( eql, value ) )
|
567
|
+
throw new Violation( this, value, { eql: eql } );
|
568
|
+
return true;
|
569
|
+
};
|
570
|
+
return this;
|
571
|
+
},
|
572
|
+
EqualTo: function ( reference ) {
|
573
|
+
this.__class__ = 'EqualTo';
|
574
|
+
if ( 'undefined' === typeof reference )
|
575
|
+
throw new Error( 'EqualTo must be instanciated with a value or a function' );
|
576
|
+
this.reference = reference;
|
577
|
+
this.validate = function ( value ) {
|
578
|
+
var reference = 'function' === typeof this.reference ? this.reference( value ) : this.reference;
|
579
|
+
if ( reference !== value )
|
580
|
+
throw new Violation( this, value, { value: reference } );
|
581
|
+
return true;
|
582
|
+
};
|
583
|
+
return this;
|
584
|
+
},
|
585
|
+
GreaterThan: function ( threshold ) {
|
586
|
+
this.__class__ = 'GreaterThan';
|
587
|
+
if ( 'undefined' === typeof threshold )
|
588
|
+
throw new Error( 'Should give a threshold value' );
|
589
|
+
this.threshold = threshold;
|
590
|
+
this.validate = function ( value ) {
|
591
|
+
if ( '' === value || isNaN( Number( value ) ) )
|
592
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
|
593
|
+
if ( this.threshold >= value )
|
594
|
+
throw new Violation( this, value, { threshold: this.threshold } );
|
595
|
+
return true;
|
596
|
+
};
|
597
|
+
return this;
|
598
|
+
},
|
599
|
+
GreaterThanOrEqual: function ( threshold ) {
|
600
|
+
this.__class__ = 'GreaterThanOrEqual';
|
601
|
+
if ( 'undefined' === typeof threshold )
|
602
|
+
throw new Error( 'Should give a threshold value' );
|
603
|
+
this.threshold = threshold;
|
604
|
+
this.validate = function ( value ) {
|
605
|
+
if ( '' === value || isNaN( Number( value ) ) )
|
606
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
|
607
|
+
if ( this.threshold > value )
|
608
|
+
throw new Violation( this, value, { threshold: this.threshold } );
|
609
|
+
return true;
|
610
|
+
};
|
611
|
+
return this;
|
612
|
+
},
|
613
|
+
InstanceOf: function ( classRef ) {
|
614
|
+
this.__class__ = 'InstanceOf';
|
615
|
+
if ( 'undefined' === typeof classRef )
|
616
|
+
throw new Error( 'InstanceOf must be instanciated with a value' );
|
617
|
+
this.classRef = classRef;
|
618
|
+
this.validate = function ( value ) {
|
619
|
+
if ( true !== (value instanceof this.classRef) )
|
620
|
+
throw new Violation( this, value, { classRef: this.classRef } );
|
621
|
+
return true;
|
622
|
+
};
|
623
|
+
return this;
|
624
|
+
},
|
625
|
+
IPv4: function () {
|
626
|
+
this.__class__ = 'IPv4';
|
627
|
+
this.validate = function ( value ) {
|
628
|
+
var regExp = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
629
|
+
if ( 'string' !== typeof value )
|
630
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
|
631
|
+
if ( !regExp.test( value ) )
|
632
|
+
throw new Violation( this, value );
|
633
|
+
return true;
|
634
|
+
};
|
635
|
+
return this;
|
636
|
+
},
|
637
|
+
Length: function ( boundaries ) {
|
638
|
+
this.__class__ = 'Length';
|
639
|
+
if ( !boundaries.min && !boundaries.max )
|
640
|
+
throw new Error( 'Lenth assert must be instanciated with a { min: x, max: y } object' );
|
641
|
+
this.min = boundaries.min;
|
642
|
+
this.max = boundaries.max;
|
643
|
+
this.validate = function ( value ) {
|
644
|
+
if ( 'string' !== typeof value && !_isArray( value ) )
|
645
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string_or_array } );
|
646
|
+
if ( 'undefined' !== typeof this.min && this.min === this.max && value.length !== this.min )
|
647
|
+
throw new Violation( this, value, { min: this.min, max: this.max } );
|
648
|
+
if ( 'undefined' !== typeof this.max && value.length > this.max )
|
649
|
+
throw new Violation( this, value, { max: this.max } );
|
650
|
+
if ( 'undefined' !== typeof this.min && value.length < this.min )
|
651
|
+
throw new Violation( this, value, { min: this.min } );
|
652
|
+
return true;
|
653
|
+
};
|
654
|
+
return this;
|
655
|
+
},
|
656
|
+
LessThan: function ( threshold ) {
|
657
|
+
this.__class__ = 'LessThan';
|
658
|
+
if ( 'undefined' === typeof threshold )
|
659
|
+
throw new Error( 'Should give a threshold value' );
|
660
|
+
this.threshold = threshold;
|
661
|
+
this.validate = function ( value ) {
|
662
|
+
if ( '' === value || isNaN( Number( value ) ) )
|
663
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
|
664
|
+
if ( this.threshold <= value )
|
665
|
+
throw new Violation( this, value, { threshold: this.threshold } );
|
666
|
+
return true;
|
667
|
+
};
|
668
|
+
return this;
|
669
|
+
},
|
670
|
+
LessThanOrEqual: function ( threshold ) {
|
671
|
+
this.__class__ = 'LessThanOrEqual';
|
672
|
+
if ( 'undefined' === typeof threshold )
|
673
|
+
throw new Error( 'Should give a threshold value' );
|
674
|
+
this.threshold = threshold;
|
675
|
+
this.validate = function ( value ) {
|
676
|
+
if ( '' === value || isNaN( Number( value ) ) )
|
677
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
|
678
|
+
if ( this.threshold < value )
|
679
|
+
throw new Violation( this, value, { threshold: this.threshold } );
|
680
|
+
return true;
|
681
|
+
};
|
682
|
+
return this;
|
683
|
+
},
|
684
|
+
Mac: function () {
|
685
|
+
this.__class__ = 'Mac';
|
686
|
+
this.validate = function ( value ) {
|
687
|
+
var regExp = /^(?:[0-9A-F]{2}:){5}[0-9A-F]{2}$/i;
|
688
|
+
if ( 'string' !== typeof value )
|
689
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
|
690
|
+
if ( !regExp.test( value ) )
|
691
|
+
throw new Violation( this, value );
|
692
|
+
return true;
|
693
|
+
};
|
694
|
+
return this;
|
695
|
+
},
|
696
|
+
NotNull: function () {
|
697
|
+
this.__class__ = 'NotNull';
|
698
|
+
this.validate = function ( value ) {
|
699
|
+
if ( null === value || 'undefined' === typeof value )
|
700
|
+
throw new Violation( this, value );
|
701
|
+
return true;
|
702
|
+
};
|
703
|
+
return this;
|
704
|
+
},
|
705
|
+
NotBlank: function () {
|
706
|
+
this.__class__ = 'NotBlank';
|
707
|
+
this.validate = function ( value ) {
|
708
|
+
if ( 'string' !== typeof value )
|
709
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
|
710
|
+
if ( '' === value.replace( /^\s+/g, '' ).replace( /\s+$/g, '' ) )
|
711
|
+
throw new Violation( this, value );
|
712
|
+
return true;
|
713
|
+
};
|
714
|
+
return this;
|
715
|
+
},
|
716
|
+
Null: function () {
|
717
|
+
this.__class__ = 'Null';
|
718
|
+
this.validate = function ( value ) {
|
719
|
+
if ( null !== value )
|
720
|
+
throw new Violation( this, value );
|
721
|
+
return true;
|
722
|
+
};
|
723
|
+
return this;
|
724
|
+
},
|
725
|
+
Range: function ( min, max ) {
|
726
|
+
this.__class__ = 'Range';
|
727
|
+
if ( 'undefined' === typeof min || 'undefined' === typeof max )
|
728
|
+
throw new Error( 'Range assert expects min and max values' );
|
729
|
+
this.min = min;
|
730
|
+
this.max = max;
|
731
|
+
this.validate = function ( value ) {
|
732
|
+
try {
|
733
|
+
// validate strings and objects with their Length
|
734
|
+
if ( ( 'string' === typeof value && isNaN( Number( value ) ) ) || _isArray( value ) )
|
735
|
+
new Assert().Length( { min: this.min, max: this.max } ).validate( value );
|
736
|
+
// validate numbers with their value
|
737
|
+
else
|
738
|
+
new Assert().GreaterThanOrEqual( this.min ).validate( value ) && new Assert().LessThanOrEqual( this.max ).validate( value );
|
739
|
+
return true;
|
740
|
+
} catch ( violation ) {
|
741
|
+
throw new Violation( this, value, violation.violation );
|
717
742
|
}
|
718
|
-
}
|
719
|
-
|
720
|
-
// force field validation next check and reset validation events
|
721
|
-
if ( 'undefined' === typeof doNotUpdateValidationEvents ) {
|
722
|
-
this.bindValidationEvents();
|
723
|
-
}
|
724
|
-
}
|
725
|
-
|
726
|
-
/**
|
727
|
-
* Dynamically update an existing constraint to a field.
|
728
|
-
* Simple API: { name: requirements }
|
729
|
-
*
|
730
|
-
* @method updtConstraint
|
731
|
-
* @param {Object} constraint
|
732
|
-
*/
|
733
|
-
, updateConstraint: function ( constraint, message ) {
|
734
|
-
for ( var name in constraint ) {
|
735
|
-
this.updtConstraint( { name: name, requirements: constraint[ name ], valid: null }, message );
|
736
|
-
}
|
737
|
-
}
|
738
|
-
|
739
|
-
/**
|
740
|
-
* Dynamically update an existing constraint to a field.
|
741
|
-
* Complex API: { name: name, requirements: requirements, valid: boolean }
|
742
|
-
*
|
743
|
-
* @method updtConstraint
|
744
|
-
* @param {Object} constraint
|
745
|
-
*/
|
746
|
-
, updtConstraint: function ( constraint, message ) {
|
747
|
-
this.constraints[ constraint.name ] = $.extend( true, this.constraints[ constraint.name ], constraint );
|
748
|
-
|
749
|
-
if ( 'string' === typeof message ) {
|
750
|
-
if ( constraint.name === 'type' )
|
751
|
-
this.Validator.messages[ constraint.name ][ constraint.requirements ] = message ;
|
752
|
-
else
|
753
|
-
this.Validator.messages[ constraint.name ] = message ;
|
754
|
-
}
|
755
|
-
|
756
|
-
// force field validation next check and reset validation events
|
757
|
-
this.bindValidationEvents();
|
758
|
-
}
|
759
|
-
|
760
|
-
/**
|
761
|
-
* Dynamically remove an existing constraint to a field.
|
762
|
-
*
|
763
|
-
* @method removeConstraint
|
764
|
-
* @param {String} constraintName
|
765
|
-
*/
|
766
|
-
, removeConstraint: function ( constraintName ) {
|
767
|
-
var constraintName = constraintName.toLowerCase();
|
768
|
-
|
769
|
-
delete this.constraints[ constraintName ];
|
770
|
-
|
771
|
-
if ( constraintName === 'required' ) {
|
772
|
-
this.isRequired = false;
|
773
|
-
}
|
774
|
-
|
775
|
-
// if there are no more constraint, reset errors and validation state
|
776
|
-
if ( !this.hasConstraints() ) {
|
777
|
-
this.UI.reset();
|
778
|
-
return;
|
779
|
-
}
|
780
|
-
|
781
|
-
this.bindValidationEvents();
|
782
|
-
}
|
783
|
-
|
784
|
-
/**
|
785
|
-
* Add custom constraint message, passed through data-API
|
786
|
-
*
|
787
|
-
* @private
|
788
|
-
* @method addCustomConstraintMessage
|
789
|
-
* @param constraint
|
790
|
-
*/
|
791
|
-
, addCustomConstraintMessage: function ( constraint ) {
|
792
|
-
// custom message type data-type-email-message -> typeEmailMessage | data-minlength-error => minlengthMessage
|
793
|
-
var customMessage = constraint
|
794
|
-
+ ( 'type' === constraint && 'undefined' !== typeof this.options[ constraint ] ? this.options[ constraint ].charAt( 0 ).toUpperCase() + this.options[ constraint ].substr( 1 ) : '' )
|
795
|
-
+ 'Message';
|
796
|
-
|
797
|
-
if ( 'undefined' !== typeof this.options[ customMessage ] ) {
|
798
|
-
this.Validator.addMessage( 'type' === constraint ? this.options[ constraint ] : constraint, this.options[ customMessage ], 'type' === constraint );
|
799
|
-
}
|
800
|
-
}
|
801
|
-
|
802
|
-
/**
|
803
|
-
* Bind validation events on a field
|
804
|
-
*
|
805
|
-
* @private
|
806
|
-
* @method bindValidationEvents
|
807
|
-
*/
|
808
|
-
, bindValidationEvents: function () {
|
809
|
-
// this field has validation events, that means it has to be validated
|
810
|
-
this.valid = null;
|
811
|
-
this.$element.addClass( 'parsley-validated' );
|
812
|
-
|
813
|
-
// remove eventually already binded events
|
814
|
-
this.$element.off( '.' + this.type );
|
815
|
-
|
816
|
-
// force add 'change' event if async remote validator here to have result before form submitting
|
817
|
-
if ( this.options.remote && !new RegExp( 'change', 'i' ).test( this.options.trigger ) ) {
|
818
|
-
this.options.trigger = !this.options.trigger ? 'change' : ' change';
|
819
|
-
}
|
820
|
-
|
821
|
-
// always bind keyup event, for better UX when a field is invalid
|
822
|
-
var triggers = ( !this.options.trigger ? '' : this.options.trigger )
|
823
|
-
+ ( new RegExp( 'key', 'i' ).test( this.options.trigger ) ? '' : ' keyup' );
|
824
|
-
|
825
|
-
// always bind change event, for better UX when a select is invalid
|
826
|
-
if ( this.$element.is( 'select' ) ) {
|
827
|
-
triggers += new RegExp( 'change', 'i' ).test( triggers ) ? '' : ' change';
|
828
|
-
}
|
829
|
-
|
830
|
-
// trim triggers to bind them correctly with .on()
|
831
|
-
triggers = triggers.replace( /^\s+/g , '' ).replace( /\s+$/g , '' );
|
832
|
-
|
833
|
-
this.$element.on( ( triggers + ' ' ).split( ' ' ).join( '.' + this.type + ' ' ), false, $.proxy( this.eventValidation, this ) );
|
834
|
-
}
|
835
|
-
|
836
|
-
/**
|
837
|
-
* Hash management. Used for ul error
|
838
|
-
*
|
839
|
-
* @method generateHash
|
840
|
-
* @returns {String} 5 letters unique hash
|
841
|
-
*/
|
842
|
-
, generateHash: function () {
|
843
|
-
return 'parsley-' + ( Math.random() + '' ).substring( 2 );
|
844
|
-
}
|
845
|
-
|
846
|
-
/**
|
847
|
-
* Public getHash accessor
|
848
|
-
*
|
849
|
-
* @method getHash
|
850
|
-
* @returns {String} hash
|
851
|
-
*/
|
852
|
-
, getHash: function () {
|
853
|
-
return this.hash;
|
854
|
-
}
|
855
|
-
|
856
|
-
/**
|
857
|
-
* Returns field val needed for validation
|
858
|
-
* Special treatment for radio & checkboxes
|
859
|
-
*
|
860
|
-
* @method getVal
|
861
|
-
* @returns {String} val
|
862
|
-
*/
|
863
|
-
, getVal: function () {
|
864
|
-
if ('undefined' !== typeof this.$element.domApi( this.options.namespace )[ 'value' ]) {
|
865
|
-
return this.$element.domApi( this.options.namespace )[ 'value' ];
|
866
|
-
}
|
867
|
-
|
868
|
-
return this.$element.val();
|
869
|
-
}
|
870
|
-
|
871
|
-
/**
|
872
|
-
* Called when validation is triggered by an event
|
873
|
-
* Do nothing if val.length < this.options.validationMinlength
|
874
|
-
*
|
875
|
-
* @method eventValidation
|
876
|
-
* @param {Object} event jQuery event
|
877
|
-
*/
|
878
|
-
, eventValidation: function ( event ) {
|
879
|
-
var val = this.getVal();
|
880
|
-
|
881
|
-
// do nothing on keypress event if not explicitely passed as data-trigger and if field has not already been validated once
|
882
|
-
if ( event.type === 'keyup' && !/keyup/i.test( this.options.trigger ) && !this.validatedOnce ) {
|
883
743
|
return true;
|
884
|
-
}
|
885
|
-
|
886
|
-
|
887
|
-
|
744
|
+
};
|
745
|
+
return this;
|
746
|
+
},
|
747
|
+
Regexp: function ( regexp, flag ) {
|
748
|
+
this.__class__ = 'Regexp';
|
749
|
+
if ( 'undefined' === typeof regexp )
|
750
|
+
throw new Error( 'You must give a regexp' );
|
751
|
+
this.regexp = regexp;
|
752
|
+
this.flag = flag || '';
|
753
|
+
this.validate = function ( value ) {
|
754
|
+
if ( 'string' !== typeof value )
|
755
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
|
756
|
+
if ( !new RegExp( this.regexp, this.flag ).test( value ) )
|
757
|
+
throw new Violation( this, value, { regexp: this.regexp, flag: this.flag } );
|
888
758
|
return true;
|
889
|
-
}
|
890
|
-
|
891
|
-
|
892
|
-
|
759
|
+
};
|
760
|
+
return this;
|
761
|
+
},
|
762
|
+
Required: function () {
|
763
|
+
this.__class__ = 'Required';
|
764
|
+
this.validate = function ( value ) {
|
765
|
+
if ( 'undefined' === typeof value )
|
766
|
+
throw new Violation( this, value );
|
767
|
+
try {
|
768
|
+
if ( 'string' === typeof value )
|
769
|
+
new Assert().NotNull().validate( value ) && new Assert().NotBlank().validate( value );
|
770
|
+
else if ( true === _isArray( value ) )
|
771
|
+
new Assert().Length( { min: 1 } ).validate( value );
|
772
|
+
} catch ( violation ) {
|
773
|
+
throw new Violation( this, value );
|
774
|
+
}
|
893
775
|
return true;
|
894
|
-
}
|
895
|
-
|
896
|
-
|
897
|
-
}
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
*/
|
915
|
-
, isValid: function () {
|
916
|
-
return this.validate( false );
|
917
|
-
}
|
918
|
-
|
919
|
-
/**
|
920
|
-
* Return if field has constraints
|
921
|
-
*
|
922
|
-
* @method hasConstraints
|
923
|
-
* @return {Boolean} Is field has constraints or not
|
924
|
-
*/
|
925
|
-
, hasConstraints: function () {
|
926
|
-
for ( var constraint in this.constraints ) {
|
776
|
+
};
|
777
|
+
return this;
|
778
|
+
},
|
779
|
+
// Unique() or Unique ( { key: foo } )
|
780
|
+
Unique: function ( object ) {
|
781
|
+
this.__class__ = 'Unique';
|
782
|
+
if ( 'object' === typeof object )
|
783
|
+
this.key = object.key;
|
784
|
+
this.validate = function ( array ) {
|
785
|
+
var value, store = [];
|
786
|
+
if ( !_isArray( array ) )
|
787
|
+
throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } );
|
788
|
+
for ( var i = 0; i < array.length; i++ ) {
|
789
|
+
value = 'object' === typeof array[ i ] ? array[ i ][ this.key ] : array[ i ];
|
790
|
+
if ( 'undefined' === typeof value )
|
791
|
+
continue;
|
792
|
+
if ( -1 !== store.indexOf( value ) )
|
793
|
+
throw new Violation( this, array, { value: value } );
|
794
|
+
store.push( value );
|
795
|
+
}
|
927
796
|
return true;
|
928
|
-
}
|
929
|
-
|
930
|
-
return false;
|
931
|
-
}
|
932
|
-
|
933
|
-
/**
|
934
|
-
* Validate a field & display errors
|
935
|
-
*
|
936
|
-
* @method validate
|
937
|
-
* @param {Boolean} errorBubbling set to false if you just want valid boolean without error bubbling next to fields
|
938
|
-
* @return {Boolean} Is field valid or not
|
939
|
-
*/
|
940
|
-
, validate: function ( errorBubbling ) {
|
941
|
-
var val = this.getVal()
|
942
|
-
, valid = null;
|
943
|
-
|
944
|
-
// do not even bother trying validating a field w/o constraints
|
945
|
-
if ( !this.hasConstraints() ) {
|
946
|
-
return null;
|
947
|
-
}
|
948
|
-
|
949
|
-
// do not validate excluded fields
|
950
|
-
if ( this.$element.is( this.options.excluded ) ) {
|
951
|
-
return null;
|
952
|
-
}
|
953
|
-
|
954
|
-
// reset Parsley validation if onFieldValidate returns true, or if field is empty and not required
|
955
|
-
if ( this.options.listeners.onFieldValidate( this.element, this ) || ( '' === val && !this.isRequired ) ) {
|
956
|
-
this.UI.reset();
|
957
|
-
return null;
|
958
|
-
}
|
959
|
-
|
960
|
-
// do not validate a field already validated and unchanged !
|
961
|
-
if ( !this.needsValidation( val ) ) {
|
962
|
-
return this.valid;
|
963
|
-
}
|
964
|
-
|
965
|
-
valid = this.applyValidators();
|
966
|
-
|
967
|
-
if ( 'undefined' !== typeof errorBubbling ? errorBubbling : this.options.showErrors ) {
|
968
|
-
this.manageValidationResult();
|
969
|
-
}
|
970
|
-
|
971
|
-
return valid;
|
972
|
-
}
|
973
|
-
|
974
|
-
/**
|
975
|
-
* Check if value has changed since previous validation
|
976
|
-
*
|
977
|
-
* @method needsValidation
|
978
|
-
* @param value
|
979
|
-
* @return {Boolean}
|
980
|
-
*/
|
981
|
-
, needsValidation: function ( val ) {
|
982
|
-
if ( !this.options.validateIfUnchanged && this.valid !== null && this.val === val && this.validatedOnce ) {
|
983
|
-
return false;
|
984
|
-
}
|
985
|
-
|
986
|
-
this.val = val;
|
987
|
-
return this.validatedOnce = true;
|
797
|
+
};
|
798
|
+
return this;
|
988
799
|
}
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
if (
|
1004
|
-
|
1005
|
-
this.constraints[ constraint ].valid = valid;
|
1006
|
-
} else if ( true === result ) {
|
1007
|
-
this.constraints[ constraint ].valid = true;
|
1008
|
-
valid = false !== valid;
|
800
|
+
};
|
801
|
+
// expose to the world these awesome classes
|
802
|
+
exports.Assert = Assert;
|
803
|
+
exports.Validator = Validator;
|
804
|
+
exports.Violation = Violation;
|
805
|
+
exports.Constraint = Constraint;
|
806
|
+
/**
|
807
|
+
* Some useful object prototypes / functions here
|
808
|
+
*/
|
809
|
+
// IE8<= compatibility
|
810
|
+
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
|
811
|
+
if (!Array.prototype.indexOf)
|
812
|
+
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
|
813
|
+
|
814
|
+
if (this === null) {
|
815
|
+
throw new TypeError();
|
1009
816
|
}
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
this.options.listeners.onFieldError( this.element, this.constraints, this );
|
1015
|
-
} else if (true === valid && false === this.options.listeners.onFieldSuccess( this.element, this.constraints, this )) {
|
1016
|
-
// if onFieldSuccess returns (bool) false, consider that field si invalid
|
1017
|
-
valid = false;
|
1018
|
-
}
|
1019
|
-
|
1020
|
-
return valid;
|
1021
|
-
}
|
1022
|
-
|
1023
|
-
/**
|
1024
|
-
* Fired when all validators have be executed
|
1025
|
-
* Returns true or false if field is valid or not
|
1026
|
-
* Display errors messages below failed fields
|
1027
|
-
* Adds parsley-success or parsley-error class on fields
|
1028
|
-
*
|
1029
|
-
* @method manageValidationResult
|
1030
|
-
* @return {Boolean} Is field valid or not
|
1031
|
-
*/
|
1032
|
-
, manageValidationResult: function () {
|
1033
|
-
var valid = null
|
1034
|
-
, errors = [];
|
1035
|
-
|
1036
|
-
for ( var constraint in this.constraints ) {
|
1037
|
-
if ( false === this.constraints[ constraint ].valid ) {
|
1038
|
-
errors.push( this.constraints[ constraint ]);
|
1039
|
-
valid = false;
|
1040
|
-
} else if ( true === this.constraints[ constraint ].valid ) {
|
1041
|
-
this.UI.removeError( this.constraints[ constraint ].name );
|
1042
|
-
valid = false !== valid;
|
817
|
+
var t = Object(this);
|
818
|
+
var len = t.length >>> 0;
|
819
|
+
if (len === 0) {
|
820
|
+
return -1;
|
1043
821
|
}
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
return true;
|
1053
|
-
} else if ( false === this.valid ) {
|
1054
|
-
if ( true === this.options.priorityEnabled ) {
|
1055
|
-
var maxPriority = 0, constraint, priority, error, errorArr = [];
|
1056
|
-
for ( var i = 0; i < errors.length; i++ ) {
|
1057
|
-
error = this.Validator.validators[ errors[ i ].name ]();
|
1058
|
-
priority = error.priority;
|
1059
|
-
errorArr.push(errors[ i ]);
|
1060
|
-
|
1061
|
-
if ( priority > maxPriority ) {
|
1062
|
-
constraint = errors[ i ];
|
1063
|
-
maxPriority = priority;
|
822
|
+
var n = 0;
|
823
|
+
if (arguments.length > 1) {
|
824
|
+
n = Number(arguments[1]);
|
825
|
+
if (n != n) { // shortcut for verifying if it's NaN
|
826
|
+
n = 0;
|
827
|
+
} else if (n !== 0 && n != Infinity && n != -Infinity) {
|
828
|
+
n = (n > 0 || -1) * Math.floor(Math.abs(n));
|
1064
829
|
}
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
830
|
+
}
|
831
|
+
if (n >= len) {
|
832
|
+
return -1;
|
833
|
+
}
|
834
|
+
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
|
835
|
+
for (; k < len; k++) {
|
836
|
+
if (k in t && t[k] === searchElement) {
|
837
|
+
return k;
|
1071
838
|
}
|
1072
|
-
}
|
1073
|
-
} else {
|
1074
|
-
for ( var i = 0; i < errors.length; i++ )
|
1075
|
-
this.UI.manageError( errors[ i ] );
|
1076
839
|
}
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
this.UI.removeErrors();
|
1085
|
-
}
|
1086
|
-
|
1087
|
-
return valid;
|
1088
|
-
}
|
1089
|
-
|
1090
|
-
/**
|
1091
|
-
* Add custom listeners
|
1092
|
-
*
|
1093
|
-
* @param {Object} { listener: function () {} }, eg { onFormValidate: function ( valid, event, focus ) { ... } }
|
1094
|
-
*/
|
1095
|
-
, addListener: function ( object ) {
|
1096
|
-
for ( var listener in object ) {
|
1097
|
-
this.options.listeners[ listener ] = object[ listener ];
|
1098
|
-
}
|
1099
|
-
}
|
1100
|
-
|
1101
|
-
/**
|
1102
|
-
* Destroy parsley field instance
|
1103
|
-
*
|
1104
|
-
* @private
|
1105
|
-
* @method destroy
|
1106
|
-
*/
|
1107
|
-
, destroy: function () {
|
1108
|
-
this.$element.removeClass( 'parsley-validated' );
|
1109
|
-
this.UI.reset();
|
1110
|
-
this.$element.off( '.' + this.type ).removeData( this.type );
|
1111
|
-
}
|
840
|
+
return -1;
|
841
|
+
};
|
842
|
+
// Test if object is empty, useful for Constraint violations check
|
843
|
+
var _isEmptyObject = function ( obj ) {
|
844
|
+
for ( var property in obj )
|
845
|
+
return false;
|
846
|
+
return true;
|
1112
847
|
};
|
1113
|
-
|
1114
|
-
|
1115
|
-
* ParsleyFieldMultiple override ParsleyField for checkbox and radio inputs
|
1116
|
-
* Pseudo-heritance to manage divergent behavior from ParsleyItem in dedicated methods
|
1117
|
-
*
|
1118
|
-
* @class ParsleyFieldMultiple
|
1119
|
-
* @constructor
|
1120
|
-
*/
|
1121
|
-
var ParsleyFieldMultiple = function ( element, options, type ) {
|
1122
|
-
this.initMultiple( element, options );
|
1123
|
-
this.inherit( element, options );
|
1124
|
-
this.Validator = new Validator( options );
|
1125
|
-
|
1126
|
-
// call ParsleyField constructor
|
1127
|
-
this.init( element, type || 'ParsleyFieldMultiple' );
|
848
|
+
var _isArray = function ( obj ) {
|
849
|
+
return Object.prototype.toString.call( obj ) === '[object Array]';
|
1128
850
|
};
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
this.siblings = this.group ? '[' + options.namespace + 'group="' + this.group + '"]' : 'input[name="' + this.$element.attr( 'name' ) + '"]';
|
1147
|
-
this.isRadioOrCheckbox = true;
|
1148
|
-
this.isRadio = this.$element.is( 'input[type=radio]' );
|
1149
|
-
this.isCheckbox = this.$element.is( 'input[type=checkbox]' );
|
1150
|
-
this.errorClassHandler = options.errors.classHandler( element, this.isRadioOrCheckbox ) || this.$element.parent();
|
1151
|
-
}
|
1152
|
-
|
1153
|
-
/**
|
1154
|
-
* Set specific constraints messages, do pseudo-heritance
|
1155
|
-
*
|
1156
|
-
* @private
|
1157
|
-
* @method inherit
|
1158
|
-
* @param {Object} element
|
1159
|
-
* @param {Object} options
|
1160
|
-
*/
|
1161
|
-
, inherit: function ( element, options ) {
|
1162
|
-
var clone = new ParsleyField( element, options, 'ParsleyFieldMultiple' );
|
1163
|
-
|
1164
|
-
for ( var property in clone ) {
|
1165
|
-
if ( 'undefined' === typeof this[ property ] ) {
|
1166
|
-
this[ property ] = clone [ property ];
|
1167
|
-
}
|
851
|
+
// https://github.com/LearnBoost/expect.js/blob/master/expect.js
|
852
|
+
var expect = {
|
853
|
+
eql: function ( actual, expected ) {
|
854
|
+
if ( actual === expected ) {
|
855
|
+
return true;
|
856
|
+
} else if ( 'undefined' !== typeof Buffer && Buffer.isBuffer( actual ) && Buffer.isBuffer( expected ) ) {
|
857
|
+
if ( actual.length !== expected.length ) return false;
|
858
|
+
for ( var i = 0; i < actual.length; i++ )
|
859
|
+
if ( actual[i] !== expected[i] ) return false;
|
860
|
+
return true;
|
861
|
+
} else if ( actual instanceof Date && expected instanceof Date ) {
|
862
|
+
return actual.getTime() === expected.getTime();
|
863
|
+
} else if ( typeof actual !== 'object' && typeof expected !== 'object' ) {
|
864
|
+
// loosy ==
|
865
|
+
return actual == expected;
|
866
|
+
} else {
|
867
|
+
return this.objEquiv(actual, expected);
|
1168
868
|
}
|
1169
|
-
}
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
* @method getVal
|
1194
|
-
* @returns {String} val
|
1195
|
-
*/
|
1196
|
-
, getVal: function () {
|
1197
|
-
if ( this.isRadio ) {
|
1198
|
-
return $( this.siblings + ':checked' ).val() || '';
|
869
|
+
},
|
870
|
+
isUndefinedOrNull: function ( value ) {
|
871
|
+
return value === null || typeof value === 'undefined';
|
872
|
+
},
|
873
|
+
isArguments: function ( object ) {
|
874
|
+
return Object.prototype.toString.call(object) == '[object Arguments]';
|
875
|
+
},
|
876
|
+
keys: function ( obj ) {
|
877
|
+
if ( Object.keys )
|
878
|
+
return Object.keys( obj );
|
879
|
+
var keys = [];
|
880
|
+
for ( var i in obj )
|
881
|
+
if ( Object.prototype.hasOwnProperty.call( obj, i ) )
|
882
|
+
keys.push(i);
|
883
|
+
return keys;
|
884
|
+
},
|
885
|
+
objEquiv: function ( a, b ) {
|
886
|
+
if ( this.isUndefinedOrNull( a ) || this.isUndefinedOrNull( b ) )
|
887
|
+
return false;
|
888
|
+
if ( a.prototype !== b.prototype ) return false;
|
889
|
+
if ( this.isArguments( a ) ) {
|
890
|
+
if ( !this.isArguments( b ) )
|
891
|
+
return false;
|
892
|
+
return eql( pSlice.call( a ) , pSlice.call( b ) );
|
1199
893
|
}
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
894
|
+
try {
|
895
|
+
var ka = this.keys( a ), kb = this.keys( b ), key, i;
|
896
|
+
if ( ka.length !== kb.length )
|
897
|
+
return false;
|
898
|
+
ka.sort();
|
899
|
+
kb.sort();
|
900
|
+
for ( i = ka.length - 1; i >= 0; i-- )
|
901
|
+
if ( ka[ i ] != kb[ i ] )
|
902
|
+
return false;
|
903
|
+
for ( i = ka.length - 1; i >= 0; i-- ) {
|
904
|
+
key = ka[i];
|
905
|
+
if ( !this.eql( a[ key ], b[ key ] ) )
|
906
|
+
return false;
|
907
|
+
}
|
908
|
+
return true;
|
909
|
+
} catch ( e ) {
|
910
|
+
return false;
|
1209
911
|
}
|
1210
|
-
|
1211
|
-
|
1212
|
-
/**
|
1213
|
-
* Bind validation events on a field
|
1214
|
-
*
|
1215
|
-
* @private
|
1216
|
-
* @method bindValidationEvents
|
1217
|
-
*/
|
1218
|
-
, bindValidationEvents: function () {
|
1219
|
-
// this field has validation events, that means it has to be validated
|
1220
|
-
this.valid = null;
|
1221
|
-
this.$element.addClass( 'parsley-validated' );
|
1222
|
-
|
1223
|
-
// remove eventually already binded events
|
1224
|
-
this.$element.off( '.' + this.type );
|
1225
|
-
|
1226
|
-
// always bind keyup event, for better UX when a field is invalid
|
1227
|
-
var self = this
|
1228
|
-
, triggers = ( !this.options.trigger ? '' : this.options.trigger )
|
1229
|
-
+ ( new RegExp( 'change', 'i' ).test( this.options.trigger ) ? '' : ' change' );
|
1230
|
-
|
1231
|
-
// trim triggers to bind them correctly with .on()
|
1232
|
-
triggers = triggers.replace( /^\s+/g , '' ).replace( /\s+$/g ,'' );
|
1233
|
-
|
1234
|
-
// bind trigger event on every siblings
|
1235
|
-
$( this.siblings ).each(function () {
|
1236
|
-
$( this ).on( triggers.split( ' ' ).join( '.' + self.type + ' ' ) , false, $.proxy( self.eventValidation, self ) );
|
1237
|
-
} )
|
1238
|
-
}
|
912
|
+
}
|
1239
913
|
};
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
this.
|
914
|
+
// AMD Compliance
|
915
|
+
if ( "function" === typeof define && define.amd ) {
|
916
|
+
define( 'validator', [],function() { return exports; } );
|
917
|
+
}
|
918
|
+
} )( 'undefined' === typeof exports ? this[ 'undefined' !== typeof validatorjs_ns ? validatorjs_ns : 'Validator' ] = {} : exports );
|
919
|
+
|
920
|
+
|
921
|
+
var ParsleyValidator = function (validators, catalog) {
|
922
|
+
this.__class__ = 'ParsleyValidator';
|
923
|
+
this.Validator = Validator;
|
924
|
+
// Default Parsley locale is en
|
925
|
+
this.locale = 'en';
|
926
|
+
this.init(validators || {}, catalog || {});
|
1250
927
|
};
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
,
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
928
|
+
ParsleyValidator.prototype = {
|
929
|
+
init: function (validators, catalog) {
|
930
|
+
this.catalog = catalog;
|
931
|
+
for (var name in validators)
|
932
|
+
this.addValidator(name, validators[name].fn, validators[name].priority);
|
933
|
+
$.emit('parsley:validator:init');
|
934
|
+
},
|
935
|
+
// Set new messages locale if we have dictionary loaded in ParsleyConfig.i18n
|
936
|
+
setLocale: function (locale) {
|
937
|
+
if ('undefined' === typeof this.catalog[locale])
|
938
|
+
throw new Error(locale + ' is not available in the catalog');
|
939
|
+
this.locale = locale;
|
940
|
+
return this;
|
941
|
+
},
|
942
|
+
// Add a new messages catalog for a given locale. Set locale for this catalog if set === `true`
|
943
|
+
addCatalog: function (locale, messages, set) {
|
944
|
+
if ('object' === typeof messages)
|
945
|
+
this.catalog[locale] = messages;
|
946
|
+
if (true === set)
|
947
|
+
return this.setLocale(locale);
|
948
|
+
return this;
|
949
|
+
},
|
950
|
+
// Add a specific message for a given constraint in a given locale
|
951
|
+
addMessage: function (locale, name, message) {
|
952
|
+
if (undefined === typeof this.catalog[locale])
|
953
|
+
this.catalog[locale] = {};
|
954
|
+
this.catalog[locale][name.toLowerCase()] = message;
|
955
|
+
return this;
|
956
|
+
},
|
957
|
+
validate: function (value, constraints, priority) {
|
958
|
+
return new this.Validator.Validator().validate.apply(new Validator.Validator(), arguments);
|
959
|
+
},
|
960
|
+
// Add a new validator
|
961
|
+
addValidator: function (name, fn, priority) {
|
962
|
+
this.validators[name.toLowerCase()] = function (requirements) {
|
963
|
+
return $.extend(new Validator.Assert().Callback(fn, requirements), { priority: priority });
|
964
|
+
};
|
965
|
+
return this;
|
966
|
+
},
|
967
|
+
updateValidator: function (name, fn, priority) {
|
968
|
+
return addValidator(name, fn, priority);
|
969
|
+
},
|
970
|
+
removeValidator: function (name) {
|
971
|
+
delete this.validators[name];
|
972
|
+
return this;
|
973
|
+
},
|
974
|
+
getErrorMessage: function (constraint) {
|
975
|
+
var message;
|
976
|
+
// Type constraints are a bit different, we have to match their requirements too to find right error message
|
977
|
+
if ('type' === constraint.name)
|
978
|
+
message = this.catalog[this.locale][constraint.name][constraint.requirements];
|
979
|
+
else
|
980
|
+
message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements);
|
981
|
+
return '' !== message ? message : this.catalog[this.locale].defaultMessage;
|
982
|
+
},
|
983
|
+
// Kind of light `sprintf()` implementation
|
984
|
+
formatMessage: function (string, parameters) {
|
985
|
+
if ('object' === typeof parameters) {
|
986
|
+
for (var i in parameters)
|
987
|
+
string = this.formatMessage(string, parameters[i]);
|
988
|
+
return string;
|
989
|
+
}
|
990
|
+
return 'string' === typeof string ? string.replace(new RegExp('%s', 'i'), parameters) : '';
|
991
|
+
},
|
992
|
+
// Here is the Parsley default validators list.
|
993
|
+
// This is basically Validatorjs validators, with different API for some of them
|
994
|
+
// and a Parsley priority set
|
995
|
+
validators: {
|
996
|
+
notblank: function () {
|
997
|
+
return $.extend(new Validator.Assert().NotBlank(), { priority: 2 });
|
998
|
+
},
|
999
|
+
required: function () {
|
1000
|
+
return $.extend(new Validator.Assert().Required(), { priority: 512 });
|
1001
|
+
},
|
1002
|
+
type: function (type) {
|
1003
|
+
var assert;
|
1004
|
+
switch (type) {
|
1005
|
+
case 'email':
|
1006
|
+
assert = new Validator.Assert().Email();
|
1007
|
+
break;
|
1008
|
+
case 'number':
|
1009
|
+
assert = new Validator.Assert().Regexp('^-?(?:\\d+|\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$');
|
1010
|
+
break;
|
1011
|
+
case 'integer':
|
1012
|
+
assert = new Validator.Assert().Regexp('^-?\\d+$');
|
1013
|
+
break;
|
1014
|
+
case 'digits':
|
1015
|
+
assert = new Validator.Assert().Regexp('^\\d+$');
|
1016
|
+
break;
|
1017
|
+
case 'alphanum':
|
1018
|
+
assert = new Validator.Assert().Regexp('^\\w+$', 'i');
|
1019
|
+
break;
|
1020
|
+
case 'url':
|
1021
|
+
assert = new Validator.Assert().Regexp('(https?:\\/\\/)?(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,4}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)', 'i');
|
1022
|
+
break;
|
1023
|
+
default:
|
1024
|
+
throw new Error('validator type `' + type + '` is not supported');
|
1025
|
+
}
|
1026
|
+
return $.extend(assert, { priority: 256 });
|
1027
|
+
},
|
1028
|
+
pattern: function (regexp) {
|
1029
|
+
var flags = '';
|
1030
|
+
// Test if RegExp is literal, if not, nothing to be done, otherwise, we need to isolate flags and pattern
|
1031
|
+
if (!!(/^\/.*\/(?:[gimy]*)$/.test(regexp))) {
|
1032
|
+
// Replace the regexp literal string with the first match group: ([gimy]*)
|
1033
|
+
// If no flag is present, this will be a blank string
|
1034
|
+
flags = regexp.replace(/.*\/([gimy]*)$/, '$1');
|
1035
|
+
// Again, replace the regexp literal string with the first match group:
|
1036
|
+
// everything excluding the opening and closing slashes and the flags
|
1037
|
+
regexp = regexp.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');
|
1038
|
+
}
|
1039
|
+
return $.extend(new Validator.Assert().Regexp(regexp, flags), { priority: 64 });
|
1040
|
+
},
|
1041
|
+
minlength: function (value) {
|
1042
|
+
return $.extend(new Validator.Assert().Length({ min: value }), {
|
1043
|
+
priority: 30,
|
1044
|
+
requirementsTransformer: function () {
|
1045
|
+
return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
|
1046
|
+
}
|
1047
|
+
});
|
1048
|
+
},
|
1049
|
+
maxlength: function (value) {
|
1050
|
+
return $.extend(new Validator.Assert().Length({ max: value }), {
|
1051
|
+
priority: 30,
|
1052
|
+
requirementsTransformer: function () {
|
1053
|
+
return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
|
1054
|
+
}
|
1266
1055
|
});
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1056
|
+
},
|
1057
|
+
length: function (array) {
|
1058
|
+
return $.extend(new Validator.Assert().Length({ min: array[0], max: array[1] }), { priority: 32 });
|
1059
|
+
},
|
1060
|
+
mincheck: function (length) {
|
1061
|
+
return this.minlength(length);
|
1062
|
+
},
|
1063
|
+
maxcheck: function (length) {
|
1064
|
+
return this.maxlength(length);
|
1065
|
+
},
|
1066
|
+
check: function (array) {
|
1067
|
+
return this.length(array);
|
1068
|
+
},
|
1069
|
+
min: function (value) {
|
1070
|
+
return $.extend(new Validator.Assert().GreaterThanOrEqual(value), {
|
1071
|
+
priority: 30,
|
1072
|
+
requirementsTransformer: function () {
|
1073
|
+
return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
|
1281
1074
|
}
|
1282
|
-
}
|
1283
|
-
|
1284
|
-
|
1075
|
+
});
|
1076
|
+
},
|
1077
|
+
max: function (value) {
|
1078
|
+
return $.extend(new Validator.Assert().LessThanOrEqual(value), {
|
1079
|
+
priority: 30,
|
1080
|
+
requirementsTransformer: function () {
|
1081
|
+
return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
|
1082
|
+
}
|
1083
|
+
});
|
1084
|
+
},
|
1085
|
+
range: function (array) {
|
1086
|
+
return $.extend(new Validator.Assert().Range(array[0], array[1]), {
|
1087
|
+
priority: 32,
|
1088
|
+
requirementsTransformer: function () {
|
1089
|
+
for (var i = 0; i < array.length; i++)
|
1090
|
+
array[i] = 'string' === typeof array[i] && !isNaN(array[i]) ? parseInt(array[i], 10) : array[i];
|
1091
|
+
return array;
|
1092
|
+
}
|
1093
|
+
});
|
1094
|
+
},
|
1095
|
+
equalto: function (value) {
|
1096
|
+
return $.extend(new Validator.Assert().EqualTo(value), {
|
1097
|
+
priority: 256,
|
1098
|
+
requirementsTransformer: function () {
|
1099
|
+
return $(value).length ? $(value).val() : value;
|
1100
|
+
}
|
1101
|
+
});
|
1285
1102
|
}
|
1286
1103
|
}
|
1104
|
+
};
|
1287
1105
|
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1106
|
+
var ParsleyUI = function (options) {
|
1107
|
+
this.__class__ = 'ParsleyUI';
|
1108
|
+
};
|
1109
|
+
ParsleyUI.prototype = {
|
1110
|
+
listen: function () {
|
1111
|
+
$.listen('parsley:form:init', this, this.setupForm);
|
1112
|
+
$.listen('parsley:field:init', this, this.setupField);
|
1113
|
+
$.listen('parsley:field:validated', this, this.reflow);
|
1114
|
+
$.listen('parsley:form:validated', this, this.focus);
|
1115
|
+
$.listen('parsley:field:reset', this, this.reset);
|
1116
|
+
$.listen('parsley:form:destroy', this, this.destroy);
|
1117
|
+
$.listen('parsley:field:destroy', this, this.destroy);
|
1118
|
+
return this;
|
1119
|
+
},
|
1120
|
+
reflow: function (fieldInstance) {
|
1121
|
+
// If this field has not an active UI (case for multiples) don't bother doing something
|
1122
|
+
if ('undefined' === typeof fieldInstance._ui || false === fieldInstance._ui.active)
|
1123
|
+
return;
|
1124
|
+
// Diff between two validation results
|
1125
|
+
var diff = this._diff(fieldInstance.validationResult, fieldInstance._ui.lastValidationResult);
|
1126
|
+
// Then store current validation result for next reflow
|
1127
|
+
fieldInstance._ui.lastValidationResult = fieldInstance.validationResult;
|
1128
|
+
// Field have been validated at least once if here. Useful for binded key events..
|
1129
|
+
fieldInstance._ui.validatedOnce = true;
|
1130
|
+
// Handle valid / invalid / none field class
|
1131
|
+
this.manageStatusClass(fieldInstance);
|
1132
|
+
// Add, remove, updated errors messages
|
1133
|
+
this.manageErrorsMessages(fieldInstance, diff);
|
1134
|
+
// Triggers impl
|
1135
|
+
this.actualizeTriggers(fieldInstance);
|
1136
|
+
// If field is not valid for the first time, bind keyup trigger to ease UX and quickly inform user
|
1137
|
+
if ((diff.kept.length || diff.added.length) && 'undefined' === typeof fieldInstance._ui.failedOnce)
|
1138
|
+
this.manageFailingFieldTrigger(fieldInstance);
|
1139
|
+
},
|
1140
|
+
// Returns an array of field's error message(s)
|
1141
|
+
getErrorsMessages: function (fieldInstance) {
|
1142
|
+
// No error message, field is valid
|
1143
|
+
if (true === fieldInstance.validationResult)
|
1144
|
+
return [];
|
1145
|
+
var messages = [];
|
1146
|
+
for (var i = 0; i < fieldInstance.validationResult.length; i++)
|
1147
|
+
messages.push(this._getErrorMessage(fieldInstance, fieldInstance.validationResult[i].assert));
|
1148
|
+
return messages;
|
1149
|
+
},
|
1150
|
+
manageStatusClass: function (fieldInstance) {
|
1151
|
+
if (true === fieldInstance.validationResult)
|
1152
|
+
this._successClass(fieldInstance);
|
1153
|
+
else if (fieldInstance.validationResult.length > 0)
|
1154
|
+
this._errorClass(fieldInstance);
|
1155
|
+
else
|
1156
|
+
this._resetClass(fieldInstance);
|
1157
|
+
},
|
1158
|
+
manageErrorsMessages: function (fieldInstance, diff) {
|
1159
|
+
if ('undefined' !== typeof fieldInstance.options.errorsMessagesDisabled)
|
1160
|
+
return;
|
1161
|
+
// Case where we have errorMessage option that configure an unique field error message, regardless failing validators
|
1162
|
+
if ('undefined' !== typeof fieldInstance.options.errorMessage) {
|
1163
|
+
if ((diff.added.length || diff.kept.length)) {
|
1164
|
+
if (0 === fieldInstance._ui.$errorsWrapper.find('.parsley-custom-error-message').length)
|
1165
|
+
fieldInstance._ui.$errorsWrapper
|
1166
|
+
.append($(fieldInstance.options.errorTemplate)
|
1167
|
+
.addClass('parsley-custom-error-message'));
|
1168
|
+
return fieldInstance._ui.$errorsWrapper
|
1169
|
+
.addClass('filled')
|
1170
|
+
.find('.parsley-custom-error-message')
|
1171
|
+
.html(fieldInstance.options.errorMessage);
|
1317
1172
|
}
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1173
|
+
return fieldInstance._ui.$errorsWrapper
|
1174
|
+
.removeClass('filled')
|
1175
|
+
.find('.parsley-custom-error-message')
|
1176
|
+
.remove();
|
1177
|
+
}
|
1178
|
+
// Show, hide, update failing constraints messages
|
1179
|
+
for (var i = 0; i < diff.removed.length; i++)
|
1180
|
+
this.removeError(fieldInstance, diff.removed[i].assert.name, true);
|
1181
|
+
for (i = 0; i < diff.added.length; i++)
|
1182
|
+
this.addError(fieldInstance, diff.added[i].assert.name, undefined, diff.added[i].assert, true);
|
1183
|
+
for (i = 0; i < diff.kept.length; i++)
|
1184
|
+
this.updateError(fieldInstance, diff.kept[i].assert.name, undefined, diff.kept[i].assert, true);
|
1185
|
+
},
|
1186
|
+
// TODO: strange API here, intuitive for manual usage with addError(pslyInstance, 'foo', 'bar')
|
1187
|
+
// but a little bit complex for above internal usage, with forced undefined parametter..
|
1188
|
+
addError: function (fieldInstance, name, message, assert, doNotUpdateClass) {
|
1189
|
+
fieldInstance._ui.$errorsWrapper
|
1190
|
+
.addClass('filled')
|
1191
|
+
.append($(fieldInstance.options.errorTemplate)
|
1192
|
+
.addClass('parsley-' + name)
|
1193
|
+
.html(message || this._getErrorMessage(fieldInstance, assert)));
|
1194
|
+
if (true !== doNotUpdateClass)
|
1195
|
+
this._errorClass(fieldInstance);
|
1196
|
+
},
|
1197
|
+
// Same as above
|
1198
|
+
updateError: function (fieldInstance, name, message, assert, doNotUpdateClass) {
|
1199
|
+
fieldInstance._ui.$errorsWrapper
|
1200
|
+
.addClass('filled')
|
1201
|
+
.find('.parsley-' + name)
|
1202
|
+
.html(message || this._getErrorMessage(fieldInstance, assert));
|
1203
|
+
if (true !== doNotUpdateClass)
|
1204
|
+
this._errorClass(fieldInstance);
|
1205
|
+
},
|
1206
|
+
// Same as above twice
|
1207
|
+
removeError: function (fieldInstance, name, doNotUpdateClass) {
|
1208
|
+
fieldInstance._ui.$errorsWrapper
|
1209
|
+
.removeClass('filled')
|
1210
|
+
.find('.parsley-' + name)
|
1211
|
+
.remove();
|
1212
|
+
// edge case possible here: remove a standard Parsley error that is still failing in fieldInstance.validationResult
|
1213
|
+
// but highly improbable cuz' manually removing a well Parsley handled error makes no sense.
|
1214
|
+
if (true !== doNotUpdateClass)
|
1215
|
+
this.manageStatusClass(fieldInstance);
|
1216
|
+
},
|
1217
|
+
focus: function (formInstance) {
|
1218
|
+
if (true === formInstance.validationResult || 'none' === formInstance.options.focus)
|
1219
|
+
return formInstance._focusedField = null;
|
1220
|
+
formInstance._focusedField = null;
|
1221
|
+
for (var i = 0; i < formInstance.fields.length; i++)
|
1222
|
+
if (true !== formInstance.fields[i].validationResult && formInstance.fields[i].validationResult.length > 0 && 'undefined' === typeof formInstance.fields[i].options.noFocus) {
|
1223
|
+
if ('first' === formInstance.options.focus) {
|
1224
|
+
formInstance._focusedField = formInstance.fields[i].$element;
|
1225
|
+
return formInstance._focusedField.focus();
|
1341
1226
|
}
|
1227
|
+
formInstance._focusedField = formInstance.fields[i].$element;
|
1342
1228
|
}
|
1229
|
+
if (null === formInstance._focusedField)
|
1230
|
+
return null;
|
1231
|
+
return formInstance._focusedField.focus();
|
1232
|
+
},
|
1233
|
+
_getErrorMessage: function (fieldInstance, constraint) {
|
1234
|
+
var customConstraintErrorMessage = constraint.name + 'Message';
|
1235
|
+
if ('undefined' !== typeof fieldInstance.options[customConstraintErrorMessage])
|
1236
|
+
return window.ParsleyValidator.formatMessage(fieldInstance.options[customConstraintErrorMessage], constraint.requirements);
|
1237
|
+
return window.ParsleyValidator.getErrorMessage(constraint);
|
1238
|
+
},
|
1239
|
+
_diff: function (newResult, oldResult, deep) {
|
1240
|
+
var
|
1241
|
+
added = [],
|
1242
|
+
kept = [];
|
1243
|
+
for (var i = 0; i < newResult.length; i++) {
|
1244
|
+
var found = false;
|
1245
|
+
for (var j = 0; j < oldResult.length; j++)
|
1246
|
+
if (newResult[i].assert.name === oldResult[j].assert.name) {
|
1247
|
+
found = true;
|
1248
|
+
break;
|
1249
|
+
}
|
1250
|
+
if (found)
|
1251
|
+
kept.push(newResult[i]);
|
1252
|
+
else
|
1253
|
+
added.push(newResult[i]);
|
1343
1254
|
}
|
1255
|
+
return {
|
1256
|
+
kept: kept,
|
1257
|
+
added: added,
|
1258
|
+
removed: !deep ? this._diff(oldResult, newResult, true).added : []
|
1259
|
+
};
|
1260
|
+
},
|
1261
|
+
setupForm: function (formInstance) {
|
1262
|
+
formInstance.$element.on('submit.Parsley', false, $.proxy(formInstance.onSubmitValidate, formInstance));
|
1263
|
+
// UI could be disabled
|
1264
|
+
if (false === formInstance.options.uiEnabled)
|
1265
|
+
return;
|
1266
|
+
formInstance.$element.attr('novalidate', '');
|
1267
|
+
},
|
1268
|
+
setupField: function (fieldInstance) {
|
1269
|
+
var _ui = { active: false };
|
1270
|
+
// UI could be disabled
|
1271
|
+
if (false === fieldInstance.options.uiEnabled)
|
1272
|
+
return;
|
1273
|
+
_ui.active = true;
|
1274
|
+
// Give field its Parsley id in DOM
|
1275
|
+
fieldInstance.$element.attr(fieldInstance.options.namespace + 'id', fieldInstance.__id__);
|
1276
|
+
/** Generate important UI elements and store them in fieldInstance **/
|
1277
|
+
// $errorClassHandler is the $element that woul have parsley-error and parsley-success classes
|
1278
|
+
_ui.$errorClassHandler = this._manageClassHandler(fieldInstance);
|
1279
|
+
// $errorsWrapper is a div that would contain the various field errors, it will be appended into $errorsContainer
|
1280
|
+
_ui.errorsWrapperId = 'parsley-id-' + ('undefined' !== typeof fieldInstance.options.multiple ? 'multiple-' + fieldInstance.options.multiple : fieldInstance.__id__);
|
1281
|
+
_ui.$errorsWrapper = $(fieldInstance.options.errorsWrapper).attr('id', _ui.errorsWrapperId);
|
1282
|
+
// ValidationResult UI storage to detect what have changed bwt two validations, and update DOM accordingly
|
1283
|
+
_ui.lastValidationResult = [];
|
1284
|
+
_ui.validatedOnce = false;
|
1285
|
+
_ui.validationInformationVisible = false;
|
1286
|
+
// Store it in fieldInstance for later
|
1287
|
+
fieldInstance._ui = _ui;
|
1288
|
+
/** Mess with DOM now **/
|
1289
|
+
this._insertErrorWrapper(fieldInstance);
|
1290
|
+
// Bind triggers first time
|
1291
|
+
this.actualizeTriggers(fieldInstance);
|
1292
|
+
},
|
1293
|
+
// Determine which element will have `parsley-error` and `parsley-success` classes
|
1294
|
+
_manageClassHandler: function (fieldInstance) {
|
1295
|
+
// An element selector could be passed through DOM with `data-parsley-class-handler=#foo`
|
1296
|
+
if ('string' === typeof fieldInstance.options.classHandler && $(fieldInstance.options.classHandler).length)
|
1297
|
+
return $(fieldInstance.options.classHandler);
|
1298
|
+
// Class handled could also be determined by function given in Parsley options
|
1299
|
+
var $handler = fieldInstance.options.classHandler(fieldInstance);
|
1300
|
+
// If this function returned a valid existing DOM element, go for it
|
1301
|
+
if ('undefined' !== typeof $handler && $handler.length)
|
1302
|
+
return $handler;
|
1303
|
+
// Otherwise, if simple element (input, texatrea, select..) it will perfectly host the classes
|
1304
|
+
if ('undefined' === typeof fieldInstance.options.multiple || fieldInstance.$element.is('select'))
|
1305
|
+
return fieldInstance.$element;
|
1306
|
+
// But if multiple element (radio, checkbox), that would be their parent
|
1307
|
+
return fieldInstance.$element.parent();
|
1308
|
+
},
|
1309
|
+
_insertErrorWrapper: function (fieldInstance) {
|
1310
|
+
var $errorsContainer;
|
1311
|
+
if ('string' === typeof fieldInstance.options.errorsContainer )
|
1312
|
+
if ($(fieldInstance.options.errorsContainer + '').length)
|
1313
|
+
return $(fieldInstance.options.errorsContainer).append(fieldInstance._ui.$errorsWrapper);
|
1314
|
+
else if (window.console && window.console.warn)
|
1315
|
+
window.console.warn('The errors container `' + fieldInstance.options.errorsContainer + '` does not exist in DOM');
|
1316
|
+
|
1317
|
+
if ('function' === typeof fieldInstance.options.errorsContainer)
|
1318
|
+
$errorsContainer = fieldInstance.options.errorsContainer(fieldInstance);
|
1319
|
+
if ('undefined' !== typeof $errorsContainer && $errorsContainer.length)
|
1320
|
+
return $errorsContainer.append(fieldInstance._ui.$errorsWrapper);
|
1321
|
+
return 'undefined' === typeof fieldInstance.options.multiple ? fieldInstance.$element.after(fieldInstance._ui.$errorsWrapper) : fieldInstance.$element.parent().after(fieldInstance._ui.$errorsWrapper);
|
1322
|
+
},
|
1323
|
+
actualizeTriggers: function (fieldInstance) {
|
1324
|
+
var that = this;
|
1325
|
+
// Remove Parsley events already binded on this field
|
1326
|
+
if (fieldInstance.options.multiple)
|
1327
|
+
$('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
|
1328
|
+
$(this).off('.Parsley');
|
1329
|
+
});
|
1330
|
+
else
|
1331
|
+
fieldInstance.$element.off('.Parsley');
|
1332
|
+
// If no trigger is set, all good
|
1333
|
+
if (false === fieldInstance.options.trigger)
|
1334
|
+
return;
|
1335
|
+
var triggers = fieldInstance.options.trigger.replace(/^\s+/g , '').replace(/\s+$/g , '');
|
1336
|
+
if ('' === triggers)
|
1337
|
+
return;
|
1338
|
+
// Bind fieldInstance.eventValidate if exists (for parsley.ajax for example), ParsleyUI.eventValidate otherwise
|
1339
|
+
if (fieldInstance.options.multiple)
|
1340
|
+
$('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
|
1341
|
+
$(this).on(
|
1342
|
+
triggers.split(' ').join('.Parsley ') + '.Parsley',
|
1343
|
+
false,
|
1344
|
+
$.proxy('function' === typeof fieldInstance.eventValidate ? fieldInstance.eventValidate : that.eventValidate, fieldInstance));
|
1345
|
+
});
|
1346
|
+
else
|
1347
|
+
fieldInstance.$element
|
1348
|
+
.on(
|
1349
|
+
triggers.split(' ').join('.Parsley ') + '.Parsley',
|
1350
|
+
false,
|
1351
|
+
$.proxy('function' === typeof fieldInstance.eventValidate ? fieldInstance.eventValidate : this.eventValidate, fieldInstance));
|
1352
|
+
},
|
1353
|
+
// Called through $.proxy with fieldInstance. `this` context is ParsleyField
|
1354
|
+
eventValidate: function(event) {
|
1355
|
+
// For keyup, keypress, keydown.. events that could be a little bit obstrusive
|
1356
|
+
// do not validate if val length < min threshold on first validation. Once field have been validated once and info
|
1357
|
+
// about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.
|
1358
|
+
if (new RegExp('key').test(event.type))
|
1359
|
+
if (!this._ui.validationInformationVisible && this.getValue().length <= this.options.validationThreshold)
|
1360
|
+
return;
|
1361
|
+
this._ui.validatedOnce = true;
|
1362
|
+
this.validate();
|
1363
|
+
},
|
1364
|
+
manageFailingFieldTrigger: function (fieldInstance) {
|
1365
|
+
fieldInstance._ui.failedOnce = true;
|
1366
|
+
// Radio and checkboxes fields must bind every field multiple
|
1367
|
+
if (fieldInstance.options.multiple)
|
1368
|
+
$('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
|
1369
|
+
if (!new RegExp('change', 'i').test($(this).parsley().options.trigger || ''))
|
1370
|
+
return $(this).on('change.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
|
1371
|
+
});
|
1372
|
+
// Select case
|
1373
|
+
if (fieldInstance.$element.is('select'))
|
1374
|
+
if (!new RegExp('change', 'i').test(fieldInstance.options.trigger || ''))
|
1375
|
+
return fieldInstance.$element.on('change.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
|
1376
|
+
// All other inputs fields
|
1377
|
+
if (!new RegExp('keyup', 'i').test(fieldInstance.options.trigger || ''))
|
1378
|
+
return fieldInstance.$element.on('keyup.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
|
1379
|
+
},
|
1380
|
+
reset: function (parsleyInstance) {
|
1381
|
+
// Reset all event listeners
|
1382
|
+
parsleyInstance.$element.off('.Parsley');
|
1383
|
+
parsleyInstance.$element.off('.ParsleyFailedOnce');
|
1384
|
+
// Nothing to do if UI never initialized for this field
|
1385
|
+
if ('undefined' === typeof parsleyInstance._ui)
|
1386
|
+
return;
|
1387
|
+
if ('ParsleyForm' === parsleyInstance.__class__)
|
1388
|
+
return;
|
1389
|
+
// Reset all errors' li
|
1390
|
+
parsleyInstance._ui.$errorsWrapper.children().each(function () {
|
1391
|
+
$(this).remove();
|
1392
|
+
});
|
1393
|
+
// Reset validation class
|
1394
|
+
this._resetClass(parsleyInstance);
|
1395
|
+
// Reset validation flags and last validation result
|
1396
|
+
parsleyInstance._ui.validatedOnce = false;
|
1397
|
+
parsleyInstance._ui.lastValidationResult = [];
|
1398
|
+
parsleyInstance._ui.validationInformationVisible = false;
|
1399
|
+
},
|
1400
|
+
destroy: function (parsleyInstance) {
|
1401
|
+
this.reset(parsleyInstance);
|
1402
|
+
if ('ParsleyForm' === parsleyInstance.__class__)
|
1403
|
+
return;
|
1404
|
+
parsleyInstance._ui.$errorsWrapper.remove();
|
1405
|
+
delete parsleyInstance._ui;
|
1406
|
+
},
|
1407
|
+
_successClass: function (fieldInstance) {
|
1408
|
+
fieldInstance._ui.validationInformationVisible = true;
|
1409
|
+
fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.errorClass).addClass(fieldInstance.options.successClass);
|
1410
|
+
},
|
1411
|
+
_errorClass: function (fieldInstance) {
|
1412
|
+
fieldInstance._ui.validationInformationVisible = true;
|
1413
|
+
fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.successClass).addClass(fieldInstance.options.errorClass);
|
1414
|
+
},
|
1415
|
+
_resetClass: function (fieldInstance) {
|
1416
|
+
fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.successClass).removeClass(fieldInstance.options.errorClass);
|
1417
|
+
}
|
1418
|
+
};
|
1344
1419
|
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
// if onFormValidate returns (bool) false, form won't be submitted, even if valid
|
1367
|
-
var onFormValidate = this.options.listeners.onFormValidate( valid, event, this );
|
1368
|
-
if ('undefined' !== typeof onFormValidate) {
|
1369
|
-
return onFormValidate;
|
1420
|
+
var ParsleyOptionsFactory = function (defaultOptions, globalOptions, userOptions, namespace) {
|
1421
|
+
this.__class__ = 'OptionsFactory';
|
1422
|
+
this.__id__ = ParsleyUtils.hash(4);
|
1423
|
+
this.formOptions = null;
|
1424
|
+
this.fieldOptions = null;
|
1425
|
+
this.staticOptions = $.extend(true, {}, defaultOptions, globalOptions, userOptions, { namespace: namespace });
|
1426
|
+
};
|
1427
|
+
ParsleyOptionsFactory.prototype = {
|
1428
|
+
get: function (parsleyInstance) {
|
1429
|
+
if ('undefined' === typeof parsleyInstance.__class__)
|
1430
|
+
throw new Error('Parsley Instance expected');
|
1431
|
+
switch (parsleyInstance.__class__) {
|
1432
|
+
case 'Parsley':
|
1433
|
+
return this.staticOptions;
|
1434
|
+
case 'ParsleyForm':
|
1435
|
+
return this.getFormOptions(parsleyInstance);
|
1436
|
+
case 'ParsleyField':
|
1437
|
+
case 'ParsleyFieldMultiple':
|
1438
|
+
return this.getFieldOptions(parsleyInstance);
|
1439
|
+
default:
|
1440
|
+
throw new Error('Instance ' + parsleyInstance.__class__ + ' is not supported');
|
1370
1441
|
}
|
1371
|
-
|
1372
|
-
|
1442
|
+
},
|
1443
|
+
getFormOptions: function (formInstance) {
|
1444
|
+
this.formOptions = ParsleyUtils.attr(formInstance.$element, this.staticOptions.namespace);
|
1445
|
+
// not deep extend, since formOptions is a 1 level deep object
|
1446
|
+
return $.extend({}, this.staticOptions, this.formOptions);
|
1447
|
+
},
|
1448
|
+
getFieldOptions: function (fieldInstance) {
|
1449
|
+
this.fieldOptions = ParsleyUtils.attr(fieldInstance.$element, this.staticOptions.namespace);
|
1450
|
+
if (null === this.formOptions && 'undefined' !== typeof fieldInstance.parent)
|
1451
|
+
this.formOptions = this.getFormOptions(fieldInstance.parent);
|
1452
|
+
// not deep extend, since formOptions and fieldOptions is a 1 level deep object
|
1453
|
+
return $.extend({}, this.staticOptions, this.formOptions, this.fieldOptions);
|
1373
1454
|
}
|
1455
|
+
};
|
1374
1456
|
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1457
|
+
var ParsleyForm = function (element, OptionsFactory) {
|
1458
|
+
this.__class__ = 'ParsleyForm';
|
1459
|
+
this.__id__ = ParsleyUtils.hash(4);
|
1460
|
+
if ('OptionsFactory' !== ParsleyUtils.get(OptionsFactory, '__class__'))
|
1461
|
+
throw new Error('You must give an OptionsFactory instance');
|
1462
|
+
this.OptionsFactory = OptionsFactory;
|
1463
|
+
this.$element = $(element);
|
1464
|
+
this.validationResult = null;
|
1465
|
+
this.options = this.OptionsFactory.get(this);
|
1466
|
+
};
|
1467
|
+
ParsleyForm.prototype = {
|
1468
|
+
onSubmitValidate: function (event) {
|
1469
|
+
this.validate(undefined, undefined, event);
|
1470
|
+
// prevent form submission if validation fails
|
1471
|
+
if (false === this.validationResult && event instanceof $.Event) {
|
1472
|
+
event.stopImmediatePropagation();
|
1473
|
+
event.preventDefault();
|
1474
|
+
}
|
1475
|
+
return this;
|
1476
|
+
},
|
1477
|
+
// @returns boolean
|
1478
|
+
validate: function (group, force, event) {
|
1479
|
+
this.submitEvent = event;
|
1480
|
+
this.validationResult = true;
|
1481
|
+
var fieldValidationResult = [];
|
1482
|
+
// Refresh form DOM options and form's fields that could have changed
|
1483
|
+
this._refreshFields();
|
1484
|
+
$.emit('parsley:form:validate', this);
|
1485
|
+
// loop through fields to validate them one by one
|
1486
|
+
for (var i = 0; i < this.fields.length; i++) {
|
1487
|
+
// do not validate a field if not the same as given validation group
|
1488
|
+
if (group && group !== this.fields[i].options.group)
|
1489
|
+
continue;
|
1490
|
+
fieldValidationResult = this.fields[i].validate(force);
|
1491
|
+
if (true !== fieldValidationResult && fieldValidationResult.length > 0 && this.validationResult)
|
1492
|
+
this.validationResult = false;
|
1493
|
+
}
|
1494
|
+
$.emit('parsley:form:validated', this);
|
1495
|
+
return this.validationResult;
|
1496
|
+
},
|
1497
|
+
// Iterate over refreshed fields, and stop on first failure
|
1498
|
+
isValid: function (group, force) {
|
1499
|
+
this._refreshFields();
|
1500
|
+
for (var i = 0; i < this.fields.length; i++) {
|
1501
|
+
// do not validate a field if not the same as given validation group
|
1502
|
+
if (group && group !== this.fields[i].options.group)
|
1503
|
+
continue;
|
1504
|
+
if (false === this.fields[i].isValid(force))
|
1378
1505
|
return false;
|
1379
|
-
}
|
1380
1506
|
}
|
1381
|
-
|
1382
1507
|
return true;
|
1508
|
+
},
|
1509
|
+
_refreshFields: function () {
|
1510
|
+
return this.actualizeOptions()._bindFields();
|
1511
|
+
},
|
1512
|
+
_bindFields: function () {
|
1513
|
+
var self = this;
|
1514
|
+
this.fields = [];
|
1515
|
+
this.fieldsMappedById = {};
|
1516
|
+
this.$element.find(this.options.inputs).each(function () {
|
1517
|
+
var fieldInstance = new window.Parsley(this, {}, self);
|
1518
|
+
// Only add valid and not excluded `ParsleyField` and `ParsleyFieldMultiple` children
|
1519
|
+
if (('ParsleyField' === fieldInstance.__class__ || 'ParsleyFieldMultiple' === fieldInstance.__class__) && !fieldInstance.$element.is(fieldInstance.options.excluded))
|
1520
|
+
if ('undefined' === typeof self.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__]) {
|
1521
|
+
self.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__] = fieldInstance;
|
1522
|
+
self.fields.push(fieldInstance);
|
1523
|
+
}
|
1524
|
+
});
|
1525
|
+
return this;
|
1383
1526
|
}
|
1527
|
+
};
|
1384
1528
|
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1529
|
+
var ConstraintFactory = function (parsleyField, name, requirements, priority, isDomConstraint) {
|
1530
|
+
if (!new RegExp('ParsleyField').test(ParsleyUtils.get(parsleyField, '__class__')))
|
1531
|
+
throw new Error('ParsleyField or ParsleyFieldMultiple instance expected');
|
1532
|
+
if ('function' !== typeof window.ParsleyValidator.validators[name] &&
|
1533
|
+
'Assert' !== window.ParsleyValidator.validators[name](requirements).__parentClass__)
|
1534
|
+
throw new Error('Valid validator expected');
|
1535
|
+
var getPriority = function (parsleyField, name) {
|
1536
|
+
if ('undefined' !== typeof parsleyField.options[name + 'Priority'])
|
1537
|
+
return parsleyField.options[name + 'Priority'];
|
1538
|
+
return ParsleyUtils.get(window.ParsleyValidator.validators[name](requirements), 'priority') || 2;
|
1539
|
+
};
|
1540
|
+
priority = priority || getPriority(parsleyField, name);
|
1541
|
+
// If validator have a requirementsTransformer, execute it
|
1542
|
+
if ('function' === typeof window.ParsleyValidator.validators[name](requirements).requirementsTransformer)
|
1543
|
+
requirements = window.ParsleyValidator.validators[name](requirements).requirementsTransformer();
|
1544
|
+
return $.extend(window.ParsleyValidator.validators[name](requirements), {
|
1545
|
+
name: name,
|
1546
|
+
requirements: requirements,
|
1547
|
+
priority: priority,
|
1548
|
+
groups: [priority],
|
1549
|
+
isDomConstraint: isDomConstraint || ParsleyUtils.attr(parsleyField.$element, parsleyField.options.namespace, name)
|
1550
|
+
});
|
1551
|
+
};
|
1405
1552
|
|
1406
|
-
|
1553
|
+
var ParsleyField = function (field, OptionsFactory, parsleyFormInstance) {
|
1554
|
+
this.__class__ = 'ParsleyField';
|
1555
|
+
this.__id__ = ParsleyUtils.hash(4);
|
1556
|
+
this.$element = $(field);
|
1557
|
+
// If we have a parent `ParsleyForm` instance given, use its `OptionsFactory`, and save parent
|
1558
|
+
if ('undefined' !== typeof parsleyFormInstance) {
|
1559
|
+
this.parent = parsleyFormInstance;
|
1560
|
+
this.OptionsFactory = this.parent.OptionsFactory;
|
1561
|
+
this.options = this.OptionsFactory.get(this);
|
1562
|
+
// Else, take the `Parsley` one
|
1563
|
+
} else {
|
1564
|
+
this.OptionsFactory = OptionsFactory;
|
1565
|
+
this.options = this.OptionsFactory.get(this);
|
1407
1566
|
}
|
1408
|
-
|
1567
|
+
// Initialize some properties
|
1568
|
+
this.constraints = [];
|
1569
|
+
this.constraintsByName = {};
|
1570
|
+
this.validationResult = [];
|
1571
|
+
// Bind constraints
|
1572
|
+
this._bindConstraints();
|
1573
|
+
};
|
1574
|
+
ParsleyField.prototype = {
|
1575
|
+
// # Public API
|
1576
|
+
// Validate field and $.emit some events for mainly `ParsleyUI`
|
1577
|
+
// @returns validationResult:
|
1578
|
+
// - `true` if all constraint passes
|
1579
|
+
// - `[]` if not required field and empty (not validated)
|
1580
|
+
// - `[Violation, [Violation..]]` if there were validation errors
|
1581
|
+
validate: function (force) {
|
1582
|
+
this.value = this.getValue();
|
1583
|
+
// Field Validate event. `this.value` could be altered for custom needs
|
1584
|
+
$.emit('parsley:field:validate', this);
|
1585
|
+
$.emit('parsley:field:' + (this.isValid(force, this.value) ? 'success' : 'error'), this);
|
1586
|
+
// Field validated event. `this.validationResult` could be altered for custom needs too
|
1587
|
+
$.emit('parsley:field:validated', this);
|
1588
|
+
return this.validationResult;
|
1589
|
+
},
|
1590
|
+
// Just validate field. Do not trigger any event
|
1591
|
+
// Same @return as `validate()`
|
1592
|
+
isValid: function (force, value) {
|
1593
|
+
// Recompute options and rebind constraints to have latest changes
|
1594
|
+
this.refreshConstraints();
|
1595
|
+
// Sort priorities to validate more important first
|
1596
|
+
var priorities = this._getConstraintsSortedPriorities();
|
1597
|
+
// Value could be passed as argument, needed to add more power to 'parsley:field:validate'
|
1598
|
+
value = value || this.getValue();
|
1599
|
+
// If a field is empty and not required, leave it alone, it's just fine
|
1600
|
+
// Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators
|
1601
|
+
if (0 === value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty && true !== force)
|
1602
|
+
return this.validationResult = [];
|
1603
|
+
// If we want to validate field against all constraints, just call Validator and let it do the job
|
1604
|
+
if (false === this.options.priorityEnabled)
|
1605
|
+
return true === (this.validationResult = this.validateThroughValidator(value, this.constraints, 'Any'));
|
1606
|
+
// Else, iterate over priorities one by one, and validate related asserts one by one
|
1607
|
+
for (var i = 0; i < priorities.length; i++)
|
1608
|
+
if (true !== (this.validationResult = this.validateThroughValidator(value, this.constraints, priorities[i])))
|
1609
|
+
return false;
|
1610
|
+
return true;
|
1611
|
+
},
|
1612
|
+
// @returns Parsley field computed value that could be overrided or configured in DOM
|
1613
|
+
getValue: function () {
|
1614
|
+
var value;
|
1615
|
+
// Value could be overriden in DOM
|
1616
|
+
if ('undefined' !== typeof this.options.value)
|
1617
|
+
value = this.options.value;
|
1618
|
+
else
|
1619
|
+
value = this.$element.val();
|
1620
|
+
// Handle wrong DOM or configurations
|
1621
|
+
if ('undefined' === typeof value || null === value)
|
1622
|
+
return '';
|
1623
|
+
// Use `data-parsley-trim-value="true"` to auto trim inputs entry
|
1624
|
+
if (true === this.options.trimValue)
|
1625
|
+
return value.replace(/^\s+|\s+$/g, '');
|
1626
|
+
return value;
|
1627
|
+
},
|
1628
|
+
// Actualize options that could have change since previous validation
|
1629
|
+
// Re-bind accordingly constraints (could be some new, removed or updated)
|
1630
|
+
refreshConstraints: function () {
|
1631
|
+
return this.actualizeOptions()._bindConstraints();
|
1632
|
+
},
|
1409
1633
|
/**
|
1410
|
-
*
|
1634
|
+
* Add a new constraint to a field
|
1411
1635
|
*
|
1412
|
-
* @method
|
1636
|
+
* @method addConstraint
|
1637
|
+
* @param {String} name
|
1638
|
+
* @param {Mixed} requirements optional
|
1639
|
+
* @param {Number} priority optional
|
1640
|
+
* @param {Boolean} isDomConstraint optional
|
1413
1641
|
*/
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1642
|
+
addConstraint: function (name, requirements, priority, isDomConstraint) {
|
1643
|
+
name = name.toLowerCase();
|
1644
|
+
if ('function' === typeof window.ParsleyValidator.validators[name]) {
|
1645
|
+
var constraint = new ConstraintFactory(this, name, requirements, priority, isDomConstraint);
|
1646
|
+
// if constraint already exist, delete it and push new version
|
1647
|
+
if ('undefined' !== this.constraintsByName[constraint.name])
|
1648
|
+
this.removeConstraint(constraint.name);
|
1649
|
+
this.constraints.push(constraint);
|
1650
|
+
this.constraintsByName[constraint.name] = constraint;
|
1417
1651
|
}
|
1652
|
+
return this;
|
1653
|
+
},
|
1654
|
+
// Remove a constraint
|
1655
|
+
removeConstraint: function (name) {
|
1656
|
+
for (var i = 0; i < this.constraints.length; i++)
|
1657
|
+
if (name === this.constraints[i].name) {
|
1658
|
+
this.constraints.splice(i, 1);
|
1659
|
+
break;
|
1660
|
+
}
|
1661
|
+
return this;
|
1662
|
+
},
|
1663
|
+
// Update a constraint (Remove + re-add)
|
1664
|
+
updateConstraint: function (name, parameters, priority) {
|
1665
|
+
return this.removeConstraint(name)
|
1666
|
+
.addConstraint(name, parameters, priority);
|
1667
|
+
},
|
1668
|
+
// # Internals
|
1669
|
+
// Internal only.
|
1670
|
+
// Bind constraints from config + options + DOM
|
1671
|
+
_bindConstraints: function () {
|
1672
|
+
var constraints = [];
|
1673
|
+
// clean all existing DOM constraints to only keep javascript user constraints
|
1674
|
+
for (var i = 0; i < this.constraints.length; i++)
|
1675
|
+
if (false === this.constraints[i].isDomConstraint)
|
1676
|
+
constraints.push(this.constraints[i]);
|
1677
|
+
this.constraints = constraints;
|
1678
|
+
// then re-add Parsley DOM-API constraints
|
1679
|
+
for (var name in this.options)
|
1680
|
+
this.addConstraint(name, this.options[name]);
|
1681
|
+
// finally, bind special HTML5 constraints
|
1682
|
+
return this._bindHtml5Constraints();
|
1683
|
+
},
|
1684
|
+
// Internal only.
|
1685
|
+
// Bind specific HTML5 constraints to be HTML5 compliant
|
1686
|
+
_bindHtml5Constraints: function () {
|
1687
|
+
// html5 required
|
1688
|
+
if (this.$element.hasClass('required') || this.$element.attr('required'))
|
1689
|
+
this.addConstraint('required', true, undefined, true);
|
1690
|
+
// html5 pattern
|
1691
|
+
if ('string' === typeof this.$element.attr('pattern'))
|
1692
|
+
this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);
|
1693
|
+
// range
|
1694
|
+
if ('undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max'))
|
1695
|
+
this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);
|
1696
|
+
// HTML5 min
|
1697
|
+
else if ('undefined' !== typeof this.$element.attr('min'))
|
1698
|
+
this.addConstraint('min', this.$element.attr('min'), undefined, true);
|
1699
|
+
// HTML5 max
|
1700
|
+
else if ('undefined' !== typeof this.$element.attr('max'))
|
1701
|
+
this.addConstraint('max', this.$element.attr('max'), undefined, true);
|
1702
|
+
// html5 types
|
1703
|
+
var type = this.$element.attr('type');
|
1704
|
+
if ('undefined' === typeof type)
|
1705
|
+
return this;
|
1706
|
+
// Small special case here for HTML5 number, that is in fact an integer validator
|
1707
|
+
if ('number' === type)
|
1708
|
+
return this.addConstraint('type', 'integer', undefined, true);
|
1709
|
+
// Regular other HTML5 supported types
|
1710
|
+
else if (new RegExp(type, 'i').test('email url range'))
|
1711
|
+
return this.addConstraint('type', type, undefined, true);
|
1712
|
+
return this;
|
1713
|
+
},
|
1714
|
+
// Internal only.
|
1715
|
+
// Field is required if have required constraint without `false` value
|
1716
|
+
_isRequired: function () {
|
1717
|
+
if ('undefined' === typeof this.constraintsByName.required)
|
1718
|
+
return false;
|
1719
|
+
return false !== this.constraintsByName.required.requirements;
|
1720
|
+
},
|
1721
|
+
// Internal only.
|
1722
|
+
// Sort constraints by priority DESC
|
1723
|
+
_getConstraintsSortedPriorities: function () {
|
1724
|
+
var priorities = [];
|
1725
|
+
// Create array unique of priorities
|
1726
|
+
for (var i = 0; i < this.constraints.length; i++)
|
1727
|
+
if (-1 === priorities.indexOf(this.constraints[i].priority))
|
1728
|
+
priorities.push(this.constraints[i].priority);
|
1729
|
+
// Sort them by priority DESC
|
1730
|
+
priorities.sort(function (a, b) { return b - a; });
|
1731
|
+
return priorities;
|
1418
1732
|
}
|
1419
1733
|
};
|
1420
1734
|
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
var parsleyInstance = $( self ).data( type );
|
1439
|
-
|
1440
|
-
// if data never binded or we want to clone a build (for radio & checkboxes), bind it right now!
|
1441
|
-
if ( !parsleyInstance ) {
|
1442
|
-
switch ( type ) {
|
1443
|
-
case 'parsleyForm':
|
1444
|
-
parsleyInstance = new ParsleyForm( self, options, 'parsleyForm' );
|
1445
|
-
break;
|
1446
|
-
case 'parsleyField':
|
1447
|
-
parsleyInstance = new ParsleyField( self, options, 'parsleyField' );
|
1448
|
-
break;
|
1449
|
-
case 'parsleyFieldMultiple':
|
1450
|
-
parsleyInstance = new ParsleyFieldMultiple( self, options, 'parsleyFieldMultiple' );
|
1451
|
-
break;
|
1452
|
-
default:
|
1453
|
-
return;
|
1454
|
-
}
|
1455
|
-
|
1456
|
-
$( self ).data( type, parsleyInstance );
|
1735
|
+
var ParsleyMultiple = function () {
|
1736
|
+
this.__class__ = 'ParsleyFieldMultiple';
|
1737
|
+
};
|
1738
|
+
ParsleyMultiple.prototype = {
|
1739
|
+
// Add new `$element` sibling for multiple field
|
1740
|
+
addElement: function ($element) {
|
1741
|
+
this.$elements.push($element);
|
1742
|
+
return this;
|
1743
|
+
},
|
1744
|
+
// See `ParsleyField.refreshConstraints()`
|
1745
|
+
refreshConstraints: function () {
|
1746
|
+
var fieldConstraints;
|
1747
|
+
this.constraints = [];
|
1748
|
+
// Select multiple special treatment
|
1749
|
+
if (this.$element.is('select')) {
|
1750
|
+
this.actualizeOptions()._bindConstraints();
|
1751
|
+
return this;
|
1457
1752
|
}
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
var
|
1462
|
-
|
1463
|
-
return 'undefined' !== typeof response ? response : $( self );
|
1753
|
+
// Gather all constraints for each input in the multiple group
|
1754
|
+
for (var i = 0; i < this.$elements.length; i++) {
|
1755
|
+
fieldConstraints = this.$elements[i].data('ParsleyFieldMultiple').refreshConstraints().constraints;
|
1756
|
+
for (var j = 0; j < fieldConstraints.length; j++)
|
1757
|
+
this.addConstraint(fieldConstraints[j].name, fieldConstraints[j].requirements, fieldConstraints[j].priority, fieldConstraints[j].isDomConstraint);
|
1464
1758
|
}
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1759
|
+
return this;
|
1760
|
+
},
|
1761
|
+
// See `ParsleyField.getValue()`
|
1762
|
+
getValue: function () {
|
1763
|
+
// Value could be overriden in DOM
|
1764
|
+
if ('undefined' !== typeof this.options.value)
|
1765
|
+
return this.options.value;
|
1766
|
+
// Radio input case
|
1767
|
+
if (this.$element.is('input[type=radio]'))
|
1768
|
+
return $('[' + this.options.namespace + 'multiple="' + this.options.multiple + '"]:checked').val() || '';
|
1769
|
+
// checkbox input case
|
1770
|
+
if (this.$element.is('input[type=checkbox]')) {
|
1771
|
+
var values = [];
|
1772
|
+
$('[' + this.options.namespace + 'multiple="' + this.options.multiple + '"]:checked').each(function () {
|
1773
|
+
values.push($(this).val());
|
1774
|
+
});
|
1775
|
+
return values.length ? values : [];
|
1776
|
+
}
|
1777
|
+
// Select multiple case
|
1778
|
+
if (this.$element.is('select') && null === this.$element.val())
|
1779
|
+
return [];
|
1780
|
+
// Default case that should never happen
|
1781
|
+
return this.$element.val();
|
1782
|
+
},
|
1783
|
+
_init: function (multiple) {
|
1784
|
+
this.$elements = [this.$element];
|
1785
|
+
this.options.multiple = multiple;
|
1786
|
+
return this;
|
1477
1787
|
}
|
1478
|
-
|
1479
|
-
return 'function' === typeof fn ? fn() : newInstance;
|
1480
1788
|
};
|
1481
1789
|
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
, regex = new RegExp("^" + namespace, 'i');
|
1496
|
-
|
1497
|
-
if ( 'undefined' === typeof this[ 0 ] ) {
|
1498
|
-
return {};
|
1499
|
-
}
|
1500
|
-
|
1501
|
-
for ( var i in this[ 0 ].attributes ) {
|
1502
|
-
attribute = this[ 0 ].attributes[ i ];
|
1503
|
-
|
1504
|
-
if ( 'undefined' !== typeof attribute && null !== attribute && attribute.specified && regex.test( attribute.name ) ) {
|
1505
|
-
obj[ camelize( attribute.name.replace( namespace, '' ) ) ] = deserializeValue( attribute.value );
|
1506
|
-
}
|
1507
|
-
}
|
1508
|
-
|
1509
|
-
return obj;
|
1790
|
+
var
|
1791
|
+
o = $({}),
|
1792
|
+
subscribed = {};
|
1793
|
+
// $.listen(name, callback);
|
1794
|
+
// $.listen(name, context, callback);
|
1795
|
+
$.listen = function (name) {
|
1796
|
+
if ('undefined' === typeof subscribed[name])
|
1797
|
+
subscribed[name] = [];
|
1798
|
+
if ('function' === typeof arguments[1])
|
1799
|
+
return subscribed[name].push({ fn: arguments[1] });
|
1800
|
+
if ('object' === typeof arguments[1] && 'function' === typeof arguments[2])
|
1801
|
+
return subscribed[name].push({ fn: arguments[2], ctxt: arguments[1] });
|
1802
|
+
throw new Error('Wrong parameters');
|
1510
1803
|
};
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
// String => self
|
1520
|
-
var deserializeValue = function( value ) {
|
1521
|
-
var num
|
1522
|
-
try {
|
1523
|
-
return value ?
|
1524
|
-
value == "true" ||
|
1525
|
-
( value == "false" ? false :
|
1526
|
-
value == "null" ? null :
|
1527
|
-
!isNaN( num = Number( value ) ) ? num :
|
1528
|
-
/^[\[\{]/.test( value ) ? $.parseJSON( value ) :
|
1529
|
-
value )
|
1530
|
-
: value;
|
1531
|
-
} catch ( e ) {
|
1532
|
-
return value;
|
1533
|
-
}
|
1804
|
+
$.listenTo = function (instance, name, fn) {
|
1805
|
+
if ('undefined' === typeof subscribed[name])
|
1806
|
+
subscribed[name] = [];
|
1807
|
+
if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
|
1808
|
+
throw new Error('Must give Parsley instance');
|
1809
|
+
if ('string' !== typeof name || 'function' !== typeof fn)
|
1810
|
+
throw new Error('Wrong parameters');
|
1811
|
+
subscribed[name].push({ instance: instance, fn: fn });
|
1534
1812
|
};
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1813
|
+
$.unsubscribe = function (name, fn) {
|
1814
|
+
if ('undefined' === typeof subscribed[name])
|
1815
|
+
return;
|
1816
|
+
if ('string' !== typeof name || 'function' !== typeof fn)
|
1817
|
+
throw new Error('Wrong arguments');
|
1818
|
+
for (var i = 0; i < subscribed[name].length; i++)
|
1819
|
+
if (subscribed[name][i].fn === fn)
|
1820
|
+
return subscribed[name].splice(i, 1);
|
1541
1821
|
};
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1822
|
+
$.unsubscribeTo = function (instance, name) {
|
1823
|
+
if ('undefined' === typeof subscribed[name])
|
1824
|
+
return;
|
1825
|
+
if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
|
1826
|
+
throw new Error('Must give Parsley instance');
|
1827
|
+
for (var i = 0; i < subscribed[name].length; i++)
|
1828
|
+
if ('undefined' !== typeof subscribed[name][i].instance && subscribed[name][i].instance.__id__ === instance.__id__)
|
1829
|
+
return subscribed[name].splice(i, 1);
|
1550
1830
|
};
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
$.
|
1559
|
-
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
1566
|
-
|
1567
|
-
|
1568
|
-
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
|
1573
|
-
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1831
|
+
$.unsubscribeAll = function (name) {
|
1832
|
+
if ('undefined' === typeof subscribed[name])
|
1833
|
+
return;
|
1834
|
+
delete subscribed[name];
|
1835
|
+
};
|
1836
|
+
// $.emit(name [, arguments...]);
|
1837
|
+
// $.emit(name, instance [, arguments..]);
|
1838
|
+
$.emit = function (name, instance) {
|
1839
|
+
if ('undefined' === typeof subscribed[name])
|
1840
|
+
return;
|
1841
|
+
// loop through registered callbacks for this event
|
1842
|
+
for (var i = 0; i < subscribed[name].length; i++) {
|
1843
|
+
// if instance is not registered, simple emit
|
1844
|
+
if ('undefined' === typeof subscribed[name][i].instance) {
|
1845
|
+
subscribed[name][i].fn.apply('undefined' !== typeof subscribed[name][i].ctxt ? subscribed[name][i].ctxt : o, Array.prototype.slice.call(arguments, 1));
|
1846
|
+
continue;
|
1847
|
+
}
|
1848
|
+
// if instance registered but no instance given for the emit, continue
|
1849
|
+
if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
|
1850
|
+
continue;
|
1851
|
+
// if instance is registered and same id, emit
|
1852
|
+
if (subscribed[name][i].instance.__id__ === instance.__id__) {
|
1853
|
+
subscribed[name][i].fn.apply(o, Array.prototype.slice.call(arguments, 1));
|
1854
|
+
continue;
|
1855
|
+
}
|
1856
|
+
// if registered instance is a Form and fired one is a Field, loop over all its fields and emit if field found
|
1857
|
+
if (subscribed[name][i].instance instanceof ParsleyForm && instance instanceof ParsleyField)
|
1858
|
+
for (var j = 0; j < subscribed[name][i].instance.fields.length; j++)
|
1859
|
+
if (subscribed[name][i].instance.fields[j].__id__ === instance.__id__) {
|
1860
|
+
subscribed[name][i].fn.apply(o, Array.prototype.slice.call(arguments, 1));
|
1861
|
+
continue;
|
1862
|
+
}
|
1863
|
+
}
|
1864
|
+
};
|
1865
|
+
$.subscribed = function () { return subscribed; };
|
1866
|
+
|
1867
|
+
// ParsleyConfig definition if not already set
|
1868
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
1869
|
+
window.ParsleyConfig.i18n = window.ParsleyConfig.i18n || {};
|
1870
|
+
// Define then the messages
|
1871
|
+
window.ParsleyConfig.i18n.en = $.extend(window.ParsleyConfig.i18n.en || {}, {
|
1872
|
+
defaultMessage: "This value seems to be invalid.",
|
1873
|
+
type: {
|
1874
|
+
email: "This value should be a valid email.",
|
1875
|
+
url: "This value should be a valid url.",
|
1876
|
+
number: "This value should be a valid number.",
|
1877
|
+
integer: "This value should be a valid integer.",
|
1878
|
+
digits: "This value should be digits.",
|
1879
|
+
alphanum: "This value should be alphanumeric."
|
1880
|
+
},
|
1881
|
+
notblank: "This value should not be blank.",
|
1882
|
+
required: "This value is required.",
|
1883
|
+
pattern: "This value seems to be invalid.",
|
1884
|
+
min: "This value should be greater than or equal to %s.",
|
1885
|
+
max: "This value should be lower than or equal to %s.",
|
1886
|
+
range: "This value should be between %s and %s.",
|
1887
|
+
minlength: "This value is too short. It should have %s characters or more.",
|
1888
|
+
maxlength: "This value is too long. It should have %s characters or less.",
|
1889
|
+
length: "This value length is invalid. It should be between %s and %s characters long.",
|
1890
|
+
mincheck: "You must select at least %s choices.",
|
1891
|
+
maxcheck: "You must select %s choices or less.",
|
1892
|
+
check: "You must select between %s and %s choices.",
|
1893
|
+
equalto: "This value should be the same."
|
1894
|
+
});
|
1895
|
+
// If file is loaded after Parsley main file, auto-load locale
|
1896
|
+
if ('undefined' !== typeof window.ParsleyValidator)
|
1897
|
+
window.ParsleyValidator.addCatalog('en', window.ParsleyConfig.i18n.en, true);
|
1898
|
+
|
1899
|
+
// Parsley.js 2.0.0
|
1900
|
+
// http://parsleyjs.org
|
1901
|
+
// (c) 20012-2014 Guillaume Potier, Wisembly
|
1902
|
+
// Parsley may be freely distributed under the MIT license.
|
1903
|
+
|
1904
|
+
// ### Parsley factory
|
1905
|
+
var Parsley = function (element, options, parsleyFormInstance) {
|
1906
|
+
this.__class__ = 'Parsley';
|
1907
|
+
this.__version__ = '2.0.0';
|
1908
|
+
this.__id__ = ParsleyUtils.hash(4);
|
1909
|
+
// Parsley must be instanciated with a DOM element or jQuery $element
|
1910
|
+
if ('undefined' === typeof element)
|
1911
|
+
throw new Error('You must give an element');
|
1912
|
+
if ('undefined' !== typeof parsleyFormInstance && 'ParsleyForm' !== parsleyFormInstance.__class__)
|
1913
|
+
throw new Error('Parent instance must be a ParsleyForm instance');
|
1914
|
+
return this.init($(element), options, parsleyFormInstance);
|
1915
|
+
};
|
1916
|
+
Parsley.prototype = {
|
1917
|
+
init: function ($element, options, parsleyFormInstance) {
|
1918
|
+
if (!$element.length)
|
1919
|
+
throw new Error('You must bind Parsley on an existing element.');
|
1920
|
+
this.$element = $element;
|
1921
|
+
// If element have already been binded, returns its saved Parsley instance
|
1922
|
+
if (this.$element.data('Parsley')) {
|
1923
|
+
var savedparsleyFormInstance = this.$element.data('Parsley');
|
1924
|
+
// If saved instance have been binded without a ParsleyForm parent and there is one given in this call, add it
|
1925
|
+
if ('undefined' !== typeof parsleyFormInstance)
|
1926
|
+
savedparsleyFormInstance.parent = parsleyFormInstance;
|
1927
|
+
return savedparsleyFormInstance;
|
1928
|
+
}
|
1929
|
+
// Handle 'static' options
|
1930
|
+
this.OptionsFactory = new ParsleyOptionsFactory(ParsleyDefaults, ParsleyUtils.get(window, 'ParsleyConfig') || {}, options, this.getNamespace(options));
|
1931
|
+
this.options = this.OptionsFactory.get(this);
|
1932
|
+
// A ParsleyForm instance is obviously a `<form>` elem but also every node that is not an input and have `data-parsley-validate` attribute
|
1933
|
+
if (this.$element.is('form') || (ParsleyUtils.attr(this.$element, this.options.namespace, 'validate') && !this.$element.is(this.options.inputs)))
|
1934
|
+
return this.bind('parsleyForm');
|
1935
|
+
// Every other supported element and not excluded element is binded as a `ParsleyField` or `ParsleyFieldMultiple`
|
1936
|
+
else if (this.$element.is(this.options.inputs) && !this.$element.is(this.options.excluded))
|
1937
|
+
return this.isMultiple() ? this.handleMultiple(parsleyFormInstance) : this.bind('parsleyField', parsleyFormInstance);
|
1938
|
+
return this;
|
1939
|
+
},
|
1940
|
+
isMultiple: function () {
|
1941
|
+
return (this.$element.is('input[type=radio], input[type=checkbox]') && 'undefined' === typeof this.options.multiple) || (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple'));
|
1942
|
+
},
|
1943
|
+
// Multiples fields are a real nightmare :(
|
1944
|
+
// Maybe some refacto would be appreciated here..
|
1945
|
+
handleMultiple: function (parsleyFormInstance) {
|
1946
|
+
var
|
1947
|
+
that = this,
|
1948
|
+
name,
|
1949
|
+
multiple,
|
1950
|
+
parsleyMultipleInstance;
|
1951
|
+
// Get parsleyFormInstance options if exist, mixed with element attributes
|
1952
|
+
this.options = $.extend(this.options, parsleyFormInstance ? parsleyFormInstance.OptionsFactory.get(parsleyFormInstance) : {}, ParsleyUtils.attr(this.$element, this.options.namespace));
|
1953
|
+
// Handle multiple name
|
1954
|
+
if (this.options.multiple) {
|
1955
|
+
multiple = this.options.multiple;
|
1956
|
+
} else if ('undefined' !== typeof this.$element.attr('name') && this.$element.attr('name').length) {
|
1957
|
+
multiple = name = this.$element.attr('name');
|
1958
|
+
} else if ('undefined' !== typeof this.$element.attr('id') && this.$element.attr('id').length) {
|
1959
|
+
multiple = this.$element.attr('id');
|
1960
|
+
}
|
1961
|
+
// Special select multiple input
|
1962
|
+
if (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple')) {
|
1963
|
+
return this.bind('parsleyFieldMultiple', parsleyFormInstance, multiple || this.__id__);
|
1964
|
+
// Else for radio / checkboxes, we need a `name` or `data-parsley-multiple` to properly bind it
|
1965
|
+
} else if ('undefined' === typeof multiple) {
|
1966
|
+
if (window.console && window.console.warn)
|
1967
|
+
window.console.warn('To be binded by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.', this.$element);
|
1968
|
+
return this;
|
1969
|
+
}
|
1970
|
+
// Remove special chars
|
1971
|
+
multiple = multiple.replace(/(:|\.|\[|\]|\$)/g, '');
|
1972
|
+
// Add proper `data-parsley-multiple` to siblings if we had a name
|
1973
|
+
if ('undefined' !== typeof name)
|
1974
|
+
$('input[name="' + name + '"]').each(function () {
|
1975
|
+
if ($(this).is('input[type=radio], input[type=checkbox]'))
|
1976
|
+
$(this).attr(that.options.namespace + 'multiple', multiple);
|
1977
|
+
});
|
1978
|
+
// Check here if we don't already have a related multiple instance saved
|
1979
|
+
if ($('[' + this.options.namespace + 'multiple=' + multiple +']').length)
|
1980
|
+
for (var i = 0; i < $('[' + this.options.namespace + 'multiple=' + multiple +']').length; i++)
|
1981
|
+
if ('undefined' !== typeof $($('[' + this.options.namespace + 'multiple=' + multiple +']').get(i)).data('Parsley')) {
|
1982
|
+
parsleyMultipleInstance = $($('[' + this.options.namespace + 'multiple=' + multiple +']').get(i)).data('Parsley');
|
1983
|
+
if (!this.$element.data('ParsleyFieldMultiple')) {
|
1984
|
+
parsleyMultipleInstance.addElement(this.$element);
|
1985
|
+
this.$element.attr(this.options.namespace + 'id', parsleyMultipleInstance.__id__);
|
1986
|
+
}
|
1987
|
+
break;
|
1988
|
+
}
|
1989
|
+
// Create a secret ParsleyField instance for every multiple field. It would be stored in `data('ParsleyFieldMultiple')`
|
1990
|
+
// And would be useful later to access classic `ParsleyField` stuff while being in a `ParsleyFieldMultiple` instance
|
1991
|
+
this.bind('parsleyField', parsleyFormInstance, multiple, true);
|
1992
|
+
return parsleyMultipleInstance || this.bind('parsleyFieldMultiple', parsleyFormInstance, multiple);
|
1993
|
+
},
|
1994
|
+
// Retrieve namespace used for DOM-API
|
1995
|
+
getNamespace: function (options) {
|
1996
|
+
// `data-parsley-namespace=<namespace>`
|
1997
|
+
if ('undefined' !== typeof this.$element.data('parsleyNamespace'))
|
1998
|
+
return this.$element.data('parsleyNamespace');
|
1999
|
+
if ('undefined' !== typeof ParsleyUtils.get(options, 'namespace'))
|
2000
|
+
return options.namespace;
|
2001
|
+
if ('undefined' !== typeof ParsleyUtils.get(window, 'ParsleyConfig.namespace'))
|
2002
|
+
return window.ParsleyConfig.namespace;
|
2003
|
+
return ParsleyDefaults.namespace;
|
2004
|
+
},
|
2005
|
+
// Return proper `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`
|
2006
|
+
bind: function (type, parentParsleyFormInstance, multiple, doNotStore) {
|
2007
|
+
var parsleyInstance;
|
2008
|
+
switch (type) {
|
2009
|
+
case 'parsleyForm':
|
2010
|
+
parsleyInstance = $.extend(
|
2011
|
+
new ParsleyForm(this.$element, this.OptionsFactory),
|
2012
|
+
new ParsleyAbstract(),
|
2013
|
+
window.ParsleyExtend
|
2014
|
+
)._bindFields();
|
2015
|
+
break;
|
2016
|
+
case 'parsleyField':
|
2017
|
+
parsleyInstance = $.extend(
|
2018
|
+
new ParsleyField(this.$element, this.OptionsFactory, parentParsleyFormInstance),
|
2019
|
+
new ParsleyAbstract(),
|
2020
|
+
window.ParsleyExtend
|
2021
|
+
);
|
2022
|
+
break;
|
2023
|
+
case 'parsleyFieldMultiple':
|
2024
|
+
parsleyInstance = $.extend(
|
2025
|
+
new ParsleyField(this.$element, this.OptionsFactory, parentParsleyFormInstance),
|
2026
|
+
new ParsleyAbstract(),
|
2027
|
+
new ParsleyMultiple(),
|
2028
|
+
window.ParsleyExtend
|
2029
|
+
)._init(multiple);
|
2030
|
+
break;
|
2031
|
+
default:
|
2032
|
+
throw new Error(type + 'is not a supported Parsley type');
|
2033
|
+
}
|
2034
|
+
if ('undefined' !== typeof multiple)
|
2035
|
+
ParsleyUtils.setAttr(this.$element, this.options.namespace, 'multiple', multiple);
|
2036
|
+
if ('undefined' !== typeof doNotStore) {
|
2037
|
+
this.$element.data('ParsleyFieldMultiple', parsleyInstance);
|
2038
|
+
return parsleyInstance;
|
2039
|
+
}
|
2040
|
+
// Store instance if `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`
|
2041
|
+
if (new RegExp('ParsleyF', 'i').test(parsleyInstance.__class__)) {
|
2042
|
+
// Store for later access the freshly binded instance in DOM element itself using jQuery `data()`
|
2043
|
+
this.$element.data('Parsley', parsleyInstance);
|
2044
|
+
// Tell the world we got a new ParsleyForm or ParsleyField instance!
|
2045
|
+
$.emit('parsley:' + ('parsleyForm' === type ? 'form' : 'field') + ':init', parsleyInstance);
|
1585
2046
|
}
|
1586
|
-
|
1587
|
-
onFieldValidate: function ( elem, ParsleyField ) { return false; } // Executed on validation. Return true to ignore field validation
|
1588
|
-
, onFormValidate: function ( isFormValid, event, ParsleyForm ) {} // Executed once on form validation. Return (bool) false to block submit, even if valid
|
1589
|
-
, onFieldError: function ( elem, constraints, ParsleyField ) {} // Executed when a field is detected as invalid
|
1590
|
-
, onFieldSuccess: function ( elem, constraints, ParsleyField ) {} // Executed when a field passes validation
|
2047
|
+
return parsleyInstance;
|
1591
2048
|
}
|
1592
2049
|
};
|
1593
|
-
|
1594
|
-
//
|
1595
|
-
|
2050
|
+
// ### jQuery API
|
2051
|
+
// `$('.elem').parsley(options)` or `$('.elem').psly(options)`
|
2052
|
+
$.fn.parsley = $.fn.psly = function (options) {
|
2053
|
+
if (this.length > 1) {
|
2054
|
+
var instances = [];
|
2055
|
+
this.each(function () {
|
2056
|
+
instances.push($(this).parsley(options));
|
2057
|
+
});
|
2058
|
+
return instances;
|
2059
|
+
}
|
2060
|
+
// Return undefined if applied to non existing DOM element
|
2061
|
+
if (!$(this).length) {
|
2062
|
+
if (window.console && window.console.warn)
|
2063
|
+
window.console.warn('You must bind Parsley on an existing element.');
|
2064
|
+
return;
|
2065
|
+
}
|
2066
|
+
return new Parsley(this, options);
|
2067
|
+
};
|
2068
|
+
// ### ParsleyUI
|
2069
|
+
// UI is a class apart that only listen to some events and them modify DOM accordingly
|
2070
|
+
// Could be overriden by defining a `window.ParsleyConfig.ParsleyUI` appropriate class (with `listen()` method basically)
|
2071
|
+
window.ParsleyUI = 'function' === typeof ParsleyUtils.get(window, 'ParsleyConfig.ParsleyUI') ?
|
2072
|
+
new window.ParsleyConfig.ParsleyUI().listen() : new ParsleyUI().listen();
|
2073
|
+
// ### ParsleyField and ParsleyForm extension
|
2074
|
+
// Ensure that defined if not already the case
|
2075
|
+
if ('undefined' === typeof window.ParsleyExtend)
|
2076
|
+
window.ParsleyExtend = {};
|
2077
|
+
// ### ParsleyConfig
|
2078
|
+
// Ensure that defined if not already the case
|
2079
|
+
if ('undefined' === typeof window.ParsleyConfig)
|
2080
|
+
window.ParsleyConfig = {};
|
2081
|
+
// ### Globals
|
2082
|
+
window.Parsley = window.psly = Parsley;
|
2083
|
+
window.ParsleyUtils = ParsleyUtils;
|
2084
|
+
window.ParsleyValidator = new ParsleyValidator(window.ParsleyConfig.validators, window.ParsleyConfig.i18n);
|
2085
|
+
// ### PARSLEY auto-binding
|
2086
|
+
// Prevent it by setting `ParsleyConfig.autoBind` to `false`
|
2087
|
+
if (false !== ParsleyUtils.get(window, 'ParsleyConfig.autoBind'))
|
2088
|
+
$(document).ready(function () {
|
2089
|
+
// Works only on `data-parsley-validate`.
|
2090
|
+
if ($('[data-parsley-validate]').length)
|
2091
|
+
$('[data-parsley-validate]').parsley();
|
2092
|
+
});
|
2093
|
+
|
2094
|
+
// AMD Compliance
|
2095
|
+
if ('function' === typeof define && define.amd)
|
2096
|
+
define('parsley', function() { return window.Parsley; } );
|
2097
|
+
})(window.jQuery);
|