formbuilder-rb 0.0.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +14 -0
  7. data/Gemfile.lock +219 -0
  8. data/Guardfile +17 -0
  9. data/{MIT-LICENSE → LICENSE.md} +1 -1
  10. data/README.md +86 -0
  11. data/app/controllers/formbuilder/concerns/forms_controller.rb +59 -0
  12. data/app/models/formbuilder/entry_attachment.rb +2 -8
  13. data/app/models/formbuilder/form.rb +53 -0
  14. data/app/models/formbuilder/response_field.rb +23 -10
  15. data/app/models/formbuilder/response_field_address.rb +12 -1
  16. data/app/models/formbuilder/response_field_checkboxes.rb +38 -0
  17. data/app/models/formbuilder/response_field_date.rb +7 -1
  18. data/app/models/formbuilder/response_field_dropdown.rb +2 -1
  19. data/app/models/formbuilder/response_field_email.rb +14 -2
  20. data/app/models/formbuilder/response_field_file.rb +75 -20
  21. data/app/models/formbuilder/response_field_number.rb +9 -2
  22. data/app/models/formbuilder/response_field_page_break.rb +13 -0
  23. data/app/models/formbuilder/response_field_paragraph.rb +19 -3
  24. data/app/models/formbuilder/response_field_price.rb +10 -6
  25. data/app/models/formbuilder/response_field_radio.rb +11 -2
  26. data/app/models/formbuilder/response_field_section_break.rb +12 -2
  27. data/app/models/formbuilder/response_field_table.rb +222 -0
  28. data/app/models/formbuilder/response_field_text.rb +9 -2
  29. data/app/models/formbuilder/response_field_time.rb +8 -1
  30. data/app/models/formbuilder/response_field_website.rb +26 -2
  31. data/app/uploaders/formbuilder/entry_attachment_uploader.rb +11 -1
  32. data/bin/rails +8 -0
  33. data/circle.yml +9 -0
  34. data/config/spring.rb +1 -0
  35. data/db/migrate/20130924185815_create_formbuilder_entry_attachments.rb +1 -0
  36. data/formbuilder-rb.gemspec +41 -0
  37. data/formbuilder-rb.sublime-project +20 -0
  38. data/lib/formbuilder.rb +8 -3
  39. data/lib/formbuilder/entry.rb +102 -159
  40. data/lib/formbuilder/entry_validator.rb +13 -6
  41. data/lib/formbuilder/version.rb +1 -1
  42. data/lib/formbuilder/views/entry_dl.rb +56 -0
  43. data/lib/formbuilder/views/form.rb +81 -0
  44. data/lib/formbuilder/views/form_field.rb +45 -0
  45. data/spec/controllers/formbuilder/forms_controller_spec.rb +40 -0
  46. data/spec/dummy/.ruby-gemset +1 -0
  47. data/spec/dummy/.ruby-version +1 -0
  48. data/spec/dummy/README.rdoc +28 -0
  49. data/spec/dummy/Rakefile +6 -0
  50. data/spec/dummy/app/assets/images/.keep +0 -0
  51. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  52. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  53. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  54. data/spec/dummy/app/controllers/forms_controller.rb +3 -0
  55. data/spec/dummy/app/controllers/test_controller.rb +57 -0
  56. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  57. data/spec/dummy/app/mailers/.keep +0 -0
  58. data/spec/dummy/app/models/concerns/.keep +0 -0
  59. data/spec/dummy/app/models/entry.rb +7 -0
  60. data/spec/dummy/app/models/entry_with_alternate_column_name.rb +11 -0
  61. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  62. data/spec/dummy/app/views/test/_form.rb +2 -0
  63. data/spec/dummy/app/views/test/render_entry.html.erb +1 -0
  64. data/spec/dummy/app/views/test/show_form.html.erb +1 -0
  65. data/spec/dummy/bin/bundle +3 -0
  66. data/spec/dummy/bin/rails +4 -0
  67. data/spec/dummy/bin/rake +4 -0
  68. data/spec/dummy/config.ru +4 -0
  69. data/spec/dummy/config/application.rb +25 -0
  70. data/spec/dummy/config/boot.rb +5 -0
  71. data/spec/dummy/config/database.yml.ci +15 -0
  72. data/spec/dummy/config/database.yml.example +15 -0
  73. data/spec/dummy/config/environment.rb +5 -0
  74. data/spec/dummy/config/environments/development.rb +29 -0
  75. data/spec/dummy/config/environments/production.rb +80 -0
  76. data/spec/dummy/config/environments/test.rb +52 -0
  77. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  78. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  79. data/spec/dummy/config/initializers/inflections.rb +16 -0
  80. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  81. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  82. data/spec/dummy/config/initializers/session_store.rb +3 -0
  83. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  84. data/spec/dummy/config/locales/en.yml +23 -0
  85. data/spec/dummy/config/routes.rb +12 -0
  86. data/spec/dummy/db/migrate/20130924182939_create_entries.rb +13 -0
  87. data/spec/dummy/db/migrate/20130924192151_create_formbuilder_forms.formbuilder.rb +11 -0
  88. data/spec/dummy/db/migrate/20130924192152_create_formbuilder_response_fields.formbuilder.rb +17 -0
  89. data/spec/dummy/db/migrate/20130926205845_create_formbuilder_entry_attachments.formbuilder.rb +12 -0
  90. data/spec/dummy/db/migrate/20140128000000_create_entry_with_alternate_column_names.rb +13 -0
  91. data/spec/dummy/db/schema.rb +64 -0
  92. data/spec/dummy/lib/assets/.keep +0 -0
  93. data/spec/dummy/log/.keep +0 -0
  94. data/spec/dummy/public/404.html +58 -0
  95. data/spec/dummy/public/422.html +58 -0
  96. data/spec/dummy/public/500.html +57 -0
  97. data/spec/dummy/public/favicon.ico +0 -0
  98. data/spec/dummy/test/fixtures/entries.yml +9 -0
  99. data/spec/dummy/test/fixtures/response_fields.yml +19 -0
  100. data/spec/dummy/test/models/entry_test.rb +7 -0
  101. data/spec/dummy/test/models/response_field_test.rb +7 -0
  102. data/spec/factories/formbuilder_forms.rb +45 -0
  103. data/spec/features/form_renderer_spec.rb +30 -0
  104. data/spec/features/submitting_an_entry_spec.rb +79 -0
  105. data/spec/fixtures/test_files/text.txt +1 -0
  106. data/spec/fixtures/test_files/text2.txt +1 -0
  107. data/spec/lib/formbuilder/entry_spec.rb +199 -0
  108. data/spec/lib/formbuilder/entry_validator_spec.rb +215 -0
  109. data/spec/lib/formbuilder/entry_with_alternate_column_name_spec.rb +37 -0
  110. data/spec/lib/formbuilder/views/entry_dl_spec.rb +38 -0
  111. data/spec/models/formbuilder/entry_attachment_spec.rb +17 -0
  112. data/spec/models/formbuilder/form_spec.rb +100 -0
  113. data/spec/models/formbuilder/response_field_address_spec.rb +25 -0
  114. data/spec/models/formbuilder/response_field_checkboxes_spec.rb +57 -0
  115. data/spec/models/formbuilder/response_field_file_spec.rb +80 -0
  116. data/spec/models/formbuilder/response_field_paragraph_spec.rb +22 -0
  117. data/spec/models/formbuilder/response_field_radio_spec.rb +30 -0
  118. data/spec/models/formbuilder/response_field_spec.rb +21 -0
  119. data/spec/models/formbuilder/response_field_table_spec.rb +124 -0
  120. data/spec/spec_helper.rb +25 -0
  121. data/spec/support/database_cleaner.rb +21 -0
  122. data/spec/support/submitting_an_entry_spec_helper.rb +151 -0
  123. metadata +286 -44
  124. data/app/controllers/formbuilder/forms_controller.rb +0 -53
  125. data/lib/formbuilder/entry_renderer.rb +0 -47
  126. data/lib/formbuilder/entry_table_renderer.rb +0 -58
  127. data/lib/formbuilder/form_renderer.rb +0 -102
