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