wheelhouse-forms 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +22 -0
- data/README.md +39 -0
- data/app/assets/images/wheelhouse-forms/checkbox.png +0 -0
- data/app/assets/images/wheelhouse-forms/checkboxes.png +0 -0
- data/app/assets/images/wheelhouse-forms/content.png +0 -0
- data/app/assets/images/wheelhouse-forms/countries.png +0 -0
- data/app/assets/images/wheelhouse-forms/csv.png +0 -0
- data/app/assets/images/wheelhouse-forms/custom.png +0 -0
- data/app/assets/images/wheelhouse-forms/drag.png +0 -0
- data/app/assets/images/wheelhouse-forms/field-set.png +0 -0
- data/app/assets/images/wheelhouse-forms/form.png +0 -0
- data/app/assets/images/wheelhouse-forms/radio-buttons.png +0 -0
- data/app/assets/images/wheelhouse-forms/select.png +0 -0
- data/app/assets/images/wheelhouse-forms/states.png +0 -0
- data/app/assets/images/wheelhouse-forms/submit-button.png +0 -0
- data/app/assets/images/wheelhouse-forms/text-area.png +0 -0
- data/app/assets/images/wheelhouse-forms/text-field.png +0 -0
- data/app/assets/javascripts/wheelhouse-forms/admin.js +125 -0
- data/app/assets/javascripts/wheelhouse-forms/jquery.autogrow.js +50 -0
- data/app/assets/javascripts/wheelhouse-forms/jquery.options.js +24 -0
- data/app/assets/stylesheets/wheelhouse-forms/admin.css.sass +244 -0
- data/app/controllers/forms/forms_controller.rb +9 -0
- data/app/controllers/forms/submissions_controller.rb +19 -0
- data/app/handlers/forms/form_handler.rb +17 -0
- data/app/helpers/forms/forms_helper.rb +36 -0
- data/app/helpers/forms/mailer_helper.rb +67 -0
- data/app/helpers/forms/submissions_helper.rb +71 -0
- data/app/mailers/forms/mailer.rb +11 -0
- data/app/models/forms/field_collection.rb +21 -0
- data/app/models/forms/fields/checkbox.rb +8 -0
- data/app/models/forms/fields/checkboxes.rb +10 -0
- data/app/models/forms/fields/content_field.rb +7 -0
- data/app/models/forms/fields/countries_dropdown.rb +14 -0
- data/app/models/forms/fields/custom_field.rb +8 -0
- data/app/models/forms/fields/field.rb +28 -0
- data/app/models/forms/fields/field_set.rb +14 -0
- data/app/models/forms/fields/optioned_field.rb +17 -0
- data/app/models/forms/fields/radio_buttons.rb +10 -0
- data/app/models/forms/fields/select_field.rb +10 -0
- data/app/models/forms/fields/states_dropdown.rb +15 -0
- data/app/models/forms/fields/submit_button.rb +7 -0
- data/app/models/forms/fields/text_area.rb +8 -0
- data/app/models/forms/fields/text_field.rb +21 -0
- data/app/models/forms/form.rb +65 -0
- data/app/models/forms/submission.rb +53 -0
- data/app/renderers/forms/checkbox_renderer.rb +7 -0
- data/app/renderers/forms/checkboxes_renderer.rb +18 -0
- data/app/renderers/forms/content_field_renderer.rb +5 -0
- data/app/renderers/forms/custom_field_renderer.rb +5 -0
- data/app/renderers/forms/field_collection_renderer.rb +13 -0
- data/app/renderers/forms/field_renderer.rb +57 -0
- data/app/renderers/forms/field_set_renderer.rb +10 -0
- data/app/renderers/forms/form_renderer.rb +30 -0
- data/app/renderers/forms/labelled_field_renderer.rb +10 -0
- data/app/renderers/forms/radio_buttons_renderer.rb +18 -0
- data/app/renderers/forms/select_field_renderer.rb +9 -0
- data/app/renderers/forms/submit_button_renderer.rb +5 -0
- data/app/renderers/forms/text_area_renderer.rb +7 -0
- data/app/renderers/forms/text_field_renderer.rb +7 -0
- data/app/templates/form.html.haml +9 -0
- data/app/templates/form.xhr.haml +4 -0
- data/app/templates/form/submission.html.haml +15 -0
- data/app/views/forms/forms/_checkbox.haml +3 -0
- data/app/views/forms/forms/_checkboxes.haml +10 -0
- data/app/views/forms/forms/_content_field.haml +3 -0
- data/app/views/forms/forms/_countries_dropdown.haml +4 -0
- data/app/views/forms/forms/_custom_field.haml +4 -0
- data/app/views/forms/forms/_field_set.haml +16 -0
- data/app/views/forms/forms/_radio_buttons.haml +10 -0
- data/app/views/forms/forms/_select_field.haml +10 -0
- data/app/views/forms/forms/_states_dropdown.haml +4 -0
- data/app/views/forms/forms/_submissions.haml +20 -0
- data/app/views/forms/forms/_submit_button.haml +2 -0
- data/app/views/forms/forms/_text_area.haml +3 -0
- data/app/views/forms/forms/_text_field.haml +4 -0
- data/app/views/forms/forms/designer.haml +56 -0
- data/app/views/forms/forms/edit.html.haml +5 -0
- data/app/views/forms/forms/form.haml +22 -0
- data/app/views/forms/forms/new.html.haml +4 -0
- data/app/views/forms/forms/show.html.haml +4 -0
- data/app/views/forms/submissions/form.haml +16 -0
- data/app/views/forms/submissions/show.html.haml +4 -0
- data/config/countries.yml +245 -0
- data/config/locales/en.yml +7 -0
- data/config/routes.rb +7 -0
- data/config/states.yml +62 -0
- data/lib/forms/csv_exporter.rb +41 -0
- data/lib/wheelhouse-forms.rb +26 -0
- metadata +149 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
module Forms::Fields
|
2
|
+
class TextField < Field
|
3
|
+
property :label, String, :required => true
|
4
|
+
property :input_type, String, :default => "text"
|
5
|
+
property :required, Boolean, :default => false
|
6
|
+
|
7
|
+
self.renderer = Forms::TextFieldRenderer
|
8
|
+
|
9
|
+
INPUT_TYPES = [
|
10
|
+
["Text", "text"],
|
11
|
+
["Email", "email"],
|
12
|
+
["Telephone", "tel"],
|
13
|
+
["URL", "url"],
|
14
|
+
["Date", "date"],
|
15
|
+
["Date & Time", "datetime"],
|
16
|
+
["Number", "number"],
|
17
|
+
["Search", "search"],
|
18
|
+
["Color", "color"]
|
19
|
+
]
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class Forms::Form < Wheelhouse::Resource
|
2
|
+
include Wheelhouse::Resource::Node
|
3
|
+
include Wheelhouse::Resource::Renderable
|
4
|
+
include Wheelhouse::Resource::Addressable
|
5
|
+
include Wheelhouse::Resource::Versioned
|
6
|
+
include Wheelhouse::Resource::Content
|
7
|
+
|
8
|
+
property :title, String, :required => true, :translate => true
|
9
|
+
property :fields, FieldCollection, :default => [Forms::Fields::FieldSet.new]
|
10
|
+
property :recipients, MongoModel::Collection[String]
|
11
|
+
property :subject, String, :default => "Form Submission"
|
12
|
+
|
13
|
+
validates_associated :fields
|
14
|
+
|
15
|
+
has_many :submissions, :class => "Forms::Submission"
|
16
|
+
|
17
|
+
activities :all
|
18
|
+
|
19
|
+
icon "wheelhouse-forms/form.png"
|
20
|
+
|
21
|
+
attr_accessor :view_context, :current_submission
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
render(view_context)
|
25
|
+
end
|
26
|
+
|
27
|
+
def render(template)
|
28
|
+
Forms::FormRenderer.new(self, current_submission, template).render
|
29
|
+
end
|
30
|
+
|
31
|
+
def submit(params)
|
32
|
+
submission = submissions.build(:params => params)
|
33
|
+
|
34
|
+
if submission.save
|
35
|
+
deliver(submission)
|
36
|
+
@success = true
|
37
|
+
else
|
38
|
+
self.current_submission = submission
|
39
|
+
@success = false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def deliver(submission)
|
44
|
+
Forms::Mailer.submission(self, submission).deliver unless recipients.empty?
|
45
|
+
rescue
|
46
|
+
# Mail delivery failed
|
47
|
+
end
|
48
|
+
|
49
|
+
def success?
|
50
|
+
@success
|
51
|
+
end
|
52
|
+
|
53
|
+
def first_content_field
|
54
|
+
@first_content_field ||= fields.flatten.find { |f| f.respond_to?(:label) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def recipients=(recipients)
|
58
|
+
recipients = recipients.split(/,/) if recipients.is_a?(String)
|
59
|
+
write_attribute(:recipients, recipients.map(&:strip))
|
60
|
+
end
|
61
|
+
|
62
|
+
def handler
|
63
|
+
Forms::FormHandler
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class Forms::Submission < Wheelhouse::BasicResource
|
2
|
+
class Parameters < Hash
|
3
|
+
def to_mongo
|
4
|
+
result = []
|
5
|
+
each do |key, value|
|
6
|
+
result << [key, value]
|
7
|
+
end
|
8
|
+
result
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.cast(params)
|
12
|
+
case params
|
13
|
+
when Hash
|
14
|
+
self[params]
|
15
|
+
when Array
|
16
|
+
params.each_with_object({}) { |v, hash| hash[v[0]] = v[1] }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.from_mongo(params)
|
21
|
+
cast(params)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
include Wheelhouse::Resource::AdminPath
|
26
|
+
|
27
|
+
property :params, Parameters
|
28
|
+
timestamps!
|
29
|
+
|
30
|
+
belongs_to :form, :class => "Forms::Form"
|
31
|
+
|
32
|
+
default_scope order(:created_at.desc)
|
33
|
+
|
34
|
+
validate do
|
35
|
+
form.fields.flatten.each do |field|
|
36
|
+
if field.required? && value_for(field).blank?
|
37
|
+
errors.add(field.label, "This field is required")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def value_for(field)
|
43
|
+
params[field.label]
|
44
|
+
end
|
45
|
+
|
46
|
+
def admin_path
|
47
|
+
form_submission_path(form_id, id)
|
48
|
+
end
|
49
|
+
|
50
|
+
def admin_url
|
51
|
+
form_submission_url(form, id, :host => form.site.domain)
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Forms::CheckboxesRenderer < Forms::FieldRenderer
|
2
|
+
include Forms::LabelledFieldRenderer
|
3
|
+
|
4
|
+
def render
|
5
|
+
super { content_tag(:ul, safe_join(list_items, "\n")) }
|
6
|
+
end
|
7
|
+
|
8
|
+
protected
|
9
|
+
def list_items
|
10
|
+
field.options.map { |o| content_tag(:li, checkbox(o)) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def checkbox(option)
|
14
|
+
content_tag(:label, :class => "option #{option.parameterize}") do
|
15
|
+
check_box_tag("#{name}[]", option, (value || []).include?(option), :id => nil) + " " + option
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Forms::FieldCollectionRenderer
|
2
|
+
include ActionView::Helpers::OutputSafetyHelper
|
3
|
+
|
4
|
+
attr_reader :collection, :submission, :template
|
5
|
+
|
6
|
+
def initialize(collection, submission, template)
|
7
|
+
@collection, @submission, @template = collection, submission, template
|
8
|
+
end
|
9
|
+
|
10
|
+
def render
|
11
|
+
safe_join(collection.map { |field| field.render(submission, template) }, "\n")
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class Forms::FieldRenderer
|
2
|
+
include ActionView::Helpers::FormTagHelper
|
3
|
+
include ActionView::Helpers::OutputSafetyHelper
|
4
|
+
|
5
|
+
attr_accessor :output_buffer
|
6
|
+
attr_reader :field, :submission, :template
|
7
|
+
|
8
|
+
def initialize(field, submission, template)
|
9
|
+
@field, @submission, @template = field, submission, template
|
10
|
+
end
|
11
|
+
|
12
|
+
def render
|
13
|
+
content_tag(:div, :class => classes.join(" ")) do
|
14
|
+
concat yield if block_given?
|
15
|
+
concat content_tag(:p, error, :class => "error") if has_errors?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
def name
|
21
|
+
"submission[#{reference}]"
|
22
|
+
end
|
23
|
+
|
24
|
+
def reference
|
25
|
+
field.label
|
26
|
+
end
|
27
|
+
|
28
|
+
def field_class
|
29
|
+
field.class.partial.dasherize
|
30
|
+
end
|
31
|
+
|
32
|
+
def classes
|
33
|
+
classes = ["field", field_class]
|
34
|
+
classes << reference.parameterize
|
35
|
+
classes << "required" if field.required?
|
36
|
+
classes << "error" if has_errors?
|
37
|
+
classes.uniq
|
38
|
+
end
|
39
|
+
|
40
|
+
def value
|
41
|
+
submission.value_for(field) if submission
|
42
|
+
end
|
43
|
+
|
44
|
+
def has_errors?
|
45
|
+
submission && submission.errors[field.label].any?
|
46
|
+
end
|
47
|
+
|
48
|
+
def error
|
49
|
+
submission.errors[field.label].first
|
50
|
+
end
|
51
|
+
|
52
|
+
def html_options
|
53
|
+
options = {}
|
54
|
+
options[:required] = "required" if field.required?
|
55
|
+
options
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class Forms::FieldSetRenderer < Forms::FieldRenderer
|
2
|
+
def render
|
3
|
+
content_tag(:fieldset, :class => field.legend? ? field.legend.parameterize : '') do
|
4
|
+
ActiveSupport::SafeBuffer.new.tap do |result|
|
5
|
+
result << content_tag(:legend, field.legend) if field.legend?
|
6
|
+
result << field.fields.render(submission, template)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Forms::FormRenderer
|
2
|
+
include ActionView::Helpers::FormTagHelper
|
3
|
+
|
4
|
+
attr_accessor :output_buffer
|
5
|
+
attr_reader :form, :submission, :template
|
6
|
+
|
7
|
+
def initialize(form, submission, template)
|
8
|
+
@form, @submission, @template = form, submission, template
|
9
|
+
end
|
10
|
+
|
11
|
+
def render
|
12
|
+
form_tag(form.path) do
|
13
|
+
concat form.fields.render(submission, template)
|
14
|
+
concat default_submit_button unless has_submit_button?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def protect_against_forgery?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def has_submit_button?
|
24
|
+
form.fields.flatten.any? { |f| f.is_a?(Forms::Fields::SubmitButton) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def default_submit_button
|
28
|
+
content_tag(:div, submit_tag("Submit"), :class => "submit")
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Forms::RadioButtonsRenderer < Forms::FieldRenderer
|
2
|
+
include Forms::LabelledFieldRenderer
|
3
|
+
|
4
|
+
def render
|
5
|
+
super { content_tag(:ul, safe_join(list_items, "\n")) }
|
6
|
+
end
|
7
|
+
|
8
|
+
protected
|
9
|
+
def list_items
|
10
|
+
field.options.map { |o| content_tag(:li, radio_button(o)) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def radio_button(option)
|
14
|
+
content_tag(:label, :class => "option #{option.parameterize}") do
|
15
|
+
radio_button_tag(name, option, value == option, :id => nil) + " " + option
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
= form_field(checkboxes, :index => index, :prefix => prefix, :class => "checkboxes") do |f|
|
2
|
+
= f.text_field :label, :title => "Checkboxes Label", :placeholder => "Checkboxes Label", :id => nil
|
3
|
+
= f.required_field_checkbox
|
4
|
+
|
5
|
+
%ul.options
|
6
|
+
%li
|
7
|
+
%label Options:
|
8
|
+
|
9
|
+
- checkboxes.options(true).each do |option|
|
10
|
+
%li= text_field_tag "#{prefix}[options][]", option, :id => nil
|
@@ -0,0 +1,4 @@
|
|
1
|
+
= form_field(countries_dropdown, :index => index, :prefix => prefix, :class => "countries-dropdown", :icon => "countries") do |f|
|
2
|
+
= f.text_field :label, :title => "Countries Dropdown Label", :placeholder => "Countries Dropdown Label", :id => nil
|
3
|
+
= f.required_field_checkbox
|
4
|
+
|
@@ -0,0 +1,4 @@
|
|
1
|
+
= form_field(custom_field, :index => index, :prefix => prefix, :class => "custom-field", :icon => "custom") do |f|
|
2
|
+
= f.text_field :label, :title => "Custom Field Label", :placeholder => "Custom Field Label", :id => nil
|
3
|
+
= f.text_field :partial, :title => "Partial", :placeholder => "Partial", :id => nil
|
4
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
.field-set{ "data-index" => index }
|
2
|
+
= hidden_field_tag "#{prefix}[type]", field_set.type.demodulize, :id => nil
|
3
|
+
|
4
|
+
.drag
|
5
|
+
|
6
|
+
.drag-area
|
7
|
+
= label_tag "fieldset_#{index}_legend", "Fieldset Legend:"
|
8
|
+
= text_field_tag "#{prefix}[legend]", field_set.legend, :id => "fieldset_#{index}_legend"
|
9
|
+
|
10
|
+
%span.note (leave blank for none)
|
11
|
+
|
12
|
+
.fields{ "data-prefix" => "form[fields][#{index}][fields]" }
|
13
|
+
= render_fields(field_set.fields, "form[fields][#{index}][fields]")
|
14
|
+
|
15
|
+
= link_to "Delete", '#', :class => 'delete'
|
16
|
+
|