client_side_validations 3.2.0.beta.6 → 3.2.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,7 +7,7 @@ module ClientSideValidations::ActiveModel
7
7
  OPTION_MAP.merge!(base::CHECKS.keys.inject({}) { |hash, key| hash.merge!(key => key) })
8
8
  end
9
9
 
10
- def client_side_hash(model, attribute)
10
+ def client_side_hash(model, attribute, force = nil)
11
11
  options = self.options.dup
12
12
  hash = { :messages => { :numericality => model.errors.generate_message(attribute, :not_a_number, options) } }
13
13
 
@@ -20,6 +20,13 @@ module ClientSideValidations::ActiveModel
20
20
 
21
21
  OPTION_MAP.each do |option, message_type|
22
22
  if count = options[option]
23
+ if count.respond_to?(:call)
24
+ if force
25
+ count = count.call(model)
26
+ else
27
+ next
28
+ end
29
+ end
23
30
  hash[:messages][option] = model.errors.generate_message(attribute, message_type, options.merge(:count => count))
24
31
  hash[option] = count
25
32
  end
@@ -13,7 +13,7 @@ module ClientSideValidations::ActiveRecord
13
13
  t = klass.arel_table
14
14
 
15
15
  if params[:case_sensitive] == 'true'
16
- if t.engine.connection.instance_variable_get("@config")[:adapter] == 'mysql'
16
+ if t.engine.connection.instance_variable_get("@config")[:adapter] =~ /^mysql/
17
17
  relation = Arel::Nodes::SqlLiteral.new("BINARY #{t[attribute].eq(value).to_sql}")
18
18
  else
19
19
  relation = t[attribute].eq(value)
@@ -1,6 +1,6 @@
1
1
  module ClientSideValidations::ActiveRecord
2
2
  module Uniqueness
3
- def client_side_hash(model, attribute)
3
+ def client_side_hash(model, attribute, force = nil)
4
4
  hash = {}
5
5
  hash[:message] = model.errors.generate_message(attribute, message_type, options.except(:scope))
6
6
  hash[:case_sensitive] = options[:case_sensitive]
@@ -1,6 +1,6 @@
1
1
  class Regexp
2
2
  def as_json(options = nil)
