client_side_validations 4.2.0 → 6.0.0

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.
@@ -6,16 +6,23 @@ module ClientSideValidations
6
6
  end
7
7
 
8
8
  def self.unique?(klass, attribute, value, params)
9
- klass = find_topmost_superclass(klass)
10
- column = klass.columns_hash[attribute.to_s]
11
- value = type_cast_value(column, value)
12
- value = column.limit ? value.to_s.mb_chars[0, column.limit] : value.to_s if value.is_a?(String)
9
+ klass = find_topmost_superclass(klass)
10
+ connection = klass.connection
11
+ column = klass.columns_hash[attribute.to_s]
12
+ value = type_cast_value(connection, column, value)
13
13
 
14
- t = klass.arel_table
14
+ sql = sql_statement(klass, connection, attribute, value, params)
15
+ relation = Arel::Nodes::SqlLiteral.new(sql)
15
16
 
17
+ klass.where(relation).empty?
18
+ end
19
+
20
+ def self.sql_statement(klass, connection, attribute, value, params)
16
21
  sql = []
22
+ t = klass.arel_table
23
+
17
24
  if params[:case_sensitive] == 'true'
18
- sql << 'BINARY' if t.engine.connection.adapter_name =~ /^mysql/i
25
+ sql << 'BINARY' if connection.adapter_name =~ /^mysql/i
19
26
  sql << t[attribute].eq(value).to_sql
20
27
  else
21
28
  escaped_value = value.gsub(/[%_]/, '\\\\\0')
@@ -25,19 +32,21 @@ module ClientSideValidations
25
32
  sql << "AND #{t[klass.primary_key].not_eq(params[:id]).to_sql}" if params[:id]
26
33
 
27
34
  (params[:scope] || {}).each do |scope_attribute, scope_value|
28
- scope_value = type_cast_value(klass.columns_hash[scope_attribute], scope_value)
35
+ scope_value = type_cast_value(connection, klass.columns_hash[scope_attribute], scope_value)
29
36
  sql << "AND #{t[scope_attribute].eq(scope_value).to_sql}"
30
37
  end
31
38
 
32
- relation = Arel::Nodes::SqlLiteral.new(sql.join(' '))
33
- !klass.where(relation).exists?
39
+ sql.join ' '
34
40
  end
35
41
 
36
- def self.type_cast_value(column, value)
37
- if column.respond_to?(:type_cast)
38
- column.type_cast(value)
42
+ def self.type_cast_value(connection, column, value)
43
+ type = connection.lookup_cast_type_from_column(column)
44
+ value = type.deserialize(value)
45
+
46
+ if column.limit && value.is_a?(String)
47
+ value.mb_chars[0, column.limit]
39
48
  else
40
- column.type_cast_from_database(value)
49
+ value
41
50
  end
42
51
  end
43
52
 
@@ -2,11 +2,10 @@ require 'client_side_validations/active_model'
2
2
  require 'client_side_validations/middleware'
3
3
  require 'client_side_validations/active_record/middleware'
4
4
 
5
- %w(uniqueness).each do |validator|
6
- require "client_side_validations/active_record/#{validator}"
7
- validator.capitalize!
8
- ActiveRecord::Validations.const_get("#{validator}Validator").send :include, ClientSideValidations::ActiveRecord.const_get(validator)
9
- end
10
-
11
5
  ActiveRecord::Base.send(:include, ClientSideValidations::ActiveModel::Validations)
12
6
  ClientSideValidations::Middleware::Uniqueness.register_orm(ClientSideValidations::ActiveRecord::Middleware)
7
+
8
+ %w(Uniqueness).each do |validator|
9
+ require "client_side_validations/active_record/#{validator.downcase}"
10
+ ActiveRecord::Validations.const_get("#{validator}Validator").send :include, ClientSideValidations::ActiveRecord.const_get(validator)
11
+ end
@@ -1,9 +1,13 @@
1
1
  module ClientSideValidations
2
2
  module Generators
3
- ASSETS = []
3
+ @@assets = []
4
4
 
5
5
  def self.register_assets(klass)
6
- ASSETS.push(*klass.assets)
6
+ @@assets.concat(klass.assets)
7
+ end
8
+
9
+ def self.assets
10
+ @@assets
7
11
  end
8
12
  end
9
13
  end
@@ -8,7 +8,7 @@ module ClientSideValidations
8
8
  end
9
9
 
10
10
  def call(env)
