dqs-jquery-form-validator-rails 2.2.163 → 2.2.164

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +21 -0
  3. data/CHANGELOG.md +4 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +24 -0
  6. data/README.md +451 -0
  7. data/Rakefile +1 -0
  8. data/app/assets/javascripts/brazil.dev.js +115 -0
  9. data/app/assets/javascripts/brazil.js +9 -0
  10. data/app/assets/javascripts/date.dev.js +81 -0
  11. data/app/assets/javascripts/date.js +9 -0
  12. data/app/assets/javascripts/file.dev.js +413 -0
  13. data/app/assets/javascripts/file.js +9 -0
  14. data/app/assets/javascripts/html5.dev.js +168 -0
  15. data/app/assets/javascripts/html5.js +9 -0
  16. data/app/assets/javascripts/jquery.form-validator.min.js +9 -0
  17. data/app/assets/javascripts/jsconf.dev.js +55 -0
  18. data/app/assets/javascripts/jsconf.js +9 -0
  19. data/app/assets/javascripts/lang/cz.dev.js +65 -0
  20. data/app/assets/javascripts/lang/cz.js +9 -0
  21. data/app/assets/javascripts/lang/de.dev.js +65 -0
  22. data/app/assets/javascripts/lang/de.js +9 -0
  23. data/app/assets/javascripts/lang/es.dev.js +62 -0
  24. data/app/assets/javascripts/lang/es.js +9 -0
  25. data/app/assets/javascripts/lang/fr.dev.js +62 -0
  26. data/app/assets/javascripts/lang/fr.js +9 -0
  27. data/app/assets/javascripts/lang/it.dev.js +62 -0
  28. data/app/assets/javascripts/lang/it.js +9 -0
  29. data/app/assets/javascripts/lang/pl.dev.js +65 -0
  30. data/app/assets/javascripts/lang/pl.js +9 -0
  31. data/app/assets/javascripts/lang/pt.dev.js +65 -0
  32. data/app/assets/javascripts/lang/pt.js +9 -0
  33. data/app/assets/javascripts/lang/ro.dev.js +65 -0
  34. data/app/assets/javascripts/lang/ro.js +9 -0
  35. data/app/assets/javascripts/lang/ru.dev.js +66 -0
  36. data/app/assets/javascripts/lang/ru.js +9 -0
  37. data/app/assets/javascripts/lang/sv.dev.js +63 -0
  38. data/app/assets/javascripts/lang/sv.js +9 -0
  39. data/app/assets/javascripts/location.dev.js +78 -0
  40. data/app/assets/javascripts/location.js +9 -0
  41. data/app/assets/javascripts/sanitize.dev.js +154 -0
  42. data/app/assets/javascripts/sanitize.js +9 -0
  43. data/app/assets/javascripts/security.dev.js +523 -0
  44. data/app/assets/javascripts/security.js +9 -0
  45. data/app/assets/javascripts/src/core-validators.js +343 -0
  46. data/app/assets/javascripts/src/dialogs.js +123 -0
  47. data/app/assets/javascripts/src/jquery-plugins.js +452 -0
  48. data/app/assets/javascripts/src/module-loader.js +150 -0
  49. data/app/assets/javascripts/src/setup.js +168 -0
  50. data/app/assets/javascripts/src/utils.js +840 -0
  51. data/app/assets/javascripts/sweden.dev.js +213 -0
  52. data/app/assets/javascripts/sweden.js +9 -0
  53. data/app/assets/javascripts/theme-default.css +108 -0
  54. data/app/assets/javascripts/theme-default.min.css +1 -0
  55. data/app/assets/javascripts/toggleDisabled.dev.js +67 -0
  56. data/app/assets/javascripts/toggleDisabled.js +9 -0
  57. data/app/assets/javascripts/uk.dev.js +85 -0
  58. data/app/assets/javascripts/uk.js +9 -0
  59. data/dqs-jquery-form-validator.gemspec +27 -0
  60. data/lib/dqs-jquery-form-validator-rails.rb +1 -0
  61. data/lib/dqs/jquery/form/validator/rails.rb +13 -0
  62. data/lib/dqs/jquery/form/validator/rails/engine.rb +12 -0
  63. data/lib/dqs/jquery/form/validator/rails/version.rb +11 -0
  64. metadata +64 -2
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Setup function for the plugin
3
+ */
4
+ (function ($) {
5
+
6
+ 'use strict';
7
+
8
+
9
+ /**
10
+ * A bit smarter split function
11
+ * delimiter can be space, comma, dash or pipe
12
+ * @param {String} val
13
+ * @param {Function|String} [callback]
14
+ * @returns {Array|void}
15
+ */
16
+ $.split = function (val, callback) {
17
+ if (typeof callback !== 'function') {
18
+ // return array
19
+ if (!val) {
20
+ return [];
21
+ }
22
+ var values = [];
23
+ $.each(val.split(callback ? callback : /[,|\-\s]\s*/g),
24
+ function (i, str) {
25
+ str = $.trim(str);
26
+ if (str.length) {
27
+ values.push(str);
28
+ }
29
+ }
30
+ );
31
+ return values;
32
+ } else if (val) {
33
+ // exec callback func on each
34
+ $.each(val.split(/[,|\-\s]\s*/g),
35
+ function (i, str) {
36
+ str = $.trim(str);
37
+ if (str.length) {
38
+ return callback(str, i);
39
+ }
40
+ }
41
+ );
42
+ }
43
+ };
44
+
45
+ /**
46
+ * Short hand function that makes the validation setup require less code
47
+ * @param conf
48
+ */
49
+ $.validate = function (conf) {
50
+
51
+ var defaultConf = $.extend($.formUtils.defaultConfig(), {
52
+ form: 'form',
53
+ validateOnEvent: false,
54
+ validateOnBlur: true,
55
+ validateCheckboxRadioOnClick: true,
56
+ showHelpOnFocus: true,
57
+ addSuggestions: true,
58
+ modules: '',
59
+ onModulesLoaded: null,
60
+ language: false,
61
+ onSuccess: false,
62
+ onError: false,
63
+ onElementValidate: false
64
+ });
65
+
66
+ conf = $.extend(defaultConf, conf || {});
67
+
68
+ if( conf.lang && conf.lang !== 'en' ) {
69
+ var langModule = 'lang/'+conf.lang+'.js';
70
+ conf.modules += conf.modules.length ? ','+langModule : langModule;
71
+ }
72
+
73
+ // Add validation to forms
74
+ $(conf.form).each(function (i, form) {
75
+
76
+ // Make a reference to the config for this form
77
+ form.validationConfig = conf;
78
+
79
+ // Trigger jQuery event that we're about to setup validation
80
+ var $form = $(form);
81
+ $.formUtils.$win.trigger('formValidationSetup', [$form, conf]);
82
+ $form.trigger('formValidationSetup', [conf]);
83
+
84
+ // Remove classes and event handlers that might have been
85
+ // added by a previous call to $.validate
86
+ $form.find('.has-help-txt')
87
+ .unbind('focus.validation')
88
+ .unbind('blur.validation');
89
+
90
+ $form
91
+ .removeClass('has-validation-callback')
92
+ .unbind('submit.validation')
93
+ .unbind('reset.validation')
94
+ .find('input[data-validation],textarea[data-validation]')
95
+ .unbind('blur.validation');
96
+
97
+ // Validate when submitted
98
+ $form.bind('submit.validation', function () {
99
+
100
+ var $form = $(this);
101
+
102
+ if ($.formUtils.haltValidation) {
103
+ // pressing several times on submit button while validation is halted
104
+ return false;
105
+ }
106
+
107
+ if ($.formUtils.isLoadingModules) {
108
+ setTimeout(function () {
109
+ $form.trigger('submit.validation');
110
+ }, 200);
111
+ return false;
112
+ }
113
+
114
+ var valid = $form.isValid(conf.language, conf);
115
+
116
+ if ($.formUtils.haltValidation) {
117
+ // Validation got halted by one of the validators
118
+ return false;
119
+ } else {
120
+ if (valid && typeof conf.onSuccess === 'function') {
121
+ var callbackResponse = conf.onSuccess($form);
122
+ if (callbackResponse === false) {
123
+ return false;
124
+ }
125
+ } else if (!valid && typeof conf.onError === 'function') {
126
+ conf.onError($form);
127
+ return false;
128
+ } else {
129
+ return valid;
130
+ }
131
+ }
132
+ })
133
+ .bind('reset.validation', function () {
134
+ var $this = $(this),
135
+ $elems = $this.find('.' + conf.errorElementClass + ',.valid');
136
+ $this.find('.' + conf.errorMessageClass + '.alert').remove();
137
+ $.formUtils.errorDialogs.removeErrorStyling($elems, conf);
138
+ })
139
+ .addClass('has-validation-callback');
140
+
141
+ if (conf.showHelpOnFocus) {
142
+ $form.showHelpOnFocus();
143
+ }
144
+ if (conf.addSuggestions) {
145
+ $form.addSuggestions();
146
+ }
147
+ if (conf.validateOnBlur) {
148
+ $form.validateOnBlur(conf.language, conf);
149
+ $form.bind('html5ValidationAttrsFound', function () {
150
+ $form.validateOnBlur(conf.language, conf);
151
+ });
152
+ }
153
+ if (conf.validateOnEvent) {
154
+ $form.validateOnEvent(conf.language, conf);
155
+ }
156
+ });
157
+
158
+ if (conf.modules !== '') {
159
+ $.formUtils.loadModules(conf.modules, false, function() {
160
+ if (typeof conf.onModulesLoaded === 'function') {
161
+ conf.onModulesLoaded();
162
+ }
163
+ $.formUtils.$win.trigger('validatorsLoaded', [typeof conf.form === 'string' ? $(conf.form) : conf.form, conf]);
164
+ });
165
+ }
166
+ };
167
+
168
+ })(jQuery);
@@ -0,0 +1,840 @@
1
+ /**
2
+ * Utility methods and properties attached to $.formUtils
3
+ */
4
+ (function($, window) {
5
+
6
+ 'use strict';
7
+
8
+ var $win = $(window);
9
+
10
+ $.formUtils = $.extend($.formUtils || {}, {
11
+
12
+ $win: $win,
13
+
14
+ /**
15
+ * Default config for $(...).isValid();
16
+ */
17
+ defaultConfig: function () {
18
+ return {
19
+ ignore: [], // Names of inputs not to be validated even though node attribute containing the validation rules tells us to
20
+ errorElementClass: 'error', // Class that will be put on elements which value is invalid
21
+ borderColorOnError: '#b94a48', // Border color of elements which value is invalid, empty string to not change border color
22
+ errorMessageClass: 'form-error', // class name of div containing error messages when validation fails
23
+ validationRuleAttribute: 'data-validation', // name of the attribute holding the validation rules
24
+ validationErrorMsgAttribute: 'data-validation-error-msg', // define custom err msg inline with element
25
+ errorMessagePosition: 'element', // Can be either "top" or "element" or "custom"
26
+ errorMessageTemplate: {
27
+ container: '<div class="{errorMessageClass} alert alert-danger">{messages}</div>',
28
+ messages: '<strong>{errorTitle}</strong><ul>{fields}</ul>',
29
+ field: '<li>{msg}</li>'
30
+ },
31
+ errorMessageCustom: this.errorDialogs.setTemplateMessage,
32
+ scrollToTopOnError: true,
33
+ dateFormat: 'yyyy-mm-dd',
34
+ addValidClassOnAll: false, // whether or not to apply class="valid" even if the input wasn't validated
35
+ decimalSeparator: '.',
36
+ inputParentClassOnError: 'has-error', // twitter-bootstrap default class name
37
+ inputParentClassOnSuccess: 'has-success', // twitter-bootstrap default class name
38
+ validateHiddenInputs: false // whether or not hidden inputs should be validated
39
+ };
40
+ },
41
+
42
+ /**
43
+ * Available validators
44
+ */
45
+ validators: {},
46
+
47
+ /**
48
+ * Events triggered by form validator
49
+ */
50
+ _events: {load: [], valid: [], invalid: []},
51
+
52
+ /**
53
+ * Setting this property to true during validation will
54
+ * stop further validation from taking place and form will
55
+ * not be sent
56
+ */
57
+ haltValidation: false,
58
+
59
+ /**
60
+ * This variable will be true $.fn.isValid() is called
61
+ * and false when $.fn.validateOnBlur is called
62
+ */
63
+ isValidatingEntireForm: false,
64
+
65
+ /**
66
+ * Function for adding a validator
67
+ * @param {Object} validator
68
+ */
69
+ addValidator: function (validator) {
70
+ // prefix with "validate_" for backward compatibility reasons
71
+ var name = validator.name.indexOf('validate_') === 0 ? validator.name : 'validate_' + validator.name;
72
+ if (validator.validateOnKeyUp === undefined) {
73
+ validator.validateOnKeyUp = true;
74
+ }
75
+ this.validators[name] = validator;
76
+ },
77
+
78
+ /**
79
+ * @var {Boolean}
80
+ */
81
+ isLoadingModules: false,
82
+
83
+ /**
84
+ * @var {Object}
85
+ */
86
+ loadedModules: {},
87
+
88
+ /**
89
+ * @example
90
+ * $.formUtils.loadModules('date, security.dev');
91
+ *
92
+ * Will load the scripts date.js and security.dev.js from the
93
+ * directory where this script resides. If you want to load
94
+ * the modules from another directory you can use the
95
+ * path argument.
96
+ *
97
+ * The script will be cached by the browser unless the module
98
+ * name ends with .dev
99
+ *
100
+ * @param {String} modules - Comma separated string with module file names (no directory nor file extension)
101
+ * @param {String} [path] - Optional, path where the module files is located if their not in the same directory as the core modules
102
+ * @param {Boolean|function} [fireEvent] - Optional, whether or not to fire event 'load' when modules finished loading
103
+ */
104
+ loadModules: function (modules, path, fireEvent) {
105
+
106
+ if (fireEvent === undefined) {
107
+ fireEvent = true;
108
+ }
109
+
110
+ if ($.formUtils.isLoadingModules) {
111
+ setTimeout(function () {
112
+ $.formUtils.loadModules(modules, path, fireEvent);
113
+ });
114
+ return;
115
+ }
116
+
117
+ var hasLoadedAnyModule = false,
118
+ loadModuleScripts = function (modules, path) {
119
+
120
+ var moduleList = $.split(modules),
121
+ numModules = moduleList.length,
122
+ moduleLoadedCallback = function () {
123
+ numModules--;
124
+ if (numModules === 0) {
125
+ $.formUtils.isLoadingModules = false;
126
+ if (fireEvent && hasLoadedAnyModule) {
127
+ if( typeof fireEvent === 'function' ) {
128
+ fireEvent();
129
+ } else {
130
+ $win.trigger('validatorsLoaded');
131
+ }
132
+ }
133
+ }
134
+ };
135
+
136
+
137
+ if (numModules > 0) {
138
+ $.formUtils.isLoadingModules = true;
139
+ }
140
+
141
+ var cacheSuffix = '?_=' + ( new Date().getTime() ),
142
+ appendToElement = document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0];
143
+
144
+ $.each(moduleList, function (i, modName) {
145
+ modName = $.trim(modName);
146
+ if (modName.length === 0) {
147
+ moduleLoadedCallback();
148
+ }
149
+ else {
150
+ var scriptUrl = path + modName + (modName.slice(-3) === '.js' ? '' : '.js'),
151
+ script = document.createElement('SCRIPT');
152
+
153
+ if (scriptUrl in $.formUtils.loadedModules) {
154
+ // already loaded
155
+ moduleLoadedCallback();
156
+ }
157
+ else {
158
+
159
+ // Remember that this script is loaded
160
+ $.formUtils.loadedModules[scriptUrl] = 1;
161
+ hasLoadedAnyModule = true;
162
+
163
+ // Load the script
164
+ script.type = 'text/javascript';
165
+ script.onload = moduleLoadedCallback;
166
+ script.src = scriptUrl + ( scriptUrl.slice(-7) === '.dev.js' ? cacheSuffix : '' );
167
+ script.onerror = function() {
168
+ $.formUtils.warn('Unable to load form validation module '+scriptUrl);
169
+ };
170
+ script.onreadystatechange = function () {
171
+ // IE 7 fix
172
+ if (this.readyState === 'complete' || this.readyState === 'loaded') {
173
+ moduleLoadedCallback();
174
+ // Handle memory leak in IE
175
+ this.onload = null;
176
+ this.onreadystatechange = null;
177
+ }
178
+ };
179
+ appendToElement.appendChild(script);
180
+ }
181
+ }
182
+ });
183
+ };
184
+
185
+ if (path) {
186
+ loadModuleScripts(modules, path);
187
+ } else {
188
+ var findScriptPathAndLoadModules = function () {
189
+ var foundPath = false;
190
+ $('script[src*="form-validator"]').each(function () {
191
+ foundPath = this.src.substr(0, this.src.lastIndexOf('/')) + '/';
192
+ if (foundPath === '/') {
193
+ foundPath = '';
194
+ }
195
+ return false;
196
+ });
197
+
198
+ if (foundPath !== false) {
199
+ loadModuleScripts(modules, foundPath);
200
+ return true;
201
+ }
202
+ return false;
203
+ };
204
+
205
+ if (!findScriptPathAndLoadModules()) {
206
+ $(findScriptPathAndLoadModules);
207
+ }
208
+ }
209
+ },
210
+
211
+ /**
212
+ * Warn user via the console if available
213
+ */
214
+ warn: function(msg) {
215
+ if( 'console' in window ) {
216
+ if( typeof window.console.warn === 'function' ) {
217
+ window.console.warn(msg);
218
+ } else if( typeof window.console.log === 'function' ) {
219
+ window.console.log(msg);
220
+ }
221
+ } else {
222
+ alert(msg);
223
+ }
224
+ },
225
+
226
+ /**
227
+ * Validate the value of given element according to the validation rules
228
+ * found in the attribute data-validation. Will return an object representing
229
+ * a validation result, having the props shouldChangeDisplay, isValid and errorMsg
230
+ * @param {jQuery} $elem
231
+ * @param {Object} language ($.formUtils.LANG)
232
+ * @param {Object} conf
233
+ * @param {jQuery} $form
234
+ * @param {String} [eventContext]
235
+ * @return {Object}
236
+ */
237
+ validateInput: function ($elem, language, conf, $form, eventContext) {
238
+
239
+ $elem.trigger('beforeValidation');
240
+ conf = conf || $.formUtils.defaultConfig();
241
+ language = language || $.formUtils.LANG;
242
+
243
+ var value = $elem.val() || '',
244
+ result = {isValid: true, shouldChangeDisplay:true, errorMsg:''},
245
+ optional = $elem.valAttr('optional'),
246
+
247
+ // test if a checkbox forces this element to be validated
248
+ validationDependsOnCheckedInput = false,
249
+ validationDependentInputIsChecked = false,
250
+ validateIfCheckedElement = false,
251
+
252
+ // get value of this element's attribute "... if-checked"
253
+ validateIfCheckedElementName = $elem.valAttr('if-checked'),
254
+ // get expected radio button value for "if-checked" optional validation
255
+ validateIfCheckedElementValue = $elem.valAttr('if-checked-value');
256
+
257
+
258
+ if ($elem.attr('disabled') || (!$elem.is(':visible') && !conf.validateHiddenInputs)) {
259
+ result.shouldChangeDisplay = false;
260
+ return result;
261
+ }
262
+
263
+ // make sure we can proceed
264
+ if (validateIfCheckedElementName != null) {
265
+
266
+ // Set the boolean telling us that the validation depends
267
+ // on another input being checked
268
+ validationDependsOnCheckedInput = true;
269
+
270
+ // select the checkbox type element in this form
271
+ validateIfCheckedElement = $form.find('input[name="' + validateIfCheckedElementName + '"]');
272
+
273
+ // test if check input value
274
+ if (validateIfCheckedElementValue != null) {
275
+ validateIfCheckedElement.each(function(index, el) {
276
+ // test if it's property "checked" is checked and value equals expected value
277
+ if ($(el).prop('checked') && $(el).val() === validateIfCheckedElementValue) {
278
+ validationDependentInputIsChecked = true;
279
+ }
280
+ });
281
+ }
282
+ else {
283
+ // test if it's property "checked" is checked
284
+ if (validateIfCheckedElement.prop('checked')) {
285
+ // set value for validation checkpoint
286
+ validationDependentInputIsChecked = true;
287
+ }
288
+ }
289
+ }
290
+
291
+
292
+ // For input type="number", browsers attempt to parse the entered value into a number.
293
+ // If the input is not numeric, browsers handle the situation differently:
294
+ // Chrome 48 simply disallows non-numeric input; FF 44 clears out the input box on blur;
295
+ // Safari 5 parses the entered string to find a leading number.
296
+ // If the input fails browser validation, the browser sets the input value equal to an empty string.
297
+ // Therefore, we cannot distinguish (apart from hacks) between an empty input type="text" and one with a
298
+ // value that can't be parsed by the browser.
299
+
300
+ // validation checkpoint
301
+ // if empty AND optional attribute is present
302
+ // OR depending on a checkbox being checked AND checkbox is checked, return true
303
+ if ((!value && optional === 'true') || (validationDependsOnCheckedInput && !validationDependentInputIsChecked)) {
304
+ result.shouldChangeDisplay = conf.addValidClassOnAll;
305
+ return result;
306
+ }
307
+
308
+ var validationRules = $elem.attr(conf.validationRuleAttribute),
309
+
310
+ // see if form element has inline err msg attribute
311
+ validationErrorMsg = true;
312
+
313
+ if (!validationRules) {
314
+ result.shouldChangeDisplay = conf.addValidClassOnAll;
315
+ return result;
316
+ }
317
+
318
+ // Filter out specified characters
319
+ var ignore = $elem.valAttr('ignore');
320
+ if( ignore ) {
321
+ $.each(ignore.split(''), function(i, char) {
322
+ value = value.replace(new RegExp('\\'+char), '');
323
+ });
324
+ }
325
+
326
+ $.split(validationRules, function (rule) {
327
+ if (rule.indexOf('validate_') !== 0) {
328
+ rule = 'validate_' + rule;
329
+ }
330
+
331
+ var validator = $.formUtils.validators[rule];
332
+
333
+ if (validator && typeof validator.validatorFunction === 'function') {
334
+
335
+ // special change of element for checkbox_group rule
336
+ if (rule === 'validate_checkbox_group') {
337
+ // set element to first in group, so error msg attr doesn't need to be set on all elements in group
338
+ $elem = $form.find('[name="' + $elem.attr('name') + '"]:eq(0)');
339
+ }
340
+
341
+ var isValid = null;
342
+ if (eventContext !== 'keyup' || validator.validateOnKeyUp) {
343
+ isValid = validator.validatorFunction(value, $elem, conf, language, $form);
344
+ }
345
+
346
+ if (!isValid) {
347
+ validationErrorMsg = null;
348
+ if (isValid !== null) {
349
+ validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute + '-' + rule.replace('validate_', ''));
350
+ if (!validationErrorMsg) {
351
+ validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute);
352
+ if (!validationErrorMsg) {
353
+ if (typeof validator.errorMessageKey !== 'function') {
354
+ validationErrorMsg = language[validator.errorMessageKey];
355
+ }
356
+ else {
357
+ validationErrorMsg = language[validator.errorMessageKey(conf)];
358
+ }
359
+ if (!validationErrorMsg) {
360
+ validationErrorMsg = validator.errorMessage;
361
+ }
362
+ }
363
+ }
364
+ }
365
+ return false; // break iteration
366
+ }
367
+
368
+ } else {
369
+
370
+ throw new Error('Using undefined validator "' + rule +
371
+ '". Maybe you have forgotten to load the module that "' + rule +'" belongs to?');
372
+
373
+ }
374
+
375
+ }, ' ');
376
+
377
+ if (typeof validationErrorMsg === 'string') {
378
+ $elem.trigger('validation', false);
379
+ result.errorMsg = validationErrorMsg;
380
+ result.isValid = false;
381
+ result.shouldChangeDisplay = true;
382
+ } else if (validationErrorMsg === null) {
383
+ result.shouldChangeDisplay = conf.addValidClassOnAll;
384
+ } else {
385
+ $elem.trigger('validation', true);
386
+ result.shouldChangeDisplay = true;
387
+ }
388
+
389
+ // Run element validation callback
390
+ if (typeof conf.onElementValidate === 'function' && validationErrorMsg !== null) {
391
+ conf.onElementValidate(result.isValid, $elem, $form, validationErrorMsg);
392
+ }
393
+
394
+ return result;
395
+ },
396
+
397
+ /**
398
+ * Is it a correct date according to given dateFormat. Will return false if not, otherwise
399
+ * an array 0=>year 1=>month 2=>day
400
+ *
401
+ * @param {String} val
402
+ * @param {String} dateFormat
403
+ * @param {Boolean} [addMissingLeadingZeros]
404
+ * @return {Array}|{Boolean}
405
+ */
406
+ parseDate: function (val, dateFormat, addMissingLeadingZeros) {
407
+ var divider = dateFormat.replace(/[a-zA-Z]/gi, '').substring(0, 1),
408
+ regexp = '^',
409
+ formatParts = dateFormat.split(divider || null),
410
+ matches, day, month, year;
411
+
412
+ $.each(formatParts, function (i, part) {
413
+ regexp += (i > 0 ? '\\' + divider : '') + '(\\d{' + part.length + '})';
414
+ });
415
+
416
+ regexp += '$';
417
+
418
+ if (addMissingLeadingZeros) {
419
+ var newValueParts = [];
420
+ $.each(val.split(divider), function(i, part) {
421
+ if(part.length === 1) {
422
+ part = '0'+part;
423
+ }
424
+ newValueParts.push(part);
425
+ });
426
+ val = newValueParts.join(divider);
427
+ }
428
+
429
+ matches = val.match(new RegExp(regexp));
430
+ if (matches === null) {
431
+ return false;
432
+ }
433
+
434
+ var findDateUnit = function (unit, formatParts, matches) {
435
+ for (var i = 0; i < formatParts.length; i++) {
436
+ if (formatParts[i].substring(0, 1) === unit) {
437
+ return $.formUtils.parseDateInt(matches[i + 1]);
438
+ }
439
+ }
440
+ return -1;
441
+ };
442
+
443
+ month = findDateUnit('m', formatParts, matches);
444
+ day = findDateUnit('d', formatParts, matches);
445
+ year = findDateUnit('y', formatParts, matches);
446
+
447
+ if ((month === 2 && day > 28 && (year % 4 !== 0 || year % 100 === 0 && year % 400 !== 0)) ||
448
+ (month === 2 && day > 29 && (year % 4 === 0 || year % 100 !== 0 && year % 400 === 0)) ||
449
+ month > 12 || month === 0) {
450
+ return false;
451
+ }
452
+ if ((this.isShortMonth(month) && day > 30) || (!this.isShortMonth(month) && day > 31) || day === 0) {
453
+ return false;
454
+ }
455
+
456
+ return [year, month, day];
457
+ },
458
+
459
+ /**
460
+ * skum fix. är talet 05 eller lägre ger parseInt rätt int annars får man 0 när man kör parseInt?
461
+ *
462
+ * @param {String} val
463
+ * @return {Number}
464
+ */
465
+ parseDateInt: function (val) {
466
+ if (val.indexOf('0') === 0) {
467
+ val = val.replace('0', '');
468
+ }
469
+ return parseInt(val, 10);
470
+ },
471
+
472
+ /**
473
+ * Has month only 30 days?
474
+ *
475
+ * @param {Number} m
476
+ * @return {Boolean}
477
+ */
478
+ isShortMonth: function (m) {
479
+ return (m % 2 === 0 && m < 7) || (m % 2 !== 0 && m > 7);
480
+ },
481
+
482
+ /**
483
+ * Restrict input length
484
+ *
485
+ * @param {jQuery} $inputElement Jquery Html object
486
+ * @param {jQuery} $maxLengthElement jQuery Html Object
487
+ * @return void
488
+ */
489
+ lengthRestriction: function ($inputElement, $maxLengthElement) {
490
+ // read maxChars from counter display initial text value
491
+ var maxChars = parseInt($maxLengthElement.text(), 10),
492
+ charsLeft = 0,
493
+
494
+ // internal function does the counting and sets display value
495
+ countCharacters = function () {
496
+ var numChars = $inputElement.val().length;
497
+ if (numChars > maxChars) {
498
+ // get current scroll bar position
499
+ var currScrollTopPos = $inputElement.scrollTop();
500
+ // trim value to max length
501
+ $inputElement.val($inputElement.val().substring(0, maxChars));
502
+ $inputElement.scrollTop(currScrollTopPos);
503
+ }
504
+ charsLeft = maxChars - numChars;
505
+ if (charsLeft < 0) {
506
+ charsLeft = 0;
507
+ }
508
+
509
+ // set counter text
510
+ $maxLengthElement.text(charsLeft);
511
+ };
512
+
513
+ // bind events to this element
514
+ // setTimeout is needed, cut or paste fires before val is available
515
+ $($inputElement).bind('keydown keyup keypress focus blur', countCharacters)
516
+ .bind('cut paste', function () {
517
+ setTimeout(countCharacters, 100);
518
+ });
519
+
520
+ // count chars on pageload, if there are prefilled input-values
521
+ $(document).bind('ready', countCharacters);
522
+ },
523
+
524
+ /**
525
+ * Test numeric against allowed range
526
+ *
527
+ * @param $value int
528
+ * @param $rangeAllowed str; (1-2, min1, max2, 10)
529
+ * @return array
530
+ */
531
+ numericRangeCheck: function (value, rangeAllowed) {
532
+ // split by dash
533
+ var range = $.split(rangeAllowed),
534
+ // min or max
535
+ minmax = parseInt(rangeAllowed.substr(3), 10);
536
+
537
+ if( range.length === 1 && rangeAllowed.indexOf('min') === -1 && rangeAllowed.indexOf('max') === -1 ) {
538
+ range = [rangeAllowed, rangeAllowed]; // only a number, checking agains an exact number of characters
539
+ }
540
+
541
+ // range ?
542
+ if (range.length === 2 && (value < parseInt(range[0], 10) || value > parseInt(range[1], 10) )) {
543
+ return [ 'out', range[0], range[1] ];
544
+ } // value is out of range
545
+ else if (rangeAllowed.indexOf('min') === 0 && (value < minmax )) // min
546
+ {
547
+ return ['min', minmax];
548
+ } // value is below min
549
+ else if (rangeAllowed.indexOf('max') === 0 && (value > minmax )) // max
550
+ {
551
+ return ['max', minmax];
552
+ } // value is above max
553
+ // since no other returns executed, value is in allowed range
554
+ return [ 'ok' ];
555
+ },
556
+
557
+
558
+ _numSuggestionElements: 0,
559
+ _selectedSuggestion: null,
560
+ _previousTypedVal: null,
561
+
562
+ /**
563
+ * Utility function that can be used to create plugins that gives
564
+ * suggestions when inputs is typed into
565
+ * @param {jQuery} $elem
566
+ * @param {Array} suggestions
567
+ * @param {Object} settings - Optional
568
+ * @return {jQuery}
569
+ */
570
+ suggest: function ($elem, suggestions, settings) {
571
+ var conf = {
572
+ css: {
573
+ maxHeight: '150px',
574
+ background: '#FFF',
575
+ lineHeight: '150%',
576
+ textDecoration: 'underline',
577
+ overflowX: 'hidden',
578
+ overflowY: 'auto',
579
+ border: '#CCC solid 1px',
580
+ borderTop: 'none',
581
+ cursor: 'pointer'
582
+ },
583
+ activeSuggestionCSS: {
584
+ background: '#E9E9E9'
585
+ }
586
+ },
587
+ setSuggsetionPosition = function ($suggestionContainer, $input) {
588
+ var offset = $input.offset();
589
+ $suggestionContainer.css({
590
+ width: $input.outerWidth(),
591
+ left: offset.left + 'px',
592
+ top: (offset.top + $input.outerHeight()) + 'px'
593
+ });
594
+ };
595
+
596
+ if (settings) {
597
+ $.extend(conf, settings);
598
+ }
599
+
600
+ conf.css.position = 'absolute';
601
+ conf.css['z-index'] = 9999;
602
+ $elem.attr('autocomplete', 'off');
603
+
604
+ if (this._numSuggestionElements === 0) {
605
+ // Re-position suggestion container if window size changes
606
+ $win.bind('resize', function () {
607
+ $('.jquery-form-suggestions').each(function () {
608
+ var $container = $(this),
609
+ suggestID = $container.attr('data-suggest-container');
610
+ setSuggsetionPosition($container, $('.suggestions-' + suggestID).eq(0));
611
+ });
612
+ });
613
+ }
614
+
615
+ this._numSuggestionElements++;
616
+
617
+ var onSelectSuggestion = function ($el) {
618
+ var suggestionId = $el.valAttr('suggestion-nr');
619
+ $.formUtils._selectedSuggestion = null;
620
+ $.formUtils._previousTypedVal = null;
621
+ $('.jquery-form-suggestion-' + suggestionId).fadeOut('fast');
622
+ };
623
+
624
+ $elem
625
+ .data('suggestions', suggestions)
626
+ .valAttr('suggestion-nr', this._numSuggestionElements)
627
+ .unbind('focus.suggest')
628
+ .bind('focus.suggest', function () {
629
+ $(this).trigger('keyup');
630
+ $.formUtils._selectedSuggestion = null;
631
+ })
632
+ .unbind('keyup.suggest')
633
+ .bind('keyup.suggest', function () {
634
+ var $input = $(this),
635
+ foundSuggestions = [],
636
+ val = $.trim($input.val()).toLocaleLowerCase();
637
+
638
+ if (val === $.formUtils._previousTypedVal) {
639
+ return;
640
+ }
641
+ else {
642
+ $.formUtils._previousTypedVal = val;
643
+ }
644
+
645
+ var hasTypedSuggestion = false,
646
+ suggestionId = $input.valAttr('suggestion-nr'),
647
+ $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
648
+
649
+ $suggestionContainer.scrollTop(0);
650
+
651
+ // Find the right suggestions
652
+ if (val !== '') {
653
+ var findPartial = val.length > 2;
654
+ $.each($input.data('suggestions'), function (i, suggestion) {
655
+ var lowerCaseVal = suggestion.toLocaleLowerCase();
656
+ if (lowerCaseVal === val) {
657
+ foundSuggestions.push('<strong>' + suggestion + '</strong>');
658
+ hasTypedSuggestion = true;
659
+ return false;
660
+ } else if (lowerCaseVal.indexOf(val) === 0 || (findPartial && lowerCaseVal.indexOf(val) > -1)) {
661
+ foundSuggestions.push(suggestion.replace(new RegExp(val, 'gi'), '<strong>$&</strong>'));
662
+ }
663
+ });
664
+ }
665
+
666
+ // Hide suggestion container
667
+ if (hasTypedSuggestion || (foundSuggestions.length === 0 && $suggestionContainer.length > 0)) {
668
+ $suggestionContainer.hide();
669
+ }
670
+
671
+ // Create suggestion container if not already exists
672
+ else if (foundSuggestions.length > 0 && $suggestionContainer.length === 0) {
673
+ $suggestionContainer = $('<div></div>').css(conf.css).appendTo('body');
674
+ $elem.addClass('suggestions-' + suggestionId);
675
+ $suggestionContainer
676
+ .attr('data-suggest-container', suggestionId)
677
+ .addClass('jquery-form-suggestions')
678
+ .addClass('jquery-form-suggestion-' + suggestionId);
679
+ }
680
+
681
+ // Show hidden container
682
+ else if (foundSuggestions.length > 0 && !$suggestionContainer.is(':visible')) {
683
+ $suggestionContainer.show();
684
+ }
685
+
686
+ // add suggestions
687
+ if (foundSuggestions.length > 0 && val.length !== foundSuggestions[0].length) {
688
+
689
+ // put container in place every time, just in case
690
+ setSuggsetionPosition($suggestionContainer, $input);
691
+
692
+ // Add suggestions HTML to container
693
+ $suggestionContainer.html('');
694
+ $.each(foundSuggestions, function (i, text) {
695
+ $('<div></div>')
696
+ .append(text)
697
+ .css({
698
+ overflow: 'hidden',
699
+ textOverflow: 'ellipsis',
700
+ whiteSpace: 'nowrap',
701
+ padding: '5px'
702
+ })
703
+ .addClass('form-suggest-element')
704
+ .appendTo($suggestionContainer)
705
+ .click(function () {
706
+ $input.focus();
707
+ $input.val($(this).text());
708
+ onSelectSuggestion($input);
709
+ });
710
+ });
711
+ }
712
+ })
713
+ .unbind('keydown.validation')
714
+ .bind('keydown.validation', function (e) {
715
+ var code = (e.keyCode ? e.keyCode : e.which),
716
+ suggestionId,
717
+ $suggestionContainer,
718
+ $input = $(this);
719
+
720
+ if (code === 13 && $.formUtils._selectedSuggestion !== null) {
721
+ suggestionId = $input.valAttr('suggestion-nr');
722
+ $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
723
+ if ($suggestionContainer.length > 0) {
724
+ var newText = $suggestionContainer.find('div').eq($.formUtils._selectedSuggestion).text();
725
+ $input.val(newText);
726
+ onSelectSuggestion($input);
727
+ e.preventDefault();
728
+ }
729
+ }
730
+ else {
731
+ suggestionId = $input.valAttr('suggestion-nr');
732
+ $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
733
+ var $suggestions = $suggestionContainer.children();
734
+ if ($suggestions.length > 0 && $.inArray(code, [38, 40]) > -1) {
735
+ if (code === 38) { // key up
736
+ if ($.formUtils._selectedSuggestion === null) {
737
+ $.formUtils._selectedSuggestion = $suggestions.length - 1;
738
+ }
739
+ else{
740
+ $.formUtils._selectedSuggestion--;
741
+ }
742
+ if ($.formUtils._selectedSuggestion < 0) {
743
+ $.formUtils._selectedSuggestion = $suggestions.length - 1;
744
+ }
745
+ }
746
+ else if (code === 40) { // key down
747
+ if ($.formUtils._selectedSuggestion === null) {
748
+ $.formUtils._selectedSuggestion = 0;
749
+ }
750
+ else {
751
+ $.formUtils._selectedSuggestion++;
752
+ }
753
+ if ($.formUtils._selectedSuggestion > ($suggestions.length - 1)) {
754
+ $.formUtils._selectedSuggestion = 0;
755
+ }
756
+ }
757
+
758
+ // Scroll in suggestion window
759
+ var containerInnerHeight = $suggestionContainer.innerHeight(),
760
+ containerScrollTop = $suggestionContainer.scrollTop(),
761
+ suggestionHeight = $suggestionContainer.children().eq(0).outerHeight(),
762
+ activeSuggestionPosY = suggestionHeight * ($.formUtils._selectedSuggestion);
763
+
764
+ if (activeSuggestionPosY < containerScrollTop || activeSuggestionPosY > (containerScrollTop + containerInnerHeight)) {
765
+ $suggestionContainer.scrollTop(activeSuggestionPosY);
766
+ }
767
+
768
+ $suggestions
769
+ .removeClass('active-suggestion')
770
+ .css('background', 'none')
771
+ .eq($.formUtils._selectedSuggestion)
772
+ .addClass('active-suggestion')
773
+ .css(conf.activeSuggestionCSS);
774
+
775
+ e.preventDefault();
776
+ return false;
777
+ }
778
+ }
779
+ })
780
+ .unbind('blur.suggest')
781
+ .bind('blur.suggest', function () {
782
+ onSelectSuggestion($(this));
783
+ });
784
+
785
+ return $elem;
786
+ },
787
+
788
+ /**
789
+ * Error dialogs
790
+ *
791
+ * @var {Object}
792
+ */
793
+ LANG: {
794
+ errorTitle: 'Form submission failed!',
795
+ requiredField: 'This is a required field',
796
+ requiredFields: 'You have not answered all required fields',
797
+ badTime: 'You have not given a correct time',
798
+ badEmail: 'You have not given a correct e-mail address',
799
+ badTelephone: 'You have not given a correct phone number',
800
+ badSecurityAnswer: 'You have not given a correct answer to the security question',
801
+ badDate: 'You have not given a correct date',
802
+ lengthBadStart: 'The input value must be between ',
803
+ lengthBadEnd: ' characters',
804
+ lengthTooLongStart: 'The input value is longer than ',
805
+ lengthTooShortStart: 'The input value is shorter than ',
806
+ notConfirmed: 'Input values could not be confirmed',
807
+ badDomain: 'Incorrect domain value',
808
+ badUrl: 'The input value is not a correct URL',
809
+ badCustomVal: 'The input value is incorrect',
810
+ andSpaces: ' and spaces ',
811
+ badInt: 'The input value was not a correct number',
812
+ badSecurityNumber: 'Your social security number was incorrect',
813
+ badUKVatAnswer: 'Incorrect UK VAT Number',
814
+ badStrength: 'The password isn\'t strong enough',
815
+ badNumberOfSelectedOptionsStart: 'You have to choose at least ',
816
+ badNumberOfSelectedOptionsEnd: ' answers',
817
+ badAlphaNumeric: 'The input value can only contain alphanumeric characters ',
818
+ badAlphaNumericExtra: ' and ',
819
+ wrongFileSize: 'The file you are trying to upload is too large (max %s)',
820
+ wrongFileType: 'Only files of type %s is allowed',
821
+ groupCheckedRangeStart: 'Please choose between ',
822
+ groupCheckedTooFewStart: 'Please choose at least ',
823
+ groupCheckedTooManyStart: 'Please choose a maximum of ',
824
+ groupCheckedEnd: ' item(s)',
825
+ badCreditCard: 'The credit card number is not correct',
826
+ badCVV: 'The CVV number was not correct',
827
+ wrongFileDim : 'Incorrect image dimensions,',
828
+ imageTooTall : 'the image can not be taller than',
829
+ imageTooWide : 'the image can not be wider than',
830
+ imageTooSmall : 'the image was too small',
831
+ min : 'min',
832
+ max : 'max',
833
+ imageRatioNotAccepted : 'Image ratio is not be accepted',
834
+ badBrazilTelephoneAnswer: 'The phone number entered is invalid',
835
+ badBrazilCEPAnswer: 'The CEP entered is invalid',
836
+ badBrazilCPFAnswer: 'The CPF entered is invalid'
837
+ }
838
+ });
839
+
840
+ })(jQuery, window);