@@ -5,6 +5,7 @@ module Formbuilder
5
5
  @serialized = true
6
6
  @sort_as_numeric = true
7
7
  @field_type = 'price'
8
+ @search_type = 'number'
8
9
  }
9
10
 
10
11
  def render_input(value, opts = {})
@@ -13,7 +14,7 @@ module Formbuilder
13
14
  <span class='above-line'>$</span>
14
15
 
15
16
  <span class='dollars'>
16
- <input type='text' name='response_fields[#{self[:id]}][dollars]' value='#{value['dollars']}' />
17
+ <input type='text' name='response_fields[#{self[:id]}][dollars]' id='response_fields_#{self[:id]}' value='#{value['dollars']}' />
17
18
  <label>Dollars</label>
18
19
  </span>
19
20
 
@@ -34,13 +35,16 @@ module Formbuilder
34
35
  # format: [dollars] [cents]
35
36
  # only one is required, and it must consist only of numbers
36
37
  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
38
+ if value.select { |k, v| k.in?(['dollars', 'cents']) && v.present? }
39
+ .find { |k, v| (Float(v) rescue nil).nil? }
40
+ .present?
41
+
42
+ "isn't a valid price."
41
43
  end
44
+ end
42
45
 
43
- return nil
46
+ def sortable_value(value)
47
+ "#{value['dollars'] || '0'}.#{value['cents'] || '0'}".to_f
44
48
  end