11
- matches = %r{\A/validators/(\w+)\z}.match(env['PATH_INFO'])
11
+ matches = %r{\A/?#{ClientSideValidations::Config.root_path}/validators\/(\w+)\z}.match(env['PATH_INFO'])
12
12
  if matches
13
13
  process_request(matches.captures.first, env)
14
14
  else
@@ -58,8 +58,8 @@ module ClientSideValidations
58
58
  end
59
59
 
60
60
  class Uniqueness < Base
61
- IGNORE_PARAMS = %w(case_sensitive id scope)
62
- REGISTERED_ORMS = []
61
+ IGNORE_PARAMS = %w(case_sensitive id scope).freeze
62
+ @@registered_orms = []
63
63
  class NotValidatable < StandardError; end
64
64
 
65
65
  def response
@@ -83,7 +83,7 @@ module ClientSideValidations
83
83
  end
84
84
 
85
85
  def self.registered_orms
86
- REGISTERED_ORMS
86
+ @@registered_orms
87
87
  end
88
88
 
89
89
  def registered_orms
@@ -98,7 +98,7 @@ module ClientSideValidations
98
98
  middleware_class = nil
99
99
 
100
100
  unless Array.wrap(klass._validators[attribute.to_sym]).find { |v| v.kind == :uniqueness }
101
- fail NotValidatable
101
+ raise NotValidatable
102
102
  end
103
103
 
104
104
  registered_orms.each do |orm|
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module ClientSideValidations
2
- VERSION = '4.2.0'.freeze
3
+ VERSION = '6.0.0'.freeze
3
4
  end
@@ -9,8 +9,6 @@ module ClientSideValidations
9
9
  end
10
10
  end
11
11
 
12
- private
13
-
14
12
  def self.asset_directory
15
13
  if asset_pipeline_enabled?
16
14
  "app#{Rails.configuration.assets.prefix}/javascripts"
@@ -19,16 +17,8 @@ module ClientSideValidations
19
17
  end
20
18
  end
21
19
 
22
- def asset_directory
23
- CopyAssetsGenerator.asset_directory
24
- end
25
-
26
20
  def self.assets
27
- ASSETS
28
- end
29
-
30
- def assets
31
- CopyAssetsGenerator.assets
21
+ ClientSideValidations::Generators.assets
32
22
  end
33
23
 
34
24
  def self.asset_file_names
@@ -40,15 +30,25 @@ module ClientSideValidations
40
30
  defined?(Sprockets).present?
41
31
  end
42
32
 
43
- def asset_pipeline_enabled?
44
- self.class.asset_pipeline_enabled?
45
- end
46
-
47
33
  def self.installation_message
48
34
  "Copies #{asset_file_names} to #{asset_directory}"
49
35
  end
50
36
 
51
37
  desc installation_message
38
+
39
+ private
40
+
41
+ def asset_directory
42
+ CopyAssetsGenerator.asset_directory
43
+ end
44
+
45
+ def assets
46
+ CopyAssetsGenerator.assets
47
+ end
48
+
49
+ def asset_pipeline_enabled?
50
+ self.class.asset_pipeline_enabled?
51
+ end
52
52
  end
53
53
  end
54
54
  end
@@ -8,8 +8,6 @@ module ClientSideValidations
8
8
  copy_file 'initializer.rb', 'config/initializers/client_side_validations.rb'
9
9
  end
10
10
 
11
- private
12
-
13
11
  def self.installation_message
14
12
  "Copies initializer into config/initializers and #{super.downcase}"
15
13
  end
@@ -1,3 +1,10 @@
1
+
2
+ /*!
3
+ * Client Side Validations - v6.0.0 (https://github.com/DavyJonesLocker/client_side_validations)
4
+ * Copyright (c) 2017 Geremia Taglialatela, Brian Cardarella
5
+ * Licensed under MIT (http://opensource.org/licenses/mit-license.php)
6
+ */
7
+
1
8
  (function() {
2
9
  var $, validateElement, validateForm, validatorsFor,
3
10
  indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
@@ -49,7 +56,7 @@
49
56
  for (validator_name in validators) {
50
57
  validator = validators[validator_name];
51
58
  if (validator_name.match("\\[" + captures[1] + "\\].*\\[\\]\\[" + captures[2] + "\\]$")) {
52
- name = name.replace(/\[[\da-z_]+\]\[(\w+)\]$/g, "[][$1]");
59
+ name = name.replace(/\[[\da-z_]+\]\[(\w+)\]$/g, '[][$1]');
53
60
  }
54
61
  }
55
62
  }
@@ -111,7 +118,7 @@
111
118
  };
112
119
  if (element.attr('name').search(/\[([^\]]*?)\]$/) >= 0) {
113
120
  destroyInputName = element.attr('name').replace(/\[([^\]]*?)\]$/, '[_destroy]');
