guardsjs-rails 0.7.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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);
|