formbuilder-rb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +24 -0
  4. data/app/controllers/formbuilder/forms_controller.rb +53 -0
  5. data/app/models/formbuilder/entry_attachment.rb +15 -0
  6. data/app/models/formbuilder/form.rb +12 -0
  7. data/app/models/formbuilder/response_field.rb +85 -0
  8. data/app/models/formbuilder/response_field_address.rb +349 -0
  9. data/app/models/formbuilder/response_field_checkboxes.rb +68 -0
  10. data/app/models/formbuilder/response_field_date.rb +46 -0
  11. data/app/models/formbuilder/response_field_dropdown.rb +30 -0
  12. data/app/models/formbuilder/response_field_email.rb +26 -0
  13. data/app/models/formbuilder/response_field_file.rb +44 -0
  14. data/app/models/formbuilder/response_field_number.rb +33 -0
  15. data/app/models/formbuilder/response_field_paragraph.rb +21 -0
  16. data/app/models/formbuilder/response_field_price.rb +47 -0
  17. data/app/models/formbuilder/response_field_radio.rb +52 -0
  18. data/app/models/formbuilder/response_field_section_break.rb +17 -0
  19. data/app/models/formbuilder/response_field_text.rb +16 -0
  20. data/app/models/formbuilder/response_field_time.rb +53 -0
  21. data/app/models/formbuilder/response_field_website.rb +31 -0
  22. data/app/uploaders/formbuilder/entry_attachment_uploader.rb +26 -0
  23. data/db/migrate/20130924185726_create_formbuilder_forms.rb +10 -0
  24. data/db/migrate/20130924185814_create_formbuilder_response_fields.rb +16 -0
  25. data/db/migrate/20130924185815_create_formbuilder_entry_attachments.rb +10 -0
  26. data/lib/formbuilder/engine.rb +5 -0
  27. data/lib/formbuilder/entry.rb +242 -0
  28. data/lib/formbuilder/entry_renderer.rb +47 -0
  29. data/lib/formbuilder/entry_table_renderer.rb +58 -0
  30. data/lib/formbuilder/entry_validator.rb +107 -0
  31. data/lib/formbuilder/form_renderer.rb +102 -0
  32. data/lib/formbuilder/version.rb +3 -0
  33. data/lib/formbuilder.rb +12 -0
  34. data/lib/tasks/formbuilder_tasks.rake +4 -0
  35. metadata +258 -0
