rails-jquery-form-validator 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/CODE_OF_CONDUCT.md +74 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +73 -0
  7. data/Rakefile +2 -0
  8. data/lib/rails-jquery-form-validator.rb +1 -0
  9. data/lib/rails/jquery/form/validator.rb +13 -0
  10. data/lib/rails/jquery/form/validator/engine.rb +12 -0
  11. data/lib/rails/jquery/form/validator/version.rb +9 -0
  12. data/rails-jquery-form-validator.gemspec +34 -0
  13. data/vendor/assets/javascripts/brazil.js +9 -0
  14. data/vendor/assets/javascripts/date.js +9 -0
  15. data/vendor/assets/javascripts/file.js +9 -0
  16. data/vendor/assets/javascripts/html5.js +9 -0
  17. data/vendor/assets/javascripts/jquery.form-validator.js +2295 -0
  18. data/vendor/assets/javascripts/jquery.form-validator.min.js +9 -0
  19. data/vendor/assets/javascripts/jsconf.js +9 -0
  20. data/vendor/assets/javascripts/lang/ca.js +9 -0
  21. data/vendor/assets/javascripts/lang/cs.js +9 -0
  22. data/vendor/assets/javascripts/lang/da.js +9 -0
  23. data/vendor/assets/javascripts/lang/de.js +9 -0
  24. data/vendor/assets/javascripts/lang/es.js +9 -0
  25. data/vendor/assets/javascripts/lang/fa.js +9 -0
  26. data/vendor/assets/javascripts/lang/fr.js +9 -0
  27. data/vendor/assets/javascripts/lang/it.js +9 -0
  28. data/vendor/assets/javascripts/lang/nl.js +9 -0
  29. data/vendor/assets/javascripts/lang/no.js +9 -0
  30. data/vendor/assets/javascripts/lang/pl.js +9 -0
  31. data/vendor/assets/javascripts/lang/pt.js +9 -0
  32. data/vendor/assets/javascripts/lang/ro.js +9 -0
  33. data/vendor/assets/javascripts/lang/ru.js +9 -0
  34. data/vendor/assets/javascripts/lang/sv.js +9 -0
  35. data/vendor/assets/javascripts/lang/vi.js +9 -0
  36. data/vendor/assets/javascripts/location.js +9 -0
  37. data/vendor/assets/javascripts/logic.js +9 -0
  38. data/vendor/assets/javascripts/poland.js +9 -0
  39. data/vendor/assets/javascripts/sanitize.js +9 -0
  40. data/vendor/assets/javascripts/security.js +9 -0
  41. data/vendor/assets/javascripts/sepa.js +9 -0
  42. data/vendor/assets/javascripts/sweden.js +9 -0
  43. data/vendor/assets/javascripts/theme-default.css +110 -0
  44. data/vendor/assets/javascripts/theme-default.min.css +1 -0
  45. data/vendor/assets/javascripts/toggleDisabled.js +9 -0
  46. data/vendor/assets/javascripts/uk.js +9 -0
  47. metadata +129 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 50c8830bdafea1289824164750034ad33f6a7292