45
49
 
46
50
  end
@@ -4,6 +4,7 @@ module Formbuilder
4
4
  after_initialize -> {
5
5
  @options_field = true
6
6
  @field_type = 'radio'
7
+ @search_type = 'one_option'
7
8
  }
8
9
 
9
10
  def render_input(value, opts = {})
@@ -30,7 +31,7 @@ module Formbuilder
30
31
  </label>
31
32
 
32
33
  <input type='text' name='response_fields[#{self[:id]}_other]'
33
- value='#{opts.try(:[], :entry).try(:responses).try(:[], "#{self[:id]}_other")}' />
34
+ value='#{opts.try(:[], :entry).try(:get_responses).try(:[], "#{self[:id]}_other")}' />
34
35
  </div>
35
36
  """
36
37
  end
@@ -41,12 +42,20 @@ module Formbuilder
41
42
  def render_entry(value, opts = {})
42
43
  str = value
43
44
 
44
- if (other = opts.try(:[], :entry).try(:responses).try(:[], "#{self.id}_other"))
45
+ if (other = opts.try(:[], :entry).try(:get_responses).try(:[], "#{self.id}_other"))
45
46
  str += " (#{other})"
46
47
  end
47
48
 
48
49
  str
49
50
  end
50
51
 
52
+ def transform_raw_value(raw_value, entry, opts = {})
53
+ entry.get_responses["#{self.id}_other"] = (raw_value == 'Other') ?
54
+ opts[:response_field_params]["#{self.id}_other"] :
55
+ nil
56
+
57
+ raw_value
58
+ end
59
+
51
60
  end
52
61
  end
@@ -7,10 +7,20 @@ module Formbuilder
7
7
  }
8
8
 
9
9
  def render_input(value, opts = {})
10
+ str = """
11
+ <div class='section-break-inner section-break-size-#{self[:field_options]['size']}'>
12
+ <div class='section-name'>#{self[:label]}</div>
10
13
  """
11
- <label class='section-name'>#{self[:label]}</label>
12
- <p>#{self[:field_options]['description']}</p>
14
+
15
+ if self[:field_options]['description'].present?
16
+ str += """<p>#{self[:field_options]['description']}</p>"""
17
+ end
18
+
19
+ str += """
20
+ </div>
13
21
  """
22
+
23
+ str
14
24
  end
15
25
 
16
26
  end
