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.
@@ -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: