jqtools-rails 0.1.1
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/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +37 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +34 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/jqtools-rails.gemspec +81 -0
- data/lib/jqtools-rails.rb +5 -0
- data/spec/jqtools-rails_spec.rb +7 -0
- data/spec/spec_helper.rb +12 -0
- data/vendor/assets/javascripts/dateinput/dateinput.js +791 -0
- data/vendor/assets/javascripts/jquery.tools.min.js +39 -0
- data/vendor/assets/javascripts/overlay/overlay.apple.js +155 -0
- data/vendor/assets/javascripts/overlay/overlay.js +293 -0
- data/vendor/assets/javascripts/rangeinput/rangeinput.js +471 -0
- data/vendor/assets/javascripts/scrollable/scrollable.autoscroll.js +96 -0
- data/vendor/assets/javascripts/scrollable/scrollable.js +368 -0
- data/vendor/assets/javascripts/scrollable/scrollable.navigator.js +134 -0
- data/vendor/assets/javascripts/tabs/tabs.js +319 -0
- data/vendor/assets/javascripts/tabs/tabs.slideshow.js +191 -0
- data/vendor/assets/javascripts/toolbox/toolbox.expose.js +224 -0
- data/vendor/assets/javascripts/toolbox/toolbox.flashembed.js +301 -0
- data/vendor/assets/javascripts/toolbox/toolbox.history.js +108 -0
- data/vendor/assets/javascripts/toolbox/toolbox.mousewheel.js +65 -0
- data/vendor/assets/javascripts/tooltip/tooltip.dynamic.js +154 -0
- data/vendor/assets/javascripts/tooltip/tooltip.js +358 -0
- data/vendor/assets/javascripts/tooltip/tooltip.slide.js +78 -0
- data/vendor/assets/javascripts/validator/validator.js +598 -0
- metadata +135 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
/**
|
2
|
+
* @license
|
3
|
+
* jQuery Tools @VERSION / Tooltip Slide Effect
|
4
|
+
*
|
5
|
+
* NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
|
6
|
+
*
|
7
|
+
* http://flowplayer.org/tools/tooltip/slide.html
|
8
|
+
*
|
9
|
+
* Since: September 2009
|
10
|
+
* Date: @DATE
|
11
|
+
*/
|
12
|
+
(function($) {
|
13
|
+
|
14
|
+
// version number
|
15
|
+
var t = $.tools.tooltip;
|
16
|
+
|
17
|
+
// extend global configuragion with effect specific defaults
|
18
|
+
$.extend(t.conf, {
|
19
|
+
direction: 'up', // down, left, right
|
20
|
+
bounce: false,
|
21
|
+
slideOffset: 10,
|
22
|
+
slideInSpeed: 200,
|
23
|
+
slideOutSpeed: 200,
|
24
|
+
slideFade: !$.browser.msie
|
25
|
+
});
|
26
|
+
|
27
|
+
// directions for slide effect
|
28
|
+
var dirs = {
|
29
|
+
up: ['-', 'top'],
|
30
|
+
down: ['+', 'top'],
|
31
|
+
left: ['-', 'left'],
|
32
|
+
right: ['+', 'left']
|
33
|
+
};
|
34
|
+
|
35
|
+
/* default effect: "slide" */
|
36
|
+
t.addEffect("slide",
|
37
|
+
|
38
|
+
// show effect
|
39
|
+
function(done) {
|
40
|
+
|
41
|
+
// variables
|
42
|
+
var conf = this.getConf(),
|
43
|
+
tip = this.getTip(),
|
44
|
+
params = conf.slideFade ? {opacity: conf.opacity} : {},
|
45
|
+
dir = dirs[conf.direction] || dirs.up;
|
46
|
+
|
47
|
+
// direction
|
48
|
+
params[dir[1]] = dir[0] +'='+ conf.slideOffset;
|
49
|
+
|
50
|
+
// perform animation
|
51
|
+
if (conf.slideFade) { tip.css({opacity:0}); }
|
52
|
+
tip.show().animate(params, conf.slideInSpeed, done);
|
53
|
+
},
|
54
|
+
|
55
|
+
// hide effect
|
56
|
+
function(done) {
|
57
|
+
|
58
|
+
// variables
|
59
|
+
var conf = this.getConf(),
|
60
|
+
offset = conf.slideOffset,
|
61
|
+
params = conf.slideFade ? {opacity: 0} : {},
|
62
|
+
dir = dirs[conf.direction] || dirs.up;
|
63
|
+
|
64
|
+
// direction
|
65
|
+
var sign = "" + dir[0];
|
66
|
+
if (conf.bounce) { sign = sign == '+' ? '-' : '+'; }
|
67
|
+
params[dir[1]] = sign +'='+ offset;
|
68
|
+
|
69
|
+
// perform animation
|
70
|
+
this.getTip().animate(params, conf.slideOutSpeed, function() {
|
71
|
+
$(this).hide();
|
72
|
+
done.call();
|
73
|
+
});
|
74
|
+
}
|
75
|
+
);
|
76
|
+
|
77
|
+
})(jQuery);
|
78
|
+
|
@@ -0,0 +1,598 @@
|
|
1
|
+
/**
|
2
|
+
* @license
|
3
|
+
* jQuery Tools Validator @VERSION - HTML5 is here. Now use it.
|
4
|
+
*
|
5
|
+
* NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
|
6
|
+
*
|
7
|
+
* http://flowplayer.org/tools/form/validator/
|
8
|
+
*
|
9
|
+
* Since: Mar 2010
|
10
|
+
* Date: @DATE
|
11
|
+
*/
|
12
|
+
/*jslint evil: true */
|
13
|
+
(function($) {
|
14
|
+
|
15
|
+
$.tools = $.tools || {version: '@VERSION'};
|
16
|
+
|
17
|
+
// globals
|
18
|
+
var typeRe = /\[type=([a-z]+)\]/,
|
19
|
+
numRe = /^-?[0-9]*(\.[0-9]+)?$/,
|
20
|
+
dateInput = $.tools.dateinput,
|
21
|
+
|
22
|
+
// http://net.tutsplus.com/tutorials/other/8-regular-expressions-you-should-know/
|
23
|
+
emailRe = /^([a-z0-9_\.\-\+]+)@([\da-z\.\-]+)\.([a-z\.]{2,6})$/i,
|
24
|
+
urlRe = /^(https?:\/\/)?[\da-z\.\-]+\.[a-z\.]{2,6}[#&+_\?\/\w \.\-=]*$/i,
|
25
|
+
v;
|
26
|
+
|
27
|
+
v = $.tools.validator = {
|
28
|
+
|
29
|
+
conf: {
|
30
|
+
grouped: false, // show all error messages at once inside the container
|
31
|
+
effect: 'default', // show/hide effect for error message. only 'default' is built-in
|
32
|
+
errorClass: 'invalid', // input field class name in case of validation error
|
33
|
+
|
34
|
+
// when to check for validity?
|
35
|
+
inputEvent: null, // change, blur, keyup, null
|
36
|
+
errorInputEvent: 'keyup', // change, blur, keyup, null
|
37
|
+
formEvent: 'submit', // submit, null
|
38
|
+
|
39
|
+
lang: 'en', // default language for error messages
|
40
|
+
message: '<div/>',
|
41
|
+
messageAttr: 'data-message', // name of the attribute for overridden error message
|
42
|
+
messageClass: 'error', // error message element's class name
|
43
|
+
offset: [0, 0],
|
44
|
+
position: 'center right',
|
45
|
+
singleError: false, // validate all inputs at once
|
46
|
+
speed: 'normal' // message's fade-in speed
|
47
|
+
},
|
48
|
+
|
49
|
+
|
50
|
+
/* The Error Messages */
|
51
|
+
messages: {
|
52
|
+
"*": { en: "Please correct this value" }
|
53
|
+
},
|
54
|
+
|
55
|
+
localize: function(lang, messages) {
|
56
|
+
$.each(messages, function(key, msg) {
|
57
|
+
v.messages[key] = v.messages[key] || {};
|
58
|
+
v.messages[key][lang] = msg;
|
59
|
+
});
|
60
|
+
},
|
61
|
+
|
62
|
+
localizeFn: function(key, messages) {
|
63
|
+
v.messages[key] = v.messages[key] || {};
|
64
|
+
$.extend(v.messages[key], messages);
|
65
|
+
},
|
66
|
+
|
67
|
+
/**
|
68
|
+
* Adds a new validator
|
69
|
+
*/
|
70
|
+
fn: function(matcher, msg, fn) {
|
71
|
+
|
72
|
+
// no message supplied
|
73
|
+
if ($.isFunction(msg)) {
|
74
|
+
fn = msg;
|
75
|
+
|
76
|
+
// message(s) on second argument
|
77
|
+
} else {
|
78
|
+
if (typeof msg == 'string') { msg = {en: msg}; }
|
79
|
+
this.messages[matcher.key || matcher] = msg;
|
80
|
+
}
|
81
|
+
|
82
|
+
// check for "[type=xxx]" (not supported by jQuery)
|
83
|
+
var test = typeRe.exec(matcher);
|
84
|
+
if (test) { matcher = isType(test[1]); }
|
85
|
+
|
86
|
+
// add validator to the arsenal
|
87
|
+
fns.push([matcher, fn]);
|
88
|
+
},
|
89
|
+
|
90
|
+
/* Add new show/hide effect */
|
91
|
+
addEffect: function(name, showFn, closeFn) {
|
92
|
+
effects[name] = [showFn, closeFn];
|
93
|
+
}
|
94
|
+
|
95
|
+
};
|
96
|
+
|
97
|
+
/* calculate error message position relative to the input */
|
98
|
+
function getPosition(trigger, el, conf) {
|
99
|
+
|
100
|
+
// get origin top/left position
|
101
|
+
var top = trigger.offset().top,
|
102
|
+
left = trigger.offset().left,
|
103
|
+
pos = conf.position.split(/,?\s+/),
|
104
|
+
y = pos[0],
|
105
|
+
x = pos[1];
|
106
|
+
|
107
|
+
top -= el.outerHeight() - conf.offset[0];
|
108
|
+
left += trigger.outerWidth() + conf.offset[1];
|
109
|
+
|
110
|
+
|
111
|
+
// iPad position fix
|
112
|
+
if (/iPad/i.test(navigator.userAgent)) {
|
113
|
+
top -= $(window).scrollTop();
|
114
|
+
}
|
115
|
+
|
116
|
+
// adjust Y
|
117
|
+
var height = el.outerHeight() + trigger.outerHeight();
|
118
|
+
if (y == 'center') { top += height / 2; }
|
119
|
+
if (y == 'bottom') { top += height; }
|
120
|
+
|
121
|
+
// adjust X
|
122
|
+
var width = trigger.outerWidth();
|
123
|
+
if (x == 'center') { left -= (width + el.outerWidth()) / 2; }
|
124
|
+
if (x == 'left') { left -= width; }
|
125
|
+
|
126
|
+
return {top: top, left: left};
|
127
|
+
}
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
// $.is("[type=xxx]") or $.filter("[type=xxx]") not working in jQuery 1.3.2 or 1.4.2
|
132
|
+
function isType(type) {
|
133
|
+
function fn() {
|
134
|
+
return this.getAttribute("type") == type;
|
135
|
+
}
|
136
|
+
fn.key = "[type=" + type + "]";
|
137
|
+
return fn;
|
138
|
+
}
|
139
|
+
|
140
|
+
|
141
|
+
var fns = [], effects = {
|
142
|
+
|
143
|
+
'default' : [
|
144
|
+
|
145
|
+
// show errors function
|
146
|
+
function(errs) {
|
147
|
+
|
148
|
+
var conf = this.getConf();
|
149
|
+
|
150
|
+
// loop errors
|
151
|
+
$.each(errs, function(i, err) {
|
152
|
+
|
153
|
+
// add error class
|
154
|
+
var input = err.input;
|
155
|
+
input.addClass(conf.errorClass);
|
156
|
+
|
157
|
+
// get handle to the error container
|
158
|
+
var msg = input.data("msg.el");
|
159
|
+
|
160
|
+
// create it if not present
|
161
|
+
if (!msg) {
|
162
|
+
msg = $(conf.message).addClass(conf.messageClass).appendTo(document.body);
|
163
|
+
input.data("msg.el", msg);
|
164
|
+
}
|
165
|
+
|
166
|
+
// clear the container
|
167
|
+
msg.css({visibility: 'hidden'}).find("p").remove();
|
168
|
+
|
169
|
+
// populate messages
|
170
|
+
$.each(err.messages, function(i, m) {
|
171
|
+
$("<p/>").html(m).appendTo(msg);
|
172
|
+
});
|
173
|
+
|
174
|
+
// make sure the width is not full body width so it can be positioned correctly
|
175
|
+
if (msg.outerWidth() == msg.parent().width()) {
|
176
|
+
msg.add(msg.find("p")).css({display: 'inline'});
|
177
|
+
}
|
178
|
+
|
179
|
+
// insert into correct position (relative to the field)
|
180
|
+
var pos = getPosition(input, msg, conf);
|
181
|
+
|
182
|
+
msg.css({ visibility: 'visible', position: 'absolute', top: pos.top, left: pos.left })
|
183
|
+
.fadeIn(conf.speed);
|
184
|
+
});
|
185
|
+
|
186
|
+
|
187
|
+
// hide errors function
|
188
|
+
}, function(inputs) {
|
189
|
+
|
190
|
+
var conf = this.getConf();
|
191
|
+
inputs.removeClass(conf.errorClass).each(function() {
|
192
|
+
var msg = $(this).data("msg.el");
|
193
|
+
if (msg) { msg.css({visibility: 'hidden'}); }
|
194
|
+
});
|
195
|
+
}
|
196
|
+
]
|
197
|
+
};
|
198
|
+
|
199
|
+
|
200
|
+
/* sperial selectors */
|
201
|
+
$.each("email,url,number".split(","), function(i, key) {
|
202
|
+
$.expr[':'][key] = function(el) {
|
203
|
+
return el.getAttribute("type") === key;
|
204
|
+
};
|
205
|
+
});
|
206
|
+
|
207
|
+
|
208
|
+
/*
|
209
|
+
oninvalid() jQuery plugin.
|
210
|
+
Usage: $("input:eq(2)").oninvalid(function() { ... });
|
211
|
+
*/
|
212
|
+
$.fn.oninvalid = function( fn ){
|
213
|
+
return this[fn ? "bind" : "trigger"]("OI", fn);
|
214
|
+
};
|
215
|
+
|
216
|
+
|
217
|
+
/******* built-in HTML5 standard validators *********/
|
218
|
+
|
219
|
+
v.fn(":email", "Please enter a valid email address", function(el, v) {
|
220
|
+
return !v || emailRe.test(v);
|
221
|
+
});
|
222
|
+
|
223
|
+
v.fn(":url", "Please enter a valid URL", function(el, v) {
|
224
|
+
return !v || urlRe.test(v);
|
225
|
+
});
|
226
|
+
|
227
|
+
v.fn(":number", "Please enter a numeric value.", function(el, v) {
|
228
|
+
return numRe.test(v);
|
229
|
+
});
|
230
|
+
|
231
|
+
v.fn("[max]", "Please enter a value no larger than $1", function(el, v) {
|
232
|
+
|
233
|
+
// skip empty values and dateinputs
|
234
|
+
if (v === '' || dateInput && el.is(":date")) { return true; }
|
235
|
+
|
236
|
+
var max = el.attr("max");
|
237
|
+
return parseFloat(v) <= parseFloat(max) ? true : [max];
|
238
|
+
});
|
239
|
+
|
240
|
+
v.fn("[min]", "Please enter a value of at least $1", function(el, v) {
|
241
|
+
|
242
|
+
// skip empty values and dateinputs
|
243
|
+
if (v === '' || dateInput && el.is(":date")) { return true; }
|
244
|
+
|
245
|
+
var min = el.attr("min");
|
246
|
+
return parseFloat(v) >= parseFloat(min) ? true : [min];
|
247
|
+
});
|
248
|
+
|
249
|
+
v.fn("[required]", "Please complete this mandatory field.", function(el, v) {
|
250
|
+
if (el.is(":checkbox")) { return el.is(":checked"); }
|
251
|
+
return !!v;
|
252
|
+
});
|
253
|
+
|
254
|
+
v.fn("[pattern]", function(el) {
|
255
|
+
var p = new RegExp("^" + el.attr("pattern") + "$");
|
256
|
+
return p.test(el.val());
|
257
|
+
});
|
258
|
+
|
259
|
+
|
260
|
+
function Validator(inputs, form, conf) {
|
261
|
+
|
262
|
+
// private variables
|
263
|
+
var self = this,
|
264
|
+
fire = form.add(self);
|
265
|
+
|
266
|
+
// make sure there are input fields available
|
267
|
+
inputs = inputs.not(":button, :image, :reset, :submit");
|
268
|
+
|
269
|
+
// Prevent default Firefox validation
|
270
|
+
form.attr("novalidate", "novalidate");
|
271
|
+
|
272
|
+
// utility function
|
273
|
+
function pushMessage(to, matcher, returnValue) {
|
274
|
+
|
275
|
+
// only one message allowed
|
276
|
+
if (!conf.grouped && to.length) { return; }
|
277
|
+
|
278
|
+
// the error message
|
279
|
+
var msg;
|
280
|
+
|
281
|
+
// substitutions are returned
|
282
|
+
if (returnValue === false || $.isArray(returnValue)) {
|
283
|
+
msg = v.messages[matcher.key || matcher] || v.messages["*"];
|
284
|
+
msg = msg[conf.lang] || v.messages["*"].en;
|
285
|
+
|
286
|
+
// substitution
|
287
|
+
var matches = msg.match(/\$\d/g);
|
288
|
+
|
289
|
+
if (matches && $.isArray(returnValue)) {
|
290
|
+
$.each(matches, function(i) {
|
291
|
+
msg = msg.replace(this, returnValue[i]);
|
292
|
+
});
|
293
|
+
}
|
294
|
+
|
295
|
+
// error message is returned directly
|
296
|
+
} else {
|
297
|
+
msg = returnValue[conf.lang] || returnValue;
|
298
|
+
}
|
299
|
+
|
300
|
+
to.push(msg);
|
301
|
+
}
|
302
|
+
|
303
|
+
|
304
|
+
// API methods
|
305
|
+
$.extend(self, {
|
306
|
+
|
307
|
+
getConf: function() {
|
308
|
+
return conf;
|
309
|
+
},
|
310
|
+
|
311
|
+
getForm: function() {
|
312
|
+
return form;
|
313
|
+
},
|
314
|
+
|
315
|
+
getInputs: function() {
|
316
|
+
return inputs;
|
317
|
+
},
|
318
|
+
|
319
|
+
reflow: function() {
|
320
|
+
inputs.each(function() {
|
321
|
+
var input = $(this),
|
322
|
+
msg = input.data("msg.el");
|
323
|
+
|
324
|
+
if (msg) {
|
325
|
+
var pos = getPosition(input, msg, conf);
|
326
|
+
msg.css({ top: pos.top, left: pos.left });
|
327
|
+
}
|
328
|
+
});
|
329
|
+
return self;
|
330
|
+
},
|
331
|
+
|
332
|
+
/* @param e - for internal use only */
|
333
|
+
invalidate: function(errs, e) {
|
334
|
+
|
335
|
+
// errors are given manually: { fieldName1: 'message1', fieldName2: 'message2' }
|
336
|
+
if (!e) {
|
337
|
+
var errors = [];
|
338
|
+
$.each(errs, function(key, val) {
|
339
|
+
var input = inputs.filter("[name='" + key + "']");
|
340
|
+
if (input.length) {
|
341
|
+
|
342
|
+
// trigger HTML5 ininvalid event
|
343
|
+
input.trigger("OI", [val]);
|
344
|
+
|
345
|
+
errors.push({ input: input, messages: [val]});
|
346
|
+
}
|
347
|
+
});
|
348
|
+
|
349
|
+
errs = errors;
|
350
|
+
e = $.Event();
|
351
|
+
}
|
352
|
+
|
353
|
+
// onFail callback
|
354
|
+
e.type = "onFail";
|
355
|
+
fire.trigger(e, [errs]);
|
356
|
+
|
357
|
+
// call the effect
|
358
|
+
if (!e.isDefaultPrevented()) {
|
359
|
+
effects[conf.effect][0].call(self, errs, e);
|
360
|
+
}
|
361
|
+
|
362
|
+
return self;
|
363
|
+
},
|
364
|
+
|
365
|
+
reset: function(els) {
|
366
|
+
els = els || inputs;
|
367
|
+
els.removeClass(conf.errorClass).each(function() {
|
368
|
+
var msg = $(this).data("msg.el");
|
369
|
+
if (msg) {
|
370
|
+
msg.remove();
|
371
|
+
$(this).data("msg.el", null);
|
372
|
+
}
|
373
|
+
}).unbind(conf.errorInputEvent || '');
|
374
|
+
return self;
|
375
|
+
},
|
376
|
+
|
377
|
+
destroy: function() {
|
378
|
+
form.unbind(conf.formEvent + ".V").unbind("reset.V");
|
379
|
+
inputs.unbind(conf.inputEvent + ".V").unbind("change.V");
|
380
|
+
return self.reset();
|
381
|
+
},
|
382
|
+
|
383
|
+
|
384
|
+
//{{{ checkValidity() - flesh and bone of this tool
|
385
|
+
|
386
|
+
/* @returns boolean */
|
387
|
+
checkValidity: function(els, e) {
|
388
|
+
|
389
|
+
els = els || inputs;
|
390
|
+
els = els.not(":disabled");
|
391
|
+
if (!els.length) { return true; }
|
392
|
+
|
393
|
+
e = e || $.Event();
|
394
|
+
|
395
|
+
// onBeforeValidate
|
396
|
+
e.type = "onBeforeValidate";
|
397
|
+
fire.trigger(e, [els]);
|
398
|
+
if (e.isDefaultPrevented()) { return e.result; }
|
399
|
+
|
400
|
+
// container for errors
|
401
|
+
var errs = [];
|
402
|
+
|
403
|
+
// loop trough the inputs
|
404
|
+
els.not(":radio:not(:checked)").each(function() {
|
405
|
+
|
406
|
+
// field and it's error message container
|
407
|
+
var msgs = [],
|
408
|
+
el = $(this).data("messages", msgs),
|
409
|
+
event = dateInput && el.is(":date") ? "onHide.v" : conf.errorInputEvent + ".v";
|
410
|
+
|
411
|
+
// cleanup previous validation event
|
412
|
+
el.unbind(event);
|
413
|
+
|
414
|
+
|
415
|
+
// loop all validator functions
|
416
|
+
$.each(fns, function() {
|
417
|
+
var fn = this, match = fn[0];
|
418
|
+
|
419
|
+
// match found
|
420
|
+
if (el.filter(match).length) {
|
421
|
+
|
422
|
+
// execute a validator function
|
423
|
+
var returnValue = fn[1].call(self, el, el.val());
|
424
|
+
|
425
|
+
|
426
|
+
// validation failed. multiple substitutions can be returned with an array
|
427
|
+
if (returnValue !== true) {
|
428
|
+
|
429
|
+
// onBeforeFail
|
430
|
+
e.type = "onBeforeFail";
|
431
|
+
fire.trigger(e, [el, match]);
|
432
|
+
if (e.isDefaultPrevented()) { return false; }
|
433
|
+
|
434
|
+
// overridden custom message
|
435
|
+
var msg = el.attr(conf.messageAttr);
|
436
|
+
if (msg) {
|
437
|
+
msgs = [msg];
|
438
|
+
return false;
|
439
|
+
} else {
|
440
|
+
pushMessage(msgs, match, returnValue);
|
441
|
+
}
|
442
|
+
}
|
443
|
+
}
|
444
|
+
});
|
445
|
+
|
446
|
+
if (msgs.length) {
|
447
|
+
|
448
|
+
errs.push({input: el, messages: msgs});
|
449
|
+
|
450
|
+
// trigger HTML5 ininvalid event
|
451
|
+
el.trigger("OI", [msgs]);
|
452
|
+
|
453
|
+
// begin validating upon error event type (such as keyup)
|
454
|
+
if (conf.errorInputEvent) {
|
455
|
+
el.bind(event, function(e) {
|
456
|
+
self.checkValidity(el, e);
|
457
|
+
});
|
458
|
+
}
|
459
|
+
}
|
460
|
+
|
461
|
+
if (conf.singleError && errs.length) { return false; }
|
462
|
+
|
463
|
+
});
|
464
|
+
|
465
|
+
|
466
|
+
// validation done. now check that we have a proper effect at hand
|
467
|
+
var eff = effects[conf.effect];
|
468
|
+
if (!eff) { throw "Validator: cannot find effect \"" + conf.effect + "\""; }
|
469
|
+
|
470
|
+
// errors found
|
471
|
+
if (errs.length) {
|
472
|
+
self.invalidate(errs, e);
|
473
|
+
return false;
|
474
|
+
|
475
|
+
// no errors
|
476
|
+
} else {
|
477
|
+
|
478
|
+
// call the effect
|
479
|
+
eff[1].call(self, els, e);
|
480
|
+
|
481
|
+
// onSuccess callback
|
482
|
+
e.type = "onSuccess";
|
483
|
+
fire.trigger(e, [els]);
|
484
|
+
|
485
|
+
els.unbind(conf.errorInputEvent + ".v");
|
486
|
+
}
|
487
|
+
|
488
|
+
return true;
|
489
|
+
}
|
490
|
+
//}}}
|
491
|
+
|
492
|
+
});
|
493
|
+
|
494
|
+
// callbacks
|
495
|
+
$.each("onBeforeValidate,onBeforeFail,onFail,onSuccess".split(","), function(i, name) {
|
496
|
+
|
497
|
+
// configuration
|
498
|
+
if ($.isFunction(conf[name])) {
|
499
|
+
$(self).bind(name, conf[name]);
|
500
|
+
}
|
501
|
+
|
502
|
+
// API methods
|
503
|
+
self[name] = function(fn) {
|
504
|
+
if (fn) { $(self).bind(name, fn); }
|
505
|
+
return self;
|
506
|
+
};
|
507
|
+
});
|
508
|
+
|
509
|
+
|
510
|
+
// form validation
|
511
|
+
if (conf.formEvent) {
|
512
|
+
form.bind(conf.formEvent + ".V", function(e) {
|
513
|
+
if (!self.checkValidity(null, e)) {
|
514
|
+
return e.preventDefault();
|
515
|
+
}
|
516
|
+
// Reset event type and target
|
517
|
+
e.target = form;
|
518
|
+
e.type = conf.formEvent;
|
519
|
+
});
|
520
|
+
}
|
521
|
+
|
522
|
+
// form reset
|
523
|
+
form.bind("reset.V", function() {
|
524
|
+
self.reset();
|
525
|
+
});
|
526
|
+
|
527
|
+
// disable browser's default validation mechanism
|
528
|
+
if (inputs[0] && inputs[0].validity) {
|
529
|
+
inputs.each(function() {
|
530
|
+
this.oninvalid = function() {
|
531
|
+
return false;
|
532
|
+
};
|
533
|
+
});
|
534
|
+
}
|
535
|
+
|
536
|
+
// Web Forms 2.0 compatibility
|
537
|
+
if (form[0]) {
|
538
|
+
form[0].checkValidity = self.checkValidity;
|
539
|
+
}
|
540
|
+
|
541
|
+
// input validation
|
542
|
+
if (conf.inputEvent) {
|
543
|
+
inputs.bind(conf.inputEvent + ".V", function(e) {
|
544
|
+
self.checkValidity($(this), e);
|
545
|
+
});
|
546
|
+
}
|
547
|
+
|
548
|
+
// checkboxes, selects and radios are checked separately
|
549
|
+
inputs.filter(":checkbox, select").filter("[required]").bind("change.V", function(e) {
|
550
|
+
var el = $(this);
|
551
|
+
if (this.checked || (el.is("select") && $(this).val())) {
|
552
|
+
effects[conf.effect][1].call(self, el, e);
|
553
|
+
}
|
554
|
+
});
|
555
|
+
|
556
|
+
var radios = inputs.filter(":radio").change(function(e) {
|
557
|
+
self.checkValidity(radios, e);
|
558
|
+
});
|
559
|
+
|
560
|
+
// reposition tooltips when window is resized
|
561
|
+
$(window).resize(function() {
|
562
|
+
self.reflow();
|
563
|
+
});
|
564
|
+
}
|
565
|
+
|
566
|
+
|
567
|
+
// jQuery plugin initialization
|
568
|
+
$.fn.validator = function(conf) {
|
569
|
+
|
570
|
+
var instance = this.data("validator");
|
571
|
+
|
572
|
+
// destroy existing instance
|
573
|
+
if (instance) {
|
574
|
+
instance.destroy();
|
575
|
+
this.removeData("validator");
|
576
|
+
}
|
577
|
+
|
578
|
+
// configuration
|
579
|
+
conf = $.extend(true, {}, v.conf, conf);
|
580
|
+
|
581
|
+
// selector is a form
|
582
|
+
if (this.is("form")) {
|
583
|
+
return this.each(function() {
|
584
|
+
var form = $(this);
|
585
|
+
instance = new Validator(form.find(":input"), form, conf);
|
586
|
+
form.data("validator", instance);
|
587
|
+
});
|
588
|
+
|
589
|
+
} else {
|
590
|
+
instance = new Validator(this, this.eq(0).closest("form"), conf);
|
591
|
+
return this.data("validator", instance);
|
592
|
+
}
|
593
|
+
|
594
|
+
};
|
595
|
+
|
596
|
+
})(jQuery);
|
597
|
+
|
598
|
+
|