rev |
line source |
paulo@81
|
1 /*global $*/
|
paulo@81
|
2 (function happyJS($) {
|
paulo@81
|
3 function trim(el) {
|
paulo@81
|
4 return (''.trim) ? el.val().trim() : $.trim(el.val());
|
paulo@81
|
5 }
|
paulo@81
|
6 $.fn.isHappy = function isHappy(config) {
|
paulo@81
|
7 var fields = [], item;
|
paulo@81
|
8 var pauseMessages = false;
|
paulo@81
|
9
|
paulo@81
|
10 function isFunction(obj) {
|
paulo@81
|
11 return !!(obj && obj.constructor && obj.call && obj.apply);
|
paulo@81
|
12 }
|
paulo@81
|
13 function defaultError(error) { //Default error template
|
paulo@81
|
14 var msgErrorClass = config.classes && config.classes.message || 'unhappyMessage';
|
paulo@81
|
15 return $('<span id="' + error.id + '" class="' + msgErrorClass + '" role="alert">' + error.message + '</span>');
|
paulo@81
|
16 }
|
paulo@81
|
17 function getError(error) { //Generate error html from either config or default
|
paulo@81
|
18 if (isFunction(config.errorTemplate)) {
|
paulo@81
|
19 return config.errorTemplate(error);
|
paulo@81
|
20 }
|
paulo@81
|
21 return defaultError(error);
|
paulo@81
|
22 }
|
paulo@81
|
23 function handleSubmit() {
|
paulo@81
|
24 var i, l;
|
paulo@81
|
25 var errors = false;
|
paulo@81
|
26 for (i = 0, l = fields.length; i < l; i += 1) {
|
paulo@81
|
27 if (!fields[i].testValid(true)) {
|
paulo@81
|
28 errors = true;
|
paulo@81
|
29 }
|
paulo@81
|
30 }
|
paulo@81
|
31 if (errors) {
|
paulo@81
|
32 if (isFunction(config.unHappy)) config.unHappy();
|
paulo@81
|
33 return false;
|
paulo@81
|
34 } else if (config.testMode) {
|
paulo@81
|
35 if (isFunction(config.happy)) return config.happy();
|
paulo@81
|
36 if (window.console) console.warn('would have submitted');
|
paulo@81
|
37 return false;
|
paulo@81
|
38 }
|
paulo@81
|
39 if (isFunction(config.happy)) return config.happy();
|
paulo@81
|
40 }
|
paulo@81
|
41 function handleMouseUp() {
|
paulo@81
|
42 pauseMessages = false;
|
paulo@81
|
43 }
|
paulo@81
|
44 function handleMouseDown() {
|
paulo@81
|
45 pauseMessages = true;
|
paulo@81
|
46 $(window).bind('mouseup', handleMouseUp);
|
paulo@81
|
47 }
|
paulo@81
|
48 function processField(opts, selector) {
|
paulo@81
|
49 var field = $(selector);
|
paulo@81
|
50 var error = {
|
paulo@81
|
51 message: opts.message || '',
|
paulo@81
|
52 id: selector.slice(1) + '_unhappy'
|
paulo@81
|
53 };
|
paulo@81
|
54 var errorEl = $(error.id).length > 0 ? $(error.id) : getError(error);
|
paulo@81
|
55 var handleBlur = function handleBlur() {
|
paulo@81
|
56 if (!pauseMessages) {
|
paulo@81
|
57 field.testValid();
|
paulo@81
|
58 } else {
|
paulo@81
|
59 $(window).bind('mouseup', field.testValid.bind(this));
|
paulo@81
|
60 }
|
paulo@81
|
61 };
|
paulo@81
|
62
|
paulo@81
|
63 fields.push(field);
|
paulo@81
|
64 field.testValid = function testValid(submit) {
|
paulo@81
|
65 var val, gotFunc, temp;
|
paulo@81
|
66 var el = $(this);
|
paulo@81
|
67 var errorTarget = (opts.errorTarget && $(opts.errorTarget)) || el;
|
paulo@81
|
68 var error = false;
|
paulo@81
|
69 var required = !!el.get(0).attributes.getNamedItem('required') || opts.required;
|
paulo@81
|
70 var password = (field.attr('type') === 'password');
|
paulo@81
|
71 var arg = isFunction(opts.arg) ? opts.arg() : opts.arg;
|
paulo@81
|
72 var fieldErrorClass = config.classes && config.classes.field || 'unhappy';
|
paulo@81
|
73
|
paulo@81
|
74 // handle control groups (checkboxes, radio)
|
paulo@81
|
75 if (el.length > 1) {
|
paulo@81
|
76 val = [];
|
paulo@81
|
77 el.each(function(i,obj) {
|
paulo@81
|
78 val.push($(obj).val());
|
paulo@81
|
79 });
|
paulo@81
|
80 val = val.join(',');
|
paulo@81
|
81 } else {
|
paulo@81
|
82 // clean it or trim it
|
paulo@81
|
83 if (isFunction(opts.clean)) {
|
paulo@81
|
84 val = opts.clean(el.val());
|
paulo@81
|
85 } else if (!password && typeof opts.trim === 'undefined' || opts.trim) {
|
paulo@81
|
86 val = trim(el);
|
paulo@81
|
87 } else {
|
paulo@81
|
88 val = el.val();
|
paulo@81
|
89 }
|
paulo@81
|
90
|
paulo@81
|
91 // write it back to the field
|
paulo@81
|
92 el.val(val);
|
paulo@81
|
93 }
|
paulo@81
|
94
|
paulo@81
|
95 // get the value
|
paulo@81
|
96 gotFunc = ((val.length > 0 || required === 'sometimes') && isFunction(opts.test));
|
paulo@81
|
97
|
paulo@81
|
98 // check if we've got an error on our hands
|
paulo@81
|
99 if (submit === true && required === true && val.length === 0) {
|
paulo@81
|
100 error = true;
|
paulo@81
|
101 } else if (gotFunc) {
|
paulo@81
|
102 error = !opts.test(val, arg);
|
paulo@81
|
103 }
|
paulo@81
|
104
|
paulo@81
|
105 if (error) {
|
paulo@81
|
106 errorTarget.addClass(fieldErrorClass).after(errorEl);
|
paulo@81
|
107 return false;
|
paulo@81
|
108 } else {
|
paulo@81
|
109 temp = errorEl.get(0);
|
paulo@81
|
110 // this is for zepto
|
paulo@81
|
111 if (temp.parentNode) {
|
paulo@81
|
112 temp.parentNode.removeChild(temp);
|
paulo@81
|
113 }
|
paulo@81
|
114 errorTarget.removeClass(fieldErrorClass);
|
paulo@81
|
115 return true;
|
paulo@81
|
116 }
|
paulo@81
|
117 };
|
paulo@81
|
118 field.bind(opts.when || config.when || 'blur', handleBlur);
|
paulo@81
|
119 }
|
paulo@81
|
120
|
paulo@81
|
121 for (item in config.fields) {
|
paulo@81
|
122 processField(config.fields[item], item);
|
paulo@81
|
123 }
|
paulo@81
|
124
|
paulo@81
|
125 $(config.submitButton || this).bind('mousedown', handleMouseDown);
|
paulo@81
|
126
|
paulo@81
|
127 if (config.submitButton) {
|
paulo@81
|
128 $(config.submitButton).click(handleSubmit);
|
paulo@81
|
129 } else {
|
paulo@81
|
130 this.bind('submit', handleSubmit);
|
paulo@81
|
131 }
|
paulo@81
|
132 return this;
|
paulo@81
|
133 };
|
paulo@81
|
134 })(this.jQuery || this.Zepto);
|