guardsjs-rails 0.7.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/guardsjs-rails/version.rb +1 -1
- data/vendor/assets/javascripts/guards.js +1554 -422
- metadata +5 -2
@@ -1,5 +1,5 @@
|
|
1
1
|
/*!
|
2
|
-
* Guards JavaScript jQuery Plugin
|
2
|
+
* Guards JavaScript jQuery Plugin v1.0.0
|
3
3
|
* https://github.com/on-site/guards.js
|
4
4
|
*
|
5
5
|
* Copyright 2010-2013, On-Site.com, http://www.on-site.com/
|
@@ -8,51 +8,52 @@
|
|
8
8
|
* Includes code for email and phone number validation from the jQuery
|
9
9
|
* Validation plugin. http://docs.jquery.com/Plugins/Validation
|
10
10
|
*
|
11
|
-
* Date:
|
11
|
+
* Date: Wed Apr 17 01:43:25 2013 -0700
|
12
12
|
*/
|
13
13
|
|
14
14
|
/**
|
15
15
|
* This plugin is initially inspired by the standard Validation jQuery
|
16
|
-
* plugin (http://
|
17
|
-
*
|
18
|
-
* To guard forms with this plugin, you must specify a set of guards
|
19
|
-
* via $.guards.add(selector).using(guard) or
|
20
|
-
* $.guard(selector).using(guard). These guards are then invoked from
|
21
|
-
* the first one specified to the last one specified.
|
22
|
-
*
|
23
|
-
* Example usage:
|
24
|
-
*
|
25
|
-
* $(function() {
|
26
|
-
* // Change the default error tag wrapper to a div.
|
27
|
-
* $.guards.defaults.tag = "div";
|
28
|
-
*
|
29
|
-
* // Enable the submit guard hook for the form with the "myForm" id.
|
30
|
-
* $("#myForm").enableGuards();
|
31
|
-
*
|
32
|
-
* // Guard that fields with "required" class have a value.
|
33
|
-
* $.guard(".required").using("required");
|
34
|
-
*
|
35
|
-
* // Guard that the text fields don't have the value "invalid" or "bad".
|
36
|
-
* $.guard(":text").using(function(value, element) {
|
37
|
-
* return $.inArray(value, ["invalid", "bad"]) == -1;
|
38
|
-
* }).message("Don't use the keyword 'invalid' or 'bad'.");
|
39
|
-
*
|
40
|
-
* // Guard that fields with "email" class specify at least one
|
41
|
-
* // value, but only show 1 error message if none is specified (but
|
42
|
-
* // still highlight all of the fields).
|
43
|
-
* $.guard(".email").using("oneRequired")
|
44
|
-
* .message("Please specify at least one email.").grouped();
|
16
|
+
* plugin (http://plugins.jquery.com/validation/).
|
45
17
|
*/
|
46
18
|
(function($) {
|
19
|
+
/*jshint devel:true, jquery:true */
|
20
|
+
"use strict";
|
21
|
+
|
22
|
+
/**
|
23
|
+
* @page Global Functions
|
24
|
+
* @section guard
|
25
|
+
* @signature jQuery.guard(selector)
|
26
|
+
* @since 1.0.0
|
27
|
+
*
|
28
|
+
* <p>
|
29
|
+
* Guard elements with the given selector when the form is guarded. This is the way to add
|
30
|
+
* new guards to form inputs. It returns a <a href="guard_type.html"><code>Guards</code></a>
|
31
|
+
* instance which has chainable methods to define the attributes of the guard.
|
32
|
+
* </p>
|
33
|
+
*
|
34
|
+
* <div class="example">
|
35
|
+
* <div class="display">
|
36
|
+
* <script>
|
37
|
+
* $.guard(".guarded").using("required").message("Please provide a value.");
|
38
|
+
* </script>
|
39
|
+
*
|
40
|
+
* <p>
|
41
|
+
* <input class="guarded" type="text" /><br />
|
42
|
+
* <small>Required field</small>
|
43
|
+
* </p>
|
44
|
+
* </div>
|
45
|
+
* </div>
|
46
|
+
*/
|
47
47
|
$.guard = function(selector) {
|
48
48
|
return $.guards.add(selector);
|
49
49
|
};
|
50
50
|
|
51
|
-
$.guard.version = "0.
|
51
|
+
$.guard.version = "1.0.0";
|
52
52
|
|
53
53
|
$.Guards = function() {
|
54
54
|
var self = this;
|
55
55
|
this._guards = [];
|
56
|
+
this.named = {};
|
56
57
|
|
57
58
|
this.options = {
|
58
59
|
stackErrors: false
|
@@ -62,120 +63,36 @@
|
|
62
63
|
notChecked: ""
|
63
64
|
};
|
64
65
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
return self[aggregator](value, function(v) {
|
70
|
-
return self[validator].apply(self, $.merge([v], args));
|
71
|
-
});
|
72
|
-
};
|
73
|
-
};
|
74
|
-
};
|
75
|
-
|
76
|
-
var minMaxMessage = function(formatting, minMaxFormat) {
|
77
|
-
return function(options) {
|
78
|
-
if (self.isNullOrUndefined(options)) {
|
79
|
-
options = {};
|
80
|
-
}
|
81
|
-
|
82
|
-
if (!$.isFunction(minMaxFormat)) {
|
83
|
-
minMaxFormat = function(x) { return x; };
|
84
|
-
}
|
85
|
-
|
86
|
-
var minDefined = !self.isNullOrUndefined(options.min);
|
87
|
-
var maxDefined = !self.isNullOrUndefined(options.max);
|
88
|
-
|
89
|
-
if (minDefined && maxDefined) {
|
90
|
-
return self.format(formatting.minAndMax, minMaxFormat(options.min), minMaxFormat(options.max));
|
91
|
-
}
|
92
|
-
|
93
|
-
if (minDefined) {
|
94
|
-
return self.format(formatting.min, minMaxFormat(options.min));
|
95
|
-
}
|
66
|
+
this.defaults = {
|
67
|
+
grouped: false,
|
68
|
+
guard: "required",
|
69
|
+
invalidClass: "invalid-field",
|
96
70
|
|
97
|
-
|
98
|
-
|
99
|
-
}
|
71
|
+
liveCallback: function(e) {
|
72
|
+
var $element = $(e.target);
|
100
73
|
|
101
|
-
if (
|
102
|
-
return
|
74
|
+
if (!$element.is(":guardable")) {
|
75
|
+
return;
|
103
76
|
}
|
104
77
|
|
105
|
-
|
106
|
-
};
|
107
|
-
};
|
108
|
-
|
109
|
-
var arrayMessage = function(formatting) {
|
110
|
-
return function(array) {
|
111
|
-
return self.format(formatting, $.map(array, function(x, i) { return $.trim("" + x); }).join(", "));
|
112
|
-
};
|
113
|
-
};
|
114
|
-
|
115
|
-
this.defaults = {
|
116
|
-
grouped: false,
|
117
|
-
guard: "required",
|
78
|
+
$element.clearErrors();
|
118
79
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
phoneUS: defineGuard("isAllValid", "isValidPhoneUS"),
|
131
|
-
required: defineGuard("isAllValid", "isPresent"),
|
132
|
-
same: defineGuard("passThrough", "isSame"),
|
133
|
-
string: defineGuard("isAllValid", "isValidString")
|
80
|
+
self.applyGuards(function(guard) {
|
81
|
+
if (guard.isGrouped()) {
|
82
|
+
if (guard.appliesTo($element)) {
|
83
|
+
return self.parentContext($element).find(":guardable");
|
84
|
+
} else {
|
85
|
+
return false;
|
86
|
+
}
|
87
|
+
} else {
|
88
|
+
return $element;
|
89
|
+
}
|
90
|
+
});
|
134
91
|
},
|
135
92
|
|
136
|
-
invalidClass: "invalid-field",
|
137
93
|
messageClass: "error-message",
|
138
94
|
|
139
95
|
messages: {
|
140
|
-
allow: arrayMessage("Please enter one of: #{0}."),
|
141
|
-
always: "There was an error.",
|
142
|
-
different: "These values must all be different.",
|
143
|
-
disallow: arrayMessage("Please don't enter: #{0}."),
|
144
|
-
email: "Please enter a valid E-mail address.",
|
145
|
-
|
146
|
-
"float": minMaxMessage({
|
147
|
-
minAndMax: "Please enter a number from #{0} to #{1}.",
|
148
|
-
min: "Please enter a number no less than #{0}.",
|
149
|
-
max: "Please enter a number no greater than #{0}.",
|
150
|
-
invalid: "Please enter a number."
|
151
|
-
}),
|
152
|
-
|
153
|
-
"int": minMaxMessage({
|
154
|
-
minAndMax: "Please enter a number from #{0} to #{1}.",
|
155
|
-
min: "Please enter a number no less than #{0}.",
|
156
|
-
max: "Please enter a number no greater than #{0}.",
|
157
|
-
invalid: "Please enter a number."
|
158
|
-
}),
|
159
|
-
|
160
|
-
moneyUS: minMaxMessage({
|
161
|
-
minAndMax: "Please enter a dollar amount from #{0} to #{1}.",
|
162
|
-
min: "Please enter a dollar amount no less than #{0}.",
|
163
|
-
max: "Please enter a dollar amount no greater than #{0}.",
|
164
|
-
invalid: "Please enter a dollar amount."
|
165
|
-
}, function(x) { return x.toFixed(2); }),
|
166
|
-
|
167
|
-
never: "There was an error.",
|
168
|
-
oneRequired: "Specify at least one.",
|
169
|
-
phoneUS: "Please enter a valid phone number.",
|
170
|
-
required: "This field is required.",
|
171
|
-
same: "These values must all match.",
|
172
|
-
|
173
|
-
string: minMaxMessage({
|
174
|
-
minAndMax: "Please enter a string with length #{0} to #{1}.",
|
175
|
-
min: "Please enter a string with length at least #{0}.",
|
176
|
-
max: "Please enter a string with length no greater than #{0}."
|
177
|
-
}),
|
178
|
-
|
179
96
|
"undefined": "Please fix this field."
|
180
97
|
},
|
181
98
|
|
@@ -190,36 +107,605 @@
|
|
190
107
|
}
|
191
108
|
},
|
192
109
|
|
110
|
+
submitCallback: function() { return self.guard($(this)); },
|
193
111
|
tag: "span",
|
194
112
|
|
195
113
|
target: function(errorElement) {
|
196
114
|
var last = $(this).filter(":last");
|
197
115
|
|
198
|
-
if (last.is(":radio,:checkbox")) {
|
116
|
+
if (last.is(":radio,:checkbox") && last[0].nextSibling) {
|
199
117
|
last = $(last[0].nextSibling);
|
200
118
|
}
|
201
119
|
|
120
|
+
var next = last.next();
|
121
|
+
|
122
|
+
while (next.size() > 0 && next[0].isGuardError) {
|
123
|
+
last = next;
|
124
|
+
next = last.next();
|
125
|
+
}
|
126
|
+
|
202
127
|
errorElement.insertAfter(last);
|
203
128
|
return false;
|
204
129
|
}
|
205
130
|
};
|
131
|
+
|
132
|
+
/**
|
133
|
+
* @page Named Guards
|
134
|
+
* @section allow
|
135
|
+
* @since 1.0.0
|
136
|
+
*
|
137
|
+
* <p>
|
138
|
+
* Only values found in the given list are considered valid. Anything else triggers a failure.
|
139
|
+
* This guard <strong>requires</strong> an array parameter of the valid values.
|
140
|
+
* </p>
|
141
|
+
*
|
142
|
+
* <div class="example">
|
143
|
+
* <div class="display">
|
144
|
+
* <script>
|
145
|
+
* $.guard(".primary-color").using("allow", ["red", "yellow", "blue"]);
|
146
|
+
* </script>
|
147
|
+
*
|
148
|
+
* <p>
|
149
|
+
* <input class="primary-color" type="text" /><br />
|
150
|
+
* <small>Allowed values: red, yellow, blue</small>
|
151
|
+
* </p>
|
152
|
+
* </div>
|
153
|
+
* </div>
|
154
|
+
*/
|
155
|
+
this.name("allow").using(this.aggregate(this.isAllValid, this.isAllowed)).message(this.arrayMessage("Please enter one of: #{0}."));
|
156
|
+
|
157
|
+
/**
|
158
|
+
* @page Named Guards
|
159
|
+
* @section always
|
160
|
+
* @since 1.0.0
|
161
|
+
*
|
162
|
+
* <p>
|
163
|
+
* Always fail, no matter what. For this guard to pass, either the guard must be removed, or
|
164
|
+
* the element(s) guarded must be removed. No parameters are accepted.
|
165
|
+
* </p>
|
166
|
+
*
|
167
|
+
* <div class="example">
|
168
|
+
* <div class="display">
|
169
|
+
* <script>
|
170
|
+
* $.guard(".always").using("always");
|
171
|
+
* </script>
|
172
|
+
*
|
173
|
+
* <p>
|
174
|
+
* <input class="always" type="text" /><br />
|
175
|
+
* <small>Always fails, no matter what</small>
|
176
|
+
* </p>
|
177
|
+
* </div>
|
178
|
+
* </div>
|
179
|
+
*/
|
180
|
+
this.name("always").using(this.aggregate(this.isAllValid, this.always)).message("There was an error.");
|
181
|
+
|
182
|
+
/**
|
183
|
+
* @page Named Guards
|
184
|
+
* @section different
|
185
|
+
* @since 1.0.0
|
186
|
+
*
|
187
|
+
* <p>
|
188
|
+
* This is a grouped guard where every field must have a different value.
|
189
|
+
* </p>
|
190
|
+
*
|
191
|
+
* <div class="example">
|
192
|
+
* <div class="display">
|
193
|
+
* <script>
|
194
|
+
* $.guard(".unique").using("different");
|
195
|
+
* </script>
|
196
|
+
*
|
197
|
+
* <p>
|
198
|
+
* <input class="unique" type="text" value="Unique Required" /><br />
|
199
|
+
* <input class="unique" type="text" value="Unique Required" /><br />
|
200
|
+
* <small>Each value must be unique</small>
|
201
|
+
* </p>
|
202
|
+
* </div>
|
203
|
+
* </div>
|
204
|
+
*/
|
205
|
+
this.name("different").grouped().using(this.aggregate(this.passThrough, this.isDifferent)).message("These values must all be different.");
|
206
|
+
|
207
|
+
/**
|
208
|
+
* @page Named Guards
|
209
|
+
* @section disallow
|
210
|
+
* @since 1.0.0
|
211
|
+
*
|
212
|
+
* <p>
|
213
|
+
* Guard against specific values. This guard <strong>requires</strong> an array parameter
|
214
|
+
* of the invalid values.
|
215
|
+
* </p>
|
216
|
+
*
|
217
|
+
* <div class="example">
|
218
|
+
* <div class="display">
|
219
|
+
* <script>
|
220
|
+
* $.guard(".not-primary-color").using("disallow", ["red", "yellow", "blue"]);
|
221
|
+
* </script>
|
222
|
+
*
|
223
|
+
* <p>
|
224
|
+
* <input class="not-primary-color" type="text" value="red" /><br />
|
225
|
+
* <small>Disallowed values: red, yellow, blue</small>
|
226
|
+
* </p>
|
227
|
+
* </div>
|
228
|
+
* </div>
|
229
|
+
*/
|
230
|
+
this.name("disallow").using(this.aggregate(this.isAllValid, this.isDisallowed)).message(this.arrayMessage("Please don't enter: #{0}."));
|
231
|
+
|
232
|
+
/**
|
233
|
+
* @page Named Guards
|
234
|
+
* @section email
|
235
|
+
* @since 1.0.0
|
236
|
+
*
|
237
|
+
* <p>
|
238
|
+
* Guard for a valid email address. An empty value is ignored, so only once a value exists will
|
239
|
+
* this guard start checking for an email address. An optional argument of
|
240
|
+
* <code>{ allowDisplay: true }</code> is allowed that may specify whether display emails of the
|
241
|
+
* form <code>John Doe <john@example.com></code> are allowed.
|
242
|
+
* </p>
|
243
|
+
*
|
244
|
+
* <div class="example">
|
245
|
+
* <div class="display">
|
246
|
+
* <script>
|
247
|
+
* $.guard(".email1").using("email");
|
248
|
+
* $.guard(".email2").using("email", { allowDisplay: true });
|
249
|
+
* </script>
|
250
|
+
*
|
251
|
+
* <p>
|
252
|
+
* <input class="email1" type="text" value="invalid" /><br />
|
253
|
+
* <small>Email address of the form "john@example.com"</small>
|
254
|
+
* </p>
|
255
|
+
*
|
256
|
+
* <p>
|
257
|
+
* <input class="email2" type="text" value="Still <invalid>" /><br />
|
258
|
+
* <small>Email address of the form "John Doe <john@example.com>"</small>
|
259
|
+
* </p>
|
260
|
+
* </div>
|
261
|
+
* </div>
|
262
|
+
*/
|
263
|
+
this.name("email").using(this.aggregate(this.isAllValid, this.isValidEmail)).message("Please enter a valid E-mail address.");
|
264
|
+
|
265
|
+
/**
|
266
|
+
* @page Named Guards
|
267
|
+
* @section float
|
268
|
+
* @since 1.0.0
|
269
|
+
*
|
270
|
+
* <p>
|
271
|
+
* Guard for a floating point number. Optionally, an object parameter may be passed with
|
272
|
+
* <code>min</code> and/or <code>max</code>. Min will restrict the minimum value, while
|
273
|
+
* max restricts the maximum. An empty value is considered valid.
|
274
|
+
* </p>
|
275
|
+
*
|
276
|
+
* <div class="example">
|
277
|
+
* <div class="display">
|
278
|
+
* <script>
|
279
|
+
* $.guard(".float1").using("float");
|
280
|
+
* $.guard(".float2").using("float", { min: -5.5 });
|
281
|
+
* $.guard(".float3").using("float", { max: 42.0 });
|
282
|
+
* $.guard(".float4").using("float", { min: 0.0, max: 10.0 });
|
283
|
+
* </script>
|
284
|
+
*
|
285
|
+
* <p>
|
286
|
+
* <input class="float1" type="text" value="not valid" /><br />
|
287
|
+
* <small>A number of any value</small>
|
288
|
+
* </p>
|
289
|
+
*
|
290
|
+
* <p>
|
291
|
+
* <input class="float2" type="text" value="-10.5" /><br />
|
292
|
+
* <small>A number no smaller than -5.5</small>
|
293
|
+
* </p>
|
294
|
+
*
|
295
|
+
* <p>
|
296
|
+
* <input class="float3" type="text" value="64.32" /><br />
|
297
|
+
* <small>A number no bigger than 42</small>
|
298
|
+
* </p>
|
299
|
+
*
|
300
|
+
* <p>
|
301
|
+
* <input class="float4" type="text" value="11" /><br />
|
302
|
+
* <small>A number from 0 to 10</small>
|
303
|
+
* </p>
|
304
|
+
* </div>
|
305
|
+
* </div>
|
306
|
+
*/
|
307
|
+
this.name("float").using(this.aggregate(this.isAllValid, this.isValidFloat)).message(this.minMaxMessage({
|
308
|
+
minAndMax: "Please enter a number from #{0} to #{1}.",
|
309
|
+
min: "Please enter a number no less than #{0}.",
|
310
|
+
max: "Please enter a number no greater than #{0}.",
|
311
|
+
invalid: "Please enter a number."
|
312
|
+
}));
|
313
|
+
|
314
|
+
/**
|
315
|
+
* @page Named Guards
|
316
|
+
* @section int
|
317
|
+
* @since 1.0.0
|
318
|
+
*
|
319
|
+
* <p>
|
320
|
+
* Guard for an integer number. Optionally, an object parameter may be passed with
|
321
|
+
* <code>min</code> and/or <code>max</code>. Min will restrict the minimum value, while
|
322
|
+
* max restricts the maximum. An empty value is considered valid.
|
323
|
+
* </p>
|
324
|
+
*
|
325
|
+
* <div class="example">
|
326
|
+
* <div class="display">
|
327
|
+
* <script>
|
328
|
+
* $.guard(".int1").using("int");
|
329
|
+
* $.guard(".int2").using("int", { min: -5 });
|
330
|
+
* $.guard(".int3").using("int", { max: 42 });
|
331
|
+
* $.guard(".int4").using("int", { min: 0, max: 10 });
|
332
|
+
* </script>
|
333
|
+
*
|
334
|
+
* <p>
|
335
|
+
* <input class="int1" type="text" value="not valid" /><br />
|
336
|
+
* <small>An integer of any value</small>
|
337
|
+
* </p>
|
338
|
+
*
|
339
|
+
* <p>
|
340
|
+
* <input class="int2" type="text" value="-10.5" /><br />
|
341
|
+
* <small>An integer no smaller than -5</small>
|
342
|
+
* </p>
|
343
|
+
*
|
344
|
+
* <p>
|
345
|
+
* <input class="int3" type="text" value="64.32" /><br />
|
346
|
+
* <small>An integer no bigger than 42</small>
|
347
|
+
* </p>
|
348
|
+
*
|
349
|
+
* <p>
|
350
|
+
* <input class="int4" type="text" value="11" /><br />
|
351
|
+
* <small>An integer from 0 to 10</small>
|
352
|
+
* </p>
|
353
|
+
* </div>
|
354
|
+
* </div>
|
355
|
+
*/
|
356
|
+
this.name("int").using(this.aggregate(this.isAllValid, this.isValidInt)).message(this.minMaxMessage({
|
357
|
+
minAndMax: "Please enter a number from #{0} to #{1}.",
|
358
|
+
min: "Please enter a number no less than #{0}.",
|
359
|
+
max: "Please enter a number no greater than #{0}.",
|
360
|
+
invalid: "Please enter a number."
|
361
|
+
}));
|
362
|
+
|
363
|
+
/**
|
364
|
+
* @page Named Guards
|
365
|
+
* @section moneyUS
|
366
|
+
* @since 1.0.0
|
367
|
+
*
|
368
|
+
* <p>
|
369
|
+
* Guard for a US dollar amount. Optionally, an object parameter may be passed with
|
370
|
+
* <code>min</code> and/or <code>max</code>. Min will restrict the minimum value, while
|
371
|
+
* max restricts the maximum. An empty value is considered valid.
|
372
|
+
* </p>
|
373
|
+
*
|
374
|
+
* <div class="example">
|
375
|
+
* <div class="display">
|
376
|
+
* <script>
|
377
|
+
* $.guard(".money1").using("moneyUS");
|
378
|
+
* $.guard(".money2").using("moneyUS", { min: -5.50 });
|
379
|
+
* $.guard(".money3").using("moneyUS", { max: 42.02 });
|
380
|
+
* $.guard(".money4").using("moneyUS", { min: 0, max: 10 });
|
381
|
+
* </script>
|
382
|
+
*
|
383
|
+
* <p>
|
384
|
+
* <input class="money1" type="text" value="not valid" /><br />
|
385
|
+
* <small>US money of any value</small>
|
386
|
+
* </p>
|
387
|
+
*
|
388
|
+
* <p>
|
389
|
+
* <input class="money2" type="text" value="-$10.55" /><br />
|
390
|
+
* <small>US money no smaller than -$5.50</small>
|
391
|
+
* </p>
|
392
|
+
*
|
393
|
+
* <p>
|
394
|
+
* <input class="money3" type="text" value="$64.32" /><br />
|
395
|
+
* <small>US money no bigger than $42.02</small>
|
396
|
+
* </p>
|
397
|
+
*
|
398
|
+
* <p>
|
399
|
+
* <input class="money4" type="text" value="$11" /><br />
|
400
|
+
* <small>US money from $0 to $10</small>
|
401
|
+
* </p>
|
402
|
+
* </div>
|
403
|
+
* </div>
|
404
|
+
*/
|
405
|
+
this.name("moneyUS").using(this.aggregate(this.isAllValid, this.isValidMoneyUS)).message(this.minMaxMessage({
|
406
|
+
minAndMax: "Please enter a dollar amount from #{0} to #{1}.",
|
407
|
+
min: "Please enter a dollar amount no less than #{0}.",
|
408
|
+
max: "Please enter a dollar amount no greater than #{0}.",
|
409
|
+
invalid: "Please enter a dollar amount."
|
410
|
+
}, function(x) { return x.toFixed(2); }));
|
411
|
+
|
412
|
+
/**
|
413
|
+
* @page Named Guards
|
414
|
+
* @section never
|
415
|
+
* @since 1.0.0
|
416
|
+
*
|
417
|
+
* <p>
|
418
|
+
* Never fail, no matter what. For this guard to fail, it must be manually triggered via
|
419
|
+
* <a href="guard_type.html#triggerError"><code>guard.triggerError(selector)</code></a>.
|
420
|
+
* This guard can be useful for marking a field as having an error immediately when the page
|
421
|
+
* loads (such as for a server detected error).
|
422
|
+
* </p>
|
423
|
+
*
|
424
|
+
* <div class="example">
|
425
|
+
* <div class="display">
|
426
|
+
* <script>
|
427
|
+
* var guard = $.guard(".never").using("never");
|
428
|
+
* $(function() { guard.triggerError(".never"); });
|
429
|
+
* </script>
|
430
|
+
*
|
431
|
+
* <p>
|
432
|
+
* <input class="never" type="text" /><br />
|
433
|
+
* <small>Never fails, except manually</small>
|
434
|
+
* </p>
|
435
|
+
* </div>
|
436
|
+
* </div>
|
437
|
+
*/
|
438
|
+
this.name("never").using(this.aggregate(this.isAllValid, this.never)).message("There was an error.");
|
439
|
+
|
440
|
+
/**
|
441
|
+
* @page Named Guards
|
442
|
+
* @section oneRequired
|
443
|
+
* @since 1.0.0
|
444
|
+
*
|
445
|
+
* <p>
|
446
|
+
* This is a grouped guard where a single field of all the selected fields must have a value.
|
447
|
+
* </p>
|
448
|
+
*
|
449
|
+
* <div class="example">
|
450
|
+
* <div class="display">
|
451
|
+
* <script>
|
452
|
+
* $.guard(".oneRequired").using("oneRequired");
|
453
|
+
* </script>
|
454
|
+
*
|
455
|
+
* <p>
|
456
|
+
* <input class="oneRequired" type="text" value="" /><br />
|
457
|
+
* <input class="oneRequired" type="text" value="" /><br />
|
458
|
+
* <small>One value is required</small>
|
459
|
+
* </p>
|
460
|
+
* </div>
|
461
|
+
* </div>
|
462
|
+
*/
|
463
|
+
this.name("oneRequired").grouped().using(this.aggregate(this.isAnyValid, this.isPresent)).message("Specify at least one.");
|
464
|
+
|
465
|
+
/**
|
466
|
+
* @page Named Guards
|
467
|
+
* @section phoneUS
|
468
|
+
* @since 1.0.0
|
469
|
+
*
|
470
|
+
* <p>
|
471
|
+
* The guarded field is considered valid if no value is given, or if the value given appears
|
472
|
+
* to be a valid US phone number. The number must include an area code. Whitespace is ignored.
|
473
|
+
* </p>
|
474
|
+
*
|
475
|
+
* <div class="example">
|
476
|
+
* <div class="display">
|
477
|
+
* <script>
|
478
|
+
* $.guard(".phone").using("phoneUS");
|
479
|
+
* </script>
|
480
|
+
*
|
481
|
+
* <p>
|
482
|
+
* <input class="phone" type="text" value="555-1234" /><br />
|
483
|
+
* <small>A valid US phone number like (555) 555-1234</small>
|
484
|
+
* </p>
|
485
|
+
* </div>
|
486
|
+
* </div>
|
487
|
+
*/
|
488
|
+
this.name("phoneUS").using(this.aggregate(this.isAllValid, this.isValidPhoneUS)).message("Please enter a valid phone number.");
|
489
|
+
|
490
|
+
/**
|
491
|
+
* @page Named Guards
|
492
|
+
* @section required
|
493
|
+
* @since 1.0.0
|
494
|
+
*
|
495
|
+
* <p>
|
496
|
+
* These guarded fields must have a value to pass. Only whitespace is not considered a value.
|
497
|
+
* If no named or custom guard is defined, this is the default guard used.
|
498
|
+
* </p>
|
499
|
+
*
|
500
|
+
* <div class="example">
|
501
|
+
* <div class="display">
|
502
|
+
* <script>
|
503
|
+
* $.guard(".required1").using("required");
|
504
|
+
* $.guard(".required2");
|
505
|
+
* </script>
|
506
|
+
*
|
507
|
+
* <p>
|
508
|
+
* <input class="required1" type="text" /><br />
|
509
|
+
* <small>A value is required</small>
|
510
|
+
* </p>
|
511
|
+
*
|
512
|
+
* <p>
|
513
|
+
* <input class="required2" type="text" /><br />
|
514
|
+
* <small>A value is required</small>
|
515
|
+
* </p>
|
516
|
+
* </div>
|
517
|
+
* </div>
|
518
|
+
*/
|
519
|
+
this.name("required").using(this.aggregate(this.isAllValid, this.isPresent)).message("This field is required.");
|
520
|
+
|
521
|
+
/**
|
522
|
+
* @page Named Guards
|
523
|
+
* @section same
|
524
|
+
* @since 1.0.0
|
525
|
+
*
|
526
|
+
* <p>
|
527
|
+
* This is a grouped guard where every field must have the same value. For example, this guard can
|
528
|
+
* be used to implement a password confirmation field.
|
529
|
+
* </p>
|
530
|
+
*
|
531
|
+
* <div class="example">
|
532
|
+
* <div class="display">
|
533
|
+
* <script>
|
534
|
+
* $.guard(".same").using("same");
|
535
|
+
* </script>
|
536
|
+
*
|
537
|
+
* <p>
|
538
|
+
* <input class="same" type="text" value="Same Required" /><br />
|
539
|
+
* <input class="same" type="text" value="The Same Required" /><br />
|
540
|
+
* <small>Each value must be the same</small>
|
541
|
+
* </p>
|
542
|
+
* </div>
|
543
|
+
* </div>
|
544
|
+
*/
|
545
|
+
this.name("same").grouped().using(this.aggregate(this.passThrough, this.isSame)).message("These values must all match.");
|
546
|
+
|
547
|
+
/**
|
548
|
+
* @page Named Guards
|
549
|
+
* @section string
|
550
|
+
* @since 1.0.0
|
551
|
+
*
|
552
|
+
* <p>
|
553
|
+
* Validate the length of the string provided. This requires an object parameter with
|
554
|
+
* <code>min</code> and/or <code>max</code>. Min will restrict the minimum length, while
|
555
|
+
* max restricts the maximum length.
|
556
|
+
* </p>
|
557
|
+
*
|
558
|
+
* <div class="example">
|
559
|
+
* <div class="display">
|
560
|
+
* <script>
|
561
|
+
* $.guard(".string1").using("string", { min: 3 });
|
562
|
+
* $.guard(".string2").using("string", { max: 7 });
|
563
|
+
* $.guard(".string3").using("string", { min: 2, max: 4 });
|
564
|
+
* </script>
|
565
|
+
*
|
566
|
+
* <p>
|
567
|
+
* <input class="string1" type="text" value="I" /><br />
|
568
|
+
* <small>A string with at lease 3 characters</small>
|
569
|
+
* </p>
|
570
|
+
*
|
571
|
+
* <p>
|
572
|
+
* <input class="string2" type="text" value="Hello World" /><br />
|
573
|
+
* <small>A string with no more than 7 characters</small>
|
574
|
+
* </p>
|
575
|
+
*
|
576
|
+
* <p>
|
577
|
+
* <input class="string3" type="text" value="Goodnight Moon" /><br />
|
578
|
+
* <small>A string with at least 2 characters and no more than 5</small>
|
579
|
+
* </p>
|
580
|
+
* </div>
|
581
|
+
* </div>
|
582
|
+
*/
|
583
|
+
this.name("string").using(this.aggregate(this.isAllValid, this.isValidString)).message(this.minMaxMessage({
|
584
|
+
minAndMax: "Please enter a string with length #{0} to #{1}.",
|
585
|
+
min: "Please enter a string with length at least #{0}.",
|
586
|
+
max: "Please enter a string with length no greater than #{0}."
|
587
|
+
}));
|
206
588
|
};
|
207
589
|
|
208
|
-
|
590
|
+
/**
|
591
|
+
* @page Guards Type
|
592
|
+
* @section version
|
593
|
+
* @signature jQuery.guards.version
|
594
|
+
* @since 1.0.0
|
595
|
+
*
|
596
|
+
* <p>
|
597
|
+
* This version of guards.js library as a string, like <code>"1.0.0"</code>.
|
598
|
+
* </p>
|
599
|
+
*/
|
600
|
+
$.Guards.prototype.version = "1.0.0";
|
601
|
+
|
602
|
+
$.Guards.prototype.parentContext = function(element) {
|
603
|
+
var $element = $(element);
|
604
|
+
var context = $element.parents("form:first");
|
209
605
|
|
210
|
-
|
211
|
-
|
212
|
-
|
606
|
+
if (context.size() == 0) {
|
607
|
+
context = $element.parents("*:last");
|
608
|
+
}
|
213
609
|
|
214
|
-
|
215
|
-
|
216
|
-
var JQUERY_CONSTRUCTOR = jQuery;
|
610
|
+
return context;
|
611
|
+
};
|
217
612
|
|
218
|
-
|
219
|
-
|
220
|
-
|
613
|
+
/**
|
614
|
+
* @page Guards Type
|
615
|
+
* @section name
|
616
|
+
* @signature jQuery.guards.name(guardName)
|
617
|
+
* @since 1.0.0
|
618
|
+
*
|
619
|
+
* <p>
|
620
|
+
* Name a guard. This behaves the same way as
|
621
|
+
* <a href="global_functions.html#guard"><code>$.guard(selector)</code></a>, except it uses
|
622
|
+
* the parameter to define a named guard with the given name, instead of defining a new
|
623
|
+
* guard affecting the given selector. Any attributes applied to it will be passed on to
|
624
|
+
* any guards that utilize this named guard. A named guard may be utilized by passing the
|
625
|
+
* name on to the <a href="guard_type.html#using"><code>using</code></a> method.
|
626
|
+
* </p>
|
627
|
+
*
|
628
|
+
* <div class="example">
|
629
|
+
* <div class="display">
|
630
|
+
* <script>
|
631
|
+
* $.guards.name("notTest").using(function(value, element) {
|
632
|
+
* return value !== "test";
|
633
|
+
* }).message("Must not be test.");
|
634
|
+
* $.guard(".named").using("notTest");
|
635
|
+
* </script>
|
636
|
+
*
|
637
|
+
* <p>
|
638
|
+
* <input class="named" type="text" value="test" /><br />
|
639
|
+
* <small>Anything except 'test'</small>
|
640
|
+
* </p>
|
641
|
+
* </div>
|
642
|
+
* </div>
|
643
|
+
*/
|
644
|
+
$.Guards.prototype.name = function(name) {
|
645
|
+
var guard = new $.Guard(null, this, true);
|
646
|
+
this.named[name] = guard;
|
647
|
+
return guard;
|
648
|
+
};
|
649
|
+
|
650
|
+
$.Guards.prototype.aggregate = function(aggregator, validator) {
|
651
|
+
var self = this;
|
652
|
+
|
653
|
+
var result = function() {
|
654
|
+
var args = $.makeArray(arguments);
|
655
|
+
|
656
|
+
return function(value) {
|
657
|
+
return aggregator.call(self, value, function(v) {
|
658
|
+
return validator.apply(self, $.merge([v], args));
|
659
|
+
});
|
660
|
+
};
|
221
661
|
};
|
222
|
-
|
662
|
+
|
663
|
+
result.acceptsArguments = true;
|
664
|
+
return result;
|
665
|
+
};
|
666
|
+
|
667
|
+
$.Guards.prototype.arrayMessage = function(formatting) {
|
668
|
+
var self = this;
|
669
|
+
|
670
|
+
return function(array) {
|
671
|
+
return self.format(formatting, $.map(array, function(x) { return $.trim("" + x); }).join(", "));
|
672
|
+
};
|
673
|
+
};
|
674
|
+
|
675
|
+
$.Guards.prototype.minMaxMessage = function(formatting, minMaxFormat) {
|
676
|
+
var self = this;
|
677
|
+
|
678
|
+
return function(options) {
|
679
|
+
if (self.isNullOrUndefined(options)) {
|
680
|
+
options = {};
|
681
|
+
}
|
682
|
+
|
683
|
+
if (!$.isFunction(minMaxFormat)) {
|
684
|
+
minMaxFormat = function(x) { return x; };
|
685
|
+
}
|
686
|
+
|
687
|
+
var minDefined = !self.isNullOrUndefined(options.min);
|
688
|
+
var maxDefined = !self.isNullOrUndefined(options.max);
|
689
|
+
|
690
|
+
if (minDefined && maxDefined) {
|
691
|
+
return self.format(formatting.minAndMax, minMaxFormat(options.min), minMaxFormat(options.max));
|
692
|
+
}
|
693
|
+
|
694
|
+
if (minDefined) {
|
695
|
+
return self.format(formatting.min, minMaxFormat(options.min));
|
696
|
+
}
|
697
|
+
|
698
|
+
if (maxDefined) {
|
699
|
+
return self.format(formatting.max, minMaxFormat(options.max));
|
700
|
+
}
|
701
|
+
|
702
|
+
if (formatting.invalid) {
|
703
|
+
return formatting.invalid;
|
704
|
+
}
|
705
|
+
|
706
|
+
return self.defaults.messages["undefined"];
|
707
|
+
};
|
708
|
+
};
|
223
709
|
|
224
710
|
// Alias for console.log, but check that such a thing exists.
|
225
711
|
$.Guards.prototype.log = function(message) {
|
@@ -242,39 +728,40 @@
|
|
242
728
|
}
|
243
729
|
};
|
244
730
|
|
731
|
+
// Utility method to remove live events, but works against any
|
732
|
+
// jQuery version that supports live events.
|
733
|
+
$.Guards.prototype.off = function(selector, event, callback) {
|
734
|
+
if ($.fn.off) {
|
735
|
+
$(document).off(event, selector, callback);
|
736
|
+
} else if ($.fn.undelegate) {
|
737
|
+
$(document).undelegate(selector, event, callback);
|
738
|
+
} else if ($.fn.die) {
|
739
|
+
$(selector).die(event, callback);
|
740
|
+
} else {
|
741
|
+
this.log("Could not unbind live handlers, probably because jQuery is too old.");
|
742
|
+
}
|
743
|
+
};
|
744
|
+
|
245
745
|
// Implementation of $.enableGuards(selector);
|
246
746
|
$.Guards.prototype.enableGuards = function(selector) {
|
247
|
-
|
747
|
+
this.on(selector, "submit", this.defaults.submitCallback);
|
748
|
+
};
|
248
749
|
|
249
|
-
|
250
|
-
|
251
|
-
|
750
|
+
// Implementation of $.disableGuards(selector);
|
751
|
+
$.Guards.prototype.disableGuards = function(selector) {
|
752
|
+
this.off(selector, "submit", this.defaults.submitCallback);
|
252
753
|
};
|
253
754
|
|
254
755
|
// Implementation of $.liveGuard(selector);
|
255
756
|
$.Guards.prototype.liveGuard = function(selector) {
|
256
|
-
var self = this;
|
257
757
|
this.enableGuards(selector);
|
758
|
+
this.on(selector, "change blur", this.defaults.liveCallback);
|
759
|
+
};
|
258
760
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
return;
|
264
|
-
}
|
265
|
-
|
266
|
-
self.applyGuards(function(guard) {
|
267
|
-
if (guard.isGrouped()) {
|
268
|
-
if (guard.appliesTo($element)) {
|
269
|
-
return $element.parents("form:first").find(":guardable");
|
270
|
-
} else {
|
271
|
-
return false;
|
272
|
-
}
|
273
|
-
} else {
|
274
|
-
return $element;
|
275
|
-
}
|
276
|
-
});
|
277
|
-
});
|
761
|
+
// Implementation of $.disableLiveGuard(selector);
|
762
|
+
$.Guards.prototype.disableLiveGuard = function(selector) {
|
763
|
+
this.disableGuards(selector);
|
764
|
+
this.off(selector, "change blur", this.defaults.liveCallback);
|
278
765
|
};
|
279
766
|
|
280
767
|
/**
|
@@ -318,44 +805,55 @@
|
|
318
805
|
};
|
319
806
|
|
320
807
|
/**
|
321
|
-
*
|
322
|
-
*
|
323
|
-
*
|
324
|
-
*
|
325
|
-
*
|
326
|
-
*
|
327
|
-
*
|
328
|
-
*
|
329
|
-
*
|
330
|
-
*
|
331
|
-
*
|
332
|
-
*
|
333
|
-
*
|
334
|
-
*
|
335
|
-
*
|
336
|
-
*
|
337
|
-
*
|
338
|
-
*
|
339
|
-
*
|
340
|
-
*
|
341
|
-
*
|
342
|
-
*
|
343
|
-
*
|
344
|
-
*
|
345
|
-
*
|
346
|
-
*
|
347
|
-
*
|
348
|
-
*
|
808
|
+
* @page Guards Type
|
809
|
+
* @section style
|
810
|
+
* @signature jQuery.guards.style([customStyling])
|
811
|
+
* @since 1.0.0
|
812
|
+
*
|
813
|
+
* <p>
|
814
|
+
* Insert a style element to the document head that will style guard errors and invalid fields.
|
815
|
+
* This will default to styling <code>.invalid-field</code> with a background color of
|
816
|
+
* <code>#ffff66</code> and <code>.error-message</code> with a color of <code>#ff0000</code>
|
817
|
+
* and a left margin of <code>10px</code>.
|
818
|
+
* </p>
|
819
|
+
*
|
820
|
+
* <p>
|
821
|
+
* There are 2 optional arguments for this method. The first is an optional css scope to restrict
|
822
|
+
* the styling affects with. The second is an object expected to contain a <code>field</code>
|
823
|
+
* and/or <code>message</code> property with css styles desired for that aspect of the styling.
|
824
|
+
* The <code>field</code> property will add styling for invalid fields while the <code>message</code>
|
825
|
+
* property will add styling for error messages. The properties of these objects may contain any
|
826
|
+
* key that is a valid css attribute, with an appropriate value.
|
827
|
+
* </p>
|
828
|
+
*
|
829
|
+
* <div class="example">
|
830
|
+
* <div class="display">
|
831
|
+
* <script>
|
832
|
+
* $.guards.style("#styled-fields", {
|
833
|
+
* message: {
|
834
|
+
* "color": "#ee0000",
|
835
|
+
* "font-weight": "bold"
|
836
|
+
* },
|
837
|
+
* field: {
|
838
|
+
* "background-color": "#ffe099"
|
839
|
+
* }
|
840
|
+
* });
|
841
|
+
*
|
842
|
+
* $.guard(".styled-field").using("required");
|
843
|
+
* </script>
|
844
|
+
*
|
845
|
+
* <p id="styled-fields">
|
846
|
+
* <input class="styled-field" type="text" />
|
847
|
+
* </p>
|
848
|
+
* </div>
|
849
|
+
* </div>
|
349
850
|
*/
|
350
851
|
$.Guards.prototype.style = function() {
|
351
852
|
$("head").append(this.styleHtml.apply(this, arguments));
|
352
853
|
};
|
353
854
|
|
354
|
-
|
355
|
-
|
356
|
-
* $.guards.style() function. The documentation for that function
|
357
|
-
* applies to this as well.
|
358
|
-
*/
|
855
|
+
// Retrieve the style html as a string to use for the $.guards.style() function.
|
856
|
+
// The documentation for that function applies to this as well.
|
359
857
|
$.Guards.prototype.styleHtml = function() {
|
360
858
|
var fieldStyle = {};
|
361
859
|
var messageStyle = {};
|
@@ -371,13 +869,13 @@
|
|
371
869
|
messageStyle = this.defaults.style.message;
|
372
870
|
}
|
373
871
|
|
374
|
-
if (arguments.length
|
375
|
-
if (typeof(arguments[0])
|
872
|
+
if (arguments.length === 1) {
|
873
|
+
if (typeof(arguments[0]) === "string") {
|
376
874
|
selectorScope = arguments[0];
|
377
875
|
} else {
|
378
876
|
styles = arguments[0];
|
379
877
|
}
|
380
|
-
} else if (arguments.length
|
878
|
+
} else if (arguments.length === 2) {
|
381
879
|
selectorScope = arguments[0];
|
382
880
|
styles = arguments[1];
|
383
881
|
}
|
@@ -419,7 +917,7 @@
|
|
419
917
|
* This guard test method is intended to always fail, thus it
|
420
918
|
* returns false no matter what.
|
421
919
|
*/
|
422
|
-
$.Guards.prototype.always = function(
|
920
|
+
$.Guards.prototype.always = function() {
|
423
921
|
return false;
|
424
922
|
};
|
425
923
|
|
@@ -431,7 +929,7 @@
|
|
431
929
|
*/
|
432
930
|
$.Guards.prototype.isAllowed = function(value, allowed) {
|
433
931
|
value = $.trim(value);
|
434
|
-
return $.inArray(value, $.map(allowed, function(x
|
932
|
+
return $.inArray(value, $.map(allowed, function(x) { return $.trim("" + x); })) !== -1;
|
435
933
|
};
|
436
934
|
|
437
935
|
/**
|
@@ -444,7 +942,7 @@
|
|
444
942
|
* Example: $.guards.isAllValid(true, function(x) { return x; }); // true
|
445
943
|
*/
|
446
944
|
$.Guards.prototype.isAllValid = function(values, fn) {
|
447
|
-
if (
|
945
|
+
if ($.isArray(values)) {
|
448
946
|
var result = true;
|
449
947
|
|
450
948
|
$.each(values, function(i, x) {
|
@@ -466,11 +964,11 @@
|
|
466
964
|
* values is not an array, the result of calling the given fn on
|
467
965
|
* that value is returned directly.
|
468
966
|
*
|
469
|
-
* Example: $.guards.
|
470
|
-
* Example: $.guards.
|
967
|
+
* Example: $.guards.isAnyValid([false, false, true], function(x) { return x; }); // true
|
968
|
+
* Example: $.guards.isAnyValid(false, function(x) { return x; }); // false
|
471
969
|
*/
|
472
970
|
$.Guards.prototype.isAnyValid = function(values, fn) {
|
473
|
-
if (
|
971
|
+
if ($.isArray(values)) {
|
474
972
|
var result = false;
|
475
973
|
|
476
974
|
$.each(values, function(i, x) {
|
@@ -491,7 +989,7 @@
|
|
491
989
|
* or a string of just spaces.
|
492
990
|
*/
|
493
991
|
$.Guards.prototype.isBlank = function(value) {
|
494
|
-
return this.isNullOrUndefined(value) || $.trim(value)
|
992
|
+
return this.isNullOrUndefined(value) || $.trim(value) === "";
|
495
993
|
};
|
496
994
|
|
497
995
|
/**
|
@@ -553,7 +1051,7 @@
|
|
553
1051
|
var result = true;
|
554
1052
|
|
555
1053
|
$.each(values, function(i, x) {
|
556
|
-
if (x
|
1054
|
+
if (x !== value) {
|
557
1055
|
result = false;
|
558
1056
|
return false;
|
559
1057
|
}
|
@@ -585,7 +1083,7 @@
|
|
585
1083
|
$.Guards.prototype.isValidInt = function(value, options) {
|
586
1084
|
value = $.trim(value);
|
587
1085
|
|
588
|
-
if (value
|
1086
|
+
if (value === "") {
|
589
1087
|
return true;
|
590
1088
|
}
|
591
1089
|
|
@@ -605,7 +1103,7 @@
|
|
605
1103
|
$.Guards.prototype.isValidFloat = function(value, options) {
|
606
1104
|
value = $.trim(value);
|
607
1105
|
|
608
|
-
if (value
|
1106
|
+
if (value === "") {
|
609
1107
|
return true;
|
610
1108
|
}
|
611
1109
|
|
@@ -625,7 +1123,7 @@
|
|
625
1123
|
$.Guards.prototype.isValidMoneyUS = function(value, options) {
|
626
1124
|
value = $.trim(value);
|
627
1125
|
|
628
|
-
if (value
|
1126
|
+
if (value === "") {
|
629
1127
|
return true;
|
630
1128
|
}
|
631
1129
|
|
@@ -662,14 +1160,14 @@
|
|
662
1160
|
*/
|
663
1161
|
$.Guards.prototype.isValidEmail = function(value, options) {
|
664
1162
|
if (options && options.allowDisplay) {
|
665
|
-
var result =
|
1163
|
+
var result = /.*<([^>]+)>\s*$/.exec(value);
|
666
1164
|
|
667
1165
|
if (result) {
|
668
1166
|
value = result[1];
|
669
1167
|
}
|
670
1168
|
}
|
671
1169
|
|
672
|
-
return value
|
1170
|
+
return value === "" || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
|
673
1171
|
};
|
674
1172
|
|
675
1173
|
/**
|
@@ -677,7 +1175,7 @@
|
|
677
1175
|
*/
|
678
1176
|
$.Guards.prototype.isValidPhoneUS = function(value) {
|
679
1177
|
value = value.replace(/\s+/g, "");
|
680
|
-
return value
|
1178
|
+
return value === "" || value.length > 9 &&
|
681
1179
|
value.match(/^(1-?)?(\([2-9]\d{2}\)|[2-9]\d{2})-?[2-9]\d{2}-?\d{4}$/);
|
682
1180
|
};
|
683
1181
|
|
@@ -696,7 +1194,7 @@
|
|
696
1194
|
* returns true no matter what. It is intended to be used to set
|
697
1195
|
* up a guard that is triggered manually via triggerError().
|
698
1196
|
*/
|
699
|
-
$.Guards.prototype.never = function(
|
1197
|
+
$.Guards.prototype.never = function() {
|
700
1198
|
return true;
|
701
1199
|
};
|
702
1200
|
|
@@ -710,7 +1208,7 @@
|
|
710
1208
|
* Example: $.guards.passThrough(true, function(x) { return x[0]; }); // true
|
711
1209
|
*/
|
712
1210
|
$.Guards.prototype.passThrough = function(values, fn) {
|
713
|
-
if (
|
1211
|
+
if (!$.isArray(values)) {
|
714
1212
|
values = [values];
|
715
1213
|
}
|
716
1214
|
|
@@ -746,7 +1244,7 @@
|
|
746
1244
|
*/
|
747
1245
|
$.Guards.prototype.guard = function(form) {
|
748
1246
|
var fields = form.guardableFields().clearErrors();
|
749
|
-
var result = this.applyGuards(function(
|
1247
|
+
var result = this.applyGuards(function() { return fields; });
|
750
1248
|
fields.filter(":visible:has-error").eq(0).focus();
|
751
1249
|
return result;
|
752
1250
|
};
|
@@ -777,7 +1275,7 @@
|
|
777
1275
|
* will be applied if the field doesn't have an error yet.
|
778
1276
|
*/
|
779
1277
|
$.Guards.prototype.test = function(guard, fields) {
|
780
|
-
if (guard.
|
1278
|
+
if (guard.isGrouped()) {
|
781
1279
|
return guard.test(fields);
|
782
1280
|
}
|
783
1281
|
|
@@ -792,114 +1290,221 @@
|
|
792
1290
|
return result;
|
793
1291
|
};
|
794
1292
|
|
795
|
-
$.Guard = function(selector, guards) {
|
1293
|
+
$.Guard = function(selector, guards, named) {
|
1294
|
+
this._named = named;
|
796
1295
|
this._guards = guards || $.guards;
|
797
1296
|
this._selector = selector;
|
798
|
-
this.
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
1297
|
+
this._guard = null;
|
1298
|
+
|
1299
|
+
if (!named) {
|
1300
|
+
this.using(this._guards.defaults.guard);
|
1301
|
+
}
|
1302
|
+
};
|
1303
|
+
|
1304
|
+
$.Guard.prototype.cloneGuard = function(guard, args) {
|
1305
|
+
var self = this;
|
1306
|
+
var namedGuard = this._guards.named[guard];
|
1307
|
+
|
1308
|
+
if (this._guards.isNullOrUndefined(namedGuard)) {
|
1309
|
+
throw new Error("There is no named guard '" + guard + "'");
|
1310
|
+
}
|
1311
|
+
|
1312
|
+
var copyAttribute = function(attribute) {
|
1313
|
+
if (self[attribute] !== undefined || namedGuard[attribute] === undefined) {
|
1314
|
+
return;
|
1315
|
+
}
|
1316
|
+
|
1317
|
+
self[attribute] = namedGuard[attribute];
|
1318
|
+
};
|
1319
|
+
|
1320
|
+
copyAttribute("_grouped");
|
1321
|
+
copyAttribute("_tag");
|
1322
|
+
copyAttribute("_messageClass");
|
1323
|
+
copyAttribute("_invalidClass");
|
1324
|
+
copyAttribute("_target");
|
1325
|
+
copyAttribute("_precondition");
|
1326
|
+
this._guard = namedGuard._guard;
|
1327
|
+
this.name = guard;
|
1328
|
+
|
1329
|
+
if (this._guard.acceptsArguments) {
|
1330
|
+
this._guard = this._guard.apply(this._guards, args);
|
1331
|
+
}
|
1332
|
+
|
1333
|
+
if ($.isFunction(namedGuard._message)) {
|
1334
|
+
return this.message(namedGuard._message.apply(this._guards, args));
|
1335
|
+
} else {
|
1336
|
+
return this.message(namedGuard._message);
|
1337
|
+
}
|
804
1338
|
};
|
805
1339
|
|
806
1340
|
/**
|
807
|
-
* Guard
|
808
|
-
*
|
809
|
-
*
|
810
|
-
*
|
811
|
-
*
|
812
|
-
*
|
813
|
-
*
|
814
|
-
*
|
815
|
-
*
|
816
|
-
*
|
817
|
-
* the
|
818
|
-
*
|
819
|
-
*
|
820
|
-
*
|
821
|
-
*
|
822
|
-
*
|
823
|
-
*
|
824
|
-
* will be
|
825
|
-
*
|
826
|
-
*
|
827
|
-
*
|
828
|
-
*
|
829
|
-
*
|
1341
|
+
* @page Guard Type
|
1342
|
+
* @section using
|
1343
|
+
* @signature guard.using(name | customFunction)
|
1344
|
+
* @since 1.0.0
|
1345
|
+
*
|
1346
|
+
* <p>
|
1347
|
+
* Guard inputs with the specified name guard, or with a custom function. If the first argument
|
1348
|
+
* provided is a string, it must correspond to a named guard. This may be one of the
|
1349
|
+
* <a href="named_guards.html"><code>default named guards</code></a>, or a guard named via
|
1350
|
+
* <a href="guards_type.html#name"><code>$.guards.name(name)</code></a>. Additional arguments
|
1351
|
+
* may be given as options to the named guard. All attributes specified by the named guard
|
1352
|
+
* will be copied over when the <code>using</code> method is invoked.
|
1353
|
+
* </p>
|
1354
|
+
*
|
1355
|
+
* <p>
|
1356
|
+
* Alternatively, a function may be provided as the custom guard function. This function is invoked
|
1357
|
+
* when guards are being tested with the value of the element guarded, and the element being
|
1358
|
+
* guarded. If the guard is grouped, it will be an array of values with the corresponding array
|
1359
|
+
* of elements.
|
1360
|
+
* </p>
|
1361
|
+
*
|
1362
|
+
* <div class="example">
|
1363
|
+
* <div class="display">
|
1364
|
+
* <script>
|
1365
|
+
* $.guard(".using1").using("required");
|
1366
|
+
* $.guard(".using2").using(function(value, element) {
|
1367
|
+
* return value !== "invalid";
|
1368
|
+
* }).message("Custom guard.");
|
1369
|
+
* $.guard(".using3").grouped().using(function(values, elements) {
|
1370
|
+
* return $.inArray("test", values) >= 0;
|
1371
|
+
* }).message("One must be 'test'");
|
1372
|
+
* </script>
|
1373
|
+
*
|
1374
|
+
* <p>
|
1375
|
+
* <input class="using1" type="text" /><br />
|
1376
|
+
* <small>Required field</small>
|
1377
|
+
* </p>
|
1378
|
+
*
|
1379
|
+
* <p>
|
1380
|
+
* <input class="using2" type="text" value="invalid" /><br />
|
1381
|
+
* <small>Field must not be 'invalid'</small>
|
1382
|
+
* </p>
|
1383
|
+
*
|
1384
|
+
* <p>
|
1385
|
+
* <input class="using3" type="text" value="Something" /><br />
|
1386
|
+
* <input class="using3" type="text" value="Somewhere" /><br />
|
1387
|
+
* <small>One must be 'test'</small>
|
1388
|
+
* </p>
|
1389
|
+
* </div>
|
1390
|
+
* </div>
|
830
1391
|
*/
|
831
1392
|
$.Guard.prototype.using = function(guard) {
|
832
|
-
if (typeof(guard)
|
1393
|
+
if (typeof(guard) === "string") {
|
833
1394
|
var args = [];
|
834
1395
|
|
835
1396
|
if (arguments.length > 1) {
|
836
1397
|
args = $.makeArray(arguments).slice(1);
|
837
1398
|
}
|
838
1399
|
|
839
|
-
|
840
|
-
|
841
|
-
if (this._guards.isNullOrUndefined(fn)) {
|
842
|
-
throw new Error("There is no standard guard named '" + guard + "'");
|
843
|
-
}
|
844
|
-
|
845
|
-
this._guard = fn.apply(this._guards.defaults.guards, args);
|
846
|
-
var message = this._guards.defaults.messages[guard];
|
1400
|
+
return this.cloneGuard(guard, args);
|
1401
|
+
}
|
847
1402
|
|
848
|
-
|
849
|
-
|
850
|
-
|
1403
|
+
this._guard = guard;
|
1404
|
+
return this.message(this._guards.defaults.messages["undefined"]);
|
1405
|
+
};
|
851
1406
|
|
852
|
-
|
1407
|
+
$.Guard.prototype.getPrecondition = function() {
|
1408
|
+
if (this._precondition === undefined) {
|
1409
|
+
return this._guards.defaults.precondition;
|
853
1410
|
}
|
854
1411
|
|
855
|
-
this.
|
856
|
-
return this.message(this._guards.defaults.messages.undefined);
|
1412
|
+
return this._precondition;
|
857
1413
|
};
|
858
1414
|
|
859
1415
|
/**
|
860
|
-
*
|
861
|
-
*
|
862
|
-
*
|
863
|
-
*
|
864
|
-
*
|
865
|
-
*
|
866
|
-
*
|
867
|
-
*
|
868
|
-
*
|
869
|
-
*
|
870
|
-
*
|
871
|
-
*
|
872
|
-
*
|
873
|
-
*
|
874
|
-
*
|
875
|
-
*
|
876
|
-
*
|
1416
|
+
* @page Guard Type
|
1417
|
+
* @section precondition
|
1418
|
+
* @signature guard.precondition(preconditionFunction)
|
1419
|
+
* @since 1.0.0
|
1420
|
+
*
|
1421
|
+
* <p>
|
1422
|
+
* Specify a precondition for this guard. A parameter is required with the precondition
|
1423
|
+
* function. This function accepts the element and element value as the parameters, like
|
1424
|
+
* a custom guard function. The precondition is executed before the guard when any given
|
1425
|
+
* input is about to be guarded. If the precondition returns false explicitly, the guard
|
1426
|
+
* will not be executed and the field will be considered valid. Any other return value
|
1427
|
+
* means the precondition passed (even no return). If the guard is grouped, the parameters
|
1428
|
+
* will be the array of values and elements (like for a custom guard function).
|
1429
|
+
* </p>
|
1430
|
+
*
|
1431
|
+
* <div class="example">
|
1432
|
+
* <div class="display">
|
1433
|
+
* <script>
|
1434
|
+
* $.guard(".with-precondition").using("required").precondition(function(value, element) {
|
1435
|
+
* return $("#precondition-checkbox").is(":checked");
|
1436
|
+
* });
|
1437
|
+
* </script>
|
1438
|
+
*
|
1439
|
+
* <p>
|
1440
|
+
* <input type="checkbox" id="precondition-checkbox" checked="checked" />
|
1441
|
+
* <label for="precondition-checkbox">Guard this field</label><br />
|
1442
|
+
* <input class="with-precondition" type="text" /><br />
|
1443
|
+
* <small>Guarded with <code>required</code> if the checkbox is checked</small>
|
1444
|
+
* </p>
|
1445
|
+
* </div>
|
1446
|
+
* </div>
|
877
1447
|
*/
|
878
1448
|
$.Guard.prototype.precondition = function(fn) {
|
879
1449
|
this._precondition = fn;
|
880
1450
|
return this;
|
881
1451
|
};
|
882
1452
|
|
883
|
-
/**
|
884
|
-
* Return whether or not this guard is grouped.
|
885
|
-
*/
|
886
1453
|
$.Guard.prototype.isGrouped = function() {
|
1454
|
+
if (this._grouped === undefined) {
|
1455
|
+
return this._guards.defaults.grouped;
|
1456
|
+
}
|
1457
|
+
|
887
1458
|
return this._grouped;
|
888
1459
|
};
|
889
1460
|
|
890
1461
|
/**
|
891
|
-
*
|
892
|
-
*
|
893
|
-
*
|
894
|
-
*
|
895
|
-
*
|
896
|
-
*
|
897
|
-
*
|
898
|
-
*
|
899
|
-
*
|
1462
|
+
* @page Guard Type
|
1463
|
+
* @section grouped
|
1464
|
+
* @signature guard.grouped([true | false])
|
1465
|
+
* @since 1.0.0
|
1466
|
+
*
|
1467
|
+
* <p>
|
1468
|
+
* Mark this guard as being grouped. A grouped guard will guard all affected elements
|
1469
|
+
* at once, instead of individually. Each guarded element with an error will still be marked
|
1470
|
+
* as an error, but only one error message will be added. Custom guard functions will receive
|
1471
|
+
* all elements and their values at once instead of individually. By default, a guard is
|
1472
|
+
* not considered grouped. Name guards, however, carry their grouped status on, so a guard
|
1473
|
+
* using <a href="named_guards.html#oneRequired"><code>oneRequired</code></a>,
|
1474
|
+
* <a href="named_guards.html#different"><code>different</code></a>, and
|
1475
|
+
* <a href="named_guards.html#same"><code>same</code></a> will be grouped by default.
|
1476
|
+
* </p>
|
1477
|
+
*
|
1478
|
+
* <p>
|
1479
|
+
* If no argument is given, the guard will be marked as grouped, otherwise the parameter is
|
1480
|
+
* exoected to be a boolean indicating whether the guard should be grouped.
|
1481
|
+
* </p>
|
1482
|
+
*
|
1483
|
+
* <div class="example">
|
1484
|
+
* <div class="display">
|
1485
|
+
* <script>
|
1486
|
+
* $.guard(".grouped1").using("oneRequired").grouped(false).message("No longer grouped.");
|
1487
|
+
* $.guard(".grouped2").grouped().using(function(values, elements) {
|
1488
|
+
* return $.inArray("test", values) >= 0;
|
1489
|
+
* }).message("One must be 'test'");
|
1490
|
+
* </script>
|
1491
|
+
*
|
1492
|
+
* <p>
|
1493
|
+
* <input class="grouped1" type="text" /><br />
|
1494
|
+
* <input class="grouped1" type="text" /><br />
|
1495
|
+
* <small>These are effectively guarded with 'required' now</small>
|
1496
|
+
* </p>
|
1497
|
+
*
|
1498
|
+
* <p>
|
1499
|
+
* <input class="grouped2" type="text" value="Something" /><br />
|
1500
|
+
* <input class="grouped2" type="text" value="Somewhere" /><br />
|
1501
|
+
* <small>One must be 'test'</small>
|
1502
|
+
* </p>
|
1503
|
+
* </div>
|
1504
|
+
* </div>
|
900
1505
|
*/
|
901
1506
|
$.Guard.prototype.grouped = function() {
|
902
|
-
if (arguments.length
|
1507
|
+
if (arguments.length === 0) {
|
903
1508
|
return this.grouped(true);
|
904
1509
|
}
|
905
1510
|
|
@@ -907,36 +1512,160 @@
|
|
907
1512
|
return this;
|
908
1513
|
};
|
909
1514
|
|
1515
|
+
$.Guard.prototype.getTag = function() {
|
1516
|
+
if (this._tag === undefined) {
|
1517
|
+
return this._guards.defaults.tag;
|
1518
|
+
}
|
1519
|
+
|
1520
|
+
return this._tag;
|
1521
|
+
};
|
1522
|
+
|
910
1523
|
/**
|
911
|
-
*
|
912
|
-
*
|
1524
|
+
* @page Guard Type
|
1525
|
+
* @section tag
|
1526
|
+
* @signature guard.tag(htmlTag)
|
1527
|
+
* @since 1.0.0
|
1528
|
+
*
|
1529
|
+
* <p>
|
1530
|
+
* Change the tag type that surrounds the error message. By default, a <code>span</code> tag is
|
1531
|
+
* used.
|
1532
|
+
* </p>
|
1533
|
+
*
|
1534
|
+
* <div class="example">
|
1535
|
+
* <div class="display">
|
1536
|
+
* <script>
|
1537
|
+
* $.guard(".custom-tag").using("required").tag("div");
|
1538
|
+
* </script>
|
913
1539
|
*
|
914
|
-
*
|
1540
|
+
* <p>
|
1541
|
+
* <input class="custom-tag" type="text" />
|
1542
|
+
* </p>
|
1543
|
+
* </div>
|
1544
|
+
* </div>
|
915
1545
|
*/
|
916
1546
|
$.Guard.prototype.tag = function(tag) {
|
917
1547
|
this._tag = tag;
|
918
1548
|
return this.resetMessageFn();
|
919
1549
|
};
|
920
1550
|
|
1551
|
+
$.Guard.prototype.getMessageClass = function() {
|
1552
|
+
if (this._messageClass === undefined) {
|
1553
|
+
return this._guards.defaults.messageClass;
|
1554
|
+
}
|
1555
|
+
|
1556
|
+
return this._messageClass;
|
1557
|
+
};
|
1558
|
+
|
1559
|
+
/**
|
1560
|
+
* @page Guard Type
|
1561
|
+
* @section messageClass
|
1562
|
+
* @signature guard.messageClass(cssClass)
|
1563
|
+
* @since 1.0.0
|
1564
|
+
*
|
1565
|
+
* <p>
|
1566
|
+
* Change what class is used for error messages added due to failed guards. By default, the
|
1567
|
+
* error element has the class <code>error-message</code>, but that class will not be userd
|
1568
|
+
* if a different one is specified with this method.
|
1569
|
+
* </p>
|
1570
|
+
*
|
1571
|
+
* <div class="example">
|
1572
|
+
* <div class="display">
|
1573
|
+
* <style>
|
1574
|
+
* .green-message { color: #00aa00; }
|
1575
|
+
* .blue-message { color: #0000aa; }
|
1576
|
+
* </style>
|
1577
|
+
*
|
1578
|
+
* <script>
|
1579
|
+
* $.guard(".custom-message-class1").using("required").messageClass("green-message");
|
1580
|
+
* $.guard(".custom-message-class2").using("required").messageClass("blue-message");
|
1581
|
+
* </script>
|
1582
|
+
*
|
1583
|
+
* <p>
|
1584
|
+
* <input class="custom-message-class1" type="text" />
|
1585
|
+
* </p>
|
1586
|
+
*
|
1587
|
+
* <p>
|
1588
|
+
* <input class="custom-message-class2" type="text" />
|
1589
|
+
* </p>
|
1590
|
+
* </div>
|
1591
|
+
* </div>
|
1592
|
+
*/
|
921
1593
|
$.Guard.prototype.messageClass = function(messageClass) {
|
922
1594
|
this._messageClass = messageClass;
|
923
1595
|
return this.resetMessageFn();
|
924
1596
|
};
|
925
1597
|
|
926
1598
|
/**
|
927
|
-
*
|
928
|
-
*
|
929
|
-
*
|
930
|
-
*
|
931
|
-
*
|
1599
|
+
* @page Guard Type
|
1600
|
+
* @section message
|
1601
|
+
* @signature guard.message(errorMessage)
|
1602
|
+
* @since 1.0.0
|
1603
|
+
*
|
1604
|
+
* <p>
|
1605
|
+
* Customize the error message displayed if the guard fails. The
|
1606
|
+
* <a href="named_guards.html"><code>default named guards</code></a>
|
1607
|
+
* have messages already defined, but they may be changed with this method.
|
1608
|
+
* </p>
|
932
1609
|
*
|
933
|
-
*
|
1610
|
+
* <div class="example">
|
1611
|
+
* <div class="display">
|
1612
|
+
* <script>
|
1613
|
+
* $.guard(".message").using("required").message("This error message is customized.");
|
1614
|
+
* </script>
|
1615
|
+
*
|
1616
|
+
* <p>
|
1617
|
+
* <input class="message" type="text" />
|
1618
|
+
* </p>
|
1619
|
+
* </div>
|
1620
|
+
* </div>
|
934
1621
|
*/
|
935
1622
|
$.Guard.prototype.message = function(message) {
|
936
1623
|
this._message = message;
|
937
1624
|
return this.resetMessageFn();
|
938
1625
|
};
|
939
1626
|
|
1627
|
+
$.Guard.prototype.getInvalidClass = function() {
|
1628
|
+
if (this._invalidClass === undefined) {
|
1629
|
+
return this._guards.defaults.invalidClass;
|
1630
|
+
}
|
1631
|
+
|
1632
|
+
return this._invalidClass;
|
1633
|
+
};
|
1634
|
+
|
1635
|
+
/**
|
1636
|
+
* @page Guard Type
|
1637
|
+
* @section invalidClass
|
1638
|
+
* @signature guard.invalidClass(cssClass)
|
1639
|
+
* @since 1.0.0
|
1640
|
+
*
|
1641
|
+
* <p>
|
1642
|
+
* Change what class is added to invalid fields. By default, the invalid class added is
|
1643
|
+
* <code>invalid</code>, but that class will not be added if a different one is specified
|
1644
|
+
* with this method.
|
1645
|
+
* </p>
|
1646
|
+
*
|
1647
|
+
* <div class="example">
|
1648
|
+
* <div class="display">
|
1649
|
+
* <style>
|
1650
|
+
* .green-invalid { background-color: #66ff66; }
|
1651
|
+
* .blue-invalid { background-color: #6666ff; }
|
1652
|
+
* </style>
|
1653
|
+
*
|
1654
|
+
* <script>
|
1655
|
+
* $.guard(".custom-invalid1").using("required").invalidClass("green-invalid");
|
1656
|
+
* $.guard(".custom-invalid2").using("required").invalidClass("blue-invalid");
|
1657
|
+
* </script>
|
1658
|
+
*
|
1659
|
+
* <p>
|
1660
|
+
* <input class="custom-invalid1" type="text" />
|
1661
|
+
* </p>
|
1662
|
+
*
|
1663
|
+
* <p>
|
1664
|
+
* <input class="custom-invalid2" type="text" />
|
1665
|
+
* </p>
|
1666
|
+
* </div>
|
1667
|
+
* </div>
|
1668
|
+
*/
|
940
1669
|
$.Guard.prototype.invalidClass = function(invalidClass) {
|
941
1670
|
this._invalidClass = invalidClass;
|
942
1671
|
return this;
|
@@ -945,7 +1674,7 @@
|
|
945
1674
|
$.Guard.prototype.resetMessageFn = function() {
|
946
1675
|
var self = this;
|
947
1676
|
return this.messageFn(function() {
|
948
|
-
return $('<' + self.
|
1677
|
+
return $('<' + self.getTag() + ' class="' + self.getMessageClass() + '"/>').html(self._message);
|
949
1678
|
});
|
950
1679
|
};
|
951
1680
|
|
@@ -955,78 +1684,119 @@
|
|
955
1684
|
};
|
956
1685
|
|
957
1686
|
$.Guard.prototype.errorElement = function() {
|
958
|
-
|
1687
|
+
var element = this._messageFn();
|
1688
|
+
element[0].isGuardError = true;
|
1689
|
+
return element;
|
959
1690
|
};
|
960
1691
|
|
961
1692
|
$.Guard.prototype.attachError = function(elements, errorElement) {
|
962
|
-
|
963
|
-
|
1693
|
+
var target = this.getTarget();
|
1694
|
+
|
1695
|
+
if (target && $.isFunction(target)) {
|
1696
|
+
var result = target.call(elements, errorElement);
|
964
1697
|
|
965
1698
|
if (result !== false) {
|
966
1699
|
errorElement.appendTo($(result).eq(0));
|
967
1700
|
}
|
968
|
-
} else if (
|
969
|
-
errorElement.appendTo($(
|
1701
|
+
} else if (target) {
|
1702
|
+
errorElement.appendTo($(target).eq(0));
|
970
1703
|
} else {
|
971
1704
|
throw new Error("The target must be a function or selector!");
|
972
1705
|
}
|
973
1706
|
};
|
974
1707
|
|
1708
|
+
$.Guard.prototype.getTarget = function() {
|
1709
|
+
if (this._target === undefined) {
|
1710
|
+
return this._guards.defaults.target;
|
1711
|
+
}
|
1712
|
+
|
1713
|
+
return this._target;
|
1714
|
+
};
|
1715
|
+
|
975
1716
|
/**
|
976
|
-
*
|
977
|
-
*
|
978
|
-
*
|
979
|
-
*
|
980
|
-
*
|
981
|
-
*
|
982
|
-
*
|
983
|
-
* set of elements
|
984
|
-
*
|
985
|
-
*
|
986
|
-
*
|
987
|
-
*
|
988
|
-
*
|
989
|
-
*
|
990
|
-
*
|
991
|
-
*
|
992
|
-
*
|
993
|
-
*
|
994
|
-
*
|
995
|
-
*
|
996
|
-
*
|
997
|
-
*
|
998
|
-
*
|
999
|
-
*
|
1000
|
-
*
|
1001
|
-
*
|
1002
|
-
*
|
1717
|
+
* @page Guard Type
|
1718
|
+
* @section target
|
1719
|
+
* @signature guard.target(selector | targetingFunction)
|
1720
|
+
* @since 1.0.0
|
1721
|
+
*
|
1722
|
+
* <p>
|
1723
|
+
* Specify where the error will be placed in the DOM when this guard fails. The argument can be
|
1724
|
+
* a jQuery selector, element, set of elements, jQuery selected set of elements, or a function.
|
1725
|
+
* If the argument is anything except a function, it will be passed to the jQuery function and
|
1726
|
+
* the first element will be retrieved and used as the place to append the error message.
|
1727
|
+
* If it is a function, the function may either insert the error message itself, or return the
|
1728
|
+
* location to place the error message.
|
1729
|
+
* </p>
|
1730
|
+
*
|
1731
|
+
* <p>
|
1732
|
+
* When provided a function, the function will be called when an error has happened. The function's
|
1733
|
+
* <code>this</code> reference will be set to the error element (or set of elements in the case of
|
1734
|
+
* a grouped guard) that had the error. The argument will be the error message element that will be
|
1735
|
+
* appended. When <code>false</code> is returned, the function is expected to have inserted the
|
1736
|
+
* provided error message in the DOM. Otherwise, the return value is expected to be a jQuery
|
1737
|
+
* selector, element, set of elements or jQuery selected set of elements of which the first will
|
1738
|
+
* have the error element appended to it.
|
1739
|
+
* </p>
|
1740
|
+
*
|
1741
|
+
* <p>
|
1742
|
+
* The default behavior is to append the error message after the last error element that is guarded.
|
1743
|
+
* If the last element is a radio button or checkbox, it will be appended after the first sibling
|
1744
|
+
* of the radio button or checkbox, which is expected to be the label for the radio button or
|
1745
|
+
* checkbox. If there is already a guard error message there, it will be appended after the last
|
1746
|
+
* guard error message (so guard messages show up in the proper order as they are specified).
|
1747
|
+
* </p>
|
1748
|
+
*
|
1749
|
+
* <div class="example">
|
1750
|
+
* <div class="display">
|
1751
|
+
* <script>
|
1752
|
+
* $.guard(".custom-target1").using("required").target("#custom-target-1-error");
|
1753
|
+
* $.guard(".custom-target2").using("required").target(function(errorMessage) {
|
1754
|
+
* return $(this).nextAll(".custom-target-error:first");
|
1755
|
+
* });
|
1756
|
+
* $.guard(".custom-target3").using("required").target(function(errorMessage) {
|
1757
|
+
* $(this).nextAll(".custom-target-error:first").append(errorMessage);
|
1758
|
+
* return false;
|
1759
|
+
* });
|
1760
|
+
* </script>
|
1761
|
+
*
|
1762
|
+
* <p>
|
1763
|
+
* <input class="custom-target1" type="text" />
|
1764
|
+
* Error message targeted with selector:
|
1765
|
+
* <span id="custom-target-1-error"></span>
|
1766
|
+
* </p>
|
1767
|
+
*
|
1768
|
+
* <p>
|
1769
|
+
* <input class="custom-target2" type="text" />
|
1770
|
+
* Error message targeted with function:
|
1771
|
+
* <span class="custom-target-error"></span>
|
1772
|
+
* </p>
|
1773
|
+
*
|
1774
|
+
* <p>
|
1775
|
+
* <input class="custom-target3" type="text" />
|
1776
|
+
* Error message inserted manually:
|
1777
|
+
* <span class="custom-target-error"></span>
|
1778
|
+
* </p>
|
1779
|
+
* </div>
|
1780
|
+
* </div>
|
1003
1781
|
*/
|
1004
1782
|
$.Guard.prototype.target = function(target) {
|
1005
1783
|
this._target = target;
|
1006
1784
|
return this;
|
1007
1785
|
};
|
1008
1786
|
|
1009
|
-
|
1010
|
-
* Determine if this guard applies to the given element (or
|
1011
|
-
* elements).
|
1012
|
-
*/
|
1787
|
+
// Determine if the guard applies to given element(s)
|
1013
1788
|
$.Guard.prototype.appliesTo = function(element) {
|
1014
1789
|
return $(element).filter(this._selector).size() > 0;
|
1015
1790
|
};
|
1016
1791
|
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
* are already errors detected on the element(s). Returns true if
|
1022
|
-
* the selector defined for this guard doesn't apply to this
|
1023
|
-
* element(s). Otherwise, applies the guard and adds an error if
|
1024
|
-
* it fails.
|
1025
|
-
*/
|
1792
|
+
// Tests this guard against element(s). Element(s) should be field elements. Returns false
|
1793
|
+
// but doesn't apply guard if there are already errors detected. Returns true if the selector
|
1794
|
+
// defined for this guard doesn't apply to this element(s). Otherwise applies and adds an
|
1795
|
+
// error if it fails.
|
1026
1796
|
$.Guard.prototype.test = function(element) {
|
1027
1797
|
var $elements = $(element).filter(this._selector);
|
1028
1798
|
|
1029
|
-
if ($elements.size()
|
1799
|
+
if ($elements.size() === 0) {
|
1030
1800
|
return true;
|
1031
1801
|
}
|
1032
1802
|
|
@@ -1034,31 +1804,31 @@
|
|
1034
1804
|
return false;
|
1035
1805
|
}
|
1036
1806
|
|
1037
|
-
var result;
|
1807
|
+
var result, elements, values;
|
1038
1808
|
|
1039
1809
|
// Grouped expects a group of elements, while non-grouped
|
1040
1810
|
// expects a single element.
|
1041
|
-
if (this.
|
1042
|
-
|
1043
|
-
|
1811
|
+
if (this.isGrouped()) {
|
1812
|
+
values = [];
|
1813
|
+
elements = [];
|
1044
1814
|
|
1045
1815
|
$elements.each(function() {
|
1046
1816
|
values.push($(this).inputValue(this._guards));
|
1047
1817
|
elements.push(this);
|
1048
1818
|
});
|
1049
|
-
|
1050
|
-
if (this._precondition && this._precondition(values, elements) === false) {
|
1051
|
-
result = true;
|
1052
|
-
} else {
|
1053
|
-
result = this._guard(values, elements);
|
1054
|
-
}
|
1055
1819
|
} else {
|
1056
|
-
|
1820
|
+
values = $elements.inputValue(this._guards);
|
1821
|
+
elements = element;
|
1822
|
+
}
|
1057
1823
|
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1824
|
+
if (!this.testPrecondition(values, elements)) {
|
1825
|
+
result = true;
|
1826
|
+
} else {
|
1827
|
+
try {
|
1828
|
+
result = this._guard(values, elements);
|
1829
|
+
} catch(e) {
|
1830
|
+
this._guards.log("A guard threw an error: " + e);
|
1831
|
+
result = false;
|
1062
1832
|
}
|
1063
1833
|
}
|
1064
1834
|
|
@@ -1069,23 +1839,104 @@
|
|
1069
1839
|
return result;
|
1070
1840
|
};
|
1071
1841
|
|
1842
|
+
// Test the precondition, if there is one. Returns true if there is none, or if it
|
1843
|
+
// doesn't return false. Returns false if the precondition throws an exception or if
|
1844
|
+
// the precondition returns false. No return, undefined, null, 0 or anything else is
|
1845
|
+
// considered passing.
|
1846
|
+
$.Guard.prototype.testPrecondition = function(values, elements) {
|
1847
|
+
var precondition = this.getPrecondition();
|
1848
|
+
|
1849
|
+
if (!precondition) {
|
1850
|
+
return true;
|
1851
|
+
}
|
1852
|
+
|
1853
|
+
try {
|
1854
|
+
return precondition(values, elements) !== false;
|
1855
|
+
} catch(e) {
|
1856
|
+
this._guards.log("A precondition threw an error: " + e);
|
1857
|
+
return false;
|
1858
|
+
}
|
1859
|
+
};
|
1860
|
+
|
1072
1861
|
/**
|
1073
|
-
*
|
1074
|
-
*
|
1075
|
-
*
|
1076
|
-
*
|
1077
|
-
*
|
1078
|
-
*
|
1862
|
+
* @page Guard Type
|
1863
|
+
* @section triggerError
|
1864
|
+
* @signature guard.triggerError([selector])
|
1865
|
+
* @since 1.0.0
|
1866
|
+
*
|
1867
|
+
* <p>
|
1868
|
+
* Exlicitly trigger an error for this guard on all elements provided to this function.
|
1869
|
+
* The argument provided is wrapped as a jQuery object, so it may be a selector, jQuery
|
1870
|
+
* object, element, or array of elements (or anything valid for a jQuery object). Note
|
1871
|
+
* that the elements provided will have the guard applied, regardless of whether they
|
1872
|
+
* match the guard selector.
|
1873
|
+
* </p>
|
1874
|
+
*
|
1875
|
+
* <p>
|
1876
|
+
* This method may alternatively be invoked with no arguments. If this is done, the
|
1877
|
+
* selector used with the guard is used to select the elents to trigger the guard error.
|
1878
|
+
* </p>
|
1879
|
+
*
|
1880
|
+
* <div class="example">
|
1881
|
+
* <div class="display">
|
1882
|
+
* <script>
|
1883
|
+
* var guard1 = $.guard(".nothingToSelect").using("never").message("Error #1");
|
1884
|
+
* var guard2 = $.guard(".triggerError2").using("never").message("Error #2");
|
1885
|
+
* $(function() {
|
1886
|
+
* guard1.triggerError(".triggerError1");
|
1887
|
+
* guard2.triggerError();
|
1888
|
+
* });
|
1889
|
+
* </script>
|
1890
|
+
*
|
1891
|
+
* <p>
|
1892
|
+
* <input class="triggerError1" type="text" /><br />
|
1893
|
+
* <small>Triggered with a different selector</small>
|
1894
|
+
* </p>
|
1895
|
+
*
|
1896
|
+
* <p>
|
1897
|
+
* <input class="triggerError2" type="text" /><br />
|
1898
|
+
* <small>Triggered using the guard's selector</small>
|
1899
|
+
* </p>
|
1900
|
+
* </div>
|
1901
|
+
* </div>
|
1079
1902
|
*/
|
1080
|
-
$.Guard.prototype.triggerError = function(
|
1081
|
-
|
1903
|
+
$.Guard.prototype.triggerError = function() {
|
1904
|
+
var elements;
|
1905
|
+
|
1906
|
+
if (arguments.length === 0) {
|
1907
|
+
elements = this._selector;
|
1908
|
+
} else if (arguments.length === 1) {
|
1909
|
+
elements = arguments[0];
|
1910
|
+
} else {
|
1911
|
+
throw new Error("Expected 0 or 1 argument to triggerError, got " + arguments.length);
|
1912
|
+
}
|
1913
|
+
|
1914
|
+
if (this.isGrouped()) {
|
1082
1915
|
$(elements).addSingleError(this);
|
1083
1916
|
} else {
|
1084
1917
|
$(elements).addError(this);
|
1085
1918
|
}
|
1086
1919
|
|
1087
1920
|
return this;
|
1088
|
-
}
|
1921
|
+
};
|
1922
|
+
|
1923
|
+
$.Guard.prototype.sendEvent = function(name, selectedElements, forForm, errorMessageElement) {
|
1924
|
+
var event = $.Event(name);
|
1925
|
+
event.guard = this;
|
1926
|
+
event.errorElements = selectedElements.toArray();
|
1927
|
+
var target = selectedElements;
|
1928
|
+
|
1929
|
+
if (forForm) {
|
1930
|
+
target = target.parents("form");
|
1931
|
+
}
|
1932
|
+
|
1933
|
+
if (errorMessageElement) {
|
1934
|
+
event.errorMessage = $(errorMessageElement)[0];
|
1935
|
+
}
|
1936
|
+
|
1937
|
+
target.trigger(event);
|
1938
|
+
return event;
|
1939
|
+
};
|
1089
1940
|
|
1090
1941
|
$.GuardError = function(guard, element, errorElement, linked) {
|
1091
1942
|
this._guard = guard;
|
@@ -1111,8 +1962,8 @@
|
|
1111
1962
|
this._element.errors.splice(index, 1);
|
1112
1963
|
}
|
1113
1964
|
|
1114
|
-
if (!$(this._element).hasErrorsWithInvalidClass(this._guard.
|
1115
|
-
$(this._element).removeClass(this._guard.
|
1965
|
+
if (!$(this._element).hasErrorsWithInvalidClass(this._guard.getInvalidClass())) {
|
1966
|
+
$(this._element).removeClass(this._guard.getInvalidClass());
|
1116
1967
|
}
|
1117
1968
|
|
1118
1969
|
this._cleared = true;
|
@@ -1131,7 +1982,41 @@
|
|
1131
1982
|
};
|
1132
1983
|
|
1133
1984
|
/**
|
1134
|
-
*
|
1985
|
+
* @page jQuery Methods
|
1986
|
+
* @section guard
|
1987
|
+
* @signature selected.guard()
|
1988
|
+
* @since 1.0.0
|
1989
|
+
*
|
1990
|
+
* <p>
|
1991
|
+
* Clear any guard errors present on the form fields within the selected form (or other
|
1992
|
+
* containing element around form elements), and then test each element in order against
|
1993
|
+
* each guard in the order the guards were defined. If any of the fields had an error,
|
1994
|
+
* focus the first such field.
|
1995
|
+
* </p>
|
1996
|
+
*
|
1997
|
+
* <div class="example">
|
1998
|
+
* <div class="display">
|
1999
|
+
* <script>
|
2000
|
+
* $.guard(".guarded-field").using("required");
|
2001
|
+
* $(function() {
|
2002
|
+
* $("#invoke-guard").click(function() {
|
2003
|
+
* $("#guard-container").guard();
|
2004
|
+
* return false;
|
2005
|
+
* });
|
2006
|
+
* });
|
2007
|
+
* </script>
|
2008
|
+
*
|
2009
|
+
* <div id="guard-container">
|
2010
|
+
* <p>
|
2011
|
+
* <input class="guarded-field" type="text" />
|
2012
|
+
* </p>
|
2013
|
+
* </div>
|
2014
|
+
*
|
2015
|
+
* <p>
|
2016
|
+
* <input id="invoke-guard" type="button" value="Test Guards" />
|
2017
|
+
* </p>
|
2018
|
+
* </div>
|
2019
|
+
* </div>
|
1135
2020
|
*/
|
1136
2021
|
$.fn.guard = function() {
|
1137
2022
|
return $.guards.guard(this);
|
@@ -1154,17 +2039,29 @@
|
|
1154
2039
|
* each selected element instead of just 1.
|
1155
2040
|
*/
|
1156
2041
|
$.fn.addSingleError = function(guard) {
|
1157
|
-
if (this.size()
|
2042
|
+
if (this.size() === 0) {
|
1158
2043
|
$.guards.log("Attempted to add error to nothing.");
|
1159
2044
|
return this;
|
1160
2045
|
}
|
1161
2046
|
|
2047
|
+
// Don't add the error if it is already there.
|
2048
|
+
if (this.hasError(guard)) {
|
2049
|
+
return this;
|
2050
|
+
}
|
2051
|
+
|
2052
|
+
var guardErrorPrevented = guard.sendEvent("guardError", this).isDefaultPrevented();
|
2053
|
+
var guardFormErrorPrevented = guard.sendEvent("guardFormError", this, true).isDefaultPrevented();
|
2054
|
+
|
2055
|
+
if (guardErrorPrevented || guardFormErrorPrevented) {
|
2056
|
+
return this;
|
2057
|
+
}
|
2058
|
+
|
1162
2059
|
var element = guard.errorElement();
|
1163
2060
|
guard.attachError(this, element);
|
1164
|
-
this.addClass(guard.
|
2061
|
+
this.addClass(guard.getInvalidClass());
|
1165
2062
|
var linked = [];
|
1166
2063
|
|
1167
|
-
|
2064
|
+
this.each(function() {
|
1168
2065
|
if (!this.errors) {
|
1169
2066
|
this.errors = [];
|
1170
2067
|
}
|
@@ -1173,6 +2070,10 @@
|
|
1173
2070
|
linked.push(error);
|
1174
2071
|
this.errors.push(error);
|
1175
2072
|
});
|
2073
|
+
|
2074
|
+
guard.sendEvent("afterGuardError", this, false, element);
|
2075
|
+
guard.sendEvent("afterGuardFormError", this, true, element);
|
2076
|
+
return this;
|
1176
2077
|
};
|
1177
2078
|
|
1178
2079
|
/**
|
@@ -1195,7 +2096,8 @@
|
|
1195
2096
|
}
|
1196
2097
|
|
1197
2098
|
radiosAdded[name] = true;
|
1198
|
-
var
|
2099
|
+
var context = guard._guards.parentContext($this);
|
2100
|
+
var radios = $("input[name='" + name + "']:radio", context);
|
1199
2101
|
radios.addSingleError(guard);
|
1200
2102
|
} else {
|
1201
2103
|
$this.addSingleError(guard);
|
@@ -1219,7 +2121,38 @@
|
|
1219
2121
|
};
|
1220
2122
|
|
1221
2123
|
/**
|
1222
|
-
*
|
2124
|
+
* @page jQuery Methods
|
2125
|
+
* @section clearErrors
|
2126
|
+
* @signature selected.clearErrors()
|
2127
|
+
* @since 1.0.0
|
2128
|
+
*
|
2129
|
+
* <p>
|
2130
|
+
* Clear any guard errors on the selected elements.
|
2131
|
+
* </p>
|
2132
|
+
*
|
2133
|
+
* <div class="example">
|
2134
|
+
* <div class="display">
|
2135
|
+
* <script>
|
2136
|
+
* $(function() {
|
2137
|
+
* $.guard(".field-to-clear").using("required").triggerError();
|
2138
|
+
* $("#clear-errors").click(function() {
|
2139
|
+
* $(".field-to-clear").clearErrors();
|
2140
|
+
* return false;
|
2141
|
+
* });
|
2142
|
+
* });
|
2143
|
+
* </script>
|
2144
|
+
*
|
2145
|
+
* <div>
|
2146
|
+
* <p>
|
2147
|
+
* <input class="field-to-clear" type="text" />
|
2148
|
+
* </p>
|
2149
|
+
* </div>
|
2150
|
+
*
|
2151
|
+
* <p>
|
2152
|
+
* <input id="clear-errors" type="button" value="Clear Errors" />
|
2153
|
+
* </p>
|
2154
|
+
* </div>
|
2155
|
+
* </div>
|
1223
2156
|
*/
|
1224
2157
|
$.fn.clearErrors = function() {
|
1225
2158
|
$.each(this.errors(), function(index, error) {
|
@@ -1229,6 +2162,23 @@
|
|
1229
2162
|
return this;
|
1230
2163
|
};
|
1231
2164
|
|
2165
|
+
/**
|
2166
|
+
* Determine if the given guard already has an error in the
|
2167
|
+
* selected elements.
|
2168
|
+
*/
|
2169
|
+
$.fn.hasError = function(guard) {
|
2170
|
+
var result = false;
|
2171
|
+
|
2172
|
+
$.each(this.errors(), function(i, error) {
|
2173
|
+
if (error._guard === guard) {
|
2174
|
+
result = true;
|
2175
|
+
return false;
|
2176
|
+
}
|
2177
|
+
});
|
2178
|
+
|
2179
|
+
return result;
|
2180
|
+
};
|
2181
|
+
|
1232
2182
|
/**
|
1233
2183
|
* Determine if any errors exist in the selected elements.
|
1234
2184
|
*/
|
@@ -1240,7 +2190,7 @@
|
|
1240
2190
|
var result = false;
|
1241
2191
|
|
1242
2192
|
$.each(this.errors(), function(i, error) {
|
1243
|
-
if (error._guard.
|
2193
|
+
if (error._guard.getInvalidClass() === invalidClass) {
|
1244
2194
|
result = true;
|
1245
2195
|
return false;
|
1246
2196
|
}
|
@@ -1258,9 +2208,9 @@
|
|
1258
2208
|
guards = guards || $.guards;
|
1259
2209
|
|
1260
2210
|
if (this.is(":radio")) {
|
1261
|
-
var checked = $("input[name='" + this.attr("name") + "']:radio:checked",
|
2211
|
+
var checked = $("input[name='" + this.attr("name") + "']:radio:checked", guards.parentContext(this));
|
1262
2212
|
|
1263
|
-
if (checked.size()
|
2213
|
+
if (checked.size() === 0) {
|
1264
2214
|
return guards.constants.notChecked;
|
1265
2215
|
}
|
1266
2216
|
|
@@ -1285,58 +2235,240 @@
|
|
1285
2235
|
* submitted if guarding fails.
|
1286
2236
|
*/
|
1287
2237
|
$.fn.enableGuards = function() {
|
1288
|
-
return this.submit
|
1289
|
-
return $(this).guard();
|
1290
|
-
});
|
2238
|
+
return this.bind("submit", $.guards.defaults.submitCallback);
|
1291
2239
|
};
|
1292
2240
|
|
1293
2241
|
/**
|
1294
|
-
*
|
1295
|
-
*
|
1296
|
-
|
2242
|
+
* Disable form submit callbacks set up via the enableGuards
|
2243
|
+
* function.
|
2244
|
+
*/
|
2245
|
+
$.fn.disableGuards = function() {
|
2246
|
+
return this.unbind("submit", $.guards.defaults.submitCallback);
|
2247
|
+
};
|
2248
|
+
|
2249
|
+
/**
|
2250
|
+
* @page Global Functions
|
2251
|
+
* @section enableGuards
|
2252
|
+
* @signature jQuery.enableGuards(selector)
|
2253
|
+
* @since 1.0.0
|
2254
|
+
*
|
2255
|
+
* <p>
|
2256
|
+
* Enable guards for a given selector. This will turn on live submit events to guard
|
2257
|
+
* the children of the selected forms/elements. Since these are live events, this
|
2258
|
+
* function need not be called when the elements actually exist (so they need not be in
|
2259
|
+
* a DOM onready handler).
|
2260
|
+
* </p>
|
2261
|
+
*
|
2262
|
+
* <div class="example not-auto-guarded">
|
2263
|
+
* <div class="display">
|
2264
|
+
* <script>
|
2265
|
+
* $.guard("input.guardable").using("required");
|
2266
|
+
* $.enableGuards("form.guardable");
|
2267
|
+
* </script>
|
2268
|
+
*
|
2269
|
+
* <form class="guardable">
|
2270
|
+
* <p>
|
2271
|
+
* <input class="guardable" type="text" />
|
2272
|
+
* </p>
|
2273
|
+
*
|
2274
|
+
* <p>
|
2275
|
+
* <input type="submit" />
|
2276
|
+
* </p>
|
2277
|
+
* </form>
|
2278
|
+
* </div>
|
2279
|
+
* </div>
|
1297
2280
|
*/
|
1298
2281
|
$.enableGuards = function(selector) {
|
1299
2282
|
$.guards.enableGuards(selector);
|
1300
2283
|
};
|
1301
2284
|
|
1302
2285
|
/**
|
1303
|
-
*
|
1304
|
-
*
|
1305
|
-
*
|
1306
|
-
*
|
2286
|
+
* @page Global Functions
|
2287
|
+
* @section disableGuards
|
2288
|
+
* @signature jQuery.disableGuards(selector)
|
2289
|
+
* @since 1.0.0
|
2290
|
+
*
|
2291
|
+
* <p>
|
2292
|
+
* Disable guards that was previously enabled for the given selector.
|
2293
|
+
* </p>
|
2294
|
+
*
|
2295
|
+
* <div class="example not-auto-guarded">
|
2296
|
+
* <div class="display">
|
2297
|
+
* <script>
|
2298
|
+
* $.guard("input.guardable2").using("required");
|
2299
|
+
* $.enableGuards("form.guardable2");
|
2300
|
+
* $(function() {
|
2301
|
+
* $("#disable-guards").click(function() {
|
2302
|
+
* $.disableGuards("form.guardable2");
|
2303
|
+
* return false;
|
2304
|
+
* });
|
2305
|
+
* });
|
2306
|
+
* </script>
|
2307
|
+
*
|
2308
|
+
* <form class="guardable2">
|
2309
|
+
* <p>
|
2310
|
+
* <input class="guardable2" type="text" />
|
2311
|
+
* </p>
|
2312
|
+
*
|
2313
|
+
* <p>
|
2314
|
+
* <input type="submit" />
|
2315
|
+
* </p>
|
2316
|
+
*
|
2317
|
+
* <p>
|
2318
|
+
* <input id="disable-guards" type="button" value="Disable Guards" />
|
2319
|
+
* </p>
|
2320
|
+
* </form>
|
2321
|
+
* </div>
|
2322
|
+
* </div>
|
2323
|
+
*/
|
2324
|
+
$.disableGuards = function(selector) {
|
2325
|
+
$.guards.disableGuards(selector);
|
2326
|
+
};
|
2327
|
+
|
2328
|
+
/**
|
2329
|
+
* @page Global Functions
|
2330
|
+
* @section liveGuard
|
2331
|
+
* @signature jQuery.liveGuard(selector)
|
2332
|
+
* @since 1.0.0
|
2333
|
+
*
|
2334
|
+
* <p>
|
2335
|
+
* Enable live guards for a given selector. This will turn on live submit, change and blur
|
2336
|
+
* events to guard the children of the selected forms/elements. Since these are live events,
|
2337
|
+
* this function need not be called when the elements actually exist (so they need not be in
|
2338
|
+
* a DOM onready handler).
|
2339
|
+
* </p>
|
2340
|
+
*
|
2341
|
+
* <div class="example not-auto-guarded">
|
2342
|
+
* <div class="display">
|
2343
|
+
* <script>
|
2344
|
+
* $.guard(".live-guarded").using("required");
|
2345
|
+
* $.liveGuard(".live-guard");
|
2346
|
+
* </script>
|
2347
|
+
*
|
2348
|
+
* <form class="live-guard">
|
2349
|
+
* <p>
|
2350
|
+
* <input class="live-guarded" type="text" />
|
2351
|
+
* </p>
|
2352
|
+
*
|
2353
|
+
* <p>
|
2354
|
+
* <input type="submit" />
|
2355
|
+
* </p>
|
2356
|
+
* </form>
|
2357
|
+
* </div>
|
2358
|
+
* </div>
|
1307
2359
|
*/
|
1308
2360
|
$.liveGuard = function(selector) {
|
1309
2361
|
$.guards.liveGuard(selector);
|
1310
2362
|
};
|
1311
2363
|
|
2364
|
+
/**
|
2365
|
+
* @page Global Functions
|
2366
|
+
* @section disableLiveGuard
|
2367
|
+
* @signature jQuery.disableLiveGuard(selector)
|
2368
|
+
* @since 1.0.0
|
2369
|
+
*
|
2370
|
+
* <p>
|
2371
|
+
* Disable live guards that was previously enabled for the given selector.
|
2372
|
+
* </p>
|
2373
|
+
*
|
2374
|
+
* <div class="example not-auto-guarded">
|
2375
|
+
* <div class="display">
|
2376
|
+
* <script>
|
2377
|
+
* $.guard(".live-guarded2").using("required");
|
2378
|
+
* $.liveGuard(".live-guard2");
|
2379
|
+
* $(function() {
|
2380
|
+
* $("#disable-live-guards").click(function() {
|
2381
|
+
* $.disableLiveGuard(".live-guard2");
|
2382
|
+
* return false;
|
2383
|
+
* });
|
2384
|
+
* });
|
2385
|
+
* </script>
|
2386
|
+
*
|
2387
|
+
* <form class="live-guard2">
|
2388
|
+
* <p>
|
2389
|
+
* <input class="live-guarded2" type="text" />
|
2390
|
+
* </p>
|
2391
|
+
*
|
2392
|
+
* <p>
|
2393
|
+
* <input type="submit" />
|
2394
|
+
* </p>
|
2395
|
+
*
|
2396
|
+
* <p>
|
2397
|
+
* <input id="disable-live-guards" type="button" value="Disable Guards" />
|
2398
|
+
* </p>
|
2399
|
+
* </form>
|
2400
|
+
* </div>
|
2401
|
+
* </div>
|
2402
|
+
*/
|
2403
|
+
$.disableLiveGuard = function(selector) {
|
2404
|
+
$.guards.disableLiveGuard(selector);
|
2405
|
+
};
|
2406
|
+
|
1312
2407
|
$.extend($.expr[":"], {
|
2408
|
+
/**
|
2409
|
+
* @page jQuery Methods
|
2410
|
+
* @section :has-error
|
2411
|
+
* @signature jQuery("selector:has-error")
|
2412
|
+
* @since 1.0.0
|
2413
|
+
*
|
2414
|
+
* <p>
|
2415
|
+
* This is a jQuery selector that can be used to select elements that currently have an error.
|
2416
|
+
* </p>
|
2417
|
+
*
|
2418
|
+
* <div class="example">
|
2419
|
+
* <div class="display">
|
2420
|
+
* <script>
|
2421
|
+
* $.guard(".field-to-select").using("required");
|
2422
|
+
* $(function() {
|
2423
|
+
* $("#select-errors").click(function() {
|
2424
|
+
* var count = $(".field-to-select:has-error").size();
|
2425
|
+
* $("#selected-error-count").text("Number of errors: " + count);
|
2426
|
+
* return false;
|
2427
|
+
* });
|
2428
|
+
* });
|
2429
|
+
* </script>
|
2430
|
+
*
|
2431
|
+
* <div>
|
2432
|
+
* <p>
|
2433
|
+
* <input class="field-to-select" type="text" />
|
2434
|
+
* </p>
|
2435
|
+
*
|
2436
|
+
* <p>
|
2437
|
+
* <input class="field-to-select" type="text" />
|
2438
|
+
* </p>
|
2439
|
+
* </div>
|
2440
|
+
*
|
2441
|
+
* <p>
|
2442
|
+
* <input id="select-errors" type="button" value="Count errors" /><br />
|
2443
|
+
* <span id="selected-error-count"></span>
|
2444
|
+
* </p>
|
2445
|
+
* </div>
|
2446
|
+
* </div>
|
2447
|
+
*/
|
1313
2448
|
"has-error": function(x) {
|
1314
|
-
return
|
2449
|
+
return !!(x.errors && x.errors.length > 0);
|
1315
2450
|
},
|
1316
2451
|
"guardable": function(x) {
|
1317
|
-
return x.tagName.toLowerCase()
|
2452
|
+
return x.tagName.toLowerCase() === "input" || x.tagName.toLowerCase() === "textarea" || x.tagName.toLowerCase() === "select";
|
1318
2453
|
}
|
1319
2454
|
});
|
1320
2455
|
|
1321
2456
|
$.guards = new $.Guards();
|
1322
2457
|
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
$(this).clearErrors();
|
1339
|
-
}
|
1340
|
-
});
|
2458
|
+
// Clear errors when the user expresses intent to fix the errors.
|
2459
|
+
var clearFn = function() { $(this).clearErrors(); };
|
2460
|
+
$.guards.on(":has-error", "change", clearFn);
|
2461
|
+
$.guards.on(":has-error:radio,:has-error:checkbox", "mouseup", clearFn);
|
2462
|
+
$.guards.on("select:has-error", "mousedown", clearFn);
|
2463
|
+
|
2464
|
+
// Make sure we don't clear it if there was no error when the
|
2465
|
+
// keydown happened, otherwise a submit on enter will have the
|
2466
|
+
// error flash and then go away on the keyup.
|
2467
|
+
$.guards.on(":has-error", "keydown", function() { this.clearable = true; });
|
2468
|
+
$.guards.on(":has-error", "keyup", function() {
|
2469
|
+
if (this.clearable) {
|
2470
|
+
this.clearable = false;
|
2471
|
+
$(this).clearErrors();
|
2472
|
+
}
|
1341
2473
|
});
|
1342
2474
|
})(jQuery);
|