jquery-form-validator-rails 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +4 -0
- data/LICENSE +24 -0
- data/README.md +51 -0
- data/Rakefile +1 -0
- data/app/assets/javascripts/date.js +1 -0
- data/app/assets/javascripts/file.js +1 -0
- data/app/assets/javascripts/html5.js +1 -0
- data/app/assets/javascripts/jquery.form-validator.js +1681 -0
- data/app/assets/javascripts/location.js +1 -0
- data/app/assets/javascripts/security.dev.js +442 -0
- data/app/assets/javascripts/security.js +1 -0
- data/app/assets/javascripts/sweden.dev.js +210 -0
- data/app/assets/javascripts/sweden.js +1 -0
- data/app/assets/javascripts/uk.dev.js +85 -0
- data/app/assets/javascripts/uk.js +1 -0
- data/jquery-form-validator.gemspec +28 -0
- data/lib/jquery-form-validator-rails.rb +1 -0
- data/lib/jquery/form/validator/rails.rb +11 -0
- data/lib/jquery/form/validator/rails/engine.rb +10 -0
- data/lib/jquery/form/validator/rails/version.rb +9 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
OTQwOGFiMjk2MTYwNGE2NGQxNzdmNDVlYWUyNGZiNDFkNjJjNzA2Yw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MzFlZDVkOWZhY2FlNzczZTk1NDkzNjcyMGRiMGVlMDc5NmE4M2Y4Ng==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZmZiMGRjYjAwYjBlOTZhMzk0NjNkMDAwYWUyNmUxZjM2Njk2OWYzYmI4YjU5
|
10
|
+
YzM1OWY5MmE4YzE3ZmNiYjE5ZWMyZTkzMTkwMDEzY2RlODdlYzI5ZGNmMWI2
|
11
|
+
ZmFkY2Q0OTM1YTU1OGRkMDY4YjY3NDViMzYxM2QxNzBiZTA1MjE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZGM1MTdhNjFkN2Q1Y2JjMTFkOTFmYTU3MDRlN2IxNjYxZmIzOTY0ZjliOWIx
|
14
|
+
OGM1OTA3M2Q4ZDkzMDM4YmYxZWQ5ODc5NTY0ZTY5ZmRlZmRiMmMwNjQ3MmUz
|
15
|
+
YjU2NjhhNWFmMzc0NzEwM2VlNGZlOGFjOGE0OWUwN2FmY2RmMTY=
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Copyright (c) 2014 Gustaf Lindqvist
|
2
|
+
|
3
|
+
jQuery Copyright (c)2012 jQuery Foundation and other contributors
|
4
|
+
|
5
|
+
MIT License
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
a copy of this software and associated documentation files (the
|
9
|
+
"Software"), to deal in the Software without restriction, including
|
10
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
permit persons to whom the Software is furnished to do so, subject to
|
13
|
+
the following conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Jquery::Form::Validator::Rails
|
2
|
+
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
Add this line to your application's Gemfile:
|
7
|
+
|
8
|
+
gem 'jquery-form-validator-rails'
|
9
|
+
|
10
|
+
And then execute:
|
11
|
+
|
12
|
+
$ bundle
|
13
|
+
|
14
|
+
Add `jquery-form-validator-rails` to your Gemfile and run `bundle install`:
|
15
|
+
|
16
|
+
gem "jquery-form-validator-rails"
|
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
|
+
### Add modules:
|
25
|
+
|
26
|
+
* security
|
27
|
+
* date
|
28
|
+
* location
|
29
|
+
* file
|
30
|
+
* sweden
|
31
|
+
* uk
|
32
|
+
|
33
|
+
Read the documentation for the modules at http://formvalidator.net
|
34
|
+
|
35
|
+
<script>
|
36
|
+
$.validate({
|
37
|
+
modules : 'security'
|
38
|
+
});
|
39
|
+
</script>
|
40
|
+
|
41
|
+
## Changes
|
42
|
+
|
43
|
+
See [CHANGELOG.md](CHANGELOG.md) in this repository for detailed changes.
|
44
|
+
|
45
|
+
## Contributing makes this repo happy!
|
46
|
+
|
47
|
+
1. Fork it
|
48
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
49
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
50
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1 @@
|
|
1
|
+
(function($){$.formUtils.addValidator({name:"time",validatorFunction:function(time){if(time.match(/^(\d{2}):(\d{2})$/)===null){return false}else{var hours=parseInt(time.split(":")[0],10);var minutes=parseInt(time.split(":")[1],10);if(hours>23||minutes>59){return false}}return true},errorMessage:"",errorMessageKey:"badTime"});$.formUtils.addValidator({name:"birthdate",validatorFunction:function(val,$el,conf){var dateFormat="yyyy-mm-dd";if($el.valAttr("format")){dateFormat=$el.valAttr("format")}else if(typeof conf.dateFormat!="undefined"){dateFormat=conf.dateFormat}var inputDate=$.formUtils.parseDate(val,dateFormat);if(!inputDate){return false}var d=new Date;var currentYear=d.getFullYear();var year=inputDate[0];var month=inputDate[1];var day=inputDate[2];if(year===currentYear){var currentMonth=d.getMonth()+1;if(month===currentMonth){var currentDay=d.getDate();return day<=currentDay}else{return month<currentMonth}}else{return year<currentYear&&year>currentYear-124}},errorMessage:"",errorMessageKey:"badDate"})})(jQuery);
|
@@ -0,0 +1 @@
|
|
1
|
+
(function($,window){var SUPPORTS_FILE_READER=typeof window.FileReader!="undefined",_getTypes=function($input){var allowedTypes=$.split(($input.valAttr("allowing")||"").toLowerCase());if($.inArray("jpg",allowedTypes)>-1&&$.inArray("jpeg",allowedTypes)==-1)allowedTypes.push("jpeg");else if($.inArray("jpeg",allowedTypes)>-1&&$.inArray("jpg",allowedTypes)==-1)allowedTypes.push("jpg");return allowedTypes};$.formUtils.addValidator({name:"mime",validatorFunction:function(str,$input){var files=$input.get(0).files||[];if(SUPPORTS_FILE_READER){var valid=true,mime="",allowedTypes=_getTypes($input);$.each(files,function(i,file){valid=false;mime=file.type||"";$.each(allowedTypes,function(j,type){valid=mime.indexOf(type)>-1;if(valid){return false}});return valid});return valid}else{return $.formUtils.validators.validate_extension.validatorFunction(str,$input)}},errorMessage:"The file you are trying to upload is of wrong type",errorMessageKey:"wrongFileType"});$.formUtils.addValidator({name:"extension",validatorFunction:function(value,$input){var valid=true,types=_getTypes($input);$.each($input.get(0).files||[],function(i,file){var val=file.value,ext=val.substr(val.lastIndexOf(".")+1);if($.inArray(ext.toLowerCase(),types)==-1){valid=false;return false}});return valid},errorMessage:"The file you are trying to upload is of wrong type",errorMessageKey:"wrongFileType"});$.formUtils.addValidator({name:"size",validatorFunction:function(val,$input){var maxSize=$input.valAttr("max-size");if(!maxSize){console.log('Input "'+$input.attr("name")+'" is missing data-validation-max-size attribute');return true}else if(!SUPPORTS_FILE_READER){return true}var maxBytes=$.formUtils.convertSizeNameToBytes(maxSize),valid=true;$.each($input.get(0).files||[],function(i,file){valid=file.size<=maxBytes;return valid});return valid},errorMessage:"The file you are trying to upload is too large",errorMessageKey:"wrongFileSize"});$.formUtils.convertSizeNameToBytes=function(sizeName){sizeName=sizeName.toUpperCase();if(sizeName.substr(sizeName.length-1,1)=="M"){return parseInt(sizeName.substr(0,sizeName.length-1),10)*1024*1024}else if(sizeName.substr(sizeName.length-2,2)=="MB"){return parseInt(sizeName.substr(0,sizeName.length-2),10)*1024*1024}else if(sizeName.substr(sizeName.length-2,2)=="KB"){return parseInt(sizeName.substr(0,sizeName.length-2),10)*1024}else if(sizeName.substr(sizeName.length-1,1)=="B"){return parseInt(sizeName.substr(0,sizeName.length-1),10)}else{return parseInt(sizeName,10)}};$(window).one("validatorsLoaded formValidationSetup",function(evt,$form){var $inputs;if($form){$inputs=$form.find('input[type="file"]')}else{$inputs=$('input[type="file"]')}$inputs.filter("*[data-validation]").bind("change",function(){$(this).removeClass("error").parent().find(".form-error").remove()})})})(jQuery,window);
|
@@ -0,0 +1 @@
|
|
1
|
+
(function($,window){"use strict";var SUPPORTS_PLACEHOLDER="placeholder"in document.createElement("INPUT"),SUPPORTS_DATALIST="options"in document.createElement("DATALIST");$(window).bind("validatorsLoaded formValidationSetup",function(evt,$form){if(!$form){$form=$("form")}var hasLoadedDateModule=false;$form.each(function(){var $f=$(this),$formInputs=$f.find("input,textarea,select"),foundHtml5Rule=false;$formInputs.each(function(){var validation=[],$input=$(this),isRequired=$input.attr("required"),attrs={};switch(($input.attr("type")||"").toLowerCase()){case"time":validation.push("time");if(!$.formUtils.validators.validate_date&&!hasLoadedDateModule){hasLoadedDateModule=true;$.formUtils.loadModules("date")}break;case"url":validation.push("url");break;case"email":validation.push("email");break;case"date":validation.push("date");break;case"number":validation.push("number");var max=$input.attr("max"),min=$input.attr("min");if(min||max){if(!min)min=0;if(!max)max=9007199254740992;attrs["data-validation-allowing"]="range["+min+";"+max+"]";if(min.indexOf("-")===0||max.indexOf("-")===0){attrs["data-validation-allowing"]+=",negative"}if(min.indexOf(".")>-1||max.indexOf(".")>-1){attrs["data-validation-allowing"]+=",float"}}break}if($input.attr("pattern")){validation.push("custom");attrs["data-validation-regexp"]=$input.attr("pattern")}if($input.attr("maxlength")){validation.push("length");attrs["data-validation-length"]="max"+$input.attr("maxlength")}console.log($input.html());if(!SUPPORTS_DATALIST&&$input.attr("list")){console.log($input.attr("list"));var suggestions=[];$("#"+$input.attr("list")+" option").each(function(){var $opt=$(this);suggestions.push($opt.attr("value")||$opt.text())});$.formUtils.suggest($input,suggestions)}if(validation.length){if(!isRequired){attrs["data-validation-optional"]="true"}foundHtml5Rule=true;$input.attr("data-validation",validation.join(" "));$.each(attrs,function(attrName,attrVal){$input.attr(attrName,attrVal)})}});if(foundHtml5Rule){$f.trigger("html5ValidationAttrsFound")}if(!SUPPORTS_PLACEHOLDER){$formInputs.filter("input[placeholder]").each(function(){this.defaultValue=this.getAttribute("placeholder");$(this).bind("focus",function(){if(this.value==this.defaultValue){this.value="";$(this).removeClass("showing-placeholder")}}).bind("blur",function(){if($.trim(this.value)==""){this.value=this.defaultValue;$(this).addClass("showing-placeholder")}})})}})})})(jQuery,window);
|
@@ -0,0 +1,1681 @@
|
|
1
|
+
/**
|
2
|
+
* jQuery Form Validator
|
3
|
+
* ------------------------------------------
|
4
|
+
* Created by Victor Jonsson <http://www.victorjonsson.se>
|
5
|
+
*
|
6
|
+
* @website http://formvalidator.net/
|
7
|
+
* @license Dual licensed under the MIT or GPL Version 2 licenses
|
8
|
+
* @version 2.1.66
|
9
|
+
*/
|
10
|
+
(function($) {
|
11
|
+
|
12
|
+
'use strict';
|
13
|
+
|
14
|
+
var $window = $(window),
|
15
|
+
_applyErrorStyle = function($elem, conf) {
|
16
|
+
$elem
|
17
|
+
.addClass(conf.errorElementClass)
|
18
|
+
.removeClass('valid')
|
19
|
+
.parent()
|
20
|
+
.addClass('has-error')
|
21
|
+
.removeClass('has-success'); // twitter bs
|
22
|
+
|
23
|
+
if(conf.borderColorOnError !== '') {
|
24
|
+
$elem.css('border-color', conf.borderColorOnError);
|
25
|
+
}
|
26
|
+
},
|
27
|
+
_removeErrorStyle = function($elem, conf) {
|
28
|
+
$elem.each(function() {
|
29
|
+
_setInlineErrorMessage($(this), '', conf, conf.errorMessagePosition);
|
30
|
+
$(this)
|
31
|
+
.removeClass('valid')
|
32
|
+
.removeClass(conf.errorElementClass)
|
33
|
+
.css('border-color', '')
|
34
|
+
.parent()
|
35
|
+
.removeClass('has-error')
|
36
|
+
.removeClass('has-success')
|
37
|
+
.find('.'+conf.errorMessageClass) // remove inline error message
|
38
|
+
.remove();
|
39
|
+
});
|
40
|
+
},
|
41
|
+
_setInlineErrorMessage = function($input, mess, conf, $messageContainer) {
|
42
|
+
var custom = _getInlineErrorElement($input);
|
43
|
+
if( custom ) {
|
44
|
+
custom.innerHTML = mess;
|
45
|
+
}
|
46
|
+
else if( typeof $messageContainer == 'object' ) {
|
47
|
+
var $found = false;
|
48
|
+
$messageContainer.find('.'+conf.errorMessageClass).each(function() {
|
49
|
+
if( this.inputReferer == $input[0] ) {
|
50
|
+
$found = $(this);
|
51
|
+
return false;
|
52
|
+
}
|
53
|
+
});
|
54
|
+
if( $found ) {
|
55
|
+
if( !mess ) {
|
56
|
+
$found.remove();
|
57
|
+
} else {
|
58
|
+
$found.html(mess);
|
59
|
+
}
|
60
|
+
} else {
|
61
|
+
var $mess = $('<div class="'+conf.errorMessageClass+'">'+mess+'</div>');
|
62
|
+
$mess[0].inputReferer = $input[0];
|
63
|
+
$messageContainer.prepend($mess);
|
64
|
+
}
|
65
|
+
}
|
66
|
+
else {
|
67
|
+
var $mess = $input.parent().find('.'+conf.errorMessageClass+'.help-block');
|
68
|
+
if( $mess.length == 0 ) {
|
69
|
+
$mess = $('<span></span>').addClass('help-block').addClass(conf.errorMessageClass);
|
70
|
+
$mess.appendTo($input.parent());
|
71
|
+
}
|
72
|
+
$mess.html(mess);
|
73
|
+
}
|
74
|
+
},
|
75
|
+
_getInlineErrorElement = function($input, conf) {
|
76
|
+
return document.getElementById($input.attr('name')+'_err_msg');
|
77
|
+
},
|
78
|
+
_templateMessage = function($form, title, errorMessages, conf) {
|
79
|
+
var messages = conf.errorMessageTemplate.messages.replace(/\{errorTitle\}/g, title);
|
80
|
+
var fields = [];
|
81
|
+
$.each(errorMessages, function(i, msg) {
|
82
|
+
fields.push(conf.errorMessageTemplate.field.replace(/\{msg\}/g, msg));
|
83
|
+
});
|
84
|
+
messages = messages.replace(/\{fields\}/g, fields.join(''));
|
85
|
+
var container = conf.errorMessageTemplate.container.replace(/\{errorMessageClass\}/g, conf.errorMessageClass);
|
86
|
+
container = container.replace(/\{messages\}/g, messages);
|
87
|
+
$form.children().eq(0).before(container);
|
88
|
+
};
|
89
|
+
|
90
|
+
/**
|
91
|
+
* Assigns validateInputOnBlur function to elements blur event
|
92
|
+
*
|
93
|
+
* @param {Object} language Optional, will override $.formUtils.LANG
|
94
|
+
* @param {Object} settings Optional, will override the default settings
|
95
|
+
* @return {jQuery}
|
96
|
+
*/
|
97
|
+
$.fn.validateOnBlur = function(language, settings) {
|
98
|
+
this.find('input[data-validation],textarea[data-validation],select[data-validation]')
|
99
|
+
.bind('blur.validation', function() {
|
100
|
+
$(this).validateInputOnBlur(language, settings);
|
101
|
+
});
|
102
|
+
|
103
|
+
return this;
|
104
|
+
};
|
105
|
+
|
106
|
+
/*
|
107
|
+
* Assigns validateInputOnBlur function to elements custom event
|
108
|
+
* @param {Object} language Optional, will override $.formUtils.LANG
|
109
|
+
* @param {Object} settings Optional, will override the default settings
|
110
|
+
* * @return {jQuery}
|
111
|
+
*/
|
112
|
+
$.fn.validateOnEvent = function(language, settings) {
|
113
|
+
this.find('input[data-validation][data-validation-event],textarea[data-validation][data-validation-event],select[data-validation][data-validation-event]')
|
114
|
+
.each(function(){
|
115
|
+
var $el = $(this),
|
116
|
+
etype = $el.attr("data-validation-event");
|
117
|
+
if (etype){
|
118
|
+
$el.bind(etype + ".validation", function(){
|
119
|
+
$(this).validateInputOnBlur(language, settings, false, etype);
|
120
|
+
});
|
121
|
+
}
|
122
|
+
});
|
123
|
+
return this;
|
124
|
+
};
|
125
|
+
|
126
|
+
/**
|
127
|
+
* fade in help message when input gains focus
|
128
|
+
* fade out when input loses focus
|
129
|
+
* <input data-help="The info that I want to display for the user when input is focused" ... />
|
130
|
+
*
|
131
|
+
* @param {String} attrName - Optional, default is data-help
|
132
|
+
* @return {jQuery}
|
133
|
+
*/
|
134
|
+
$.fn.showHelpOnFocus = function(attrName) {
|
135
|
+
if(!attrName) {
|
136
|
+
attrName = 'data-validation-help';
|
137
|
+
}
|
138
|
+
|
139
|
+
// Remove previously added event listeners
|
140
|
+
this.find('.has-help-txt')
|
141
|
+
.valAttr('has-keyup-event', false)
|
142
|
+
.valAttr('backend-valid', false)
|
143
|
+
.valAttr('backend-invalid', false)
|
144
|
+
.removeClass('has-help-txt');
|
145
|
+
|
146
|
+
// Add help text listeners
|
147
|
+
this.find('textarea,input').each(function() {
|
148
|
+
var $elem = $(this),
|
149
|
+
className = 'jquery_form_help_' + ($elem.attr('name') || '').replace( /(:|\.|\[|\])/g, "" ),
|
150
|
+
help = $elem.attr(attrName);
|
151
|
+
|
152
|
+
if(help) {
|
153
|
+
$elem
|
154
|
+
.addClass('has-help-txt')
|
155
|
+
.unbind('focus.help')
|
156
|
+
.bind('focus.help', function() {
|
157
|
+
var $help = $elem.parent().find('.'+className);
|
158
|
+
if($help.length == 0) {
|
159
|
+
$help = $('<span />')
|
160
|
+
.addClass(className)
|
161
|
+
.addClass('help')
|
162
|
+
.addClass('help-block') // twitter bs
|
163
|
+
.text(help)
|
164
|
+
.hide();
|
165
|
+
|
166
|
+
$elem.after($help);
|
167
|
+
|
168
|
+
}
|
169
|
+
$help.fadeIn();
|
170
|
+
})
|
171
|
+
.unbind('blur.help')
|
172
|
+
.bind('blur.help', function() {
|
173
|
+
$(this)
|
174
|
+
.parent()
|
175
|
+
.find('.'+className)
|
176
|
+
.fadeOut('slow');
|
177
|
+
});
|
178
|
+
}
|
179
|
+
});
|
180
|
+
|
181
|
+
return this;
|
182
|
+
};
|
183
|
+
|
184
|
+
/**
|
185
|
+
* Validate single input when it loses focus
|
186
|
+
* shows error message in a span element
|
187
|
+
* that is appended to the parent element
|
188
|
+
*
|
189
|
+
* @param {Object} [language] Optional, will override $.formUtils.LANG
|
190
|
+
* @param {Object} [conf] Optional, will override the default settings
|
191
|
+
* @param {Boolean} [attachKeyupEvent] Optional
|
192
|
+
* @param {String} [eventContext]
|
193
|
+
* @return {jQuery}
|
194
|
+
*/
|
195
|
+
$.fn.validateInputOnBlur = function(language, conf, attachKeyupEvent, eventContext) {
|
196
|
+
if(attachKeyupEvent === undefined)
|
197
|
+
attachKeyupEvent = true;
|
198
|
+
if(!eventContext)
|
199
|
+
eventContext = 'blur';
|
200
|
+
|
201
|
+
if( (this.valAttr('suggestion-nr') || this.valAttr('postpone') || this.hasClass('hasDatepicker')) && !window.postponedValidation ) {
|
202
|
+
// This validation has to be postponed
|
203
|
+
var _self = this,
|
204
|
+
postponeTime = this.valAttr('postpone') || 200;
|
205
|
+
|
206
|
+
window.postponedValidation = function() {
|
207
|
+
_self.validateInputOnBlur(language, conf, attachKeyupEvent);
|
208
|
+
window.postponedValidation = false;
|
209
|
+
};
|
210
|
+
setTimeout(function() {
|
211
|
+
if( window.postponedValidation ) {
|
212
|
+
window.postponedValidation();
|
213
|
+
}
|
214
|
+
}, postponeTime);
|
215
|
+
|
216
|
+
return this;
|
217
|
+
}
|
218
|
+
|
219
|
+
language = $.extend({}, $.formUtils.LANG, language || {});
|
220
|
+
_removeErrorStyle(this, conf);
|
221
|
+
|
222
|
+
var $elem = this,
|
223
|
+
$form = $elem.closest("form"),
|
224
|
+
validationRule = $elem.attr(conf.validationRuleAttribute),
|
225
|
+
validation = $.formUtils.validateInput(
|
226
|
+
$elem,
|
227
|
+
language,
|
228
|
+
$.extend({}, conf, {errorMessagePosition:'element'}),
|
229
|
+
$form,
|
230
|
+
eventContext
|
231
|
+
);
|
232
|
+
|
233
|
+
$elem.trigger('validation', [validation===null ? null : validation===true]);
|
234
|
+
|
235
|
+
if(validation === true) {
|
236
|
+
$elem
|
237
|
+
.addClass('valid')
|
238
|
+
.parent()
|
239
|
+
.addClass('has-success'); // twitter bs
|
240
|
+
} else if(validation !== null) {
|
241
|
+
|
242
|
+
_applyErrorStyle($elem, conf);
|
243
|
+
_setInlineErrorMessage($elem, validation, conf, conf.errorMessagePosition);
|
244
|
+
|
245
|
+
if(attachKeyupEvent) {
|
246
|
+
$elem.bind('keyup', function() {
|
247
|
+
$(this).validateInputOnBlur(language, conf, false, 'keyup');
|
248
|
+
});
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
return this;
|
253
|
+
};
|
254
|
+
|
255
|
+
/**
|
256
|
+
* Short hand for fetching/adding/removing element attributes
|
257
|
+
* prefixed with 'data-validation-'
|
258
|
+
*
|
259
|
+
* @param {String} name
|
260
|
+
* @param {String|Boolean} [val]
|
261
|
+
* @return string|undefined
|
262
|
+
* @protected
|
263
|
+
*/
|
264
|
+
$.fn.valAttr = function(name, val) {
|
265
|
+
if( val === undefined ) {
|
266
|
+
return this.attr('data-validation-'+name);
|
267
|
+
} else if( val === false || val === null ) {
|
268
|
+
return this.removeAttr('data-validation-'+name);
|
269
|
+
} else {
|
270
|
+
if(name.length > 0) name='-'+name;
|
271
|
+
return this.attr('data-validation'+name, val);
|
272
|
+
}
|
273
|
+
};
|
274
|
+
|
275
|
+
/**
|
276
|
+
* Function that validate all inputs in given element
|
277
|
+
*
|
278
|
+
* @param {Object} [language]
|
279
|
+
* @param {Object} [conf]
|
280
|
+
* @param {Boolean} [displayError] Defaults to true
|
281
|
+
*/
|
282
|
+
$.fn.isValid = function(language, conf, displayError) {
|
283
|
+
|
284
|
+
if ($.formUtils.isLoadingModules) {
|
285
|
+
var $self = this;
|
286
|
+
setTimeout(function () {
|
287
|
+
$self.isValid(language, conf, displayError);
|
288
|
+
}, 200);
|
289
|
+
return null;
|
290
|
+
}
|
291
|
+
|
292
|
+
conf = $.extend({}, $.formUtils.defaultConfig(), conf || {});
|
293
|
+
language = $.extend({}, $.formUtils.LANG, language || {});
|
294
|
+
displayError = displayError !== false;
|
295
|
+
|
296
|
+
$.formUtils.isValidatingEntireForm = true;
|
297
|
+
$.formUtils.haltValidation = false;
|
298
|
+
|
299
|
+
/**
|
300
|
+
* Adds message to error message stack if not already in the message stack
|
301
|
+
*
|
302
|
+
* @param {String} mess
|
303
|
+
* @para {jQuery} $elem
|
304
|
+
*/
|
305
|
+
var addErrorMessage = function(mess, $elem) {
|
306
|
+
// validate server side will return null as error message before the server is requested
|
307
|
+
if(mess !== null) {
|
308
|
+
if ($.inArray(mess, errorMessages) < 0) {
|
309
|
+
errorMessages.push(mess);
|
310
|
+
}
|
311
|
+
errorInputs.push($elem);
|
312
|
+
$elem.attr('current-error', mess);
|
313
|
+
if( displayError )
|
314
|
+
_applyErrorStyle($elem, conf);
|
315
|
+
}
|
316
|
+
},
|
317
|
+
|
318
|
+
/** Error messages for this validation */
|
319
|
+
errorMessages = [],
|
320
|
+
|
321
|
+
/** Input elements which value was not valid */
|
322
|
+
errorInputs = [],
|
323
|
+
|
324
|
+
/** Form instance */
|
325
|
+
$form = this,
|
326
|
+
|
327
|
+
/**
|
328
|
+
* Tells whether or not to validate element with this name and of this type
|
329
|
+
*
|
330
|
+
* @param {String} name
|
331
|
+
* @param {String} type
|
332
|
+
* @return {Boolean}
|
333
|
+
*/
|
334
|
+
ignoreInput = function(name, type) {
|
335
|
+
if (type === 'submit' || type === 'button' || type == 'reset') {
|
336
|
+
return true;
|
337
|
+
}
|
338
|
+
return $.inArray(name, conf.ignore || []) > -1;
|
339
|
+
};
|
340
|
+
|
341
|
+
// Reset style and remove error class
|
342
|
+
if( displayError ) {
|
343
|
+
$form.find('.'+conf.errorMessageClass+'.alert').remove();
|
344
|
+
_removeErrorStyle($form.find('.'+conf.errorElementClass+',.valid'), conf);
|
345
|
+
}
|
346
|
+
|
347
|
+
// Validate element values
|
348
|
+
$form.find('input,textarea,select').filter(':not([type="submit"],[type="button"])').each(function() {
|
349
|
+
var $elem = $(this);
|
350
|
+
var elementType = $elem.attr('type');
|
351
|
+
if (!ignoreInput($elem.attr('name'), elementType)) {
|
352
|
+
|
353
|
+
var validation = $.formUtils.validateInput(
|
354
|
+
$elem,
|
355
|
+
language,
|
356
|
+
conf,
|
357
|
+
$form,
|
358
|
+
'submit'
|
359
|
+
);
|
360
|
+
|
361
|
+
$elem.trigger('validation', [validation===true]);
|
362
|
+
|
363
|
+
// Run element validation callback
|
364
|
+
if( typeof conf.onElementValidate == 'function' ) {
|
365
|
+
conf.onElementValidate((validation === true), $elem, $form, validation);
|
366
|
+
}
|
367
|
+
|
368
|
+
if(validation !== true) {
|
369
|
+
addErrorMessage(validation, $elem);
|
370
|
+
} else {
|
371
|
+
$elem
|
372
|
+
.valAttr('current-error', false)
|
373
|
+
.addClass('valid')
|
374
|
+
.parent()
|
375
|
+
.addClass('has-success');
|
376
|
+
}
|
377
|
+
}
|
378
|
+
|
379
|
+
});
|
380
|
+
|
381
|
+
// Run validation callback
|
382
|
+
if( typeof conf.onValidate == 'function' ) {
|
383
|
+
var errors = conf.onValidate($form);
|
384
|
+
if( $.isArray(errors) ) {
|
385
|
+
$.each(errors, function(i, err) {
|
386
|
+
addErrorMessage(err.message, err.element);
|
387
|
+
});
|
388
|
+
}
|
389
|
+
else if( errors && errors.element && errors.message ) {
|
390
|
+
addErrorMessage(errors.message, errors.element);
|
391
|
+
}
|
392
|
+
}
|
393
|
+
|
394
|
+
// Reset form validation flag
|
395
|
+
$.formUtils.isValidatingEntireForm = false;
|
396
|
+
|
397
|
+
// Validation failed
|
398
|
+
if ( !$.formUtils.haltValidation && errorInputs.length > 0 ) {
|
399
|
+
|
400
|
+
if( displayError ) {
|
401
|
+
// display all error messages in top of form
|
402
|
+
if (conf.errorMessagePosition === 'top') {
|
403
|
+
_templateMessage($form, language.errorTitle, errorMessages, conf);
|
404
|
+
}
|
405
|
+
// Customize display message
|
406
|
+
else if(conf.errorMessagePosition === 'custom') {
|
407
|
+
if( typeof conf.errorMessageCustom === 'function' ) {
|
408
|
+
conf.errorMessageCustom($form, language.errorTitle, errorMessages, conf);
|
409
|
+
}
|
410
|
+
}
|
411
|
+
// Display error message below input field or in defined container
|
412
|
+
else {
|
413
|
+
$.each(errorInputs, function(i, $input) {
|
414
|
+
_setInlineErrorMessage($input, $input.attr('current-error'), conf, conf.errorMessagePosition);
|
415
|
+
});
|
416
|
+
}
|
417
|
+
|
418
|
+
if(conf.scrollToTopOnError) {
|
419
|
+
$window.scrollTop($form.offset().top - 20);
|
420
|
+
}
|
421
|
+
}
|
422
|
+
|
423
|
+
return false;
|
424
|
+
}
|
425
|
+
|
426
|
+
return !$.formUtils.haltValidation;
|
427
|
+
};
|
428
|
+
|
429
|
+
/**
|
430
|
+
* @deprecated
|
431
|
+
* @param language
|
432
|
+
* @param conf
|
433
|
+
*/
|
434
|
+
$.fn.validateForm = function(language, conf) {
|
435
|
+
if( window.console && typeof window.console.warn == 'function' ) {
|
436
|
+
window.console.warn('Use of deprecated function $.validateForm, use $.isValid instead');
|
437
|
+
}
|
438
|
+
return this.isValid(language, conf, true);
|
439
|
+
}
|
440
|
+
|
441
|
+
/**
|
442
|
+
* Plugin for displaying input length restriction
|
443
|
+
*/
|
444
|
+
$.fn.restrictLength = function(maxLengthElement) {
|
445
|
+
new $.formUtils.lengthRestriction(this, maxLengthElement);
|
446
|
+
return this;
|
447
|
+
};
|
448
|
+
|
449
|
+
/**
|
450
|
+
* Add suggestion dropdown to inputs having data-suggestions with a comma
|
451
|
+
* separated string with suggestions
|
452
|
+
* @param {Array} [settings]
|
453
|
+
* @returns {jQuery}
|
454
|
+
*/
|
455
|
+
$.fn.addSuggestions = function(settings) {
|
456
|
+
var sugs = false;
|
457
|
+
this.find('input').each(function() {
|
458
|
+
var $field = $(this);
|
459
|
+
|
460
|
+
sugs = $.split($field.attr('data-suggestions'));
|
461
|
+
|
462
|
+
if( sugs.length > 0 && !$field.hasClass('has-suggestions') ) {
|
463
|
+
$.formUtils.suggest($field, sugs, settings);
|
464
|
+
$field.addClass('has-suggestions');
|
465
|
+
}
|
466
|
+
});
|
467
|
+
return this;
|
468
|
+
};
|
469
|
+
|
470
|
+
/**
|
471
|
+
* A bit smarter split function
|
472
|
+
* @param {String} val
|
473
|
+
* @param {Function|String} [func]
|
474
|
+
* @param {String} [delim]
|
475
|
+
* @returns {Array|void}
|
476
|
+
*/
|
477
|
+
$.split = function(val, func, delim) {
|
478
|
+
if( typeof func != 'function' ) {
|
479
|
+
// return string
|
480
|
+
if( !val )
|
481
|
+
return [];
|
482
|
+
var values = [];
|
483
|
+
$.each(val.split(func ? func:','), function(i,str) {
|
484
|
+
str = $.trim(str);
|
485
|
+
if( str.length )
|
486
|
+
values.push(str);
|
487
|
+
});
|
488
|
+
return values;
|
489
|
+
} else if( val ) {
|
490
|
+
// use callback on each
|
491
|
+
if( !delim )
|
492
|
+
delim = ',';
|
493
|
+
$.each(val.split(delim), function(i, str) {
|
494
|
+
str = $.trim(str);
|
495
|
+
if( str.length )
|
496
|
+
return func(str, i);
|
497
|
+
});
|
498
|
+
}
|
499
|
+
};
|
500
|
+
|
501
|
+
/**
|
502
|
+
* Short hand function that makes the validation setup require less code
|
503
|
+
* @param conf
|
504
|
+
*/
|
505
|
+
$.validate = function(conf) {
|
506
|
+
|
507
|
+
var defaultConf = $.extend($.formUtils.defaultConfig(), {
|
508
|
+
form : 'form',
|
509
|
+
/*
|
510
|
+
* Enable custom event for validation
|
511
|
+
*/
|
512
|
+
validateOnEvent : true,
|
513
|
+
validateOnBlur : true,
|
514
|
+
showHelpOnFocus : true,
|
515
|
+
addSuggestions : true,
|
516
|
+
modules : '',
|
517
|
+
onModulesLoaded : null,
|
518
|
+
language : false,
|
519
|
+
onSuccess : false,
|
520
|
+
onError : false,
|
521
|
+
onElementValidate : false
|
522
|
+
});
|
523
|
+
|
524
|
+
conf = $.extend(defaultConf, conf || {});
|
525
|
+
|
526
|
+
// Add validation to forms
|
527
|
+
$.split(conf.form, function(formQuery) {
|
528
|
+
|
529
|
+
var $form = $(formQuery);
|
530
|
+
$window.trigger('formValidationSetup', [$form]);
|
531
|
+
|
532
|
+
// Remove all event listeners previously added
|
533
|
+
$form.find('.has-help-txt')
|
534
|
+
.unbind('focus.validation')
|
535
|
+
.unbind('blur.validation');
|
536
|
+
$form
|
537
|
+
.removeClass('has-validation-callback')
|
538
|
+
.unbind('submit.validation')
|
539
|
+
.unbind('reset.validation')
|
540
|
+
.find('input[data-validation],textarea[data-validation]')
|
541
|
+
.unbind('blur.validation');
|
542
|
+
|
543
|
+
// Validate when submitted
|
544
|
+
$form.bind('submit.validation', function() {
|
545
|
+
var $form = $(this);
|
546
|
+
|
547
|
+
if($.formUtils.isLoadingModules) {
|
548
|
+
setTimeout(function() {
|
549
|
+
$form.trigger('submit.validation');
|
550
|
+
}, 200);
|
551
|
+
return false;
|
552
|
+
}
|
553
|
+
var valid = $form.isValid(conf.language, conf);
|
554
|
+
if( valid && typeof conf.onSuccess == 'function') {
|
555
|
+
var callbackResponse = conf.onSuccess($form);
|
556
|
+
if( callbackResponse === false )
|
557
|
+
return false;
|
558
|
+
} else if ( !valid && typeof conf.onError == 'function' ) {
|
559
|
+
conf.onError($form);
|
560
|
+
return false;
|
561
|
+
} else {
|
562
|
+
return valid;
|
563
|
+
}
|
564
|
+
})
|
565
|
+
.bind('reset.validation', function() {
|
566
|
+
// remove messages
|
567
|
+
$(this).find('.'+conf.errorMessageClass+'.alert').remove();
|
568
|
+
_removeErrorStyle($(this).find('.'+conf.errorElementClass+',.valid'), conf);
|
569
|
+
})
|
570
|
+
.addClass('has-validation-callback');
|
571
|
+
|
572
|
+
if( conf.showHelpOnFocus ) {
|
573
|
+
$form.showHelpOnFocus();
|
574
|
+
}
|
575
|
+
if( conf.addSuggestions ) {
|
576
|
+
$form.addSuggestions();
|
577
|
+
}
|
578
|
+
if( conf.validateOnBlur ) {
|
579
|
+
$form.validateOnBlur(conf.language, conf);
|
580
|
+
$form.bind('html5ValidationAttrsFound', function() {
|
581
|
+
$form.validateOnBlur(conf.language, conf);
|
582
|
+
})
|
583
|
+
}
|
584
|
+
if( conf.validateOnEvent ){
|
585
|
+
$form.validateOnEvent(conf.language, conf);
|
586
|
+
}
|
587
|
+
|
588
|
+
});
|
589
|
+
|
590
|
+
if( conf.modules != '' ) {
|
591
|
+
if( typeof conf.onModulesLoaded == 'function' ) {
|
592
|
+
$window.one('validatorsLoaded', conf.onModulesLoaded);
|
593
|
+
}
|
594
|
+
$.formUtils.loadModules(conf.modules);
|
595
|
+
}
|
596
|
+
};
|
597
|
+
|
598
|
+
/**
|
599
|
+
* Object containing utility methods for this plugin
|
600
|
+
*/
|
601
|
+
$.formUtils = {
|
602
|
+
|
603
|
+
/**
|
604
|
+
* Default config for $(...).isValid();
|
605
|
+
*/
|
606
|
+
defaultConfig : function() {
|
607
|
+
return {
|
608
|
+
ignore : [], // Names of inputs not to be validated even though node attribute containing the validation rules tells us to
|
609
|
+
errorElementClass : 'error', // Class that will be put on elements which value is invalid
|
610
|
+
borderColorOnError : 'red', // Border color of elements which value is invalid, empty string to not change border color
|
611
|
+
errorMessageClass : 'form-error', // class name of div containing error messages when validation fails
|
612
|
+
validationRuleAttribute : 'data-validation', // name of the attribute holding the validation rules
|
613
|
+
validationErrorMsgAttribute : 'data-validation-error-msg', // define custom err msg inline with element
|
614
|
+
errorMessagePosition : 'element', // Can be either "top" or "element" or "custom"
|
615
|
+
errorMessageTemplate : {
|
616
|
+
container: '<div class="{errorMessageClass} alert alert-danger">{messages}</div>',
|
617
|
+
messages: '<strong>{errorTitle}</strong><ul>{fields}</ul>',
|
618
|
+
field: '<li>{msg}</li>'
|
619
|
+
},
|
620
|
+
errorMessageCustom: _templateMessage,
|
621
|
+
scrollToTopOnError : true,
|
622
|
+
dateFormat : 'yyyy-mm-dd',
|
623
|
+
addValidClassOnAll : false, // whether or not to apply class="valid" even if the input wasn't validated
|
624
|
+
decimalSeparator : '.'
|
625
|
+
}
|
626
|
+
},
|
627
|
+
|
628
|
+
/**
|
629
|
+
* Available validators
|
630
|
+
*/
|
631
|
+
validators : {},
|
632
|
+
|
633
|
+
/**
|
634
|
+
* Events triggered by form validator
|
635
|
+
*/
|
636
|
+
_events : {load : [], valid: [], invalid:[]},
|
637
|
+
|
638
|
+
/**
|
639
|
+
* Setting this property to true during validation will
|
640
|
+
* stop further validation from taking place and form will
|
641
|
+
* not be sent
|
642
|
+
*/
|
643
|
+
haltValidation : false,
|
644
|
+
|
645
|
+
/**
|
646
|
+
* This variable will be true $.fn.isValid() is called
|
647
|
+
* and false when $.fn.validateOnBlur is called
|
648
|
+
*/
|
649
|
+
isValidatingEntireForm : false,
|
650
|
+
|
651
|
+
/**
|
652
|
+
* Function for adding a validator
|
653
|
+
* @param {Object} validator
|
654
|
+
*/
|
655
|
+
addValidator : function(validator) {
|
656
|
+
// prefix with "validate_" for backward compatibility reasons
|
657
|
+
var name = validator.name.indexOf('validate_') === 0 ? validator.name : 'validate_'+validator.name;
|
658
|
+
if( validator.validateOnKeyUp === undefined )
|
659
|
+
validator.validateOnKeyUp = true;
|
660
|
+
this.validators[name] = validator;
|
661
|
+
},
|
662
|
+
|
663
|
+
/**
|
664
|
+
* @var {Boolean}
|
665
|
+
*/
|
666
|
+
isLoadingModules : false,
|
667
|
+
|
668
|
+
/**
|
669
|
+
* @var {Object}
|
670
|
+
*/
|
671
|
+
loadedModules : {},
|
672
|
+
|
673
|
+
/**
|
674
|
+
* @example
|
675
|
+
* $.formUtils.loadModules('date, security.dev');
|
676
|
+
*
|
677
|
+
* Will load the scripts date.js and security.dev.js from the
|
678
|
+
* directory where this script resides. If you want to load
|
679
|
+
* the modules from another directory you can use the
|
680
|
+
* path argument.
|
681
|
+
*
|
682
|
+
* The script will be cached by the browser unless the module
|
683
|
+
* name ends with .dev
|
684
|
+
*
|
685
|
+
* @param {String} modules - Comma separated string with module file names (no directory nor file extension)
|
686
|
+
* @param {String} [path] - Optional, path where the module files is located if their not in the same directory as the core modules
|
687
|
+
* @param {Boolean} [fireEvent] - Optional, whether or not to fire event 'load' when modules finished loading
|
688
|
+
*/
|
689
|
+
loadModules : function(modules, path, fireEvent) {
|
690
|
+
|
691
|
+
if( fireEvent === undefined )
|
692
|
+
fireEvent = true;
|
693
|
+
|
694
|
+
if( $.formUtils.isLoadingModules ) {
|
695
|
+
setTimeout(function() {
|
696
|
+
$.formUtils.loadModules(modules, path, fireEvent);
|
697
|
+
});
|
698
|
+
return;
|
699
|
+
}
|
700
|
+
|
701
|
+
var hasLoadedAnyModule = false,
|
702
|
+
loadModuleScripts = function(modules, path) {
|
703
|
+
|
704
|
+
var moduleList = $.split(modules),
|
705
|
+
numModules = moduleList.length,
|
706
|
+
moduleLoadedCallback = function() {
|
707
|
+
numModules--;
|
708
|
+
if( numModules == 0 ) {
|
709
|
+
$.formUtils.isLoadingModules = false;
|
710
|
+
if( fireEvent && hasLoadedAnyModule ) {
|
711
|
+
$window.trigger('validatorsLoaded');
|
712
|
+
}
|
713
|
+
}
|
714
|
+
};
|
715
|
+
|
716
|
+
if( numModules > 0 ) {
|
717
|
+
$.formUtils.isLoadingModules = true;
|
718
|
+
}
|
719
|
+
|
720
|
+
var cacheSuffix = '?__='+( new Date().getTime() ),
|
721
|
+
appendToElement = document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0];
|
722
|
+
|
723
|
+
$.each(moduleList, function(i, modName) {
|
724
|
+
modName = $.trim(modName);
|
725
|
+
if( modName.length == 0 ) {
|
726
|
+
moduleLoadedCallback();
|
727
|
+
}
|
728
|
+
else {
|
729
|
+
var scriptUrl = path + modName + (modName.substr(-3) == '.js' ? '':'.js'),
|
730
|
+
script = document.createElement('SCRIPT');
|
731
|
+
|
732
|
+
if( scriptUrl in $.formUtils.loadedModules ) {
|
733
|
+
// already loaded
|
734
|
+
moduleLoadedCallback();
|
735
|
+
}
|
736
|
+
else {
|
737
|
+
|
738
|
+
// Remember that this script is loaded
|
739
|
+
$.formUtils.loadedModules[scriptUrl] = 1;
|
740
|
+
hasLoadedAnyModule = true;
|
741
|
+
|
742
|
+
// Load the script
|
743
|
+
script.type = 'text/javascript';
|
744
|
+
script.onload = moduleLoadedCallback;
|
745
|
+
script.src = scriptUrl + ( scriptUrl.substr(-7) == '.dev.js' ? cacheSuffix:'' );
|
746
|
+
script.onreadystatechange = function() {
|
747
|
+
// IE 7 fix
|
748
|
+
if( this.readyState == 'complete' || this.readyState == 'loaded' ) {
|
749
|
+
moduleLoadedCallback();
|
750
|
+
// Handle memory leak in IE
|
751
|
+
this.onload = null;
|
752
|
+
this.onreadystatechange = null;
|
753
|
+
}
|
754
|
+
};
|
755
|
+
appendToElement.appendChild( script );
|
756
|
+
}
|
757
|
+
}
|
758
|
+
});
|
759
|
+
};
|
760
|
+
|
761
|
+
if( path ) {
|
762
|
+
loadModuleScripts(modules, path);
|
763
|
+
} else {
|
764
|
+
var findScriptPathAndLoadModules = function() {
|
765
|
+
var foundPath = false;
|
766
|
+
$('script').each(function() {
|
767
|
+
if( this.src ) {
|
768
|
+
var scriptName = this.src.substr(this.src.lastIndexOf('/')+1, this.src.length);
|
769
|
+
if(scriptName.indexOf('jquery.form-validator.js') > -1 || scriptName.indexOf('jquery.form-validator.min.js') > -1) {
|
770
|
+
foundPath = this.src.substr(0, this.src.lastIndexOf('/')) + '/';
|
771
|
+
if( foundPath == '/' )
|
772
|
+
foundPath = '';
|
773
|
+
return false;
|
774
|
+
}
|
775
|
+
}
|
776
|
+
});
|
777
|
+
|
778
|
+
if( foundPath !== false) {
|
779
|
+
loadModuleScripts(modules, foundPath);
|
780
|
+
return true;
|
781
|
+
}
|
782
|
+
return false;
|
783
|
+
};
|
784
|
+
|
785
|
+
if( !findScriptPathAndLoadModules() ) {
|
786
|
+
$(findScriptPathAndLoadModules);
|
787
|
+
}
|
788
|
+
}
|
789
|
+
},
|
790
|
+
|
791
|
+
/**
|
792
|
+
* Validate the value of given element according to the validation rules
|
793
|
+
* found in the attribute data-validation. Will return true if valid,
|
794
|
+
* error message otherwise
|
795
|
+
*
|
796
|
+
* @param {jQuery} $elem
|
797
|
+
* @param {Object} language ($.formUtils.LANG)
|
798
|
+
* @param {Object} conf
|
799
|
+
* @param {jQuery} $form
|
800
|
+
* @param {String} [eventContext]
|
801
|
+
* @return {String|Boolean}
|
802
|
+
*/
|
803
|
+
validateInput : function($elem, language, conf, $form, eventContext) {
|
804
|
+
|
805
|
+
if( $elem.attr('disabled') )
|
806
|
+
return null; // returning null will prevent that the valid class gets applied to the element
|
807
|
+
|
808
|
+
$elem.trigger('beforeValidation');
|
809
|
+
|
810
|
+
var value = $.trim( $elem.val() || ''),
|
811
|
+
optional = $elem.valAttr('optional'),
|
812
|
+
|
813
|
+
// test if a checkbox forces this element to be validated
|
814
|
+
validationDependsOnCheckedInput = false,
|
815
|
+
validationDependentInputIsChecked = false,
|
816
|
+
validateIfCheckedElement = false,
|
817
|
+
|
818
|
+
// get value of this element's attribute "... if-checked"
|
819
|
+
validateIfCheckedElementName = $elem.valAttr("if-checked");
|
820
|
+
|
821
|
+
// make sure we can proceed
|
822
|
+
if (validateIfCheckedElementName != null) {
|
823
|
+
|
824
|
+
// Set the boolean telling us that the validation depends
|
825
|
+
// on another input being checked
|
826
|
+
validationDependsOnCheckedInput = true;
|
827
|
+
|
828
|
+
// select the checkbox type element in this form
|
829
|
+
validateIfCheckedElement = $form.find('input[name="' + validateIfCheckedElementName + '"]');
|
830
|
+
|
831
|
+
// test if it's property "checked" is checked
|
832
|
+
if ( validateIfCheckedElement.prop('checked') ) {
|
833
|
+
// set value for validation checkpoint
|
834
|
+
validationDependentInputIsChecked = true;
|
835
|
+
}
|
836
|
+
}
|
837
|
+
|
838
|
+
// validation checkpoint
|
839
|
+
// if empty AND optional attribute is present
|
840
|
+
// OR depending on a checkbox being checked AND checkbox is checked, return true
|
841
|
+
if ((!value && optional === 'true') || (validationDependsOnCheckedInput && !validationDependentInputIsChecked)) {
|
842
|
+
return conf.addValidClassOnAll ? true:null;
|
843
|
+
}
|
844
|
+
|
845
|
+
var validationRules = $elem.attr(conf.validationRuleAttribute),
|
846
|
+
|
847
|
+
// see if form element has inline err msg attribute
|
848
|
+
validationErrorMsg = true;
|
849
|
+
|
850
|
+
if( !validationRules ) {
|
851
|
+
return conf.addValidClassOnAll ? true:null;
|
852
|
+
}
|
853
|
+
|
854
|
+
$.split(validationRules, function(rule) {
|
855
|
+
if( rule.indexOf('validate_') !== 0 ) {
|
856
|
+
rule = 'validate_' + rule;
|
857
|
+
}
|
858
|
+
|
859
|
+
var validator = $.formUtils.validators[rule];
|
860
|
+
|
861
|
+
if( validator && typeof validator['validatorFunction'] == 'function' ) {
|
862
|
+
// special change of element for checkbox_group rule
|
863
|
+
if ( rule == 'validate_checkbox_group' ) {
|
864
|
+
// set element to first in group, so error msg is set only once
|
865
|
+
$elem = $("[name='"+$elem.attr('name')+"']:eq(0)");
|
866
|
+
}
|
867
|
+
|
868
|
+
var isValid = true;
|
869
|
+
if( eventContext != 'keyup' || validator.validateOnKeyUp ) {
|
870
|
+
isValid = validator.validatorFunction(value, $elem, conf, language, $form);
|
871
|
+
}
|
872
|
+
|
873
|
+
if(!isValid) {
|
874
|
+
validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute+'-'+rule.replace('validate_', ''));
|
875
|
+
if( !validationErrorMsg ) {
|
876
|
+
validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute);
|
877
|
+
if( !validationErrorMsg ) {
|
878
|
+
validationErrorMsg = language[validator.errorMessageKey];
|
879
|
+
if( !validationErrorMsg )
|
880
|
+
validationErrorMsg = validator.errorMessage;
|
881
|
+
}
|
882
|
+
}
|
883
|
+
return false; // breaks the iteration
|
884
|
+
}
|
885
|
+
|
886
|
+
} else {
|
887
|
+
console.warn('Using undefined validator "'+rule+'"');
|
888
|
+
}
|
889
|
+
|
890
|
+
}, ' ');
|
891
|
+
|
892
|
+
if( typeof validationErrorMsg == 'string' ) {
|
893
|
+
return validationErrorMsg;
|
894
|
+
} else {
|
895
|
+
return true;
|
896
|
+
}
|
897
|
+
},
|
898
|
+
|
899
|
+
/**
|
900
|
+
* Is it a correct date according to given dateFormat. Will return false if not, otherwise
|
901
|
+
* an array 0=>year 1=>month 2=>day
|
902
|
+
*
|
903
|
+
* @param {String} val
|
904
|
+
* @param {String} dateFormat
|
905
|
+
* @return {Array}|{Boolean}
|
906
|
+
*/
|
907
|
+
parseDate : function(val, dateFormat) {
|
908
|
+
var divider = dateFormat.replace(/[a-zA-Z]/gi, '').substring(0,1),
|
909
|
+
regexp = '^',
|
910
|
+
formatParts = dateFormat.split(divider),
|
911
|
+
matches, day, month, year;
|
912
|
+
|
913
|
+
$.each(formatParts, function(i, part) {
|
914
|
+
regexp += (i > 0 ? '\\'+divider:'') + '(\\d{'+part.length+'})';
|
915
|
+
});
|
916
|
+
|
917
|
+
regexp += '$';
|
918
|
+
|
919
|
+
matches = val.match(new RegExp(regexp));
|
920
|
+
if (matches === null) {
|
921
|
+
return false;
|
922
|
+
}
|
923
|
+
|
924
|
+
var findDateUnit = function(unit, formatParts, matches) {
|
925
|
+
for(var i=0; i < formatParts.length; i++) {
|
926
|
+
if(formatParts[i].substring(0,1) === unit) {
|
927
|
+
return $.formUtils.parseDateInt(matches[i+1]);
|
928
|
+
}
|
929
|
+
}
|
930
|
+
return -1;
|
931
|
+
};
|
932
|
+
|
933
|
+
month = findDateUnit('m', formatParts, matches);
|
934
|
+
day = findDateUnit('d', formatParts, matches);
|
935
|
+
year = findDateUnit('y', formatParts, matches);
|
936
|
+
|
937
|
+
if ((month === 2 && day > 28 && (year % 4 !== 0 || year % 100 === 0 && year % 400 !== 0))
|
938
|
+
|| (month === 2 && day > 29 && (year % 4 === 0 || year % 100 !== 0 && year % 400 === 0))
|
939
|
+
|| month > 12 || month === 0) {
|
940
|
+
return false;
|
941
|
+
}
|
942
|
+
if ((this.isShortMonth(month) && day > 30) || (!this.isShortMonth(month) && day > 31) || day === 0) {
|
943
|
+
return false;
|
944
|
+
}
|
945
|
+
|
946
|
+
return [year, month, day];
|
947
|
+
},
|
948
|
+
|
949
|
+
/**
|
950
|
+
* skum fix. är talet 05 eller lägre ger parseInt rätt int annars får man 0 när man kör parseInt?
|
951
|
+
*
|
952
|
+
* @param {String} val
|
953
|
+
* @param {Number}
|
954
|
+
*/
|
955
|
+
parseDateInt : function(val) {
|
956
|
+
if (val.indexOf('0') === 0) {
|
957
|
+
val = val.replace('0', '');
|
958
|
+
}
|
959
|
+
return parseInt(val,10);
|
960
|
+
},
|
961
|
+
|
962
|
+
/**
|
963
|
+
* Has month only 30 days?
|
964
|
+
*
|
965
|
+
* @param {Number} m
|
966
|
+
* @return {Boolean}
|
967
|
+
*/
|
968
|
+
isShortMonth : function(m) {
|
969
|
+
return (m % 2 === 0 && m < 7) || (m % 2 !== 0 && m > 7);
|
970
|
+
},
|
971
|
+
|
972
|
+
/**
|
973
|
+
* Restrict input length
|
974
|
+
*
|
975
|
+
* @param {jQuery} $inputElement Jquery Html object
|
976
|
+
* @param {jQuery} $maxLengthElement jQuery Html Object
|
977
|
+
* @return void
|
978
|
+
*/
|
979
|
+
lengthRestriction : function($inputElement, $maxLengthElement) {
|
980
|
+
// read maxChars from counter display initial text value
|
981
|
+
var maxChars = parseInt($maxLengthElement.text(),10),
|
982
|
+
charsLeft = 0,
|
983
|
+
|
984
|
+
// internal function does the counting and sets display value
|
985
|
+
countCharacters = function() {
|
986
|
+
var numChars = $inputElement.val().length;
|
987
|
+
if(numChars > maxChars) {
|
988
|
+
// get current scroll bar position
|
989
|
+
var currScrollTopPos = $inputElement.scrollTop();
|
990
|
+
// trim value to max length
|
991
|
+
$inputElement.val($inputElement.val().substring(0, maxChars));
|
992
|
+
$inputElement.scrollTop(currScrollTopPos);
|
993
|
+
}
|
994
|
+
charsLeft = maxChars - numChars;
|
995
|
+
if( charsLeft < 0 )
|
996
|
+
charsLeft = 0;
|
997
|
+
|
998
|
+
// set counter text
|
999
|
+
$maxLengthElement.text(charsLeft);
|
1000
|
+
};
|
1001
|
+
|
1002
|
+
// bind events to this element
|
1003
|
+
// setTimeout is needed, cut or paste fires before val is available
|
1004
|
+
$($inputElement).bind('keydown keyup keypress focus blur', countCharacters )
|
1005
|
+
.bind('cut paste', function(){ setTimeout(countCharacters, 100); } ) ;
|
1006
|
+
|
1007
|
+
// count chars on pageload, if there are prefilled input-values
|
1008
|
+
$(document).bind("ready", countCharacters);
|
1009
|
+
},
|
1010
|
+
|
1011
|
+
/**
|
1012
|
+
* Test numeric against allowed range
|
1013
|
+
*
|
1014
|
+
* @param $value int
|
1015
|
+
* @param $rangeAllowed str; (1-2, min1, max2)
|
1016
|
+
* @return array
|
1017
|
+
*/
|
1018
|
+
numericRangeCheck : function(value, rangeAllowed)
|
1019
|
+
{
|
1020
|
+
// split by dash
|
1021
|
+
var range = $.split(rangeAllowed, '-');
|
1022
|
+
// min or max
|
1023
|
+
var minmax = parseInt(rangeAllowed.substr(3),10)
|
1024
|
+
// range ?
|
1025
|
+
if (range.length == 2 && (value < parseInt(range[0],10) || value > parseInt(range[1],10) ) )
|
1026
|
+
{ return [ "out", range[0], range[1] ] ; } // value is out of range
|
1027
|
+
else if (rangeAllowed.indexOf('min') === 0 && (value < minmax ) ) // min
|
1028
|
+
{ return ["min", minmax]; } // value is below min
|
1029
|
+
else if (rangeAllowed.indexOf('max') === 0 && (value > minmax ) ) // max
|
1030
|
+
{ return ["max", minmax]; } // value is above max
|
1031
|
+
else { return [ "ok" ] ; } // value is in allowed range
|
1032
|
+
},
|
1033
|
+
|
1034
|
+
|
1035
|
+
_numSuggestionElements : 0,
|
1036
|
+
_selectedSuggestion : null,
|
1037
|
+
_previousTypedVal : null,
|
1038
|
+
|
1039
|
+
/**
|
1040
|
+
* Utility function that can be used to create plugins that gives
|
1041
|
+
* suggestions when inputs is typed into
|
1042
|
+
* @param {jQuery} $elem
|
1043
|
+
* @param {Array} suggestions
|
1044
|
+
* @param {Object} settings - Optional
|
1045
|
+
* @return {jQuery}
|
1046
|
+
*/
|
1047
|
+
suggest : function($elem, suggestions, settings) {
|
1048
|
+
var conf = {
|
1049
|
+
css : {
|
1050
|
+
maxHeight: '150px',
|
1051
|
+
background: '#FFF',
|
1052
|
+
lineHeight:'150%',
|
1053
|
+
textDecoration : 'underline',
|
1054
|
+
overflowX : 'hidden',
|
1055
|
+
overflowY : 'auto',
|
1056
|
+
border : '#CCC solid 1px',
|
1057
|
+
borderTop : 'none',
|
1058
|
+
cursor: 'pointer'
|
1059
|
+
},
|
1060
|
+
activeSuggestionCSS : {
|
1061
|
+
background : '#E9E9E9'
|
1062
|
+
}
|
1063
|
+
},
|
1064
|
+
setSuggsetionPosition = function($suggestionContainer, $input) {
|
1065
|
+
var offset = $input.offset();
|
1066
|
+
$suggestionContainer.css({
|
1067
|
+
width : $input.outerWidth(),
|
1068
|
+
left : offset.left + 'px',
|
1069
|
+
top : (offset.top + $input.outerHeight()) +'px'
|
1070
|
+
});
|
1071
|
+
};
|
1072
|
+
|
1073
|
+
if(settings)
|
1074
|
+
$.extend(conf, settings);
|
1075
|
+
|
1076
|
+
conf.css['position'] = 'absolute';
|
1077
|
+
conf.css['z-index'] = 9999;
|
1078
|
+
$elem.attr('autocomplete', 'off');
|
1079
|
+
|
1080
|
+
if( this._numSuggestionElements === 0 ) {
|
1081
|
+
// Re-position suggestion container if window size changes
|
1082
|
+
$window.bind('resize', function() {
|
1083
|
+
$('.jquery-form-suggestions').each(function() {
|
1084
|
+
var $container = $(this),
|
1085
|
+
suggestID = $container.attr('data-suggest-container');
|
1086
|
+
setSuggsetionPosition($container, $('.suggestions-'+suggestID).eq(0));
|
1087
|
+
});
|
1088
|
+
});
|
1089
|
+
}
|
1090
|
+
|
1091
|
+
this._numSuggestionElements++;
|
1092
|
+
|
1093
|
+
var onSelectSuggestion = function($el) {
|
1094
|
+
var suggestionId = $el.valAttr('suggestion-nr');
|
1095
|
+
$.formUtils._selectedSuggestion = null;
|
1096
|
+
$.formUtils._previousTypedVal = null;
|
1097
|
+
$('.jquery-form-suggestion-'+suggestionId).fadeOut('fast');
|
1098
|
+
};
|
1099
|
+
|
1100
|
+
$elem
|
1101
|
+
.data('suggestions', suggestions)
|
1102
|
+
.valAttr('suggestion-nr', this._numSuggestionElements)
|
1103
|
+
.unbind('focus.suggest')
|
1104
|
+
.bind('focus.suggest', function() {
|
1105
|
+
$(this).trigger('keyup');
|
1106
|
+
$.formUtils._selectedSuggestion = null;
|
1107
|
+
})
|
1108
|
+
.unbind('keyup.suggest')
|
1109
|
+
.bind('keyup.suggest', function() {
|
1110
|
+
var $input = $(this),
|
1111
|
+
foundSuggestions = [],
|
1112
|
+
val = $.trim($input.val()).toLocaleLowerCase();
|
1113
|
+
|
1114
|
+
if(val == $.formUtils._previousTypedVal) {
|
1115
|
+
return;
|
1116
|
+
}
|
1117
|
+
else {
|
1118
|
+
$.formUtils._previousTypedVal = val;
|
1119
|
+
}
|
1120
|
+
|
1121
|
+
var hasTypedSuggestion = false,
|
1122
|
+
suggestionId = $input.valAttr('suggestion-nr'),
|
1123
|
+
$suggestionContainer = $('.jquery-form-suggestion-'+suggestionId);
|
1124
|
+
|
1125
|
+
$suggestionContainer.scrollTop(0);
|
1126
|
+
|
1127
|
+
// Find the right suggestions
|
1128
|
+
if(val != '') {
|
1129
|
+
var findPartial = val.length > 2;
|
1130
|
+
$.each($input.data('suggestions'), function(i, suggestion) {
|
1131
|
+
var lowerCaseVal = suggestion.toLocaleLowerCase();
|
1132
|
+
if( lowerCaseVal == val ) {
|
1133
|
+
foundSuggestions.push('<strong>'+suggestion+'</strong>');
|
1134
|
+
hasTypedSuggestion = true;
|
1135
|
+
return false;
|
1136
|
+
} else if(lowerCaseVal.indexOf(val) === 0 || (findPartial && lowerCaseVal.indexOf(val) > -1)) {
|
1137
|
+
foundSuggestions.push(suggestion.replace(new RegExp(val, 'gi'), '<strong>$&</strong>'));
|
1138
|
+
}
|
1139
|
+
});
|
1140
|
+
}
|
1141
|
+
|
1142
|
+
// Hide suggestion container
|
1143
|
+
if(hasTypedSuggestion || (foundSuggestions.length == 0 && $suggestionContainer.length > 0)) {
|
1144
|
+
$suggestionContainer.hide();
|
1145
|
+
}
|
1146
|
+
|
1147
|
+
// Create suggestion container if not already exists
|
1148
|
+
else if(foundSuggestions.length > 0 && $suggestionContainer.length == 0) {
|
1149
|
+
$suggestionContainer = $('<div></div>').css(conf.css).appendTo('body');
|
1150
|
+
$elem.addClass('suggestions-'+suggestionId);
|
1151
|
+
$suggestionContainer
|
1152
|
+
.attr('data-suggest-container', suggestionId)
|
1153
|
+
.addClass('jquery-form-suggestions')
|
1154
|
+
.addClass('jquery-form-suggestion-'+suggestionId);
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
// Show hidden container
|
1158
|
+
else if(foundSuggestions.length > 0 && !$suggestionContainer.is(':visible')) {
|
1159
|
+
$suggestionContainer.show();
|
1160
|
+
}
|
1161
|
+
|
1162
|
+
// add suggestions
|
1163
|
+
if(foundSuggestions.length > 0 && val.length != foundSuggestions[0].length) {
|
1164
|
+
|
1165
|
+
// put container in place every time, just in case
|
1166
|
+
setSuggsetionPosition($suggestionContainer, $input);
|
1167
|
+
|
1168
|
+
// Add suggestions HTML to container
|
1169
|
+
$suggestionContainer.html('');
|
1170
|
+
$.each(foundSuggestions, function(i, text) {
|
1171
|
+
$('<div></div>')
|
1172
|
+
.append(text)
|
1173
|
+
.css({
|
1174
|
+
overflow: 'hidden',
|
1175
|
+
textOverflow : 'ellipsis',
|
1176
|
+
whiteSpace : 'nowrap',
|
1177
|
+
padding: '5px'
|
1178
|
+
})
|
1179
|
+
.addClass('form-suggest-element')
|
1180
|
+
.appendTo($suggestionContainer)
|
1181
|
+
.click(function() {
|
1182
|
+
$input.focus();
|
1183
|
+
$input.val( $(this).text() );
|
1184
|
+
onSelectSuggestion($input);
|
1185
|
+
});
|
1186
|
+
});
|
1187
|
+
}
|
1188
|
+
})
|
1189
|
+
.unbind('keydown.validation')
|
1190
|
+
.bind('keydown.validation', function(e) {
|
1191
|
+
var code = (e.keyCode ? e.keyCode : e.which),
|
1192
|
+
suggestionId,
|
1193
|
+
$suggestionContainer,
|
1194
|
+
$input = $(this);
|
1195
|
+
|
1196
|
+
if(code == 13 && $.formUtils._selectedSuggestion !== null) {
|
1197
|
+
suggestionId = $input.valAttr('suggestion-nr');
|
1198
|
+
$suggestionContainer = $('.jquery-form-suggestion-'+suggestionId);
|
1199
|
+
if($suggestionContainer.length > 0) {
|
1200
|
+
var newText = $suggestionContainer.find('div').eq($.formUtils._selectedSuggestion).text();
|
1201
|
+
$input.val(newText);
|
1202
|
+
onSelectSuggestion($input);
|
1203
|
+
e.preventDefault();
|
1204
|
+
}
|
1205
|
+
}
|
1206
|
+
else {
|
1207
|
+
suggestionId = $input.valAttr('suggestion-nr');
|
1208
|
+
$suggestionContainer = $('.jquery-form-suggestion-'+suggestionId);
|
1209
|
+
var $suggestions = $suggestionContainer.children();
|
1210
|
+
if($suggestions.length > 0 && $.inArray(code, [38,40]) > -1) {
|
1211
|
+
if(code == 38) { // key up
|
1212
|
+
if($.formUtils._selectedSuggestion === null)
|
1213
|
+
$.formUtils._selectedSuggestion = $suggestions.length-1;
|
1214
|
+
else
|
1215
|
+
$.formUtils._selectedSuggestion--;
|
1216
|
+
if($.formUtils._selectedSuggestion < 0)
|
1217
|
+
$.formUtils._selectedSuggestion = $suggestions.length-1;
|
1218
|
+
}
|
1219
|
+
else if(code == 40) { // key down
|
1220
|
+
if($.formUtils._selectedSuggestion === null)
|
1221
|
+
$.formUtils._selectedSuggestion = 0;
|
1222
|
+
else
|
1223
|
+
$.formUtils._selectedSuggestion++;
|
1224
|
+
if($.formUtils._selectedSuggestion > ($suggestions.length-1))
|
1225
|
+
$.formUtils._selectedSuggestion = 0;
|
1226
|
+
|
1227
|
+
}
|
1228
|
+
|
1229
|
+
// Scroll in suggestion window
|
1230
|
+
var containerInnerHeight = $suggestionContainer.innerHeight(),
|
1231
|
+
containerScrollTop = $suggestionContainer.scrollTop(),
|
1232
|
+
suggestionHeight = $suggestionContainer.children().eq(0).outerHeight(),
|
1233
|
+
activeSuggestionPosY = suggestionHeight * ($.formUtils._selectedSuggestion);
|
1234
|
+
|
1235
|
+
if( activeSuggestionPosY < containerScrollTop || activeSuggestionPosY > (containerScrollTop+containerInnerHeight)) {
|
1236
|
+
$suggestionContainer.scrollTop( activeSuggestionPosY );
|
1237
|
+
}
|
1238
|
+
|
1239
|
+
$suggestions
|
1240
|
+
.removeClass('active-suggestion')
|
1241
|
+
.css('background', 'none')
|
1242
|
+
.eq($.formUtils._selectedSuggestion)
|
1243
|
+
.addClass('active-suggestion')
|
1244
|
+
.css(conf.activeSuggestionCSS);
|
1245
|
+
|
1246
|
+
e.preventDefault();
|
1247
|
+
return false;
|
1248
|
+
}
|
1249
|
+
}
|
1250
|
+
})
|
1251
|
+
.unbind('blur.suggest')
|
1252
|
+
.bind('blur.suggest', function() {
|
1253
|
+
onSelectSuggestion($(this));
|
1254
|
+
});
|
1255
|
+
|
1256
|
+
return $elem;
|
1257
|
+
},
|
1258
|
+
|
1259
|
+
/**
|
1260
|
+
* Error dialogs
|
1261
|
+
*
|
1262
|
+
* @var {Object}
|
1263
|
+
*/
|
1264
|
+
LANG : {
|
1265
|
+
errorTitle : 'Form submission failed!',
|
1266
|
+
requiredFields : 'You have not answered all required fields',
|
1267
|
+
badTime : 'You have not given a correct time',
|
1268
|
+
badEmail : 'You have not given a correct e-mail address',
|
1269
|
+
badTelephone : 'You have not given a correct phone number',
|
1270
|
+
badSecurityAnswer : 'You have not given a correct answer to the security question',
|
1271
|
+
badDate : 'You have not given a correct date',
|
1272
|
+
lengthBadStart : 'You must give an answer between ',
|
1273
|
+
lengthBadEnd : ' characters',
|
1274
|
+
lengthTooLongStart : 'You have given an answer longer than ',
|
1275
|
+
lengthTooShortStart : 'You have given an answer shorter than ',
|
1276
|
+
notConfirmed : 'Values could not be confirmed',
|
1277
|
+
badDomain : 'Incorrect domain value',
|
1278
|
+
badUrl : 'The answer you gave was not a correct URL',
|
1279
|
+
badCustomVal : 'You gave an incorrect answer',
|
1280
|
+
badInt : 'The answer you gave was not a correct number',
|
1281
|
+
badSecurityNumber : 'Your isVsocial security number was incorrect',
|
1282
|
+
badUKVatAnswer : 'Incorrect UK VAT Number',
|
1283
|
+
badStrength : 'The password isn\'t strong enough',
|
1284
|
+
badNumberOfSelectedOptionsStart : 'You have to choose at least ',
|
1285
|
+
badNumberOfSelectedOptionsEnd : ' answers',
|
1286
|
+
badAlphaNumeric : 'The answer you gave must contain only alphanumeric characters ',
|
1287
|
+
badAlphaNumericExtra: ' and ',
|
1288
|
+
wrongFileSize : 'The file you are trying to upload is too large',
|
1289
|
+
wrongFileType : 'The file you are trying to upload is of wrong type',
|
1290
|
+
groupCheckedRangeStart : 'Please choose between ',
|
1291
|
+
groupCheckedTooFewStart : 'Please choose at least ',
|
1292
|
+
groupCheckedTooManyStart : 'Please choose a maximum of ',
|
1293
|
+
groupCheckedEnd : ' item(s)',
|
1294
|
+
badCreditCard : 'The credit card number is not correct',
|
1295
|
+
badCVV : 'The CVV number was not correct'
|
1296
|
+
}
|
1297
|
+
};
|
1298
|
+
|
1299
|
+
|
1300
|
+
/* * * * * * * * * * * * * * * * * * * * * *
|
1301
|
+
CORE VALIDATORS
|
1302
|
+
* * * * * * * * * * * * * * * * * * * * */
|
1303
|
+
|
1304
|
+
|
1305
|
+
/*
|
1306
|
+
* Validate email
|
1307
|
+
*/
|
1308
|
+
$.formUtils.addValidator({
|
1309
|
+
name : 'email',
|
1310
|
+
validatorFunction : function(email) {
|
1311
|
+
|
1312
|
+
var emailParts = email.toLowerCase().split('@');
|
1313
|
+
if( emailParts.length == 2 ) {
|
1314
|
+
return $.formUtils.validators.validate_domain.validatorFunction(emailParts[1]) &&
|
1315
|
+
!(/[^\w\+\.\-]/.test(emailParts[0]));
|
1316
|
+
}
|
1317
|
+
|
1318
|
+
return false;
|
1319
|
+
},
|
1320
|
+
errorMessage : '',
|
1321
|
+
errorMessageKey : 'badEmail'
|
1322
|
+
});
|
1323
|
+
|
1324
|
+
/*
|
1325
|
+
* Validate domain name
|
1326
|
+
*/
|
1327
|
+
$.formUtils.addValidator({
|
1328
|
+
name : 'domain',
|
1329
|
+
validatorFunction : function(val, $input) {
|
1330
|
+
|
1331
|
+
var topDomains = ['.ac', '.ad', '.ae', '.aero', '.af', '.ag', '.ai', '.al', '.am', '.an', '.ao',
|
1332
|
+
'.aq', '.ar', '.arpa', '.as', '.asia', '.at', '.au', '.aw', '.ax', '.az', '.ba', '.bb',
|
1333
|
+
'.bd', '.be', '.bf', '.bg', '.bh', '.bi', '.bike', '.biz', '.bj', '.bm', '.bn', '.bo',
|
1334
|
+
'.br', '.bs', '.bt', '.bv', '.bw', '.by', '.bz', '.ca', '.camera', '.cat', '.cc', '.cd',
|
1335
|
+
'.cf', '.cg', '.ch', '.ci', '.ck', '.cl', '.clothing', '.cm', '.cn', '.co', '.com',
|
1336
|
+
'.construction', '.contractors', '.coop', '.cr', '.cu', '.cv', '.cw', '.cx', '.cy', '.cz',
|
1337
|
+
'.de', '.diamonds', '.directory', '.dj', '.dk', '.dm', '.do', '.dz', '.ec', '.edu', '.ee',
|
1338
|
+
'.eg', '.enterprises', '.equipment', '.er', '.es', '.estate', '.et', '.eu', '.fi', '.fj',
|
1339
|
+
'.fk', '.fm', '.fo', '.fr', '.ga', '.gallery', '.gb', '.gd', '.ge', '.gf', '.gg', '.gh',
|
1340
|
+
'.gi', '.gl', '.gm', '.gn', '.gov', '.gp', '.gq', '.gr', '.graphics', '.gs', '.gt', '.gu',
|
1341
|
+
'.guru', '.gw', '.gy', '.hk', '.hm', '.hn', '.holdings', '.hr', '.ht', '.hu', '.id', '.ie',
|
1342
|
+
'.il', '.im', '.in', '.info', '.int', '.io', '.iq', '.ir', '.is', '.it', '.je', '.jm', '.jo',
|
1343
|
+
'.jobs', '.jp', '.ke', '.kg', '.kh', '.ki', '.kitchen', '.km', '.kn', '.kp', '.kr', '.kw',
|
1344
|
+
'.ky', '.kz', '.la', '.land', '.lb', '.lc', '.li', '.lighting', '.lk', '.lr', '.ls', '.lt',
|
1345
|
+
'.lu', '.lv', '.ly', '.ma', '.mc', '.md', '.me', '.menu', '.mg', '.mh', '.mil', '.mk', '.ml',
|
1346
|
+
'.mm', '.mn', '.mo', '.mobi', '.mp', '.mq', '.mr', '.ms', '.mt', '.mu', '.museum', '.mv',
|
1347
|
+
'.mw', '.mx', '.my', '.mz', '.na', '.name', '.nc', '.ne', '.net', '.nf', '.ng', '.ni',
|
1348
|
+
'.nl', '.no', '.np', '.nr', '.nu', '.nz', '.om', '.org', '.pa', '.pe', '.pf', '.pg', '.ph',
|
1349
|
+
'.photography', '.pk', '.pl', '.plumbing', '.pm', '.pn', '.post', '.pr', '.pro', '.ps', '.pt',
|
1350
|
+
'.pw', '.py', '.qa', '.re', '.ro', '.rs', '.ru', '.rw', '.sa', '.sb', '.sc', '.sd', '.se',
|
1351
|
+
'.sexy', '.sg', '.sh', '.si', '.singles', '.sj', '.sk', '.sl', '.sm', '.sn', '.so', '.sr',
|
1352
|
+
'.st', '.su', '.sv', '.sx', '.sy', '.sz', '.tattoo', '.tc', '.td', '.technology', '.tel', '.tf',
|
1353
|
+
'.tg', '.th', '.tips', '.tj', '.tk', '.tl', '.tm', '.tn', '.to', '.today', '.tp', '.tr', '.travel',
|
1354
|
+
'.tt', '.tv', '.tw', '.tz', '.ua', '.ug', '.uk', '.uno', '.us', '.uy', '.uz', '.va', '.vc', '.ve',
|
1355
|
+
'.ventures', '.vg', '.vi', '.vn', '.voyage', '.vu', '.wf', '.ws', '.xn--3e0b707e', '.xn--45brj9c',
|
1356
|
+
'.xn--80ao21a', '.xn--80asehdb', '.xn--80aswg', '.xn--90a3ac', '.xn--clchc0ea0b2g2a9gcd', '.xn--fiqs8s',
|
1357
|
+
'.xn--fiqz9s', '.xn--fpcrj9c3d', '.xn--fzc2c9e2c', '.xn--gecrj9c', '.xn--h2brj9c', '.xn--j1amh',
|
1358
|
+
'.xn--j6w193g', '.xn--kprw13d', '.xn--kpry57d', '.xn--l1acc', '.xn--lgbbat1ad8j', '.xn--mgb9awbf',
|
1359
|
+
'.xn--mgba3a4f16a', '.xn--mgbaam7a8h', '.xn--mgbayh7gpa', '.xn--mgbbh1a71e', '.xn--mgbc0a9azcg',
|
1360
|
+
'.xn--mgberp4a5d4ar', '.xn--mgbx4cd0ab', '.xn--ngbc5azd', '.xn--o3cw4h', '.xn--ogbpf8fl', '.xn--p1ai',
|
1361
|
+
'.xn--pgbs0dh', '.xn--q9jyb4c', '.xn--s9brj9c', '.xn--unup4y', '.xn--wgbh1c', '.xn--wgbl6a',
|
1362
|
+
'.xn--xkc2al3hye2a', '.xn--xkc2dl3a5ee0h', '.xn--yfro4i67o', '.xn--ygbi2ammx', '.xxx', '.ye',
|
1363
|
+
'.yt', '.za', '.zm', '.zw'],
|
1364
|
+
|
1365
|
+
ukTopDomains = ['co', 'me', 'ac', 'gov', 'judiciary','ltd', 'mod', 'net', 'nhs', 'nic',
|
1366
|
+
'org', 'parliament', 'plc', 'police', 'sch', 'bl', 'british-library', 'jet','nls'],
|
1367
|
+
|
1368
|
+
dot = val.lastIndexOf('.'),
|
1369
|
+
domain = val.substring(0, dot),
|
1370
|
+
ext = val.substring(dot, val.length),
|
1371
|
+
hasTopDomain = false;
|
1372
|
+
|
1373
|
+
for (var i = 0; i < topDomains.length; i++) {
|
1374
|
+
if (topDomains[i] === ext) {
|
1375
|
+
if(ext==='.uk') {
|
1376
|
+
//Run Extra Checks for UK Domain Names
|
1377
|
+
var domainParts = val.split('.');
|
1378
|
+
var tld2 = domainParts[domainParts.length-2];
|
1379
|
+
for(var j = 0; j < ukTopDomains.length; j++) {
|
1380
|
+
if(ukTopDomains[j] === tld2) {
|
1381
|
+
hasTopDomain = true;
|
1382
|
+
break;
|
1383
|
+
}
|
1384
|
+
}
|
1385
|
+
|
1386
|
+
if(hasTopDomain)
|
1387
|
+
break;
|
1388
|
+
|
1389
|
+
} else {
|
1390
|
+
hasTopDomain = true;
|
1391
|
+
break;
|
1392
|
+
}
|
1393
|
+
}
|
1394
|
+
}
|
1395
|
+
|
1396
|
+
if (!hasTopDomain) {
|
1397
|
+
return false;
|
1398
|
+
} else if (dot < 2 || dot > 57) {
|
1399
|
+
return false;
|
1400
|
+
} else {
|
1401
|
+
var firstChar = domain.substring(0, 1),
|
1402
|
+
lastChar = domain.substring(domain.length - 1, domain.length);
|
1403
|
+
|
1404
|
+
if (firstChar === '-' || firstChar === '.' || lastChar === '-' || lastChar === '.') {
|
1405
|
+
return false;
|
1406
|
+
}
|
1407
|
+
if (domain.split('.').length > 3 || domain.split('..').length > 1) {
|
1408
|
+
return false;
|
1409
|
+
}
|
1410
|
+
if (domain.replace(/[-\da-z\.]/g, '') !== '') {
|
1411
|
+
return false;
|
1412
|
+
}
|
1413
|
+
}
|
1414
|
+
|
1415
|
+
// It's valid, lets update input with trimmed value perhaps??
|
1416
|
+
if(typeof $input !== 'undefined') {
|
1417
|
+
$input.val(val);
|
1418
|
+
}
|
1419
|
+
|
1420
|
+
return true;
|
1421
|
+
},
|
1422
|
+
errorMessage : '',
|
1423
|
+
errorMessageKey: 'badDomain'
|
1424
|
+
});
|
1425
|
+
|
1426
|
+
/*
|
1427
|
+
* Validate required
|
1428
|
+
*/
|
1429
|
+
$.formUtils.addValidator({
|
1430
|
+
name : 'required',
|
1431
|
+
validatorFunction : function(val, $el, config, language, $form) {
|
1432
|
+
switch ( $el.attr('type') ) {
|
1433
|
+
case 'checkbox':
|
1434
|
+
return $el.is(':checked');
|
1435
|
+
case 'radio':
|
1436
|
+
return $form.find('input[name="'+$el.attr('name')+'"]').filter(':checked').length > 0;
|
1437
|
+
default:
|
1438
|
+
return $.trim(val) !== '';
|
1439
|
+
}
|
1440
|
+
},
|
1441
|
+
errorMessage : '',
|
1442
|
+
errorMessageKey: 'requiredFields'
|
1443
|
+
});
|
1444
|
+
|
1445
|
+
/*
|
1446
|
+
* Validate length range
|
1447
|
+
*/
|
1448
|
+
$.formUtils.addValidator({
|
1449
|
+
name : 'length',
|
1450
|
+
validatorFunction : function(val, $el, conf, lang) {
|
1451
|
+
var lengthAllowed = $el.valAttr('length'),
|
1452
|
+
type = $el.attr('type');
|
1453
|
+
|
1454
|
+
if(lengthAllowed == undefined) {
|
1455
|
+
var elementType = $el.get(0).nodeName;
|
1456
|
+
alert('Please add attribute "data-validation-length" to '+elementType+' named '+$el.attr('name'));
|
1457
|
+
return true;
|
1458
|
+
}
|
1459
|
+
|
1460
|
+
// check if length is above min, below max or within range.
|
1461
|
+
var len = type == 'file' && $el.get(0).files !== undefined ? $el.get(0).files.length : val.length,
|
1462
|
+
lengthCheckResults = $.formUtils.numericRangeCheck(len, lengthAllowed),
|
1463
|
+
checkResult;
|
1464
|
+
|
1465
|
+
switch(lengthCheckResults[0])
|
1466
|
+
{ // outside of allowed range
|
1467
|
+
case "out":
|
1468
|
+
this.errorMessage = lang.lengthBadStart + lengthAllowed + lang.lengthBadEnd;
|
1469
|
+
checkResult = false;
|
1470
|
+
break;
|
1471
|
+
// too short
|
1472
|
+
case "min":
|
1473
|
+
this.errorMessage = lang.lengthTooShortStart + lengthCheckResults[1] + lang.lengthBadEnd;
|
1474
|
+
checkResult = false;
|
1475
|
+
break;
|
1476
|
+
// too long
|
1477
|
+
case "max":
|
1478
|
+
this.errorMessage = lang.lengthTooLongStart + lengthCheckResults[1] + lang.lengthBadEnd;
|
1479
|
+
checkResult = false;
|
1480
|
+
break;
|
1481
|
+
// ok
|
1482
|
+
default:
|
1483
|
+
checkResult = true;
|
1484
|
+
}
|
1485
|
+
|
1486
|
+
return checkResult;
|
1487
|
+
},
|
1488
|
+
errorMessage : '',
|
1489
|
+
errorMessageKey: ''
|
1490
|
+
});
|
1491
|
+
|
1492
|
+
/*
|
1493
|
+
* Validate url
|
1494
|
+
*/
|
1495
|
+
$.formUtils.addValidator({
|
1496
|
+
name : 'url',
|
1497
|
+
validatorFunction : function(url) {
|
1498
|
+
// written by Scott Gonzalez: http://projects.scottsplayground.com/iri/
|
1499
|
+
// - Victor Jonsson added support for arrays in the url ?arg[]=sdfsdf
|
1500
|
+
// - General improvements made by Stéphane Moureau <https://github.com/TraderStf>
|
1501
|
+
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;
|
1502
|
+
if( urlFilter.test(url) ) {
|
1503
|
+
var domain = url.split('://')[1];
|
1504
|
+
var domainSlashPos = domain.indexOf('/');
|
1505
|
+
if(domainSlashPos > -1)
|
1506
|
+
domain = domain.substr(0, domainSlashPos);
|
1507
|
+
|
1508
|
+
return $.formUtils.validators.validate_domain.validatorFunction(domain); // todo: add support for IP-addresses
|
1509
|
+
}
|
1510
|
+
return false;
|
1511
|
+
},
|
1512
|
+
errorMessage : '',
|
1513
|
+
errorMessageKey: 'badUrl'
|
1514
|
+
});
|
1515
|
+
|
1516
|
+
/*
|
1517
|
+
* Validate number (floating or integer)
|
1518
|
+
*/
|
1519
|
+
$.formUtils.addValidator({
|
1520
|
+
name : 'number',
|
1521
|
+
validatorFunction : function(val, $el, conf) {
|
1522
|
+
if(val !== '') {
|
1523
|
+
var allowing = $el.valAttr('allowing') || '',
|
1524
|
+
decimalSeparator = $el.valAttr('decimal-separator') || conf.decimalSeparator,
|
1525
|
+
allowsRange = false,
|
1526
|
+
begin, end;
|
1527
|
+
|
1528
|
+
if(allowing.indexOf('number') == -1)
|
1529
|
+
allowing += ',number';
|
1530
|
+
|
1531
|
+
if(allowing.indexOf('negative') > -1 && val.indexOf('-') === 0) {
|
1532
|
+
val = val.substr(1);
|
1533
|
+
}
|
1534
|
+
|
1535
|
+
if (allowing.indexOf('range') > -1)
|
1536
|
+
{
|
1537
|
+
begin = parseFloat(allowing.substring(allowing.indexOf("[")+1, allowing.indexOf(";")));
|
1538
|
+
end = parseFloat(allowing.substring(allowing.indexOf(";")+1,allowing.indexOf("]")));
|
1539
|
+
allowsRange = true;
|
1540
|
+
}
|
1541
|
+
|
1542
|
+
if( decimalSeparator == ',' ) {
|
1543
|
+
if( val.indexOf('.') > -1 ) {
|
1544
|
+
return false;
|
1545
|
+
}
|
1546
|
+
// Fix for checking range with floats using ,
|
1547
|
+
val = val.replace(',', '.');
|
1548
|
+
}
|
1549
|
+
|
1550
|
+
if(allowing.indexOf('number') > -1 && val.replace(/[0-9]/g, '') === '' && (!allowsRange || (val >= begin && val <= end)) ) {
|
1551
|
+
return true;
|
1552
|
+
}
|
1553
|
+
if(allowing.indexOf('float') > -1 && val.match(new RegExp('^([0-9]+)\\.([0-9]+)$')) !== null && (!allowsRange || (val >= begin && val <= end)) ) {
|
1554
|
+
return true;
|
1555
|
+
}
|
1556
|
+
}
|
1557
|
+
return false;
|
1558
|
+
},
|
1559
|
+
errorMessage : '',
|
1560
|
+
errorMessageKey: 'badInt'
|
1561
|
+
});
|
1562
|
+
|
1563
|
+
/*
|
1564
|
+
* Validate alpha numeric
|
1565
|
+
*/
|
1566
|
+
$.formUtils.addValidator({
|
1567
|
+
name : 'alphanumeric',
|
1568
|
+
validatorFunction : function(val, $el, conf, language) {
|
1569
|
+
var patternStart = '^([a-zA-Z0-9',
|
1570
|
+
patternEnd = ']+)$',
|
1571
|
+
additionalChars = $el.attr('data-validation-allowing'),
|
1572
|
+
pattern = '';
|
1573
|
+
|
1574
|
+
if( additionalChars ) {
|
1575
|
+
pattern = patternStart + additionalChars + patternEnd;
|
1576
|
+
var extra = additionalChars.replace(/\\/g, '');
|
1577
|
+
if( extra.indexOf(' ') > -1 ) {
|
1578
|
+
extra = extra.replace(' ', '');
|
1579
|
+
extra += ' and spaces ';
|
1580
|
+
}
|
1581
|
+
this.errorMessage = language.badAlphaNumeric + language.badAlphaNumericExtra + extra;
|
1582
|
+
} else {
|
1583
|
+
pattern = patternStart + patternEnd;
|
1584
|
+
this.errorMessage = language.badAlphaNumeric;
|
1585
|
+
}
|
1586
|
+
|
1587
|
+
return new RegExp(pattern).test(val);
|
1588
|
+
},
|
1589
|
+
errorMessage : '',
|
1590
|
+
errorMessageKey: ''
|
1591
|
+
});
|
1592
|
+
|
1593
|
+
/*
|
1594
|
+
* Validate against regexp
|
1595
|
+
*/
|
1596
|
+
$.formUtils.addValidator({
|
1597
|
+
name : 'custom',
|
1598
|
+
validatorFunction : function(val, $el, conf) {
|
1599
|
+
var regexp = new RegExp($el.valAttr('regexp'));
|
1600
|
+
return regexp.test(val);
|
1601
|
+
},
|
1602
|
+
errorMessage : '',
|
1603
|
+
errorMessageKey: 'badCustomVal'
|
1604
|
+
});
|
1605
|
+
|
1606
|
+
/*
|
1607
|
+
* Validate date
|
1608
|
+
*/
|
1609
|
+
$.formUtils.addValidator({
|
1610
|
+
name : 'date',
|
1611
|
+
validatorFunction : function(date, $el, conf) {
|
1612
|
+
var dateFormat = 'yyyy-mm-dd';
|
1613
|
+
if($el.valAttr('format')) {
|
1614
|
+
dateFormat = $el.valAttr('format');
|
1615
|
+
}
|
1616
|
+
else if( conf.dateFormat ) {
|
1617
|
+
dateFormat = conf.dateFormat;
|
1618
|
+
}
|
1619
|
+
|
1620
|
+
return $.formUtils.parseDate(date, dateFormat) !== false;
|
1621
|
+
},
|
1622
|
+
errorMessage : '',
|
1623
|
+
errorMessageKey: 'badDate'
|
1624
|
+
});
|
1625
|
+
|
1626
|
+
|
1627
|
+
/*
|
1628
|
+
* Validate group of checkboxes, validate qty required is checked
|
1629
|
+
* written by Steve Wasiura : http://stevewasiura.waztech.com
|
1630
|
+
* element attrs
|
1631
|
+
* data-validation="checkbox_group"
|
1632
|
+
* data-validation-qty="1-2" // min 1 max 2
|
1633
|
+
* data-validation-error-msg="chose min 1, max of 2 checkboxes"
|
1634
|
+
*/
|
1635
|
+
$.formUtils.addValidator({
|
1636
|
+
name : 'checkbox_group',
|
1637
|
+
validatorFunction : function(val, $el, conf, lang, $form)
|
1638
|
+
{ // preset return var
|
1639
|
+
var checkResult = true;
|
1640
|
+
// get name of element. since it is a checkbox group, all checkboxes will have same name
|
1641
|
+
var elname = $el.attr('name');
|
1642
|
+
// get count of checked checkboxes with this name
|
1643
|
+
var checkedCount = $("input[type=checkbox][name^='"+elname+"']:checked", $form).length;
|
1644
|
+
// get el attr that specs qty required / allowed
|
1645
|
+
var qtyAllowed = $el.valAttr('qty');
|
1646
|
+
if (qtyAllowed == undefined) {
|
1647
|
+
var elementType = $el.get(0).nodeName;
|
1648
|
+
alert('Attribute "data-validation-qty" is missing from '+elementType+' named '+$el.attr('name'));
|
1649
|
+
}
|
1650
|
+
// call Utility function to check if count is above min, below max, within range etc.
|
1651
|
+
var qtyCheckResults = $.formUtils.numericRangeCheck(checkedCount, qtyAllowed) ;
|
1652
|
+
// results will be array, [0]=result str, [1]=qty int
|
1653
|
+
switch(qtyCheckResults[0] ) {
|
1654
|
+
// outside allowed range
|
1655
|
+
case "out":
|
1656
|
+
this.errorMessage = lang.groupCheckedRangeStart + qtyAllowed + lang.groupCheckedEnd;
|
1657
|
+
checkResult = false;
|
1658
|
+
break;
|
1659
|
+
// below min qty
|
1660
|
+
case "min":
|
1661
|
+
this.errorMessage = lang.groupCheckedTooFewStart + qtyCheckResults[1] + lang.groupCheckedEnd;
|
1662
|
+
checkResult = false;
|
1663
|
+
break;
|
1664
|
+
// above max qty
|
1665
|
+
case "max":
|
1666
|
+
this.errorMessage = lang.groupCheckedTooManyStart + qtyCheckResults[1] + lang.groupCheckedEnd;
|
1667
|
+
checkResult = false;
|
1668
|
+
break;
|
1669
|
+
// ok
|
1670
|
+
default:
|
1671
|
+
checkResult = true;
|
1672
|
+
}
|
1673
|
+
|
1674
|
+
return checkResult;
|
1675
|
+
|
1676
|
+
}
|
1677
|
+
// errorMessage : '', // set above in switch statement
|
1678
|
+
// errorMessageKey: '' // not used
|
1679
|
+
});
|
1680
|
+
|
1681
|
+
})(jQuery);
|