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

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