client_side_validations 3.2.0.beta.4 → 3.2.0.beta.5
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.
- data/client_side_validations.gemspec +1 -0
- data/lib/client_side_validations/action_view/form_helper.rb +3 -3
- data/lib/client_side_validations/active_model.rb +4 -4
- data/lib/client_side_validations/active_model/numericality.rb +2 -0
- data/lib/client_side_validations/active_record/uniqueness.rb +3 -2
- data/lib/client_side_validations/middleware.rb +5 -3
- data/lib/client_side_validations/version.rb +1 -1
- data/vendor/assets/javascripts/rails.validations.js +91 -29
- metadata +21 -2
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.add_development_dependency 'rails', '~> 3.2.0'
|
19
19
|
s.add_development_dependency 'sqlite3'
|
20
20
|
s.add_development_dependency 'mocha'
|
21
|
+
s.add_development_dependency 'm'
|
21
22
|
|
22
23
|
# For QUnit testing
|
23
24
|
s.add_development_dependency 'sinatra', '~> 1.0'
|
@@ -51,9 +51,9 @@ module ClientSideValidations::ActionView::Helpers
|
|
51
51
|
options[:html][:validate] = true if options[:validate]
|
52
52
|
end
|
53
53
|
|
54
|
-
def fields_for(record_or_name_or_array,
|
54
|
+
def fields_for(record_or_name_or_array, record_object = nil, options = {}, &block)
|
55
55
|
output = super
|
56
|
-
@validators.merge!(
|
56
|
+
@validators.merge!(options[:validators]) if @validators
|
57
57
|
output
|
58
58
|
end
|
59
59
|
|
@@ -95,7 +95,7 @@ module ClientSideValidations::ActionView::Helpers
|
|
95
95
|
end
|
96
96
|
|
97
97
|
content_tag(:script) do
|
98
|
-
"//<![CDATA[\
|
98
|
+
"//<![CDATA[\nif(window.ClientSideValidations==undefined)window.ClientSideValidations={};if(window.ClientSideValidations.forms==undefined)window.ClientSideValidations.forms={};window.ClientSideValidations.forms['#{var_name}'] = #{builder.client_side_form_settings(options, self).merge(:validators => 'validator_hash').to_json};\n//]]>".html_safe
|
99
99
|
end
|
100
100
|
end
|
101
101
|
end
|
@@ -24,14 +24,14 @@ module ClientSideValidations::ActiveModel
|
|
24
24
|
@client_side_validation_hash ||= _validators.inject({}) do |attr_hash, attr|
|
25
25
|
unless [nil, :block].include?(attr[0])
|
26
26
|
|
27
|
-
validator_hash = attr[1].inject({}) do |kind_hash, validator|
|
27
|
+
validator_hash = attr[1].inject(Hash.new { |h,k| h[k] = []}) do |kind_hash, validator|
|
28
28
|
client_side_hash = validator.client_side_hash(self, attr[0])
|
29
29
|
# Yeah yeah, #new_record? is not part of ActiveModel :p
|
30
30
|
if can_use_for_client_side_validation?(client_side_hash, validator) && uniqueness_validations_allowed_or_not_applicable?(validator)
|
31
|
-
kind_hash
|
32
|
-
else
|
33
|
-
kind_hash.merge!({})
|
31
|
+
kind_hash[validator.kind] << client_side_hash.except(:on)
|
34
32
|
end
|
33
|
+
|
34
|
+
kind_hash
|
35
35
|
end
|
36
36
|
|
37
37
|
if validator_hash.present?
|
@@ -16,6 +16,8 @@ module ClientSideValidations::ActiveModel
|
|
16
16
|
hash[:only_integer] = true
|
17
17
|
end
|
18
18
|
|
19
|
+
hash[:allow_blank] = true if options[:allow_nil]
|
20
|
+
|
19
21
|
OPTION_MAP.each do |option, message_type|
|
20
22
|
if count = options[option]
|
21
23
|
hash[:messages][option] = model.errors.generate_message(attribute, message_type, options.merge(:count => count))
|
@@ -2,9 +2,10 @@ module ClientSideValidations::ActiveRecord
|
|
2
2
|
module Uniqueness
|
3
3
|
def client_side_hash(model, attribute)
|
4
4
|
hash = {}
|
5
|
-
hash[:message]
|
5
|
+
hash[:message] = model.errors.generate_message(attribute, message_type, options.except(:scope))
|
6
6
|
hash[:case_sensitive] = options[:case_sensitive]
|
7
|
-
hash[:id]
|
7
|
+
hash[:id] = model.id unless model.new_record?
|
8
|
+
hash[:allow_blank] = true if options[:allow_blank]
|
8
9
|
if options.key?(:scope) && options[:scope].present?
|
9
10
|
hash[:scope] = Array.wrap(options[:scope]).inject({}) do |scope_hash, scope_item|
|
10
11
|
scope_hash.merge!(scope_item => model.send(scope_item))
|
@@ -24,9 +24,11 @@ module ClientSideValidations
|
|
24
24
|
attr_accessor :request, :body, :status
|
25
25
|
|
26
26
|
def initialize(env)
|
27
|
-
|
28
|
-
|
29
|
-
self.
|
27
|
+
# Filter out cache buster
|
28
|
+
env['QUERY_STRING'] = env['QUERY_STRING'].split('&').select { |p| !p.match(/^_=/) }.join('&')
|
29
|
+
self.body = ''
|
30
|
+
self.status = 200
|
31
|
+
self.request = ActionDispatch::Request.new(env)
|
30
32
|
end
|
31
33
|
|
32
34
|
def response
|
@@ -15,8 +15,10 @@
|
|
15
15
|
removeError = function(element) {
|
16
16
|
return ClientSideValidations.formBuilders[settings.type].remove(element, settings);
|
17
17
|
};
|
18
|
-
form.submit(function() {
|
19
|
-
|
18
|
+
form.submit(function(eventData) {
|
19
|
+
if (!form.isValid(settings.validators)) {
|
20
|
+
return eventData.preventDefault();
|
21
|
+
}
|
20
22
|
});
|
21
23
|
_ref = {
|
22
24
|
'ajax:beforeSend': function(eventData) {
|
@@ -121,9 +123,10 @@
|
|
121
123
|
form.trigger('form:validate:before');
|
122
124
|
valid = true;
|
123
125
|
form.find('[data-validate="true"]:input:enabled').each(function() {
|
124
|
-
if (
|
125
|
-
|
126
|
+
if (!$(this).isValid(validators)) {
|
127
|
+
valid = false;
|
126
128
|
}
|
129
|
+
return true;
|
127
130
|
});
|
128
131
|
if (valid) {
|
129
132
|
form.trigger('form:validate:pass');
|
@@ -135,7 +138,7 @@
|
|
135
138
|
};
|
136
139
|
|
137
140
|
validateElement = function(element, validators) {
|
138
|
-
var context, fn, kind, message, valid, _ref;
|
141
|
+
var context, fn, kind, message, valid, validator, _i, _j, _len, _len1, _ref, _ref1;
|
139
142
|
element.trigger('element:validate:before');
|
140
143
|
if (element.data('changed') !== false) {
|
141
144
|
valid = true;
|
@@ -143,19 +146,37 @@
|
|
143
146
|
context = ClientSideValidations.validators.local;
|
144
147
|
for (kind in context) {
|
145
148
|
fn = context[kind];
|
146
|
-
if (validators[kind]
|
147
|
-
|
148
|
-
|
149
|
-
|
149
|
+
if (validators[kind]) {
|
150
|
+
_ref = validators[kind];
|
151
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
152
|
+
validator = _ref[_i];
|
153
|
+
if (message = fn.call(context, element, validator)) {
|
154
|
+
element.trigger('element:validate:fail', message).data('valid', false);
|
155
|
+
valid = false;
|
156
|
+
break;
|
157
|
+
}
|
158
|
+
}
|
159
|
+
if (!valid) {
|
160
|
+
break;
|
161
|
+
}
|
150
162
|
}
|
151
163
|
}
|
152
164
|
if (valid) {
|
153
165
|
context = ClientSideValidations.validators.remote;
|
154
166
|
for (kind in context) {
|
155
167
|
fn = context[kind];
|
156
|
-
if (validators[kind]
|
157
|
-
|
158
|
-
|
168
|
+
if (validators[kind]) {
|
169
|
+
_ref1 = validators[kind];
|
170
|
+
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
171
|
+
validator = _ref1[_j];
|
172
|
+
if (message = fn.call(context, element, validator)) {
|
173
|
+
element.trigger('element:validate:fail', message).data('valid', false);
|
174
|
+
valid = false;
|
175
|
+
break;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
179
|
+
if (!valid) {
|
159
180
|
break;
|
160
181
|
}
|
161
182
|
}
|
@@ -166,9 +187,7 @@
|
|
166
187
|
}
|
167
188
|
}
|
168
189
|
element.trigger('element:validate:after');
|
169
|
-
return
|
170
|
-
"false": true
|
171
|
-
};
|
190
|
+
return element.data('valid') !== false;
|
172
191
|
};
|
173
192
|
|
174
193
|
$(function() {
|
@@ -218,11 +237,15 @@
|
|
218
237
|
}
|
219
238
|
},
|
220
239
|
numericality: function(element, options) {
|
221
|
-
var CHECKS, check, fn, operator;
|
222
|
-
|
240
|
+
var CHECKS, check, check_value, fn, form, operator, val;
|
241
|
+
val = jQuery.trim(element.val());
|
242
|
+
if (!ClientSideValidations.patterns.numericality.test(val)) {
|
243
|
+
if (options.allow_blank === true) {
|
244
|
+
return;
|
245
|
+
}
|
223
246
|
return options.messages.numericality;
|
224
247
|
}
|
225
|
-
if (options.only_integer && !/^[+-]?\d+$/.test(
|
248
|
+
if (options.only_integer && !/^[+-]?\d+$/.test(val)) {
|
226
249
|
return options.messages.only_integer;
|
227
250
|
}
|
228
251
|
CHECKS = {
|
@@ -232,20 +255,28 @@
|
|
232
255
|
less_than: '<',
|
233
256
|
less_than_or_equal_to: '<='
|
234
257
|
};
|
258
|
+
form = $(element[0].form);
|
235
259
|
for (check in CHECKS) {
|
236
260
|
operator = CHECKS[check];
|
237
261
|
if (!(options[check] != null)) {
|
238
262
|
continue;
|
239
263
|
}
|
240
|
-
|
264
|
+
if (!isNaN(parseFloat(options[check])) && isFinite(options[check])) {
|
265
|
+
check_value = options[check];
|
266
|
+
} else if (form.find("[name*=" + options[check] + "]").size() === 1) {
|
267
|
+
check_value = form.find("[name*=" + options[check] + "]").val();
|
268
|
+
} else {
|
269
|
+
return;
|
270
|
+
}
|
271
|
+
fn = new Function("return " + val + " " + operator + " " + check_value);
|
241
272
|
if (!fn()) {
|
242
273
|
return options.messages[check];
|
243
274
|
}
|
244
275
|
}
|
245
|
-
if (options.odd && !(parseInt(
|
276
|
+
if (options.odd && !(parseInt(val, 10) % 2)) {
|
246
277
|
return options.messages.odd;
|
247
278
|
}
|
248
|
-
if (options.even && (parseInt(
|
279
|
+
if (options.even && (parseInt(val, 10) % 2)) {
|
249
280
|
return options.messages.even;
|
250
281
|
}
|
251
282
|
},
|
@@ -346,6 +377,35 @@
|
|
346
377
|
if (element.val() !== jQuery("#" + (element.attr('id')) + "_confirmation").val()) {
|
347
378
|
return options.message;
|
348
379
|
}
|
380
|
+
},
|
381
|
+
uniqueness: function(element, options) {
|
382
|
+
var form, matches, name, name_prefix, name_suffix, valid, value;
|
383
|
+
name = element.attr('name');
|
384
|
+
if (/_attributes\]\[\d/.test(name)) {
|
385
|
+
matches = name.match(/^(.+_attributes\])\[\d+\](.+)$/);
|
386
|
+
name_prefix = matches[1];
|
387
|
+
name_suffix = matches[2];
|
388
|
+
value = element.val();
|
389
|
+
if (name_prefix && name_suffix) {
|
390
|
+
form = element.closest('form');
|
391
|
+
valid = true;
|
392
|
+
form.find(':input[name^="' + name_prefix + '"][name$="' + name_suffix + '"]').each(function() {
|
393
|
+
if ($(this).attr('name') !== name) {
|
394
|
+
if ($(this).val() === value) {
|
395
|
+
valid = false;
|
396
|
+
return $(this).data('notLocallyUnique', true);
|
397
|
+
} else {
|
398
|
+
if ($(this).data('notLocallyUnique')) {
|
399
|
+
return $(this).removeData('notLocallyUnique').data('changed', true);
|
400
|
+
}
|
401
|
+
}
|
402
|
+
}
|
403
|
+
});
|
404
|
+
if (!valid) {
|
405
|
+
return options.message;
|
406
|
+
}
|
407
|
+
}
|
408
|
+
}
|
349
409
|
}
|
350
410
|
},
|
351
411
|
remote: {
|
@@ -404,11 +464,12 @@
|
|
404
464
|
formBuilders: {
|
405
465
|
'ActionView::Helpers::FormBuilder': {
|
406
466
|
add: function(element, settings, message) {
|
407
|
-
var inputErrorField, label, labelErrorField;
|
408
|
-
|
467
|
+
var form, inputErrorField, label, labelErrorField;
|
468
|
+
form = $(element[0].form);
|
469
|
+
if (element.data('valid') !== false && !(form.find("label.message[for='" + (element.attr('id')) + "']")[0] != null)) {
|
409
470
|
inputErrorField = jQuery(settings.input_tag);
|
410
471
|
labelErrorField = jQuery(settings.label_tag);
|
411
|
-
label =
|
472
|
+
label = form.find("label[for='" + (element.attr('id')) + "']:not(.message)");
|
412
473
|
if (element.attr('autofocus')) {
|
413
474
|
element.attr('autofocus', false);
|
414
475
|
}
|
@@ -416,16 +477,17 @@
|
|
416
477
|
inputErrorField.find('span#input_tag').replaceWith(element);
|
417
478
|
inputErrorField.find('label.message').attr('for', element.attr('id'));
|
418
479
|
labelErrorField.find('label.message').attr('for', element.attr('id'));
|
419
|
-
|
480
|
+
labelErrorField.insertAfter(label);
|
420
481
|
labelErrorField.find('label#label_tag').replaceWith(label);
|
421
482
|
}
|
422
|
-
return
|
483
|
+
return form.find("label.message[for='" + (element.attr('id')) + "']").text(message);
|
423
484
|
},
|
424
485
|
remove: function(element, settings) {
|
425
|
-
var errorFieldClass, inputErrorField, label, labelErrorField;
|
486
|
+
var errorFieldClass, form, inputErrorField, label, labelErrorField;
|
487
|
+
form = $(element[0].form);
|
426
488
|
errorFieldClass = jQuery(settings.input_tag).attr('class');
|
427
489
|
inputErrorField = element.closest("." + (errorFieldClass.replace(" ", ".")));
|
428
|
-
label =
|
490
|
+
label = form.find("label[for='" + (element.attr('id')) + "']:not(.message)");
|
429
491
|
labelErrorField = label.closest("." + errorFieldClass);
|
430
492
|
if (inputErrorField[0]) {
|
431
493
|
inputErrorField.find("#" + (element.attr('id'))).detach();
|
@@ -437,7 +499,7 @@
|
|
437
499
|
}
|
438
500
|
},
|
439
501
|
patterns: {
|
440
|
-
numericality:
|
502
|
+
numericality: /^(-|\+)?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d*)?$/
|
441
503
|
},
|
442
504
|
callbacks: {
|
443
505
|
element: {
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: client_side_validations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.0.beta.
|
4
|
+
version: 3.2.0.beta.5
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -59,6 +59,22 @@ dependencies:
|
|
59
59
|
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: m
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
62
78
|
- !ruby/object:Gem::Dependency
|
63
79
|
name: sinatra
|
64
80
|
requirement: !ruby/object:Gem::Requirement
|
@@ -188,6 +204,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
188
204
|
- - ! '>='
|
189
205
|
- !ruby/object:Gem::Version
|
190
206
|
version: '0'
|
207
|
+
segments:
|
208
|
+
- 0
|
209
|
+
hash: 467030908926839385
|
191
210
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
192
211
|
none: false
|
193
212
|
requirements:
|