114
- if ($("input[name='" + destroyInputName + "']").val() === "1") {
121
+ if ($("input[name='" + destroyInputName + "']").val() === '1') {
115
122
  passElement();
116
123
  return afterValidate();
117
124
  }
@@ -184,25 +191,25 @@
184
191
  'submit.ClientSideValidations': function(eventData) {
185
192
  if (!$form.isValid(form.ClientSideValidations.settings.validators)) {
186
193
  eventData.preventDefault();
187
- return eventData.stopImmediatePropagation();
194
+ eventData.stopImmediatePropagation();
188
195
  }
189
196
  },
190
197
  'ajax:beforeSend.ClientSideValidations': function(eventData) {
191
198
  if (eventData.target === this) {
192
- return $form.isValid(form.ClientSideValidations.settings.validators);
199
+ $form.isValid(form.ClientSideValidations.settings.validators);
193
200
  }
194
201
  },
195
202
  'form:validate:after.ClientSideValidations': function(eventData) {
196
- return ClientSideValidations.callbacks.form.after($form, eventData);
203
+ ClientSideValidations.callbacks.form.after($form, eventData);
197
204
  },
198
205
  'form:validate:before.ClientSideValidations': function(eventData) {
199
- return ClientSideValidations.callbacks.form.before($form, eventData);
206
+ ClientSideValidations.callbacks.form.before($form, eventData);
200
207
  },
201
208
  'form:validate:fail.ClientSideValidations': function(eventData) {
202
- return ClientSideValidations.callbacks.form.fail($form, eventData);
209
+ ClientSideValidations.callbacks.form.fail($form, eventData);
203
210
  },
204
211
  'form:validate:pass.ClientSideValidations': function(eventData) {
205
- return ClientSideValidations.callbacks.form.pass($form, eventData);
212
+ ClientSideValidations.callbacks.form.pass($form, eventData);
206
213
  }
207
214
  };
