wheelhouse-forms 1.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/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
|