edifice 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/edifice/version.rb +1 -1
- data/lib/public/javascripts/edifice/edifice_form.js +103 -0
- data/lib/public/javascripts/edifice/form.js +116 -83
- data/test/rails3/app/views/posts/new.html.erb +1 -1
- data/test/rails3/config/application.rb +1 -1
- metadata +4 -4
- data/lib/public/javascripts/edifice/ajax_form.js +0 -127
data/lib/edifice/version.rb
CHANGED
@@ -0,0 +1,103 @@
|
|
1
|
+
// add methods to a form element so it can be easily manipulated
|
2
|
+
//
|
3
|
+
// add client side validation
|
4
|
+
// understands:
|
5
|
+
// - rails form structures
|
6
|
+
// - rails form errors in JSON
|
7
|
+
// - etc
|
8
|
+
(function($) {
|
9
|
+
$.fn.edifice_form = function() {
|
10
|
+
$.extend(this, methods);
|
11
|
+
return this;
|
12
|
+
};
|
13
|
+
|
14
|
+
// VALIDATORS:
|
15
|
+
// validators expect a form element and return true or an error message
|
16
|
+
$.fn.edifice_form.validators = {
|
17
|
+
not_empty: function($input) {
|
18
|
+
return $input.val() ? true : 'must not be empty';
|
19
|
+
}
|
20
|
+
};
|
21
|
+
|
22
|
+
|
23
|
+
// in these 'this' is the $form
|
24
|
+
var methods = {
|
25
|
+
fields: function() {
|
26
|
+
return this.find('input, textarea, select');
|
27
|
+
},
|
28
|
+
|
29
|
+
error_fields: function() {
|
30
|
+
var $form = this;
|
31
|
+
return this.fields().filter(function() {
|
32
|
+
return $form.has_error($(this));
|
33
|
+
});
|
34
|
+
},
|
35
|
+
|
36
|
+
submits: function() {
|
37
|
+
return this.find('input[type=submit], button[type=submit]');
|
38
|
+
},
|
39
|
+
|
40
|
+
valid: function() {
|
41
|
+
var $form = this, valid = true;
|
42
|
+
|
43
|
+
this.fields().each(function() {
|
44
|
+
if (!$form.validate($(this))) { valid = false; }
|
45
|
+
});
|
46
|
+
|
47
|
+
return valid;
|
48
|
+
},
|
49
|
+
|
50
|
+
// 'prepare' a validator --> validator returns true or an error string
|
51
|
+
set_validator: function($field, validator) {
|
52
|
+
if (typeof validator === 'string') {
|
53
|
+
validator = $.fn.edifice_form.validators[validator] || validator;
|
54
|
+
if (typeof validator !== 'function') { throw "Validator not defined: '" + validator + "'"; }
|
55
|
+
};
|
56
|
+
$field.data('validator', validator);
|
57
|
+
},
|
58
|
+
|
59
|
+
// validate a single field
|
60
|
+
validate: function($field) {
|
61
|
+
var validator;
|
62
|
+
if (validator = $field.data('validator')) {
|
63
|
+
var error = validator($field), valid = error === true;
|
64
|
+
this.clear_error($field);
|
65
|
+
if (!valid) {
|
66
|
+
this.add_error($field, error);
|
67
|
+
}
|
68
|
+
|
69
|
+
return valid;
|
70
|
+
} else {
|
71
|
+
return true;
|
72
|
+
}
|
73
|
+
},
|
74
|
+
|
75
|
+
has_error: function($field) {
|
76
|
+
return $field.parent('.field_with_errors').length > 0;
|
77
|
+
},
|
78
|
+
|
79
|
+
clear_error: function($field) {
|
80
|
+
var id = $field.attr('id');
|
81
|
+
if (this.has_error($field)) { $field.unwrap() }
|
82
|
+
|
83
|
+
this.find('.field_with_errors label[for=' + id + ']')
|
84
|
+
.unwrap()
|
85
|
+
.next('.formError').remove();
|
86
|
+
},
|
87
|
+
|
88
|
+
add_error: function($field, error) {
|
89
|
+
var id = $field.attr('id');
|
90
|
+
$field.wrap('<div class="field_with_errors">');
|
91
|
+
this.find('label[for=' + id + ']')
|
92
|
+
.wrap('<div class="field_with_errors">')
|
93
|
+
.after('<div class="formError">' + error + '</div>');
|
94
|
+
},
|
95
|
+
|
96
|
+
set_errors: function(errors) {
|
97
|
+
for (var name in errors) {
|
98
|
+
this.add_error(this.fields().filter('[name*=' + name + ']'), errors[name][0]);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
};
|
102
|
+
|
103
|
+
}(jQuery));
|
@@ -1,105 +1,138 @@
|
|
1
1
|
(function($) {
|
2
|
-
|
3
|
-
|
4
|
-
//
|
5
|
-
|
6
|
-
//
|
7
|
-
|
8
|
-
//
|
9
|
-
|
10
|
-
// - etc
|
11
|
-
$.fn.edifice_form = function() {
|
12
|
-
$.extend(this, methods);
|
13
|
-
return this;
|
14
|
-
};
|
15
|
-
|
16
|
-
// VALIDATORS:
|
17
|
-
// validators expect a form element and return true or an error message
|
18
|
-
$.fn.edifice_form.validators = {
|
19
|
-
not_empty: function($input) {
|
20
|
-
return $input.val() ? true : 'must not be empty';
|
21
|
-
}
|
2
|
+
var defaults = {
|
3
|
+
status_element: this, // element to set to .submitting/.success/.error as we submit
|
4
|
+
// a hash of input selector -> validation functions/names
|
5
|
+
validators: {},
|
6
|
+
// stop the form from submitting and use ajax
|
7
|
+
ajax: true,
|
8
|
+
// type of data to pass around (and thus what's seen by e.g. success)
|
9
|
+
dataType: 'html'
|
22
10
|
};
|
23
11
|
|
12
|
+
// EVENTS that fire during the course of the life of the submission:
|
13
|
+
// submit, invalid, success | error (+ user_error | server_error), complete
|
14
|
+
//
|
15
|
+
// -> success,errors + complete are all passed the data you would expect from
|
16
|
+
// jQuery.ajax
|
17
|
+
//
|
18
|
+
// obviously on submit + invalid fire for non-ajax forms
|
24
19
|
|
25
|
-
|
26
|
-
var methods = {
|
27
|
-
fields: function() {
|
28
|
-
return this.find('input, textarea, select');
|
29
|
-
},
|
20
|
+
$.edifice_widgets.form = function() { return this.each(form); }
|
30
21
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
});
|
36
|
-
},
|
22
|
+
function form() {
|
23
|
+
var $form = $(this).edifice_form();
|
24
|
+
$form.settings = $form.read_options(defaults);
|
25
|
+
$.extend($form, methods);
|
37
26
|
|
38
|
-
|
39
|
-
|
27
|
+
$form.initialize();
|
28
|
+
}
|
29
|
+
var methods = {
|
30
|
+
initialize: function() {
|
31
|
+
this.prepare_validators();
|
32
|
+
this.prepare_submit();
|
40
33
|
},
|
41
34
|
|
42
|
-
|
43
|
-
var $form = this
|
35
|
+
prepare_validators: function() {
|
36
|
+
var $form = this;
|
44
37
|
|
45
|
-
|
46
|
-
|
38
|
+
// setup validators from settings
|
39
|
+
for (var selector in $form.settings.validators) {
|
40
|
+
$form.set_validator($(selector), $form.settings.validators[selector]);
|
41
|
+
}
|
42
|
+
|
43
|
+
// setup validators from html
|
44
|
+
$form.fields().filter('[data-widget-validator]').each(function() {
|
45
|
+
$form.set_validator($(this), $(this).attr('data-widget-validator'));
|
47
46
|
});
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
set_validator: function($field, validator) {
|
54
|
-
if (typeof validator === 'string') {
|
55
|
-
validator = $.fn.edifice_form.validators[validator] || validator;
|
56
|
-
if (typeof validator !== 'function') { throw "Validator not defined: '" + validator + "'"; }
|
57
|
-
};
|
58
|
-
$field.data('validator', validator);
|
48
|
+
// listen to validator
|
49
|
+
this.fields().live('change.ajax_form focusout.ajax_form', function() {
|
50
|
+
$form.validate($(this));
|
51
|
+
});
|
59
52
|
},
|
60
53
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
54
|
+
prepare_submit: function() {
|
55
|
+
var $form = this;
|
56
|
+
this.submit(function(event) {
|
57
|
+
// do pre-submit validations
|
58
|
+
if (!$form.valid()) {
|
59
|
+
$form.trigger('invalid');
|
60
|
+
$form.focus_error();
|
61
|
+
return false; // we are done.
|
69
62
|
}
|
63
|
+
|
64
|
+
$form.submits().attr('disabled', true); // disable submit buttons
|
65
|
+
|
66
|
+
// TODO - set status class
|
67
|
+
if ($form.settings.ajax && $form.settings.ajax !== 'false') {
|
68
|
+
// send up the form and process the results
|
69
|
+
$.ajax({
|
70
|
+
url: $form.attr('action'), type: $form.attr('method'),
|
71
|
+
dataType: $form.settings.dataType,
|
72
|
+
data: $.param($form.serializeArray()),
|
73
|
+
cache: false,
|
74
|
+
error: function (x, t, e) { $form.error(x, t, e); },
|
75
|
+
success: function (data, status) {
|
76
|
+
$form.trigger('success', data, status);
|
77
|
+
},
|
78
|
+
complete: function (request, text_status) {
|
79
|
+
$form.trigger('complete', request, text_status);
|
70
80
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
81
|
+
$form.submits().removeAttr('disabled');
|
82
|
+
}
|
83
|
+
});
|
84
|
+
event.preventDefault();
|
85
|
+
return false;
|
86
|
+
}
|
87
|
+
|
88
|
+
});
|
79
89
|
},
|
80
90
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
this.find('.field_with_errors label[for=' + id + ']')
|
86
|
-
.unwrap()
|
87
|
-
.next('.formError').remove();
|
91
|
+
// focus the first error
|
92
|
+
focus_error: function() {
|
93
|
+
this.error_fields().eq(0).focus();
|
88
94
|
},
|
89
95
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
+
error: function(request, text_status, error) {
|
97
|
+
this.trigger('error', request, status, error);
|
98
|
+
|
99
|
+
// handle the different possible errors that we can see
|
100
|
+
if (request.status >= 400 && request.status < 500) {
|
101
|
+
// CLIENT ERROR -- server-side validation failed.
|
102
|
+
this.trigger('client_error', request, status, error);
|
103
|
+
|
104
|
+
// if data is html, we replace this content of the form with the content
|
105
|
+
// of the form that we've just received back
|
106
|
+
if (this.settings.dataType === 'html') {
|
107
|
+
// wrap in a div incase there are a bunch of floating elements, pull the form out
|
108
|
+
var $new_form = $('<div>').append(request.responseText).find('#' + this.attr('id'));
|
109
|
+
|
110
|
+
this.html($new_form.html());
|
111
|
+
this.prepare_validators();
|
112
|
+
|
113
|
+
} else if (this.settings.dataType === 'json') {
|
114
|
+
// we will be receiving an error object back, we can pass it straight into form.js
|
115
|
+
this.set_errors($.parseJSON(request.responseText));
|
116
|
+
} else {
|
117
|
+
throw "Don't know how to handle dataType " + this.settings.dataType;
|
118
|
+
}
|
119
|
+
|
120
|
+
this.focus_error();
|
121
|
+
} else if (x.status >= 500 && x.status < 600) {
|
122
|
+
// a SERVER ERROR -- something unrecoverable happened on the server
|
123
|
+
this.trigger('server_error', request, status, error);
|
124
|
+
|
125
|
+
// we aren't going to do anything here.
|
126
|
+
// FIXME: we should probably have a way to set this behaviour at the application level.
|
127
|
+
// for instance, you probably just want to redirect to somewhere, or show a dialog,
|
128
|
+
// or popup something or.....?
|
129
|
+
} else {
|
130
|
+
// some other kind of error. Revisit
|
131
|
+
alert('Form failed. Please try again.');
|
132
|
+
}
|
133
|
+
|
134
|
+
|
96
135
|
},
|
136
|
+
}
|
97
137
|
|
98
|
-
set_errors: function(errors) {
|
99
|
-
for (var name in errors) {
|
100
|
-
this.add_error(this.fields().filter('[name*=' + name + ']'), errors[name][0]);
|
101
|
-
}
|
102
|
-
}
|
103
|
-
};
|
104
|
-
|
105
138
|
}(jQuery));
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<h1>Edit your Post</h1>
|
2
|
-
<%= form_for @post, :html => {:'data-widget' => '
|
2
|
+
<%= form_for @post, :html => {:'data-widget' => 'form', :'data-widget-ajax' => false,
|
3
3
|
:'data-widget-validators' => ActiveSupport::JSON.encode({'#post_title' => 'not_empty'})} do |f| %>
|
4
4
|
<%= f.label :email %>
|
5
5
|
<%= f.error_message_on :email %>
|
@@ -38,7 +38,7 @@ module Rails3
|
|
38
38
|
|
39
39
|
# JavaScript files you want as :defaults (application.js is always included).
|
40
40
|
config.action_view.javascript_expansions[:defaults] = %w(
|
41
|
-
jquery-1.5.1 edifice/framework edifice/
|
41
|
+
jquery-1.5.1 edifice/framework edifice/edifice_form edifice/form
|
42
42
|
)
|
43
43
|
|
44
44
|
# Configure the default encoding used in templates for Ruby 1.9.
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: edifice
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 6
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.6.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tom Coleman
|
@@ -48,7 +48,7 @@ files:
|
|
48
48
|
- lib/edifice/railtie.rb
|
49
49
|
- lib/edifice/responder.rb
|
50
50
|
- lib/edifice/version.rb
|
51
|
-
- lib/public/javascripts/edifice/
|
51
|
+
- lib/public/javascripts/edifice/edifice_form.js
|
52
52
|
- lib/public/javascripts/edifice/form.js
|
53
53
|
- lib/public/javascripts/edifice/framework.js
|
54
54
|
- lib/tasks/edifice.rake
|
@@ -1,127 +0,0 @@
|
|
1
|
-
(function($) {
|
2
|
-
var defaults = {
|
3
|
-
status_element: this, // element to set to .submitting/.success/.error as we submit
|
4
|
-
// a hash of input selector -> validation functions/names
|
5
|
-
validators: {},
|
6
|
-
// type of data to pass around (and thus what's seen by e.g. success)
|
7
|
-
dataType: 'html'
|
8
|
-
};
|
9
|
-
|
10
|
-
// EVENTS that fire during the course of the life of the submission:
|
11
|
-
// submit, invalid, success | error (+ user_error | server_error), complete
|
12
|
-
//
|
13
|
-
// -> success,errors + complete are all passed the data you would expect from
|
14
|
-
// jQuery.ajax
|
15
|
-
|
16
|
-
$.edifice_widgets.ajax_form = function() { return this.each(ajax_form); }
|
17
|
-
|
18
|
-
function ajax_form() {
|
19
|
-
var $form = $(this).edifice_form();
|
20
|
-
$form.settings = $form.read_options(defaults);
|
21
|
-
$.extend($form, methods);
|
22
|
-
|
23
|
-
$form.initialize();
|
24
|
-
}
|
25
|
-
var methods = {
|
26
|
-
initialize: function() {
|
27
|
-
this.prepare_validators();
|
28
|
-
this.prepare_submit();
|
29
|
-
},
|
30
|
-
|
31
|
-
prepare_validators: function() {
|
32
|
-
var $form = this;
|
33
|
-
|
34
|
-
// setup validators from settings
|
35
|
-
for (var selector in $form.settings.validators) {
|
36
|
-
$form.set_validator($(selector), $form.settings.validators[selector]);
|
37
|
-
}
|
38
|
-
|
39
|
-
// setup validators from html
|
40
|
-
$form.fields().filter('[data-widget-validator]').each(function() {
|
41
|
-
$form.set_validator($(this), $(this).attr('data-widget-validator'));
|
42
|
-
});
|
43
|
-
|
44
|
-
// listen to validator
|
45
|
-
this.fields().live('change.ajax_form focusout.ajax_form', function() {
|
46
|
-
$form.validate($(this));
|
47
|
-
});
|
48
|
-
},
|
49
|
-
|
50
|
-
prepare_submit: function() {
|
51
|
-
var $form = this;
|
52
|
-
this.submit(function(event) {
|
53
|
-
event.preventDefault();
|
54
|
-
|
55
|
-
// do pre-submit validations
|
56
|
-
if (!$form.valid()) {
|
57
|
-
$form.trigger('invalid');
|
58
|
-
$form.error_fields().eq(0).focus(); // focus the first error
|
59
|
-
return false; // we are done.
|
60
|
-
}
|
61
|
-
|
62
|
-
$form.submits().attr('disabled', true); // disable submit buttons
|
63
|
-
|
64
|
-
// TODO - set status class
|
65
|
-
|
66
|
-
// send up the form and process the results
|
67
|
-
$.ajax({
|
68
|
-
url: $form.attr('action'), type: $form.attr('method'),
|
69
|
-
dataType: $form.settings.dataType,
|
70
|
-
data: $.param($form.serializeArray()),
|
71
|
-
cache: false,
|
72
|
-
error: function (x, t, e) { $form.error(x, t, e); },
|
73
|
-
success: function (data, status) {
|
74
|
-
$form.trigger('success', data, status);
|
75
|
-
},
|
76
|
-
complete: function (request, text_status) {
|
77
|
-
$form.trigger('complete', request, text_status);
|
78
|
-
|
79
|
-
$form.submits().removeAttr('disabled');
|
80
|
-
}
|
81
|
-
});
|
82
|
-
|
83
|
-
return false;
|
84
|
-
});
|
85
|
-
},
|
86
|
-
|
87
|
-
error: function(request, text_status, error) {
|
88
|
-
this.trigger('error', request, status, error);
|
89
|
-
|
90
|
-
// handle the different possible errors that we can see
|
91
|
-
if (request.status >= 400 && request.status < 500) {
|
92
|
-
// CLIENT ERROR -- server-side validation failed.
|
93
|
-
this.trigger('client_error', request, status, error);
|
94
|
-
|
95
|
-
// if data is html, we replace this content of the form with the content
|
96
|
-
// of the form that we've just received back
|
97
|
-
if (this.settings.dataType === 'html') {
|
98
|
-
// wrap in a div incase there are a bunch of floating elements, pull the form out
|
99
|
-
var $new_form = $('<div>').append(request.responseText).find('#' + this.attr('id'));
|
100
|
-
|
101
|
-
this.html($new_form.html());
|
102
|
-
this.prepare_validators();
|
103
|
-
|
104
|
-
} else if (this.settings.dataType === 'json') {
|
105
|
-
// we will be receiving an error object back, we can pass it straight into form.js
|
106
|
-
this.set_errors($.parseJSON(request.responseText));
|
107
|
-
} else {
|
108
|
-
throw "Don't know how to handle dataType " + this.settings.dataType;
|
109
|
-
}
|
110
|
-
} else if (x.status >= 500 && x.status < 600) {
|
111
|
-
// a SERVER ERROR -- something unrecoverable happened on the server
|
112
|
-
this.trigger('server_error', request, status, error);
|
113
|
-
|
114
|
-
// we aren't going to do anything here.
|
115
|
-
// FIXME: we should probably have a way to set this behaviour at the application level.
|
116
|
-
// for instance, you probably just want to redirect to somewhere, or show a dialog,
|
117
|
-
// or popup something or.....?
|
118
|
-
} else {
|
119
|
-
// some other kind of error. Revisit
|
120
|
-
alert('Form failed. Please try again.');
|
121
|
-
}
|
122
|
-
|
123
|
-
|
124
|
-
},
|
125
|
-
}
|
126
|
-
|
127
|
-
}(jQuery));
|