@@ -0,0 +1,222 @@
1
+ module Formbuilder
2
+ class ResponseFieldTable < ResponseField
3
+
4
+ include ActionView::Helpers::TagHelper
5
+ include ActionView::Context
6
+
7
+ after_initialize -> {
8
+ @serialized = true
9
+ @field_type = 'table'
10
+ @search_type = 'table'
11
+ }
12
+
13
+ def columns_array
14
+ Array(self[:field_options]['columns']).map { |column| column['label'] }
15
+ end
16
+
17
+ def render_input(value, opts = {})
18
+ value ||= {}
19
+
20
+ str = """
21
+ <table class='border_all'>
22
+ <thead>
23
+ <tr>
24
+ """
25
+
26
+ columns_array.each_with_index do |column, i|
27
+ str += """<th>#{column}</th>"""
28
+ end
29
+
30
+ str += """
31
+ </tr>
32
+ </thead>
33
+ <tbody>
34
+ """
35
+
36
+ [self[:field_options]['minrows'].to_i, 1, number_of_saved_rows(value)].max.times do |i|
37
+ str += """
38
+ <tr>
39
+ """
40
+
41
+ columns_array.each_with_index do |column, j|
42
+ preset_val = Hash(self.field_options['preset_values']).try(:[], column).try(:[], i)
43
+ val = preset_val.presence || value[column].try(:[], i)
44
+
45
+ str += """
46
+ <td>
47
+ <textarea name='response_fields[#{self[:id]}][#{j}][]'
48
+ #{preset_val.present? ? 'readonly' : ''}
49
+ data-col='#{j}'
50
+ data-row='#{i}'
51
+ rows='1'>#{val}</textarea>
52
+ </td>
53
+ """
54
+ end
55
+
56
+ str += """
57
+ </tr>
58
+ """
59
+ end
60
+
61
+ str += """
62
+ <script class='template' type='text/template'>
63
+ <tr>
64
+ """
65
+
66
+ columns_array.each_with_index do |_, j|
67
+ str += """
68
+ <td>
69
+ <textarea name='response_fields[#{self[:id]}][#{j}][]' rows='1'></textarea>
70
+ </td>
71
+ """
72
+ end
73
+
74
+ str += """
75
+ </tr>
76
+ </script>
77
+ """
78
+
79
+ str += """
80
+ </tbody>
81
+ """
82
+
83
+ if self[:field_options]['column_totals']
84
+ str += """
85
+ <tfoot>
86
+ """
87
+
88
+ columns_array.each_with_index do |column, j|
89
+ str += """
90
+ <td><span></span></td>
91
+ """
92
+ end
93
+
94
+ str += """
95
+ </tfoot>
96
+ """
97
+ end
98
+
99
+ str += """
100
+ </table>
101
+ """
102
+
103
+ str += """
104
+ <div class='margin_th margin_bh'>
105
+ <a class='uppercase add_another_row'><i class='icon-plus-sign'></i> Add another row</a>
106
+ </div>
107
+ """
108
+
109
+ str
110
+ end
111
+
112
+ def render_entry(value, opts = {})
113
+ value ||= {}
114
+
115
+ str = """
116
+ <table class='border_all'>
117
+ <thead>
118
+ <tr>
119
+ """
120
+
121
+ columns_array.each_with_index do |column, i|
122
+ str += """<th>#{column}</th>"""
123
+ end
124
+
125
+ str += """
126
+ </tr>
127
+ </thead>
128
+ <tbody>
129
+ """
130
+
131
+ number_of_saved_rows(value).times do |i|
132
+ str += """
133
+ <tr>
134
+ """
135
+
136
+ columns_array.each_with_index do |column, j|
137
+ str += """
138
+ <td>#{value[column].try(:[], i)}</td>
139
+ """
140
+ end
141
+
142
+ str += """
143
+ </tr>
144
+ """
145
+ end
146
+
147
+ str += """
148
+ </tbody>
149
+ """
150
+
151
+ if self[:field_options]['column_totals']
152
+ str += """
153
+ <tfoot>
154
+ """
155
+
156
+ columns_array.each_with_index do |column, j|
157
+ total = opts.try(:[], :entry).try(:get_responses).try(:[], "#{self.id}_sum_#{column}")
158
+
159
+ str += """
160
+ <td><span>#{total.to_f > 0 ? total : ''}</span></td>
161
+ """
162
+ end
163
+
164
+ str += """
165
+ </tfoot>
166
+ """
167
+ end
168
+
169
+ str += """
170
+ </table>
171
+ """
172
+
173
+ str
174
+ end
175
+
176
+ def render_entry_text(value, opts = {})
177
+ (value || {}).map do |k, v|
178
+ "#{k}: " + Array(v).join(', ')
179
+ end.join("; ")
180
+ end
181
+
182
+ def sortable_value(value)
183
+ nil # see :normalize_response for override
184
+ end
185
+
186
+ def number_of_saved_rows(value)
187
+ value.try(:first).try(:[], 1).try(:length) || 0
188
+ end
189
+
190
+ def normalize_response(value, all_responses)
191
+ # Calculate sums and store in the hstore
192
+ columns_array.each do |column|
193
+ all_responses["#{self.id}_sum_#{column}"] = Array(value[column]).map do |x|
194
+ x.gsub(/\$?,?/, '').to_f
195
+ end.inject(:+)
196
+ end
197
+ end
198
+
199
+ def transform_raw_value(raw_value, entry, opts = {})
200
+ raw_value ||= {}
201
+
202
+ {}.tap do |h|
203
+ columns_array.each_with_index do |column, index|
204
+ h[column] = raw_value[index.to_s]
205
+ end
206
+
207
+ # Iterate through each row, and remove ones without any values.
208
+ i = Array(h.first[1]).length - 1
209
+ while i >= 0
210
+ unless h.find { |k, v| v[i].present? }
211
+ h.each do |k, v|
212
+ v.delete_at(i)
213
+ end
214
+ end
215
+
216
+ i = i - 1
217
+ end
218
+ end
219
+ end
220
+
221
+ end
222
+ end
@@ -5,11 +5,18 @@ module Formbuilder
5
5
 