@@ -0,0 +1,30 @@
1
+ module Formbuilder
2
+ class ResponseFieldDropdown < ResponseField
3
+
4
+ after_initialize -> {
5
+ @options_field = true
6
+ @field_type = 'dropdown'
7
+ }
8
+
9
+ def render_input(value, opts = {})
10
+ options = ""
11
+ options += "<option></option>" if self[:field_options]['include_blank_option']
12
+
13
+ Array(self[:field_options]['options']).each_with_index do |option, i|
14
+ selected = (value == option["label"]) || (value.blank? && option["checked"])
15
+ options += "<option value='#{option["label"]}' #{selected ? 'selected' : ''}>#{option['label']}</option>"
16
+ end
17
+
18
+ """
19
+ <select name='response_fields[#{self[:id]}]'>
20
+ #{options}
21
+ </select>
22
+ """
23
+ end
24
+
25
+ def render_entry(value, opts = {})
26
+ value
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ module Formbuilder
2
+ class ResponseFieldEmail < ResponseField
3
+
4
+ include ActionView::Helpers::TagHelper
5
+
6
+ after_initialize -> {
7
+ @field_type = 'email'
8
+ }
9
+
10
+ def render_input(value, opts = {})
11
+ tag(:input, type: 'text', name: "response_fields[#{self.id}]", class: "rf-size-#{self[:field_options]['size']}",
12
+ data: self.length_validations, value: value)
13
+ end
14
+
15
+ def render_entry(value, opts = {})
16
+ "<a href='mailto:#{value}'>#{value}</a>"
17
+ end
18
+
19
+ def validate_response(value)
20
+ unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
21
+ "isn't a valid email address."
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,44 @@
1
+ module Formbuilder
2
+ class ResponseFieldFile < ResponseField
3
+
4
+ after_initialize -> {
5
+ @field_type = 'file'
6
+ }
7
+
8
+ # @todo dropzone?
9
+ def render_input(value, opts = {})
10
+ attachment = value && EntryAttachment.find(value)
11
+
12
+ """
13
+ <span class='existing-filename'>#{attachment.try(:upload).try(:file).try(:filename).try(:gsub, /\?.*$/, '')}</span>
14
+ <input type='file' name='response_fields[#{self[:id]}]' />
15
+ """
16
+ end
17
+
18
+ def render_entry(value, opts = {})
19
+ attachment = EntryAttachment.find(value)
20
+
21
+ return unless attachment
22
+
23
+ str = ""
24
+
25
+ str += """
26
+ <a href='#{attachment.upload.url}' target='_blank'>
27
+ """
28
+
29
+ if attachment.upload.send(:active_versions).include?(:thumb)
30
+ str += """
31
+ <img src='#{attachment.upload.thumb.url}' /><br />
32
+ """
33
+ end
34
+
35
+ str +="""
36
+ #{attachment.upload.try(:file).try(:filename).try(:gsub, /\?.*$/, '')}
37
+ </a>
38
+ """
39
+
40
+ str
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,33 @@
1
+ module Formbuilder
2
+ class ResponseFieldNumber < ResponseField
3
+
4
+ include ActionView::Helpers::TagHelper
5
+
6
+ after_initialize -> {
7
+ @sort_as_numeric = true
8
+ @field_type = 'number'
9
+ }
10
+
11
+ def render_input(value, opts = {})
12
+ str = tag(:input, type: 'text', name: "response_fields[#{self.id}]",
13
+ class: "rf-size-#{self[:field_options]['size']}", value: value)
14
+
15
+ if (units = self[:field_options]['units'].presence)
16
+ str += "<span class='units'>#{units}</span>".html_safe
17
+ end
18
+
19
+ str
20
+ end
21
+
22
+ def render_entry(value, opts = {})
23
+ value
24
+ end
25
+
26
+ def validate_response(value)
27
+ unless (Float(value) rescue nil)
28
+ "isn't a valid number."
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ module Formbuilder
2
+ class ResponseFieldParagraph < ResponseField
3
+
4
+ include ActionView::Helpers::TagHelper
5
+ include ActionView::Context
6
+
7
+ after_initialize -> {
8
+ @field_type = 'paragraph'
9
+ }
10
+
11
+ def render_input(value, opts = {})
12
+ content_tag(:textarea, name: "response_fields[#{self.id}]", class: "rf-size-#{self[:field_options]['size']}",
13
+ data: self.length_validations) { value }
14
+ end
15
+
16
+ def render_entry(value, opts = {})
17
+ ActionController::Base.helpers.simple_format(value)
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ module Formbuilder
2
+ class ResponseFieldPrice < ResponseField
3
+
4
+ after_initialize -> {
5
+ @serialized = true
6
+ @sort_as_numeric = true
7
+ @field_type = 'price'
8
+ }
9
+
10
+ def render_input(value, opts = {})
11
+ """
12
+ <div class='input-line'>
13
+ <span class='above-line'>$</span>
14
+
15
+ <span class='dollars'>
16
+ <input type='text' name='response_fields[#{self[:id]}][dollars]' value='#{value['dollars']}' />
17
+ <label>Dollars</label>
18
+ </span>
19
+
20
+ <span class='above-line'>.</span>
21
+
22
+ <span class='cents'>
23
+ <input type='text' name='response_fields[#{self[:id]}][cents]' value='#{value['cents']}' maxlength='2' />
24
+ <label>Cents</label>
25
+ </span>
26
+ </div>
27
+ """
28
+ end
29
+
30
+ def render_entry(value, opts = {})
31
+ "$#{sprintf('%.2f', "#{value['dollars']}.#{value['cents']}".to_f)}"
32
+ end
33
+
34
+ # format: [dollars] [cents]
35
+ # only one is required, and it must consist only of numbers
36
+ def validate_response(value)
37
+ value.select { |k, v| k.in?(['dollars', 'cents']) && v.present? }.each do |k, v|
38
+ unless (Float(v) rescue 0) > 0
39
+ return "isn't a valid price."
40
+ end
41
+ end
42
+
43
+ return nil
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,52 @@
1
+ module Formbuilder
2
+ class ResponseFieldRadio < ResponseField
3
+
4
+ after_initialize -> {
5
+ @options_field = true
6
+ @field_type = 'radio'
7
+ }
8
+
9
+ def render_input(value, opts = {})
10
+ value ||= {}
11
+
12
+ str = (self[:field_options]["options"] || []).each_with_index.map do |option, i|
13
+
14
+ checked = (value == option["label"]) || (value.blank? && option["checked"])
15
+
16
+ """
17
+ <label>
18
+ <input type='radio' name='response_fields[#{self[:id]}]' #{checked ? 'checked' : ''} value='#{option['label']}' />
19
+ #{option['label']}
20
+ </label>
21
+ """
22
+ end.join('')
23
+
24
+ if self[:field_options]['include_other_option']
25
+ str += """
26
+ <div class='other-option'>
27
+ <label>
28
+ <input type='radio' name='response_fields[#{self[:id]}]' #{value == 'Other' ? 'checked' : ''} value='Other' />
29
+ Other
30
+ </label>
31
+
32
+ <input type='text' name='response_fields[#{self[:id]}_other]'
33
+ value='#{opts.try(:[], :entry).try(:responses).try(:[], "#{self[:id]}_other")}' />
34
+ </div>
35
+ """
36
+ end
37
+
38
+ str
39
+ end
40
+
41
+ def render_entry(value, opts = {})
42
+ str = value
43
+
44
+ if (other = opts.try(:[], :entry).try(:responses).try(:[], "#{self.id}_other"))
45
+ str += " (#{other})"
46
+ end
47
+
48
+ str
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,17 @@
1
+ module Formbuilder
2
+ class ResponseFieldSectionBreak < ResponseField
3
+
4
+ after_initialize -> {
5
+ @input_field = false
6
+ @field_type = 'section_break'
7
+ }
8
+
9
+ def render_input(value, opts = {})
10
+ """
11
+ <label class='section-name'>#{self[:label]}</label>
12
+ <p>#{self[:field_options]['description']}</p>
13
+ """
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module Formbuilder
2
+ class ResponseFieldText < ResponseField
3
+
4
+ include ActionView::Helpers::TagHelper
5
+
6
+ after_initialize -> {
7
+ @field_type = 'text'
8
+ }
9
+
10
+ def render_input(value, opts = {})
11
+ tag(:input, type: 'text', name: "response_fields[#{self.id}]", class: "rf-size-#{self[:field_options]['size']}",
12
+ data: self.length_validations, value: value)
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,53 @@
1
+ module Formbuilder
2
+ class ResponseFieldTime < ResponseField
3
+
4
+ after_initialize -> {
5
+ @serialized = true
6
+ @sort_as_numeric = true
7
+ @field_type = 'time'
8
+ }
9
+
10
+ def render_input(value, opts = {})
11
+ """
12
+ <div class='input-line'>
13
+ <span class='hours'>
14
+ <input type='text' name='response_fields[#{self[:id]}][hours]' value='#{value['hours']}' maxlength='2' />
15
+ <label>HH</label>
16
+ </span>
17
+
18
+ <span class='above-line'>:</span>
19
+
20
+ <span class='minutes'>
21
+ <input type='text' name='response_fields[#{self[:id]}][minutes]' value='#{value['minutes']}' maxlength='2' />
22
+ <label>MM</label>
23
+ </span>
24
+
25
+ <span class='above-line'>:</span>
26
+
27
+ <span class='seconds'>
28
+ <input type='text' name='response_fields[#{self[:id]}][seconds]' value='#{value['seconds']}' maxlength='2' />
29
+ <label>SS</label>
30
+ </span>
31
+
32
+ <span class='am_pm'>
33
+ <select name='response_fields[#{self[:id]}][am_pm]'>
34
+ <option value='AM' #{value['am_pm'] == "AM" ? 'selected' : ''}>AM</option>
35
+ <option value='PM' #{value['am_pm'] == "PM" ? 'selected' : ''}>PM</option>
36
+ </select>
37
+ </span>
38
+ </div>
39
+ """
40
+ end
41
+
42
+ def render_entry(value, opts = {})
43
+ "#{value['hours']}:#{value['minutes']}#{if !value['seconds'].blank? then ':'+value['seconds'] end} #{value['am_pm']}"
44
+ end
45
+
46
+ def validate_response(value)
47
+ if !value['hours'].to_i.between?(1, 12) || !value['minutes'].to_i.between?(0, 60) || !value['seconds'].to_i.between?(0, 60)
48
+ "isn't a valid time."
49
+ end
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,31 @@
1
+ module Formbuilder
2
+ class ResponseFieldWebsite < ResponseField
3
+
4
+ include ActionView::Helpers::TagHelper
5
+
6
+ after_initialize -> {
7
+ @field_type = 'website'
8
+ }
9
+
10
+ def render_input(value, opts = {})
11
+ tag(:input, type: 'text', name: "response_fields[#{self.id}]", class: "rf-size-#{self[:field_options]['size']}",
12
+ value: value, placeholder: 'http://')
13
+ end
14
+
15
+ def render_entry(value, opts = {})
16
+ "<a href='#{value}' target='_blank' rel='nofollow'>#{value}</a>"
17
+ end
18
+
19
+ def validate_response(value)
20
+ require 'uri'
21
+
22
+ # add http if not present
23
+ value = "http://#{value}" unless value[/^http:\/\//] || value[/^https:\/\//]
24
+
25
+ if !(value =~ URI::regexp) # this doesn't really validate, since almost *anything* matches
26
+ "isn't a valid URL."
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ require 'carrierwave/processing/mime_types'
2
+
3
+ module Formbuilder
4
+ class EntryAttachmentUploader < CarrierWave::Uploader::Base
5
+ include CarrierWave::MimeTypes
6
+ include CarrierWave::RMagick
7
+
8
+ @fog_public = false
9
+
10
+ process :set_content_type
11
+
12
+ version :thumb, :if => :image? do
13
+ process resize_to_limit: [250, 250]
14
+ end
15
+
16
+ def store_dir
17
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
18
+ end
19
+
20
+ protected
21
+ def image?(file)
22
+ content_type = file.content_type || model.try(:content_type)
23
+ content_type && content_type.include?('image')
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ class CreateFormbuilderForms < ActiveRecord::Migration
2
+ def change
3
+ create_table :formbuilder_forms do |t|
4
+ t.integer :formable_id
5
+ t.string :formable_type
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ class CreateFormbuilderResponseFields < ActiveRecord::Migration
2
+ def change
3
+ create_table :formbuilder_response_fields do |t|
4
+ t.integer :form_id
5
+ t.text :label
6
+ t.string :type
7
+ t.text :field_options
8
+ t.integer :sort_order
9
+ t.boolean :required, default: false
10
+ t.boolean :blind, default: false
11
+ t.boolean :admin_only, default: false
12
+
13
+ t.timestamps
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ class CreateFormbuilderEntryAttachments < ActiveRecord::Migration
2
+ def change
3
+ create_table :formbuilder_entry_attachments do |t|
4
+ t.string :upload
5
+ t.string :content_type
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module Formbuilder
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Formbuilder
4
+ end
5
+ end