pcai_client_side_validations 3.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/client_side_validations.gemspec +42 -0
  2. data/lib/client_side_validations.rb +13 -0
  3. data/lib/client_side_validations/action_view.rb +14 -0
  4. data/lib/client_side_validations/action_view/form_builder.rb +157 -0
  5. data/lib/client_side_validations/action_view/form_helper.rb +86 -0
  6. data/lib/client_side_validations/action_view/form_tag_helper.rb +12 -0
  7. data/lib/client_side_validations/active_model.rb +60 -0
  8. data/lib/client_side_validations/active_model/acceptance.rb +10 -0
  9. data/lib/client_side_validations/active_model/exclusion.rb +15 -0
  10. data/lib/client_side_validations/active_model/format.rb +10 -0
  11. data/lib/client_side_validations/active_model/inclusion.rb +15 -0
  12. data/lib/client_side_validations/active_model/length.rb +24 -0
  13. data/lib/client_side_validations/active_model/numericality.rb +31 -0
  14. data/lib/client_side_validations/active_model/presence.rb +10 -0
  15. data/lib/client_side_validations/active_record.rb +11 -0
  16. data/lib/client_side_validations/active_record/middleware.rb +33 -0
  17. data/lib/client_side_validations/active_record/uniqueness.rb +28 -0
  18. data/lib/client_side_validations/core_ext.rb +3 -0
  19. data/lib/client_side_validations/core_ext/range.rb +10 -0
  20. data/lib/client_side_validations/core_ext/regexp.rb +14 -0
  21. data/lib/client_side_validations/engine.rb +6 -0
  22. data/lib/client_side_validations/files.rb +8 -0
  23. data/lib/client_side_validations/formtastic.rb +21 -0
  24. data/lib/client_side_validations/middleware.rb +81 -0
  25. data/lib/client_side_validations/mongo_mapper.rb +9 -0
  26. data/lib/client_side_validations/mongo_mapper/middleware.rb +20 -0
  27. data/lib/client_side_validations/mongo_mapper/uniqueness.rb +28 -0
  28. data/lib/client_side_validations/mongoid.rb +9 -0
  29. data/lib/client_side_validations/mongoid/middleware.rb +20 -0
  30. data/lib/client_side_validations/mongoid/uniqueness.rb +28 -0
  31. data/lib/client_side_validations/simple_form.rb +24 -0
  32. data/lib/client_side_validations/version.rb +3 -0
  33. data/lib/generators/client_side_validations/copy_asset_generator.rb +36 -0
  34. data/lib/generators/client_side_validations/install_generator.rb +45 -0
  35. data/lib/generators/templates/client_side_validations/README.rails.3.0 +6 -0
  36. data/lib/generators/templates/client_side_validations/README.rails.3.1 +7 -0
  37. data/lib/generators/templates/client_side_validations/initializer.rb +14 -0
  38. data/vendor/assets/javascripts/rails.validations.js +410 -0
  39. metadata +226 -0
