client_side_validations 3.2.0.beta.4 → 3.2.0.beta.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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, *args, &block)
54
+ def fields_for(record_or_name_or_array, record_object = nil, options = {}, &block)
55
55
  output = super
56
- @validators.merge!(args.last[:validators]) if @validators
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[\nwindow.ClientSideValidations.forms['#{var_name}'] = #{builder.client_side_form_settings(options, self).merge(:validators => 'validator_hash').to_json};\n//]]>".html_safe
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.merge!(validator.kind => client_side_hash.except(:on))
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] = model.errors.generate_message(attribute, message_type, options.except(:scope))
5
+ hash[:message] = model.errors.generate_message(attribute, message_type, options.except(:scope))
6
6
  hash[:case_sensitive] = options[:case_sensitive]
7
- hash[:id] = model.id unless model.new_record?
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
- self.body = ''
28
- self.status = 200
29
- self.request = ActionDispatch::Request.new(env)
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
@@ -1,3 +1,3 @@
1
1
  module ClientSideValidations
2
- VERSION = '3.2.0.beta.4'
2
+ VERSION = '3.2.0.beta.5'
3
3
  end
@@ -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
- return form.isValid(settings.validators);
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 ($(this).isValid(validators)) {
125
- return valid = false;
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] && (message = fn.call(context, element, validators[kind]))) {
147
- element.trigger('element:validate:fail', message).data('valid', false);
148
- valid = false;
149
- break;
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] && (message = fn.call(context, element, validators[kind]))) {
157
- element.trigger('element:validate:fail', message).data('valid', false);
158
- valid = false;
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 (_ref = element.data('valid') === false) != null ? _ref : {
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
- if (!ClientSideValidations.patterns.numericality.test(element.val())) {
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(element.val())) {
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
- fn = new Function("return " + (element.val()) + " " + operator + " " + options[check]);
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(element.val(), 10) % 2)) {
276
+ if (options.odd && !(parseInt(val, 10) % 2)) {
246
277
  return options.messages.odd;
247
278
  }
248
- if (options.even && (parseInt(element.val(), 10) % 2)) {
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
- if (element.data('valid') !== false && !(jQuery("label.message[for='" + (element.attr('id')) + "']")[0] != null)) {
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 = jQuery("label[for='" + (element.attr('id')) + "']:not(.message)");
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
- label.replaceWith(labelErrorField);
480
+ labelErrorField.insertAfter(label);
420
481
  labelErrorField.find('label#label_tag').replaceWith(label);
421
482
  }
422
- return jQuery("label.message[for='" + (element.attr('id')) + "']").text(message);
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 = jQuery("label[for='" + (element.attr('id')) + "']:not(.message)");
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: /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d*)?$/
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
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-09 00:00:00.000000000 Z
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: