jekyll-theme-ici3d 0.1.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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +50 -0
- data/_data/publications/pulliam2012.yml +12 -0
- data/_data/team/ackley.yml +25 -0
- data/_data/team/are.yml +22 -0
- data/_data/team/beauclair.yml +14 -0
- data/_data/team/bekele.yml +14 -0
- data/_data/team/bellan.yml +46 -0
- data/_data/team/bolton.yml +33 -0
- data/_data/team/borchering.yml +65 -0
- data/_data/team/brook.yml +15 -0
- data/_data/team/brown.yml +18 -0
- data/_data/team/bruce.yml +26 -0
- data/_data/team/brucePA.yml +9 -0
- data/_data/team/deleo.yml +49 -0
- data/_data/team/delva.yml +15 -0
- data/_data/team/dushoff.yml +52 -0
- data/_data/team/ervin.yml +10 -0
- data/_data/team/faikah.yml +26 -0
- data/_data/team/grebe.yml +36 -0
- data/_data/team/hargrove.yml +36 -0
- data/_data/team/hitchcock.yml +10 -0
- data/_data/team/hladish.yml +45 -0
- data/_data/team/january.yml +9 -0
- data/_data/team/kassanjee.yml +20 -0
- data/_data/team/li.yml +45 -0
- data/_data/team/lord.yml +20 -0
- data/_data/team/marx.yml +14 -0
- data/_data/team/mcintosh.yml +20 -0
- data/_data/team/mhlanga.yml +22 -0
- data/_data/team/mthombothi.yml +23 -0
- data/_data/team/mugwagwa.yml +18 -0
- data/_data/team/mwangi.yml +24 -0
- data/_data/team/mwebaze.yml +20 -0
- data/_data/team/ndifon.yml +18 -0
- data/_data/team/ngonghala.yml +30 -0
- data/_data/team/nondi.yml +14 -0
- data/_data/team/nyamai.yml +18 -0
- data/_data/team/october.yml +9 -0
- data/_data/team/paradza.yml +19 -0
- data/_data/team/pearson.yml +58 -0
- data/_data/team/porco.yml +14 -0
- data/_data/team/pulliam.yml +51 -0
- data/_data/team/reiner.yml +18 -0
- data/_data/team/scheepers.yml +9 -0
- data/_data/team/scott.yml +51 -0
- data/_data/team/sempa.yml +32 -0
- data/_data/team/sikhondze.yml +14 -0
- data/_data/team/template.yml +18 -0
- data/_data/team/ujeneza.yml +38 -0
- data/_data/team/vanschalkwyk.yml +32 -0
- data/_data/team/welte.yml +18 -0
- data/_data/team/williams.yml +28 -0
- data/_data/team/ying.yml +21 -0
- data/_includes/MedPH/.DS_Store +0 -0
- data/_includes/MedPH/assignments.md +42 -0
- data/_includes/MedPH/assignmentsStandard.md +74 -0
- data/_includes/MedPH/computerlabs.md +38 -0
- data/_includes/MedPH/computerlabsStandard.md +38 -0
- data/_includes/MedPH/lectures.md +12 -0
- data/_includes/MedPH/references.md +71 -0
- data/_includes/MedPH/schedule.md +85 -0
- data/_includes/MedPH/scheduleStandard.md +93 -0
- data/_includes/bottomTable.html +5 -0
- data/_includes/centerTable.html +5 -0
- data/_includes/clinicNavbar.html +46 -0
- data/_includes/contact.html +12 -0
- data/_includes/directors.html +47 -0
- data/_includes/footer.html +23 -0
- data/_includes/head.html +28 -0
- data/_includes/header.html +31 -0
- data/_includes/hero.html +14 -0
- data/_includes/index.md +9 -0
- data/_includes/mission.html +13 -0
- data/_includes/navStructure.html +70 -0
- data/_includes/navbar.html +65 -0
- data/_includes/outputs.html +74 -0
- data/_includes/partners.html +75 -0
- data/_includes/profile.html +67 -0
- data/_includes/publications/faculty.md +13 -0
- data/_includes/publications/instructional.md +5 -0
- data/_includes/publications/participant.md +33 -0
- data/_includes/talk.html +12 -0
- data/_includes/topTable.html +6 -0
- data/_includes/upcoming.html +43 -0
- data/_layouts/clinic.liquid +43 -0
- data/_layouts/example.liquid +601 -0
- data/_layouts/main.liquid +34 -0
- data/_layouts/medph.page.liquid +60 -0
- data/_layouts/page.liquid +41 -0
- data/_layouts/people.page.liquid +27 -0
- data/_layouts/profile.liquid +44 -0
- data/_layouts/redirect.liquid +15 -0
- data/_layouts/talk.liquid +42 -0
- data/assets/css/academicons.css +249 -0
- data/assets/css/academicons.min.css +1 -0
- data/assets/css/bootstrap.css +6760 -0
- data/assets/css/bootstrap.css.map +1 -0
- data/assets/css/bootstrap.min.css +6 -0
- data/assets/css/font-awesome.css +2086 -0
- data/assets/css/font-awesome.min.css +4 -0
- data/assets/css/ie.css +5 -0
- data/assets/css/main-one-page.css +6433 -0
- data/assets/css/main.css +7160 -0
- data/assets/css/my-custom-styles.css +14 -0
- data/assets/css/shop-main.css +3117 -0
- data/assets/css/skins/brown.css +299 -0
- data/assets/css/skins/deepskyblue.css +299 -0
- data/assets/css/skins/goldenrod.css +299 -0
- data/assets/css/skins/ici3dBlue.css +229 -0
- data/assets/css/skins/ici3dBlue.css.map +7 -0
- data/assets/css/skins/ici3dIndigo.css +229 -0
- data/assets/css/skins/ici3dIndigo.css.map +7 -0
- data/assets/css/skins/indianred.css +299 -0
- data/assets/css/skins/lightgreen.css +299 -0
- data/assets/css/skins/orange.css +299 -0
- data/assets/css/skins/seagreen.css +299 -0
- data/assets/css/skins/slategray.css +299 -0
- data/assets/fonts/academicons.eot +0 -0
- data/assets/fonts/academicons.svg +66 -0
- data/assets/fonts/academicons.ttf +0 -0
- data/assets/fonts/academicons.woff +0 -0
- data/assets/fonts/fontawesome-webfont.eot +0 -0
- data/assets/fonts/fontawesome-webfont.svg +655 -0
- data/assets/fonts/fontawesome-webfont.ttf +0 -0
- data/assets/fonts/fontawesome-webfont.woff +0 -0
- data/assets/fonts/fontawesome-webfont.woff2 +0 -0
- data/assets/fonts/glyphicons-halflings-regular.eot +0 -0
- data/assets/fonts/glyphicons-halflings-regular.svg +288 -0
- data/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/assets/fonts/glyphicons-halflings-regular.woff +0 -0
- data/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/assets/ico/favicon.ico +0 -0
- data/assets/ico/favicon.png +0 -0
- data/assets/ico/ici3d114x114.png +0 -0
- data/assets/ico/ici3d144x144.png +0 -0
- data/assets/ico/ici3d57x57.png +0 -0
- data/assets/ico/ici3d72x72.png +0 -0
- data/assets/img/8hearts.png +0 -0
- data/assets/img/MMED2015_tutorials.jpg +0 -0
- data/assets/img/badge.png +0 -0
- data/assets/img/blog/balloon-med.jpg +0 -0
- data/assets/img/blog/balloon.jpg +0 -0
- data/assets/img/blog/buildings-med.jpg +0 -0
- data/assets/img/blog/buildings.jpg +0 -0
- data/assets/img/blog/people-med.jpg +0 -0
- data/assets/img/blog/people.jpg +0 -0
- data/assets/img/bx_loader.gif +0 -0
- data/assets/img/clients/logo1.png +0 -0
- data/assets/img/clients/logo2.png +0 -0
- data/assets/img/clients/logo3.png +0 -0
- data/assets/img/clients/logo4.png +0 -0
- data/assets/img/clients/logo5.png +0 -0
- data/assets/img/flags/China.png +0 -0
- data/assets/img/flags/Germany.png +0 -0
- data/assets/img/flags/Japan.png +0 -0
- data/assets/img/flags/South-Africa.png +0 -0
- data/assets/img/flags/United-Kingdom.png +0 -0
- data/assets/img/flags/United-States.png +0 -0
- data/assets/img/free.png +0 -0
- data/assets/img/fullscreen-bg.jpg +0 -0
- data/assets/img/gray_jean.png +0 -0
- data/assets/img/hero-unit-bg.png +0 -0
- data/assets/img/hero-unit-obj.png +0 -0
- data/assets/img/hero-unit-obj2.png +0 -0
- data/assets/img/hero-unit-obj3.png +0 -0
- data/assets/img/intro-img.png +0 -0
- data/assets/img/location-pin.png +0 -0
- data/assets/img/logo/ici3d-logo-light.png +0 -0
- data/assets/img/logo/ici3d-logo-nav.png +0 -0
- data/assets/img/logo/ici3d-logo-white.png +0 -0
- data/assets/img/logo/ici3d-logo-white_v2.png +0 -0
- data/assets/img/logo/ici3d-logo-white_v3.png +0 -0
- data/assets/img/logo/repute-logo-light-brown.png +0 -0
- data/assets/img/logo/repute-logo-light-deepskyblue.png +0 -0
- data/assets/img/logo/repute-logo-light-goldenrod.png +0 -0
- data/assets/img/logo/repute-logo-light-indianred.png +0 -0
- data/assets/img/logo/repute-logo-light-lightgreen.png +0 -0
- data/assets/img/logo/repute-logo-light-orange.png +0 -0
- data/assets/img/logo/repute-logo-light-seagreen.png +0 -0
- data/assets/img/logo/repute-logo-light-slategray.png +0 -0
- data/assets/img/logo/repute-logo-light.png +0 -0
- data/assets/img/logo/repute-logo-nav-brown.png +0 -0
- data/assets/img/logo/repute-logo-nav-deepskyblue.png +0 -0
- data/assets/img/logo/repute-logo-nav-goldenrod.png +0 -0
- data/assets/img/logo/repute-logo-nav-indianred.png +0 -0
- data/assets/img/logo/repute-logo-nav-light.png +0 -0
- data/assets/img/logo/repute-logo-nav-lightgreen.png +0 -0
- data/assets/img/logo/repute-logo-nav-orange.png +0 -0
- data/assets/img/logo/repute-logo-nav-seagreen.png +0 -0
- data/assets/img/logo/repute-logo-nav-slategray.png +0 -0
- data/assets/img/logo/repute-logo-nav.png +0 -0
- data/assets/img/mentors/are.jpg +0 -0
- data/assets/img/mentors/bolton.jpg +0 -0
- data/assets/img/mentors/brown.jpg +0 -0
- data/assets/img/mentors/kassanjee.jpg +0 -0
- data/assets/img/mentors/mhlanga.jpg +0 -0
- data/assets/img/mentors/nyamai.png +0 -0
- data/assets/img/news/featured-news.png +0 -0
- data/assets/img/news/news1.png +0 -0
- data/assets/img/news/news2.png +0 -0
- data/assets/img/news/news3.png +0 -0
- data/assets/img/news/news4.png +0 -0
- data/assets/img/news/news5.png +0 -0
- data/assets/img/other/snoep.jpg +0 -0
- data/assets/img/page-header-bg.png +0 -0
- data/assets/img/participants/SempaJB.jpg +0 -0
- data/assets/img/partners/AIMS-SA.jpg +0 -0
- data/assets/img/partners/CEMA_UN.pdf +0 -0
- data/assets/img/partners/CEMA_UN.png +0 -0
- data/assets/img/partners/CIDID.png +0 -0
- data/assets/img/partners/CIDID_long.png +0 -0
- data/assets/img/partners/Colby.png +0 -0
- data/assets/img/partners/MIDAS.png +0 -0
- data/assets/img/partners/McMaster.jpg +0 -0
- data/assets/img/partners/PSU.png +0 -0
- data/assets/img/partners/Proctor.png +0 -0
- data/assets/img/partners/SACEMA_228.png +0 -0
- data/assets/img/partners/UCSF.png +0 -0
- data/assets/img/partners/UF.png +0 -0
- data/assets/img/partners/UGA_228.png +0 -0
- data/assets/img/pattern-geometry.png +0 -0
- data/assets/img/portfolio/800x500/work1.png +0 -0
- data/assets/img/portfolio/800x500/work2.png +0 -0
- data/assets/img/portfolio/800x500/work3.png +0 -0
- data/assets/img/portfolio/800x500/work4.png +0 -0
- data/assets/img/portfolio/800x500/work5.png +0 -0
- data/assets/img/portfolio/800x500/work6.png +0 -0
- data/assets/img/portfolio/800x500/work7.png +0 -0
- data/assets/img/portfolio/800x500/work8.png +0 -0
- data/assets/img/portfolio/800x800/work1.png +0 -0
- data/assets/img/portfolio/800x800/work2.png +0 -0
- data/assets/img/portfolio/800x800/work3.png +0 -0
- data/assets/img/portfolio/800x800/work4.png +0 -0
- data/assets/img/portfolio/800x800/work5.png +0 -0
- data/assets/img/portfolio/800x800/work6.png +0 -0
- data/assets/img/portfolio/800x800/work7.png +0 -0
- data/assets/img/portfolio/800x800/work8.png +0 -0
- data/assets/img/portfolio/single/bicycle.jpg +0 -0
- data/assets/img/portfolio/single/blurred_lines.jpg +0 -0
- data/assets/img/portfolio/single/edge.jpg +0 -0
- data/assets/img/scholars/ackley.jpg +0 -0
- data/assets/img/scholars/beauclair.jpg +0 -0
- data/assets/img/scholars/beauclair.png +0 -0
- data/assets/img/scholars/bekele.jpg +0 -0
- data/assets/img/scholars/lord.jpg +0 -0
- data/assets/img/scholars/marx.jpg +0 -0
- data/assets/img/scholars/mcintosh.jpg +0 -0
- data/assets/img/scholars/mwebaze.jpg +0 -0
- data/assets/img/scholars/nondi.jpg +0 -0
- data/assets/img/scholars/sempa.jpg +0 -0
- data/assets/img/scholars/ying.jpg +0 -0
- data/assets/img/sliders/full-slide-color.jpg +0 -0
- data/assets/img/sliders/full-slide-color2.jpg +0 -0
- data/assets/img/sliders/full-slide-color3.jpg +0 -0
- data/assets/img/sliders/full-slide.jpg +0 -0
- data/assets/img/sliders/full-slide2.jpg +0 -0
- data/assets/img/sliders/full-slide3.jpg +0 -0
- data/assets/img/sliders/slider1-h500.png +0 -0
- data/assets/img/sliders/slider2-h500.png +0 -0
- data/assets/img/sliders/slider3-h500.png +0 -0
- data/assets/img/team/bellan.jpg +0 -0
- data/assets/img/team/borchering.jpg +0 -0
- data/assets/img/team/brook.jpg +0 -0
- data/assets/img/team/bruce.jpg +0 -0
- data/assets/img/team/deleo.jpg +0 -0
- data/assets/img/team/delva.jpg +0 -0
- data/assets/img/team/dushoff.jpg +0 -0
- data/assets/img/team/ervin.jpg +0 -0
- data/assets/img/team/grebe.jpg +0 -0
- data/assets/img/team/hargrove.jpg +0 -0
- data/assets/img/team/hitchcock.jpg +0 -0
- data/assets/img/team/hladish.jpg +0 -0
- data/assets/img/team/january.jpg +0 -0
- data/assets/img/team/li.jpg +0 -0
- data/assets/img/team/mthombothi.jpg +0 -0
- data/assets/img/team/mugwagwa.jpg +0 -0
- data/assets/img/team/mwangi.png +0 -0
- data/assets/img/team/ndifon.jpg +0 -0
- data/assets/img/team/ngonghala.jpg +0 -0
- data/assets/img/team/october.jpg +0 -0
- data/assets/img/team/paradza.jpg +0 -0
- data/assets/img/team/pearson.jpg +0 -0
- data/assets/img/team/porco.jpg +0 -0
- data/assets/img/team/pulliam.jpg +0 -0
- data/assets/img/team/reiner.jpg +0 -0
- data/assets/img/team/scheepers.jpg +0 -0
- data/assets/img/team/scott.jpg +0 -0
- data/assets/img/team/ujeneza.jpg +0 -0
- data/assets/img/team/vanschalkwyk.jpg +0 -0
- data/assets/img/team/welte.jpg +0 -0
- data/assets/img/team/williams.jpg +0 -0
- data/assets/img/testimonial-bg.png +0 -0
- data/assets/img/transmission.png +0 -0
- data/assets/js/bootstrap.js +2363 -0
- data/assets/js/bootstrap.min.js +7 -0
- data/assets/js/jquery-2.1.1.min.js +4 -0
- data/assets/js/plugins/autohidingnavbar/jquery.bootstrap-autohidingnavbar.js +213 -0
- data/assets/js/plugins/autohidingnavbar/jquery.bootstrap-autohidingnavbar.min.js +9 -0
- data/assets/js/plugins/bootstrap-datepicker/bootstrap-datepicker.js +474 -0
- data/assets/js/plugins/bootstrap-multiselect/bootstrap-multiselect.js +994 -0
- data/assets/js/plugins/daterangepicker/daterangepicker.js +868 -0
- data/assets/js/plugins/easing/jquery.easing.js +205 -0
- data/assets/js/plugins/easing/jquery.easing.min.js +71 -0
- data/assets/js/plugins/fitvids/jquery.fitvids.js +83 -0
- data/assets/js/plugins/google-map/google-map.js +160 -0
- data/assets/js/plugins/isotope/isotope.pkgd.js +4049 -0
- data/assets/js/plugins/isotope/isotope.pkgd.min.js +8 -0
- data/assets/js/plugins/jquery-cycle/jquery.cycle.all.js +1543 -0
- data/assets/js/plugins/jquery-easypiechart/jquery.easypiechart.js +359 -0
- data/assets/js/plugins/jquery-easypiechart/jquery.easypiechart.min.js +9 -0
- data/assets/js/plugins/jquery-maskedinput/jquery.masked-input.js +338 -0
- data/assets/js/plugins/jquery-maskedinput/jquery.masked-input.min.js +7 -0
- data/assets/js/plugins/maximage/jquery.maximage.js +697 -0
- data/assets/js/plugins/maximage/jquery.maximage.min.js +4 -0
- data/assets/js/plugins/moment/moment.js +1662 -0
- data/assets/js/plugins/moment/moment.min.js +6 -0
- data/assets/js/plugins/parsley-validation/parsley.js +2074 -0
- data/assets/js/plugins/parsley-validation/parsley.min.js +9 -0
- data/assets/js/plugins/scrollto/jquery.localscroll-1.2.7-min.js +9 -0
- data/assets/js/plugins/scrollto/jquery.localscroll-1.2.7.js +133 -0
- data/assets/js/plugins/scrollto/jquery.scrollTo-1.4.3.1-min.js +7 -0
- data/assets/js/plugins/scrollto/jquery.scrollTo-1.4.3.1.js +218 -0
- data/assets/js/plugins/slick/slick.js +2643 -0
- data/assets/js/plugins/slick/slick.min.js +18 -0
- data/assets/js/plugins/stellar/jquery.stellar.js +660 -0
- data/assets/js/plugins/stellar/jquery.stellar.min.js +2 -0
- data/assets/js/repute-scripts.js +539 -0
- metadata +385 -0
@@ -0,0 +1,2074 @@
|
|
1
|
+
/*!
|
2
|
+
* Parsleyjs
|
3
|
+
* Guillaume Potier - <guillaume@wisembly.com>
|
4
|
+
* Version 2.0.6 - built Tue Dec 02 2014 17:12:12
|
5
|
+
* MIT Licensed
|
6
|
+
*
|
7
|
+
*/
|
8
|
+
!(function (factory) {
|
9
|
+
if (typeof define === 'function' && define.amd) {
|
10
|
+
// AMD. Register as an anonymous module depending on jQuery.
|
11
|
+
define(['jquery'], factory);
|
12
|
+
} else {
|
13
|
+
// No AMD. Register plugin with global jQuery object.
|
14
|
+
factory(jQuery);
|
15
|
+
}
|
16
|
+
}(function ($) {
|
17
|
+
// small hack for requirejs if jquery is loaded through map and not path
|
18
|
+
// see http://requirejs.org/docs/jquery.html
|
19
|
+
if ('undefined' === typeof $ && 'undefined' !== typeof window.jQuery)
|
20
|
+
$ = window.jQuery;
|
21
|
+
var ParsleyUtils = {
|
22
|
+
// Parsley DOM-API
|
23
|
+
// returns object from dom attributes and values
|
24
|
+
// if attr is given, returns bool if attr present in DOM or not
|
25
|
+
attr: function ($element, namespace, checkAttr) {
|
26
|
+
var
|
27
|
+
attribute,
|
28
|
+
obj = {},
|
29
|
+
msie = this.msieversion(),
|
30
|
+
regex = new RegExp('^' + namespace, 'i');
|
31
|
+
if ('undefined' === typeof $element || 'undefined' === typeof $element[0])
|
32
|
+
return {};
|
33
|
+
for (var i in $element[0].attributes) {
|
34
|
+
attribute = $element[0].attributes[i];
|
35
|
+
if ('undefined' !== typeof attribute && null !== attribute && (!msie || msie >= 8 || attribute.specified) && regex.test(attribute.name)) {
|
36
|
+
if ('undefined' !== typeof checkAttr && new RegExp(checkAttr + '$', 'i').test(attribute.name))
|
37
|
+
return true;
|
38
|
+
obj[this.camelize(attribute.name.replace(namespace, ''))] = this.deserializeValue(attribute.value);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
return 'undefined' === typeof checkAttr ? obj : false;
|
42
|
+
},
|
43
|
+
setAttr: function ($element, namespace, attr, value) {
|
44
|
+
$element[0].setAttribute(this.dasherize(namespace + attr), String(value));
|
45
|
+
},
|
46
|
+
// Recursive object / array getter
|
47
|
+
get: function (obj, path) {
|
48
|
+
var
|
49
|
+
i = 0,
|
50
|
+
paths = (path || '').split('.');
|
51
|
+
while (this.isObject(obj) || this.isArray(obj)) {
|
52
|
+
obj = obj[paths[i++]];
|
53
|
+
if (i === paths.length)
|
54
|
+
return obj;
|
55
|
+
}
|
56
|
+
return undefined;
|
57
|
+
},
|
58
|
+
hash: function (length) {
|
59
|
+
return String(Math.random()).substring(2, length ? length + 2 : 9);
|
60
|
+
},
|
61
|
+
/** Third party functions **/
|
62
|
+
// Underscore isArray
|
63
|
+
isArray: function (mixed) {
|
64
|
+
return Object.prototype.toString.call(mixed) === '[object Array]';
|
65
|
+
},
|
66
|
+
// Underscore isObject
|
67
|
+
isObject: function (mixed) {
|
68
|
+
return mixed === Object(mixed);
|
69
|
+
},
|
70
|
+
// Zepto deserialize function
|
71
|
+
deserializeValue: function (value) {
|
72
|
+
var num;
|
73
|
+
try {
|
74
|
+
return value ?
|
75
|
+
value == "true" ||
|
76
|
+
(value == "false" ? false :
|
77
|
+
value == "null" ? null :
|
78
|
+
!isNaN(num = Number(value)) ? num :
|
79
|
+
/^[\[\{]/.test(value) ? $.parseJSON(value) :
|
80
|
+
value)
|
81
|
+
: value;
|
82
|
+
} catch (e) { return value; }
|
83
|
+
},
|
84
|
+
// Zepto camelize function
|
85
|
+
camelize: function (str) {
|
86
|
+
return str.replace(/-+(.)?/g, function(match, chr) {
|
87
|
+
return chr ? chr.toUpperCase() : '';
|
88
|
+
});
|
89
|
+
},
|
90
|
+
// Zepto dasherize function
|
91
|
+
dasherize: function (str) {
|
92
|
+
return str.replace(/::/g, '/')
|
93
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
|
94
|
+
.replace(/([a-z\d])([A-Z])/g, '$1_$2')
|
95
|
+
.replace(/_/g, '-')
|
96
|
+
.toLowerCase();
|
97
|
+
},
|
98
|
+
// http://support.microsoft.com/kb/167820
|
99
|
+
// http://stackoverflow.com/questions/19999388/jquery-check-if-user-is-using-ie
|
100
|
+
msieversion: function () {
|
101
|
+
var
|
102
|
+
ua = window.navigator.userAgent,
|
103
|
+
msie = ua.indexOf('MSIE ');
|
104
|
+
if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./))
|
105
|
+
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
|
106
|
+
return 0;
|
107
|
+
}
|
108
|
+
};
|
109
|
+
// All these options could be overriden and specified directly in DOM using
|
110
|
+
// `data-parsley-` default DOM-API
|
111
|
+
// eg: `inputs` can be set in DOM using `data-parsley-inputs="input, textarea"`
|
112
|
+
// eg: `data-parsley-stop-on-first-failing-constraint="false"`
|
113
|
+
var ParsleyDefaults = {
|
114
|
+
// ### General
|
115
|
+
// Default data-namespace for DOM API
|
116
|
+
namespace: 'data-parsley-',
|
117
|
+
// Supported inputs by default
|
118
|
+
inputs: 'input, textarea, select',
|
119
|
+
// Excluded inputs by default
|
120
|
+
excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]',
|
121
|
+
// Stop validating field on highest priority failing constraint
|
122
|
+
priorityEnabled: true,
|
123
|
+
// ### UI
|
124
|
+
// Enable\Disable error messages
|
125
|
+
uiEnabled: true,
|
126
|
+
// Key events threshold before validation
|
127
|
+
validationThreshold: 3,
|
128
|
+
// Focused field on form validation error. 'fist'|'last'|'none'
|
129
|
+
focus: 'first',
|
130
|
+
// `$.Event()` that will trigger validation. eg: `keyup`, `change`..
|
131
|
+
trigger: false,
|
132
|
+
// Class that would be added on every failing validation Parsley field
|
133
|
+
errorClass: 'parsley-error',
|
134
|
+
// Same for success validation
|
135
|
+
successClass: 'parsley-success',
|
136
|
+
// Return the `$element` that will receive these above success or error classes
|
137
|
+
// Could also be (and given directly from DOM) a valid selector like `'#div'`
|
138
|
+
classHandler: function (ParsleyField) {},
|
139
|
+
// Return the `$element` where errors will be appended
|
140
|
+
// Could also be (and given directly from DOM) a valid selector like `'#div'`
|
141
|
+
errorsContainer: function (ParsleyField) {},
|
142
|
+
// ul elem that would receive errors' list
|
143
|
+
errorsWrapper: '<ul class="parsley-errors-list"></ul>',
|
144
|
+
// li elem that would receive error message
|
145
|
+
errorTemplate: '<li></li>'
|
146
|
+
};
|
147
|
+
|
148
|
+
var ParsleyAbstract = function() {};
|
149
|
+
ParsleyAbstract.prototype = {
|
150
|
+
asyncSupport: false,
|
151
|
+
actualizeOptions: function () {
|
152
|
+
this.options = this.OptionsFactory.get(this);
|
153
|
+
return this;
|
154
|
+
},
|
155
|
+
// ParsleyValidator validate proxy function . Could be replaced by third party scripts
|
156
|
+
validateThroughValidator: function (value, constraints, priority) {
|
157
|
+
return window.ParsleyValidator.validate.apply(window.ParsleyValidator, [value, constraints, priority]);
|
158
|
+
},
|
159
|
+
// Subscribe an event and a handler for a specific field or a specific form
|
160
|
+
// If on a ParsleyForm instance, it will be attached to form instance and also
|
161
|
+
// To every field instance for this form
|
162
|
+
subscribe: function (name, fn) {
|
163
|
+
$.listenTo(this, name.toLowerCase(), fn);
|
164
|
+
return this;
|
165
|
+
},
|
166
|
+
// Same as subscribe above. Unsubscribe an event for field, or form + its fields
|
167
|
+
unsubscribe: function (name) {
|
168
|
+
$.unsubscribeTo(this, name.toLowerCase());
|
169
|
+
return this;
|
170
|
+
},
|
171
|
+
// Reset UI
|
172
|
+
reset: function () {
|
173
|
+
// Field case: just emit a reset event for UI
|
174
|
+
if ('ParsleyForm' !== this.__class__)
|
175
|
+
return $.emit('parsley:field:reset', this);
|
176
|
+
// Form case: emit a reset event for each field
|
177
|
+
for (var i = 0; i < this.fields.length; i++)
|
178
|
+
$.emit('parsley:field:reset', this.fields[i]);
|
179
|
+
$.emit('parsley:form:reset', this);
|
180
|
+
},
|
181
|
+
// Destroy Parsley instance (+ UI)
|
182
|
+
destroy: function () {
|
183
|
+
// Field case: emit destroy event to clean UI and then destroy stored instance
|
184
|
+
if ('ParsleyForm' !== this.__class__) {
|
185
|
+
this.$element.removeData('Parsley');
|
186
|
+
this.$element.removeData('ParsleyFieldMultiple');
|
187
|
+
$.emit('parsley:field:destroy', this);
|
188
|
+
return;
|
189
|
+
}
|
190
|
+
// Form case: destroy all its fields and then destroy stored instance
|
191
|
+
for (var i = 0; i < this.fields.length; i++)
|
192
|
+
this.fields[i].destroy();
|
193
|
+
this.$element.removeData('Parsley');
|
194
|
+
$.emit('parsley:form:destroy', this);
|
195
|
+
}
|
196
|
+
};
|
197
|
+
/*!
|
198
|
+
* validator.js
|
199
|
+
* Guillaume Potier - <guillaume@wisembly.com>
|
200
|
+
* Version 1.0.0 - built Sun Aug 03 2014 17:42:31
|
201
|
+
* MIT Licensed
|
202
|
+
*
|
203
|
+
*/
|
204
|
+
var Validator = ( function ( ) {
|
205
|
+
var exports = {};
|
206
|
+
/**
|
207
|
+
* Validator
|
208
|
+
*/
|
209
|
+
var Validator = function ( options ) {
|
210
|
+
this.__class__ = 'Validator';
|
211
|
+
this.__version__ = '1.0.0';
|
212
|
+
this.options = options || {};
|
213
|
+
this.bindingKey = this.options.bindingKey || '_validatorjsConstraint';
|
214
|
+
};
|
215
|
+
Validator.prototype = {
|
216
|
+
constructor: Validator,
|
217
|
+
/*
|
218
|
+
* Validate string: validate( string, Assert, string ) || validate( string, [ Assert, Assert ], [ string, string ] )
|
219
|
+
* Validate object: validate( object, Constraint, string ) || validate( object, Constraint, [ string, string ] )
|
220
|
+
* Validate binded object: validate( object, string ) || validate( object, [ string, string ] )
|
221
|
+
*/
|
222
|
+
validate: function ( objectOrString, AssertsOrConstraintOrGroup, group ) {
|
223
|
+
if ( 'string' !== typeof objectOrString && 'object' !== typeof objectOrString )
|
224
|
+
throw new Error( 'You must validate an object or a string' );
|
225
|
+
// string / array validation
|
226
|
+
if ( 'string' === typeof objectOrString || _isArray(objectOrString) )
|
227
|
+
return this._validateString( objectOrString, AssertsOrConstraintOrGroup, group );
|
228
|
+
// binded object validation
|
229
|
+
if ( this.isBinded( objectOrString ) )
|
230
|
+
return this._validateBindedObject( objectOrString, AssertsOrConstraintOrGroup );
|
231
|
+
// regular object validation
|
232
|
+
return this._validateObject( objectOrString, AssertsOrConstraintOrGroup, group );
|
233
|
+
},
|
234
|
+
bind: function ( object, constraint ) {
|
235
|
+
if ( 'object' !== typeof object )
|
236
|
+
throw new Error( 'Must bind a Constraint to an object' );
|
237
|
+
object[ this.bindingKey ] = new Constraint( constraint );
|
238
|
+
return this;
|
239
|
+
},
|
240
|
+
unbind: function ( object ) {
|
241
|
+
if ( 'undefined' === typeof object._validatorjsConstraint )
|
242
|
+
return this;
|
243
|
+
delete object[ this.bindingKey ];
|
244
|
+
return this;
|
245
|
+
},
|
246
|
+
isBinded: function ( object ) {
|
247
|
+
return 'undefined' !== typeof object[ this.bindingKey ];
|
248
|
+
},
|
249
|
+
getBinded: function ( object ) {
|
250
|
+
return this.isBinded( object ) ? object[ this.bindingKey ] : null;
|
251
|
+
},
|
252
|
+
_validateString: function ( string, assert, group ) {
|
253
|
+
var result, failures = [];
|
254
|
+
if ( !_isArray( assert ) )
|
255
|
+
assert = [ assert ];
|
256
|
+
for ( var i = 0; i < assert.length; i++ ) {
|
257
|
+
if ( ! ( assert[ i ] instanceof Assert) )
|
258
|
+
throw new Error( 'You must give an Assert or an Asserts array to validate a string' );
|
259
|
+
result = assert[ i ].check( string, group );
|
260
|
+
if ( result instanceof Violation )
|
261
|
+
failures.push( result );
|
262
|
+
}
|
263
|
+
return failures.length ? failures : true;
|
264
|
+
},
|
265
|
+
_validateObject: function ( object, constraint, group ) {
|
266
|
+
if ( 'object' !== typeof constraint )
|
267
|
+
throw new Error( 'You must give a constraint to validate an object' );
|
268
|
+
if ( constraint instanceof Constraint )
|
269
|
+
return constraint.check( object, group );
|
270
|
+
return new Constraint( constraint ).check( object, group );
|
271
|
+
},
|
272
|
+
_validateBindedObject: function ( object, group ) {
|
273
|
+
return object[ this.bindingKey ].check( object, group );
|
274
|
+
}
|
275
|
+
};
|
276
|
+
Validator.errorCode = {
|
277
|
+
must_be_a_string: 'must_be_a_string',
|
278
|
+
must_be_an_array: 'must_be_an_array',
|
279
|
+
must_be_a_number: 'must_be_a_number',
|
280
|
+
must_be_a_string_or_array: 'must_be_a_string_or_array'
|
281
|
+
};
|
282
|
+
/**
|
283
|
+
* Constraint
|
284
|
+
*/
|
285
|
+
var Constraint = function ( data, options ) {
|
286
|
+
this.__class__ = 'Constraint';
|
287
|
+
this.options = options || {};
|
288
|
+
this.nodes = {};
|
289
|
+
if ( data ) {
|
290
|
+
try {
|
291
|
+
this._bootstrap( data );
|
292
|
+
} catch ( err ) {
|
293
|
+
throw new Error( 'Should give a valid mapping object to Constraint', err, data );
|
294
|
+
}
|
295
|
+
}
|
296
|
+
};
|
297
|
+
Constraint.prototype = {
|
298
|
+
constructor: Constraint,
|
299
|
+
check: function ( object, group ) {
|
300
|
+
var result, failures = {};
|
301
|
+
// check all constraint nodes.
|
302
|
+
for ( var property in this.nodes ) {
|
303
|
+
var isRequired = false;
|
304
|
+
var constraint = this.get(property);
|
305
|
+
var constraints = _isArray( constraint ) ? constraint : [constraint];
|
306
|
+
for (var i = constraints.length - 1; i >= 0; i--) {
|
307
|
+
if ( 'Required' === constraints[i].__class__ ) {
|
308
|
+
isRequired = constraints[i].requiresValidation( group );
|
309
|
+
continue;
|
310
|
+
}
|
311
|
+
}
|
312
|
+
if ( ! this.has( property, object ) && ! this.options.strict && ! isRequired ) {
|
313
|
+
continue;
|
314
|
+
}
|
315
|
+
try {
|
316
|
+
if (! this.has( property, this.options.strict || isRequired ? object : undefined ) ) {
|
317
|
+
// we trigger here a HaveProperty Assert violation to have uniform Violation object in the end
|
318
|
+
new Assert().HaveProperty( property ).validate( object );
|
319
|
+
}
|
320
|
+
result = this._check( property, object[ property ], group );
|
321
|
+
// check returned an array of Violations or an object mapping Violations
|
322
|
+
if ( ( _isArray( result ) && result.length > 0 ) || ( !_isArray( result ) && !_isEmptyObject( result ) ) ) {
|
323
|
+
failures[ property ] = result;
|
324
|
+
}
|
325
|
+
} catch ( violation ) {
|
326
|
+
failures[ property ] = violation;
|
327
|
+
}
|
328
|
+
}
|
329
|
+
return _isEmptyObject(failures) ? true : failures;
|
330
|
+
},
|
331
|
+
add: function ( node, object ) {
|
332
|
+
if ( object instanceof Assert || ( _isArray( object ) && object[ 0 ] instanceof Assert ) ) {
|
333
|
+
this.nodes[ node ] = object;
|
334
|
+
return this;
|
335
|
+
}
|
336
|
+
if ( 'object' === typeof object && !_isArray( object ) ) {
|
337
|
+
this.nodes[ node ] = object instanceof Constraint ? object : new Constraint( object );
|
338
|
+
return this;
|
339
|
+
}
|
340
|
+
throw new Error( 'Should give an Assert, an Asserts array, a Constraint', object );
|
341
|
+
},
|
342
|
+
has: function ( node, nodes ) {
|
343
|
+
nodes = 'undefined' !== typeof nodes ? nodes : this.nodes;
|
344
|
+
return 'undefined' !== typeof nodes[ node ];
|
345
|
+
},
|
346
|
+
get: function ( node, placeholder ) {
|
347
|
+
return this.has( node ) ? this.nodes[ node ] : placeholder || null;
|
348
|
+
},
|
349
|
+
remove: function ( node ) {
|
350
|
+
var _nodes = [];
|
351
|
+
for ( var i in this.nodes )
|
352
|
+
if ( i !== node )
|
353
|
+
_nodes[ i ] = this.nodes[ i ];
|
354
|
+
this.nodes = _nodes;
|
355
|
+
return this;
|
356
|
+
},
|
357
|
+
_bootstrap: function ( data ) {
|
358
|
+
if ( data instanceof Constraint )
|
359
|
+
return this.nodes = data.nodes;
|
360
|
+
for ( var node in data )
|
361
|
+
this.add( node, data[ node ] );
|
362
|
+
},
|
363
|
+
_check: function ( node, value, group ) {
|
364
|
+
// Assert
|
365
|
+
if ( this.nodes[ node ] instanceof Assert )
|
366
|
+
return this._checkAsserts( value, [ this.nodes[ node ] ], group );
|
367
|
+
// Asserts
|
368
|
+
if ( _isArray( this.nodes[ node ] ) )
|
369
|
+
return this._checkAsserts( value, this.nodes[ node ], group );
|
370
|
+
// Constraint -> check api
|
371
|
+
if ( this.nodes[ node ] instanceof Constraint )
|
372
|
+
return this.nodes[ node ].check( value, group );
|
373
|
+
throw new Error( 'Invalid node', this.nodes[ node ] );
|
374
|
+
},
|
375
|
+
_checkAsserts: function ( value, asserts, group ) {
|
376
|
+
var result, failures = [];
|
377
|
+
for ( var i = 0; i < asserts.length; i++ ) {
|
378
|
+
result = asserts[ i ].check( value, group );
|
379
|
+
if ( 'undefined' !== typeof result && true !== result )
|
380
|
+
failures.push( result );
|
381
|
+
// Some asserts (Collection for example) could return an object
|
382
|
+
// if ( result && ! ( result instanceof Violation ) )
|
383
|
+
// return result;
|
384
|
+
//
|
385
|
+
// // Vast assert majority return Violation
|
386
|
+
// if ( result instanceof Violation )
|
387
|
+
// failures.push( result );
|
388
|
+
}
|
389
|
+
return failures;
|
390
|
+
}
|
391
|
+
};
|
392
|
+
/**
|
393
|
+
* Violation
|
394
|
+
*/
|
395
|
+
var Violation = function ( assert, value, violation ) {
|
396
|
+
this.__class__ = 'Violation';
|
397
|
+
if ( ! ( assert instanceof Assert ) )
|
398
|
+
throw new Error( 'Should give an assertion implementing the Assert interface' );
|
399
|
+
this.assert = assert;
|
400
|
+
this.value = value;
|
401
|
+
if ( 'undefined' !== typeof violation )
|
402
|
+
this.violation = violation;
|
403
|
+
};
|
404
|
+
Violation.prototype = {
|
405
|
+
show: function () {
|
406
|
+
var show = {
|
407
|
+
assert: this.assert.__class__,
|
408
|
+
value: this.value
|
409
|
+
};
|
410
|
+
if ( this.violation )
|
411
|
+
show.violation = this.violation;
|
412
|
+
return show;
|
413
|
+
},
|
414
|
+
__toString: function () {
|
415
|
+
if ( 'undefined' !== typeof this.violation )
|
416
|
+
this.violation = '", ' + this.getViolation().constraint + ' expected was ' + this.getViolation().expected;
|
417
|
+
return this.assert.__class__ + ' assert failed for "' + this.value + this.violation || '';
|
418
|
+
},
|
419
|
+
getViolation: function () {
|
420
|
+
var constraint, expected;
|
421
|
+
for ( constraint in this.violation )
|
422
|
+
expected = this.violation[ constraint ];
|
423
|
+
return { constraint: constraint, expected: expected };
|
424
|
+
}
|
425
|
+
};
|
426
|
+
/**
|
427
|
+
* Assert
|
428
|
+
*/
|
429
|
+
var Assert = function ( group ) {
|
430
|
+
this.__class__ = 'Assert';
|
431
|
+
this.__parentClass__ = this.__class__;
|
432
|
+
this.groups = [];
|
433
|
+
if ( 'undefined' !== typeof group )
|
434
|
+
this.addGroup( group );
|
435
|
+
};
|
436
|
+
Assert.prototype = {
|
437
|
+
construct: Assert,
|
438
|
+
requiresValidation: function ( group ) {
|
439
|
+
if ( group && !this.hasGroup( group ) )
|
440
|
+
return false;
|
441
|
+
if ( !group && this.hasGroups() )
|
442
|
+
return false;
|
443
|
+
return true;
|
444
|
+
},
|
445
|
+
check: function ( value, group ) {
|
446
|
+
if ( !this.requiresValidation( group ) )
|
447
|
+
return;
|
448
|
+
try {
|
449
|
+
return this.validate( value, group );
|
450
|
+
} catch ( violation ) {
|
451
|
+
return violation;
|
452
|
+
}
|
453
|
+
},
|
454
|
+
hasGroup: function ( group ) {
|
455
|
+
if ( _isArray( group ) )
|
456
|
+
return this.hasOneOf( group );
|
457
|
+
// All Asserts respond to "Any" group
|
458
|
+
if ( 'Any' === group )
|
459
|
+
return true;
|
460
|
+
// Asserts with no group also respond to "Default" group. Else return false
|
461
|
+
if ( !this.hasGroups() )
|
462
|
+
return 'Default' === group;
|
463
|
+
return -1 !== this.groups.indexOf( group );
|
464
|
+
},
|
465
|
+
hasOneOf: function ( groups ) {
|
466
|
+
for ( var i = 0; i < groups.length; i++ )
|
467
|
+
if ( this.hasGroup( groups[ i ] ) )
|
468
|
+
return true;
|
469
|
+
return false;
|
470
|
+
},
|
471
|
+
hasGroups: function () {
|
472
|
+
return this.groups.length > 0;
|
473
|
+
},
|
474
|
+
addGroup: function ( group ) {
|
475
|
+
if ( _isArray( group ) )
|
476
|
+
return this.addGroups( group );
|
477
|
+
if ( !this.hasGroup( group ) )
|
478
|
+
this.groups.push( group );
|
479
|
+
return this;
|
480
|
+
},
|
481
|
+
removeGroup: function ( group ) {
|
482
|
+
var _groups = [];
|
483
|
+
for ( var i = 0; i < this.groups.length; i++ )
|
484
|
+
if ( group !== this.groups[ i ] )
|
485
|
+
_groups.push( this.groups[ i ] );
|
486
|
+
this.groups = _groups;
|
487
|
+
return this;
|
488
|
+
},
|
489
|
+
addGroups: function ( groups ) {
|
490
|
+
for ( var i = 0; i < groups.length; i++ )
|
491
|
+
this.addGroup( groups[ i ] );
|
492
|
+
return this;
|
493
|
+
},
|
494
|
+
/**
|
495
|
+
* Asserts definitions
|
496
|
+
*/
|
497
|
+
HaveProperty: function ( node ) {
|
498
|
+
this.__class__ = 'HaveProperty';
|
499
|
+
this.node = node;
|
500
|
+
this.validate = function ( object ) {
|
501
|
+
if ( 'undefined' === typeof object[ this.node ] )
|
502
|
+
throw new Violation( this, object, { value: this.node } );
|
503
|
+
return true;
|
504
|
+
};
|
505
|
+
return this;
|
506
|
+
},
|
507
|
+
Blank: function () {
|
508
|
+
this.__class__ = 'Blank';
|
509
|
+
this.validate = function ( value ) {
|
510
|
+
if ( 'string' !== typeof value )
|
511
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
|
512
|
+
if ( '' !== value.replace( /^\s+/g, '' ).replace( /\s+$/g, '' ) )
|
513
|
+
throw new Violation( this, value );
|
514
|
+
return true;
|
515
|
+
};
|
516
|
+
return this;
|
517
|
+
},
|
518
|
+
Callback: function ( fn ) {
|
519
|
+
this.__class__ = 'Callback';
|
520
|
+
this.arguments = Array.prototype.slice.call( arguments );
|
521
|
+
if ( 1 === this.arguments.length )
|
522
|
+
this.arguments = [];
|
523
|
+
else
|
524
|
+
this.arguments.splice( 0, 1 );
|
525
|
+
if ( 'function' !== typeof fn )
|
526
|
+
throw new Error( 'Callback must be instanciated with a function' );
|
527
|
+
this.fn = fn;
|
528
|
+
this.validate = function ( value ) {
|
529
|
+
var result = this.fn.apply( this, [ value ].concat( this.arguments ) );
|
530
|
+
if ( true !== result )
|
531
|
+
throw new Violation( this, value, { result: result } );
|
532
|
+
return true;
|
533
|
+
};
|
534
|
+
return this;
|
535
|
+
},
|
536
|
+
Choice: function ( list ) {
|
537
|
+
this.__class__ = 'Choice';
|
538
|
+
if ( !_isArray( list ) && 'function' !== typeof list )
|
539
|
+
throw new Error( 'Choice must be instanciated with an array or a function' );
|
540
|
+
this.list = list;
|
541
|
+
this.validate = function ( value ) {
|
542
|
+
var list = 'function' === typeof this.list ? this.list() : this.list;
|
543
|
+
for ( var i = 0; i < list.length; i++ )
|
544
|
+
if ( value === list[ i ] )
|
545
|
+
return true;
|
546
|
+
throw new Violation( this, value, { choices: list } );
|
547
|
+
};
|
548
|
+
return this;
|
549
|
+
},
|
550
|
+
Collection: function ( assertOrConstraint ) {
|
551
|
+
this.__class__ = 'Collection';
|
552
|
+
this.constraint = 'undefined' !== typeof assertOrConstraint ? (assertOrConstraint instanceof Assert ? assertOrConstraint : new Constraint( assertOrConstraint )) : false;
|
553
|
+
this.validate = function ( collection, group ) {
|
554
|
+
var result, validator = new Validator(), count = 0, failures = {}, groups = this.groups.length ? this.groups : group;
|
555
|
+
if ( !_isArray( collection ) )
|
556
|
+
throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } );
|
557
|
+
for ( var i = 0; i < collection.length; i++ ) {
|
558
|
+
result = this.constraint ?
|
559
|
+
validator.validate( collection[ i ], this.constraint, groups ) :
|
560
|
+
validator.validate( collection[ i ], groups );
|
561
|
+
if ( !_isEmptyObject( result ) )
|
562
|
+
failures[ count ] = result;
|
563
|
+
count++;
|
564
|
+
}
|
565
|
+
return !_isEmptyObject( failures ) ? failures : true;
|
566
|
+
};
|
567
|
+
return this;
|
568
|
+
},
|
569
|
+
Count: function ( count ) {
|
570
|
+
this.__class__ = 'Count';
|
571
|
+
this.count = count;
|
572
|
+
this.validate = function ( array ) {
|
573
|
+
if ( !_isArray( array ) )
|
574
|
+
throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } );
|
575
|
+
var count = 'function' === typeof this.count ? this.count( array ) : this.count;
|
576
|
+
if ( isNaN( Number( count ) ) )
|
577
|
+
throw new Error( 'Count must be a valid interger', count );
|
578
|
+
if ( count !== array.length )
|
579
|
+
throw new Violation( this, array, { count: count } );
|
580
|
+
return true;
|
581
|
+
};
|
582
|
+
return this;
|
583
|
+
},
|
584
|
+
Email: function () {
|
585
|
+
this.__class__ = 'Email';
|
586
|
+
this.validate = function ( value ) {
|
587
|
+
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;
|
588
|
+
if ( 'string' !== typeof value )
|
589
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
|
590
|
+
if ( !regExp.test( value ) )
|
591
|
+
throw new Violation( this, value );
|
592
|
+
return true;
|
593
|
+
};
|
594
|
+
return this;
|
595
|
+
},
|
596
|
+
EqualTo: function ( reference ) {
|
597
|
+
this.__class__ = 'EqualTo';
|
598
|
+
if ( 'undefined' === typeof reference )
|
599
|
+
throw new Error( 'EqualTo must be instanciated with a value or a function' );
|
600
|
+
this.reference = reference;
|
601
|
+
this.validate = function ( value ) {
|
602
|
+
var reference = 'function' === typeof this.reference ? this.reference( value ) : this.reference;
|
603
|
+
if ( reference !== value )
|
604
|
+
throw new Violation( this, value, { value: reference } );
|
605
|
+
return true;
|
606
|
+
};
|
607
|
+
return this;
|
608
|
+
},
|
609
|
+
GreaterThan: function ( threshold ) {
|
610
|
+
this.__class__ = 'GreaterThan';
|
611
|
+
if ( 'undefined' === typeof threshold )
|
612
|
+
throw new Error( 'Should give a threshold value' );
|
613
|
+
this.threshold = threshold;
|
614
|
+
this.validate = function ( value ) {
|
615
|
+
if ( '' === value || isNaN( Number( value ) ) )
|
616
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
|
617
|
+
if ( this.threshold >= value )
|
618
|
+
throw new Violation( this, value, { threshold: this.threshold } );
|
619
|
+
return true;
|
620
|
+
};
|
621
|
+
return this;
|
622
|
+
},
|
623
|
+
GreaterThanOrEqual: function ( threshold ) {
|
624
|
+
this.__class__ = 'GreaterThanOrEqual';
|
625
|
+
if ( 'undefined' === typeof threshold )
|
626
|
+
throw new Error( 'Should give a threshold value' );
|
627
|
+
this.threshold = threshold;
|
628
|
+
this.validate = function ( value ) {
|
629
|
+
if ( '' === value || isNaN( Number( value ) ) )
|
630
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
|
631
|
+
if ( this.threshold > value )
|
632
|
+
throw new Violation( this, value, { threshold: this.threshold } );
|
633
|
+
return true;
|
634
|
+
};
|
635
|
+
return this;
|
636
|
+
},
|
637
|
+
InstanceOf: function ( classRef ) {
|
638
|
+
this.__class__ = 'InstanceOf';
|
639
|
+
if ( 'undefined' === typeof classRef )
|
640
|
+
throw new Error( 'InstanceOf must be instanciated with a value' );
|
641
|
+
this.classRef = classRef;
|
642
|
+
this.validate = function ( value ) {
|
643
|
+
if ( true !== (value instanceof this.classRef) )
|
644
|
+
throw new Violation( this, value, { classRef: this.classRef } );
|
645
|
+
return true;
|
646
|
+
};
|
647
|
+
return this;
|
648
|
+
},
|
649
|
+
Length: function ( boundaries ) {
|
650
|
+
this.__class__ = 'Length';
|
651
|
+
if ( !boundaries.min && !boundaries.max )
|
652
|
+
throw new Error( 'Lenth assert must be instanciated with a { min: x, max: y } object' );
|
653
|
+
this.min = boundaries.min;
|
654
|
+
this.max = boundaries.max;
|
655
|
+
this.validate = function ( value ) {
|
656
|
+
if ( 'string' !== typeof value && !_isArray( value ) )
|
657
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string_or_array } );
|
658
|
+
if ( 'undefined' !== typeof this.min && this.min === this.max && value.length !== this.min )
|
659
|
+
throw new Violation( this, value, { min: this.min, max: this.max } );
|
660
|
+
if ( 'undefined' !== typeof this.max && value.length > this.max )
|
661
|
+
throw new Violation( this, value, { max: this.max } );
|
662
|
+
if ( 'undefined' !== typeof this.min && value.length < this.min )
|
663
|
+
throw new Violation( this, value, { min: this.min } );
|
664
|
+
return true;
|
665
|
+
};
|
666
|
+
return this;
|
667
|
+
},
|
668
|
+
LessThan: function ( threshold ) {
|
669
|
+
this.__class__ = 'LessThan';
|
670
|
+
if ( 'undefined' === typeof threshold )
|
671
|
+
throw new Error( 'Should give a threshold value' );
|
672
|
+
this.threshold = threshold;
|
673
|
+
this.validate = function ( value ) {
|
674
|
+
if ( '' === value || isNaN( Number( value ) ) )
|
675
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
|
676
|
+
if ( this.threshold <= value )
|
677
|
+
throw new Violation( this, value, { threshold: this.threshold } );
|
678
|
+
return true;
|
679
|
+
};
|
680
|
+
return this;
|
681
|
+
},
|
682
|
+
LessThanOrEqual: function ( threshold ) {
|
683
|
+
this.__class__ = 'LessThanOrEqual';
|
684
|
+
if ( 'undefined' === typeof threshold )
|
685
|
+
throw new Error( 'Should give a threshold value' );
|
686
|
+
this.threshold = threshold;
|
687
|
+
this.validate = function ( value ) {
|
688
|
+
if ( '' === value || isNaN( Number( value ) ) )
|
689
|
+
throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
|
690
|
+
if ( this.threshold < value )
|
691
|
+
throw new Violation( this, value, { threshold: this.threshold } );
|
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 );
|
742
|
+
}
|
743
|
+
return true;
|
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 } );
|
758
|
+
return true;
|
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
|
+
}
|
775
|
+
return true;
|
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
|
+
}
|
796
|
+
return true;
|
797
|
+
};
|
798
|
+
return this;
|
799
|
+
}
|
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();
|
816
|
+
}
|
817
|
+
var t = Object(this);
|
818
|
+
var len = t.length >>> 0;
|
819
|
+
if (len === 0) {
|
820
|
+
return -1;
|
821
|
+
}
|
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));
|
829
|
+
}
|
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;
|
838
|
+
}
|
839
|
+
}
|
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;
|
847
|
+
};
|
848
|
+
var _isArray = function ( obj ) {
|
849
|
+
return Object.prototype.toString.call( obj ) === '[object Array]';
|
850
|
+
};
|
851
|
+
// AMD export
|
852
|
+
if ( typeof define === 'function' && define.amd ) {
|
853
|
+
define( 'vendors/validator.js/dist/validator',[],function() {
|
854
|
+
return exports;
|
855
|
+
} );
|
856
|
+
// commonjs export
|
857
|
+
} else if ( typeof module !== 'undefined' && module.exports ) {
|
858
|
+
module.exports = exports;
|
859
|
+
// browser
|
860
|
+
} else {
|
861
|
+
window[ 'undefined' !== typeof validatorjs_ns ? validatorjs_ns : 'Validator' ] = exports;
|
862
|
+
}
|
863
|
+
|
864
|
+
return exports;
|
865
|
+
} )( );
|
866
|
+
|
867
|
+
// This is needed for Browserify usage that requires Validator.js through module.exports
|
868
|
+
Validator = 'undefined' !== typeof Validator ? Validator : ('undefined' !== typeof module ? module.exports : null);
|
869
|
+
var ParsleyValidator = function (validators, catalog) {
|
870
|
+
this.__class__ = 'ParsleyValidator';
|
871
|
+
this.Validator = Validator;
|
872
|
+
// Default Parsley locale is en
|
873
|
+
this.locale = 'en';
|
874
|
+
this.init(validators || {}, catalog || {});
|
875
|
+
};
|
876
|
+
ParsleyValidator.prototype = {
|
877
|
+
init: function (validators, catalog) {
|
878
|
+
this.catalog = catalog;
|
879
|
+
for (var name in validators)
|
880
|
+
this.addValidator(name, validators[name].fn, validators[name].priority, validators[name].requirementsTransformer);
|
881
|
+
$.emit('parsley:validator:init');
|
882
|
+
},
|
883
|
+
// Set new messages locale if we have dictionary loaded in ParsleyConfig.i18n
|
884
|
+
setLocale: function (locale) {
|
885
|
+
if ('undefined' === typeof this.catalog[locale])
|
886
|
+
throw new Error(locale + ' is not available in the catalog');
|
887
|
+
this.locale = locale;
|
888
|
+
return this;
|
889
|
+
},
|
890
|
+
// Add a new messages catalog for a given locale. Set locale for this catalog if set === `true`
|
891
|
+
addCatalog: function (locale, messages, set) {
|
892
|
+
if ('object' === typeof messages)
|
893
|
+
this.catalog[locale] = messages;
|
894
|
+
if (true === set)
|
895
|
+
return this.setLocale(locale);
|
896
|
+
return this;
|
897
|
+
},
|
898
|
+
// Add a specific message for a given constraint in a given locale
|
899
|
+
addMessage: function (locale, name, message) {
|
900
|
+
if ('undefined' === typeof this.catalog[locale])
|
901
|
+
this.catalog[locale] = {};
|
902
|
+
this.catalog[locale][name.toLowerCase()] = message;
|
903
|
+
return this;
|
904
|
+
},
|
905
|
+
validate: function (value, constraints, priority) {
|
906
|
+
return new this.Validator.Validator().validate.apply(new Validator.Validator(), arguments);
|
907
|
+
},
|
908
|
+
// Add a new validator
|
909
|
+
addValidator: function (name, fn, priority, requirementsTransformer) {
|
910
|
+
this.validators[name.toLowerCase()] = function (requirements) {
|
911
|
+
return $.extend(new Validator.Assert().Callback(fn, requirements), {
|
912
|
+
priority: priority,
|
913
|
+
requirementsTransformer: requirementsTransformer
|
914
|
+
});
|
915
|
+
};
|
916
|
+
return this;
|
917
|
+
},
|
918
|
+
updateValidator: function (name, fn, priority, requirementsTransformer) {
|
919
|
+
return this.addValidator(name, fn, priority, requirementsTransformer);
|
920
|
+
},
|
921
|
+
removeValidator: function (name) {
|
922
|
+
delete this.validators[name];
|
923
|
+
return this;
|
924
|
+
},
|
925
|
+
getErrorMessage: function (constraint) {
|
926
|
+
var message;
|
927
|
+
// Type constraints are a bit different, we have to match their requirements too to find right error message
|
928
|
+
if ('type' === constraint.name)
|
929
|
+
message = this.catalog[this.locale][constraint.name][constraint.requirements];
|
930
|
+
else
|
931
|
+
message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements);
|
932
|
+
return '' !== message ? message : this.catalog[this.locale].defaultMessage;
|
933
|
+
},
|
934
|
+
// Kind of light `sprintf()` implementation
|
935
|
+
formatMessage: function (string, parameters) {
|
936
|
+
if ('object' === typeof parameters) {
|
937
|
+
for (var i in parameters)
|
938
|
+
string = this.formatMessage(string, parameters[i]);
|
939
|
+
return string;
|
940
|
+
}
|
941
|
+
return 'string' === typeof string ? string.replace(new RegExp('%s', 'i'), parameters) : '';
|
942
|
+
},
|
943
|
+
// Here is the Parsley default validators list.
|
944
|
+
// This is basically Validatorjs validators, with different API for some of them
|
945
|
+
// and a Parsley priority set
|
946
|
+
validators: {
|
947
|
+
notblank: function () {
|
948
|
+
return $.extend(new Validator.Assert().NotBlank(), { priority: 2 });
|
949
|
+
},
|
950
|
+
required: function () {
|
951
|
+
return $.extend(new Validator.Assert().Required(), { priority: 512 });
|
952
|
+
},
|
953
|
+
type: function (type) {
|
954
|
+
var assert;
|
955
|
+
switch (type) {
|
956
|
+
case 'email':
|
957
|
+
assert = new Validator.Assert().Email();
|
958
|
+
break;
|
959
|
+
// range type just ensure we have a number here
|
960
|
+
case 'range':
|
961
|
+
case 'number':
|
962
|
+
assert = new Validator.Assert().Regexp('^-?(?:\\d+|\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$');
|
963
|
+
break;
|
964
|
+
case 'integer':
|
965
|
+
assert = new Validator.Assert().Regexp('^-?\\d+$');
|
966
|
+
break;
|
967
|
+
case 'digits':
|
968
|
+
assert = new Validator.Assert().Regexp('^\\d+$');
|
969
|
+
break;
|
970
|
+
case 'alphanum':
|
971
|
+
assert = new Validator.Assert().Regexp('^\\w+$', 'i');
|
972
|
+
break;
|
973
|
+
case 'url':
|
974
|
+
assert = new Validator.Assert().Regexp('(https?:\\/\\/)?(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,4}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)', 'i');
|
975
|
+
break;
|
976
|
+
default:
|
977
|
+
throw new Error('validator type `' + type + '` is not supported');
|
978
|
+
}
|
979
|
+
return $.extend(assert, { priority: 256 });
|
980
|
+
},
|
981
|
+
pattern: function (regexp) {
|
982
|
+
var flags = '';
|
983
|
+
// Test if RegExp is literal, if not, nothing to be done, otherwise, we need to isolate flags and pattern
|
984
|
+
if (!!(/^\/.*\/(?:[gimy]*)$/.test(regexp))) {
|
985
|
+
// Replace the regexp literal string with the first match group: ([gimy]*)
|
986
|
+
// If no flag is present, this will be a blank string
|
987
|
+
flags = regexp.replace(/.*\/([gimy]*)$/, '$1');
|
988
|
+
// Again, replace the regexp literal string with the first match group:
|
989
|
+
// everything excluding the opening and closing slashes and the flags
|
990
|
+
regexp = regexp.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');
|
991
|
+
}
|
992
|
+
return $.extend(new Validator.Assert().Regexp(regexp, flags), { priority: 64 });
|
993
|
+
},
|
994
|
+
minlength: function (value) {
|
995
|
+
return $.extend(new Validator.Assert().Length({ min: value }), {
|
996
|
+
priority: 30,
|
997
|
+
requirementsTransformer: function () {
|
998
|
+
return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
|
999
|
+
}
|
1000
|
+
});
|
1001
|
+
},
|
1002
|
+
maxlength: function (value) {
|
1003
|
+
return $.extend(new Validator.Assert().Length({ max: value }), {
|
1004
|
+
priority: 30,
|
1005
|
+
requirementsTransformer: function () {
|
1006
|
+
return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
|
1007
|
+
}
|
1008
|
+
});
|
1009
|
+
},
|
1010
|
+
length: function (array) {
|
1011
|
+
return $.extend(new Validator.Assert().Length({ min: array[0], max: array[1] }), { priority: 32 });
|
1012
|
+
},
|
1013
|
+
mincheck: function (length) {
|
1014
|
+
return this.minlength(length);
|
1015
|
+
},
|
1016
|
+
maxcheck: function (length) {
|
1017
|
+
return this.maxlength(length);
|
1018
|
+
},
|
1019
|
+
check: function (array) {
|
1020
|
+
return this.length(array);
|
1021
|
+
},
|
1022
|
+
min: function (value) {
|
1023
|
+
return $.extend(new Validator.Assert().GreaterThanOrEqual(value), {
|
1024
|
+
priority: 30,
|
1025
|
+
requirementsTransformer: function () {
|
1026
|
+
return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
|
1027
|
+
}
|
1028
|
+
});
|
1029
|
+
},
|
1030
|
+
max: function (value) {
|
1031
|
+
return $.extend(new Validator.Assert().LessThanOrEqual(value), {
|
1032
|
+
priority: 30,
|
1033
|
+
requirementsTransformer: function () {
|
1034
|
+
return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
|
1035
|
+
}
|
1036
|
+
});
|
1037
|
+
},
|
1038
|
+
range: function (array) {
|
1039
|
+
return $.extend(new Validator.Assert().Range(array[0], array[1]), {
|
1040
|
+
priority: 32,
|
1041
|
+
requirementsTransformer: function () {
|
1042
|
+
for (var i = 0; i < array.length; i++)
|
1043
|
+
array[i] = 'string' === typeof array[i] && !isNaN(array[i]) ? parseInt(array[i], 10) : array[i];
|
1044
|
+
return array;
|
1045
|
+
}
|
1046
|
+
});
|
1047
|
+
},
|
1048
|
+
equalto: function (value) {
|
1049
|
+
return $.extend(new Validator.Assert().EqualTo(value), {
|
1050
|
+
priority: 256,
|
1051
|
+
requirementsTransformer: function () {
|
1052
|
+
return $(value).length ? $(value).val() : value;
|
1053
|
+
}
|
1054
|
+
});
|
1055
|
+
}
|
1056
|
+
}
|
1057
|
+
};
|
1058
|
+
|
1059
|
+
var ParsleyUI = function (options) {
|
1060
|
+
this.__class__ = 'ParsleyUI';
|
1061
|
+
};
|
1062
|
+
ParsleyUI.prototype = {
|
1063
|
+
listen: function () {
|
1064
|
+
$.listen('parsley:form:init', this, this.setupForm);
|
1065
|
+
$.listen('parsley:field:init', this, this.setupField);
|
1066
|
+
$.listen('parsley:field:validated', this, this.reflow);
|
1067
|
+
$.listen('parsley:form:validated', this, this.focus);
|
1068
|
+
$.listen('parsley:field:reset', this, this.reset);
|
1069
|
+
$.listen('parsley:form:destroy', this, this.destroy);
|
1070
|
+
$.listen('parsley:field:destroy', this, this.destroy);
|
1071
|
+
return this;
|
1072
|
+
},
|
1073
|
+
reflow: function (fieldInstance) {
|
1074
|
+
// If this field has not an active UI (case for multiples) don't bother doing something
|
1075
|
+
if ('undefined' === typeof fieldInstance._ui || false === fieldInstance._ui.active)
|
1076
|
+
return;
|
1077
|
+
// Diff between two validation results
|
1078
|
+
var diff = this._diff(fieldInstance.validationResult, fieldInstance._ui.lastValidationResult);
|
1079
|
+
// Then store current validation result for next reflow
|
1080
|
+
fieldInstance._ui.lastValidationResult = fieldInstance.validationResult;
|
1081
|
+
// Field have been validated at least once if here. Useful for binded key events..
|
1082
|
+
fieldInstance._ui.validatedOnce = true;
|
1083
|
+
// Handle valid / invalid / none field class
|
1084
|
+
this.manageStatusClass(fieldInstance);
|
1085
|
+
// Add, remove, updated errors messages
|
1086
|
+
this.manageErrorsMessages(fieldInstance, diff);
|
1087
|
+
// Triggers impl
|
1088
|
+
this.actualizeTriggers(fieldInstance);
|
1089
|
+
// If field is not valid for the first time, bind keyup trigger to ease UX and quickly inform user
|
1090
|
+
if ((diff.kept.length || diff.added.length) && 'undefined' === typeof fieldInstance._ui.failedOnce)
|
1091
|
+
this.manageFailingFieldTrigger(fieldInstance);
|
1092
|
+
},
|
1093
|
+
// Returns an array of field's error message(s)
|
1094
|
+
getErrorsMessages: function (fieldInstance) {
|
1095
|
+
// No error message, field is valid
|
1096
|
+
if (true === fieldInstance.validationResult)
|
1097
|
+
return [];
|
1098
|
+
var messages = [];
|
1099
|
+
for (var i = 0; i < fieldInstance.validationResult.length; i++)
|
1100
|
+
messages.push(this._getErrorMessage(fieldInstance, fieldInstance.validationResult[i].assert));
|
1101
|
+
return messages;
|
1102
|
+
},
|
1103
|
+
manageStatusClass: function (fieldInstance) {
|
1104
|
+
if (true === fieldInstance.validationResult)
|
1105
|
+
this._successClass(fieldInstance);
|
1106
|
+
else if (fieldInstance.validationResult.length > 0)
|
1107
|
+
this._errorClass(fieldInstance);
|
1108
|
+
else
|
1109
|
+
this._resetClass(fieldInstance);
|
1110
|
+
},
|
1111
|
+
manageErrorsMessages: function (fieldInstance, diff) {
|
1112
|
+
if ('undefined' !== typeof fieldInstance.options.errorsMessagesDisabled)
|
1113
|
+
return;
|
1114
|
+
// Case where we have errorMessage option that configure an unique field error message, regardless failing validators
|
1115
|
+
if ('undefined' !== typeof fieldInstance.options.errorMessage) {
|
1116
|
+
if ((diff.added.length || diff.kept.length)) {
|
1117
|
+
if (0 === fieldInstance._ui.$errorsWrapper.find('.parsley-custom-error-message').length)
|
1118
|
+
fieldInstance._ui.$errorsWrapper
|
1119
|
+
.append($(fieldInstance.options.errorTemplate)
|
1120
|
+
.addClass('parsley-custom-error-message'));
|
1121
|
+
return fieldInstance._ui.$errorsWrapper
|
1122
|
+
.addClass('filled')
|
1123
|
+
.find('.parsley-custom-error-message')
|
1124
|
+
.html(fieldInstance.options.errorMessage);
|
1125
|
+
}
|
1126
|
+
return fieldInstance._ui.$errorsWrapper
|
1127
|
+
.removeClass('filled')
|
1128
|
+
.find('.parsley-custom-error-message')
|
1129
|
+
.remove();
|
1130
|
+
}
|
1131
|
+
// Show, hide, update failing constraints messages
|
1132
|
+
for (var i = 0; i < diff.removed.length; i++)
|
1133
|
+
this.removeError(fieldInstance, diff.removed[i].assert.name, true);
|
1134
|
+
for (i = 0; i < diff.added.length; i++)
|
1135
|
+
this.addError(fieldInstance, diff.added[i].assert.name, undefined, diff.added[i].assert, true);
|
1136
|
+
for (i = 0; i < diff.kept.length; i++)
|
1137
|
+
this.updateError(fieldInstance, diff.kept[i].assert.name, undefined, diff.kept[i].assert, true);
|
1138
|
+
},
|
1139
|
+
// TODO: strange API here, intuitive for manual usage with addError(pslyInstance, 'foo', 'bar')
|
1140
|
+
// but a little bit complex for above internal usage, with forced undefined parametter..
|
1141
|
+
addError: function (fieldInstance, name, message, assert, doNotUpdateClass) {
|
1142
|
+
fieldInstance._ui.$errorsWrapper
|
1143
|
+
.addClass('filled')
|
1144
|
+
.append($(fieldInstance.options.errorTemplate)
|
1145
|
+
.addClass('parsley-' + name)
|
1146
|
+
.html(message || this._getErrorMessage(fieldInstance, assert)));
|
1147
|
+
if (true !== doNotUpdateClass)
|
1148
|
+
this._errorClass(fieldInstance);
|
1149
|
+
},
|
1150
|
+
// Same as above
|
1151
|
+
updateError: function (fieldInstance, name, message, assert, doNotUpdateClass) {
|
1152
|
+
fieldInstance._ui.$errorsWrapper
|
1153
|
+
.addClass('filled')
|
1154
|
+
.find('.parsley-' + name)
|
1155
|
+
.html(message || this._getErrorMessage(fieldInstance, assert));
|
1156
|
+
if (true !== doNotUpdateClass)
|
1157
|
+
this._errorClass(fieldInstance);
|
1158
|
+
},
|
1159
|
+
// Same as above twice
|
1160
|
+
removeError: function (fieldInstance, name, doNotUpdateClass) {
|
1161
|
+
fieldInstance._ui.$errorsWrapper
|
1162
|
+
.removeClass('filled')
|
1163
|
+
.find('.parsley-' + name)
|
1164
|
+
.remove();
|
1165
|
+
// edge case possible here: remove a standard Parsley error that is still failing in fieldInstance.validationResult
|
1166
|
+
// but highly improbable cuz' manually removing a well Parsley handled error makes no sense.
|
1167
|
+
if (true !== doNotUpdateClass)
|
1168
|
+
this.manageStatusClass(fieldInstance);
|
1169
|
+
},
|
1170
|
+
focus: function (formInstance) {
|
1171
|
+
if (true === formInstance.validationResult || 'none' === formInstance.options.focus)
|
1172
|
+
return formInstance._focusedField = null;
|
1173
|
+
formInstance._focusedField = null;
|
1174
|
+
for (var i = 0; i < formInstance.fields.length; i++)
|
1175
|
+
if (true !== formInstance.fields[i].validationResult && formInstance.fields[i].validationResult.length > 0 && 'undefined' === typeof formInstance.fields[i].options.noFocus) {
|
1176
|
+
if ('first' === formInstance.options.focus) {
|
1177
|
+
formInstance._focusedField = formInstance.fields[i].$element;
|
1178
|
+
return formInstance._focusedField.focus();
|
1179
|
+
}
|
1180
|
+
formInstance._focusedField = formInstance.fields[i].$element;
|
1181
|
+
}
|
1182
|
+
if (null === formInstance._focusedField)
|
1183
|
+
return null;
|
1184
|
+
return formInstance._focusedField.focus();
|
1185
|
+
},
|
1186
|
+
_getErrorMessage: function (fieldInstance, constraint) {
|
1187
|
+
var customConstraintErrorMessage = constraint.name + 'Message';
|
1188
|
+
if ('undefined' !== typeof fieldInstance.options[customConstraintErrorMessage])
|
1189
|
+
return window.ParsleyValidator.formatMessage(fieldInstance.options[customConstraintErrorMessage], constraint.requirements);
|
1190
|
+
return window.ParsleyValidator.getErrorMessage(constraint);
|
1191
|
+
},
|
1192
|
+
_diff: function (newResult, oldResult, deep) {
|
1193
|
+
var
|
1194
|
+
added = [],
|
1195
|
+
kept = [];
|
1196
|
+
for (var i = 0; i < newResult.length; i++) {
|
1197
|
+
var found = false;
|
1198
|
+
for (var j = 0; j < oldResult.length; j++)
|
1199
|
+
if (newResult[i].assert.name === oldResult[j].assert.name) {
|
1200
|
+
found = true;
|
1201
|
+
break;
|
1202
|
+
}
|
1203
|
+
if (found)
|
1204
|
+
kept.push(newResult[i]);
|
1205
|
+
else
|
1206
|
+
added.push(newResult[i]);
|
1207
|
+
}
|
1208
|
+
return {
|
1209
|
+
kept: kept,
|
1210
|
+
added: added,
|
1211
|
+
removed: !deep ? this._diff(oldResult, newResult, true).added : []
|
1212
|
+
};
|
1213
|
+
},
|
1214
|
+
setupForm: function (formInstance) {
|
1215
|
+
formInstance.$element.on('submit.Parsley', false, $.proxy(formInstance.onSubmitValidate, formInstance));
|
1216
|
+
// UI could be disabled
|
1217
|
+
if (false === formInstance.options.uiEnabled)
|
1218
|
+
return;
|
1219
|
+
formInstance.$element.attr('novalidate', '');
|
1220
|
+
},
|
1221
|
+
setupField: function (fieldInstance) {
|
1222
|
+
var _ui = { active: false };
|
1223
|
+
// UI could be disabled
|
1224
|
+
if (false === fieldInstance.options.uiEnabled)
|
1225
|
+
return;
|
1226
|
+
_ui.active = true;
|
1227
|
+
// Give field its Parsley id in DOM
|
1228
|
+
fieldInstance.$element.attr(fieldInstance.options.namespace + 'id', fieldInstance.__id__);
|
1229
|
+
/** Generate important UI elements and store them in fieldInstance **/
|
1230
|
+
// $errorClassHandler is the $element that woul have parsley-error and parsley-success classes
|
1231
|
+
_ui.$errorClassHandler = this._manageClassHandler(fieldInstance);
|
1232
|
+
// $errorsWrapper is a div that would contain the various field errors, it will be appended into $errorsContainer
|
1233
|
+
_ui.errorsWrapperId = 'parsley-id-' + ('undefined' !== typeof fieldInstance.options.multiple ? 'multiple-' + fieldInstance.options.multiple : fieldInstance.__id__);
|
1234
|
+
_ui.$errorsWrapper = $(fieldInstance.options.errorsWrapper).attr('id', _ui.errorsWrapperId);
|
1235
|
+
// ValidationResult UI storage to detect what have changed bwt two validations, and update DOM accordingly
|
1236
|
+
_ui.lastValidationResult = [];
|
1237
|
+
_ui.validatedOnce = false;
|
1238
|
+
_ui.validationInformationVisible = false;
|
1239
|
+
// Store it in fieldInstance for later
|
1240
|
+
fieldInstance._ui = _ui;
|
1241
|
+
// Stops excluded inputs from getting errorContainer added
|
1242
|
+
if( !fieldInstance.$element.is(fieldInstance.options.excluded) ) {
|
1243
|
+
/** Mess with DOM now **/
|
1244
|
+
this._insertErrorWrapper(fieldInstance);
|
1245
|
+
}
|
1246
|
+
// Bind triggers first time
|
1247
|
+
this.actualizeTriggers(fieldInstance);
|
1248
|
+
},
|
1249
|
+
// Determine which element will have `parsley-error` and `parsley-success` classes
|
1250
|
+
_manageClassHandler: function (fieldInstance) {
|
1251
|
+
// An element selector could be passed through DOM with `data-parsley-class-handler=#foo`
|
1252
|
+
if ('string' === typeof fieldInstance.options.classHandler && $(fieldInstance.options.classHandler).length)
|
1253
|
+
return $(fieldInstance.options.classHandler);
|
1254
|
+
// Class handled could also be determined by function given in Parsley options
|
1255
|
+
var $handler = fieldInstance.options.classHandler(fieldInstance);
|
1256
|
+
// If this function returned a valid existing DOM element, go for it
|
1257
|
+
if ('undefined' !== typeof $handler && $handler.length)
|
1258
|
+
return $handler;
|
1259
|
+
// Otherwise, if simple element (input, texatrea, select..) it will perfectly host the classes
|
1260
|
+
if ('undefined' === typeof fieldInstance.options.multiple || fieldInstance.$element.is('select'))
|
1261
|
+
return fieldInstance.$element;
|
1262
|
+
// But if multiple element (radio, checkbox), that would be their parent
|
1263
|
+
return fieldInstance.$element.parent();
|
1264
|
+
},
|
1265
|
+
_insertErrorWrapper: function (fieldInstance) {
|
1266
|
+
var $errorsContainer;
|
1267
|
+
if ('string' === typeof fieldInstance.options.errorsContainer) {
|
1268
|
+
if ($(fieldInstance.options.errorsContainer).length)
|
1269
|
+
return $(fieldInstance.options.errorsContainer).append(fieldInstance._ui.$errorsWrapper);
|
1270
|
+
else if (window.console && window.console.warn)
|
1271
|
+
window.console.warn('The errors container `' + fieldInstance.options.errorsContainer + '` does not exist in DOM');
|
1272
|
+
}
|
1273
|
+
else if ('function' === typeof fieldInstance.options.errorsContainer)
|
1274
|
+
$errorsContainer = fieldInstance.options.errorsContainer(fieldInstance);
|
1275
|
+
if ('undefined' !== typeof $errorsContainer && $errorsContainer.length)
|
1276
|
+
return $errorsContainer.append(fieldInstance._ui.$errorsWrapper);
|
1277
|
+
return 'undefined' === typeof fieldInstance.options.multiple ? fieldInstance.$element.after(fieldInstance._ui.$errorsWrapper) : fieldInstance.$element.parent().after(fieldInstance._ui.$errorsWrapper);
|
1278
|
+
},
|
1279
|
+
actualizeTriggers: function (fieldInstance) {
|
1280
|
+
var that = this;
|
1281
|
+
// Remove Parsley events already binded on this field
|
1282
|
+
if (fieldInstance.options.multiple)
|
1283
|
+
$('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
|
1284
|
+
$(this).off('.Parsley');
|
1285
|
+
});
|
1286
|
+
else
|
1287
|
+
fieldInstance.$element.off('.Parsley');
|
1288
|
+
// If no trigger is set, all good
|
1289
|
+
if (false === fieldInstance.options.trigger)
|
1290
|
+
return;
|
1291
|
+
var triggers = fieldInstance.options.trigger.replace(/^\s+/g , '').replace(/\s+$/g , '');
|
1292
|
+
if ('' === triggers)
|
1293
|
+
return;
|
1294
|
+
// Bind fieldInstance.eventValidate if exists (for parsley.ajax for example), ParsleyUI.eventValidate otherwise
|
1295
|
+
if (fieldInstance.options.multiple)
|
1296
|
+
$('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
|
1297
|
+
$(this).on(
|
1298
|
+
triggers.split(' ').join('.Parsley ') + '.Parsley',
|
1299
|
+
false,
|
1300
|
+
$.proxy('function' === typeof fieldInstance.eventValidate ? fieldInstance.eventValidate : that.eventValidate, fieldInstance));
|
1301
|
+
});
|
1302
|
+
else
|
1303
|
+
fieldInstance.$element
|
1304
|
+
.on(
|
1305
|
+
triggers.split(' ').join('.Parsley ') + '.Parsley',
|
1306
|
+
false,
|
1307
|
+
$.proxy('function' === typeof fieldInstance.eventValidate ? fieldInstance.eventValidate : this.eventValidate, fieldInstance));
|
1308
|
+
},
|
1309
|
+
// Called through $.proxy with fieldInstance. `this` context is ParsleyField
|
1310
|
+
eventValidate: function(event) {
|
1311
|
+
// For keyup, keypress, keydown.. events that could be a little bit obstrusive
|
1312
|
+
// do not validate if val length < min threshold on first validation. Once field have been validated once and info
|
1313
|
+
// about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.
|
1314
|
+
if (new RegExp('key').test(event.type))
|
1315
|
+
if (!this._ui.validationInformationVisible && this.getValue().length <= this.options.validationThreshold)
|
1316
|
+
return;
|
1317
|
+
this._ui.validatedOnce = true;
|
1318
|
+
this.validate();
|
1319
|
+
},
|
1320
|
+
manageFailingFieldTrigger: function (fieldInstance) {
|
1321
|
+
fieldInstance._ui.failedOnce = true;
|
1322
|
+
// Radio and checkboxes fields must bind every field multiple
|
1323
|
+
if (fieldInstance.options.multiple)
|
1324
|
+
$('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
|
1325
|
+
if (!new RegExp('change', 'i').test($(this).parsley().options.trigger || ''))
|
1326
|
+
return $(this).on('change.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
|
1327
|
+
});
|
1328
|
+
// Select case
|
1329
|
+
if (fieldInstance.$element.is('select'))
|
1330
|
+
if (!new RegExp('change', 'i').test(fieldInstance.options.trigger || ''))
|
1331
|
+
return fieldInstance.$element.on('change.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
|
1332
|
+
// All other inputs fields
|
1333
|
+
if (!new RegExp('keyup', 'i').test(fieldInstance.options.trigger || ''))
|
1334
|
+
return fieldInstance.$element.on('keyup.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
|
1335
|
+
},
|
1336
|
+
reset: function (parsleyInstance) {
|
1337
|
+
// Reset all event listeners
|
1338
|
+
parsleyInstance.$element.off('.Parsley');
|
1339
|
+
parsleyInstance.$element.off('.ParsleyFailedOnce');
|
1340
|
+
// Nothing to do if UI never initialized for this field
|
1341
|
+
if ('undefined' === typeof parsleyInstance._ui)
|
1342
|
+
return;
|
1343
|
+
if ('ParsleyForm' === parsleyInstance.__class__)
|
1344
|
+
return;
|
1345
|
+
// Reset all errors' li
|
1346
|
+
parsleyInstance._ui.$errorsWrapper
|
1347
|
+
.removeClass('filled')
|
1348
|
+
.children()
|
1349
|
+
.remove();
|
1350
|
+
// Reset validation class
|
1351
|
+
this._resetClass(parsleyInstance);
|
1352
|
+
// Reset validation flags and last validation result
|
1353
|
+
parsleyInstance._ui.validatedOnce = false;
|
1354
|
+
parsleyInstance._ui.lastValidationResult = [];
|
1355
|
+
parsleyInstance._ui.validationInformationVisible = false;
|
1356
|
+
},
|
1357
|
+
destroy: function (parsleyInstance) {
|
1358
|
+
this.reset(parsleyInstance);
|
1359
|
+
if ('ParsleyForm' === parsleyInstance.__class__)
|
1360
|
+
return;
|
1361
|
+
if ('undefined' !== typeof parsleyInstance._ui)
|
1362
|
+
parsleyInstance._ui.$errorsWrapper.remove();
|
1363
|
+
delete parsleyInstance._ui;
|
1364
|
+
},
|
1365
|
+
_successClass: function (fieldInstance) {
|
1366
|
+
fieldInstance._ui.validationInformationVisible = true;
|
1367
|
+
fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.errorClass).addClass(fieldInstance.options.successClass);
|
1368
|
+
},
|
1369
|
+
_errorClass: function (fieldInstance) {
|
1370
|
+
fieldInstance._ui.validationInformationVisible = true;
|
1371
|
+
fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.successClass).addClass(fieldInstance.options.errorClass);
|
1372
|
+
},
|
1373
|
+
_resetClass: function (fieldInstance) {
|
1374
|
+
fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.successClass).removeClass(fieldInstance.options.errorClass);
|
1375
|
+
}
|
1376
|
+
};
|
1377
|
+
|
1378
|
+
var ParsleyOptionsFactory = function (defaultOptions, globalOptions, userOptions, namespace) {
|
1379
|
+
this.__class__ = 'OptionsFactory';
|
1380
|
+
this.__id__ = ParsleyUtils.hash(4);
|
1381
|
+
this.formOptions = null;
|
1382
|
+
this.fieldOptions = null;
|
1383
|
+
this.staticOptions = $.extend(true, {}, defaultOptions, globalOptions, userOptions, { namespace: namespace });
|
1384
|
+
};
|
1385
|
+
ParsleyOptionsFactory.prototype = {
|
1386
|
+
get: function (parsleyInstance) {
|
1387
|
+
if ('undefined' === typeof parsleyInstance.__class__)
|
1388
|
+
throw new Error('Parsley Instance expected');
|
1389
|
+
switch (parsleyInstance.__class__) {
|
1390
|
+
case 'Parsley':
|
1391
|
+
return this.staticOptions;
|
1392
|
+
case 'ParsleyForm':
|
1393
|
+
return this.getFormOptions(parsleyInstance);
|
1394
|
+
case 'ParsleyField':
|
1395
|
+
case 'ParsleyFieldMultiple':
|
1396
|
+
return this.getFieldOptions(parsleyInstance);
|
1397
|
+
default:
|
1398
|
+
throw new Error('Instance ' + parsleyInstance.__class__ + ' is not supported');
|
1399
|
+
}
|
1400
|
+
},
|
1401
|
+
getFormOptions: function (formInstance) {
|
1402
|
+
this.formOptions = ParsleyUtils.attr(formInstance.$element, this.staticOptions.namespace);
|
1403
|
+
// not deep extend, since formOptions is a 1 level deep object
|
1404
|
+
return $.extend({}, this.staticOptions, this.formOptions);
|
1405
|
+
},
|
1406
|
+
getFieldOptions: function (fieldInstance) {
|
1407
|
+
this.fieldOptions = ParsleyUtils.attr(fieldInstance.$element, this.staticOptions.namespace);
|
1408
|
+
if (null === this.formOptions && 'undefined' !== typeof fieldInstance.parent)
|
1409
|
+
this.formOptions = this.getFormOptions(fieldInstance.parent);
|
1410
|
+
// not deep extend, since formOptions and fieldOptions is a 1 level deep object
|
1411
|
+
return $.extend({}, this.staticOptions, this.formOptions, this.fieldOptions);
|
1412
|
+
}
|
1413
|
+
};
|
1414
|
+
|
1415
|
+
var ParsleyForm = function (element, OptionsFactory) {
|
1416
|
+
this.__class__ = 'ParsleyForm';
|
1417
|
+
this.__id__ = ParsleyUtils.hash(4);
|
1418
|
+
if ('OptionsFactory' !== ParsleyUtils.get(OptionsFactory, '__class__'))
|
1419
|
+
throw new Error('You must give an OptionsFactory instance');
|
1420
|
+
this.OptionsFactory = OptionsFactory;
|
1421
|
+
this.$element = $(element);
|
1422
|
+
this.validationResult = null;
|
1423
|
+
this.options = this.OptionsFactory.get(this);
|
1424
|
+
};
|
1425
|
+
ParsleyForm.prototype = {
|
1426
|
+
onSubmitValidate: function (event) {
|
1427
|
+
this.validate(undefined, undefined, event);
|
1428
|
+
// prevent form submission if validation fails
|
1429
|
+
if (false === this.validationResult && event instanceof $.Event) {
|
1430
|
+
event.stopImmediatePropagation();
|
1431
|
+
event.preventDefault();
|
1432
|
+
}
|
1433
|
+
return this;
|
1434
|
+
},
|
1435
|
+
// @returns boolean
|
1436
|
+
validate: function (group, force, event) {
|
1437
|
+
this.submitEvent = event;
|
1438
|
+
this.validationResult = true;
|
1439
|
+
var fieldValidationResult = [];
|
1440
|
+
// Refresh form DOM options and form's fields that could have changed
|
1441
|
+
this._refreshFields();
|
1442
|
+
$.emit('parsley:form:validate', this);
|
1443
|
+
// loop through fields to validate them one by one
|
1444
|
+
for (var i = 0; i < this.fields.length; i++) {
|
1445
|
+
// do not validate a field if not the same as given validation group
|
1446
|
+
if (group && !this._isFieldInGroup(this.fields[i], group))
|
1447
|
+
continue;
|
1448
|
+
fieldValidationResult = this.fields[i].validate(force);
|
1449
|
+
if (true !== fieldValidationResult && fieldValidationResult.length > 0 && this.validationResult)
|
1450
|
+
this.validationResult = false;
|
1451
|
+
}
|
1452
|
+
$.emit('parsley:form:validated', this);
|
1453
|
+
return this.validationResult;
|
1454
|
+
},
|
1455
|
+
// Iterate over refreshed fields, and stop on first failure
|
1456
|
+
isValid: function (group, force) {
|
1457
|
+
this._refreshFields();
|
1458
|
+
for (var i = 0; i < this.fields.length; i++) {
|
1459
|
+
// do not validate a field if not the same as given validation group
|
1460
|
+
if (group && !this._isFieldInGroup(this.fields[i], group))
|
1461
|
+
continue;
|
1462
|
+
if (false === this.fields[i].isValid(force))
|
1463
|
+
return false;
|
1464
|
+
}
|
1465
|
+
return true;
|
1466
|
+
},
|
1467
|
+
_isFieldInGroup: function (field, group) {
|
1468
|
+
if(ParsleyUtils.isArray(field.options.group))
|
1469
|
+
return -1 !== $.inArray(group, field.options.group);
|
1470
|
+
return field.options.group === group;
|
1471
|
+
},
|
1472
|
+
_refreshFields: function () {
|
1473
|
+
return this.actualizeOptions()._bindFields();
|
1474
|
+
},
|
1475
|
+
_bindFields: function () {
|
1476
|
+
var self = this;
|
1477
|
+
this.fields = [];
|
1478
|
+
this.fieldsMappedById = {};
|
1479
|
+
this.$element.find(this.options.inputs).each(function () {
|
1480
|
+
var fieldInstance = new window.Parsley(this, {}, self);
|
1481
|
+
// Only add valid and not excluded `ParsleyField` and `ParsleyFieldMultiple` children
|
1482
|
+
if (('ParsleyField' === fieldInstance.__class__ || 'ParsleyFieldMultiple' === fieldInstance.__class__) && !fieldInstance.$element.is(fieldInstance.options.excluded))
|
1483
|
+
if ('undefined' === typeof self.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__]) {
|
1484
|
+
self.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__] = fieldInstance;
|
1485
|
+
self.fields.push(fieldInstance);
|
1486
|
+
}
|
1487
|
+
});
|
1488
|
+
return this;
|
1489
|
+
}
|
1490
|
+
};
|
1491
|
+
|
1492
|
+
var ConstraintFactory = function (parsleyField, name, requirements, priority, isDomConstraint) {
|
1493
|
+
if (!new RegExp('ParsleyField').test(ParsleyUtils.get(parsleyField, '__class__')))
|
1494
|
+
throw new Error('ParsleyField or ParsleyFieldMultiple instance expected');
|
1495
|
+
if ('function' !== typeof window.ParsleyValidator.validators[name] &&
|
1496
|
+
'Assert' !== window.ParsleyValidator.validators[name](requirements).__parentClass__)
|
1497
|
+
throw new Error('Valid validator expected');
|
1498
|
+
var getPriority = function (parsleyField, name) {
|
1499
|
+
if ('undefined' !== typeof parsleyField.options[name + 'Priority'])
|
1500
|
+
return parsleyField.options[name + 'Priority'];
|
1501
|
+
return ParsleyUtils.get(window.ParsleyValidator.validators[name](requirements), 'priority') || 2;
|
1502
|
+
};
|
1503
|
+
priority = priority || getPriority(parsleyField, name);
|
1504
|
+
// If validator have a requirementsTransformer, execute it
|
1505
|
+
if ('function' === typeof window.ParsleyValidator.validators[name](requirements).requirementsTransformer)
|
1506
|
+
requirements = window.ParsleyValidator.validators[name](requirements).requirementsTransformer();
|
1507
|
+
return $.extend(window.ParsleyValidator.validators[name](requirements), {
|
1508
|
+
name: name,
|
1509
|
+
requirements: requirements,
|
1510
|
+
priority: priority,
|
1511
|
+
groups: [priority],
|
1512
|
+
isDomConstraint: isDomConstraint || ParsleyUtils.attr(parsleyField.$element, parsleyField.options.namespace, name)
|
1513
|
+
});
|
1514
|
+
};
|
1515
|
+
|
1516
|
+
var ParsleyField = function (field, OptionsFactory, parsleyFormInstance) {
|
1517
|
+
this.__class__ = 'ParsleyField';
|
1518
|
+
this.__id__ = ParsleyUtils.hash(4);
|
1519
|
+
this.$element = $(field);
|
1520
|
+
// If we have a parent `ParsleyForm` instance given, use its `OptionsFactory`, and save parent
|
1521
|
+
if ('undefined' !== typeof parsleyFormInstance) {
|
1522
|
+
this.parent = parsleyFormInstance;
|
1523
|
+
this.OptionsFactory = this.parent.OptionsFactory;
|
1524
|
+
this.options = this.OptionsFactory.get(this);
|
1525
|
+
// Else, take the `Parsley` one
|
1526
|
+
} else {
|
1527
|
+
this.OptionsFactory = OptionsFactory;
|
1528
|
+
this.options = this.OptionsFactory.get(this);
|
1529
|
+
}
|
1530
|
+
// Initialize some properties
|
1531
|
+
this.constraints = [];
|
1532
|
+
this.constraintsByName = {};
|
1533
|
+
this.validationResult = [];
|
1534
|
+
// Bind constraints
|
1535
|
+
this._bindConstraints();
|
1536
|
+
};
|
1537
|
+
ParsleyField.prototype = {
|
1538
|
+
// # Public API
|
1539
|
+
// Validate field and $.emit some events for mainly `ParsleyUI`
|
1540
|
+
// @returns validationResult:
|
1541
|
+
// - `true` if all constraint passes
|
1542
|
+
// - `[]` if not required field and empty (not validated)
|
1543
|
+
// - `[Violation, [Violation..]]` if there were validation errors
|
1544
|
+
validate: function (force) {
|
1545
|
+
this.value = this.getValue();
|
1546
|
+
// Field Validate event. `this.value` could be altered for custom needs
|
1547
|
+
$.emit('parsley:field:validate', this);
|
1548
|
+
$.emit('parsley:field:' + (this.isValid(force, this.value) ? 'success' : 'error'), this);
|
1549
|
+
// Field validated event. `this.validationResult` could be altered for custom needs too
|
1550
|
+
$.emit('parsley:field:validated', this);
|
1551
|
+
return this.validationResult;
|
1552
|
+
},
|
1553
|
+
// Just validate field. Do not trigger any event
|
1554
|
+
// Same @return as `validate()`
|
1555
|
+
isValid: function (force, value) {
|
1556
|
+
// Recompute options and rebind constraints to have latest changes
|
1557
|
+
this.refreshConstraints();
|
1558
|
+
// Sort priorities to validate more important first
|
1559
|
+
var priorities = this._getConstraintsSortedPriorities();
|
1560
|
+
if (0 === priorities.length)
|
1561
|
+
return this.validationResult = [];
|
1562
|
+
// Value could be passed as argument, needed to add more power to 'parsley:field:validate'
|
1563
|
+
value = value || this.getValue();
|
1564
|
+
// If a field is empty and not required, leave it alone, it's just fine
|
1565
|
+
// Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators
|
1566
|
+
if (!value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty && true !== force)
|
1567
|
+
return this.validationResult = [];
|
1568
|
+
// If we want to validate field against all constraints, just call Validator and let it do the job
|
1569
|
+
if (false === this.options.priorityEnabled)
|
1570
|
+
return true === (this.validationResult = this.validateThroughValidator(value, this.constraints, 'Any'));
|
1571
|
+
// Else, iterate over priorities one by one, and validate related asserts one by one
|
1572
|
+
for (var i = 0; i < priorities.length; i++)
|
1573
|
+
if (true !== (this.validationResult = this.validateThroughValidator(value, this.constraints, priorities[i])))
|
1574
|
+
return false;
|
1575
|
+
return true;
|
1576
|
+
},
|
1577
|
+
// @returns Parsley field computed value that could be overrided or configured in DOM
|
1578
|
+
getValue: function () {
|
1579
|
+
var value;
|
1580
|
+
// Value could be overriden in DOM
|
1581
|
+
if ('undefined' !== typeof this.options.value)
|
1582
|
+
value = this.options.value;
|
1583
|
+
else
|
1584
|
+
value = this.$element.val();
|
1585
|
+
// Handle wrong DOM or configurations
|
1586
|
+
if ('undefined' === typeof value || null === value)
|
1587
|
+
return '';
|
1588
|
+
// Use `data-parsley-trim-value="true"` to auto trim inputs entry
|
1589
|
+
if (true === this.options.trimValue)
|
1590
|
+
return value.replace(/^\s+|\s+$/g, '');
|
1591
|
+
return value;
|
1592
|
+
},
|
1593
|
+
// Actualize options that could have change since previous validation
|
1594
|
+
// Re-bind accordingly constraints (could be some new, removed or updated)
|
1595
|
+
refreshConstraints: function () {
|
1596
|
+
return this.actualizeOptions()._bindConstraints();
|
1597
|
+
},
|
1598
|
+
/**
|
1599
|
+
* Add a new constraint to a field
|
1600
|
+
*
|
1601
|
+
* @method addConstraint
|
1602
|
+
* @param {String} name
|
1603
|
+
* @param {Mixed} requirements optional
|
1604
|
+
* @param {Number} priority optional
|
1605
|
+
* @param {Boolean} isDomConstraint optional
|
1606
|
+
*/
|
1607
|
+
addConstraint: function (name, requirements, priority, isDomConstraint) {
|
1608
|
+
name = name.toLowerCase();
|
1609
|
+
if ('function' === typeof window.ParsleyValidator.validators[name]) {
|
1610
|
+
var constraint = new ConstraintFactory(this, name, requirements, priority, isDomConstraint);
|
1611
|
+
// if constraint already exist, delete it and push new version
|
1612
|
+
if ('undefined' !== this.constraintsByName[constraint.name])
|
1613
|
+
this.removeConstraint(constraint.name);
|
1614
|
+
this.constraints.push(constraint);
|
1615
|
+
this.constraintsByName[constraint.name] = constraint;
|
1616
|
+
}
|
1617
|
+
return this;
|
1618
|
+
},
|
1619
|
+
// Remove a constraint
|
1620
|
+
removeConstraint: function (name) {
|
1621
|
+
for (var i = 0; i < this.constraints.length; i++)
|
1622
|
+
if (name === this.constraints[i].name) {
|
1623
|
+
this.constraints.splice(i, 1);
|
1624
|
+
break;
|
1625
|
+
}
|
1626
|
+
delete this.constraintsByName[name];
|
1627
|
+
return this;
|
1628
|
+
},
|
1629
|
+
// Update a constraint (Remove + re-add)
|
1630
|
+
updateConstraint: function (name, parameters, priority) {
|
1631
|
+
return this.removeConstraint(name)
|
1632
|
+
.addConstraint(name, parameters, priority);
|
1633
|
+
},
|
1634
|
+
// # Internals
|
1635
|
+
// Internal only.
|
1636
|
+
// Bind constraints from config + options + DOM
|
1637
|
+
_bindConstraints: function () {
|
1638
|
+
var constraints = [], constraintsByName = {};
|
1639
|
+
// clean all existing DOM constraints to only keep javascript user constraints
|
1640
|
+
for (var i = 0; i < this.constraints.length; i++)
|
1641
|
+
if (false === this.constraints[i].isDomConstraint) {
|
1642
|
+
constraints.push(this.constraints[i]);
|
1643
|
+
constraintsByName[this.constraints[i].name] = this.constraints[i];
|
1644
|
+
}
|
1645
|
+
this.constraints = constraints;
|
1646
|
+
this.constraintsByName = constraintsByName;
|
1647
|
+
// then re-add Parsley DOM-API constraints
|
1648
|
+
for (var name in this.options)
|
1649
|
+
this.addConstraint(name, this.options[name]);
|
1650
|
+
// finally, bind special HTML5 constraints
|
1651
|
+
return this._bindHtml5Constraints();
|
1652
|
+
},
|
1653
|
+
// Internal only.
|
1654
|
+
// Bind specific HTML5 constraints to be HTML5 compliant
|
1655
|
+
_bindHtml5Constraints: function () {
|
1656
|
+
// html5 required
|
1657
|
+
if (this.$element.hasClass('required') || this.$element.attr('required'))
|
1658
|
+
this.addConstraint('required', true, undefined, true);
|
1659
|
+
// html5 pattern
|
1660
|
+
if ('string' === typeof this.$element.attr('pattern'))
|
1661
|
+
this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);
|
1662
|
+
// range
|
1663
|
+
if ('undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max'))
|
1664
|
+
this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);
|
1665
|
+
// HTML5 min
|
1666
|
+
else if ('undefined' !== typeof this.$element.attr('min'))
|
1667
|
+
this.addConstraint('min', this.$element.attr('min'), undefined, true);
|
1668
|
+
// HTML5 max
|
1669
|
+
else if ('undefined' !== typeof this.$element.attr('max'))
|
1670
|
+
this.addConstraint('max', this.$element.attr('max'), undefined, true);
|
1671
|
+
// html5 types
|
1672
|
+
var type = this.$element.attr('type');
|
1673
|
+
if ('undefined' === typeof type)
|
1674
|
+
return this;
|
1675
|
+
// Small special case here for HTML5 number: integer validator if step attribute is undefined or an integer value, number otherwise
|
1676
|
+
if ('number' === type) {
|
1677
|
+
if (('undefined' === typeof this.$element.attr('step')) || (0 === parseFloat(this.$element.attr('step')) % 1)) {
|
1678
|
+
return this.addConstraint('type', 'integer', undefined, true);
|
1679
|
+
} else {
|
1680
|
+
return this.addConstraint('type', 'number', undefined, true);
|
1681
|
+
}
|
1682
|
+
// Regular other HTML5 supported types
|
1683
|
+
} else if (new RegExp(type, 'i').test('email url range')) {
|
1684
|
+
return this.addConstraint('type', type, undefined, true);
|
1685
|
+
}
|
1686
|
+
return this;
|
1687
|
+
},
|
1688
|
+
// Internal only.
|
1689
|
+
// Field is required if have required constraint without `false` value
|
1690
|
+
_isRequired: function () {
|
1691
|
+
if ('undefined' === typeof this.constraintsByName.required)
|
1692
|
+
return false;
|
1693
|
+
return false !== this.constraintsByName.required.requirements;
|
1694
|
+
},
|
1695
|
+
// Internal only.
|
1696
|
+
// Sort constraints by priority DESC
|
1697
|
+
_getConstraintsSortedPriorities: function () {
|
1698
|
+
var priorities = [];
|
1699
|
+
// Create array unique of priorities
|
1700
|
+
for (var i = 0; i < this.constraints.length; i++)
|
1701
|
+
if (-1 === priorities.indexOf(this.constraints[i].priority))
|
1702
|
+
priorities.push(this.constraints[i].priority);
|
1703
|
+
// Sort them by priority DESC
|
1704
|
+
priorities.sort(function (a, b) { return b - a; });
|
1705
|
+
return priorities;
|
1706
|
+
}
|
1707
|
+
};
|
1708
|
+
|
1709
|
+
var ParsleyMultiple = function () {
|
1710
|
+
this.__class__ = 'ParsleyFieldMultiple';
|
1711
|
+
};
|
1712
|
+
ParsleyMultiple.prototype = {
|
1713
|
+
// Add new `$element` sibling for multiple field
|
1714
|
+
addElement: function ($element) {
|
1715
|
+
this.$elements.push($element);
|
1716
|
+
return this;
|
1717
|
+
},
|
1718
|
+
// See `ParsleyField.refreshConstraints()`
|
1719
|
+
refreshConstraints: function () {
|
1720
|
+
var fieldConstraints;
|
1721
|
+
this.constraints = [];
|
1722
|
+
// Select multiple special treatment
|
1723
|
+
if (this.$element.is('select')) {
|
1724
|
+
this.actualizeOptions()._bindConstraints();
|
1725
|
+
return this;
|
1726
|
+
}
|
1727
|
+
// Gather all constraints for each input in the multiple group
|
1728
|
+
for (var i = 0; i < this.$elements.length; i++) {
|
1729
|
+
// Check if element have not been dynamically removed since last binding
|
1730
|
+
if (!$('html').has(this.$elements[i]).length) {
|
1731
|
+
this.$elements.splice(i, 1);
|
1732
|
+
continue;
|
1733
|
+
}
|
1734
|
+
fieldConstraints = this.$elements[i].data('ParsleyFieldMultiple').refreshConstraints().constraints;
|
1735
|
+
for (var j = 0; j < fieldConstraints.length; j++)
|
1736
|
+
this.addConstraint(fieldConstraints[j].name, fieldConstraints[j].requirements, fieldConstraints[j].priority, fieldConstraints[j].isDomConstraint);
|
1737
|
+
}
|
1738
|
+
return this;
|
1739
|
+
},
|
1740
|
+
// See `ParsleyField.getValue()`
|
1741
|
+
getValue: function () {
|
1742
|
+
// Value could be overriden in DOM
|
1743
|
+
if ('undefined' !== typeof this.options.value)
|
1744
|
+
return this.options.value;
|
1745
|
+
// Radio input case
|
1746
|
+
if (this.$element.is('input[type=radio]'))
|
1747
|
+
return $('[' + this.options.namespace + 'multiple="' + this.options.multiple + '"]:checked').val() || '';
|
1748
|
+
// checkbox input case
|
1749
|
+
if (this.$element.is('input[type=checkbox]')) {
|
1750
|
+
var values = [];
|
1751
|
+
$('[' + this.options.namespace + 'multiple="' + this.options.multiple + '"]:checked').each(function () {
|
1752
|
+
values.push($(this).val());
|
1753
|
+
});
|
1754
|
+
return values.length ? values : [];
|
1755
|
+
}
|
1756
|
+
// Select multiple case
|
1757
|
+
if (this.$element.is('select') && null === this.$element.val())
|
1758
|
+
return [];
|
1759
|
+
// Default case that should never happen
|
1760
|
+
return this.$element.val();
|
1761
|
+
},
|
1762
|
+
_init: function (multiple) {
|
1763
|
+
this.$elements = [this.$element];
|
1764
|
+
this.options.multiple = multiple;
|
1765
|
+
return this;
|
1766
|
+
}
|
1767
|
+
};
|
1768
|
+
|
1769
|
+
var
|
1770
|
+
o = $({}),
|
1771
|
+
subscribed = {};
|
1772
|
+
// $.listen(name, callback);
|
1773
|
+
// $.listen(name, context, callback);
|
1774
|
+
$.listen = function (name) {
|
1775
|
+
if ('undefined' === typeof subscribed[name])
|
1776
|
+
subscribed[name] = [];
|
1777
|
+
if ('function' === typeof arguments[1])
|
1778
|
+
return subscribed[name].push({ fn: arguments[1] });
|
1779
|
+
if ('object' === typeof arguments[1] && 'function' === typeof arguments[2])
|
1780
|
+
return subscribed[name].push({ fn: arguments[2], ctxt: arguments[1] });
|
1781
|
+
throw new Error('Wrong parameters');
|
1782
|
+
};
|
1783
|
+
$.listenTo = function (instance, name, fn) {
|
1784
|
+
if ('undefined' === typeof subscribed[name])
|
1785
|
+
subscribed[name] = [];
|
1786
|
+
if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
|
1787
|
+
throw new Error('Must give Parsley instance');
|
1788
|
+
if ('string' !== typeof name || 'function' !== typeof fn)
|
1789
|
+
throw new Error('Wrong parameters');
|
1790
|
+
subscribed[name].push({ instance: instance, fn: fn });
|
1791
|
+
};
|
1792
|
+
$.unsubscribe = function (name, fn) {
|
1793
|
+
if ('undefined' === typeof subscribed[name])
|
1794
|
+
return;
|
1795
|
+
if ('string' !== typeof name || 'function' !== typeof fn)
|
1796
|
+
throw new Error('Wrong arguments');
|
1797
|
+
for (var i = 0; i < subscribed[name].length; i++)
|
1798
|
+
if (subscribed[name][i].fn === fn)
|
1799
|
+
return subscribed[name].splice(i, 1);
|
1800
|
+
};
|
1801
|
+
$.unsubscribeTo = function (instance, name) {
|
1802
|
+
if ('undefined' === typeof subscribed[name])
|
1803
|
+
return;
|
1804
|
+
if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
|
1805
|
+
throw new Error('Must give Parsley instance');
|
1806
|
+
for (var i = 0; i < subscribed[name].length; i++)
|
1807
|
+
if ('undefined' !== typeof subscribed[name][i].instance && subscribed[name][i].instance.__id__ === instance.__id__)
|
1808
|
+
return subscribed[name].splice(i, 1);
|
1809
|
+
};
|
1810
|
+
$.unsubscribeAll = function (name) {
|
1811
|
+
if ('undefined' === typeof subscribed[name])
|
1812
|
+
return;
|
1813
|
+
delete subscribed[name];
|
1814
|
+
};
|
1815
|
+
// $.emit(name [, arguments...]);
|
1816
|
+
// $.emit(name, instance [, arguments..]);
|
1817
|
+
$.emit = function (name, instance) {
|
1818
|
+
if ('undefined' === typeof subscribed[name])
|
1819
|
+
return;
|
1820
|
+
// loop through registered callbacks for this event
|
1821
|
+
for (var i = 0; i < subscribed[name].length; i++) {
|
1822
|
+
// if instance is not registered, simple emit
|
1823
|
+
if ('undefined' === typeof subscribed[name][i].instance) {
|
1824
|
+
subscribed[name][i].fn.apply('undefined' !== typeof subscribed[name][i].ctxt ? subscribed[name][i].ctxt : o, Array.prototype.slice.call(arguments, 1));
|
1825
|
+
continue;
|
1826
|
+
}
|
1827
|
+
// if instance registered but no instance given for the emit, continue
|
1828
|
+
if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
|
1829
|
+
continue;
|
1830
|
+
// if instance is registered and same id, emit
|
1831
|
+
if (subscribed[name][i].instance.__id__ === instance.__id__) {
|
1832
|
+
subscribed[name][i].fn.apply(o, Array.prototype.slice.call(arguments, 1));
|
1833
|
+
continue;
|
1834
|
+
}
|
1835
|
+
// if registered instance is a Form and fired one is a Field, loop over all its fields and emit if field found
|
1836
|
+
if (subscribed[name][i].instance instanceof ParsleyForm && instance instanceof ParsleyField)
|
1837
|
+
for (var j = 0; j < subscribed[name][i].instance.fields.length; j++)
|
1838
|
+
if (subscribed[name][i].instance.fields[j].__id__ === instance.__id__) {
|
1839
|
+
subscribed[name][i].fn.apply(o, Array.prototype.slice.call(arguments, 1));
|
1840
|
+
continue;
|
1841
|
+
}
|
1842
|
+
}
|
1843
|
+
};
|
1844
|
+
$.subscribed = function () { return subscribed; };
|
1845
|
+
|
1846
|
+
// ParsleyConfig definition if not already set
|
1847
|
+
window.ParsleyConfig = window.ParsleyConfig || {};
|
1848
|
+
window.ParsleyConfig.i18n = window.ParsleyConfig.i18n || {};
|
1849
|
+
// Define then the messages
|
1850
|
+
window.ParsleyConfig.i18n.en = $.extend(window.ParsleyConfig.i18n.en || {}, {
|
1851
|
+
defaultMessage: "This value seems to be invalid.",
|
1852
|
+
type: {
|
1853
|
+
email: "This value should be a valid email.",
|
1854
|
+
url: "This value should be a valid url.",
|
1855
|
+
number: "This value should be a valid number.",
|
1856
|
+
integer: "This value should be a valid integer.",
|
1857
|
+
digits: "This value should be digits.",
|
1858
|
+
alphanum: "This value should be alphanumeric."
|
1859
|
+
},
|
1860
|
+
notblank: "This value should not be blank.",
|
1861
|
+
required: "This value is required.",
|
1862
|
+
pattern: "This value seems to be invalid.",
|
1863
|
+
min: "This value should be greater than or equal to %s.",
|
1864
|
+
max: "This value should be lower than or equal to %s.",
|
1865
|
+
range: "This value should be between %s and %s.",
|
1866
|
+
minlength: "This value is too short. It should have %s characters or more.",
|
1867
|
+
maxlength: "This value is too long. It should have %s characters or fewer.",
|
1868
|
+
length: "This value length is invalid. It should be between %s and %s characters long.",
|
1869
|
+
mincheck: "You must select at least %s choices.",
|
1870
|
+
maxcheck: "You must select %s choices or fewer.",
|
1871
|
+
check: "You must select between %s and %s choices.",
|
1872
|
+
equalto: "This value should be the same."
|
1873
|
+
});
|
1874
|
+
// If file is loaded after Parsley main file, auto-load locale
|
1875
|
+
if ('undefined' !== typeof window.ParsleyValidator)
|
1876
|
+
window.ParsleyValidator.addCatalog('en', window.ParsleyConfig.i18n.en, true);
|
1877
|
+
|
1878
|
+
// Parsley.js 2.0.6
|
1879
|
+
// http://parsleyjs.org
|
1880
|
+
// (c) 20012-2014 Guillaume Potier, Wisembly
|
1881
|
+
// Parsley may be freely distributed under the MIT license.
|
1882
|
+
|
1883
|
+
// ### Parsley factory
|
1884
|
+
var Parsley = function (element, options, parsleyFormInstance) {
|
1885
|
+
this.__class__ = 'Parsley';
|
1886
|
+
this.__version__ = '2.0.6';
|
1887
|
+
this.__id__ = ParsleyUtils.hash(4);
|
1888
|
+
// Parsley must be instanciated with a DOM element or jQuery $element
|
1889
|
+
if ('undefined' === typeof element)
|
1890
|
+
throw new Error('You must give an element');
|
1891
|
+
if ('undefined' !== typeof parsleyFormInstance && 'ParsleyForm' !== parsleyFormInstance.__class__)
|
1892
|
+
throw new Error('Parent instance must be a ParsleyForm instance');
|
1893
|
+
return this.init($(element), options, parsleyFormInstance);
|
1894
|
+
};
|
1895
|
+
Parsley.prototype = {
|
1896
|
+
init: function ($element, options, parsleyFormInstance) {
|
1897
|
+
if (!$element.length)
|
1898
|
+
throw new Error('You must bind Parsley on an existing element.');
|
1899
|
+
this.$element = $element;
|
1900
|
+
// If element have already been binded, returns its saved Parsley instance
|
1901
|
+
if (this.$element.data('Parsley')) {
|
1902
|
+
var savedparsleyFormInstance = this.$element.data('Parsley');
|
1903
|
+
// If saved instance have been binded without a ParsleyForm parent and there is one given in this call, add it
|
1904
|
+
if ('undefined' !== typeof parsleyFormInstance)
|
1905
|
+
savedparsleyFormInstance.parent = parsleyFormInstance;
|
1906
|
+
return savedparsleyFormInstance;
|
1907
|
+
}
|
1908
|
+
// Handle 'static' options
|
1909
|
+
this.OptionsFactory = new ParsleyOptionsFactory(ParsleyDefaults, ParsleyUtils.get(window, 'ParsleyConfig') || {}, options, this.getNamespace(options));
|
1910
|
+
this.options = this.OptionsFactory.get(this);
|
1911
|
+
// A ParsleyForm instance is obviously a `<form>` elem but also every node that is not an input and have `data-parsley-validate` attribute
|
1912
|
+
if (this.$element.is('form') || (ParsleyUtils.attr(this.$element, this.options.namespace, 'validate') && !this.$element.is(this.options.inputs)))
|
1913
|
+
return this.bind('parsleyForm');
|
1914
|
+
// Every other supported element and not excluded element is binded as a `ParsleyField` or `ParsleyFieldMultiple`
|
1915
|
+
else if (this.$element.is(this.options.inputs) && !this.$element.is(this.options.excluded))
|
1916
|
+
return this.isMultiple() ? this.handleMultiple(parsleyFormInstance) : this.bind('parsleyField', parsleyFormInstance);
|
1917
|
+
return this;
|
1918
|
+
},
|
1919
|
+
isMultiple: function () {
|
1920
|
+
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'));
|
1921
|
+
},
|
1922
|
+
// Multiples fields are a real nightmare :(
|
1923
|
+
// Maybe some refacto would be appreciated here..
|
1924
|
+
handleMultiple: function (parsleyFormInstance) {
|
1925
|
+
var
|
1926
|
+
that = this,
|
1927
|
+
name,
|
1928
|
+
multiple,
|
1929
|
+
parsleyMultipleInstance;
|
1930
|
+
// Get parsleyFormInstance options if exist, mixed with element attributes
|
1931
|
+
this.options = $.extend(this.options, parsleyFormInstance ? parsleyFormInstance.OptionsFactory.get(parsleyFormInstance) : {}, ParsleyUtils.attr(this.$element, this.options.namespace));
|
1932
|
+
// Handle multiple name
|
1933
|
+
if (this.options.multiple)
|
1934
|
+
multiple = this.options.multiple;
|
1935
|
+
else if ('undefined' !== typeof this.$element.attr('name') && this.$element.attr('name').length)
|
1936
|
+
multiple = name = this.$element.attr('name');
|
1937
|
+
else if ('undefined' !== typeof this.$element.attr('id') && this.$element.attr('id').length)
|
1938
|
+
multiple = this.$element.attr('id');
|
1939
|
+
// Special select multiple input
|
1940
|
+
if (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple')) {
|
1941
|
+
return this.bind('parsleyFieldMultiple', parsleyFormInstance, multiple || this.__id__);
|
1942
|
+
// Else for radio / checkboxes, we need a `name` or `data-parsley-multiple` to properly bind it
|
1943
|
+
} else if ('undefined' === typeof multiple) {
|
1944
|
+
if (window.console && window.console.warn)
|
1945
|
+
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);
|
1946
|
+
return this;
|
1947
|
+
}
|
1948
|
+
// Remove special chars
|
1949
|
+
multiple = multiple.replace(/(:|\.|\[|\]|\{|\}|\$)/g, '');
|
1950
|
+
// Add proper `data-parsley-multiple` to siblings if we have a valid multiple name
|
1951
|
+
if ('undefined' !== typeof name) {
|
1952
|
+
$('input[name="' + name + '"]').each(function () {
|
1953
|
+
if ($(this).is('input[type=radio], input[type=checkbox]'))
|
1954
|
+
$(this).attr(that.options.namespace + 'multiple', multiple);
|
1955
|
+
});
|
1956
|
+
}
|
1957
|
+
// Check here if we don't already have a related multiple instance saved
|
1958
|
+
if ($('[' + this.options.namespace + 'multiple=' + multiple +']').length) {
|
1959
|
+
for (var i = 0; i < $('[' + this.options.namespace + 'multiple=' + multiple +']').length; i++) {
|
1960
|
+
if ('undefined' !== typeof $($('[' + this.options.namespace + 'multiple=' + multiple +']').get(i)).data('Parsley')) {
|
1961
|
+
parsleyMultipleInstance = $($('[' + this.options.namespace + 'multiple=' + multiple +']').get(i)).data('Parsley');
|
1962
|
+
if (!this.$element.data('ParsleyFieldMultiple')) {
|
1963
|
+
parsleyMultipleInstance.addElement(this.$element);
|
1964
|
+
this.$element.attr(this.options.namespace + 'id', parsleyMultipleInstance.__id__);
|
1965
|
+
}
|
1966
|
+
break;
|
1967
|
+
}
|
1968
|
+
}
|
1969
|
+
}
|
1970
|
+
// Create a secret ParsleyField instance for every multiple field. It would be stored in `data('ParsleyFieldMultiple')`
|
1971
|
+
// And would be useful later to access classic `ParsleyField` stuff while being in a `ParsleyFieldMultiple` instance
|
1972
|
+
this.bind('parsleyField', parsleyFormInstance, multiple, true);
|
1973
|
+
return parsleyMultipleInstance || this.bind('parsleyFieldMultiple', parsleyFormInstance, multiple);
|
1974
|
+
},
|
1975
|
+
// Retrieve namespace used for DOM-API
|
1976
|
+
getNamespace: function (options) {
|
1977
|
+
// `data-parsley-namespace=<namespace>`
|
1978
|
+
if ('undefined' !== typeof this.$element.data('parsleyNamespace'))
|
1979
|
+
return this.$element.data('parsleyNamespace');
|
1980
|
+
if ('undefined' !== typeof ParsleyUtils.get(options, 'namespace'))
|
1981
|
+
return options.namespace;
|
1982
|
+
if ('undefined' !== typeof ParsleyUtils.get(window, 'ParsleyConfig.namespace'))
|
1983
|
+
return window.ParsleyConfig.namespace;
|
1984
|
+
return ParsleyDefaults.namespace;
|
1985
|
+
},
|
1986
|
+
// Return proper `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`
|
1987
|
+
bind: function (type, parentParsleyFormInstance, multiple, doNotStore) {
|
1988
|
+
var parsleyInstance;
|
1989
|
+
switch (type) {
|
1990
|
+
case 'parsleyForm':
|
1991
|
+
parsleyInstance = $.extend(
|
1992
|
+
new ParsleyForm(this.$element, this.OptionsFactory),
|
1993
|
+
new ParsleyAbstract(),
|
1994
|
+
window.ParsleyExtend
|
1995
|
+
)._bindFields();
|
1996
|
+
break;
|
1997
|
+
case 'parsleyField':
|
1998
|
+
parsleyInstance = $.extend(
|
1999
|
+
new ParsleyField(this.$element, this.OptionsFactory, parentParsleyFormInstance),
|
2000
|
+
new ParsleyAbstract(),
|
2001
|
+
window.ParsleyExtend
|
2002
|
+
);
|
2003
|
+
break;
|
2004
|
+
case 'parsleyFieldMultiple':
|
2005
|
+
parsleyInstance = $.extend(
|
2006
|
+
new ParsleyField(this.$element, this.OptionsFactory, parentParsleyFormInstance),
|
2007
|
+
new ParsleyAbstract(),
|
2008
|
+
new ParsleyMultiple(),
|
2009
|
+
window.ParsleyExtend
|
2010
|
+
)._init(multiple);
|
2011
|
+
break;
|
2012
|
+
default:
|
2013
|
+
throw new Error(type + 'is not a supported Parsley type');
|
2014
|
+
}
|
2015
|
+
if ('undefined' !== typeof multiple)
|
2016
|
+
ParsleyUtils.setAttr(this.$element, this.options.namespace, 'multiple', multiple);
|
2017
|
+
if ('undefined' !== typeof doNotStore) {
|
2018
|
+
this.$element.data('ParsleyFieldMultiple', parsleyInstance);
|
2019
|
+
return parsleyInstance;
|
2020
|
+
}
|
2021
|
+
// Store instance if `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`
|
2022
|
+
if (new RegExp('ParsleyF', 'i').test(parsleyInstance.__class__)) {
|
2023
|
+
// Store for later access the freshly binded instance in DOM element itself using jQuery `data()`
|
2024
|
+
this.$element.data('Parsley', parsleyInstance);
|
2025
|
+
// Tell the world we got a new ParsleyForm or ParsleyField instance!
|
2026
|
+
$.emit('parsley:' + ('parsleyForm' === type ? 'form' : 'field') + ':init', parsleyInstance);
|
2027
|
+
}
|
2028
|
+
return parsleyInstance;
|
2029
|
+
}
|
2030
|
+
};
|
2031
|
+
// ### jQuery API
|
2032
|
+
// `$('.elem').parsley(options)` or `$('.elem').psly(options)`
|
2033
|
+
$.fn.parsley = $.fn.psly = function (options) {
|
2034
|
+
if (this.length > 1) {
|
2035
|
+
var instances = [];
|
2036
|
+
this.each(function () {
|
2037
|
+
instances.push($(this).parsley(options));
|
2038
|
+
});
|
2039
|
+
return instances;
|
2040
|
+
}
|
2041
|
+
// Return undefined if applied to non existing DOM element
|
2042
|
+
if (!$(this).length) {
|
2043
|
+
if (window.console && window.console.warn)
|
2044
|
+
window.console.warn('You must bind Parsley on an existing element.');
|
2045
|
+
return;
|
2046
|
+
}
|
2047
|
+
return new Parsley(this, options);
|
2048
|
+
};
|
2049
|
+
// ### ParsleyUI
|
2050
|
+
// UI is a class apart that only listen to some events and them modify DOM accordingly
|
2051
|
+
// Could be overriden by defining a `window.ParsleyConfig.ParsleyUI` appropriate class (with `listen()` method basically)
|
2052
|
+
window.ParsleyUI = 'function' === typeof ParsleyUtils.get(window, 'ParsleyConfig.ParsleyUI') ?
|
2053
|
+
new window.ParsleyConfig.ParsleyUI().listen() : new ParsleyUI().listen();
|
2054
|
+
// ### ParsleyField and ParsleyForm extension
|
2055
|
+
// Ensure that defined if not already the case
|
2056
|
+
if ('undefined' === typeof window.ParsleyExtend)
|
2057
|
+
window.ParsleyExtend = {};
|
2058
|
+
// ### ParsleyConfig
|
2059
|
+
// Ensure that defined if not already the case
|
2060
|
+
if ('undefined' === typeof window.ParsleyConfig)
|
2061
|
+
window.ParsleyConfig = {};
|
2062
|
+
// ### Globals
|
2063
|
+
window.Parsley = window.psly = Parsley;
|
2064
|
+
window.ParsleyUtils = ParsleyUtils;
|
2065
|
+
window.ParsleyValidator = new ParsleyValidator(window.ParsleyConfig.validators, window.ParsleyConfig.i18n);
|
2066
|
+
// ### PARSLEY auto-binding
|
2067
|
+
// Prevent it by setting `ParsleyConfig.autoBind` to `false`
|
2068
|
+
if (false !== ParsleyUtils.get(window, 'ParsleyConfig.autoBind'))
|
2069
|
+
$(function () {
|
2070
|
+
// Works only on `data-parsley-validate`.
|
2071
|
+
if ($('[data-parsley-validate]').length)
|
2072
|
+
$('[data-parsley-validate]').parsley();
|
2073
|
+
});
|
2074
|
+
}));
|