208
215
  for (event in ref) {
@@ -220,28 +227,28 @@
220
227
  $form = $(form);
221
228
  ref = {
222
229
  'focusout.ClientSideValidations': function() {
223
- return $(this).isValid(form.ClientSideValidations.settings.validators);
230
+ $(this).isValid(form.ClientSideValidations.settings.validators);
224
231
  },
225
232
  'change.ClientSideValidations': function() {
226
- return $(this).data('changed', true);
233
+ $(this).data('changed', true);
227
234
  },
228
235
  'element:validate:after.ClientSideValidations': function(eventData) {
229
- return ClientSideValidations.callbacks.element.after($(this), eventData);
236
+ ClientSideValidations.callbacks.element.after($(this), eventData);
230
237
  },
231
238
  'element:validate:before.ClientSideValidations': function(eventData) {
232
- return ClientSideValidations.callbacks.element.before($(this), eventData);
239
+ ClientSideValidations.callbacks.element.before($(this), eventData);
233
240
  },
234
241
  'element:validate:fail.ClientSideValidations': function(eventData, message) {
235
242
  var element;
236
243
  element = $(this);
237
- return ClientSideValidations.callbacks.element.fail(element, message, function() {
244
+ ClientSideValidations.callbacks.element.fail(element, message, function() {
238
245
  return form.ClientSideValidations.addError(element, message);
239
246
  }, eventData);
240
247
  },
241
248
  'element:validate:pass.ClientSideValidations': function(eventData) {
242
249
  var element;
243
250
  element = $(this);
244
- return ClientSideValidations.callbacks.element.pass(element, function() {
251
+ ClientSideValidations.callbacks.element.pass(element, function() {
245
252
  return form.ClientSideValidations.removeError(element);
246
253
  }, eventData);
247
254
  }
@@ -253,7 +260,7 @@
253
260
  }).on(event, binding);
254
261
  }
255
262
  $input.filter(':checkbox').on('change.ClientSideValidations', function() {
256
- return $(this).isValid(form.ClientSideValidations.settings.validators);
263
+ $(this).isValid(form.ClientSideValidations.settings.validators);
257
264
  });
258
265
  return $input.filter('[id$=_confirmation]').each(function() {
259
266
  var confirmationElement, element, ref1, results;
@@ -262,10 +269,10 @@
262
269
  if (element[0]) {
263
270
  ref1 = {
264
271
  'focusout.ClientSideValidations': function() {
265
- return element.data('changed', true).isValid(form.ClientSideValidations.settings.validators);
272
+ element.data('changed', true).isValid(form.ClientSideValidations.settings.validators);
266
273
  },
267
274
  'keyup.ClientSideValidations': function() {
268
- return element.data('changed', true).isValid(form.ClientSideValidations.settings.validators);
275
+ element.data('changed', true).isValid(form.ClientSideValidations.settings.validators);
269
276
  }
270
277
  };
271
278
  results = [];
@@ -325,7 +332,7 @@
325
332
  }
326
333
  },
327
334
  numericality: function(element, options) {
328
- var CHECKS, check, check_value, fn, form, operator, val;
335
+ var CHECKS, check, checkValue, fn, form, operator, val;
329
336
  val = $.trim(element.val());
330
337
  if (!ClientSideValidations.patterns.numericality.test(val)) {
331
338
  if (options.allow_blank === true && this.presence(element, {
@@ -335,7 +342,7 @@
335
342
  }
336
343
  return options.messages.numericality;
337
344
  }
338
- val = val.replace(new RegExp("\\" + ClientSideValidations.number_format.delimiter, 'g'), "").replace(new RegExp("\\" + ClientSideValidations.number_format.separator, 'g'), ".");
345
+ val = val.replace(new RegExp("\\" + ClientSideValidations.number_format.delimiter, 'g'), '').replace(new RegExp("\\" + ClientSideValidations.number_format.separator, 'g'), '.');
339
346
  if (options.only_integer && !/^[+-]?\d+$/.test(val)) {
340
347
  return options.messages.only_integer;
341
348
  }
@@ -352,14 +359,11 @@
352
359
  if (!(options[check] != null)) {
353
360
  continue;
354
361
  }
355
- if (!isNaN(parseFloat(options[check])) && isFinite(options[check])) {
356
- check_value = options[check];
357
- } else if (form.find("[name*=" + options[check] + "]").size() === 1) {
358
- check_value = form.find("[name*=" + options[check] + "]").val();
359
- } else {
362
+ checkValue = !isNaN(parseFloat(options[check])) && isFinite(options[check]) ? options[check] : form.find("[name*=" + options[check] + "]").length === 1 ? form.find("[name*=" + options[check] + "]").val() : void 0;
363
+ if ((checkValue == null) || checkValue === '') {
360
364
  return;
361
365
  }
362
- fn = new Function("return " + val + " " + operator + " " + check_value);
366
+ fn = new Function("return " + val + " " + operator + " " + checkValue);
363
367
  if (!fn()) {
364
368
  return options.messages[check];
365
369
  }
@@ -465,7 +469,9 @@
465
469
  }
466
470
  },
467
471
  confirmation: function(element, options) {
468
- if (element.val() !== $("#" + (element.attr('id')) + "_confirmation").val()) {
472
+ var regex;
473
+ regex = new RegExp("^" + (element.val()) + "$", options.case_sensitive ? '' : 'i');
474
+ if (!regex.test($("#" + (element.attr('id')) + "_confirmation").val())) {
469
475
  return options.message;
470
476
  }
471
477
  },
@@ -480,7 +486,7 @@
480
486
  if (name_prefix && name_suffix) {
481
487
  form = element.closest('form');
482
488
  valid = true;
483
- form.find(':input[name^="' + name_prefix + '"][name$="' + name_suffix + '"]').each(function() {
489
+ form.find(":input[name^=\"" + name_prefix + "\"][name$=\"" + name_suffix + "\"]").each(function() {
484
490
  if ($(this).attr('name') !== name) {
485
491
  if ($(this).val() === value) {
486
492
  valid = false;
@@ -544,7 +550,7 @@
544
550
  name = element.attr('name');
545
551
  }
546
552
  if (options['class']) {
547
- name = options['class'] + '[' + name.split('[')[1];
553
+ name = options['class'] + "[" + (name.split('[')[1]);
548
554
  }
549
555
  data[name] = element.val();
550
556
  if ($.ajax({
@@ -646,7 +652,9 @@
646
652
  }
647
653
  };
648
654
 
649
- $(document).bind((window.Turbolinks ? 'page:change' : 'ready'), function() {
655
+ window.ClientSideValidations.event = (window.Turbolinks != null) && window.Turbolinks.supported ? window.Turbolinks.EVENTS != null ? 'page:change' : 'turbolinks:load' : 'ready';
656
+
657
+ $(document).bind(window.ClientSideValidations.event, function() {
650
658
  ClientSideValidations.disableValidators();
651
659
  return $(ClientSideValidations.selectors.forms).validate();
652
660
  });