@@ -0,0 +1,3 @@
1
+ module ClientSideValidations
2
+ VERSION = '3.1.5'
3
+ end
@@ -0,0 +1,36 @@
1
+ module ClientSideValidations
2
+ module Generators
3
+ class CopyAssetGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../../../../vendor/assets/javascripts', __FILE__)
5
+
6
+ private
7
+
8
+ def self.asset_pipeline_enabled?
9
+ (Rails.configuration.respond_to?(:assets) ? (Rails.configuration.assets || {}) : {})[:enabled]
10
+ end
11
+
12
+ def asset_pipeline_enabled?
13
+ self.class.asset_pipeline_enabled?
14
+ end
15
+
16
+ public
17
+
18
+ if asset_pipeline_enabled?
19
+ desc 'Creates a ClientSideValidations initializer and copies rails.validations.js to app/assets/javascripts.'
20
+ else
21
+ desc 'Creates a ClientSideValidations initializer and copies rails.validations.js to public/javascripts.'
22
+ end
23
+
24
+ def copy_javascript_asset
25
+ if asset_pipeline_enabled?
26
+ destination = 'app/assets/javascripts'
27
+ else
28
+ destination = 'public/javascripts'
29
+ end
30
+
31
+ copy_file 'rails.validations.js', "#{destination}/rails.validations.js"
32
+ end
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,45 @@
1
+ module ClientSideValidations
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../../templates/client_side_validations', __FILE__)
5
+
6
+ private
7
+
8
+ def self.asset_pipeline_enabled?
9
+ (Rails.configuration.respond_to?(:assets) ? (Rails.configuration.assets || {}) : {})[:enabled]
10
+ end
11
+
12
+ def asset_pipeline_enabled?
13
+ self.class.asset_pipeline_enabled?
14
+ end
15
+
16
+ public
17
+
18
+ if asset_pipeline_enabled?
19
+ desc 'Creates a ClientSideValidations initializer.'
20
+ else
21
+ desc 'Creates a ClientSideValidations initializer and copies rails.validations.js to public/javascripts.'
22
+ end
23
+
24
+ def copy_initializer
25
+ copy_file 'initializer.rb', 'config/initializers/client_side_validations.rb'
26
+ end
27
+
28
+ def copy_javascript_asset
29
+ unless asset_pipeline_enabled?
30
+ copy_file '../../../../vendor/assets/javascripts/rails.validations.js', 'public/javascripts/rails.validations.js'
31
+ end
32
+ end
33
+
34
+ def show_readme
35
+ if Rails.version >= '3.1'
36
+ readme 'README.rails.3.1' if behavior == :invoke
37
+ else
38
+ readme 'README.rails.3.0' if behavior == :invoke
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+ end
45
+
@@ -0,0 +1,6 @@
1
+ *********************
2
+ ClientSideValidations
3
+ *********************
4
+
5
+ Client Side Validations only works with jQuery.
6
+ You'll need to include jQuery in your layout file before you include 'rails.validations.js'
@@ -0,0 +1,7 @@
1
+ *********************
2
+ ClientSideValidations
3
+ *********************
4
+
5
+ In your app/assets/javascripts/application.js file add the following:
6
+
7
+ //= require rails.validations
@@ -0,0 +1,14 @@
1
+ # ClientSideValidations Initializer
2
+
3
+ require 'client_side_validations/simple_form' if defined?(::SimpleForm)
4
+ require 'client_side_validations/formtastic' if defined?(::Formtastic)
5
+
6
+ # Uncomment the following block if you want each input field to have the validation messages attached.
7
+ # ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
8
+ # unless html_tag =~ /^<label/
9
+ # %{<div class="field_with_errors">#{html_tag}<label for="#{instance.send(:tag_id)}" class="message">#{instance.error_message.first}</label></div>}.html_safe
10
+ # else
11
+ # %{<div class="field_with_errors">#{html_tag}</div>}.html_safe
12
+ # end
13
+ # end
14
+
@@ -0,0 +1,410 @@
1
+ /*!
2
+ * Rails 3 Client Side Validations - v3.1.4
3
+ * https://github.com/bcardarlela/client_side_validations
4
+ *
5
+ * Copyright (c) 2011 Brian Cardarella
6
+ * Licensed under the MIT license
7
+ * http://www.opensource.org/licenses/mit-license.php
8
+ */
9
+
10
+ (function($) {
11
+ $.fn.validate = function() {
12
+ return this.filter('form[data-validate]').each(function() {
13
+ var form = $(this);
14
+ var settings = window[form.attr('id')];
15
+
16
+ // Set up the events for the form
17
+ form
18
+ .submit( function() { return form.isValid(settings.validators); })
19
+ .bind('ajax:beforeSend', function(eventData) { if(eventData.target == this) return form.isValid(settings.validators); })
20
+ // Callbacks
21
+ .bind('form:validate:after', function(eventData) { clientSideValidations.callbacks.form.after( form, eventData); })
22
+ .bind('form:validate:before', function(eventData) { clientSideValidations.callbacks.form.before(form, eventData); })
23
+ .bind('form:validate:fail', function(eventData) { clientSideValidations.callbacks.form.fail( form, eventData); })
24
+ .bind('form:validate:pass', function(eventData) { clientSideValidations.callbacks.form.pass( form, eventData); })
25
+
26
+ // Set up the events for each validatable form element
27
+ .find('[data-validate]:input:not(:radio)')
28
+ .live('focusout', function() { $(this).isValid(settings.validators); })
29
+ .live('change', function() { $(this).data('changed', true); })
30
+ // Callbacks
31
+ .live('element:validate:after', function(eventData) { clientSideValidations.callbacks.element.after( $(this), eventData); })
32
+ .live('element:validate:before', function(eventData) { clientSideValidations.callbacks.element.before($(this), eventData); })
33
+ .live('element:validate:fail', function(eventData, message) {
34
+ var element = $(this);
35
+ clientSideValidations.callbacks.element.fail(element, message, function() {
36
+ addError(element, message);
37
+ }, eventData) })
38
+ .live('element:validate:pass', function(eventData) {
39
+ var element = $(this);
40
+ clientSideValidations.callbacks.element.pass(element, function() {
41
+ removeError(element);
42
+ }, eventData) })
43
+ // Checkboxes - Live events don't support filter
44
+ .end().find('[data-validate]:checkbox')
45
+ .live('click', function() { $(this).isValid(settings.validators); })
46
+ // Inputs for confirmations
47
+ .end().find('[id*=_confirmation]').each(function() {
48
+ var confirmationElement = $(this),
49
+ element = form.find('#' + this.id.match(/(.+)_confirmation/)[1] + '[data-validate]:input');
50
+
51
+ if (element[0]) {
52
+ $('#' + confirmationElement.attr('id'))
53
+ .live('focusout', function() {
54
+ element.data('changed', true).isValid(settings.validators);
55
+ })
56
+ .live('keyup', function() {
57
+ element.data('changed', true).isValid(settings.validators);
58
+ })
59
+ }
60
+ });
61
+
62
+ var addError = function(element, message) {
63
+ clientSideValidations.formBuilders[settings.type].add(element, settings, message);
64
+ }
65
+
66
+ var removeError = function(element) {
67
+ clientSideValidations.formBuilders[settings.type].remove(element, settings);
68
+ }
69
+ });
70
+ }
71
+
72
+ $.fn.isValid = function(validators) {
73
+ if ($(this[0]).is('form')) {
74
+ return validateForm($(this[0]), validators);
75
+ } else {
76
+ return validateElement($(this[0]), validators[this[0].name]);
77
+ }
78
+ }
79
+
80
+ var validateForm = function(form, validators) {
81
+ var valid = true;
82
+
83
+ form.trigger('form:validate:before').find('[data-validate]:input').each(function() {
84
+ if (!$(this).isValid(validators)) { valid = false; }
85
+ });
86
+
87
+ if (valid) {
88
+ form.trigger('form:validate:pass');
89
+ } else {
90
+ form.trigger('form:validate:fail');
91
+ }
92
+
93
+ form.trigger('form:validate:after');
94
+ return valid;
95
+ }
96
+
97
+ var validateElement = function(element, validators) {
98
+ element.trigger('element:validate:before');
99
+
100
+ if (element.data('changed') !== false) {
101
+ var valid = true;
102
+ element.data('changed', false);
103
+
104
+ // Because 'length' is defined on the list of validators we cannot call jQuery.each on
105
+ // the clientSideValidations.validators.all() object
106
+ for (kind in clientSideValidations.validators.all()) {
107
+ if (validators[kind] && (message = clientSideValidations.validators.all()[kind](element, validators[kind]))) {
108
+ element.trigger('element:validate:fail', message).data('valid', false);
109
+ valid = false;
110
+ break;
111
+ }
112
+ }
113
+
114
+ if (valid) { element.data('valid', null); element.trigger('element:validate:pass'); }
115
+ }
116
+
117
+ element.trigger('element:validate:after');
118
+ return element.data('valid') === false ? false : true;
119
+ }
120
+
121
+ // Main hook
122
+ // If new forms are dynamically introduced into the DOM the .validate() method
123
+ // must be invoked on that form
124
+ $(function() { $('form[data-validate]').validate(); })
125
+ })(jQuery);
126
+
127
+ var clientSideValidations = {
128
+ validators: {
129
+ all: function() { return jQuery.extend({}, clientSideValidations.validators.local, clientSideValidations.validators.remote) },
130
+ local: {
131
+ presence: function(element, options) {
132
+ if (/^\s*$/.test(element.val() || "")) {
133
+ return options.message;
134
+ }
135
+ },
136
+ acceptance: function(element, options) {
137
+ switch (element.attr('type')) {
138
+ case 'checkbox':
139
+ if (!element.attr('checked')) {
140
+ return options.message;
141
+ }
142
+ break;
143
+ case 'text':
144
+ if (element.val() != (options.accept || '1')) {
145
+ return options.message;
146
+ }
147
+ break;
148
+ }
149
+ },
150
+ format: function(element, options) {
151
+ if ((message = this.presence(element, options)) && options.allow_blank == true) {
152
+ return;
153
+ } else if (message) {
154
+ return message;
155
+ } else {
156
+ if (options['with'] && !options['with'].test(element.val())) {
157
+ return options.message;
158
+ } else if (options['without'] && options['without'].test(element.val())) {
159
+ return options.message;
160
+ }
161
+ }
162
+ },
163
+ numericality: function(element, options) {
164
+ if (!/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d*)?$/.test(element.val()) && element.val() != '') {
165
+ return options.messages.numericality;
166
+ }
167
+
168
+ if (options.only_integer && !/^[+-]?\d+$/.test(element.val())) {
169
+ return options.messages.only_integer;
170
+ }
171
+
172
+ var CHECKS = { greater_than: '>', greater_than_or_equal_to: '>=',
173
+ equal_to: '==', less_than: '<', less_than_or_equal_to: '<=' }
174
+
175
+ for (var check in CHECKS) {
176
+ if (options[check] != undefined && !(new Function("return " + element.val() + CHECKS[check] + options[check])())) {
177
+ return options.messages[check];
178
+ }
179
+ }
180
+
181
+ if (options.odd && !(parseInt(element.val()) % 2)) {
182
+ return options.messages.odd;
183
+ }
184
+
185
+ if (options.even && (parseInt(element.val()) % 2)) {
186
+ return options.messages.even;
187
+ }
188
+ },
189
+ length: function(element, options) {
190
+ var blankOptions = {};
191
+ if (options.is) {
192
+ blankOptions.message = options.messages.is;
193
+ } else if (options.minimum) {
194
+ blankOptions.message = options.messages.minimum;
195
+ }
196
+ if ((message = this.presence(element, blankOptions)) && options.allow_blank == true) {
197
+ return;
198
+ } else if (message) {
199
+ return message;
200
+ } else {
201
+ var CHECKS = { is: '==', minimum: '>=', maximum: '<=' }
202
+ var tokenizer = options.js_tokenizer || "split('')";
203
+ var tokenized_length = new Function("element", "return (element.val()." + tokenizer + " || '').length;")(element);
204
+
205
+ for (var check in CHECKS) {
206
+ if (options[check] && !(new Function("return " + tokenized_length + CHECKS[check] + options[check])())) {
207
+ return options.messages[check];
208
+ }
209
+ }
210
+ }
211
+ },
212
+ exclusion: function(element, options) {
213
+ if ((message = this.presence(element, options)) && options.allow_blank == true) {
214
+ return;
215
+ } else if (message) {
216
+ return message;
217
+ } else {
218
+ if (options['in']) {
219
+ for (var i = 0; i < options['in'].length; i++) {
220
+ if (options['in'][i] == element.val()) {
221
+ return options.message;
222
+ }
223
+ }
224
+ } else if (options['range']) {
225
+ var lower = options['range'][0],
226
+ upper = options['range'][1];
227
+ if (element.val() >= lower && element.val() <= upper) {
228
+ return options.message;
229
+ }
230
+ }
231
+ }
232
+ },
233
+ inclusion: function(element, options) {
234
+ if ((message = this.presence(element, options)) && options.allow_blank == true) {
235
+ return;
236
+ } else if (message) {
237
+ return message;
238
+ } else {
239
+ if (options['in']) {
240
+ for (var i = 0; i < options['in'].length; i++) {
241
+ if (options['in'][i] == element.val()) {
242
+ return;
243
+ }
244
+ }
245
+ return options.message;
246
+ } else if (options['range']) {
247
+ var lower = options['range'][0],
248
+ upper = options['range'][1];
249
+
250
+ if (element.val() >= lower && element.val() <= upper) {
251
+ return;
252
+ } else {
253
+ return options.message;
254
+ }
255
+ }
256
+ }
257
+ },
258
+ confirmation: function(element, options) {
259
+ if (element.val() != jQuery('#' + element.attr('id') + '_confirmation').val()) {
260
+ return options.message;
261
+ }
262
+ }
263
+ },
264
+ remote: {
265
+ uniqueness: function(element, options) {
266
+ if ((message = clientSideValidations.validators.local.presence(element, options)) && options.allow_blank === true) {
267
+ return;
268
+ } else if (message) {
269
+ return message;
270
+ } else {
271
+ var data = {};
272
+ data['case_sensitive'] = !!options.case_sensitive;
273
+ if (options.id) {
274
+ data['id'] = options.id;
275
+ }
276
+
277
+ if (options.scope) {
278
+ data.scope = {}
279
+ for (key in options.scope) {
280
+ var scoped_element = jQuery('[name="' + element.attr('name').replace(/\[\w+]$/, '[' + key + ']' + '"]'));
281
+ if (scoped_element[0] && scoped_element.val() != options.scope[key]) {
282
+ data.scope[key] = scoped_element.val();
283
+ scoped_element.unbind('change.' + element.id).bind('change.' + element.id, function() { element.trigger('change'); element.trigger('focusout'); });
284
+ } else {
285
+ data.scope[key] = options.scope[key];
286
+ }
287
+ }
288
+ }
289
+
290
+ // Kind of a hack but this will isolate the resource name and attribute.
291
+ // e.g. user[records_attributes][0][title] => records[title]
292
+ // e.g. user[record_attributes][title] => record[title]
293
+ // Server side handles classifying the resource properly
294
+ if (/_attributes]/.test(element.attr('name'))) {
295
+ var name = element.attr('name').match(/\[\w+_attributes]/g).pop().match(/\[(\w+)_attributes]/).pop();
296
+ name += /(\[\w+])$/.exec(element.attr('name'))[1];
297
+ } else {
298
+ var name = element.attr('name');
299
+ }
300
+
301
+ // Override the name if a nested module class is passed
302
+ if (options['class']) {
303
+ name = options['class'] + '[' + name.split('[')[1]
304
+ }
305
+ data[name] = element.val();
306
+
307
+ if (jQuery.ajax({
308
+ url: '/validators/uniqueness',
309
+ data: data,
310
+ async: false
311
+ }).status == 200) {
312
+ return options.message;
313
+ }
314
+ }
315
+ }
316
+ }
317
+ },
318
+ formBuilders: {
319
+ 'ActionView::Helpers::FormBuilder': {
320
+ add: function(element, settings, message) {
321
+ if (element.data('valid') !== false && jQuery('label.message[for="' + element.attr('id') + '"]')[0] == undefined) {
322
+ var inputErrorField = jQuery(settings.input_tag),
323
+ labelErrorField = jQuery(settings.label_tag),
324
+ label = jQuery('label[for="' + element.attr('id') + '"]:not(.message)');
325
+
326
+ if (element.attr('autofocus')) { element.attr('autofocus', false) };
327
+ element.before(inputErrorField);
328
+ inputErrorField.find('span#input_tag').replaceWith(element);
329
+ inputErrorField.find('label.message').attr('for', element.attr('id'));
330
+ labelErrorField.find('label.message').attr('for', element.attr('id'));
331
+ label.replaceWith(labelErrorField);
332
+ labelErrorField.find('label#label_tag').replaceWith(label);
333
+ }
334
+ jQuery('label.message[for="' + element.attr('id') + '"]').text(message);
335
+ },
336
+ remove: function(element, settings) {
337
+ var errorFieldClass = jQuery(settings.input_tag).attr('class'),
338
+ inputErrorField = element.closest('.' + errorFieldClass),
339
+ label = jQuery('label[for="' + element.attr('id') + '"]:not(.message)'),
340
+ labelErrorField = label.closest('.' + errorFieldClass);
341
+
342
+ if (inputErrorField[0]) {
343
+ inputErrorField.find('#' + element.attr('id')).detach();
344
+ inputErrorField.replaceWith(element);
345
+ label.detach();
346
+ labelErrorField.replaceWith(label);
347
+ }
348
+ }
349
+ },
350
+ 'SimpleForm::FormBuilder': {
351
+ add: function(element, settings, message) {
352
+ if (element.data('valid') !== false) {
353
+ var wrapper = element.closest(settings.wrapper_tag);
354
+ wrapper.addClass(settings.wrapper_error_class);
355
+ var errorElement = $('<' + settings.error_tag + ' class="' + settings.error_class + '">' + message + '</' + settings.error_tag + '>');
356
+ wrapper.append(errorElement);
357
+ } else {
358
+ element.parent().find(settings.error_tag + '.' + settings.error_class).text(message);
359
+ }
360
+ },
361
+ remove: function(element, settings) {
362
+ var wrapper = element.closest(settings.wrapper_tag + '.' + settings.wrapper_error_class);
363
+ wrapper.removeClass(settings.wrapper_error_class);
364
+ var errorElement = wrapper.find(settings.error_tag + '.' + settings.error_class);
365
+ errorElement.remove();
366
+ }
367
+
368
+ },
369
+ 'Formtastic::FormBuilder': {
370
+ add: function(element, settings, message) {
371
+ if (element.data('valid') !== false) {
372
+ var wrapper = element.closest('li');
373
+ wrapper.addClass('error');
374
+ var errorElement = $('<p class="' + settings.inline_error_class + '">' + message + '</p>');
375
+ wrapper.append(errorElement);
376
+ } else {
377
+ element.parent().find('p.' + settings.inline_error_class).text(message);
378
+ }
379
+ },
380
+ remove: function(element, settings) {
381
+ var wrapper = element.closest('li.error');
382
+ wrapper.removeClass('error');
383
+ var errorElement = wrapper.find('p.' + settings.inline_error_class);
384
+ errorElement.remove();
385
+ }
386
+ },
387
+ 'NestedForm::Builder': {
388
+ add: function(element, settings, message) {
389
+ clientSideValidations.formBuilders['ActionView::Helpers::FormBuilder'].add(element, settings, message);
390
+ },
391
+ remove: function(element, settings, message) {
392
+ clientSideValidations.formBuilders['ActionView::Helpers::FormBuilder'].remove(element, settings, message);
393
+ }
394
+ }
395
+ },
396
+ callbacks: {
397
+ element: {
398
+ after: function(element, eventData) { },
399
+ before: function(element, eventData) { },
400
+ fail: function(element, message, addError, eventData) { addError() },
401
+ pass: function(element, removeError, eventData) { removeError() }
402
+ },
403
+ form: {
404
+ after: function(form, eventData) { },
405
+ before: function(form, eventData) { },
406
+ fail: function(form, eventData) { },
407
+ pass: function(form, eventData) { }
408
+ }
409
+ }
410
+ };