6
6
  after_initialize -> {
7
7
  @field_type = 'text'
8
+ @search_type = 'text'
8
9
  }
9
10
 
10
11
  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)
12
+ tag(
13
+ :input,
14
+ type: 'text',
15
+ name: "response_fields[#{self.id}]",
16
+ id: "response_fields_#{self.id}",
17
+ class: "rf-size-#{self[:field_options]['size']}",
18
+ data: self.length_validations, value: value
19
+ )
13
20
  end
14
21
 
15
22
  end
@@ -5,13 +5,14 @@ module Formbuilder
5
5
  @serialized = true
6
6
  @sort_as_numeric = true
7
7
  @field_type = 'time'
8
+ @search_type = 'time'
8
9
  }
9
10
 
10
11
  def render_input(value, opts = {})
11
12
  """
12
13
  <div class='input-line'>
13
14
  <span class='hours'>
14
- <input type='text' name='response_fields[#{self[:id]}][hours]' value='#{value['hours']}' maxlength='2' />
15
+ <input type='text' name='response_fields[#{self[:id]}][hours]' id='response_fields_#{self[:id]}' value='#{value['hours']}' maxlength='2' />
15
16
  <label>HH</label>
16
17
  </span>
17
18
 
@@ -49,5 +50,11 @@ module Formbuilder
49
50
  end
50
51
  end
51
52
 
53
+ def sortable_value(value)
54
+ hours = value['hours'].to_i
55
+ hours += 12 if value['am_pm'] && value['am_pm'] == 'PM'
56
+ (hours*60*60) + (value['minutes'].to_i * 60) + value['seconds'].to_i
57
+ end
58
+
52
59
  end
53
60
  end
@@ -5,17 +5,29 @@ module Formbuilder
5
5
 
6
6
  after_initialize -> {
7
7
  @field_type = 'website'
8
+ @search_type = 'text'
8
9
  }
9
10
 
10
11
  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://')
12
+ tag(
13
+ :input,
14
+ type: 'text',
15
+ name: "response_fields[#{self.id}]",
16
+ id: "response_fields_#{self.id}",
17
+ class: "rf-size-#{self[:field_options]['size']}",
18
+ value: value,
19
+ placeholder: 'http://'
20
+ )
13
21
  end
14
22
 
15
23
  def render_entry(value, opts = {})
16
24
  "<a href='#{value}' target='_blank' rel='nofollow'>#{value}</a>"
17
25
  end
18
26
 
27
+ def render_entry_text(value, opts = {})
28
+ value
29
+ end
30
+
19
31
  def validate_response(value)
20
32
  require 'uri'
21
33
 
@@ -27,5 +39,17 @@ module Formbuilder
27
39
  end
28
40
  end
29
41
 
42
+ def normalize_response(value, all_responses)
43
+ return if value.blank?
44
+
45
+ unless value[/^http:\/\//] || value[/^https:\/\//]
46
+ all_responses[self.id.to_s] = "http://#{value}"
47
+ end
48
+ end
49
+
50
+ def sortable_value(value)
51
+ value[0..20]
52
+ end
53
+
30
54
  end
31
55
  end
@@ -8,6 +8,7 @@ module Formbuilder
8
8
  @fog_public = false
9
9
 
10
10
  process :set_content_type
11
+ process :save_content_type_and_size_in_model
11
12
 
12
13
  version :thumb, :if => :image? do
13
14
  process resize_to_limit: [250, 250]
@@ -17,10 +18,19 @@ module Formbuilder
17
18
  "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
18
19
  end
19
20
 
21
+ def raw_filename
22
+ @model.read_attribute(:upload)
23
+ end
24
+
20
25
  protected
21
26
  def image?(file)
22
- content_type = file.content_type || model.try(:content_type)
27
+ content_type = file.try(:content_type) || model.try(:content_type)
23
28
  content_type && content_type.include?('image')
24
29
  end
30
+
31
+ def save_content_type_and_size_in_model
32
+ model.content_type = file.try(:content_type)
33
+ model.file_size = file.try(:size)
34
+ end
25
35
  end
26
36
  end