judge 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -2,7 +2,11 @@ rvm:
2
2
  - 1.9.2
3
3
  - 1.9.3
4
4
 
5
- script: "bundle exec rake spec"
5
+ before_script:
6
+ - "export DISPLAY=:99.0"
7
+ - "sh -e /etc/init.d/xvfb start"
8
+
9
+ script: "bundle exec rake"
6
10
 
7
11
  notifications:
8
12
  recipients:
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  judge
2
2
  =====
3
3
 
4
+ [![Build status](https://secure.travis-ci.org/joecorcoran/judge.png?branch=master)](http://travis-ci.org/joecorcoran/judge)
5
+
4
6
  Client-side form validation in Rails 3.
5
7
 
6
8
  Usage
@@ -8,12 +10,17 @@ Usage
8
10
 
9
11
  See http://judge.joecorcoran.co.uk for documentation.
10
12
 
13
+ Extensions
14
+ ----------
15
+
16
+ Use Judge with your favourite form building tool.
17
+
18
+ * http://github.com/joecorcoran/judge-formtastic
19
+ * http://github.com/joecorcoran/judge-simple_form
20
+
11
21
  License
12
22
  -------
13
23
 
14
24
  Released under an MIT license (see LICENSE.txt).
15
25
 
16
- http://tribesports.com
17
- http://blog.joecorcoran.co.uk
18
-
19
-
26
+ http://blog.joecorcoran.co.uk
data/judge.gemspec CHANGED
@@ -6,19 +6,18 @@ Gem::Specification.new do |s|
6
6
  s.name = "judge"
7
7
  s.version = Judge::VERSION
8
8
  s.homepage = "http://github.com/joecorcoran/judge"
9
- s.license = "MIT"
10
- s.summary = %Q{Simple client side ActiveModel::Validators}
11
- s.description = %Q{Validate forms on the client side, cleanly}
9
+ s.summary = "Simple client side ActiveModel::Validators"
10
+ s.description = "Validate Rails 3 forms on the client side, cleanly"
12
11
  s.email = "joe@tribesports.com"
13
12
  s.authors = ["Joe Corcoran"]
14
13
 
15
14
  s.files = `git ls-files`.split("\n")
16
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.test_files = `git ls-files -- spec/*`.split("\n")
17
16
  s.require_paths = ["lib"]
18
17
 
19
- s.add_development_dependency "jasmine", "~> 1.0.2"
20
- s.add_development_dependency "rails", "~> 3.0.10"
21
- s.add_development_dependency "rspec", "~> 2.8.0"
22
- s.add_development_dependency "sqlite3-ruby", "~> 1.3.2"
23
- s.add_development_dependency "factory_girl_rails", "~> 1.7.0"
18
+ s.add_development_dependency "jasmine", "~> 1.1.2"
19
+ s.add_development_dependency "rails", "~> 3.2"
20
+ s.add_development_dependency "rspec", "~> 2.8"
21
+ s.add_development_dependency "sqlite3-ruby", "~> 1.3.3"
22
+ s.add_development_dependency "factory_girl", "~> 2.6"
24
23
  end
@@ -1,14 +1,17 @@
1
+ // Judge 1.2.0
2
+ // (c) 2011–2012 Joe Corcoran
3
+ // http://raw.github.com/joecorcoran/judge/master/LICENSE.txt
1
4
  // This is the JavaScript part of Judge, a client-side validation gem for Rails 3.
2
5
  // You can find a guide and some more traditional API documentation at <http://joecorcoran.github.com/judge/>.
3
- // Hopefully this page will help you understand what's happening under the hood.
4
-
5
- /* http://raw.github.com/joecorcoran/judge/master/LICENSE.txt */
6
+ // Hopefully the comments here will help you understand what's happening under the hood.
6
7
 
7
8
  /*jshint curly: true, evil: true, newcap: true, noarg: true, strict: false */
8
9
  /*global _: false, JSON: false */
9
10
 
10
11
  // The judge namespace.
11
- var judge = judge || {};
12
+ var judge = {};
13
+
14
+ judge.VERSION = '1.2.0';
12
15
 
13
16
  // A judge.Watcher is a DOM element wrapper that judge uses to store validation info and instance methods.
14
17
  judge.Watcher = function (element) {
@@ -34,7 +37,6 @@ judge.Watcher = function (element) {
34
37
  message: '[judge][constructor] No DOM element passed to constructor'
35
38
  };
36
39
  }
37
-
38
40
  if (element.getAttribute('data-validate') === null) {
39
41
  throw {
40
42
  name: 'ReferenceError',
@@ -42,199 +44,149 @@ judge.Watcher = function (element) {
42
44
  };
43
45
  }
44
46
 
45
- // Convenient access to this Watcher.
46
- var watcher = this;
47
-
48
47
  // Watcher instance properties.
49
48
  this.element = element;
50
49
  this.validators = JSON.parse(this.element.getAttribute('data-validate'));
51
-
52
- // The `validate` instance method returns the validity of the watched element,
53
- // represented as an object containing the element itself and some validity information.
54
- this.validate = function() {
55
- watcher.errorMessages = [];
56
- var validators = watcher.validators,
57
- validity = true,
58
- messages = [];
59
- _(validators).each(function(validator) {
60
- var options = validator.options,
61
- msgs = validator.messages;
62
- if (watcher.element.value.length || options.allow_blank !== true) {
63
- var result = watcher.validates()[validator.kind](options, msgs);
64
- if (!result.valid && result.hasOwnProperty('messages')) {
65
- validity = false;
66
- messages.push(result.messages);
67
- }
50
+ };
51
+
52
+ // The `validate` method returns an object which describes the current validity of the
53
+ // value of the watched element.
54
+ judge.Watcher.prototype.validate = function() {
55
+ var allMessages = [];
56
+ _(this.validators).each(function(v) {
57
+ if (this.element.value.length || v.options.allow_blank !== true) {
58
+ var messages = this.validates()[v.kind](this.element.value, v.options, v.messages);
59
+ if (messages.length) {
60
+ allMessages.push(messages);
68
61
  }
69
- });
70
- return {
71
- valid: validity,
72
- messages: _(messages).flatten(),
73
- element: watcher.element
74
- };
62
+ }
63
+ }, this);
64
+ allMessages = _(allMessages).flatten();
65
+ return {
66
+ valid: (allMessages.length < 1),
67
+ messages: allMessages,
68
+ element: this.element
75
69
  };
76
-
77
70
  };
78
71
 
79
- // Watcher prototype methods.
80
- judge.Watcher.prototype.validates = function() {
81
- var watcher = this,
82
- extendedMethods = judge.customValidators,
83
- methods = {
84
-
85
- // Presence validator ported as closely as possible
86
- // from [ActiveModel::Validations::PresenceValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/PresenceValidator.html).
87
- presence: function(options, messages) {
88
- if (watcher.element.value.length) {
89
- return { valid:true };
90
- } else{
91
- return { valid:false, messages:[messages.blank] };
92
- }
93
- },
94
-
95
- // Length validator ported as closely as possible
96
- // from [ActiveModel::Validations::LengthValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/LengthValidator.html).
97
- length: function(options, messages) {
98
- var msgs = [],
99
- length = watcher.element.value.length,
100
- types = {
101
- minimum: { operator: '<', message: 'too_short' },
102
- maximum: { operator: '>', message: 'too_long' },
103
- is: { operator: '!=', message: 'wrong_length' }
104
- };
105
- _(types).each(function(properties, type) {
106
- var invalid = judge.utils.operate(length, properties.operator, options[type]);
107
- if (options.hasOwnProperty(type) && invalid) {
108
- msgs.push(messages[properties.message]);
109
- }
110
- });
111
- return msgs.length ? { valid:false, messages:msgs } : { valid:true };
112
- },
113
-
114
- // Exclusion validator ported as closely as possible
115
- // from [ActiveModel::Validations::ExclusionValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/ExclusionValidator.html).
116
- exclusion: function(options, messages) {
117
- var stringIn = _(options['in']).map(function(o) { return o.toString(); });
118
- if (_(stringIn).include(watcher.element.value)) {
119
- return {
120
- valid:false,
121
- messages:[messages.exclusion]
122
- };
123
- } else {
124
- return { valid:true };
125
- }
126
- },
127
-
128
- // Inclusion validator ported as closely as possible
129
- // from [ActiveModel::Validations::InclusionValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/InclusionValidator.html).
130
- inclusion: function(options, messages) {
131
- var stringIn = _(options['in']).map(function(o) { return o.toString(); });
132
- if (!_(stringIn).include(watcher.element.value)) {
133
- return {
134
- valid:false,
135
- messages:[messages.inclusion]
136
- };
137
- } else {
138
- return { valid:true };
139
- }
140
- },
141
-
142
- // Numericality validator ported as closely as possible
143
- // from [ActiveModel::Validations::NumericalityValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/NumericalityValidator.html).
144
- numericality: function(options, messages) {
145
- var operators = {
146
- greater_than: '>',
147
- greater_than_or_equal_to: '>=',
148
- equal_to: '==',
149
- less_than: '<',
150
- less_than_or_equal_to: '<='
151
- },
152
- msgs = [],
153
- value = watcher.element.value,
154
- parsedValue = parseFloat(value, 10);
72
+ // Ported ActiveModel validators.
73
+ // See <http://api.rubyonrails.org/classes/ActiveModel/Validations.html> for the originals.
74
+ judge.eachValidators = (function() {
75
+ return {
76
+ // ActiveModel::Validations::PresenceValidator
77
+ presence: function(value, options, messages) {
78
+ return (value.length) ? [] : [messages.blank];
79
+ },
80
+
81
+ // ActiveModel::Validations::LengthValidator
82
+ length: function(value, options, messages) {
83
+ var msgs = [],
84
+ types = {
85
+ minimum: { operator: '<', message: 'too_short' },
86
+ maximum: { operator: '>', message: 'too_long' },
87
+ is: { operator: '!=', message: 'wrong_length' }
88
+ };
89
+ _(types).each(function(properties, type) {
90
+ var invalid = judge.utils.operate(value.length, properties.operator, options[type]);
91
+ if (options.hasOwnProperty(type) && invalid) {
92
+ msgs.push(messages[properties.message]);
93
+ }
94
+ });
95
+ return msgs;
96
+ },
97
+
98
+ // ActiveModel::Validations::ExclusionValidator
99
+ exclusion: function(value, options, messages) {
100
+ var stringIn = _(options['in']).map(function(o) { return o.toString(); });
101
+ return (_(stringIn).include(value)) ? [messages.exclusion] : [];
102
+ },
103
+
104
+ // ActiveModel::Validations::InclusionValidator
105
+ inclusion: function(value, options, messages) {
106
+ var stringIn = _(options['in']).map(function(o) { return o.toString(); });
107
+ return (!_(stringIn).include(value)) ? [messages.inclusion] : [];
108
+ },
109
+
110
+ // ActiveModel::Validations::NumericalityValidator
111
+ numericality: function(value, options, messages) {
112
+ var operators = {
113
+ greater_than: '>',
114
+ greater_than_or_equal_to: '>=',
115
+ equal_to: '==',
116
+ less_than: '<',
117
+ less_than_or_equal_to: '<='
118
+ },
119
+ msgs = [],
120
+ parsedValue = parseFloat(value, 10);
155
121
 
156
- if (isNaN(Number(value))) {
157
- msgs.push(messages.not_a_number);
158
- } else {
159
- if (options.odd && judge.utils.isEven(parsedValue)) {
160
- msgs.push(messages.odd);
161
- }
162
- if (options.even && judge.utils.isOdd(parsedValue)) {
163
- msgs.push(messages.even);
164
- }
165
- if (options.only_integer && !judge.utils.isInt(parsedValue)) {
166
- msgs.push(messages.not_an_integer);
167
- }
168
- _(operators).each(function(operator, key) {
169
- var valid = judge.utils.operate(parsedValue, operators[key], parseFloat(options[key], 10));
170
- if (options.hasOwnProperty(key) && !valid) {
171
- msgs.push(messages[key]);
172
- }
173
- });
174
- }
175
- return msgs.length ? { valid:false, messages:msgs } : { valid:true };
176
- },
177
-
178
- // Format validator ported as closely as possible
179
- // from [ActiveModel::Validations::FormatValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/FormatValidator.html).
180
- format: function(options, messages) {
181
- var msgs = [],
182
- value = watcher.element.value;
183
- if (options.hasOwnProperty('with')) {
184
- var withReg = judge.utils.convertRegExp(options['with']);
185
- if (!withReg.test(value)) {
186
- msgs.push(messages.invalid);
187
- }
188
- }
189
- if (options.hasOwnProperty('without')) {
190
- var withoutReg = judge.utils.convertRegExp(options.without);
191
- if (withoutReg.test(value)) {
192
- msgs.push(messages.invalid);
193
- }
194
- }
195
- return msgs.length ? { valid:false, messages:msgs } : { valid:true };
196
- },
197
-
198
- // Acceptance validator ported as closely as possible
199
- // from [ActiveModel::Validations::AcceptanceValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/AcceptanceValidator.html).
200
- acceptance: function(options, messages) {
201
- if (watcher.element.checked === true) {
202
- return { valid:true };
203
- } else {
204
- return {
205
- valid:false,
206
- messages:[messages.accepted]
207
- };
208
- }
209
- },
210
-
211
- // Confirmation validator ported as closely as possible
212
- // from [ActiveModel::Validations::ConfirmationValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/ConfirmationValidator.html).
213
- confirmation: function(options, messages) {
214
- var id = watcher.element.getAttribute('id'),
215
- confId = id + '_confirmation',
216
- confElem = document.getElementById(confId);
217
- if (watcher.element.value === confElem.value) {
218
- return { valid:true };
219
- } else {
220
- return {
221
- valid:false,
222
- messages:[messages.confirmation]
223
- };
122
+ if (isNaN(Number(value))) {
123
+ msgs.push(messages.not_a_number);
124
+ } else {
125
+ if (options.odd && judge.utils.isEven(parsedValue)) {
126
+ msgs.push(messages.odd);
127
+ }
128
+ if (options.even && judge.utils.isOdd(parsedValue)) {
129
+ msgs.push(messages.even);
130
+ }
131
+ if (options.only_integer && !judge.utils.isInt(parsedValue)) {
132
+ msgs.push(messages.not_an_integer);
133
+ }
134
+ _(operators).each(function(operator, key) {
135
+ var valid = judge.utils.operate(parsedValue, operators[key], parseFloat(options[key], 10));
136
+ if (options.hasOwnProperty(key) && !valid) {
137
+ msgs.push(messages[key]);
224
138
  }
139
+ });
140
+ }
141
+ return msgs;
142
+ },
143
+
144
+ // ActiveModel::Validations::FormatValidator
145
+ format: function(value, options, messages) {
146
+ var msgs = [];
147
+ if (options.hasOwnProperty('with')) {
148
+ var withReg = judge.utils.convertRegExp(options['with']);
149
+ if (!withReg.test(value)) {
150
+ msgs.push(messages.invalid);
225
151
  }
226
- };
227
- // Return all validation methods, including those found in judge.customValidators.
228
- // If you name a custom validation method the same as a default one, for example
229
- // `judge.customValidators.presence = function() {};`
230
- // then the custom method _will overwrite_ the default one, so be careful!
231
- return _.extend(methods, extendedMethods);
232
- };
152
+ }
153
+ if (options.hasOwnProperty('without')) {
154
+ var withoutReg = judge.utils.convertRegExp(options.without);
155
+ if (withoutReg.test(value)) {
156
+ msgs.push(messages.invalid);
157
+ }
158
+ }
159
+ return msgs;
160
+ },
161
+
162
+ // ActiveModel::Validations::AcceptanceValidator
163
+ acceptance: function(value, options, messages) {
164
+ return (this._element.checked === true) ? [] : [messages.accepted];
165
+ },
166
+
167
+ // ActiveModel::Validations::ConfirmationValidator
168
+ confirmation: function(value, options, messages) {
169
+ var id = this._element.getAttribute('id'),
170
+ confId = id + '_confirmation',
171
+ confElem = document.getElementById(confId);
172
+ return (value === confElem.value) ? [] : [messages.confirmation];
173
+ }
174
+ };
175
+
176
+ }());
233
177
 
234
178
  // This object should contain any judge validation methods
235
179
  // that correspond to custom validators used in the model.
236
180
  judge.customValidators = {};
237
181
 
182
+ // Return all validation methods, including those found in judge.customValidators.
183
+ // If you name a custom validation method the same as a default one, for example
184
+ // `judge.customValidators.presence = function() {};`
185
+ // then the custom method _will overwrite_ the default one, so be careful!
186
+ judge.Watcher.prototype.validates = function() {
187
+ return _.extend({_element: this.element}, judge.eachValidators, judge.customValidators);
188
+ };
189
+
238
190
  // The judge store is now open :)
239
191
  judge.store = (function() {
240
192
  var store = {};
@@ -365,19 +317,13 @@ judge.utils = {
365
317
  // If you know of a better way (or an existing library) to convert regular expressions
366
318
  // from Ruby to JavaScript, I would really love to hear from you.
367
319
  convertRegExp: function(string) {
368
- var p = string.slice(1, -1).split(':'),
369
- o = p.shift(),
370
- r = p.join(':').replace(/\\\\/g, '\\');
371
- return new RegExp(r, judge.utils.convertFlags(o));
320
+ var parts = string.slice(1, -1).split(':'),
321
+ flags = parts.shift().replace('?', ''),
322
+ source = parts.join(':').replace(/\\\\/g, '\\');
323
+ return new RegExp(source, judge.utils.convertFlags(flags));
372
324
  },
373
325
  convertFlags: function(string) {
374
- var off = new RegExp('-'),
375
- multi = new RegExp('m');
376
- string = string.replace('?', '');
377
- if (off.test(string) || !multi.test(string)) {
378
- return '';
379
- } else {
380
- return 'm';
381
- }
326
+ var on = string.split('-')[0];
327
+ return (/m/.test(on)) ? 'm' : '';
382
328
  }
383
- };
329
+ };