client_side_validations 15.0.0 → 16.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +48 -16
- data/lib/client_side_validations/version.rb +1 -1
- data/vendor/assets/javascripts/rails.validations.js +656 -490
- metadata +19 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43b783baa4ef85e0722508e882ae809de87bc469f480a740f81eff2d7e103e55
|
4
|
+
data.tar.gz: 22d4a7022f6403cfeca96a1eca204cd94454135fbf11b196193c196ba0d19344
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a4fb820cf1b79a10295f504e0a3bf229578d4611d2e2a4aa82e2050735a436da730fb815bcd3db98aaca914c532a5d98b1d7743e671642337eab73d22cf0b3b
|
7
|
+
data.tar.gz: 3d2eebecc60968800d8fb9b4b013055658ea0ae100e73012ee50988bd41271a6d23999587bd0e8524c74fb8c17db733197e0b60bcf2c59301cb45acf5ede696e
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 16.0.0 / 2019-08-23
|
4
|
+
|
5
|
+
* [FEATURE] Move to ES6
|
6
|
+
* [FEATURE] Add Webpacker compatibility
|
7
|
+
* [BUGFIX] Fix acceptance validator
|
8
|
+
* [ENHANCEMENT] Update development dependencies
|
9
|
+
|
3
10
|
## 15.0.0 / 2019-05-14
|
4
11
|
|
5
12
|
* [FEATURE] Drop Ruby 2.2 support
|
@@ -163,6 +170,7 @@
|
|
163
170
|
## 6.0.0 / 2017-01-20
|
164
171
|
|
165
172
|
* [FEATURE] Rails 5.0 compatibility
|
173
|
+
* [FEATURE] Drop Rails 4.x support
|
166
174
|
|
167
175
|
## 4.2.12 / 2017-01-19
|
168
176
|
|
data/README.md
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# ClientSideValidations #
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/client_side_validations)
|
4
|
+
[](https://badge.fury.io/js/%40client-side-validations%2Fclient-side-validations)
|
4
5
|
[](https://travis-ci.org/DavyJonesLocker/client_side_validations)
|
5
6
|
[](https://codeclimate.com/github/DavyJonesLocker/client_side_validations/maintainability)
|
6
7
|
[](https://coveralls.io/github/DavyJonesLocker/client_side_validations?branch=master)
|
7
8
|
|
8
|
-
`ClientSideValidations` made easy for your Rails 5.x / Rails 6 applications!
|
9
|
+
`ClientSideValidations` made easy for your Rails 5.x / Rails 6.0 applications!
|
9
10
|
|
10
11
|
## Project Goals ##
|
11
12
|
|
@@ -49,11 +50,53 @@ This will install the initializer:
|
|
49
50
|
config/initializers/client_side_validations.rb
|
50
51
|
```
|
51
52
|
|
52
|
-
|
53
|
+
### JavaScript file ###
|
54
|
+
|
55
|
+
Instructions depend on your technology stack.
|
56
|
+
|
57
|
+
Please note that CSV depends on jQuery >= 1.12.4 (jQuery slim is fine).
|
58
|
+
|
59
|
+
#### When using Webpacker ####
|
60
|
+
|
61
|
+
Make sure that you are requiring jQuery.
|
62
|
+
|
63
|
+
Add the following package:
|
64
|
+
|
65
|
+
```sh
|
66
|
+
yarn add @client-side-validations/client-side-validations
|
67
|
+
```
|
68
|
+
|
69
|
+
Then add the following line to your `app/javascript/packs/application.js` pack:
|
70
|
+
|
71
|
+
```js
|
72
|
+
import '@client-side-validations/client-side-validations'
|
73
|
+
```
|
74
|
+
|
75
|
+
If you are using [Turbolinks](https://github.com/turbolinks/turbolinks),
|
76
|
+
make sure that '@client-side-validations/client-side-validations' is imported
|
77
|
+
**after** `Turbolinks.start()`, so ClientSideValidations can properly attach its
|
78
|
+
event handlers.
|
79
|
+
|
80
|
+
#### When using Sprockets ####
|
81
|
+
|
82
|
+
Make sure that you are requiring jQuery.
|
83
|
+
|
84
|
+
Add the following to your `app/assets/javascripts/application.js` file.
|
85
|
+
|
86
|
+
```js
|
87
|
+
//= require rails.validations
|
88
|
+
```
|
89
|
+
|
90
|
+
If you are using [Turbolinks](https://github.com/turbolinks/turbolinks),
|
91
|
+
make sure that `rails.validations` is required **after** `turbolinks`, so
|
92
|
+
ClientSideValidations can properly attach its event handlers.
|
93
|
+
|
94
|
+
If you need to copy the asset files from the gem into your project, run:
|
53
95
|
|
54
96
|
```
|
55
97
|
rails g client_side_validations:copy_assets
|
56
98
|
```
|
99
|
+
|
57
100
|
Note: If you run `copy_assets`, you will need to run it again each time you update this project.
|
58
101
|
|
59
102
|
## Initializer ##
|
@@ -79,17 +122,6 @@ Rails `FormBuilders`. Please see the [Plugin wiki page](https://github.com/DavyJ
|
|
79
122
|
|
80
123
|
## Usage ##
|
81
124
|
|
82
|
-
The javascript file is served up in the asset pipeline. Add the
|
83
|
-
following to your `app/assets/javascripts/application.js` file.
|
84
|
-
|
85
|
-
```js
|
86
|
-
//= require rails.validations
|
87
|
-
```
|
88
|
-
|
89
|
-
Note: If you are using [Turbolinks](https://github.com/turbolinks/turbolinks),
|
90
|
-
make sure that `rails.validations` is required **after** `turbolinks`, so
|
91
|
-
ClientSideValidations can properly attach its event handler.
|
92
|
-
|
93
125
|
In your `FormBuilder` you only need to enable validations:
|
94
126
|
|
95
127
|
```erb
|
@@ -119,9 +151,9 @@ in the form. Given the following model:
|
|
119
151
|
|
120
152
|
```ruby
|
121
153
|
class Person < ActiveRecord::Base
|
122
|
-
validates :name,
|
154
|
+
validates :name, presence: true, length: { maximum: 10 }, if: :can_validate?
|
123
155
|
|
124
|
-
def can_validate
|
156
|
+
def can_validate?
|
125
157
|
true
|
126
158
|
end
|
127
159
|
end
|
@@ -247,7 +279,7 @@ were overwritten by the call to `FormBuilder#validate`
|
|
247
279
|
|
248
280
|
If you need to change the markup of how the errors are rendered you can modify that in `config/initializers/client_side_validations.rb`
|
249
281
|
|
250
|
-
*Please Note* if you modify the markup, you will also need to modify `ClientSideValidations.formBuilders['ActionView::Helpers::FormBuilder']`'s `add` and `remove` functions. You can override the behavior by creating a new
|
282
|
+
*Please Note* if you modify the markup, you will also need to modify `ClientSideValidations.formBuilders['ActionView::Helpers::FormBuilder']`'s `add` and `remove` functions. You can override the behavior by creating a new JavaScript file called `rails.validations.actionView.js` that contains the following:
|
251
283
|
|
252
284
|
```js
|
253
285
|
window.ClientSideValidations.formBuilders['ActionView::Helpers::FormBuilder'] = {
|
@@ -1,286 +1,185 @@
|
|
1
|
-
|
2
1
|
/*!
|
3
|
-
* Client Side Validations -
|
2
|
+
* Client Side Validations JS - v0.0.3 (https://github.com/DavyJonesLocker/client_side_validations)
|
4
3
|
* Copyright (c) 2019 Geremia Taglialatela, Brian Cardarella
|
5
4
|
* Licensed under MIT (https://opensource.org/licenses/mit-license.php)
|
6
5
|
*/
|
7
6
|
|
8
|
-
(function() {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
$.fn.disableClientSideValidations = function() {
|
15
|
-
ClientSideValidations.disable(this);
|
16
|
-
return this;
|
17
|
-
};
|
18
|
-
|
19
|
-
$.fn.enableClientSideValidations = function() {
|
20
|
-
this.filter(ClientSideValidations.selectors.forms).each(function() {
|
21
|
-
return ClientSideValidations.enablers.form(this);
|
22
|
-
});
|
23
|
-
this.filter(ClientSideValidations.selectors.inputs).each(function() {
|
24
|
-
return ClientSideValidations.enablers.input(this);
|
25
|
-
});
|
26
|
-
return this;
|
27
|
-
};
|
28
|
-
|
29
|
-
$.fn.resetClientSideValidations = function() {
|
30
|
-
this.filter(ClientSideValidations.selectors.forms).each(function() {
|
31
|
-
return ClientSideValidations.reset(this);
|
32
|
-
});
|
33
|
-
return this;
|
34
|
-
};
|
35
|
-
|
36
|
-
$.fn.validate = function() {
|
37
|
-
this.filter(ClientSideValidations.selectors.forms).each(function() {
|
38
|
-
return $(this).enableClientSideValidations();
|
39
|
-
});
|
40
|
-
return this;
|
41
|
-
};
|
42
|
-
|
43
|
-
$.fn.isValid = function(validators) {
|
44
|
-
var obj;
|
45
|
-
obj = $(this[0]);
|
46
|
-
if (obj.is('form')) {
|
47
|
-
return validateForm(obj, validators);
|
48
|
-
} else {
|
49
|
-
return validateElement(obj, validatorsFor(this[0].name, validators));
|
50
|
-
}
|
51
|
-
};
|
7
|
+
(function (global, factory) {
|
8
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) :
|
9
|
+
typeof define === 'function' && define.amd ? define(['jquery'], factory) :
|
10
|
+
(global = global || self, global.clientSideValidations = factory(global.$));
|
11
|
+
}(this, function ($) { 'use strict';
|
52
12
|
|
53
|
-
|
54
|
-
var captures, validator, validator_name;
|
55
|
-
if (validators.hasOwnProperty(name)) {
|
56
|
-
return validators[name];
|
57
|
-
}
|
58
|
-
name = name.replace(/\[(\w+_attributes)\]\[[\da-z_]+\](?=\[(?:\w+_attributes)\])/g, '[$1][]');
|
59
|
-
if (captures = name.match(/\[(\w+_attributes)\].*\[(\w+)\]$/)) {
|
60
|
-
for (validator_name in validators) {
|
61
|
-
validator = validators[validator_name];
|
62
|
-
if (validator_name.match("\\[" + captures[1] + "\\].*\\[\\]\\[" + captures[2] + "\\]$")) {
|
63
|
-
name = name.replace(/\[[\da-z_]+\]\[(\w+)\]$/g, '[][$1]');
|
64
|
-
}
|
65
|
-
}
|
66
|
-
}
|
67
|
-
return validators[name] || {};
|
68
|
-
};
|
13
|
+
$ = $ && $.hasOwnProperty('default') ? $['default'] : $;
|
69
14
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
if (!$(this).isValid(validators)) {
|
76
|
-
valid = false;
|
77
|
-
}
|
78
|
-
return true;
|
79
|
-
});
|
80
|
-
if (valid) {
|
81
|
-
form.trigger('form:validate:pass.ClientSideValidations');
|
15
|
+
function _typeof(obj) {
|
16
|
+
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
|
17
|
+
_typeof = function (obj) {
|
18
|
+
return typeof obj;
|
19
|
+
};
|
82
20
|
} else {
|
83
|
-
|
21
|
+
_typeof = function (obj) {
|
22
|
+
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
23
|
+
};
|
84
24
|
}
|
85
|
-
form.trigger('form:validate:after.ClientSideValidations');
|
86
|
-
return valid;
|
87
|
-
};
|
88
25
|
|
89
|
-
|
90
|
-
|
91
|
-
element.trigger('element:validate:before.ClientSideValidations');
|
92
|
-
passElement = function() {
|
93
|
-
return element.trigger('element:validate:pass.ClientSideValidations').data('valid', null);
|
94
|
-
};
|
95
|
-
failElement = function(message) {
|
96
|
-
element.trigger('element:validate:fail.ClientSideValidations', message).data('valid', false);
|
97
|
-
return false;
|
98
|
-
};
|
99
|
-
afterValidate = function() {
|
100
|
-
return element.trigger('element:validate:after.ClientSideValidations').data('valid') !== false;
|
101
|
-
};
|
102
|
-
executeValidators = function(context) {
|
103
|
-
var fn, i, kind, len, message, ref, valid, validator;
|
104
|
-
valid = true;
|
105
|
-
for (kind in context) {
|
106
|
-
fn = context[kind];
|
107
|
-
if (validators[kind]) {
|
108
|
-
ref = validators[kind];
|
109
|
-
for (i = 0, len = ref.length; i < len; i++) {
|
110
|
-
validator = ref[i];
|
111
|
-
if (message = fn.call(context, element, validator)) {
|
112
|
-
valid = failElement(message);
|
113
|
-
break;
|
114
|
-
}
|
115
|
-
}
|
116
|
-
if (!valid) {
|
117
|
-
break;
|
118
|
-
}
|
119
|
-
}
|
120
|
-
}
|
121
|
-
return valid;
|
122
|
-
};
|
123
|
-
if (element.attr('name').search(/\[([^\]]*?)\]$/) >= 0) {
|
124
|
-
destroyInputName = element.attr('name').replace(/\[([^\]]*?)\]$/, '[_destroy]');
|
125
|
-
if ($("input[name='" + destroyInputName + "']").val() === '1') {
|
126
|
-
passElement();
|
127
|
-
return afterValidate();
|
128
|
-
}
|
129
|
-
}
|
130
|
-
if (element.data('changed') === false) {
|
131
|
-
return afterValidate();
|
132
|
-
}
|
133
|
-
element.data('changed', false);
|
134
|
-
local = ClientSideValidations.validators.local;
|
135
|
-
remote = ClientSideValidations.validators.remote;
|
136
|
-
if (executeValidators(local) && executeValidators(remote)) {
|
137
|
-
passElement();
|
138
|
-
}
|
139
|
-
return afterValidate();
|
140
|
-
};
|
26
|
+
return _typeof(obj);
|
27
|
+
}
|
141
28
|
|
142
|
-
ClientSideValidations = {
|
29
|
+
var ClientSideValidations = {
|
143
30
|
callbacks: {
|
144
31
|
element: {
|
145
|
-
after: function(element, eventData) {},
|
146
|
-
before: function(element, eventData) {},
|
147
|
-
fail: function(element, message, addError, eventData) {
|
32
|
+
after: function after(element, eventData) {},
|
33
|
+
before: function before(element, eventData) {},
|
34
|
+
fail: function fail(element, message, addError, eventData) {
|
148
35
|
return addError();
|
149
36
|
},
|
150
|
-
pass: function(element, removeError, eventData) {
|
37
|
+
pass: function pass(element, removeError, eventData) {
|
151
38
|
return removeError();
|
152
39
|
}
|
153
40
|
},
|
154
41
|
form: {
|
155
|
-
after: function(form, eventData) {},
|
156
|
-
before: function(form, eventData) {},
|
157
|
-
fail: function(form, eventData) {},
|
158
|
-
pass: function(form, eventData) {}
|
42
|
+
after: function after(form, eventData) {},
|
43
|
+
before: function before(form, eventData) {},
|
44
|
+
fail: function fail(form, eventData) {},
|
45
|
+
pass: function pass(form, eventData) {}
|
159
46
|
}
|
160
47
|
},
|
161
|
-
|
162
|
-
form: function(form) {
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
settings: $form.data('clientSideValidations'),
|
167
|
-
addError: function(element, message) {
|
168
|
-
return ClientSideValidations.formBuilders[form.ClientSideValidations.settings.html_settings.type].add(element, form.ClientSideValidations.settings.html_settings, message);
|
169
|
-
},
|
170
|
-
removeError: function(element) {
|
171
|
-
return ClientSideValidations.formBuilders[form.ClientSideValidations.settings.html_settings.type].remove(element, form.ClientSideValidations.settings.html_settings);
|
172
|
-
}
|
173
|
-
};
|
174
|
-
ref = {
|
175
|
-
'submit.ClientSideValidations': function(eventData) {
|
176
|
-
if (!$form.isValid(form.ClientSideValidations.settings.validators)) {
|
48
|
+
eventsToBind: {
|
49
|
+
form: function form(_form, $form) {
|
50
|
+
return {
|
51
|
+
'submit.ClientSideValidations': function submitClientSideValidations(eventData) {
|
52
|
+
if (!$form.isValid(_form.ClientSideValidations.settings.validators)) {
|
177
53
|
eventData.preventDefault();
|
178
54
|
eventData.stopImmediatePropagation();
|
179
55
|
}
|
180
56
|
},
|
181
|
-
'ajax:beforeSend.ClientSideValidations': function(eventData) {
|
57
|
+
'ajax:beforeSend.ClientSideValidations': function ajaxBeforeSendClientSideValidations(eventData) {
|
182
58
|
if (eventData.target === this) {
|
183
|
-
$form.isValid(
|
59
|
+
$form.isValid(_form.ClientSideValidations.settings.validators);
|
184
60
|
}
|
185
61
|
},
|
186
|
-
'form:validate:after.ClientSideValidations': function(eventData) {
|
62
|
+
'form:validate:after.ClientSideValidations': function formValidateAfterClientSideValidations(eventData) {
|
187
63
|
ClientSideValidations.callbacks.form.after($form, eventData);
|
188
64
|
},
|
189
|
-
'form:validate:before.ClientSideValidations': function(eventData) {
|
65
|
+
'form:validate:before.ClientSideValidations': function formValidateBeforeClientSideValidations(eventData) {
|
190
66
|
ClientSideValidations.callbacks.form.before($form, eventData);
|
191
67
|
},
|
192
|
-
'form:validate:fail.ClientSideValidations': function(eventData) {
|
68
|
+
'form:validate:fail.ClientSideValidations': function formValidateFailClientSideValidations(eventData) {
|
193
69
|
ClientSideValidations.callbacks.form.fail($form, eventData);
|
194
70
|
},
|
195
|
-
'form:validate:pass.ClientSideValidations': function(eventData) {
|
71
|
+
'form:validate:pass.ClientSideValidations': function formValidatePassClientSideValidations(eventData) {
|
196
72
|
ClientSideValidations.callbacks.form.pass($form, eventData);
|
197
73
|
}
|
198
74
|
};
|
199
|
-
for (event in ref) {
|
200
|
-
binding = ref[event];
|
201
|
-
$form.on(event, binding);
|
202
|
-
}
|
203
|
-
return $form.find(ClientSideValidations.selectors.inputs).each(function() {
|
204
|
-
return ClientSideValidations.enablers.input(this);
|
205
|
-
});
|
206
75
|
},
|
207
|
-
input: function(
|
208
|
-
|
209
|
-
|
210
|
-
form = input.form;
|
211
|
-
$form = $(form);
|
212
|
-
ref = {
|
213
|
-
'focusout.ClientSideValidations': function() {
|
76
|
+
input: function input(form) {
|
77
|
+
return {
|
78
|
+
'focusout.ClientSideValidations': function focusoutClientSideValidations() {
|
214
79
|
$(this).isValid(form.ClientSideValidations.settings.validators);
|
215
80
|
},
|
216
|
-
'change.ClientSideValidations': function() {
|
81
|
+
'change.ClientSideValidations': function changeClientSideValidations() {
|
217
82
|
$(this).data('changed', true);
|
218
83
|
},
|
219
|
-
'element:validate:after.ClientSideValidations': function(eventData) {
|
84
|
+
'element:validate:after.ClientSideValidations': function elementValidateAfterClientSideValidations(eventData) {
|
220
85
|
ClientSideValidations.callbacks.element.after($(this), eventData);
|
221
86
|
},
|
222
|
-
'element:validate:before.ClientSideValidations': function(eventData) {
|
87
|
+
'element:validate:before.ClientSideValidations': function elementValidateBeforeClientSideValidations(eventData) {
|
223
88
|
ClientSideValidations.callbacks.element.before($(this), eventData);
|
224
89
|
},
|
225
|
-
'element:validate:fail.ClientSideValidations': function(eventData, message) {
|
226
|
-
var element;
|
227
|
-
element
|
228
|
-
|
229
|
-
return form.ClientSideValidations.addError(element, message);
|
90
|
+
'element:validate:fail.ClientSideValidations': function elementValidateFailClientSideValidations(eventData, message) {
|
91
|
+
var $element = $(this);
|
92
|
+
ClientSideValidations.callbacks.element.fail($element, message, function () {
|
93
|
+
return form.ClientSideValidations.addError($element, message);
|
230
94
|
}, eventData);
|
231
95
|
},
|
232
|
-
'element:validate:pass.ClientSideValidations': function(eventData) {
|
233
|
-
var element;
|
234
|
-
element
|
235
|
-
|
236
|
-
return form.ClientSideValidations.removeError(element);
|
96
|
+
'element:validate:pass.ClientSideValidations': function elementValidatePassClientSideValidations(eventData) {
|
97
|
+
var $element = $(this);
|
98
|
+
ClientSideValidations.callbacks.element.pass($element, function () {
|
99
|
+
return form.ClientSideValidations.removeError($element);
|
237
100
|
}, eventData);
|
238
101
|
}
|
239
102
|
};
|
240
|
-
|
241
|
-
|
242
|
-
|
103
|
+
},
|
104
|
+
inputConfirmation: function inputConfirmation(element, form) {
|
105
|
+
return {
|
106
|
+
'focusout.ClientSideValidations': function focusoutClientSideValidations() {
|
107
|
+
element.data('changed', true).isValid(form.ClientSideValidations.settings.validators);
|
108
|
+
},
|
109
|
+
'keyup.ClientSideValidations': function keyupClientSideValidations() {
|
110
|
+
element.data('changed', true).isValid(form.ClientSideValidations.settings.validators);
|
111
|
+
}
|
112
|
+
};
|
113
|
+
}
|
114
|
+
},
|
115
|
+
enablers: {
|
116
|
+
form: function form(_form2) {
|
117
|
+
var $form = $(_form2);
|
118
|
+
_form2.ClientSideValidations = {
|
119
|
+
settings: $form.data('clientSideValidations'),
|
120
|
+
addError: function addError(element, message) {
|
121
|
+
return ClientSideValidations.formBuilders[_form2.ClientSideValidations.settings.html_settings.type].add(element, _form2.ClientSideValidations.settings.html_settings, message);
|
122
|
+
},
|
123
|
+
removeError: function removeError(element) {
|
124
|
+
return ClientSideValidations.formBuilders[_form2.ClientSideValidations.settings.html_settings.type].remove(element, _form2.ClientSideValidations.settings.html_settings);
|
125
|
+
}
|
126
|
+
};
|
127
|
+
var eventsToBind = ClientSideValidations.eventsToBind.form(_form2, $form);
|
128
|
+
|
129
|
+
for (var eventName in eventsToBind) {
|
130
|
+
var eventFunction = eventsToBind[eventName];
|
131
|
+
$form.on(eventName, eventFunction);
|
132
|
+
}
|
133
|
+
|
134
|
+
$form.find(ClientSideValidations.selectors.inputs).each(function () {
|
135
|
+
ClientSideValidations.enablers.input(this);
|
136
|
+
});
|
137
|
+
},
|
138
|
+
input: function input(_input) {
|
139
|
+
var $input = $(_input);
|
140
|
+
var form = _input.form;
|
141
|
+
var $form = $(form);
|
142
|
+
var eventsToBind = ClientSideValidations.eventsToBind.input(form);
|
143
|
+
|
144
|
+
for (var eventName in eventsToBind) {
|
145
|
+
var eventFunction = eventsToBind[eventName];
|
146
|
+
$input.filter(':not(:radio):not([id$=_confirmation])').each(function () {
|
243
147
|
return $(this).attr('data-validate', true);
|
244
|
-
}).on(
|
148
|
+
}).on(eventName, eventFunction);
|
245
149
|
}
|
246
|
-
|
150
|
+
|
151
|
+
$input.filter(':checkbox').on('change.ClientSideValidations', function () {
|
247
152
|
$(this).isValid(form.ClientSideValidations.settings.validators);
|
248
153
|
});
|
249
|
-
|
250
|
-
var
|
251
|
-
|
252
|
-
|
253
|
-
if (
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
'
|
259
|
-
element.data('changed', true).isValid(form.ClientSideValidations.settings.validators);
|
260
|
-
}
|
261
|
-
};
|
262
|
-
results = [];
|
263
|
-
for (event in ref1) {
|
264
|
-
binding = ref1[event];
|
265
|
-
results.push($("#" + (confirmationElement.attr('id'))).on(event, binding));
|
154
|
+
$input.filter('[id$=_confirmation]').each(function () {
|
155
|
+
var $element = $(this);
|
156
|
+
var $elementToConfirm = $form.find('#' + this.id.match(/(.+)_confirmation/)[1] + ':input');
|
157
|
+
|
158
|
+
if ($elementToConfirm.length) {
|
159
|
+
var _eventsToBind = ClientSideValidations.eventsToBind.inputConfirmation($elementToConfirm, form);
|
160
|
+
|
161
|
+
for (var _eventName in _eventsToBind) {
|
162
|
+
var _eventFunction = _eventsToBind[_eventName];
|
163
|
+
$('#' + $element.attr('id')).on(_eventName, _eventFunction);
|
266
164
|
}
|
267
|
-
return results;
|
268
165
|
}
|
269
166
|
});
|
270
167
|
}
|
271
168
|
},
|
272
169
|
formBuilders: {
|
273
170
|
'ActionView::Helpers::FormBuilder': {
|
274
|
-
add: function(element, settings, message) {
|
275
|
-
var form
|
276
|
-
|
277
|
-
if (element.data('valid') !== false &&
|
278
|
-
inputErrorField = $(settings.input_tag);
|
279
|
-
labelErrorField = $(settings.label_tag);
|
280
|
-
label = form.find("label[for='" +
|
171
|
+
add: function add(element, settings, message) {
|
172
|
+
var form = $(element[0].form);
|
173
|
+
|
174
|
+
if (element.data('valid') !== false && form.find("label.message[for='" + element.attr('id') + "']")[0] == null) {
|
175
|
+
var inputErrorField = $(settings.input_tag);
|
176
|
+
var labelErrorField = $(settings.label_tag);
|
177
|
+
var label = form.find("label[for='" + element.attr('id') + "']:not(.message)");
|
178
|
+
|
281
179
|
if (element.attr('autofocus')) {
|
282
180
|
element.attr('autofocus', false);
|
283
181
|
}
|
182
|
+
|
284
183
|
element.before(inputErrorField);
|
285
184
|
inputErrorField.find('span#input_tag').replaceWith(element);
|
286
185
|
inputErrorField.find('label.message').attr('for', element.attr('id'));
|
@@ -288,20 +187,21 @@
|
|
288
187
|
labelErrorField.insertAfter(label);
|
289
188
|
labelErrorField.find('label#label_tag').replaceWith(label);
|
290
189
|
}
|
291
|
-
|
190
|
+
|
191
|
+
form.find("label.message[for='" + element.attr('id') + "']").text(message);
|
292
192
|
},
|
293
|
-
remove: function(element, settings) {
|
294
|
-
var
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
193
|
+
remove: function remove(element, settings) {
|
194
|
+
var form = $(element[0].form);
|
195
|
+
var errorFieldClass = $(settings.input_tag).attr('class');
|
196
|
+
var inputErrorField = element.closest('.' + errorFieldClass.replace(/ /g, '.'));
|
197
|
+
var label = form.find("label[for='" + element.attr('id') + "']:not(.message)");
|
198
|
+
var labelErrorField = label.closest('.' + errorFieldClass);
|
199
|
+
|
300
200
|
if (inputErrorField[0]) {
|
301
|
-
inputErrorField.find(
|
201
|
+
inputErrorField.find('#' + element.attr('id')).detach();
|
302
202
|
inputErrorField.replaceWith(element);
|
303
203
|
label.detach();
|
304
|
-
|
204
|
+
labelErrorField.replaceWith(label);
|
305
205
|
}
|
306
206
|
}
|
307
207
|
}
|
@@ -318,285 +218,551 @@
|
|
318
218
|
forms: 'form[data-client-side-validations]'
|
319
219
|
},
|
320
220
|
validators: {
|
321
|
-
all: function() {
|
322
|
-
return $.extend({}
|
323
|
-
},
|
324
|
-
local: {
|
325
|
-
absence: function(element, options) {
|
326
|
-
if (!/^\s*$/.test(element.val() || '')) {
|
327
|
-
return options.message;
|
328
|
-
}
|
329
|
-
},
|
330
|
-
presence: function(element, options) {
|
331
|
-
if (/^\s*$/.test(element.val() || '')) {
|
332
|
-
return options.message;
|
333
|
-
}
|
334
|
-
},
|
335
|
-
acceptance: function(element, options) {
|
336
|
-
var ref;
|
337
|
-
switch (element.attr('type')) {
|
338
|
-
case 'checkbox':
|
339
|
-
if (!element.prop('checked')) {
|
340
|
-
return options.message;
|
341
|
-
}
|
342
|
-
break;
|
343
|
-
case 'text':
|
344
|
-
if (element.val() !== (((ref = options.accept) != null ? ref.toString() : void 0) || '1')) {
|
345
|
-
return options.message;
|
346
|
-
}
|
347
|
-
}
|
348
|
-
},
|
349
|
-
format: function(element, options) {
|
350
|
-
var message;
|
351
|
-
message = this.presence(element, options);
|
352
|
-
if (message) {
|
353
|
-
if (options.allow_blank === true) {
|
354
|
-
return;
|
355
|
-
}
|
356
|
-
return message;
|
357
|
-
}
|
358
|
-
if (options["with"] && !new RegExp(options["with"].source, options["with"].options).test(element.val())) {
|
359
|
-
return options.message;
|
360
|
-
}
|
361
|
-
if (options.without && new RegExp(options.without.source, options.without.options).test(element.val())) {
|
362
|
-
return options.message;
|
363
|
-
}
|
364
|
-
},
|
365
|
-
numericality: function(element, options) {
|
366
|
-
var $form, NUMERICALITY_CHECKS, check, checkValue, check_function, number_format, val;
|
367
|
-
if (options.allow_blank === true && this.presence(element, {
|
368
|
-
message: options.messages.numericality
|
369
|
-
})) {
|
370
|
-
return;
|
371
|
-
}
|
372
|
-
$form = $(element[0].form);
|
373
|
-
number_format = $form[0].ClientSideValidations.settings.number_format;
|
374
|
-
val = $.trim(element.val()).replace(new RegExp("\\" + number_format.separator, 'g'), '.');
|
375
|
-
if (options.only_integer && !ClientSideValidations.patterns.numericality.only_integer.test(val)) {
|
376
|
-
return options.messages.only_integer;
|
377
|
-
}
|
378
|
-
if (!ClientSideValidations.patterns.numericality["default"].test(val)) {
|
379
|
-
return options.messages.numericality;
|
380
|
-
}
|
381
|
-
NUMERICALITY_CHECKS = {
|
382
|
-
greater_than: function(a, b) {
|
383
|
-
return a > b;
|
384
|
-
},
|
385
|
-
greater_than_or_equal_to: function(a, b) {
|
386
|
-
return a >= b;
|
387
|
-
},
|
388
|
-
equal_to: function(a, b) {
|
389
|
-
return a === b;
|
390
|
-
},
|
391
|
-
less_than: function(a, b) {
|
392
|
-
return a < b;
|
393
|
-
},
|
394
|
-
less_than_or_equal_to: function(a, b) {
|
395
|
-
return a <= b;
|
396
|
-
}
|
397
|
-
};
|
398
|
-
for (check in NUMERICALITY_CHECKS) {
|
399
|
-
check_function = NUMERICALITY_CHECKS[check];
|
400
|
-
if (!(options[check] != null)) {
|
401
|
-
continue;
|
402
|
-
}
|
403
|
-
checkValue = !isNaN(parseFloat(options[check])) && isFinite(options[check]) ? options[check] : $form.find("[name*=" + options[check] + "]").length === 1 ? $form.find("[name*=" + options[check] + "]").val() : void 0;
|
404
|
-
if ((checkValue == null) || checkValue === '') {
|
405
|
-
return;
|
406
|
-
}
|
407
|
-
if (!check_function(parseFloat(val), parseFloat(checkValue))) {
|
408
|
-
return options.messages[check];
|
409
|
-
}
|
410
|
-
}
|
411
|
-
if (options.odd && !(parseInt(val, 10) % 2)) {
|
412
|
-
return options.messages.odd;
|
413
|
-
}
|
414
|
-
if (options.even && (parseInt(val, 10) % 2)) {
|
415
|
-
return options.messages.even;
|
416
|
-
}
|
417
|
-
},
|
418
|
-
length: function(element, options) {
|
419
|
-
var LENGTH_CHECKS, blankOptions, check, check_function, length, message;
|
420
|
-
length = element.val().length;
|
421
|
-
LENGTH_CHECKS = {
|
422
|
-
is: function(a, b) {
|
423
|
-
return a === b;
|
424
|
-
},
|
425
|
-
minimum: function(a, b) {
|
426
|
-
return a >= b;
|
427
|
-
},
|
428
|
-
maximum: function(a, b) {
|
429
|
-
return a <= b;
|
430
|
-
}
|
431
|
-
};
|
432
|
-
blankOptions = {};
|
433
|
-
blankOptions.message = options.is ? options.messages.is : options.minimum ? options.messages.minimum : void 0;
|
434
|
-
message = this.presence(element, blankOptions);
|
435
|
-
if (message) {
|
436
|
-
if (options.allow_blank === true) {
|
437
|
-
return;
|
438
|
-
}
|
439
|
-
return message;
|
440
|
-
}
|
441
|
-
for (check in LENGTH_CHECKS) {
|
442
|
-
check_function = LENGTH_CHECKS[check];
|
443
|
-
if (options[check]) {
|
444
|
-
if (!check_function(length, parseInt(options[check]))) {
|
445
|
-
return options.messages[check];
|
446
|
-
}
|
447
|
-
}
|
448
|
-
}
|
449
|
-
},
|
450
|
-
exclusion: function(element, options) {
|
451
|
-
var lower, message, option, ref, upper;
|
452
|
-
message = this.presence(element, options);
|
453
|
-
if (message) {
|
454
|
-
if (options.allow_blank === true) {
|
455
|
-
return;
|
456
|
-
}
|
457
|
-
return message;
|
458
|
-
}
|
459
|
-
if (options["in"]) {
|
460
|
-
if (ref = element.val(), indexOf.call((function() {
|
461
|
-
var i, len, ref1, results;
|
462
|
-
ref1 = options["in"];
|
463
|
-
results = [];
|
464
|
-
for (i = 0, len = ref1.length; i < len; i++) {
|
465
|
-
option = ref1[i];
|
466
|
-
results.push(option.toString());
|
467
|
-
}
|
468
|
-
return results;
|
469
|
-
})(), ref) >= 0) {
|
470
|
-
return options.message;
|
471
|
-
}
|
472
|
-
}
|
473
|
-
if (options.range) {
|
474
|
-
lower = options.range[0];
|
475
|
-
upper = options.range[1];
|
476
|
-
if (element.val() >= lower && element.val() <= upper) {
|
477
|
-
return options.message;
|
478
|
-
}
|
479
|
-
}
|
480
|
-
},
|
481
|
-
inclusion: function(element, options) {
|
482
|
-
var lower, message, option, ref, upper;
|
483
|
-
message = this.presence(element, options);
|
484
|
-
if (message) {
|
485
|
-
if (options.allow_blank === true) {
|
486
|
-
return;
|
487
|
-
}
|
488
|
-
return message;
|
489
|
-
}
|
490
|
-
if (options["in"]) {
|
491
|
-
if (ref = element.val(), indexOf.call((function() {
|
492
|
-
var i, len, ref1, results;
|
493
|
-
ref1 = options["in"];
|
494
|
-
results = [];
|
495
|
-
for (i = 0, len = ref1.length; i < len; i++) {
|
496
|
-
option = ref1[i];
|
497
|
-
results.push(option.toString());
|
498
|
-
}
|
499
|
-
return results;
|
500
|
-
})(), ref) >= 0) {
|
501
|
-
return;
|
502
|
-
}
|
503
|
-
return options.message;
|
504
|
-
}
|
505
|
-
if (options.range) {
|
506
|
-
lower = options.range[0];
|
507
|
-
upper = options.range[1];
|
508
|
-
if (element.val() >= lower && element.val() <= upper) {
|
509
|
-
return;
|
510
|
-
}
|
511
|
-
return options.message;
|
512
|
-
}
|
513
|
-
},
|
514
|
-
confirmation: function(element, options) {
|
515
|
-
var confirmation_value, value;
|
516
|
-
value = element.val();
|
517
|
-
confirmation_value = $("#" + (element.attr('id')) + "_confirmation").val();
|
518
|
-
if (!options.case_sensitive) {
|
519
|
-
value = value.toLowerCase();
|
520
|
-
confirmation_value = confirmation_value.toLowerCase();
|
521
|
-
}
|
522
|
-
if (value !== confirmation_value) {
|
523
|
-
return options.message;
|
524
|
-
}
|
525
|
-
},
|
526
|
-
uniqueness: function(element, options) {
|
527
|
-
var form, matches, name, name_prefix, name_suffix, valid, value;
|
528
|
-
name = element.attr('name');
|
529
|
-
if (/_attributes\]\[\d/.test(name)) {
|
530
|
-
matches = name.match(/^(.+_attributes\])\[\d+\](.+)$/);
|
531
|
-
name_prefix = matches[1];
|
532
|
-
name_suffix = matches[2];
|
533
|
-
value = element.val();
|
534
|
-
if (name_prefix && name_suffix) {
|
535
|
-
form = element.closest('form');
|
536
|
-
valid = true;
|
537
|
-
form.find(":input[name^=\"" + name_prefix + "\"][name$=\"" + name_suffix + "\"]").each(function() {
|
538
|
-
var other_value;
|
539
|
-
other_value = $(this).val();
|
540
|
-
if (!options.case_sensitive) {
|
541
|
-
value = value.toLowerCase();
|
542
|
-
other_value = other_value.toLowerCase();
|
543
|
-
}
|
544
|
-
if ($(this).attr('name') !== name) {
|
545
|
-
if (other_value === value) {
|
546
|
-
valid = false;
|
547
|
-
return $(this).data('notLocallyUnique', true);
|
548
|
-
} else {
|
549
|
-
if ($(this).data('notLocallyUnique')) {
|
550
|
-
return $(this).removeData('notLocallyUnique').data('changed', true);
|
551
|
-
}
|
552
|
-
}
|
553
|
-
}
|
554
|
-
});
|
555
|
-
if (!valid) {
|
556
|
-
return options.message;
|
557
|
-
}
|
558
|
-
}
|
559
|
-
}
|
560
|
-
}
|
221
|
+
all: function all() {
|
222
|
+
return $.extend({});
|
561
223
|
},
|
224
|
+
local: {},
|
562
225
|
remote: {}
|
563
226
|
},
|
564
|
-
disable: function(target) {
|
565
|
-
var $target;
|
566
|
-
$target = $(target);
|
227
|
+
disable: function disable(target) {
|
228
|
+
var $target = $(target);
|
567
229
|
$target.off('.ClientSideValidations');
|
230
|
+
|
568
231
|
if ($target.is('form')) {
|
569
|
-
|
232
|
+
ClientSideValidations.disable($target.find(':input'));
|
570
233
|
} else {
|
571
|
-
$target.removeData('valid');
|
572
|
-
$target.
|
573
|
-
|
574
|
-
return $(this).removeAttr('data-validate');
|
234
|
+
$target.removeData(['changed', 'valid']);
|
235
|
+
$target.filter(':input').each(function () {
|
236
|
+
$(this).removeAttr('data-validate');
|
575
237
|
});
|
576
238
|
}
|
577
239
|
},
|
578
|
-
reset: function(form) {
|
579
|
-
var $form
|
580
|
-
$form = $(form);
|
240
|
+
reset: function reset(form) {
|
241
|
+
var $form = $(form);
|
581
242
|
ClientSideValidations.disable(form);
|
582
|
-
|
243
|
+
|
244
|
+
for (var key in form.ClientSideValidations.settings.validators) {
|
583
245
|
form.ClientSideValidations.removeError($form.find("[name='" + key + "']"));
|
584
246
|
}
|
585
|
-
|
247
|
+
|
248
|
+
ClientSideValidations.enablers.form(form);
|
249
|
+
},
|
250
|
+
start: function start() {
|
251
|
+
if (window.Turbolinks != null && window.Turbolinks.supported) {
|
252
|
+
var initializeOnEvent = window.Turbolinks.EVENTS != null ? 'page:change' : 'turbolinks:load';
|
253
|
+
$(document).on(initializeOnEvent, function () {
|
254
|
+
return $(ClientSideValidations.selectors.forms).validate();
|
255
|
+
});
|
256
|
+
} else {
|
257
|
+
$(function () {
|
258
|
+
return $(ClientSideValidations.selectors.forms).validate();
|
259
|
+
});
|
260
|
+
}
|
261
|
+
}
|
262
|
+
};
|
263
|
+
|
264
|
+
var arrayHasValue = function arrayHasValue(value, otherValues) {
|
265
|
+
for (var i = 0, l = otherValues.length; i < l; i++) {
|
266
|
+
if (value === otherValues[i]) {
|
267
|
+
return true;
|
268
|
+
}
|
269
|
+
}
|
270
|
+
|
271
|
+
return false;
|
272
|
+
};
|
273
|
+
var valueIsPresent = function valueIsPresent(value) {
|
274
|
+
return !/^\s*$/.test(value || '');
|
275
|
+
};
|
276
|
+
|
277
|
+
var absenceLocalValidator = function absenceLocalValidator(element, options) {
|
278
|
+
if (valueIsPresent(element.val())) {
|
279
|
+
return options.message;
|
280
|
+
}
|
281
|
+
};
|
282
|
+
var presenceLocalValidator = function presenceLocalValidator(element, options) {
|
283
|
+
if (!valueIsPresent(element.val())) {
|
284
|
+
return options.message;
|
285
|
+
}
|
286
|
+
};
|
287
|
+
|
288
|
+
var DEFAULT_ACCEPT_OPTION = ['1', true];
|
289
|
+
Array.isArray || (Array.isArray = function (a) {
|
290
|
+
var object = {};
|
291
|
+
return '' + a !== a && object.toString.call(a) === '[object Array]';
|
292
|
+
});
|
293
|
+
|
294
|
+
var isTextAccepted = function isTextAccepted(value, acceptOption) {
|
295
|
+
if (!acceptOption) {
|
296
|
+
acceptOption = DEFAULT_ACCEPT_OPTION;
|
297
|
+
}
|
298
|
+
|
299
|
+
if (Array.isArray(acceptOption)) {
|
300
|
+
return arrayHasValue(value, acceptOption);
|
301
|
+
}
|
302
|
+
|
303
|
+
return value === acceptOption;
|
304
|
+
};
|
305
|
+
|
306
|
+
var acceptanceLocalValidator = function acceptanceLocalValidator(element, options) {
|
307
|
+
var valid = true;
|
308
|
+
|
309
|
+
if (element.attr('type') === 'checkbox') {
|
310
|
+
valid = element.prop('checked');
|
311
|
+
}
|
312
|
+
|
313
|
+
if (element.attr('type') === 'text') {
|
314
|
+
valid = isTextAccepted(element.val(), options.accept);
|
315
|
+
}
|
316
|
+
|
317
|
+
if (!valid) {
|
318
|
+
return options.message;
|
319
|
+
}
|
320
|
+
};
|
321
|
+
|
322
|
+
var isMatching = function isMatching(value, regExpOptions) {
|
323
|
+
return new RegExp(regExpOptions.source, regExpOptions.options).test(value);
|
324
|
+
};
|
325
|
+
|
326
|
+
var hasValidFormat = function hasValidFormat(value, withOptions, withoutOptions) {
|
327
|
+
return withOptions && isMatching(value, withOptions) || withoutOptions && !isMatching(value, withoutOptions);
|
328
|
+
};
|
329
|
+
|
330
|
+
var formatLocalValidator = function formatLocalValidator(element, options) {
|
331
|
+
var value = element.val();
|
332
|
+
|
333
|
+
if (options.allow_blank && !valueIsPresent(value)) {
|
334
|
+
return;
|
335
|
+
}
|
336
|
+
|
337
|
+
if (!hasValidFormat(value, options["with"], options.without)) {
|
338
|
+
return options.message;
|
339
|
+
}
|
340
|
+
};
|
341
|
+
|
342
|
+
var VALIDATIONS = {
|
343
|
+
even: function even(a) {
|
344
|
+
return parseInt(a, 10) % 2 === 0;
|
345
|
+
},
|
346
|
+
greater_than: function greater_than(a, b) {
|
347
|
+
return parseFloat(a) > parseFloat(b);
|
348
|
+
},
|
349
|
+
greater_than_or_equal_to: function greater_than_or_equal_to(a, b) {
|
350
|
+
return parseFloat(a) >= parseFloat(b);
|
351
|
+
},
|
352
|
+
equal_to: function equal_to(a, b) {
|
353
|
+
return parseFloat(a) === parseFloat(b);
|
354
|
+
},
|
355
|
+
less_than: function less_than(a, b) {
|
356
|
+
return parseFloat(a) < parseFloat(b);
|
357
|
+
},
|
358
|
+
less_than_or_equal_to: function less_than_or_equal_to(a, b) {
|
359
|
+
return parseFloat(a) <= parseFloat(b);
|
360
|
+
},
|
361
|
+
odd: function odd(a) {
|
362
|
+
return parseInt(a, 10) % 2 === 1;
|
363
|
+
}
|
364
|
+
};
|
365
|
+
|
366
|
+
var getOtherValue = function getOtherValue(validationOption, $form) {
|
367
|
+
if (!isNaN(parseFloat(validationOption))) {
|
368
|
+
return validationOption;
|
369
|
+
}
|
370
|
+
|
371
|
+
var validationElement = $form.find('[name*=' + validationOption + ']');
|
372
|
+
|
373
|
+
if (validationElement.length === 1) {
|
374
|
+
var numberFormat = $form[0].ClientSideValidations.settings.number_format;
|
375
|
+
var otherFormattedValue = $.trim(validationElement.val()).replace(new RegExp('\\' + numberFormat.separator, 'g'), '.');
|
376
|
+
|
377
|
+
if (!isNaN(parseFloat(otherFormattedValue))) {
|
378
|
+
return otherFormattedValue;
|
379
|
+
}
|
380
|
+
}
|
381
|
+
};
|
382
|
+
|
383
|
+
var isValid = function isValid(validationFunction, validationOption, formattedValue, $form) {
|
384
|
+
if (validationFunction.length === 2) {
|
385
|
+
var otherValue = getOtherValue(validationOption, $form);
|
386
|
+
return otherValue == null || otherValue === '' || validationFunction(formattedValue, otherValue);
|
387
|
+
} else {
|
388
|
+
return validationFunction(formattedValue);
|
389
|
+
}
|
390
|
+
};
|
391
|
+
|
392
|
+
var runFunctionValidations = function runFunctionValidations(formattedValue, $form, options) {
|
393
|
+
for (var validation in VALIDATIONS) {
|
394
|
+
var validationOption = options[validation];
|
395
|
+
var validationFunction = VALIDATIONS[validation]; // Must check for null because this could be 0
|
396
|
+
|
397
|
+
if (validationOption == null) {
|
398
|
+
continue;
|
399
|
+
}
|
400
|
+
|
401
|
+
if (!isValid(validationFunction, validationOption, formattedValue, $form)) {
|
402
|
+
return options.messages[validation];
|
403
|
+
}
|
404
|
+
}
|
405
|
+
};
|
406
|
+
|
407
|
+
var runValidations = function runValidations(formattedValue, $form, options) {
|
408
|
+
if (options.only_integer && !ClientSideValidations.patterns.numericality.only_integer.test(formattedValue)) {
|
409
|
+
return options.messages.only_integer;
|
410
|
+
}
|
411
|
+
|
412
|
+
if (!ClientSideValidations.patterns.numericality["default"].test(formattedValue)) {
|
413
|
+
return options.messages.numericality;
|
414
|
+
}
|
415
|
+
|
416
|
+
return runFunctionValidations(formattedValue, $form, options);
|
417
|
+
};
|
418
|
+
|
419
|
+
var numericalityLocalValidator = function numericalityLocalValidator(element, options) {
|
420
|
+
var value = element.val();
|
421
|
+
|
422
|
+
if (options.allow_blank && !valueIsPresent(value)) {
|
423
|
+
return;
|
424
|
+
}
|
425
|
+
|
426
|
+
var $form = $(element[0].form);
|
427
|
+
var numberFormat = $form[0].ClientSideValidations.settings.number_format;
|
428
|
+
var formattedValue = $.trim(value).replace(new RegExp('\\' + numberFormat.separator, 'g'), '.');
|
429
|
+
return runValidations(formattedValue, $form, options);
|
430
|
+
};
|
431
|
+
|
432
|
+
var VALIDATIONS$1 = {
|
433
|
+
is: function is(a, b) {
|
434
|
+
return a === parseInt(b, 10);
|
435
|
+
},
|
436
|
+
minimum: function minimum(a, b) {
|
437
|
+
return a >= parseInt(b, 10);
|
438
|
+
},
|
439
|
+
maximum: function maximum(a, b) {
|
440
|
+
return a <= parseInt(b, 10);
|
441
|
+
}
|
442
|
+
};
|
443
|
+
|
444
|
+
var runValidations$1 = function runValidations(valueLength, options) {
|
445
|
+
for (var validation in VALIDATIONS$1) {
|
446
|
+
var validationOption = options[validation];
|
447
|
+
var validationFunction = VALIDATIONS$1[validation];
|
448
|
+
|
449
|
+
if (validationOption && !validationFunction(valueLength, validationOption)) {
|
450
|
+
return options.messages[validation];
|
451
|
+
}
|
452
|
+
}
|
453
|
+
};
|
454
|
+
|
455
|
+
var lengthLocalValidator = function lengthLocalValidator(element, options) {
|
456
|
+
var value = element.val();
|
457
|
+
|
458
|
+
if (options.allow_blank && !valueIsPresent(value)) {
|
459
|
+
return;
|
460
|
+
}
|
461
|
+
|
462
|
+
return runValidations$1(value.length, options);
|
463
|
+
};
|
464
|
+
|
465
|
+
var isInList = function isInList(value, otherValues) {
|
466
|
+
var normalizedOtherValues = [];
|
467
|
+
|
468
|
+
for (var otherValueIndex in otherValues) {
|
469
|
+
normalizedOtherValues.push(otherValues[otherValueIndex].toString());
|
470
|
+
}
|
471
|
+
|
472
|
+
return arrayHasValue(value, normalizedOtherValues);
|
473
|
+
};
|
474
|
+
|
475
|
+
var isInRange = function isInRange(value, range) {
|
476
|
+
return value >= range[0] && value <= range[1];
|
477
|
+
};
|
478
|
+
|
479
|
+
var isIncluded = function isIncluded(value, options, allowBlank) {
|
480
|
+
if ((options.allow_blank && !valueIsPresent(value)) === allowBlank) {
|
481
|
+
return true;
|
482
|
+
}
|
483
|
+
|
484
|
+
return options["in"] && isInList(value, options["in"]) || options.range && isInRange(value, options.range);
|
485
|
+
};
|
486
|
+
|
487
|
+
var exclusionLocalValidator = function exclusionLocalValidator(element, options) {
|
488
|
+
var value = element.val();
|
489
|
+
|
490
|
+
if (isIncluded(value, options, false) || !options.allow_blank && !valueIsPresent(value)) {
|
491
|
+
return options.message;
|
492
|
+
}
|
493
|
+
};
|
494
|
+
var inclusionLocalValidator = function inclusionLocalValidator(element, options) {
|
495
|
+
if (!isIncluded(element.val(), options, true)) {
|
496
|
+
return options.message;
|
497
|
+
}
|
498
|
+
};
|
499
|
+
|
500
|
+
var confirmationLocalValidator = function confirmationLocalValidator(element, options) {
|
501
|
+
var value = element.val();
|
502
|
+
var confirmationValue = $('#' + element.attr('id') + '_confirmation').val();
|
503
|
+
|
504
|
+
if (!options.case_sensitive) {
|
505
|
+
value = value.toLowerCase();
|
506
|
+
confirmationValue = confirmationValue.toLowerCase();
|
507
|
+
}
|
508
|
+
|
509
|
+
if (value !== confirmationValue) {
|
510
|
+
return options.message;
|
511
|
+
}
|
512
|
+
};
|
513
|
+
|
514
|
+
var isLocallyUnique = function isLocallyUnique(currentElement, value, otherValue, caseSensitive) {
|
515
|
+
if (!caseSensitive) {
|
516
|
+
value = value.toLowerCase();
|
517
|
+
otherValue = otherValue.toLowerCase();
|
518
|
+
}
|
519
|
+
|
520
|
+
if (otherValue === value) {
|
521
|
+
$(currentElement).data('notLocallyUnique', true);
|
522
|
+
return false;
|
523
|
+
}
|
524
|
+
|
525
|
+
if ($(currentElement).data('notLocallyUnique')) {
|
526
|
+
$(currentElement).removeData('notLocallyUnique').data('changed', true);
|
527
|
+
}
|
528
|
+
|
529
|
+
return true;
|
530
|
+
};
|
531
|
+
|
532
|
+
var uniquenessLocalValidator = function uniquenessLocalValidator(element, options) {
|
533
|
+
var elementName = element.attr('name');
|
534
|
+
var matches = elementName.match(/^(.+_attributes\])\[\d+\](.+)$/);
|
535
|
+
|
536
|
+
if (!matches) {
|
537
|
+
return;
|
538
|
+
}
|
539
|
+
|
540
|
+
var form = element.closest('form');
|
541
|
+
var value = element.val();
|
542
|
+
var valid = true;
|
543
|
+
form.find(':input[name^="' + matches[1] + '"][name$="' + matches[2] + '"]').not(element).each(function () {
|
544
|
+
var otherValue = $(this).val();
|
545
|
+
|
546
|
+
if (!isLocallyUnique(this, value, otherValue, options.case_sensitive)) {
|
547
|
+
valid = false;
|
548
|
+
}
|
549
|
+
});
|
550
|
+
|
551
|
+
if (!valid) {
|
552
|
+
return options.message;
|
553
|
+
}
|
554
|
+
};
|
555
|
+
|
556
|
+
ClientSideValidations.validators.local = {
|
557
|
+
absence: absenceLocalValidator,
|
558
|
+
presence: presenceLocalValidator,
|
559
|
+
acceptance: acceptanceLocalValidator,
|
560
|
+
format: formatLocalValidator,
|
561
|
+
numericality: numericalityLocalValidator,
|
562
|
+
length: lengthLocalValidator,
|
563
|
+
inclusion: inclusionLocalValidator,
|
564
|
+
exclusion: exclusionLocalValidator,
|
565
|
+
confirmation: confirmationLocalValidator,
|
566
|
+
uniqueness: uniquenessLocalValidator
|
567
|
+
};
|
568
|
+
|
569
|
+
$.fn.disableClientSideValidations = function () {
|
570
|
+
ClientSideValidations.disable(this);
|
571
|
+
return this;
|
572
|
+
};
|
573
|
+
|
574
|
+
$.fn.enableClientSideValidations = function () {
|
575
|
+
var _this = this;
|
576
|
+
|
577
|
+
var selectors = {
|
578
|
+
forms: 'form',
|
579
|
+
inputs: 'input'
|
580
|
+
};
|
581
|
+
|
582
|
+
var _loop = function _loop() {
|
583
|
+
var enablers = selectors[selector];
|
584
|
+
|
585
|
+
_this.filter(ClientSideValidations.selectors[selector]).each(function () {
|
586
|
+
return ClientSideValidations.enablers[enablers](this);
|
587
|
+
});
|
588
|
+
};
|
589
|
+
|
590
|
+
for (var selector in selectors) {
|
591
|
+
_loop();
|
586
592
|
}
|
593
|
+
|
594
|
+
return this;
|
587
595
|
};
|
588
596
|
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
return $(ClientSideValidations.selectors.forms).validate();
|
597
|
+
$.fn.resetClientSideValidations = function () {
|
598
|
+
this.filter(ClientSideValidations.selectors.forms).each(function () {
|
599
|
+
return ClientSideValidations.reset(this);
|
593
600
|
});
|
594
|
-
|
595
|
-
|
596
|
-
|
601
|
+
return this;
|
602
|
+
};
|
603
|
+
|
604
|
+
$.fn.validate = function () {
|
605
|
+
this.filter(ClientSideValidations.selectors.forms).each(function () {
|
606
|
+
return $(this).enableClientSideValidations();
|
607
|
+
});
|
608
|
+
return this;
|
609
|
+
};
|
610
|
+
|
611
|
+
$.fn.isValid = function (validators) {
|
612
|
+
var obj = $(this[0]);
|
613
|
+
|
614
|
+
if (obj.is('form')) {
|
615
|
+
return validateForm(obj, validators);
|
616
|
+
} else {
|
617
|
+
return validateElement(obj, validatorsFor(this[0].name, validators));
|
618
|
+
}
|
619
|
+
};
|
620
|
+
|
621
|
+
var cleanNestedElementName = function cleanNestedElementName(elementName, nestedMatches, validators) {
|
622
|
+
for (var validatorName in validators) {
|
623
|
+
if (validatorName.match('\\[' + nestedMatches[1] + '\\].*\\[\\]\\[' + nestedMatches[2] + '\\]$')) {
|
624
|
+
elementName = elementName.replace(/\[[\da-z_]+\]\[(\w+)\]$/g, '[][$1]');
|
625
|
+
}
|
626
|
+
}
|
627
|
+
|
628
|
+
return elementName;
|
629
|
+
};
|
630
|
+
|
631
|
+
var cleanElementName = function cleanElementName(elementName, validators) {
|
632
|
+
elementName = elementName.replace(/\[(\w+_attributes)\]\[[\da-z_]+\](?=\[(?:\w+_attributes)\])/g, '[$1][]');
|
633
|
+
var nestedMatches = elementName.match(/\[(\w+_attributes)\].*\[(\w+)\]$/);
|
634
|
+
|
635
|
+
if (nestedMatches) {
|
636
|
+
elementName = cleanNestedElementName(elementName, nestedMatches, validators);
|
637
|
+
}
|
638
|
+
|
639
|
+
return elementName;
|
640
|
+
};
|
641
|
+
|
642
|
+
var validatorsFor = function validatorsFor(elementName, validators) {
|
643
|
+
if (Object.prototype.isPrototypeOf.call(validators, elementName)) {
|
644
|
+
return validators[elementName];
|
645
|
+
}
|
646
|
+
|
647
|
+
return validators[cleanElementName(elementName, validators)] || {};
|
648
|
+
};
|
649
|
+
|
650
|
+
var validateForm = function validateForm(form, validators) {
|
651
|
+
var valid = true;
|
652
|
+
form.trigger('form:validate:before.ClientSideValidations');
|
653
|
+
form.find(ClientSideValidations.selectors.validate_inputs).each(function () {
|
654
|
+
if (!$(this).isValid(validators)) {
|
655
|
+
valid = false;
|
656
|
+
}
|
657
|
+
|
658
|
+
return true;
|
597
659
|
});
|
660
|
+
|
661
|
+
if (valid) {
|
662
|
+
form.trigger('form:validate:pass.ClientSideValidations');
|
663
|
+
} else {
|
664
|
+
form.trigger('form:validate:fail.ClientSideValidations');
|
665
|
+
}
|
666
|
+
|
667
|
+
form.trigger('form:validate:after.ClientSideValidations');
|
668
|
+
return valid;
|
669
|
+
};
|
670
|
+
|
671
|
+
var passElement = function passElement(element) {
|
672
|
+
element.trigger('element:validate:pass.ClientSideValidations').data('valid', null);
|
673
|
+
};
|
674
|
+
|
675
|
+
var failElement = function failElement(element, message) {
|
676
|
+
element.trigger('element:validate:fail.ClientSideValidations', message).data('valid', false);
|
677
|
+
};
|
678
|
+
|
679
|
+
var afterValidate = function afterValidate(element) {
|
680
|
+
return element.trigger('element:validate:after.ClientSideValidations').data('valid') !== false;
|
681
|
+
};
|
682
|
+
|
683
|
+
var executeValidator = function executeValidator(validatorFunctions, validatorFunction, validatorOptions, element) {
|
684
|
+
for (var validatorOption in validatorOptions) {
|
685
|
+
var message = validatorFunction.call(validatorFunctions, element, validatorOptions[validatorOption]);
|
686
|
+
|
687
|
+
if (message) {
|
688
|
+
failElement(element, message);
|
689
|
+
return false;
|
690
|
+
}
|
691
|
+
}
|
692
|
+
|
693
|
+
return true;
|
694
|
+
};
|
695
|
+
|
696
|
+
var executeValidators = function executeValidators(validatorFunctions, element, validators) {
|
697
|
+
for (var validator in validators) {
|
698
|
+
var validatorFunction = validatorFunctions[validator];
|
699
|
+
|
700
|
+
if (!validatorFunction) {
|
701
|
+
continue;
|
702
|
+
}
|
703
|
+
|
704
|
+
if (!executeValidator(validatorFunctions, validatorFunction, validators[validator], element)) {
|
705
|
+
return false;
|
706
|
+
}
|
707
|
+
}
|
708
|
+
|
709
|
+
return true;
|
710
|
+
};
|
711
|
+
|
712
|
+
var isMarkedForDestroy = function isMarkedForDestroy(element) {
|
713
|
+
if (element.attr('name').search(/\[([^\]]*?)\]$/) >= 0) {
|
714
|
+
var destroyInputName = element.attr('name').replace(/\[([^\]]*?)\]$/, '[_destroy]');
|
715
|
+
|
716
|
+
if ($("input[name='" + destroyInputName + "']").val() === '1') {
|
717
|
+
return true;
|
718
|
+
}
|
719
|
+
}
|
720
|
+
|
721
|
+
return false;
|
722
|
+
};
|
723
|
+
|
724
|
+
var executeAllValidators = function executeAllValidators(element, validators) {
|
725
|
+
if (element.data('changed') !== false) {
|
726
|
+
element.data('changed', false);
|
727
|
+
|
728
|
+
if (executeValidators(ClientSideValidations.validators.local, element, validators) && executeValidators(ClientSideValidations.validators.remote, element, validators)) {
|
729
|
+
passElement(element);
|
730
|
+
}
|
731
|
+
}
|
732
|
+
};
|
733
|
+
|
734
|
+
var validateElement = function validateElement(element, validators) {
|
735
|
+
element.trigger('element:validate:before.ClientSideValidations');
|
736
|
+
|
737
|
+
if (isMarkedForDestroy(element)) {
|
738
|
+
passElement(element);
|
739
|
+
} else {
|
740
|
+
executeAllValidators(element, validators);
|
741
|
+
}
|
742
|
+
|
743
|
+
return afterValidate(element);
|
744
|
+
};
|
745
|
+
|
746
|
+
if (!window.ClientSideValidations) {
|
747
|
+
window.ClientSideValidations = ClientSideValidations;
|
748
|
+
|
749
|
+
if (!isAMD() && !isCommonJS()) {
|
750
|
+
ClientSideValidations.start();
|
751
|
+
}
|
598
752
|
}
|
599
753
|
|
600
|
-
|
754
|
+
function isAMD() {
|
755
|
+
return typeof define === 'function' && define.amd; // eslint-disable-line no-undef
|
756
|
+
}
|
757
|
+
|
758
|
+
function isCommonJS() {
|
759
|
+
return (typeof exports === "undefined" ? "undefined" : _typeof(exports)) === 'object' && typeof module !== 'undefined'; // eslint-disable-line no-undef
|
760
|
+
}
|
761
|
+
|
762
|
+
var main = {
|
763
|
+
ClientSideValidations: ClientSideValidations
|
764
|
+
};
|
765
|
+
|
766
|
+
return main;
|
601
767
|
|
602
|
-
})
|
768
|
+
}));
|