4
+ data.tar.gz: e67f50ec6f9e9790dc0f9ed6cd34e313d8e720fd
5
+ SHA512:
6
+ metadata.gz: 0bf62c5983d21475861500908bb27b0271318820a63737056cc417711fcb8dec57c377ad0ac3ac7baa10001a94ecf877a147a1a67fe5e1f120da5a6549da0517
7
+ data.tar.gz: 4f5e6fe99f01ca9cb877fee7debbfc733eda54db1468ca2fba1956bb2a1593e9fe03b3421f826359d81569a9c27ad08d6e6d55aa11c52dd2820e9cf39821eb2b
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.idea/
11
+ /.idea/workspace.xml
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at tanbir2025@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rails-jquery-form-validator.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 hmtanbir
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,73 @@
1
+ # Rails::Jquery::Form::Validator
2
+
3
+ Jquery-form-validator-rails gem is based on Victor Jonsson's jQuery plugin: https://github.com/victorjonsson/jQuery-Form-Validator
4
+
5
+ jQuery Form Validator is a feature rich and multilingual jQuery plugin that makes it easy to validate user input while keeping your HTML markup clean from javascript code. Even though this plugin has a wide range of validation functions it's designed to require as little network traffic as possible. This is achieved by grouping together validation functions in "modules", making it possible to load only those functions that's needed to validate a particular form.
6
+
7
+ Form demos and full documentation available at http://formvalidator.net/
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'jquery-form-validator-rails'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ ### Include jquery.form-validator-rails javascript assets
19
+
20
+ Add the following to your `app/assets/javascripts/application.js`:
21
+
22
+ //= require jquery.form-validator
23
+
24
+
25
+ ### Easy example
26
+
27
+ Example how to add Jquery Form Validator to FormHelper `text_field`:
28
+
29
+ <div class="controls">
30
+ <%= f.text_field(:example, class: "field", data: {
31
+ :validation => "required validate_max_length length50",
32
+ "validation-error-msg" => "This field is required and cannot be longer than 50 characters."
33
+ }) %>
34
+ </div>
35
+
36
+ Then add following to your `app/assets/javascripts/application.js`
37
+
38
+ <script>
39
+ $(document).ready(function() {
40
+ $.validate();
41
+ });
42
+ </script>
43
+
44
+ Other configuration options can be seen here: http://formvalidator.net/#configuration
45
+
46
+ ### Added modules:
47
+
48
+ * security
49
+ * date
50
+ * location
51
+ * file
52
+ * sweden
53
+ * uk
54
+
55
+ The following code shows you how to load the module.
56
+
57
+ <script>
58
+ $.validate({
59
+ modules : 'security'
60
+ });
61
+ </script>
62
+
63
+ Read the documentation for the modules at http://formvalidator.net
64
+
65
+ ## Contributing makes this repo happy!
66
+
67
+ Please just hop in and help out! :smile:
68
+
69
+ 1. Fork it
70
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
71
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
72
+ 4. Push to the branch (`git push origin my-new-feature`)
73
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1 @@
1
+ require 'rails/jquery/form/validator'
@@ -0,0 +1,13 @@
1
+ require 'rails/jquery/form/validator/version'
2
+ require 'rails/jquery/form/validator/version' if ::Rails.version >= '3.2'
3
+
4
+ module Rails
5
+ module Jquery
6
+ module Form
7
+ module Validator
8
+ module Rails
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module Rails
2
+ module Jquery
3
+ module Form
4
+ module Validator
5
+ module Rails
6
+ class Engine < ::Rails::Engine
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module Rails
2
+ module Jquery
3
+ module Form
4
+ module Validator
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'rails/jquery/form/validator/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "rails-jquery-form-validator"
9
+ spec.version = Rails::Jquery::Form::Validator::VERSION
10
+ spec.authors = ["hmtanbir"]
11
+ spec.email = ["tanbir2025@gmail.com"]
12
+
13
+ spec.summary = %q{Integrate the jQuery Form Validator plugin into the Rails asset pipeline}
14
+ spec.description = %q{ jQuery Form Validator is a feature rich jQuery plugin that makes it easy to validate user input while keeping your HTML markup clean from javascript code. Even though this plugin has a wide range of validation functions it's designed to require as little jQuery bandwidth as possible. This is achieved by grouping together validation functions in 'modules', making it possible for the programmer to load only }
15
+ spec.homepage = "https://github.com/bdmade/rails-jquery-form-validator"
16
+ spec.license = "MIT"
17
+
18
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
19
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
20
+ if spec.respond_to?(:metadata)
21
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
22
+ else
23
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
24
+ end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_development_dependency "bundler", "~> 1.12"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+
34
+ end
@@ -0,0 +1,9 @@
1
+ /** File generated by Grunt -- do not modify
2
+ * JQUERY-FORM-VALIDATOR
3
+ *
4
+ * @version 2.3.55
5
+ * @website http://formvalidator.net/
6
+ * @author Victor Jonsson, http://victorjonsson.se
7
+ * @license MIT
8
+ */
9
+ !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){$.formUtils.addValidator({name:"cpf",validatorFunction:function(a){var b=a.replace(/\D/g,""),c=0,d=0,e=0,f=0;if(11!==b.length||"00000000000"===b)return!1;for(i=1;i<=9;i++)c+=parseInt(b.substring(i-1,i))*(11-i);if(e=10*c%11,e>=10&&(e=0),e!==parseInt(b.substring(9,10)))return!1;for(i=1;i<=10;i++)d+=parseInt(b.substring(i-1,i))*(12-i);return f=10*d%11,f>=10&&(f=0),f===parseInt(b.substring(10,11))},errorMessage:"",errorMessageKey:"badBrazilCPFAnswer"}),$.formUtils.addValidator({name:"brphone",validatorFunction:function(a){return!!a.match(/^(\+[\d]{1,3}[\s]{0,1}){0,1}(\(){0,1}(\d){2}(\)){0,1}(\s){0,1}(\d){4,5}([-. ]){0,1}(\d){4}$/g)},errorMessage:"",errorMessageKey:"badBrazilTelephoneAnswer"}),$.formUtils.addValidator({name:"cep",validatorFunction:function(a){return!!a.match(/^(\d){5}([-. ]){0,1}(\d){3}$/g)},errorMessage:"",errorMessageKey:"badBrazilCEPAnswer"})});
@@ -0,0 +1,9 @@
1
+ /** File generated by Grunt -- do not modify
2
+ * JQUERY-FORM-VALIDATOR
3
+ *
4
+ * @version 2.3.55
5
+ * @website http://formvalidator.net/
6
+ * @author Victor Jonsson, http://victorjonsson.se
7
+ * @license MIT
8
+ */
9
+ !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){!function(a){a.formUtils.addValidator({name:"time",validatorFunction:function(a){if(null===a.match(/^(\d{2}):(\d{2})$/))return!1;var b=parseInt(a.split(":")[0],10),c=parseInt(a.split(":")[1],10);return!(b>23||c>59)},errorMessage:"",errorMessageKey:"badTime"}),a.formUtils.addValidator({name:"birthdate",validatorFunction:function(b,c,d){var e="yyyy-mm-dd";c.valAttr("format")?e=c.valAttr("format"):"undefined"!=typeof d.dateFormat&&(e=d.dateFormat);var f=a.formUtils.parseDate(b,e);if(!f)return!1;var g=new Date,h=g.getFullYear(),i=f[0],j=f[1],k=f[2];if(i===h){var l=g.getMonth()+1;if(j===l){var m=g.getDate();return k<=m}return j<l}return i<h&&i>h-124},errorMessage:"",errorMessageKey:"badDate"})}(a)});
@@ -0,0 +1,9 @@
1
+ /** File generated by Grunt -- do not modify
2
+ * JQUERY-FORM-VALIDATOR
3
+ *
4
+ * @version 2.3.55
5
+ * @website http://formvalidator.net/
6
+ * @author Victor Jonsson, http://victorjonsson.se
7
+ * @license MIT
8
+ */
9
+ !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){!function(a,b){"use strict";var c="undefined"!=typeof b.FileReader,d=function(b){var c=a.split((b.valAttr("allowing")||"").toLowerCase());return a.inArray("jpg",c)>-1&&a.inArray("jpeg",c)===-1?c.push("jpeg"):a.inArray("jpeg",c)>-1&&a.inArray("jpg",c)===-1&&c.push("jpg"),c},e=function(a,b,c,d){var e=d[b]||"";a.errorMessageKey="",a.errorMessage=e.replace("%s",c)},f=function(c,d,e){var f=new FileReader,g=new Image;f.readAsDataURL(c),f.onload=function(c){g.onload=function(){a(b).trigger("imageValidation",[this]),d(this)},g.onerror=function(){e()},g.src=c.target.result}};a.formUtils.addValidator({name:"mime",validatorFunction:function(b,f,g,h){if(c){var i=!0,j=f.get(0).files||[],k="",l=d(f);return j.length&&(a.each(j,function(b,c){return i=!1,k=c.type||c.name.substring(c.name.lastIndexOf(".")+1),a.each(l,function(a,b){if(i=k.indexOf(b)>-1)return!1}),i}),i||(a.formUtils.warn("Trying to upload a file with mime type "+k+" which is not allowed"),e(this,"wrongFileType",l.join(", "),h))),i}return a.formUtils.warn("FileReader not supported by browser, will check file extension"),a.formUtils.validators.validate_extension.validatorFunction(b,f,g,h)},errorMessage:"",errorMessageKey:"wrongFileType"}),a.formUtils.addValidator({name:"extension",validatorFunction:function(b,c,f,g){var h=!0,i=this,j=d(c);return a.each(c.get(0).files||[b],function(b,c){var d="string"==typeof c?c:c.value||c.fileName||c.name,f=d.substr(d.lastIndexOf(".")+1);if(a.inArray(f.toLowerCase(),j)===-1)return h=!1,e(i,"wrongFileType",j.join(", "),g),!1}),h},errorMessage:"",errorMessageKey:"wrongFileType"}),a.formUtils.addValidator({name:"size",validatorFunction:function(b,d,f,g){var h=d.valAttr("max-size");if(!h)return a.formUtils.warn('Input "'+d.attr("name")+'" is missing data-validation-max-size attribute'),!0;if(!c)return!0;var i=a.formUtils.convertSizeNameToBytes(h),j=!0;return a.each(d.get(0).files||[],function(a,b){return j=b.size<=i}),j||e(this,"wrongFileSize",h,g),j},errorMessage:"",errorMessageKey:"wrongFileSize"}),a.formUtils.convertSizeNameToBytes=function(a){return a=a.toUpperCase(),"M"===a.substr(a.length-1,1)?1024*parseInt(a.substr(0,a.length-1),10)*1024:"MB"===a.substr(a.length-2,2)?1024*parseInt(a.substr(0,a.length-2),10)*1024:"KB"===a.substr(a.length-2,2)?1024*parseInt(a.substr(0,a.length-2),10):"B"===a.substr(a.length-1,1)?parseInt(a.substr(0,a.length-1),10):parseInt(a,10)},a.formUtils.checkImageDimension=function(a,b,c){var d=!1,e={width:0,height:0},f=function(a){a=a.replace("min","").replace("max","");var b=a.split("x");e.width=b[0],e.height=b[1]?b[1]:b[0]},g=!1,h=!1,i=b.split("-");return 1===i.length?0===i[0].indexOf("min")?g=i[0]:h=i[0]:(g=i[0],h=i[1]),g&&(f(g),(a.width<e.width||a.height<e.height)&&(d=c.imageTooSmall+" ("+c.min+" "+e.width+"x"+e.height+"px)")),!d&&h&&(f(h),(a.width>e.width||a.height>e.height)&&(d=a.width>e.width?c.imageTooWide+" "+e.width+"px":c.imageTooTall+" "+e.height+"px",d+=" ("+c.max+" "+e.width+"x"+e.height+"px)")),d},a.formUtils.checkImageRatio=function(a,b,c){var d=a.width/a.height,e=function(a){var b=a.replace("max","").replace("min","").split(":");return b[0]/b[1]},f=b.split("-"),g=function(a,b,c){return a>=b&&a<=c};if(1===f.length){if(d!==e(f[0]))return c.imageRatioNotAccepted}else if(2===f.length&&!g(d,e(f[0]),e(f[1])))return c.imageRatioNotAccepted;return!1},a.formUtils.addValidator({name:"dimension",validatorFunction:function(b,d,e,g,h,i){if(c){var j=this,k=a.formUtils.asyncValidation(this.name,d,h);return k.run(i,function(b){var c=d.get(0).files||[];d.attr("data-validation").indexOf("mime")===-1?(alert("You should validate file type being jpg, gif or png on input "+d[0].name),b(!1)):c.length>1?(alert("Validating image dimensions does not support inputs allowing multiple files"),b(!1)):0===c.length?b(!0):f(c[0],function(c){var e=!1;d.valAttr("dimension")&&(e=a.formUtils.checkImageDimension(c,d.valAttr("dimension"),g)),!e&&d.valAttr("ratio")&&(e=a.formUtils.checkImageRatio(c,d.valAttr("ratio"),g)),e?(j.errorMessage=g.wrongFileDim+" "+d.valAttr("has-not-valid-dim"),b(!1)):b(!0)},function(a){throw a})})}return!0},errorMessage:"",errorMessageKey:""}),a(b).one("validatorsLoaded formValidationSetup",function(b,c,d){var e;e=c?c.find('input[type="file"]'):a('input[type="file"]'),a.formUtils.dialogs.removeInputStylingAndMessage(e,d)})}(a,window)});
@@ -0,0 +1,9 @@
1
+ /** File generated by Grunt -- do not modify
2
+ * JQUERY-FORM-VALIDATOR
3
+ *
4
+ * @version 2.3.55
5
+ * @website http://formvalidator.net/
6
+ * @author Victor Jonsson, http://victorjonsson.se
7
+ * @license MIT
8
+ */
9
+ !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){!function(a){"use strict";var b="placeholder"in document.createElement("INPUT"),c="options"in document.createElement("DATALIST"),d=!1,e=function(e){e.each(function(){var e=a(this),f=e.find("input,textarea,select"),g=!1;f.each(function(){var b=[],e=a(this),f=e.attr("required"),h={};switch(f&&b.push("required"),(e.attr("type")||"").toLowerCase()){case"time":b.push("time"),a.formUtils.validators.validate_date||d||(d=!0,a.formUtils.loadModules("date"));break;case"url":b.push("url");break;case"email":b.push("email");break;case"date":b.push("date");break;case"number":b.push("number");var i=e.attr("max"),j=e.attr("min"),k=e.attr("step");j||i?(j||(j="0"),i||(i="9007199254740992"),k||(k="1"),h["data-validation-allowing"]="range["+j+";"+i+"]",0!==j.indexOf("-")&&0!==i.indexOf("-")||(h["data-validation-allowing"]+=",negative"),(j.indexOf(".")>-1||i.indexOf(".")>-1||k.indexOf(".")>-1)&&(h["data-validation-allowing"]+=",float")):h["data-validation-allowing"]+=",float,negative"}if(e.attr("pattern")&&(b.push("custom"),h["data-validation-regexp"]=e.attr("pattern")),e.attr("maxlength")&&(b.push("length"),h["data-validation-length"]="max"+e.attr("maxlength")),!c&&e.attr("list")){var l=[],m=a("#"+e.attr("list"));if(m.find("option").each(function(){l.push(a(this).text())}),0===l.length){var n=a.trim(a("#"+e.attr("list")).text()).split("\n");a.each(n,function(b,c){l.push(a.trim(c))})}m.remove(),a.formUtils.suggest(e,l)}if(b.length){f||(h["data-validation-optional"]="true"),g=!0;var o=(e.attr("data-validation")||"")+" "+b.join(" ");e.attr("data-validation",a.trim(o)),a.each(h,function(a,b){e.attr(a,b)})}}),g&&e.trigger("html5ValidationAttrsFound"),b||f.filter("input[placeholder]").each(function(){this.__defaultValue=this.getAttribute("placeholder"),a(this).bind("focus",function(){this.value===this.__defaultValue&&(this.value="",a(this).removeClass("showing-placeholder"))}).bind("blur",function(){""===a.trim(this.value)&&(this.value=this.__defaultValue,a(this).addClass("showing-placeholder"))})})})};a.formUtils.$win.bind("validatorsLoaded formValidationSetup",function(b,c){c||(c=a("form")),e(c)}),a.formUtils.setupValidationUsingHTML5Attr=e}(a,window)});
@@ -0,0 +1,2295 @@
1
+ (function (root, factory) {
2
+ if (typeof define === 'function' && define.amd) {
3
+ // AMD. Register as an anonymous module unless amdModuleId is set
4
+ define(["jquery"], function (a0) {
5
+ return (factory(a0));
6
+ });
7
+ } else if (typeof exports === 'object') {
8
+ // Node. Does not work with strict CommonJS, but
9
+ // only CommonJS-like environments that support module.exports,
10
+ // like Node.
11
+ module.exports = factory(require("jquery"));
12
+ } else {
13
+ factory(jQuery);
14
+ }
15
+ }(this, function (jQuery) {
16
+
17
+ /** File generated by Grunt -- do not modify
18
+ * JQUERY-FORM-VALIDATOR
19
+ *
20
+ * @version 2.3.55
21
+ * @website http://formvalidator.net/
22
+ * @author Victor Jonsson, http://victorjonsson.se
23
+ * @license MIT
24
+ */
25
+ /**
26
+ */
27
+ (function ($, undefined) {
28
+
29
+ var disableFormSubmit = function () {
30
+ return false;
31
+ },
32
+ HaltManager = {
33
+ numHalted: 0,
34
+ haltValidation: function($form) {
35
+ this.numHalted++;
36
+ $.formUtils.haltValidation = true;
37
+ $form
38
+ .unbind('submit', disableFormSubmit)
39
+ .bind('submit', disableFormSubmit)
40
+ .find('*[type="submit"]')
41
+ .addClass('disabled')
42
+ .attr('disabled', 'disabled');
43
+ },
44
+ unHaltValidation: function($form) {
45
+ this.numHalted--;
46
+ if (this.numHalted === 0) {
47
+ $.formUtils.haltValidation = false;
48
+ $form
49
+ .unbind('submit', disableFormSubmit)
50
+ .find('*[type="submit"]')
51
+ .removeClass('disabled')
52
+ .removeAttr('disabled', 'disabled');
53
+ }
54
+ }
55
+ };
56
+
57
+ function AsyncValidation($form, $input) {
58
+ this.$form = $form;
59
+ this.$input = $input;
60
+ this.reset();
61
+ $input.on('change paste', this.reset.bind(this));
62
+ }
63
+
64
+ AsyncValidation.prototype.reset = function() {
65
+ this.haltedFormValidation = false;
66
+ this.hasRun = false;
67
+ this.isRunning = false;
68
+ this.result = undefined;
69
+ };
70
+
71
+ AsyncValidation.prototype.run = function(eventContext, callback) {
72
+ if (eventContext === 'keyup') {
73
+ return null;
74
+ } else if (this.isRunning) {
75
+ if (!this.haltedFormValidation && eventContext === 'submit') {
76
+ HaltManager.haltValidation();
77
+ this.haltedFormValidation = true;
78
+ }
79
+ return null; // Waiting for result
80
+ } else if(this.hasRun) {
81
+ //this.$input.one('keyup change paste', this.reset.bind(this));
82
+ return this.result;
83
+ } else {
84
+ if (eventContext === 'submit') {
85
+ HaltManager.haltValidation(this.$form);
86
+ this.haltedFormValidation = true;
87
+ }
88
+ this.isRunning = true;
89
+ this.$input
90
+ .attr('disabled', 'disabled')
91
+ .addClass('async-validation');
92
+ this.$form.addClass('async-validation');
93
+
94
+ callback(function(result) {
95
+ this.done(result);
96
+ }.bind(this));
97
+
98
+ return null;
99
+ }
100
+ };
101
+
102
+ AsyncValidation.prototype.done = function(result) {
103
+ this.result = result;
104
+ this.hasRun = true;
105
+ this.isRunning = false;
106
+ this.$input
107
+ .removeAttr('disabled')
108
+ .removeClass('async-validation');
109
+ this.$form.removeClass('async-validation');
110
+ if (this.haltedFormValidation) {
111
+ HaltManager.unHaltValidation(this.$form);
112
+ this.$form.trigger('submit');
113
+ } else {
114
+ this.$input.trigger('validation.revalidate');
115
+ }
116
+ };
117
+
118
+ $.formUtils = $.extend($.formUtils || {}, {
119
+ asyncValidation: function(validatorName, $input, $form) {
120
+ // Return async validator attached to this input element
121
+ // or create a new async validator and attach it to the input
122
+ var asyncValidation,
123
+ input = $input.get(0);
124
+
125
+ if (!input.asyncValidators) {
126
+ input.asyncValidators = {};
127
+ }
128
+
129
+ if (input.asyncValidators[validatorName]) {
130
+ asyncValidation = input.asyncValidators[validatorName];
131
+ } else {
132
+ asyncValidation = new AsyncValidation($form, $input);
133
+ input.asyncValidators[validatorName] = asyncValidation;
134
+ }
135
+
136
+ return asyncValidation;
137
+ }
138
+ });
139
+
140
+ })(jQuery);
141
+
142
+ /**
143
+ * Deprecated functions and attributes
144
+ * @todo: Remove in release of 3.0
145
+ */
146
+ (function ($, undefined) {
147
+
148
+ 'use strict';
149
+
150
+ /**
151
+ * @deprecated
152
+ * @param language
153
+ * @param conf
154
+ */
155
+ $.fn.validateForm = function (language, conf) {
156
+ $.formUtils.warn('Use of deprecated function $.validateForm, use $.isValid instead');
157
+ return this.isValid(language, conf, true);
158
+ };
159
+
160
+ $(window)
161
+ .on('formValidationPluginInit', function(evt, config) {
162
+ convertDeprecatedLangCodeToISO6391(config);
163
+ addSupportForCustomErrorMessageCallback(config);
164
+ addSupportForElementReferenceInPositionParam(config);
165
+ })
166
+ .on('validatorsLoaded formValidationSetup', function(evt, $form) {
167
+ if( !$form ) {
168
+ $form = $('form');
169
+ }
170
+ addSupportForValidationDependingOnCheckedInput($form);
171
+ });
172
+
173
+
174
+ function addSupportForCustomErrorMessageCallback(config) {
175
+ if (config &&
176
+ config.errorMessagePosition === 'custom' &&
177
+ typeof config.errorMessageCustom === 'function') {
178
+
179
+ $.formUtils.warn('Use of deprecated function errorMessageCustom, use config.submitErrorMessageCallback instead');
180
+
181
+ config.submitErrorMessageCallback = function($form, errorMessages) {
182
+ config.errorMessageCustom(
183
+ $form,
184
+ config.language.errorTitle,
185
+ errorMessages,
186
+ config
187
+ );
188
+ };
189
+ }
190
+ }
191
+
192
+ function addSupportForElementReferenceInPositionParam(config) {
193
+ if (config.errorMessagePosition && typeof config.errorMessagePosition === 'object') {
194
+ $.formUtils.warn('Deprecated use of config parameter errorMessagePosition, use config.submitErrorMessageCallback instead');
195
+ var $errorMessageContainer = config.errorMessagePosition;
196
+ config.errorMessagePosition = 'top';
197
+ config.submitErrorMessageCallback = function() {
198
+ return $errorMessageContainer;
199
+ };
200
+ }
201
+ }
202
+
203
+ function addSupportForValidationDependingOnCheckedInput($form) {
204
+ var $inputsDependingOnCheckedInputs = $form.find('[data-validation-if-checked]');
205
+ if ($inputsDependingOnCheckedInputs.length) {
206
+ $.formUtils.warn(
207
+ 'Detected use of attribute "data-validation-if-checked" which is '+
208
+ 'deprecated. Use "data-validation-depends-on" provided by module "logic"'
209
+ );
210
+ }
211
+
212
+ $inputsDependingOnCheckedInputs
213
+ .on('beforeValidation', function() {
214
+
215
+ var $elem = $(this),
216
+ nameOfDependingInput = $elem.valAttr('if-checked');
217
+
218
+ // Set the boolean telling us that the validation depends
219
+ // on another input being checked
220
+ var $dependingInput = $('input[name="' + nameOfDependingInput + '"]', $form),
221
+ dependingInputIsChecked = $dependingInput.is(':checked'),
222
+ valueOfDependingInput = ($.formUtils.getValue($dependingInput) || '').toString(),
223
+ requiredValueOfDependingInput = $elem.valAttr('if-checked-value');
224
+
225
+ if (!dependingInputIsChecked || !(
226
+ !requiredValueOfDependingInput ||
227
+ requiredValueOfDependingInput === valueOfDependingInput
228
+ )) {
229
+ $elem.valAttr('skipped', true);
230
+ }
231
+
232
+ });
233
+ }
234
+
235
+ function convertDeprecatedLangCodeToISO6391(config) {
236
+ var deprecatedLangCodes = {
237
+ se: 'sv',
238
+ cz: 'cs',
239
+ dk: 'da'
240
+ };
241
+
242
+ if (config.lang in deprecatedLangCodes) {
243
+ var newLangCode = deprecatedLangCodes[config.lang];
244
+ $.formUtils.warn(
245
+ 'Deprecated use of lang code "'+config.lang+'" use "'+newLangCode+'" instead'
246
+ );
247
+ config.lang = newLangCode;
248
+ }
249
+ }
250
+
251
+ })(jQuery);
252
+
253
+ /**
254
+ * Utility methods used for displaying error messages (attached to $.formUtils)
255
+ */
256
+ (function ($) {
257
+
258
+ 'use strict';
259
+
260
+ var dialogs = {
261
+
262
+ resolveErrorMessage: function($elem, validator, validatorName, conf, language) {
263
+ var errorMsgAttr = conf.validationErrorMsgAttribute + '-' + validatorName.replace('validate_', ''),
264
+ validationErrorMsg = $elem.attr(errorMsgAttr);
265
+
266
+ if (!validationErrorMsg) {
267
+ validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute);
268
+ if (!validationErrorMsg) {
269
+ if (typeof validator.errorMessageKey !== 'function') {
270
+ validationErrorMsg = language[validator.errorMessageKey];
271
+ }
272
+ else {
273
+ validationErrorMsg = language[validator.errorMessageKey(conf)];
274
+ }
275
+ if (!validationErrorMsg) {
276
+ validationErrorMsg = validator.errorMessage;
277
+ }
278
+ }
279
+ }
280
+ return validationErrorMsg;
281
+ },
282
+ getParentContainer: function ($elem) {
283
+ if ($elem.valAttr('error-msg-container')) {
284
+ return $($elem.valAttr('error-msg-container'));
285
+ } else {
286
+ var $parent = $elem.parent();
287
+ if (!$parent.hasClass('form-group') && !$parent.closest('form').hasClass('form-horizontal')) {
288
+ var $formGroup = $parent.closest('.form-group');
289
+ if ($formGroup.length) {
290
+ return $formGroup.eq(0);
291
+ }
292
+ }
293
+ if ($parent.hasClass("input-group")) {
294
+ return $parent.parent();
295
+ }
296
+ return $parent;
297
+ }
298
+ },
299
+ applyInputErrorStyling: function ($input, conf) {
300
+ $input
301
+ .addClass(conf.errorElementClass)
302
+ .removeClass(conf.successElementClass);
303
+
304
+ this.getParentContainer($input)
305
+ .addClass(conf.inputParentClassOnError)
306
+ .removeClass(conf.inputParentClassOnSuccess);
307
+
308
+ if (conf.borderColorOnError !== '') {
309
+ $input.css('border-color', conf.borderColorOnError);
310
+ }
311
+ },
312
+ applyInputSuccessStyling: function($input, conf) {
313
+ $input.addClass('valid');
314
+ this.getParentContainer($input)
315
+ .addClass(conf.inputParentClassOnSuccess);
316
+ },
317
+ removeInputStylingAndMessage: function($input, conf) {
318
+
319
+ // Reset input css
320
+ $input
321
+ .removeClass(conf.successElementClass)
322
+ .removeClass(conf.errorElementClass)
323
+ .css('border-color', '');
324
+
325
+ var $parentContainer = dialogs.getParentContainer($input);
326
+
327
+ // Reset parent css
328
+ $parentContainer
329
+ .removeClass(conf.inputParentClassOnError)
330
+ .removeClass(conf.inputParentClassOnSuccess);
331
+
332
+ // Remove possible error message
333
+ if (typeof conf.inlineErrorMessageCallback === 'function') {
334
+ var $errorMessage = conf.inlineErrorMessageCallback($input, false, conf);
335
+ if ($errorMessage) {
336
+ $errorMessage.html('');
337
+ }
338
+ } else {
339
+ $parentContainer
340
+ .find('.' + conf.errorMessageClass)
341
+ .remove();
342
+ }
343
+
344
+ },
345
+ removeAllMessagesAndStyling: function($form, conf) {
346
+
347
+ // Remove error messages in top of form
348
+ if (typeof conf.submitErrorMessageCallback === 'function') {
349
+ var $errorMessagesInTopOfForm = conf.submitErrorMessageCallback($form, false, conf);
350
+ if ($errorMessagesInTopOfForm) {
351
+ $errorMessagesInTopOfForm.html('');
352
+ }
353
+ } else {
354
+ $form.find('.' + conf.errorMessageClass + '.alert').remove();
355
+ }
356
+
357
+ // Remove input css/messages
358
+ $form.find('.' + conf.errorElementClass + ',.' + conf.successElementClass).each(function() {
359
+ dialogs.removeInputStylingAndMessage($(this), conf);
360
+ });
361
+ },
362
+ setInlineMessage: function ($input, errorMsg, conf) {
363
+
364
+ this.applyInputErrorStyling($input, conf);
365
+
366
+ var custom = document.getElementById($input.attr('name') + '_err_msg'),
367
+ $messageContainer = false,
368
+ setErrorMessage = function ($elem) {
369
+ $.formUtils.$win.trigger('validationErrorDisplay', [$input, $elem]);
370
+ $elem.html(errorMsg);
371
+ },
372
+ addErrorToMessageContainer = function() {
373
+ var $found = false;
374
+ $messageContainer.find('.' + conf.errorMessageClass).each(function () {
375
+ if (this.inputReferer === $input[0]) {
376
+ $found = $(this);
377
+ return false;
378
+ }
379
+ });
380
+ if ($found) {
381
+ if (!errorMsg) {
382
+ $found.remove();
383
+ } else {
384
+ setErrorMessage($found);
385
+ }
386
+ } else if(errorMsg !== '') {
387
+ $message = $('<div class="' + conf.errorMessageClass + ' alert"></div>');
388
+ setErrorMessage($message);
389
+ $message[0].inputReferer = $input[0];
390
+ $messageContainer.prepend($message);
391
+ }
392
+ },
393
+ $message;
394
+
395
+ if (custom) {
396
+ // Todo: remove in 3.0
397
+ $.formUtils.warn('Using deprecated element reference ' + custom.id);
398
+ $messageContainer = $(custom);
399
+ addErrorToMessageContainer();
400
+ } else if (typeof conf.inlineErrorMessageCallback === 'function') {
401
+ $messageContainer = conf.inlineErrorMessageCallback($input, errorMsg, conf);
402
+ if (!$messageContainer) {
403
+ // Error display taken care of by inlineErrorMessageCallback
404
+ return;
405
+ }
406
+ addErrorToMessageContainer();
407
+ } else {
408
+ var $parent = this.getParentContainer($input);
409
+ $message = $parent.find('.' + conf.errorMessageClass + '.help-block');
410
+ if ($message.length === 0) {
411
+ $message = $('<span></span>').addClass('help-block').addClass(conf.errorMessageClass);
412
+ $message.appendTo($parent);
413
+ }
414
+ setErrorMessage($message);
415
+ }
416
+ },
417
+ setMessageInTopOfForm: function ($form, errorMessages, conf, lang) {
418
+ var view = '<div class="{errorMessageClass} alert alert-danger">'+
419
+ '<strong>{errorTitle}</strong>'+
420
+ '<ul>{fields}</ul>'+
421
+ '</div>',
422
+ $container = false;
423
+
424
+ if (typeof conf.submitErrorMessageCallback === 'function') {
425
+ $container = conf.submitErrorMessageCallback($form, errorMessages, conf);
426
+ if (!$container) {
427
+ // message display taken care of by callback
428
+ return;
429
+ }
430
+ }
431
+
432
+ var viewParams = {
433
+ errorTitle: lang.errorTitle,
434
+ fields: '',
435
+ errorMessageClass: conf.errorMessageClass
436
+ };
437
+
438
+ $.each(errorMessages, function (i, msg) {
439
+ viewParams.fields += '<li>'+msg+'</li>';
440
+ });
441
+
442
+ $.each(viewParams, function(param, value) {
443
+ view = view.replace('{'+param+'}', value);
444
+ });
445
+
446
+ if ($container) {
447
+ $container.html(view);
448
+ } else {
449
+ $form.children().eq(0).before($(view));
450
+ }
451
+ }
452
+ };
453
+
454
+ $.formUtils = $.extend($.formUtils || {}, {
455
+ dialogs: dialogs
456
+ });
457
+
458
+ })(jQuery);
459
+
460
+ /**
461
+ * File declaring all methods if this plugin which is applied to $.fn.
462
+ */
463
+ (function($, window, undefined) {
464
+
465
+ 'use strict';
466
+
467
+ var _helpers = 0;
468
+
469
+
470
+ /**
471
+ * Assigns validateInputOnBlur function to elements blur event
472
+ *
473
+ * @param {Object} language Optional, will override $.formUtils.LANG
474
+ * @param {Object} conf Optional, will override the default settings
475
+ * @return {jQuery}
476
+ */
477
+ $.fn.validateOnBlur = function (language, conf) {
478
+ var $form = this,
479
+ $elems = this.find('*[data-validation]');
480
+
481
+ $elems.each(function(){
482
+ var $this = $(this);
483
+ if ($this.is('[type=radio]')){
484
+ var $additionals = $form.find('[type=radio][name="' + $this.attr('name') + '"]');
485
+ $additionals.bind('blur.validation', function(){
486
+ $this.validateInputOnBlur(language, conf, true, 'blur');
487
+ });
488
+ if (conf.validateCheckboxRadioOnClick) {
489
+ $additionals.bind('click.validation', function () {
490
+ $this.validateInputOnBlur(language, conf, true, 'click');
491
+ });
492
+ }
493
+ }
494
+ });
495
+
496
+ $elems.bind('blur.validation', function () {
497
+ $(this).validateInputOnBlur(language, conf, true, 'blur');
498
+ });
499
+
500
+ if (conf.validateCheckboxRadioOnClick) {
501
+ // bind click event to validate on click for radio & checkboxes for nice UX
502
+ this.find('input[type=checkbox][data-validation],input[type=radio][data-validation]')
503
+ .bind('click.validation', function () {
504
+ $(this).validateInputOnBlur(language, conf, true, 'click');
505
+ });
506
+ }
507
+
508
+ return this;
509
+ };
510
+
511
+ /*
512
+ * Assigns validateInputOnBlur function to elements custom event
513
+ * @param {Object} language Optional, will override $.formUtils.LANG
514
+ * @param {Object} settings Optional, will override the default settings
515
+ * * @return {jQuery}
516
+ */
517
+ $.fn.validateOnEvent = function (language, config) {
518
+ var $elements = this[0].nodeName === 'FORM' ? this.find('*[data-validation-event]') : this;
519
+ $elements
520
+ .each(function () {
521
+ var $el = $(this),
522
+ etype = $el.valAttr('event');
523
+ if (etype) {
524
+ $el
525
+ .unbind(etype + '.validation')
526
+ .bind(etype + '.validation', function (evt) {
527
+ if( (evt || {}).keyCode !== 9 ) {
528
+ $(this).validateInputOnBlur(language, config, true, etype);
529
+ }
530
+ });
531
+ }
532
+ });
533
+ return this;
534
+ };
535
+
536
+ /**
537
+ * fade in help message when input gains focus
538
+ * fade out when input loses focus
539
+ * <input data-help="The info that I want to display for the user when input is focused" ... />
540
+ *
541
+ * @param {String} attrName - Optional, default is data-help
542
+ * @return {jQuery}
543
+ */
544
+ $.fn.showHelpOnFocus = function (attrName) {
545
+ if (!attrName) {
546
+ attrName = 'data-validation-help';
547
+ }
548
+
549
+ // Add help text listeners
550
+ this.find('textarea,input').each(function () {
551
+ var $elem = $(this),
552
+ className = 'jquery_form_help_' + (++_helpers),
553
+ help = $elem.attr(attrName);
554
+
555
+ // Reset
556
+ $elem
557
+ .removeClass('has-help-text')
558
+ .unbind('focus.help')
559
+ .unbind('blur.help');
560
+
561
+ if (help) {
562
+ $elem
563
+ .addClass('has-help-txt')
564
+ .bind('focus.help', function () {
565
+ var $help = $elem.parent().find('.' + className);
566
+ if ($help.length === 0) {
567
+ $help = $('<span />')
568
+ .addClass(className)
569
+ .addClass('help')
570
+ .addClass('help-block') // twitter bs
571
+ .text(help)
572
+ .hide();
573
+
574
+ $elem.after($help);
575
+ }
576
+ $help.fadeIn();
577
+ })
578
+ .bind('blur.help', function () {
579
+ $(this)
580
+ .parent()
581
+ .find('.' + className)
582
+ .fadeOut('slow');
583
+ });
584
+ }
585
+ });
586
+
587
+ return this;
588
+ };
589
+
590
+ /**
591
+ * @param {Function} cb
592
+ * @param {Object} [conf]
593
+ * @param {Object} [lang]
594
+ */
595
+ $.fn.validate = function(cb, conf, lang) {
596
+ var language = $.extend({}, $.formUtils.LANG, lang || {});
597
+ this.each(function() {
598
+ var $elem = $(this),
599
+ $closestForm = $elem.closest('form').get(0) || {},
600
+ formDefaultConfig = $closestForm.validationConfig || {};
601
+
602
+ $elem.one('validation', function(evt, isValid) {
603
+ if ( typeof cb === 'function' ) {
604
+ cb(isValid, this, evt);
605
+ }
606
+ });
607
+
608
+ $elem.validateInputOnBlur(
609
+ language,
610
+ $.extend({}, formDefaultConfig, conf || {}),
611
+ true
612
+ );
613
+ });
614
+ };
615
+
616
+ /**
617
+ * Tells whether or not validation of this input will have to postpone the form submit ()
618
+ * @returns {Boolean}
619
+ */
620
+ $.fn.willPostponeValidation = function() {
621
+ return (this.valAttr('suggestion-nr') ||
622
+ this.valAttr('postpone') ||
623
+ this.hasClass('hasDatepicker')) &&
624
+ !window.postponedValidation;
625
+ };
626
+
627
+ /**
628
+ * Validate single input when it loses focus
629
+ * shows error message in a span element
630
+ * that is appended to the parent element
631
+ *
632
+ * @param {Object} [language] Optional, will override $.formUtils.LANG
633
+ * @param {Object} [conf] Optional, will override the default settings
634
+ * @param {Boolean} attachKeyupEvent Optional
635
+ * @param {String} eventContext
636
+ * @return {jQuery}
637
+ */
638
+ $.fn.validateInputOnBlur = function (language, conf, attachKeyupEvent, eventContext) {
639
+
640
+ $.formUtils.eventType = eventContext;
641
+
642
+ if ( this.willPostponeValidation() ) {
643
+ // This validation has to be postponed
644
+ var _self = this,
645
+ postponeTime = this.valAttr('postpone') || 200;
646
+
647
+ window.postponedValidation = function () {
648
+ _self.validateInputOnBlur(language, conf, attachKeyupEvent, eventContext);
649
+ window.postponedValidation = false;
650
+ };
651
+
652
+ setTimeout(function () {
653
+ if (window.postponedValidation) {
654
+ window.postponedValidation();
655
+ }
656
+ }, postponeTime);
657
+
658
+ return this;
659
+ }
660
+
661
+ language = $.extend({}, $.formUtils.LANG, language || {});
662
+ $.formUtils.dialogs.removeInputStylingAndMessage(this, conf);
663
+
664
+ var $elem = this,
665
+ $form = $elem.closest('form'),
666
+ result = $.formUtils.validateInput(
667
+ $elem,
668
+ language,
669
+ conf,
670
+ $form,
671
+ eventContext
672
+ );
673
+
674
+ var reValidate = function() {
675
+ $elem.validateInputOnBlur(language, conf, false, 'blur.revalidated');
676
+ };
677
+
678
+ if (eventContext === 'blur') {
679
+ $elem
680
+ .unbind('validation.revalidate', reValidate)
681
+ .one('validation.revalidate', reValidate);
682
+ }
683
+
684
+ if (attachKeyupEvent) {
685
+ $elem.removeKeyUpValidation();
686
+ }
687
+
688
+ if (result.shouldChangeDisplay) {
689
+ if (result.isValid) {
690
+ $.formUtils.dialogs.applyInputSuccessStyling($elem, conf);
691
+ } else {
692
+ $.formUtils.dialogs.setInlineMessage($elem, result.errorMsg, conf);
693
+ }
694
+ }
695
+
696
+ if (!result.isValid && attachKeyupEvent) {
697
+ $elem.validateOnKeyUp(language, conf);
698
+ }
699
+
700
+ return this;
701
+ };
702
+
703
+ /**
704
+ * Validate element on keyup-event
705
+ */
706
+ $.fn.validateOnKeyUp = function(language, conf) {
707
+ this.each(function() {
708
+ var $input = $(this);
709
+ if (!$input.valAttr('has-keyup-event')) {
710
+ $input
711
+ .valAttr('has-keyup-event', 'true')
712
+ .bind('keyup.validation', function (evt) {
713
+ if( evt.keyCode !== 9 ) {
714
+ $input.validateInputOnBlur(language, conf, false, 'keyup');
715
+ }
716
+ });
717
+ }
718
+ });
719
+ return this;
720
+ };
721
+
722
+ /**
723
+ * Remove validation on keyup
724
+ */
725
+ $.fn.removeKeyUpValidation = function() {
726
+ this.each(function() {
727
+ $(this)
728
+ .valAttr('has-keyup-event', false)
729
+ .unbind('keyup.validation');
730
+ });
731
+ return this;
732
+ };
733
+
734
+ /**
735
+ * Short hand for fetching/adding/removing element attributes
736
+ * prefixed with 'data-validation-'
737
+ *
738
+ * @param {String} name
739
+ * @param {String|Boolean} [val]
740
+ * @return {String|undefined|jQuery}
741
+ * @protected
742
+ */
743
+ $.fn.valAttr = function (name, val) {
744
+ if (val === undefined) {
745
+ return this.attr('data-validation-' + name);
746
+ } else if (val === false || val === null) {
747
+ return this.removeAttr('data-validation-' + name);
748
+ } else {
749
+ name = ((name.length > 0) ? '-' + name : '');
750
+ return this.attr('data-validation' + name, val);
751
+ }
752
+ };
753
+
754
+ /**
755
+ * Function that validates all inputs in active form
756
+ *
757
+ * @param {Object} [language]
758
+ * @param {Object} [conf]
759
+ * @param {Boolean} [displayError] Defaults to true
760
+ */
761
+ $.fn.isValid = function (language, conf, displayError) {
762
+
763
+ if ($.formUtils.isLoadingModules) {
764
+ var $self = this;
765
+ setTimeout(function () {
766
+ $self.isValid(language, conf, displayError);
767
+ }, 200);
768
+ return null;
769
+ }
770
+
771
+ conf = $.extend({}, $.formUtils.defaultConfig(), conf || {});
772
+ language = $.extend({}, $.formUtils.LANG, language || {});
773
+ displayError = displayError !== false;
774
+
775
+ if ($.formUtils.errorDisplayPreventedWhenHalted) {
776
+ // isValid() was called programmatically with argument displayError set
777
+ // to false when the validation was halted by any of the validators
778
+ delete $.formUtils.errorDisplayPreventedWhenHalted;
779
+ displayError = false;
780
+ }
781
+
782
+ /**
783
+ * Adds message to error message stack if not already in the message stack
784
+ *
785
+ * @param {String} mess
786
+ * @para {jQuery} $elem
787
+ */
788
+ var addErrorMessage = function (mess, $elem) {
789
+ if ($.inArray(mess, errorMessages) < 0) {
790
+ errorMessages.push(mess);
791
+ }
792
+ errorInputs.push($elem);
793
+ $elem.valAttr('current-error', mess);
794
+ if (displayError) {
795
+ $.formUtils.dialogs.applyInputErrorStyling($elem, conf);
796
+ }
797
+ },
798
+
799
+ /** Holds inputs (of type checkox or radio) already validated, to prevent recheck of mulitple checkboxes & radios */
800
+ checkedInputs = [],
801
+
802
+ /** Error messages for this validation */
803
+ errorMessages = [],
804
+
805
+ /** Input elements which value was not valid */
806
+ errorInputs = [],
807
+
808
+ /** Form instance */
809
+ $form = this,
810
+
811
+ /**
812
+ * Tells whether or not to validate element with this name and of this type
813
+ *
814
+ * @param {String} name
815
+ * @param {String} type
816
+ * @return {Boolean}
817
+ */
818
+ ignoreInput = function (name, type) {
819
+ if (type === 'submit' || type === 'button' || type === 'reset') {
820
+ return true;
821
+ }
822
+ return $.inArray(name, conf.ignore || []) > -1;
823
+ };
824
+
825
+ // Reset style and remove error class
826
+ if (displayError) {
827
+ $.formUtils.dialogs.removeAllMessagesAndStyling($form, conf);
828
+ }
829
+
830
+ // Validate element values
831
+ $form.find('input,textarea,select').filter(':not([type="submit"],[type="button"])').each(function () {
832
+ var $elem = $(this),
833
+ elementType = $elem.attr('type'),
834
+ isCheckboxOrRadioBtn = elementType === 'radio' || elementType === 'checkbox',
835
+ elementName = $elem.attr('name');
836
+
837
+ if (!ignoreInput(elementName, elementType) && (!isCheckboxOrRadioBtn || $.inArray(elementName, checkedInputs) < 0)) {
838
+
839
+ if (isCheckboxOrRadioBtn) {
840
+ checkedInputs.push(elementName);
841
+ }
842
+
843
+ var result = $.formUtils.validateInput(
844
+ $elem,
845
+ language,
846
+ conf,
847
+ $form,
848
+ 'submit'
849
+ );
850
+
851
+ if (!result.isValid) {
852
+ addErrorMessage(result.errorMsg, $elem);
853
+ } else if (result.isValid && result.shouldChangeDisplay) {
854
+ $elem.valAttr('current-error', false);
855
+ $.formUtils.dialogs.applyInputSuccessStyling($elem, conf);
856
+ }
857
+ }
858
+
859
+ });
860
+
861
+ // Run validation callback
862
+ if (typeof conf.onValidate === 'function') {
863
+ var errors = conf.onValidate($form);
864
+ if ($.isArray(errors)) {
865
+ $.each(errors, function (i, err) {
866
+ addErrorMessage(err.message, err.element);
867
+ });
868
+ }
869
+ else if (errors && errors.element && errors.message) {
870
+ addErrorMessage(errors.message, errors.element);
871
+ }
872
+ }
873
+
874
+ // Reset form validation flag
875
+ $.formUtils.isValidatingEntireForm = false;
876
+
877
+ // Validation failed
878
+ if (errorInputs.length > 0) {
879
+ if (displayError) {
880
+ if (conf.errorMessagePosition === 'top') {
881
+ $.formUtils.dialogs.setMessageInTopOfForm($form, errorMessages, conf, language);
882
+ } else {
883
+ $.each(errorInputs, function (i, $input) {
884
+ $.formUtils.dialogs.setInlineMessage($input, $input.valAttr('current-error'), conf);
885
+ });
886
+ }
887
+ if (conf.scrollToTopOnError) {
888
+ $.formUtils.$win.scrollTop($form.offset().top - 20);
889
+ }
890
+ }
891
+ }
892
+
893
+ if (!displayError && $.formUtils.haltValidation) {
894
+ $.formUtils.errorDisplayPreventedWhenHalted = true;
895
+ }
896
+
897
+ return errorInputs.length === 0 && !$.formUtils.haltValidation;
898
+ };
899
+
900
+ /**
901
+ * Plugin for displaying input length restriction
902
+ */
903
+ $.fn.restrictLength = function (maxLengthElement) {
904
+ new $.formUtils.lengthRestriction(this, maxLengthElement);
905
+ return this;
906
+ };
907
+
908
+ /**
909
+ * Add suggestion dropdown to inputs having data-suggestions with a comma
910
+ * separated string with suggestions
911
+ * @param {Array} [settings]
912
+ * @returns {jQuery}
913
+ */
914
+ $.fn.addSuggestions = function (settings) {
915
+ var sugs = false;
916
+ this.find('input').each(function () {
917
+ var $field = $(this);
918
+
919
+ sugs = $.split($field.attr('data-suggestions'));
920
+
921
+ if (sugs.length > 0 && !$field.hasClass('has-suggestions')) {
922
+ $.formUtils.suggest($field, sugs, settings);
923
+ $field.addClass('has-suggestions');
924
+ }
925
+ });
926
+ return this;
927
+ };
928
+
929
+
930
+ })(jQuery, window);
931
+
932
+ /**
933
+ * Utility methods used for handling loading of modules (attached to $.formUtils)
934
+ */
935
+ (function($) {
936
+
937
+ 'use strict';
938
+
939
+ $.formUtils = $.extend($.formUtils || {}, {
940
+
941
+ /**
942
+ * @var {Boolean}
943
+ */
944
+ isLoadingModules: false,
945
+
946
+ /**
947
+ * @var {Object}
948
+ */
949
+ loadedModules: {},
950
+
951
+ /**
952
+ * @example
953
+ * $.formUtils.loadModules('date, security.dev');
954
+ *
955
+ * Will load the scripts date.js and security.dev.js from the
956
+ * directory where this script resides. If you want to load
957
+ * the modules from another directory you can use the
958
+ * path argument.
959
+ *
960
+ * The script will be cached by the browser unless the module
961
+ * name ends with .dev
962
+ *
963
+ * @param {String} modules - Comma separated string with module file names (no directory nor file extension)
964
+ * @param {String} [path] - Optional, path where the module files is located if their not in the same directory as the core modules
965
+ * @param {function} [callback] - Optional, whether or not to fire event 'load' when modules finished loading
966
+ */
967
+ loadModules: function (modules, path, callback) {
968
+
969
+ if ($.formUtils.isLoadingModules) {
970
+ setTimeout(function () {
971
+ $.formUtils.loadModules(modules, path, callback);
972
+ }, 10);
973
+ return;
974
+ }
975
+
976
+ var hasLoadedAnyModule = false,
977
+ loadModuleScripts = function (modules, path) {
978
+
979
+ var moduleList = $.split(modules),
980
+ numModules = moduleList.length,
981
+ moduleLoadedCallback = function () {
982
+ numModules--;
983
+ if (numModules === 0) {
984
+ $.formUtils.isLoadingModules = false;
985
+ if (callback && hasLoadedAnyModule) {
986
+ if( typeof callback === 'function' ) {
987
+ callback();
988
+ }
989
+ }
990
+ }
991
+ };
992
+
993
+
994
+ if (numModules > 0) {
995
+ $.formUtils.isLoadingModules = true;
996
+ }
997
+
998
+ var cacheSuffix = '?_=' + ( new Date().getTime() ),
999
+ appendToElement = document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0];
1000
+
1001
+ $.each(moduleList, function (i, modName) {
1002
+ modName = $.trim(modName);
1003
+ if (modName.length === 0) {
1004
+ moduleLoadedCallback();
1005
+ }
1006
+ else {
1007
+ var scriptUrl = path + modName + (modName.slice(-3) === '.js' ? '' : '.js'),
1008
+ script = document.createElement('SCRIPT');
1009
+
1010
+ if (scriptUrl in $.formUtils.loadedModules) {
1011
+ // already loaded
1012
+ moduleLoadedCallback();
1013
+ }
1014
+ else {
1015
+
1016
+ // Remember that this script is loaded
1017
+ $.formUtils.loadedModules[scriptUrl] = 1;
1018
+ hasLoadedAnyModule = true;
1019
+
1020
+ if (typeof define === 'function' && define.amd) {
1021
+ require([scriptUrl + ( scriptUrl.slice(-7) === '.dev.js' ? cacheSuffix : '' )], moduleLoadedCallback);
1022
+ } else {
1023
+ // Load the script
1024
+ script.type = 'text/javascript';
1025
+ script.onload = moduleLoadedCallback;
1026
+ script.src = scriptUrl + ( scriptUrl.slice(-7) === '.dev.js' ? cacheSuffix : '' );
1027
+ script.onerror = function() {
1028
+ $.formUtils.warn('Unable to load form validation module '+scriptUrl);
1029
+ };
1030
+ script.onreadystatechange = function () {
1031
+ // IE 7 fix
1032
+ if (this.readyState === 'complete' || this.readyState === 'loaded') {
1033
+ moduleLoadedCallback();
1034
+ // Handle memory leak in IE
1035
+ this.onload = null;
1036
+ this.onreadystatechange = null;
1037
+ }
1038
+ };
1039
+ appendToElement.appendChild(script);
1040
+ }
1041
+ }
1042
+ }
1043
+ });
1044
+ };
1045
+
1046
+ if (path) {
1047
+ loadModuleScripts(modules, path);
1048
+ } else {
1049
+ var findScriptPathAndLoadModules = function () {
1050
+ var foundPath = false;
1051
+ $('script[src*="form-validator"]').each(function () {
1052
+ var isScriptFromPluginNodeModulesDirectory = this.src.split('form-validator')[1].split('node_modules').length > 1;
1053
+ if (!isScriptFromPluginNodeModulesDirectory) {
1054
+ foundPath = this.src.substr(0, this.src.lastIndexOf('/')) + '/';
1055
+ if (foundPath === '/') {
1056
+ foundPath = '';
1057
+ }
1058
+ return false;
1059
+ }
1060
+ });
1061
+
1062
+ if (foundPath !== false) {
1063
+ loadModuleScripts(modules, foundPath);
1064
+ return true;
1065
+ }
1066
+ return false;
1067
+ };
1068
+
1069
+ if (!findScriptPathAndLoadModules()) {
1070
+ $(findScriptPathAndLoadModules);
1071
+ }
1072
+ }
1073
+ }
1074
+
1075
+ });
1076
+
1077
+ })(jQuery);
1078
+
1079
+ /**
1080
+ * Setup function for the plugin
1081
+ */
1082
+ (function ($) {
1083
+
1084
+ 'use strict';
1085
+
1086
+
1087
+ /**
1088
+ * A bit smarter split function
1089
+ * delimiter can be space, comma, dash or pipe
1090
+ * @param {String} val
1091
+ * @param {Function|String} [callback]
1092
+ * @param {Boolean} [allowSpaceAsDelimiter]
1093
+ * @returns {Array|void}
1094
+ */
1095
+ $.split = function (val, callback, allowSpaceAsDelimiter) {
1096
+ // default to true
1097
+ allowSpaceAsDelimiter = allowSpaceAsDelimiter === undefined || allowSpaceAsDelimiter === true;
1098
+ var pattern = '[,|'+(allowSpaceAsDelimiter ? '\\s':'')+'-]\\s*',
1099
+ regex = new RegExp(pattern, 'g');
1100
+ if (typeof callback !== 'function') {
1101
+ // return array
1102
+ if (!val) {
1103
+ return [];
1104
+ }
1105
+ var values = [];
1106
+ $.each(val.split(callback ? callback : regex),
1107
+ function (i, str) {
1108
+ str = $.trim(str);
1109
+ if (str.length) {
1110
+ values.push(str);
1111
+ }
1112
+ }
1113
+ );
1114
+ return values;
1115
+ } else if (val) {
1116
+ // exec callback func on each
1117
+ $.each(val.split(regex),
1118
+ function (i, str) {
1119
+ str = $.trim(str);
1120
+ if (str.length) {
1121
+ return callback(str, i);
1122
+ }
1123
+ }
1124
+ );
1125
+ }
1126
+ };
1127
+
1128
+ /**
1129
+ * Short hand function that makes the validation setup require less code
1130
+ * @param conf
1131
+ */
1132
+ $.validate = function (conf) {
1133
+
1134
+ var defaultConf = $.extend($.formUtils.defaultConfig(), {
1135
+ form: 'form',
1136
+ validateOnEvent: false,
1137
+ validateOnBlur: true,
1138
+ validateCheckboxRadioOnClick: true,
1139
+ showHelpOnFocus: true,
1140
+ addSuggestions: true,
1141
+ modules: '',
1142
+ onModulesLoaded: null,
1143
+ language: false,
1144
+ onSuccess: false,
1145
+ onError: false,
1146
+ onElementValidate: false
1147
+ });
1148
+
1149
+ conf = $.extend(defaultConf, conf || {});
1150
+
1151
+ $(window).trigger('formValidationPluginInit', [conf]);
1152
+
1153
+ if( conf.lang && conf.lang !== 'en' ) {
1154
+ var langModule = 'lang/'+conf.lang+'.js';
1155
+ conf.modules += conf.modules.length ? ','+langModule : langModule;
1156
+ }
1157
+
1158
+ // Add validation to forms
1159
+ $(conf.form).each(function (i, form) {
1160
+
1161
+ // Make a reference to the config for this form
1162
+ form.validationConfig = conf;
1163
+
1164
+ // Trigger jQuery event that we're about to setup validation
1165
+ var $form = $(form);
1166
+ $form.trigger('formValidationSetup', [$form, conf]);
1167
+
1168
+ // Remove classes and event handlers that might have been
1169
+ // added by a previous call to $.validate
1170
+ $form.find('.has-help-txt')
1171
+ .unbind('focus.validation')
1172
+ .unbind('blur.validation');
1173
+
1174
+ $form
1175
+ .removeClass('has-validation-callback')
1176
+ .unbind('submit.validation')
1177
+ .unbind('reset.validation')
1178
+ .find('input[data-validation],textarea[data-validation]')
1179
+ .unbind('blur.validation');
1180
+
1181
+ // Validate when submitted
1182
+ $form.bind('submit.validation', function (evt) {
1183
+
1184
+ var $form = $(this),
1185
+ stop = function() {
1186
+ evt.stopImmediatePropagation();
1187
+ return false;
1188
+ };
1189
+
1190
+ if ($.formUtils.haltValidation) {
1191
+ // pressing several times on submit button while validation is halted
1192
+ return stop();
1193
+ }
1194
+
1195
+ if ($.formUtils.isLoadingModules) {
1196
+ setTimeout(function () {
1197
+ $form.trigger('submit.validation');
1198
+ }, 200);
1199
+ return stop();
1200
+ }
1201
+
1202
+ var valid = $form.isValid(conf.language, conf);
1203
+ if ($.formUtils.haltValidation) {
1204
+ // Validation got halted by one of the validators
1205
+ return stop();
1206
+ } else {
1207
+ if (valid && typeof conf.onSuccess === 'function') {
1208
+ var callbackResponse = conf.onSuccess($form);
1209
+ if (callbackResponse === false) {
1210
+ return stop();
1211
+ }
1212
+ } else if (!valid && typeof conf.onError === 'function') {
1213
+ conf.onError($form);
1214
+ return stop();
1215
+ } else {
1216
+ return valid ? true : stop();
1217
+ }
1218
+ }
1219
+ })
1220
+ .bind('reset.validation', function () {
1221
+ $.formUtils.dialogs.removeAllMessagesAndStyling($form, conf);
1222
+ })
1223
+ .addClass('has-validation-callback');
1224
+
1225
+ if (conf.showHelpOnFocus) {
1226
+ $form.showHelpOnFocus();
1227
+ }
1228
+ if (conf.addSuggestions) {
1229
+ $form.addSuggestions();
1230
+ }
1231
+ if (conf.validateOnBlur) {
1232
+ $form.validateOnBlur(conf.language, conf);
1233
+ $form.bind('html5ValidationAttrsFound', function () {
1234
+ $form.validateOnBlur(conf.language, conf);
1235
+ });
1236
+ }
1237
+ if (conf.validateOnEvent) {
1238
+ $form.validateOnEvent(conf.language, conf);
1239
+ }
1240
+ });
1241
+
1242
+ if (conf.modules !== '') {
1243
+ $.formUtils.loadModules(conf.modules, false, function() {
1244
+ if (typeof conf.onModulesLoaded === 'function') {
1245
+ conf.onModulesLoaded();
1246
+ }
1247
+ var $form = typeof conf.form === 'string' ? $(conf.form) : conf.form;
1248
+ $.formUtils.$win.trigger('validatorsLoaded', [$form, conf]);
1249
+ });
1250
+ }
1251
+ };
1252
+
1253
+ })(jQuery);
1254
+
1255
+ /**
1256
+ * Utility methods and properties attached to $.formUtils
1257
+ */
1258
+ (function($, window) {
1259
+
1260
+ 'use strict';
1261
+
1262
+ var $win = $(window);
1263
+
1264
+ $.formUtils = $.extend($.formUtils || {}, {
1265
+
1266
+ $win: $win,
1267
+
1268
+ /**
1269
+ * Default config for $(...).isValid();
1270
+ */
1271
+ defaultConfig: function () {
1272
+ return {
1273
+ ignore: [], // Names of inputs not to be validated even though `validationRuleAttribute` containing the validation rules tells us to
1274
+ errorElementClass: 'error', // Class that will be put on elements which value is invalid
1275
+ borderColorOnError: '#b94a48', // Border color of elements which value is invalid, empty string to not change border color
1276
+ errorMessageClass: 'form-error', // class name of div containing error messages when validation fails
1277
+ validationRuleAttribute: 'data-validation', // name of the attribute holding the validation rules
1278
+ validationErrorMsgAttribute: 'data-validation-error-msg', // define custom err msg inline with element
1279
+ errorMessagePosition: 'inline', // Can be either "top" or "inline"
1280
+ errorMessageTemplate: {
1281
+ container: '<div class="{errorMessageClass} alert alert-danger">{messages}</div>',
1282
+ messages: '<strong>{errorTitle}</strong><ul>{fields}</ul>',
1283
+ field: '<li>{msg}</li>'
1284
+ },
1285
+ scrollToTopOnError: true,
1286
+ dateFormat: 'yyyy-mm-dd',
1287
+ addValidClassOnAll: false, // whether or not to apply class="valid" even if the input wasn't validated
1288
+ decimalSeparator: '.',
1289
+ inputParentClassOnError: 'has-error', // twitter-bootstrap default class name
1290
+ inputParentClassOnSuccess: 'has-success', // twitter-bootstrap default class name
1291
+ validateHiddenInputs: false, // whether or not hidden inputs should be validated
1292
+ inlineErrorMessageCallback: false,
1293
+ submitErrorMessageCallback: false
1294
+ };
1295
+ },
1296
+
1297
+ /**
1298
+ * Available validators
1299
+ */
1300
+ validators: {},
1301
+
1302
+ /**
1303
+ * Events triggered by form validator
1304
+ */
1305
+ _events: {load: [], valid: [], invalid: []},
1306
+
1307
+ /**
1308
+ * Setting this property to true during validation will
1309
+ * stop further validation from taking place and form will
1310
+ * not be sent
1311
+ */
1312
+ haltValidation: false,
1313
+
1314
+ /**
1315
+ * Function for adding a validator
1316
+ * @param {Object} validator
1317
+ */
1318
+ addValidator: function (validator) {
1319
+ // prefix with "validate_" for backward compatibility reasons
1320
+ var name = validator.name.indexOf('validate_') === 0 ? validator.name : 'validate_' + validator.name;
1321
+ if (validator.validateOnKeyUp === undefined) {
1322
+ validator.validateOnKeyUp = true;
1323
+ }
1324
+ this.validators[name] = validator;
1325
+ },
1326
+
1327
+ /**
1328
+ * Warn user via the console if available
1329
+ */
1330
+ warn: function(msg) {
1331
+ if( 'console' in window ) {
1332
+ if( typeof window.console.warn === 'function' ) {
1333
+ window.console.warn(msg);
1334
+ } else if( typeof window.console.log === 'function' ) {
1335
+ window.console.log(msg);
1336
+ }
1337
+ } else {
1338
+ alert(msg);
1339
+ }
1340
+ },
1341
+
1342
+ /**
1343
+ * Same as input $.fn.val() but also supporting input of typ radio or checkbox
1344
+ * @example
1345
+ *
1346
+ * $.formUtils.getValue('.myRadioButtons', $('#some-form'));
1347
+ * $.formUtils.getValue($('#some-form').find('.check-boxes'));
1348
+ *
1349
+ * @param query
1350
+ * @param $parent
1351
+ * @returns {String|Boolean}
1352
+ */
1353
+ getValue: function(query, $parent) {
1354
+ var $inputs = $parent ? $parent.find(query) : query;
1355
+ if ($inputs.length > 0 ) {
1356
+ var type = $inputs.eq(0).attr('type');
1357
+ if (type === 'radio' || type === 'checkbox') {
1358
+ return $inputs.filter(':checked').val() || '';
1359
+ } else {
1360
+ return $inputs.val() || '';
1361
+ }
1362
+ }
1363
+ return false;
1364
+ },
1365
+
1366
+ /**
1367
+ * Validate the value of given element according to the validation rules
1368
+ * found in the attribute data-validation. Will return an object representing
1369
+ * a validation result, having the props shouldChangeDisplay, isValid and errorMsg
1370
+ * @param {jQuery} $elem
1371
+ * @param {Object} language ($.formUtils.LANG)
1372
+ * @param {Object} conf
1373
+ * @param {jQuery} $form
1374
+ * @param {String} [eventContext]
1375
+ * @return {Object}
1376
+ */
1377
+ validateInput: function ($elem, language, conf, $form, eventContext) {
1378
+
1379
+ conf = conf || $.formUtils.defaultConfig();
1380
+ language = language || $.formUtils.LANG;
1381
+
1382
+ var value = this.getValue($elem);
1383
+
1384
+ $elem
1385
+ .valAttr('skipped', false)
1386
+ .one('beforeValidation', function() {
1387
+ // Skip input because its hidden or disabled
1388
+ // Doing this in a callback makes it possible for others to prevent the default
1389
+ // behaviour by binding to the same event and call evt.stopImmediatePropagation()
1390
+ if ($elem.attr('disabled') || (!$elem.is(':visible') && !conf.validateHiddenInputs)) {
1391
+ $elem.valAttr('skipped', 1);
1392
+ }
1393
+ })
1394
+ .trigger('beforeValidation', [value, language, conf]);
1395
+
1396
+
1397
+ var inputIsOptional = $elem.valAttr('optional') === 'true',
1398
+ skipBecauseItsEmpty = !value && inputIsOptional,
1399
+ validationRules = $elem.attr(conf.validationRuleAttribute),
1400
+ isValid = true,
1401
+ errorMsg = '',
1402
+ result = {isValid: true, shouldChangeDisplay:true, errorMsg:''};
1403
+
1404
+ // For input type="number", browsers attempt to parse the entered value into a number.
1405
+ // If the input is not numeric, browsers handle the situation differently:
1406
+ // Chrome 48 simply disallows non-numeric input; FF 44 clears out the input box on blur;
1407
+ // Safari 5 parses the entered string to find a leading number.
1408
+ // If the input fails browser validation, the browser sets the input value equal to an empty string.
1409
+ // Therefore, we cannot distinguish (apart from hacks) between an empty input type="text" and one with a
1410
+ // value that can't be parsed by the browser.
1411
+
1412
+ if (!validationRules || skipBecauseItsEmpty || $elem.valAttr('skipped')) {
1413
+ result.shouldChangeDisplay = conf.addValidClassOnAll;
1414
+ return result;
1415
+ }
1416
+
1417
+ // Filter out specified characters
1418
+ var ignore = $elem.valAttr('ignore');
1419
+ if (ignore) {
1420
+ $.each(ignore.split(''), function(i, character) {
1421
+ value = value.replace(new RegExp('\\'+character, 'g'), '');
1422
+ });
1423
+ }
1424
+
1425
+ $.split(validationRules, function (rule) {
1426
+
1427
+ if (rule.indexOf('validate_') !== 0) {
1428
+ rule = 'validate_' + rule;
1429
+ }
1430
+
1431
+ var validator = $.formUtils.validators[rule];
1432
+
1433
+ if (validator) {
1434
+
1435
+ // special change of element for checkbox_group rule
1436
+ if (rule === 'validate_checkbox_group') {
1437
+ // set element to first in group, so error msg attr doesn't need to be set on all elements in group
1438
+ $elem = $form.find('[name="' + $elem.attr('name') + '"]:eq(0)');
1439
+ }
1440
+
1441
+ if (eventContext !== 'keyup' || validator.validateOnKeyUp) {
1442
+ // A validator can prevent itself from getting triggered on keyup
1443
+ isValid = validator.validatorFunction(value, $elem, conf, language, $form, eventContext);
1444
+ }
1445
+
1446
+ if (!isValid) {
1447
+ if (conf.validateOnBlur) {
1448
+ $elem.validateOnKeyUp(language, conf);
1449
+ }
1450
+ errorMsg = $.formUtils.dialogs.resolveErrorMessage($elem, validator, rule, conf, language);
1451
+ return false; // break iteration
1452
+ }
1453
+
1454
+ } else {
1455
+
1456
+ // todo: Add some validator lookup function and tell immediately which module is missing
1457
+ throw new Error('Using undefined validator "' + rule +
1458
+ '". Maybe you have forgotten to load the module that "' + rule +'" belongs to?');
1459
+
1460
+ }
1461
+
1462
+ });
1463
+
1464
+
1465
+ if (isValid === false) {
1466
+ $elem.trigger('validation', false);
1467
+ result.errorMsg = errorMsg;
1468
+ result.isValid = false;
1469
+ result.shouldChangeDisplay = true;
1470
+ } else if (isValid === null) {
1471
+ // A validatorFunction returning null means that it's not able to validate
1472
+ // the input at this time. Most probably some async stuff need to gets finished
1473
+ // first and then the validator will re-trigger the validation.
1474
+ result.shouldChangeDisplay = false;
1475
+ } else {
1476
+ $elem.trigger('validation', true);
1477
+ result.shouldChangeDisplay = true;
1478
+ }
1479
+
1480
+ // Run element validation callback
1481
+ if (typeof conf.onElementValidate === 'function' && errorMsg !== null) {
1482
+ conf.onElementValidate(result.isValid, $elem, $form, errorMsg);
1483
+ }
1484
+
1485
+ $elem.trigger('afterValidation', [result, eventContext]);
1486
+
1487
+ return result;
1488
+ },
1489
+
1490
+ /**
1491
+ * Is it a correct date according to given dateFormat. Will return false if not, otherwise
1492
+ * an array 0=>year 1=>month 2=>day
1493
+ *
1494
+ * @param {String} val
1495
+ * @param {String} dateFormat
1496
+ * @param {Boolean} [addMissingLeadingZeros]
1497
+ * @return {Array}|{Boolean}
1498
+ */
1499
+ parseDate: function (val, dateFormat, addMissingLeadingZeros) {
1500
+ var divider = dateFormat.replace(/[a-zA-Z]/gi, '').substring(0, 1),
1501
+ regexp = '^',
1502
+ formatParts = dateFormat.split(divider || null),
1503
+ matches, day, month, year;
1504
+
1505
+ $.each(formatParts, function (i, part) {
1506
+ regexp += (i > 0 ? '\\' + divider : '') + '(\\d{' + part.length + '})';
1507
+ });
1508
+
1509
+ regexp += '$';
1510
+
1511
+ if (addMissingLeadingZeros) {
1512
+ var newValueParts = [];
1513
+ $.each(val.split(divider), function(i, part) {
1514
+ if(part.length === 1) {
1515
+ part = '0'+part;
1516
+ }
1517
+ newValueParts.push(part);
1518
+ });
1519
+ val = newValueParts.join(divider);
1520
+ }
1521
+
1522
+ matches = val.match(new RegExp(regexp));
1523
+ if (matches === null) {
1524
+ return false;
1525
+ }
1526
+
1527
+ var findDateUnit = function (unit, formatParts, matches) {
1528
+ for (var i = 0; i < formatParts.length; i++) {
1529
+ if (formatParts[i].substring(0, 1) === unit) {
1530
+ return $.formUtils.parseDateInt(matches[i + 1]);
1531
+ }
1532
+ }
1533
+ return -1;
1534
+ };
1535
+
1536
+ month = findDateUnit('m', formatParts, matches);
1537
+ day = findDateUnit('d', formatParts, matches);
1538
+ year = findDateUnit('y', formatParts, matches);
1539
+
1540
+ if ((month === 2 && day > 28 && (year % 4 !== 0 || year % 100 === 0 && year % 400 !== 0)) ||
1541
+ (month === 2 && day > 29 && (year % 4 === 0 || year % 100 !== 0 && year % 400 === 0)) ||
1542
+ month > 12 || month === 0) {
1543
+ return false;
1544
+ }
1545
+ if ((this.isShortMonth(month) && day > 30) || (!this.isShortMonth(month) && day > 31) || day === 0) {
1546
+ return false;
1547
+ }
1548
+
1549
+ return [year, month, day];
1550
+ },
1551
+
1552
+ /**
1553
+ * skum fix. är talet 05 eller lägre ger parseInt rätt int annars får man 0 när man kör parseInt?
1554
+ *
1555
+ * @param {String} val
1556
+ * @return {Number}
1557
+ */
1558
+ parseDateInt: function (val) {
1559
+ if (val.indexOf('0') === 0) {
1560
+ val = val.replace('0', '');
1561
+ }
1562
+ return parseInt(val, 10);
1563
+ },
1564
+
1565
+ /**
1566
+ * Has month only 30 days?
1567
+ *
1568
+ * @param {Number} m
1569
+ * @return {Boolean}
1570
+ */
1571
+ isShortMonth: function (m) {
1572
+ return (m % 2 === 0 && m < 7) || (m % 2 !== 0 && m > 7);
1573
+ },
1574
+
1575
+ /**
1576
+ * Restrict input length
1577
+ *
1578
+ * @param {jQuery} $inputElement Jquery Html object
1579
+ * @param {jQuery} $maxLengthElement jQuery Html Object
1580
+ * @return void
1581
+ */
1582
+ lengthRestriction: function ($inputElement, $maxLengthElement) {
1583
+ // read maxChars from counter display initial text value
1584
+ var maxChars = parseInt($maxLengthElement.text(), 10),
1585
+ charsLeft = 0,
1586
+
1587
+ // internal function does the counting and sets display value
1588
+ countCharacters = function () {
1589
+ var numChars = $inputElement.val().length;
1590
+ if (numChars > maxChars) {
1591
+ // get current scroll bar position
1592
+ var currScrollTopPos = $inputElement.scrollTop();
1593
+ // trim value to max length
1594
+ $inputElement.val($inputElement.val().substring(0, maxChars));
1595
+ $inputElement.scrollTop(currScrollTopPos);
1596
+ }
1597
+ charsLeft = maxChars - numChars;
1598
+ if (charsLeft < 0) {
1599
+ charsLeft = 0;
1600
+ }
1601
+
1602
+ // set counter text
1603
+ $maxLengthElement.text(charsLeft);
1604
+ };
1605
+
1606
+ // bind events to this element
1607
+ // setTimeout is needed, cut or paste fires before val is available
1608
+ $($inputElement).bind('keydown keyup keypress focus blur', countCharacters)
1609
+ .bind('cut paste', function () {
1610
+ setTimeout(countCharacters, 100);
1611
+ });
1612
+
1613
+ // count chars on pageload, if there are prefilled input-values
1614
+ $(document).bind('ready', countCharacters);
1615
+ },
1616
+
1617
+ /**
1618
+ * Test numeric against allowed range
1619
+ *
1620
+ * @param $value int
1621
+ * @param $rangeAllowed str; (1-2, min1, max2, 10)
1622
+ * @return array
1623
+ */
1624
+ numericRangeCheck: function (value, rangeAllowed) {
1625
+ // split by dash
1626
+ var range = $.split(rangeAllowed),
1627
+ // min or max
1628
+ minmax = parseInt(rangeAllowed.substr(3), 10);
1629
+
1630
+ if( range.length === 1 && rangeAllowed.indexOf('min') === -1 && rangeAllowed.indexOf('max') === -1 ) {
1631
+ range = [rangeAllowed, rangeAllowed]; // only a number, checking agains an exact number of characters
1632
+ }
1633
+
1634
+ // range ?
1635
+ if (range.length === 2 && (value < parseInt(range[0], 10) || value > parseInt(range[1], 10) )) {
1636
+ return [ 'out', range[0], range[1] ];
1637
+ } // value is out of range
1638
+ else if (rangeAllowed.indexOf('min') === 0 && (value < minmax )) // min
1639
+ {
1640
+ return ['min', minmax];
1641
+ } // value is below min
1642
+ else if (rangeAllowed.indexOf('max') === 0 && (value > minmax )) // max
1643
+ {
1644
+ return ['max', minmax];
1645
+ } // value is above max
1646
+ // since no other returns executed, value is in allowed range
1647
+ return [ 'ok' ];
1648
+ },
1649
+
1650
+
1651
+ _numSuggestionElements: 0,
1652
+ _selectedSuggestion: null,
1653
+ _previousTypedVal: null,
1654
+
1655
+ /**
1656
+ * Utility function that can be used to create plugins that gives
1657
+ * suggestions when inputs is typed into
1658
+ * @param {jQuery} $elem
1659
+ * @param {Array} suggestions
1660
+ * @param {Object} settings - Optional
1661
+ * @return {jQuery}
1662
+ */
1663
+ suggest: function ($elem, suggestions, settings) {
1664
+ var conf = {
1665
+ css: {
1666
+ maxHeight: '150px',
1667
+ background: '#FFF',
1668
+ lineHeight: '150%',
1669
+ textDecoration: 'underline',
1670
+ overflowX: 'hidden',
1671
+ overflowY: 'auto',
1672
+ border: '#CCC solid 1px',
1673
+ borderTop: 'none',
1674
+ cursor: 'pointer'
1675
+ },
1676
+ activeSuggestionCSS: {
1677
+ background: '#E9E9E9'
1678
+ }
1679
+ },
1680
+ setSuggsetionPosition = function ($suggestionContainer, $input) {
1681
+ var offset = $input.offset();
1682
+ $suggestionContainer.css({
1683
+ width: $input.outerWidth(),
1684
+ left: offset.left + 'px',
1685
+ top: (offset.top + $input.outerHeight()) + 'px'
1686
+ });
1687
+ };
1688
+
1689
+ if (settings) {
1690
+ $.extend(conf, settings);
1691
+ }
1692
+
1693
+ conf.css.position = 'absolute';
1694
+ conf.css['z-index'] = 9999;
1695
+ $elem.attr('autocomplete', 'off');
1696
+
1697
+ if (this._numSuggestionElements === 0) {
1698
+ // Re-position suggestion container if window size changes
1699
+ $win.bind('resize', function () {
1700
+ $('.jquery-form-suggestions').each(function () {
1701
+ var $container = $(this),
1702
+ suggestID = $container.attr('data-suggest-container');
1703
+ setSuggsetionPosition($container, $('.suggestions-' + suggestID).eq(0));
1704
+ });
1705
+ });
1706
+ }
1707
+
1708
+ this._numSuggestionElements++;
1709
+
1710
+ var onSelectSuggestion = function ($el) {
1711
+ var suggestionId = $el.valAttr('suggestion-nr');
1712
+ $.formUtils._selectedSuggestion = null;
1713
+ $.formUtils._previousTypedVal = null;
1714
+ $('.jquery-form-suggestion-' + suggestionId).fadeOut('fast');
1715
+ };
1716
+
1717
+ $elem
1718
+ .data('suggestions', suggestions)
1719
+ .valAttr('suggestion-nr', this._numSuggestionElements)
1720
+ .unbind('focus.suggest')
1721
+ .bind('focus.suggest', function () {
1722
+ $(this).trigger('keyup');
1723
+ $.formUtils._selectedSuggestion = null;
1724
+ })
1725
+ .unbind('keyup.suggest')
1726
+ .bind('keyup.suggest', function () {
1727
+ var $input = $(this),
1728
+ foundSuggestions = [],
1729
+ val = $.trim($input.val()).toLocaleLowerCase();
1730
+
1731
+ if (val === $.formUtils._previousTypedVal) {
1732
+ return;
1733
+ }
1734
+ else {
1735
+ $.formUtils._previousTypedVal = val;
1736
+ }
1737
+
1738
+ var hasTypedSuggestion = false,
1739
+ suggestionId = $input.valAttr('suggestion-nr'),
1740
+ $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1741
+
1742
+ $suggestionContainer.scrollTop(0);
1743
+
1744
+ // Find the right suggestions
1745
+ if (val !== '') {
1746
+ var findPartial = val.length > 2;
1747
+ $.each($input.data('suggestions'), function (i, suggestion) {
1748
+ var lowerCaseVal = suggestion.toLocaleLowerCase();
1749
+ if (lowerCaseVal === val) {
1750
+ foundSuggestions.push('<strong>' + suggestion + '</strong>');
1751
+ hasTypedSuggestion = true;
1752
+ return false;
1753
+ } else if (lowerCaseVal.indexOf(val) === 0 || (findPartial && lowerCaseVal.indexOf(val) > -1)) {
1754
+ foundSuggestions.push(suggestion.replace(new RegExp(val, 'gi'), '<strong>$&</strong>'));
1755
+ }
1756
+ });
1757
+ }
1758
+
1759
+ // Hide suggestion container
1760
+ if (hasTypedSuggestion || (foundSuggestions.length === 0 && $suggestionContainer.length > 0)) {
1761
+ $suggestionContainer.hide();
1762
+ }
1763
+
1764
+ // Create suggestion container if not already exists
1765
+ else if (foundSuggestions.length > 0 && $suggestionContainer.length === 0) {
1766
+ $suggestionContainer = $('<div></div>').css(conf.css).appendTo('body');
1767
+ $elem.addClass('suggestions-' + suggestionId);
1768
+ $suggestionContainer
1769
+ .attr('data-suggest-container', suggestionId)
1770
+ .addClass('jquery-form-suggestions')
1771
+ .addClass('jquery-form-suggestion-' + suggestionId);
1772
+ }
1773
+
1774
+ // Show hidden container
1775
+ else if (foundSuggestions.length > 0 && !$suggestionContainer.is(':visible')) {
1776
+ $suggestionContainer.show();
1777
+ }
1778
+
1779
+ // add suggestions
1780
+ if (foundSuggestions.length > 0 && val.length !== foundSuggestions[0].length) {
1781
+
1782
+ // put container in place every time, just in case
1783
+ setSuggsetionPosition($suggestionContainer, $input);
1784
+
1785
+ // Add suggestions HTML to container
1786
+ $suggestionContainer.html('');
1787
+ $.each(foundSuggestions, function (i, text) {
1788
+ $('<div></div>')
1789
+ .append(text)
1790
+ .css({
1791
+ overflow: 'hidden',
1792
+ textOverflow: 'ellipsis',
1793
+ whiteSpace: 'nowrap',
1794
+ padding: '5px'
1795
+ })
1796
+ .addClass('form-suggest-element')
1797
+ .appendTo($suggestionContainer)
1798
+ .click(function () {
1799
+ $input.focus();
1800
+ $input.val($(this).text());
1801
+ $input.trigger('change');
1802
+ onSelectSuggestion($input);
1803
+ });
1804
+ });
1805
+ }
1806
+ })
1807
+ .unbind('keydown.validation')
1808
+ .bind('keydown.validation', function (e) {
1809
+ var code = (e.keyCode ? e.keyCode : e.which),
1810
+ suggestionId,
1811
+ $suggestionContainer,
1812
+ $input = $(this);
1813
+
1814
+ if (code === 13 && $.formUtils._selectedSuggestion !== null) {
1815
+ suggestionId = $input.valAttr('suggestion-nr');
1816
+ $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1817
+ if ($suggestionContainer.length > 0) {
1818
+ var newText = $suggestionContainer.find('div').eq($.formUtils._selectedSuggestion).text();
1819
+ $input.val(newText);
1820
+ $input.trigger('change');
1821
+ onSelectSuggestion($input);
1822
+ e.preventDefault();
1823
+ }
1824
+ }
1825
+ else {
1826
+ suggestionId = $input.valAttr('suggestion-nr');
1827
+ $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1828
+ var $suggestions = $suggestionContainer.children();
1829
+ if ($suggestions.length > 0 && $.inArray(code, [38, 40]) > -1) {
1830
+ if (code === 38) { // key up
1831
+ if ($.formUtils._selectedSuggestion === null) {
1832
+ $.formUtils._selectedSuggestion = $suggestions.length - 1;
1833
+ }
1834
+ else{
1835
+ $.formUtils._selectedSuggestion--;
1836
+ }
1837
+ if ($.formUtils._selectedSuggestion < 0) {
1838
+ $.formUtils._selectedSuggestion = $suggestions.length - 1;
1839
+ }
1840
+ }
1841
+ else if (code === 40) { // key down
1842
+ if ($.formUtils._selectedSuggestion === null) {
1843
+ $.formUtils._selectedSuggestion = 0;
1844
+ }
1845
+ else {
1846
+ $.formUtils._selectedSuggestion++;
1847
+ }
1848
+ if ($.formUtils._selectedSuggestion > ($suggestions.length - 1)) {
1849
+ $.formUtils._selectedSuggestion = 0;
1850
+ }
1851
+ }
1852
+
1853
+ // Scroll in suggestion window
1854
+ var containerInnerHeight = $suggestionContainer.innerHeight(),
1855
+ containerScrollTop = $suggestionContainer.scrollTop(),
1856
+ suggestionHeight = $suggestionContainer.children().eq(0).outerHeight(),
1857
+ activeSuggestionPosY = suggestionHeight * ($.formUtils._selectedSuggestion);
1858
+
1859
+ if (activeSuggestionPosY < containerScrollTop || activeSuggestionPosY > (containerScrollTop + containerInnerHeight)) {
1860
+ $suggestionContainer.scrollTop(activeSuggestionPosY);
1861
+ }
1862
+
1863
+ $suggestions
1864
+ .removeClass('active-suggestion')
1865
+ .css('background', 'none')
1866
+ .eq($.formUtils._selectedSuggestion)
1867
+ .addClass('active-suggestion')
1868
+ .css(conf.activeSuggestionCSS);
1869
+
1870
+ e.preventDefault();
1871
+ return false;
1872
+ }
1873
+ }
1874
+ })
1875
+ .unbind('blur.suggest')
1876
+ .bind('blur.suggest', function () {
1877
+ onSelectSuggestion($(this));
1878
+ });
1879
+
1880
+ return $elem;
1881
+ },
1882
+
1883
+ /**
1884
+ * Error dialogs
1885
+ *
1886
+ * @var {Object}
1887
+ */
1888
+ LANG: {
1889
+ errorTitle: 'Form submission failed!',
1890
+ requiredField: 'This is a required field',
1891
+ requiredFields: 'You have not answered all required fields',
1892
+ badTime: 'You have not given a correct time',
1893
+ badEmail: 'You have not given a correct e-mail address',
1894
+ badTelephone: 'You have not given a correct phone number',
1895
+ badSecurityAnswer: 'You have not given a correct answer to the security question',
1896
+ badDate: 'You have not given a correct date',
1897
+ lengthBadStart: 'The input value must be between ',
1898
+ lengthBadEnd: ' characters',
1899
+ lengthTooLongStart: 'The input value is longer than ',
1900
+ lengthTooShortStart: 'The input value is shorter than ',
1901
+ notConfirmed: 'Input values could not be confirmed',
1902
+ badDomain: 'Incorrect domain value',
1903
+ badUrl: 'The input value is not a correct URL',
1904
+ badCustomVal: 'The input value is incorrect',
1905
+ andSpaces: ' and spaces ',
1906
+ badInt: 'The input value was not a correct number',
1907
+ badSecurityNumber: 'Your social security number was incorrect',
1908
+ badUKVatAnswer: 'Incorrect UK VAT Number',
1909
+ badUKNin: 'Incorrect UK NIN',
1910
+ badUKUtr: 'Incorrect UK UTR Number',
1911
+ badStrength: 'The password isn\'t strong enough',
1912
+ badNumberOfSelectedOptionsStart: 'You have to choose at least ',
1913
+ badNumberOfSelectedOptionsEnd: ' answers',
1914
+ badAlphaNumeric: 'The input value can only contain alphanumeric characters ',
1915
+ badAlphaNumericExtra: ' and ',
1916
+ wrongFileSize: 'The file you are trying to upload is too large (max %s)',
1917
+ wrongFileType: 'Only files of type %s is allowed',
1918
+ groupCheckedRangeStart: 'Please choose between ',
1919
+ groupCheckedTooFewStart: 'Please choose at least ',
1920
+ groupCheckedTooManyStart: 'Please choose a maximum of ',
1921
+ groupCheckedEnd: ' item(s)',
1922
+ badCreditCard: 'The credit card number is not correct',
1923
+ badCVV: 'The CVV number was not correct',
1924
+ wrongFileDim : 'Incorrect image dimensions,',
1925
+ imageTooTall : 'the image can not be taller than',
1926
+ imageTooWide : 'the image can not be wider than',
1927
+ imageTooSmall : 'the image was too small',
1928
+ min : 'min',
1929
+ max : 'max',
1930
+ imageRatioNotAccepted : 'Image ratio is not be accepted',
1931
+ badBrazilTelephoneAnswer: 'The phone number entered is invalid',
1932
+ badBrazilCEPAnswer: 'The CEP entered is invalid',
1933
+ badBrazilCPFAnswer: 'The CPF entered is invalid',
1934
+ badPlPesel: 'The PESEL entered is invalid',
1935
+ badPlNip: 'The NIP entered is invalid',
1936
+ badPlRegon: 'The REGON entered is invalid',
1937
+ badreCaptcha: 'Please confirm that you are not a bot',
1938
+ passwordComplexityStart: 'Password must contain at least ',
1939
+ passwordComplexitySeparator: ', ',
1940
+ passwordComplexityUppercaseInfo: ' uppercase letter(s)',
1941
+ passwordComplexityLowercaseInfo: ' lowercase letter(s)',
1942
+ passwordComplexitySpecialCharsInfo: ' special character(s)',
1943
+ passwordComplexityNumericCharsInfo: ' numeric character(s)',
1944
+ passwordComplexityEnd: '.'
1945
+ }
1946
+ });
1947
+
1948
+ })(jQuery, window);
1949
+
1950
+ /**
1951
+ * File declaring all default validators.
1952
+ */
1953
+ (function($) {
1954
+
1955
+ /*
1956
+ * Validate email
1957
+ */
1958
+ $.formUtils.addValidator({
1959
+ name: 'email',
1960
+ validatorFunction: function (email) {
1961
+
1962
+ var emailParts = email.toLowerCase().split('@'),
1963
+ localPart = emailParts[0],
1964
+ domain = emailParts[1];
1965
+
1966
+ if (localPart && domain) {
1967
+
1968
+ if( localPart.indexOf('"') === 0 ) {
1969
+ var len = localPart.length;
1970
+ localPart = localPart.replace(/\"/g, '');
1971
+ if( localPart.length !== (len-2) ) {
1972
+ return false; // It was not allowed to have more than two apostrophes
1973
+ }
1974
+ }
1975
+
1976
+ return $.formUtils.validators.validate_domain.validatorFunction(emailParts[1]) &&
1977
+ localPart.indexOf('.') !== 0 &&
1978
+ localPart.substring(localPart.length-1, localPart.length) !== '.' &&
1979
+ localPart.indexOf('..') === -1 &&
1980
+ !(/[^\w\+\.\-\#\-\_\~\!\$\&\'\(\)\*\+\,\;\=\:]/.test(localPart));
1981
+ }
1982
+
1983
+ return false;
1984
+ },
1985
+ errorMessage: '',
1986
+ errorMessageKey: 'badEmail'
1987
+ });
1988
+
1989
+ /*
1990
+ * Validate domain name
1991
+ */
1992
+ $.formUtils.addValidator({
1993
+ name: 'domain',
1994
+ validatorFunction: function (val) {
1995
+ return val.length > 0 &&
1996
+ val.length <= 253 && // Including sub domains
1997
+ !(/[^a-zA-Z0-9]/.test(val.slice(-2))) && !(/[^a-zA-Z0-9]/.test(val.substr(0, 1))) && !(/[^a-zA-Z0-9\.\-]/.test(val)) &&
1998
+ val.split('..').length === 1 &&
1999
+ val.split('.').length > 1;
2000
+ },
2001
+ errorMessage: '',
2002
+ errorMessageKey: 'badDomain'
2003
+ });
2004
+
2005
+ /*
2006
+ * Validate required
2007
+ */
2008
+ $.formUtils.addValidator({
2009
+ name: 'required',
2010
+ validatorFunction: function (val, $el, config, language, $form) {
2011
+ switch ($el.attr('type')) {
2012
+ case 'checkbox':
2013
+ return $el.is(':checked');
2014
+ case 'radio':
2015
+ return $form.find('input[name="' + $el.attr('name') + '"]').filter(':checked').length > 0;
2016
+ default:
2017
+ return $.trim(val) !== '';
2018
+ }
2019
+ },
2020
+ errorMessage: '',
2021
+ errorMessageKey: function(config) {
2022
+ if (config.errorMessagePosition === 'top' || typeof config.errorMessagePosition === 'function') {
2023
+ return 'requiredFields';
2024
+ }
2025
+ else {
2026
+ return 'requiredField';
2027
+ }
2028
+ }
2029
+ });
2030
+
2031
+ /*
2032
+ * Validate length range
2033
+ */
2034
+ $.formUtils.addValidator({
2035
+ name: 'length',
2036
+ validatorFunction: function (val, $el, conf, lang) {
2037
+ var lengthAllowed = $el.valAttr('length'),
2038
+ type = $el.attr('type');
2039
+
2040
+ if (lengthAllowed === undefined) {
2041
+ alert('Please add attribute "data-validation-length" to ' + $el[0].nodeName + ' named ' + $el.attr('name'));
2042
+ return true;
2043
+ }
2044
+
2045
+ // check if length is above min, below max or within range.
2046
+ var len = type === 'file' && $el.get(0).files !== undefined ? $el.get(0).files.length : val.length,
2047
+ lengthCheckResults = $.formUtils.numericRangeCheck(len, lengthAllowed),
2048
+ checkResult;
2049
+
2050
+ switch (lengthCheckResults[0]) { // outside of allowed range
2051
+ case 'out':
2052
+ this.errorMessage = lang.lengthBadStart + lengthAllowed + lang.lengthBadEnd;
2053
+ checkResult = false;
2054
+ break;
2055
+ // too short
2056
+ case 'min':
2057
+ this.errorMessage = lang.lengthTooShortStart + lengthCheckResults[1] + lang.lengthBadEnd;
2058
+ checkResult = false;
2059
+ break;
2060
+ // too long
2061
+ case 'max':
2062
+ this.errorMessage = lang.lengthTooLongStart + lengthCheckResults[1] + lang.lengthBadEnd;
2063
+ checkResult = false;
2064
+ break;
2065
+ // ok
2066
+ default:
2067
+ checkResult = true;
2068
+ }
2069
+
2070
+ return checkResult;
2071
+ },
2072
+ errorMessage: '',
2073
+ errorMessageKey: ''
2074
+ });
2075
+
2076
+ /*
2077
+ * Validate url
2078
+ */
2079
+ $.formUtils.addValidator({
2080
+ name: 'url',
2081
+ validatorFunction: function (url) {
2082
+ // written by Scott Gonzalez: http://projects.scottsplayground.com/iri/
2083
+ // - Victor Jonsson added support for arrays in the url ?arg[]=sdfsdf
2084
+ // - General improvements made by Stéphane Moureau <https://github.com/TraderStf>
2085
+
2086
+ var urlFilter = /^(https?|ftp):\/\/((((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])(\w|-|\.|~|[\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])(\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|\[|\]|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
2087
+ if (urlFilter.test(url)) {
2088
+ var domain = url.split('://')[1],
2089
+ domainSlashPos = domain.indexOf('/');
2090
+
2091
+ if (domainSlashPos > -1) {
2092
+ domain = domain.substr(0, domainSlashPos);
2093
+ }
2094
+
2095
+ return $.formUtils.validators.validate_domain.validatorFunction(domain); // todo: add support for IP-addresses
2096
+ }
2097
+ return false;
2098
+ },
2099
+ errorMessage: '',
2100
+ errorMessageKey: 'badUrl'
2101
+ });
2102
+
2103
+ /*
2104
+ * Validate number (floating or integer)
2105
+ */
2106
+ $.formUtils.addValidator({
2107
+ name: 'number',
2108
+ validatorFunction: function (val, $el, conf) {
2109
+ if (val !== '') {
2110
+ var allowing = $el.valAttr('allowing') || '',
2111
+ decimalSeparator = $el.valAttr('decimal-separator') || conf.decimalSeparator,
2112
+ allowsRange = false,
2113
+ begin, end,
2114
+ steps = $el.valAttr('step') || '',
2115
+ allowsSteps = false,
2116
+ sanitize = $el.attr('data-sanitize') || '',
2117
+ isFormattedWithNumeral = sanitize.match(/(^|[\s])numberFormat([\s]|$)/i);
2118
+
2119
+ if (isFormattedWithNumeral) {
2120
+ if (!window.numeral) {
2121
+ throw new ReferenceError('The data-sanitize value numberFormat cannot be used without the numeral' +
2122
+ ' library. Please see Data Validation in http://www.formvalidator.net for more information.');
2123
+ }
2124
+ //Unformat input first, then convert back to String
2125
+ if (val.length) {
2126
+ val = String(numeral().unformat(val));
2127
+ }
2128
+ }
2129
+
2130
+ if (allowing.indexOf('number') === -1) {
2131
+ allowing += ',number';
2132
+ }
2133
+
2134
+ if (allowing.indexOf('negative') === -1 && val.indexOf('-') === 0) {
2135
+ return false;
2136
+ }
2137
+
2138
+ if (allowing.indexOf('range') > -1) {
2139
+ begin = parseFloat(allowing.substring(allowing.indexOf('[') + 1, allowing.indexOf(';')));
2140
+ end = parseFloat(allowing.substring(allowing.indexOf(';') + 1, allowing.indexOf(']')));
2141
+ allowsRange = true;
2142
+ }
2143
+
2144
+ if (steps !== '') {
2145
+ allowsSteps = true;
2146
+ }
2147
+
2148
+ if (decimalSeparator === ',') {
2149
+ if (val.indexOf('.') > -1) {
2150
+ return false;
2151
+ }
2152
+ // Fix for checking range with floats using ,
2153
+ val = val.replace(',', '.');
2154
+ }
2155
+ if (val.replace(/[0-9-]/g, '') === '' && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps === 0))) {
2156
+ return true;
2157
+ }
2158
+
2159
+ if (allowing.indexOf('float') > -1 && val.match(new RegExp('^([0-9-]+)\\.([0-9]+)$')) !== null && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps === 0))) {
2160
+ return true;
2161
+ }
2162
+ }
2163
+ return false;
2164
+ },
2165
+ errorMessage: '',
2166
+ errorMessageKey: 'badInt'
2167
+ });
2168
+
2169
+ /*
2170
+ * Validate alpha numeric
2171
+ */
2172
+ $.formUtils.addValidator({
2173
+ name: 'alphanumeric',
2174
+ validatorFunction: function (val, $el, conf, language) {
2175
+ var patternStart = '^([a-zA-Z0-9',
2176
+ patternEnd = ']+)$',
2177
+ additionalChars = $el.valAttr('allowing'),
2178
+ pattern = '';
2179
+
2180
+ if (additionalChars) {
2181
+ pattern = patternStart + additionalChars + patternEnd;
2182
+ var extra = additionalChars.replace(/\\/g, '');
2183
+ if (extra.indexOf(' ') > -1) {
2184
+ extra = extra.replace(' ', '');
2185
+ extra += language.andSpaces || $.formUtils.LANG.andSpaces;
2186
+ }
2187
+ this.errorMessage = language.badAlphaNumeric + language.badAlphaNumericExtra + extra;
2188
+ } else {
2189
+ pattern = patternStart + patternEnd;
2190
+ this.errorMessage = language.badAlphaNumeric;
2191
+ }
2192
+
2193
+ return new RegExp(pattern).test(val);
2194
+ },
2195
+ errorMessage: '',
2196
+ errorMessageKey: ''
2197
+ });
2198
+
2199
+ /*
2200
+ * Validate against regexp
2201
+ */
2202
+ $.formUtils.addValidator({
2203
+ name: 'custom',
2204
+ validatorFunction: function (val, $el) {
2205
+ var regexp = new RegExp($el.valAttr('regexp'));
2206
+ return regexp.test(val);
2207
+ },
2208
+ errorMessage: '',
2209
+ errorMessageKey: 'badCustomVal'
2210
+ });
2211
+
2212
+ /*
2213
+ * Validate date
2214
+ */
2215
+ $.formUtils.addValidator({
2216
+ name: 'date',
2217
+ validatorFunction: function (date, $el, conf) {
2218
+ var dateFormat = $el.valAttr('format') || conf.dateFormat || 'yyyy-mm-dd',
2219
+ addMissingLeadingZeros = $el.valAttr('require-leading-zero') === 'false';
2220
+ return $.formUtils.parseDate(date, dateFormat, addMissingLeadingZeros) !== false;
2221
+ },
2222
+ errorMessage: '',
2223
+ errorMessageKey: 'badDate'
2224
+ });
2225
+
2226
+
2227
+ /*
2228
+ * Validate group of checkboxes, validate qty required is checked
2229
+ * written by Steve Wasiura : http://stevewasiura.waztech.com
2230
+ * element attrs
2231
+ * data-validation="checkbox_group"
2232
+ * data-validation-qty="1-2" // min 1 max 2
2233
+ * data-validation-error-msg="chose min 1, max of 2 checkboxes"
2234
+ */
2235
+ $.formUtils.addValidator({
2236
+ name: 'checkbox_group',
2237
+ validatorFunction: function (val, $el, conf, lang, $form) {
2238
+ // preset return var
2239
+ var isValid = true,
2240
+ // get name of element. since it is a checkbox group, all checkboxes will have same name
2241
+ elname = $el.attr('name'),
2242
+ // get checkboxes and count the checked ones
2243
+ $checkBoxes = $('input[type=checkbox][name^="' + elname + '"]', $form),
2244
+ checkedCount = $checkBoxes.filter(':checked').length,
2245
+ // get el attr that specs qty required / allowed
2246
+ qtyAllowed = $el.valAttr('qty');
2247
+
2248
+ if (qtyAllowed === undefined) {
2249
+ var elementType = $el.get(0).nodeName;
2250
+ alert('Attribute "data-validation-qty" is missing from ' + elementType + ' named ' + $el.attr('name'));
2251
+ }
2252
+
2253
+ // call Utility function to check if count is above min, below max, within range etc.
2254
+ var qtyCheckResults = $.formUtils.numericRangeCheck(checkedCount, qtyAllowed);
2255
+
2256
+ // results will be array, [0]=result str, [1]=qty int
2257
+ switch (qtyCheckResults[0]) {
2258
+ // outside allowed range
2259
+ case 'out':
2260
+ this.errorMessage = lang.groupCheckedRangeStart + qtyAllowed + lang.groupCheckedEnd;
2261
+ isValid = false;
2262
+ break;
2263
+ // below min qty
2264
+ case 'min':
2265
+ this.errorMessage = lang.groupCheckedTooFewStart + qtyCheckResults[1] + lang.groupCheckedEnd;
2266
+ isValid = false;
2267
+ break;
2268
+ // above max qty
2269
+ case 'max':
2270
+ this.errorMessage = lang.groupCheckedTooManyStart + qtyCheckResults[1] + lang.groupCheckedEnd;
2271
+ isValid = false;
2272
+ break;
2273
+ // ok
2274
+ default:
2275
+ isValid = true;
2276
+ }
2277
+
2278
+ if( !isValid ) {
2279
+ var _triggerOnBlur = function() {
2280
+ $checkBoxes.unbind('click', _triggerOnBlur);
2281
+ $checkBoxes.filter('*[data-validation]').validateInputOnBlur(lang, conf, false, 'blur');
2282
+ };
2283
+ $checkBoxes.bind('click', _triggerOnBlur);
2284
+ }
2285
+
2286
+ return isValid;
2287
+ }
2288
+ // errorMessage : '', // set above in switch statement
2289
+ // errorMessageKey: '' // not used
2290
+ });
2291
+
2292
+ })(jQuery);
2293
+
2294
+
2295
+ }));