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,19 @@
|
|
1
|
+
require_dependency "forms/csv_exporter"
|
2
|
+
|
3
|
+
class Forms::SubmissionsController < Wheelhouse::ResourceController
|
4
|
+
belongs_to :form, :class_name => Forms::Form
|
5
|
+
self.resource_class = Forms::Submission
|
6
|
+
|
7
|
+
manage_site_breadcrumb
|
8
|
+
breadcrumb { [parent.label, parent] }
|
9
|
+
|
10
|
+
actions :show, :destroy
|
11
|
+
|
12
|
+
respond_to :csv
|
13
|
+
|
14
|
+
def index
|
15
|
+
respond_with(parent) do |format|
|
16
|
+
format.csv { render :text => Forms::CsvExporter.new(parent).to_csv }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Forms::FormHandler < Wheelhouse::ResourceHandler
|
2
|
+
skip_before_filter :verify_authenticity_token
|
3
|
+
|
4
|
+
before_filter :set_form_context
|
5
|
+
|
6
|
+
get do
|
7
|
+
end
|
8
|
+
|
9
|
+
post do
|
10
|
+
@form.submit(params[:submission])
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
def set_form_context
|
15
|
+
@form.view_context = view_context
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Forms::FormsHelper
|
2
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
3
|
+
def required_field_checkbox
|
4
|
+
@template.content_tag(:label, :class => "required") do
|
5
|
+
check_box(:required, :id => nil) + " This field is required"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def form_field(field, options={}, &block)
|
11
|
+
builder = FormBuilder.new(options[:prefix], field, self, {}, block)
|
12
|
+
icon = options[:icon] || field.class.model_name.demodulize.underscore.dasherize
|
13
|
+
|
14
|
+
content_tag(:div, :class => options[:class], :data => { :index => options[:index] }) do
|
15
|
+
concat builder.hidden_field(:type, :value => field.type.demodulize, :id => nil)
|
16
|
+
|
17
|
+
concat content_tag(:div, image_tag("wheelhouse-forms/#{icon}.png", :alt => field.class.model_name.human, :title => field.class.model_name.human), :class => "drag")
|
18
|
+
|
19
|
+
concat content_tag(:div, capture(builder, &block), :class => "drag-area")
|
20
|
+
|
21
|
+
concat link_to("Delete", '#', :class => 'delete')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def render_fields(fields, prefix)
|
26
|
+
fields.map_with_index do |field, index|
|
27
|
+
render(:partial => field.class.partial, :object => field, :locals => { :index => index, :prefix => "#{prefix}[#{index}]" })
|
28
|
+
end.join("\n").html_safe
|
29
|
+
end
|
30
|
+
|
31
|
+
def field_template(id, klass)
|
32
|
+
jquery_template_tag(id) do
|
33
|
+
render :partial => klass.partial, :object => klass.new, :locals => { :index => "${index}", :prefix => "${prefix}" }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Forms::MailerHelper
|
2
|
+
def render_field(field)
|
3
|
+
case field
|
4
|
+
when Forms::Fields::FieldSet
|
5
|
+
render_fieldset(field)
|
6
|
+
when Forms::Fields::CustomField
|
7
|
+
render_custom_field(field)
|
8
|
+
when Forms::Fields::Checkboxes
|
9
|
+
render_array(field, @submission.value_for(field) || ["None given"])
|
10
|
+
when Forms::Fields::ContentField
|
11
|
+
# Nothing
|
12
|
+
else
|
13
|
+
render_text_field(field, @submission.value_for(field))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def render_fieldset(fieldset)
|
19
|
+
content_tag(:div, :class => "fieldset") do
|
20
|
+
concat content_tag(:h3, fieldset.legend) if fieldset.legend?
|
21
|
+
concat safe_join(fieldset.fields.map { |f| render_field(f) }, "\n")
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def render_custom_field(field)
|
27
|
+
value = @submission.value_for(field)
|
28
|
+
|
29
|
+
case value
|
30
|
+
when Array
|
31
|
+
render_array(field, value)
|
32
|
+
when Hash
|
33
|
+
render_hash(field, value)
|
34
|
+
else
|
35
|
+
render_text_field(field, value)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def render_array(field, array)
|
40
|
+
labelled_field(field) do
|
41
|
+
concat content_tag(:ul, safe_join(array.map { |i| content_tag(:li, i) }))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def render_hash(field, hash)
|
46
|
+
labelled_field(field) do
|
47
|
+
concat content_tag(:ul, safe_join(hash.map { |k, v|
|
48
|
+
content_tag(:li, content_tag(:strong, k) + ": " + v)
|
49
|
+
}))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def render_text_field(field, value)
|
54
|
+
labelled_field(field) do
|
55
|
+
concat field.is_a?(Forms::Fields::TextArea) ? tag(:br) : " "
|
56
|
+
concat value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def labelled_field(field)
|
61
|
+
content_tag(:p, :class => "field") do
|
62
|
+
concat content_tag(:strong, field.label + ":")
|
63
|
+
yield
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Forms::SubmissionsHelper
|
2
|
+
def render_field(field)
|
3
|
+
case field
|
4
|
+
when Forms::Fields::FieldSet
|
5
|
+
render_fieldset(field)
|
6
|
+
when Forms::Fields::CustomField
|
7
|
+
render_custom_field(field)
|
8
|
+
when Forms::Fields::Checkboxes
|
9
|
+
labelled_field(field) do
|
10
|
+
value = @submission.value_for(field)
|
11
|
+
render_array(field, value || [""])
|
12
|
+
end
|
13
|
+
when Forms::Fields::TextArea
|
14
|
+
labelled_field(field) do
|
15
|
+
value = @submission.value_for(field)
|
16
|
+
form.text_area field.label, :value => value || "", :readonly => true, :rows => 5
|
17
|
+
end
|
18
|
+
when Forms::Fields::ContentField
|
19
|
+
# Nothing
|
20
|
+
else
|
21
|
+
labelled_field(field) do
|
22
|
+
value = @submission.value_for(field)
|
23
|
+
form.text_field field.label, :value => value || "", :readonly => true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def labelled_field(field)
|
30
|
+
field(field.label, :label => field.label.html_safe) do
|
31
|
+
yield
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def render_fieldset(fieldset)
|
36
|
+
content_tag(:div, :class => "shaded") do
|
37
|
+
concat content_tag(:h2, fieldset.legend) if fieldset.legend?
|
38
|
+
concat safe_join(fieldset.fields.map { |f| render_field(f) })
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def render_custom_field(field)
|
44
|
+
labelled_field(field) do
|
45
|
+
value = @submission.value_for(field)
|
46
|
+
|
47
|
+
case value
|
48
|
+
when Array
|
49
|
+
render_array(field, value)
|
50
|
+
when Hash
|
51
|
+
render_hash(field, value)
|
52
|
+
else
|
53
|
+
form.text_field field.label, :value => value || "", :readonly => true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def render_array(field, array)
|
59
|
+
content_tag(:ul, safe_join(array.map { |value|
|
60
|
+
content_tag(:li, form.text_field("#{field.label}[]", :value => value || "", :readonly => true))
|
61
|
+
}))
|
62
|
+
end
|
63
|
+
|
64
|
+
def render_hash(field, hash)
|
65
|
+
content_tag(:div, :class => "inline") do
|
66
|
+
safe_join(hash.map { |key, value|
|
67
|
+
form.label("#{field.label} #{key}", key) + form.text_field("#{field.label} #{key}", :value => value || "", :readonly => true, :size => nil)
|
68
|
+
})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Forms::Mailer < ActionMailer::Base
|
2
|
+
default :template_path => "form"
|
3
|
+
|
4
|
+
def submission(form, submission)
|
5
|
+
@form, @submission = form, submission
|
6
|
+
|
7
|
+
mail(:from => "no-reply@#{form.site.domain}",
|
8
|
+
:to => form.recipients,
|
9
|
+
:subject => form.subject)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Forms::FieldCollection < MongoModel::Collection[Forms::Fields::Field]
|
2
|
+
def map_with_index
|
3
|
+
result = []
|
4
|
+
each_with_index { |item, index| result[index] = yield(item, index) }
|
5
|
+
result
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.cast(collection)
|
9
|
+
case collection
|
10
|
+
when Hash
|
11
|
+
sorted_attrs = collection.sort { |(a, _), (b, _)| a.to_i <=> b.to_i }.map { |_, attrs| attrs }
|
12
|
+
super(sorted_attrs)
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def render(submission, template)
|
19
|
+
Forms::FieldCollectionRenderer.new(self, submission, template).render
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Forms::Fields
|
2
|
+
class CountriesDropdown < Field
|
3
|
+
property :label, String, :default => "Country", :required => true
|
4
|
+
property :required, Boolean, :default => false
|
5
|
+
|
6
|
+
self.renderer = Forms::SelectFieldRenderer
|
7
|
+
|
8
|
+
def options
|
9
|
+
COUNTRIES
|
10
|
+
end
|
11
|
+
|
12
|
+
COUNTRIES = Forms::Plugin.load_yaml("countries.yml")
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Forms::Fields
|
2
|
+
class Field < Wheelhouse::EmbeddedResource
|
3
|
+
class_attribute :renderer
|
4
|
+
self.renderer = Forms::FieldRenderer
|
5
|
+
|
6
|
+
def render(submission, template)
|
7
|
+
self.class.renderer.new(self, submission, template).render
|
8
|
+
end
|
9
|
+
|
10
|
+
def required?
|
11
|
+
read_attribute(:required)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.partial
|
15
|
+
name.demodulize.underscore
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.cast(attrs)
|
19
|
+
case attrs
|
20
|
+
when Hash
|
21
|
+
type = attrs.delete('type')
|
22
|
+
Forms::Fields.const_get(type).new(attrs)
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Forms::Fields
|
2
|
+
module OptionedField
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
property :options, MongoModel::Collection[String]
|
7
|
+
end
|
8
|
+
|
9
|
+
def options=(options)
|
10
|
+
write_attribute(:options, options.reject(&:blank?))
|
11
|
+
end
|
12
|
+
|
13
|
+
def options(include_blank = false)
|
14
|
+
read_attribute(:options) + (include_blank ? [""] : [])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Forms::Fields
|
2
|
+
class StatesDropdown < Field
|
3
|
+
property :label, String, :default => "State", :required => true
|
4
|
+
property :country, String, :required => true
|
5
|
+
property :required, Boolean, :default => false
|
6
|
+
|
7
|
+
self.renderer = Forms::SelectFieldRenderer
|
8
|
+
|
9
|
+
def options
|
10
|
+
STATES[country]
|
11
|
+
end
|
12
|
+
|
13
|
+
STATES = Forms::Plugin.load_yaml("states.yml").tap { |hash| hash.each { |k, v| hash[k] = v.invert } }
|
14
|
+
end
|
15
|
+
end
|