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.
Files changed (330) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +50 -0
  4. data/_data/publications/pulliam2012.yml +12 -0
  5. data/_data/team/ackley.yml +25 -0
  6. data/_data/team/are.yml +22 -0
  7. data/_data/team/beauclair.yml +14 -0
  8. data/_data/team/bekele.yml +14 -0
  9. data/_data/team/bellan.yml +46 -0
  10. data/_data/team/bolton.yml +33 -0
  11. data/_data/team/borchering.yml +65 -0
  12. data/_data/team/brook.yml +15 -0
  13. data/_data/team/brown.yml +18 -0
  14. data/_data/team/bruce.yml +26 -0
  15. data/_data/team/brucePA.yml +9 -0
  16. data/_data/team/deleo.yml +49 -0
  17. data/_data/team/delva.yml +15 -0
  18. data/_data/team/dushoff.yml +52 -0
  19. data/_data/team/ervin.yml +10 -0
  20. data/_data/team/faikah.yml +26 -0
  21. data/_data/team/grebe.yml +36 -0
  22. data/_data/team/hargrove.yml +36 -0
  23. data/_data/team/hitchcock.yml +10 -0
  24. data/_data/team/hladish.yml +45 -0
  25. data/_data/team/january.yml +9 -0
  26. data/_data/team/kassanjee.yml +20 -0
  27. data/_data/team/li.yml +45 -0
  28. data/_data/team/lord.yml +20 -0
  29. data/_data/team/marx.yml +14 -0
  30. data/_data/team/mcintosh.yml +20 -0
  31. data/_data/team/mhlanga.yml +22 -0
  32. data/_data/team/mthombothi.yml +23 -0
  33. data/_data/team/mugwagwa.yml +18 -0
  34. data/_data/team/mwangi.yml +24 -0
  35. data/_data/team/mwebaze.yml +20 -0
  36. data/_data/team/ndifon.yml +18 -0
  37. data/_data/team/ngonghala.yml +30 -0
  38. data/_data/team/nondi.yml +14 -0
  39. data/_data/team/nyamai.yml +18 -0
  40. data/_data/team/october.yml +9 -0
  41. data/_data/team/paradza.yml +19 -0
  42. data/_data/team/pearson.yml +58 -0
  43. data/_data/team/porco.yml +14 -0
  44. data/_data/team/pulliam.yml +51 -0
  45. data/_data/team/reiner.yml +18 -0
  46. data/_data/team/scheepers.yml +9 -0
  47. data/_data/team/scott.yml +51 -0
  48. data/_data/team/sempa.yml +32 -0
  49. data/_data/team/sikhondze.yml +14 -0
  50. data/_data/team/template.yml +18 -0
  51. data/_data/team/ujeneza.yml +38 -0
  52. data/_data/team/vanschalkwyk.yml +32 -0
  53. data/_data/team/welte.yml +18 -0
  54. data/_data/team/williams.yml +28 -0
  55. data/_data/team/ying.yml +21 -0
  56. data/_includes/MedPH/.DS_Store +0 -0
  57. data/_includes/MedPH/assignments.md +42 -0
  58. data/_includes/MedPH/assignmentsStandard.md +74 -0
  59. data/_includes/MedPH/computerlabs.md +38 -0
  60. data/_includes/MedPH/computerlabsStandard.md +38 -0
  61. data/_includes/MedPH/lectures.md +12 -0
  62. data/_includes/MedPH/references.md +71 -0
  63. data/_includes/MedPH/schedule.md +85 -0
  64. data/_includes/MedPH/scheduleStandard.md +93 -0
  65. data/_includes/bottomTable.html +5 -0
  66. data/_includes/centerTable.html +5 -0
  67. data/_includes/clinicNavbar.html +46 -0
  68. data/_includes/contact.html +12 -0
  69. data/_includes/directors.html +47 -0
  70. data/_includes/footer.html +23 -0
  71. data/_includes/head.html +28 -0
  72. data/_includes/header.html +31 -0
  73. data/_includes/hero.html +14 -0
  74. data/_includes/index.md +9 -0
  75. data/_includes/mission.html +13 -0
  76. data/_includes/navStructure.html +70 -0
  77. data/_includes/navbar.html +65 -0
  78. data/_includes/outputs.html +74 -0
  79. data/_includes/partners.html +75 -0
  80. data/_includes/profile.html +67 -0
  81. data/_includes/publications/faculty.md +13 -0
  82. data/_includes/publications/instructional.md +5 -0
  83. data/_includes/publications/participant.md +33 -0
  84. data/_includes/talk.html +12 -0
  85. data/_includes/topTable.html +6 -0
  86. data/_includes/upcoming.html +43 -0
  87. data/_layouts/clinic.liquid +43 -0
  88. data/_layouts/example.liquid +601 -0
  89. data/_layouts/main.liquid +34 -0
  90. data/_layouts/medph.page.liquid +60 -0
  91. data/_layouts/page.liquid +41 -0
  92. data/_layouts/people.page.liquid +27 -0
  93. data/_layouts/profile.liquid +44 -0
  94. data/_layouts/redirect.liquid +15 -0
  95. data/_layouts/talk.liquid +42 -0
  96. data/assets/css/academicons.css +249 -0
  97. data/assets/css/academicons.min.css +1 -0
  98. data/assets/css/bootstrap.css +6760 -0
  99. data/assets/css/bootstrap.css.map +1 -0
  100. data/assets/css/bootstrap.min.css +6 -0
  101. data/assets/css/font-awesome.css +2086 -0
  102. data/assets/css/font-awesome.min.css +4 -0
  103. data/assets/css/ie.css +5 -0
  104. data/assets/css/main-one-page.css +6433 -0
  105. data/assets/css/main.css +7160 -0
  106. data/assets/css/my-custom-styles.css +14 -0
  107. data/assets/css/shop-main.css +3117 -0
  108. data/assets/css/skins/brown.css +299 -0
  109. data/assets/css/skins/deepskyblue.css +299 -0
  110. data/assets/css/skins/goldenrod.css +299 -0
  111. data/assets/css/skins/ici3dBlue.css +229 -0
  112. data/assets/css/skins/ici3dBlue.css.map +7 -0
  113. data/assets/css/skins/ici3dIndigo.css +229 -0
  114. data/assets/css/skins/ici3dIndigo.css.map +7 -0
  115. data/assets/css/skins/indianred.css +299 -0
  116. data/assets/css/skins/lightgreen.css +299 -0
  117. data/assets/css/skins/orange.css +299 -0
  118. data/assets/css/skins/seagreen.css +299 -0
  119. data/assets/css/skins/slategray.css +299 -0
  120. data/assets/fonts/academicons.eot +0 -0
  121. data/assets/fonts/academicons.svg +66 -0
  122. data/assets/fonts/academicons.ttf +0 -0
  123. data/assets/fonts/academicons.woff +0 -0
  124. data/assets/fonts/fontawesome-webfont.eot +0 -0
  125. data/assets/fonts/fontawesome-webfont.svg +655 -0
  126. data/assets/fonts/fontawesome-webfont.ttf +0 -0
  127. data/assets/fonts/fontawesome-webfont.woff +0 -0
  128. data/assets/fonts/fontawesome-webfont.woff2 +0 -0
  129. data/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  130. data/assets/fonts/glyphicons-halflings-regular.svg +288 -0
  131. data/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  132. data/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  133. data/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
  134. data/assets/ico/favicon.ico +0 -0
  135. data/assets/ico/favicon.png +0 -0
  136. data/assets/ico/ici3d114x114.png +0 -0
  137. data/assets/ico/ici3d144x144.png +0 -0
  138. data/assets/ico/ici3d57x57.png +0 -0
  139. data/assets/ico/ici3d72x72.png +0 -0
  140. data/assets/img/8hearts.png +0 -0
  141. data/assets/img/MMED2015_tutorials.jpg +0 -0
  142. data/assets/img/badge.png +0 -0
  143. data/assets/img/blog/balloon-med.jpg +0 -0
  144. data/assets/img/blog/balloon.jpg +0 -0
  145. data/assets/img/blog/buildings-med.jpg +0 -0
  146. data/assets/img/blog/buildings.jpg +0 -0
  147. data/assets/img/blog/people-med.jpg +0 -0
  148. data/assets/img/blog/people.jpg +0 -0
  149. data/assets/img/bx_loader.gif +0 -0
  150. data/assets/img/clients/logo1.png +0 -0
  151. data/assets/img/clients/logo2.png +0 -0
  152. data/assets/img/clients/logo3.png +0 -0
  153. data/assets/img/clients/logo4.png +0 -0
  154. data/assets/img/clients/logo5.png +0 -0
  155. data/assets/img/flags/China.png +0 -0
  156. data/assets/img/flags/Germany.png +0 -0
  157. data/assets/img/flags/Japan.png +0 -0
  158. data/assets/img/flags/South-Africa.png +0 -0
  159. data/assets/img/flags/United-Kingdom.png +0 -0
  160. data/assets/img/flags/United-States.png +0 -0
  161. data/assets/img/free.png +0 -0
  162. data/assets/img/fullscreen-bg.jpg +0 -0
  163. data/assets/img/gray_jean.png +0 -0
  164. data/assets/img/hero-unit-bg.png +0 -0
  165. data/assets/img/hero-unit-obj.png +0 -0
  166. data/assets/img/hero-unit-obj2.png +0 -0
  167. data/assets/img/hero-unit-obj3.png +0 -0
  168. data/assets/img/intro-img.png +0 -0
  169. data/assets/img/location-pin.png +0 -0
  170. data/assets/img/logo/ici3d-logo-light.png +0 -0
  171. data/assets/img/logo/ici3d-logo-nav.png +0 -0
  172. data/assets/img/logo/ici3d-logo-white.png +0 -0
  173. data/assets/img/logo/ici3d-logo-white_v2.png +0 -0
  174. data/assets/img/logo/ici3d-logo-white_v3.png +0 -0
  175. data/assets/img/logo/repute-logo-light-brown.png +0 -0
  176. data/assets/img/logo/repute-logo-light-deepskyblue.png +0 -0
  177. data/assets/img/logo/repute-logo-light-goldenrod.png +0 -0
  178. data/assets/img/logo/repute-logo-light-indianred.png +0 -0
  179. data/assets/img/logo/repute-logo-light-lightgreen.png +0 -0
  180. data/assets/img/logo/repute-logo-light-orange.png +0 -0
  181. data/assets/img/logo/repute-logo-light-seagreen.png +0 -0
  182. data/assets/img/logo/repute-logo-light-slategray.png +0 -0
  183. data/assets/img/logo/repute-logo-light.png +0 -0
  184. data/assets/img/logo/repute-logo-nav-brown.png +0 -0
  185. data/assets/img/logo/repute-logo-nav-deepskyblue.png +0 -0
  186. data/assets/img/logo/repute-logo-nav-goldenrod.png +0 -0
  187. data/assets/img/logo/repute-logo-nav-indianred.png +0 -0
  188. data/assets/img/logo/repute-logo-nav-light.png +0 -0
  189. data/assets/img/logo/repute-logo-nav-lightgreen.png +0 -0
  190. data/assets/img/logo/repute-logo-nav-orange.png +0 -0
  191. data/assets/img/logo/repute-logo-nav-seagreen.png +0 -0
  192. data/assets/img/logo/repute-logo-nav-slategray.png +0 -0
  193. data/assets/img/logo/repute-logo-nav.png +0 -0
  194. data/assets/img/mentors/are.jpg +0 -0
  195. data/assets/img/mentors/bolton.jpg +0 -0
  196. data/assets/img/mentors/brown.jpg +0 -0
  197. data/assets/img/mentors/kassanjee.jpg +0 -0
  198. data/assets/img/mentors/mhlanga.jpg +0 -0
  199. data/assets/img/mentors/nyamai.png +0 -0
  200. data/assets/img/news/featured-news.png +0 -0
  201. data/assets/img/news/news1.png +0 -0
  202. data/assets/img/news/news2.png +0 -0
  203. data/assets/img/news/news3.png +0 -0
  204. data/assets/img/news/news4.png +0 -0
  205. data/assets/img/news/news5.png +0 -0
  206. data/assets/img/other/snoep.jpg +0 -0
  207. data/assets/img/page-header-bg.png +0 -0
  208. data/assets/img/participants/SempaJB.jpg +0 -0
  209. data/assets/img/partners/AIMS-SA.jpg +0 -0
  210. data/assets/img/partners/CEMA_UN.pdf +0 -0
  211. data/assets/img/partners/CEMA_UN.png +0 -0
  212. data/assets/img/partners/CIDID.png +0 -0
  213. data/assets/img/partners/CIDID_long.png +0 -0
  214. data/assets/img/partners/Colby.png +0 -0
  215. data/assets/img/partners/MIDAS.png +0 -0
  216. data/assets/img/partners/McMaster.jpg +0 -0
  217. data/assets/img/partners/PSU.png +0 -0
  218. data/assets/img/partners/Proctor.png +0 -0
  219. data/assets/img/partners/SACEMA_228.png +0 -0
  220. data/assets/img/partners/UCSF.png +0 -0
  221. data/assets/img/partners/UF.png +0 -0
  222. data/assets/img/partners/UGA_228.png +0 -0
  223. data/assets/img/pattern-geometry.png +0 -0
  224. data/assets/img/portfolio/800x500/work1.png +0 -0
  225. data/assets/img/portfolio/800x500/work2.png +0 -0
  226. data/assets/img/portfolio/800x500/work3.png +0 -0
  227. data/assets/img/portfolio/800x500/work4.png +0 -0
  228. data/assets/img/portfolio/800x500/work5.png +0 -0
  229. data/assets/img/portfolio/800x500/work6.png +0 -0
  230. data/assets/img/portfolio/800x500/work7.png +0 -0
  231. data/assets/img/portfolio/800x500/work8.png +0 -0
  232. data/assets/img/portfolio/800x800/work1.png +0 -0
  233. data/assets/img/portfolio/800x800/work2.png +0 -0
  234. data/assets/img/portfolio/800x800/work3.png +0 -0
  235. data/assets/img/portfolio/800x800/work4.png +0 -0
  236. data/assets/img/portfolio/800x800/work5.png +0 -0
  237. data/assets/img/portfolio/800x800/work6.png +0 -0
  238. data/assets/img/portfolio/800x800/work7.png +0 -0
  239. data/assets/img/portfolio/800x800/work8.png +0 -0
  240. data/assets/img/portfolio/single/bicycle.jpg +0 -0
  241. data/assets/img/portfolio/single/blurred_lines.jpg +0 -0
  242. data/assets/img/portfolio/single/edge.jpg +0 -0
  243. data/assets/img/scholars/ackley.jpg +0 -0
  244. data/assets/img/scholars/beauclair.jpg +0 -0
  245. data/assets/img/scholars/beauclair.png +0 -0
  246. data/assets/img/scholars/bekele.jpg +0 -0
  247. data/assets/img/scholars/lord.jpg +0 -0
  248. data/assets/img/scholars/marx.jpg +0 -0
  249. data/assets/img/scholars/mcintosh.jpg +0 -0
  250. data/assets/img/scholars/mwebaze.jpg +0 -0
  251. data/assets/img/scholars/nondi.jpg +0 -0
  252. data/assets/img/scholars/sempa.jpg +0 -0
  253. data/assets/img/scholars/ying.jpg +0 -0
  254. data/assets/img/sliders/full-slide-color.jpg +0 -0
  255. data/assets/img/sliders/full-slide-color2.jpg +0 -0
  256. data/assets/img/sliders/full-slide-color3.jpg +0 -0
  257. data/assets/img/sliders/full-slide.jpg +0 -0
  258. data/assets/img/sliders/full-slide2.jpg +0 -0
  259. data/assets/img/sliders/full-slide3.jpg +0 -0
  260. data/assets/img/sliders/slider1-h500.png +0 -0
  261. data/assets/img/sliders/slider2-h500.png +0 -0
  262. data/assets/img/sliders/slider3-h500.png +0 -0
  263. data/assets/img/team/bellan.jpg +0 -0
  264. data/assets/img/team/borchering.jpg +0 -0
  265. data/assets/img/team/brook.jpg +0 -0
  266. data/assets/img/team/bruce.jpg +0 -0
  267. data/assets/img/team/deleo.jpg +0 -0
  268. data/assets/img/team/delva.jpg +0 -0
  269. data/assets/img/team/dushoff.jpg +0 -0
  270. data/assets/img/team/ervin.jpg +0 -0
  271. data/assets/img/team/grebe.jpg +0 -0
  272. data/assets/img/team/hargrove.jpg +0 -0
  273. data/assets/img/team/hitchcock.jpg +0 -0
  274. data/assets/img/team/hladish.jpg +0 -0
  275. data/assets/img/team/january.jpg +0 -0
  276. data/assets/img/team/li.jpg +0 -0
  277. data/assets/img/team/mthombothi.jpg +0 -0
  278. data/assets/img/team/mugwagwa.jpg +0 -0
  279. data/assets/img/team/mwangi.png +0 -0
  280. data/assets/img/team/ndifon.jpg +0 -0
  281. data/assets/img/team/ngonghala.jpg +0 -0
  282. data/assets/img/team/october.jpg +0 -0
  283. data/assets/img/team/paradza.jpg +0 -0
  284. data/assets/img/team/pearson.jpg +0 -0
  285. data/assets/img/team/porco.jpg +0 -0
  286. data/assets/img/team/pulliam.jpg +0 -0
  287. data/assets/img/team/reiner.jpg +0 -0
  288. data/assets/img/team/scheepers.jpg +0 -0
  289. data/assets/img/team/scott.jpg +0 -0
  290. data/assets/img/team/ujeneza.jpg +0 -0
  291. data/assets/img/team/vanschalkwyk.jpg +0 -0
  292. data/assets/img/team/welte.jpg +0 -0
  293. data/assets/img/team/williams.jpg +0 -0
  294. data/assets/img/testimonial-bg.png +0 -0
  295. data/assets/img/transmission.png +0 -0
  296. data/assets/js/bootstrap.js +2363 -0
  297. data/assets/js/bootstrap.min.js +7 -0
  298. data/assets/js/jquery-2.1.1.min.js +4 -0
  299. data/assets/js/plugins/autohidingnavbar/jquery.bootstrap-autohidingnavbar.js +213 -0
  300. data/assets/js/plugins/autohidingnavbar/jquery.bootstrap-autohidingnavbar.min.js +9 -0
  301. data/assets/js/plugins/bootstrap-datepicker/bootstrap-datepicker.js +474 -0
  302. data/assets/js/plugins/bootstrap-multiselect/bootstrap-multiselect.js +994 -0
  303. data/assets/js/plugins/daterangepicker/daterangepicker.js +868 -0
  304. data/assets/js/plugins/easing/jquery.easing.js +205 -0
  305. data/assets/js/plugins/easing/jquery.easing.min.js +71 -0
  306. data/assets/js/plugins/fitvids/jquery.fitvids.js +83 -0
  307. data/assets/js/plugins/google-map/google-map.js +160 -0
  308. data/assets/js/plugins/isotope/isotope.pkgd.js +4049 -0
  309. data/assets/js/plugins/isotope/isotope.pkgd.min.js +8 -0
  310. data/assets/js/plugins/jquery-cycle/jquery.cycle.all.js +1543 -0
  311. data/assets/js/plugins/jquery-easypiechart/jquery.easypiechart.js +359 -0
  312. data/assets/js/plugins/jquery-easypiechart/jquery.easypiechart.min.js +9 -0
  313. data/assets/js/plugins/jquery-maskedinput/jquery.masked-input.js +338 -0
  314. data/assets/js/plugins/jquery-maskedinput/jquery.masked-input.min.js +7 -0
  315. data/assets/js/plugins/maximage/jquery.maximage.js +697 -0
  316. data/assets/js/plugins/maximage/jquery.maximage.min.js +4 -0
  317. data/assets/js/plugins/moment/moment.js +1662 -0
  318. data/assets/js/plugins/moment/moment.min.js +6 -0
  319. data/assets/js/plugins/parsley-validation/parsley.js +2074 -0
  320. data/assets/js/plugins/parsley-validation/parsley.min.js +9 -0
  321. data/assets/js/plugins/scrollto/jquery.localscroll-1.2.7-min.js +9 -0
  322. data/assets/js/plugins/scrollto/jquery.localscroll-1.2.7.js +133 -0
  323. data/assets/js/plugins/scrollto/jquery.scrollTo-1.4.3.1-min.js +7 -0
  324. data/assets/js/plugins/scrollto/jquery.scrollTo-1.4.3.1.js +218 -0
  325. data/assets/js/plugins/slick/slick.js +2643 -0
  326. data/assets/js/plugins/slick/slick.min.js +18 -0
  327. data/assets/js/plugins/stellar/jquery.stellar.js +660 -0
  328. data/assets/js/plugins/stellar/jquery.stellar.min.js +2 -0
  329. data/assets/js/repute-scripts.js +539 -0
  330. 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
+ }));