edifice 0.5.0 → 0.6.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/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));
|