3
- Regexp.new inspect.sub('\\A','^').sub('\\Z','$').sub('\\z','$').sub(/^\//,'').sub(/\/[a-z]*$/,'').gsub(/\(\?#.+\)/, '').gsub(/\(\?-\w+:/,'('), self.options
3
+ Regexp.new inspect.sub('\\A','^').sub('\\Z','$').sub('\\z','$').sub(/^\//,'').sub(/\/[a-z]*$/,'').gsub(/\(\?#.+\)/, '').gsub(/\(\?-\w+:/,'(').gsub(/\s/,''), self.options & 5
4
4
  end
5
5
 
6
6
  def to_json(options = nil)
@@ -11,4 +11,3 @@ class Regexp
11
11
  inspect
12
12
  end
13
13
  end
14
-
@@ -1,3 +1,3 @@
1
1
  module ClientSideValidations
2
- VERSION = '3.2.0.beta.6'
2
+ VERSION = '3.2.0.rc.1'
3
3
  end
@@ -38,7 +38,9 @@ module ClientSideValidations
38
38
  end
39
39
 
40
40
  def self.asset_pipeline_enabled?
41
- (Rails.configuration.respond_to?(:assets) ? (Rails.configuration.assets || {}) : {})[:enabled]
41
+ if Rails.application
42
+ (Rails.configuration.respond_to?(:assets) ? (Rails.configuration.assets || {}) : {})[:enabled]
43
+ end
42
44
  end
43
45
 
44
46
  def asset_pipeline_enabled?
@@ -73,16 +73,16 @@
73
73
  };
74
74
  for (event in _ref1) {
75
75
  binding = _ref1[event];
76
- form.find('[data-validate="true"]:input:enabled:not(:radio)').live(event, binding);
76
+ form.find(':input:enabled:not(:radio):not([id$=_confirmation])').live(event, binding);
77
77
  }
78
- form.find('[data-validate="true"]:checkbox').live('click', function() {
78
+ form.find(':checkbox').live('click', function() {
79
79
  $(this).isValid(settings.validators);
80
80
  return true;
81
81
  });
82
- return form.find('[id*=_confirmation]').each(function() {
82
+ return form.find('[id$=_confirmation]').each(function() {
83
83
  var confirmationElement, element, _ref2, _results;
84
84
  confirmationElement = $(this);
85
- element = form.find("#" + (this.id.match(/(.+)_confirmation/)[1]) + "[data-validate='true']:input");
85
+ element = form.find("#" + (this.id.match(/(.+)_confirmation/)[1]) + ":input");
86
86
  if (element[0]) {
87
87
  _ref2 = {
88
88
  'focusout': function() {
@@ -115,14 +115,14 @@
115
115
 
116
116
  validatorsFor = function(name, validators) {
117
117
  name = name.replace(/_attributes\]\[\d+\]/g, "_attributes][]");
118
- return validators[name];
118
+ return validators[name] || {};
119
119
  };
120
120
 
121
121
  validateForm = function(form, validators) {
122
122
  var valid;
123
123
  form.trigger('form:validate:before');
124
124
  valid = true;
125
- form.find('[data-validate="true"]:input:enabled').each(function() {
125
+ form.find(':input:enabled').each(function() {
126
126
  if (!$(this).isValid(validators)) {
127
127
  valid = false;
128
128
  }
@@ -138,12 +138,21 @@
138
138
  };
139
139
 
140
140
  validateElement = function(element, validators) {
141
- var context, fn, kind, message, valid, validator, _i, _j, _len, _len1, _ref, _ref1;
141
+ var afterValidate, destroyInputName, executeValidators, failElement, local, passElement, remote;
142
142
  element.trigger('element:validate:before');
143
- if (element.data('changed') !== false) {
143
+ passElement = function() {
144
+ return element.trigger('element:validate:pass').data('valid', null);
145
+ };
146
+ failElement = function(message) {
147
+ element.trigger('element:validate:fail', message).data('valid', false);
148
+ return false;
149
+ };
150
+ afterValidate = function() {
151
+ return element.trigger('element:validate:after').data('valid') !== false;
152
+ };
153
+ executeValidators = function(context) {
154
+ var fn, kind, message, valid, validator, _i, _len, _ref;
144
155
  valid = true;
145
- element.data('changed', false);
146
- context = ClientSideValidations.validators.local;
147
156
  for (kind in context) {
148
157
  fn = context[kind];
149
158
  if (validators[kind]) {
@@ -151,8 +160,7 @@
151
160
  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
152
161
  validator = _ref[_i];
153
162
  if (message = fn.call(context, element, validator)) {
154
- element.trigger('element:validate:fail', message).data('valid', false);
155
- valid = false;
163
+ valid = failElement(message);
156
164
  break;
157
165
  }
158
166
  }
@@ -161,363 +169,366 @@
161
169
  }
162
170
  }
163
171
  }
164
- if (valid) {
165
- context = ClientSideValidations.validators.remote;
166
- for (kind in context) {
167
- fn = context[kind];
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) {
180
- break;
181
- }
182
- }
183
- }
184
- if (valid) {
185
- element.data('valid', null);
186
- element.trigger('element:validate:pass');
187
- }
172
+ return valid;
173
+ };
174
+ destroyInputName = element.attr('name').replace(/\[([^\]]*?)\]$/, '[_destroy]');
175
+ if ($("input[name='" + destroyInputName + "']").val() === "1") {
176
+ passElement();
177
+ return afterValidate();
188
178
  }
189
- element.trigger('element:validate:after');
190
- return element.data('valid') !== false;
179
+ if (element.data('changed') === false) {
180
+ return afterValidate();
181
+ }
182
+ element.data('changed', false);
183
+ local = ClientSideValidations.validators.local;
184
+ remote = ClientSideValidations.validators.remote;
185
+ if (executeValidators(local) && executeValidators(remote)) {
186
+ passElement();
187
+ }
188
+ return afterValidate();
191
189
  };
192
190
 
193
191
  $(function() {
194
192
  return $('form[data-validate]').validate();
195
193
  });
196
194
 
197
- window.ClientSideValidations = {
198
- forms: {},
199
- validators: {
200
- all: function() {
201
- return jQuery.extend({}, ClientSideValidations.validators.local, ClientSideValidations.validators.remote);
195
+ if (window.ClientSideValidations === void 0) {
196
+ window.ClientSideValidations = {};
197
+ }
198
+
199
+ if (window.ClientSideValidations.forms === void 0) {
200
+ window.ClientSideValidations.forms = {};
201
+ }
202
+
203
+ window.ClientSideValidations.validators = {
204
+ all: function() {
205
+ return jQuery.extend({}, ClientSideValidations.validators.local, ClientSideValidations.validators.remote);
206
+ },
207
+ local: {
208
+ presence: function(element, options) {
209
+ if (/^\s*$/.test(element.val() || '')) {
210
+ return options.message;
211
+ }
202
212
  },
203
- local: {
204
- presence: function(element, options) {
205
- if (/^\s*$/.test(element.val() || '')) {
206
- return options.message;
207
- }
208
- },
209
- acceptance: function(element, options) {
210
- var _ref;
211
- switch (element.attr('type')) {
212
- case 'checkbox':
213
- if (!element.attr('checked')) {
214
- return options.message;
215
- }
216
- break;
217
- case 'text':
218
- if (element.val() !== (((_ref = options.accept) != null ? _ref.toString() : void 0) || '1')) {
219
- return options.message;
220
- }
221
- }
222
- },
223
- format: function(element, options) {
224
- var message;
225
- message = this.presence(element, options);
226
- if (message) {
227
- if (options.allow_blank === true) {
228
- return;
229
- }
230
- return message;
231
- }
232
- if (options["with"] && !options["with"].test(element.val())) {
233
- return options.message;
234
- }
235
- if (options.without && options.without.test(element.val())) {
236
- return options.message;
237
- }
238
- },
239
- numericality: function(element, options) {
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
- }
246
- return options.messages.numericality;
247
- }
248
- if (options.only_integer && !/^[+-]?\d+$/.test(val)) {
249
- return options.messages.only_integer;
250
- }
251
- CHECKS = {
252
- greater_than: '>',
253
- greater_than_or_equal_to: '>=',
254
- equal_to: '==',
255
- less_than: '<',
256
- less_than_or_equal_to: '<='
257
- };
258
- form = $(element[0].form);
259
- for (check in CHECKS) {
260
- operator = CHECKS[check];
261
- if (!(options[check] != null)) {
262
- continue;
263
- }
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);
272
- if (!fn()) {
273
- return options.messages[check];
274
- }
275
- }
276
- if (options.odd && !(parseInt(val, 10) % 2)) {
277
- return options.messages.odd;
278
- }
279
- if (options.even && (parseInt(val, 10) % 2)) {
280
- return options.messages.even;
281
- }
282
- },
283
- length: function(element, options) {
284
- var CHECKS, blankOptions, check, fn, message, operator, tokenized_length, tokenizer;
285
- tokenizer = options.js_tokenizer || "split('')";
286
- tokenized_length = new Function('element', "return (element.val()." + tokenizer + " || '').length")(element);
287
- CHECKS = {
288
- is: '==',
289
- minimum: '>=',
290
- maximum: '<='
291
- };
292
- blankOptions = {};
293
- blankOptions.message = options.is ? options.messages.is : options.minimum ? options.messages.minimum : void 0;
294
- message = this.presence(element, blankOptions);
295
- if (message) {
296
- if (options.allow_blank === true) {
297
- return;
298
- }
299
- return message;
300
- }
301
- for (check in CHECKS) {
302
- operator = CHECKS[check];
303
- if (!options[check]) {
304
- continue;
305
- }
306
- fn = new Function("return " + tokenized_length + " " + operator + " " + options[check]);
307
- if (!fn()) {
308
- return options.messages[check];
309
- }
310
- }
311
- },
312
- exclusion: function(element, options) {
313
- var lower, message, o, upper, _ref;
314
- message = this.presence(element, options);
315
- if (message) {
316
- if (options.allow_blank === true) {
317
- return;
318
- }
319
- return message;
320
- }
321
- if (options["in"]) {
322
- if (_ref = element.val(), __indexOf.call((function() {
323
- var _i, _len, _ref1, _results;
324
- _ref1 = options["in"];
325
- _results = [];
326
- for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
327
- o = _ref1[_i];
328
- _results.push(o.toString());
329
- }
330
- return _results;
331
- })(), _ref) >= 0) {
213
+ acceptance: function(element, options) {
214
+ var _ref;
215
+ switch (element.attr('type')) {
216
+ case 'checkbox':
217
+ if (!element.attr('checked')) {
332
218
  return options.message;
333
219
  }
334
- }
335
- if (options.range) {
336
- lower = options.range[0];
337
- upper = options.range[1];
338
- if (element.val() >= lower && element.val() <= upper) {
220
+ break;
221
+ case 'text':
222
+ if (element.val() !== (((_ref = options.accept) != null ? _ref.toString() : void 0) || '1')) {
339
223
  return options.message;
340
224
  }
225
+ }
226
+ },
227
+ format: function(element, options) {
228
+ var message;
229
+ message = this.presence(element, options);
230
+ if (message) {
231
+ if (options.allow_blank === true) {
232
+ return;
233
+ }
234
+ return message;
235
+ }
236
+ if (options["with"] && !options["with"].test(element.val())) {
237
+ return options.message;
238
+ }
239
+ if (options.without && options.without.test(element.val())) {
240
+ return options.message;
241
+ }
242
+ },
243
+ numericality: function(element, options) {
244
+ var CHECKS, check, check_value, fn, form, operator, val;
245
+ val = jQuery.trim(element.val());
246
+ if (!ClientSideValidations.patterns.numericality.test(val)) {
247
+ if (options.allow_blank === true) {
248
+ return;
249
+ }
250
+ return options.messages.numericality;
251
+ }
252
+ if (options.only_integer && !/^[+-]?\d+$/.test(val)) {
253
+ return options.messages.only_integer;
254
+ }
255
+ CHECKS = {
256
+ greater_than: '>',
257
+ greater_than_or_equal_to: '>=',
258
+ equal_to: '==',
259
+ less_than: '<',
260
+ less_than_or_equal_to: '<='
261
+ };
262
+ form = $(element[0].form);
263
+ for (check in CHECKS) {
264
+ operator = CHECKS[check];
265
+ if (!(options[check] != null)) {
266
+ continue;
267
+ }
268
+ if (!isNaN(parseFloat(options[check])) && isFinite(options[check])) {
269
+ check_value = options[check];
270
+ } else if (form.find("[name*=" + options[check] + "]").size() === 1) {
271
+ check_value = form.find("[name*=" + options[check] + "]").val();
272
+ } else {
273
+ return;
341
274
  }
342
- },
343
- inclusion: function(element, options) {
344
- var lower, message, o, upper, _ref;
345
- message = this.presence(element, options);
346
- if (message) {
347
- if (options.allow_blank === true) {
348
- return;
349
- }
350
- return message;
275
+ fn = new Function("return " + val + " " + operator + " " + check_value);
276
+ if (!fn()) {
277
+ return options.messages[check];
351
278
  }
352
- if (options["in"]) {
353
- if (_ref = element.val(), __indexOf.call((function() {
354
- var _i, _len, _ref1, _results;
355
- _ref1 = options["in"];
356
- _results = [];
357
- for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
358
- o = _ref1[_i];
359
- _results.push(o.toString());
360
- }
361
- return _results;
362
- })(), _ref) >= 0) {
363
- return;
364
- }
365
- return options.message;
279
+ }
280
+ if (options.odd && !(parseInt(val, 10) % 2)) {
281
+ return options.messages.odd;
282
+ }
283
+ if (options.even && (parseInt(val, 10) % 2)) {
284
+ return options.messages.even;
285
+ }
286
+ },
287
+ length: function(element, options) {
288
+ var CHECKS, blankOptions, check, fn, message, operator, tokenized_length, tokenizer;
289
+ tokenizer = options.js_tokenizer || "split('')";
290
+ tokenized_length = new Function('element', "return (element.val()." + tokenizer + " || '').length")(element);
291
+ CHECKS = {
292
+ is: '==',
293
+ minimum: '>=',
294
+ maximum: '<='
295
+ };
296
+ blankOptions = {};
297
+ blankOptions.message = options.is ? options.messages.is : options.minimum ? options.messages.minimum : void 0;
298
+ message = this.presence(element, blankOptions);
299
+ if (message) {
300
+ if (options.allow_blank === true) {
301
+ return;
302
+ }
303
+ return message;
304
+ }
305
+ for (check in CHECKS) {
306
+ operator = CHECKS[check];
307
+ if (!options[check]) {
308
+ continue;
366
309
  }
367
- if (options.range) {
368
- lower = options.range[0];
369
- upper = options.range[1];
370
- if (element.val() >= lower && element.val() <= upper) {
371
- return;
310
+ fn = new Function("return " + tokenized_length + " " + operator + " " + options[check]);
311
+ if (!fn()) {
312
+ return options.messages[check];
313
+ }
314
+ }
315
+ },
316
+ exclusion: function(element, options) {
317
+ var lower, message, o, upper, _ref;
318
+ message = this.presence(element, options);
319
+ if (message) {
320
+ if (options.allow_blank === true) {
321
+ return;
322
+ }
323
+ return message;
324
+ }
325
+ if (options["in"]) {
326
+ if (_ref = element.val(), __indexOf.call((function() {
327
+ var _i, _len, _ref1, _results;
328
+ _ref1 = options["in"];
329
+ _results = [];
330
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
331
+ o = _ref1[_i];
332
+ _results.push(o.toString());
372
333
  }
334
+ return _results;
335
+ })(), _ref) >= 0) {
373
336
  return options.message;
374
337
  }
375
- },
376
- confirmation: function(element, options) {
377
- if (element.val() !== jQuery("#" + (element.attr('id')) + "_confirmation").val()) {
338
+ }
339
+ if (options.range) {
340
+ lower = options.range[0];
341
+ upper = options.range[1];
342
+ if (element.val() >= lower && element.val() <= upper) {
378
343
  return options.message;
379
344
  }
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
- }
409
345
  }
410
346
  },
411
- remote: {
412
- uniqueness: function(element, options) {
413
- var data, key, message, name, scope_value, scoped_element, scoped_name, _ref;
414
- message = ClientSideValidations.validators.local.presence(element, options);
415
- if (message) {
416
- if (options.allow_blank === true) {
417
- return;
347
+ inclusion: function(element, options) {
348
+ var lower, message, o, upper, _ref;
349
+ message = this.presence(element, options);
350
+ if (message) {
351
+ if (options.allow_blank === true) {
352
+ return;
353
+ }
354
+ return message;
355
+ }
356
+ if (options["in"]) {
357
+ if (_ref = element.val(), __indexOf.call((function() {
358
+ var _i, _len, _ref1, _results;
359
+ _ref1 = options["in"];
360
+ _results = [];
361
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
362
+ o = _ref1[_i];
363
+ _results.push(o.toString());
418
364
  }
419
- return message;
365
+ return _results;
366
+ })(), _ref) >= 0) {
367
+ return;
420
368
  }
421
- data = {};
422
- data.case_sensitive = !!options.case_sensitive;
423
- if (options.id) {
424
- data.id = options.id;
369
+ return options.message;
370
+ }
371
+ if (options.range) {
372
+ lower = options.range[0];
373
+ upper = options.range[1];
374
+ if (element.val() >= lower && element.val() <= upper) {
375
+ return;
425
376
  }
426
- if (options.scope) {
427
- data.scope = {};
428
- _ref = options.scope;
429
- for (key in _ref) {
430
- scope_value = _ref[key];
431
- scoped_name = element.attr('name').replace(/\[\w+\]$/, "[" + key + "]");
432
- scoped_element = jQuery("[name='" + scoped_name + "']");
433
- if (scoped_element[0] && scoped_element.val() !== scope_value) {
434
- data.scope[key] = scoped_element.val();
435
- scoped_element.unbind("change." + element.id).bind("change." + element.id, function() {
436
- element.trigger('change');
437
- return element.trigger('focusout');
438
- });
439
- } else {
440
- data.scope[key] = scope_value;
377
+ return options.message;
378
+ }
379
+ },
380
+ confirmation: function(element, options) {
381
+ if (element.val() !== jQuery("#" + (element.attr('id')) + "_confirmation").val()) {
382
+ return options.message;
383
+ }
384
+ },
385
+ uniqueness: function(element, options) {
386
+ var form, matches, name, name_prefix, name_suffix, valid, value;
387
+ name = element.attr('name');
388
+ if (/_attributes\]\[\d/.test(name)) {
389
+ matches = name.match(/^(.+_attributes\])\[\d+\](.+)$/);
390
+ name_prefix = matches[1];
391
+ name_suffix = matches[2];
392
+ value = element.val();
393
+ if (name_prefix && name_suffix) {
394
+ form = element.closest('form');
395
+ valid = true;
396
+ form.find(':input[name^="' + name_prefix + '"][name$="' + name_suffix + '"]').each(function() {
397
+ if ($(this).attr('name') !== name) {
398
+ if ($(this).val() === value) {
399
+ valid = false;
400
+ return $(this).data('notLocallyUnique', true);
401
+ } else {
402
+ if ($(this).data('notLocallyUnique')) {
403
+ return $(this).removeData('notLocallyUnique').data('changed', true);
404
+ }
405
+ }
441
406
  }
407
+ });
408
+ if (!valid) {
409
+ return options.message;
442
410
  }
443
411
  }
444
- if (/_attributes\]/.test(element.attr('name'))) {
445
- name = element.attr('name').match(/\[\w+_attributes\]/g).pop().match(/\[(\w+)_attributes\]/).pop();
446
- name += /(\[\w+\])$/.exec(element.attr('name'))[1];
447
- } else {
448
- name = element.attr('name');
449
- }
450
- if (options['class']) {
451
- name = options['class'] + '[' + name.split('[')[1];
452
- }
453
- data[name] = element.val();
454
- if (jQuery.ajax({
455
- url: '/validators/uniqueness',
456
- data: data,
457
- async: false
458
- }).status === 200) {
459
- return options.message;
460
- }
461
412
  }
462
413
  }
463
414
  },
464
- formBuilders: {
465
- 'ActionView::Helpers::FormBuilder': {
466
- add: function(element, settings, message) {
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)) {
470
- inputErrorField = jQuery(settings.input_tag);
471
- labelErrorField = jQuery(settings.label_tag);
472
- label = form.find("label[for='" + (element.attr('id')) + "']:not(.message)");
473
- if (element.attr('autofocus')) {
474
- element.attr('autofocus', false);
415
+ remote: {
416
+ uniqueness: function(element, options) {
417
+ var data, key, message, name, scope_value, scoped_element, scoped_name, _ref;
418
+ message = ClientSideValidations.validators.local.presence(element, options);
419
+ if (message) {
420
+ if (options.allow_blank === true) {
421
+ return;
422
+ }
423
+ return message;
424
+ }
425
+ data = {};
426
+ data.case_sensitive = !!options.case_sensitive;
427
+ if (options.id) {
428
+ data.id = options.id;
429
+ }
430
+ if (options.scope) {
431
+ data.scope = {};
432
+ _ref = options.scope;
433
+ for (key in _ref) {
434
+ scope_value = _ref[key];
435
+ scoped_name = element.attr('name').replace(/\[\w+\]$/, "[" + key + "]");
436
+ scoped_element = jQuery("[name='" + scoped_name + "']");
437
+ jQuery("[name='" + scoped_name + "']:checkbox").each(function() {
438
+ if (this.checked) {
439
+ return scoped_element = this;
440
+ }
441
+ });
442
+ if (scoped_element[0] && scoped_element.val() !== scope_value) {
443
+ data.scope[key] = scoped_element.val();
444
+ scoped_element.unbind("change." + element.id).bind("change." + element.id, function() {
445
+ element.trigger('change');
446
+ return element.trigger('focusout');
447
+ });
448
+ } else {
449
+ data.scope[key] = scope_value;
475
450
  }
476
- element.before(inputErrorField);
477
- inputErrorField.find('span#input_tag').replaceWith(element);
478
- inputErrorField.find('label.message').attr('for', element.attr('id'));
479
- labelErrorField.find('label.message').attr('for', element.attr('id'));
480
- labelErrorField.insertAfter(label);
481
- labelErrorField.find('label#label_tag').replaceWith(label);
482
- }
483
- return form.find("label.message[for='" + (element.attr('id')) + "']").text(message);
484
- },
485
- remove: function(element, settings) {
486
- var errorFieldClass, form, inputErrorField, label, labelErrorField;
487
- form = $(element[0].form);
488
- errorFieldClass = jQuery(settings.input_tag).attr('class');
489
- inputErrorField = element.closest("." + (errorFieldClass.replace(" ", ".")));
490
- label = form.find("label[for='" + (element.attr('id')) + "']:not(.message)");
491
- labelErrorField = label.closest("." + errorFieldClass);
492
- if (inputErrorField[0]) {
493
- inputErrorField.find("#" + (element.attr('id'))).detach();
494
- inputErrorField.replaceWith(element);
495
- label.detach();
496
- return labelErrorField.replaceWith(label);
497
451
  }
498
452
  }
453
+ if (/_attributes\]/.test(element.attr('name'))) {
454
+ name = element.attr('name').match(/\[\w+_attributes\]/g).pop().match(/\[(\w+)_attributes\]/).pop();
455
+ name += /(\[\w+\])$/.exec(element.attr('name'))[1];
456
+ } else {
457
+ name = element.attr('name');
458
+ }
459
+ if (options['class']) {
460
+ name = options['class'] + '[' + name.split('[')[1];
461
+ }
462
+ data[name] = element.val();
463
+ if (jQuery.ajax({
464
+ url: '/validators/uniqueness',
465
+ data: data,
466
+ async: false
467
+ }).status === 200) {
468
+ return options.message;
469
+ }
499
470
  }
500
- },
501
- patterns: {
502
- numericality: /^(-|\+)?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d*)?$/
503
- },
504
- callbacks: {
505
- element: {
506
- after: function(element, eventData) {},
507
- before: function(element, eventData) {},
508
- fail: function(element, message, addError, eventData) {
509
- return addError();
510
- },
511
- pass: function(element, removeError, eventData) {
512
- return removeError();
471
+ }
472
+ };
473
+
474
+ window.ClientSideValidations.formBuilders = {
475
+ 'ActionView::Helpers::FormBuilder': {
476
+ add: function(element, settings, message) {
477
+ var form, inputErrorField, label, labelErrorField;
478
+ form = $(element[0].form);
479
+ if (element.data('valid') !== false && !(form.find("label.message[for='" + (element.attr('id')) + "']")[0] != null)) {
480
+ inputErrorField = jQuery(settings.input_tag);
481
+ labelErrorField = jQuery(settings.label_tag);
482
+ label = form.find("label[for='" + (element.attr('id')) + "']:not(.message)");
483
+ if (element.attr('autofocus')) {
484
+ element.attr('autofocus', false);
485
+ }
486
+ element.before(inputErrorField);
487
+ inputErrorField.find('span#input_tag').replaceWith(element);
488
+ inputErrorField.find('label.message').attr('for', element.attr('id'));
489
+ labelErrorField.find('label.message').attr('for', element.attr('id'));
490
+ labelErrorField.insertAfter(label);
491
+ labelErrorField.find('label#label_tag').replaceWith(label);
492
+ }
493
+ return form.find("label.message[for='" + (element.attr('id')) + "']").text(message);
494
+ },
495
+ remove: function(element, settings) {
496
+ var errorFieldClass, form, inputErrorField, label, labelErrorField;
497
+ form = $(element[0].form);
498
+ errorFieldClass = jQuery(settings.input_tag).attr('class');
499
+ inputErrorField = element.closest("." + (errorFieldClass.replace(" ", ".")));
500
+ label = form.find("label[for='" + (element.attr('id')) + "']:not(.message)");
501
+ labelErrorField = label.closest("." + errorFieldClass);
502
+ if (inputErrorField[0]) {
503
+ inputErrorField.find("#" + (element.attr('id'))).detach();
504
+ inputErrorField.replaceWith(element);
505
+ label.detach();
506
+ return labelErrorField.replaceWith(label);
513
507
  }
508
+ }
509
+ }
510
+ };
511
+
512
+ window.ClientSideValidations.patterns = {
513
+ numericality: /^(-|\+)?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d*)?$/
514
+ };
515
+
516
+ window.ClientSideValidations.callbacks = {
517
+ element: {
518
+ after: function(element, eventData) {},
519
+ before: function(element, eventData) {},
520
+ fail: function(element, message, addError, eventData) {
521
+ return addError();
514
522
  },
515
- form: {
516
- after: function(form, eventData) {},
517
- before: function(form, eventData) {},
518
- fail: function(form, eventData) {},
519
- pass: function(form, eventData) {}
523
+ pass: function(element, removeError, eventData) {
524
+ return removeError();
520
525
  }
526
+ },
527
+ form: {
528
+ after: function(form, eventData) {},
529
+ before: function(form, eventData) {},
530
+ fail: function(form, eventData) {},
531
+ pass: function(form, eventData) {}
521
532
  }
522
533
  };
523
534