surveyor_gui 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (283) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +44 -0
  3. data/.travis.yml +17 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE +21 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +159 -0
  8. data/Rakefile +66 -0
  9. data/app/controllers/answers_controller.rb +3 -0
  10. data/app/controllers/application_controller.rb +3 -0
  11. data/app/controllers/dependencys_controller.rb +286 -0
  12. data/app/controllers/question_groups_controller.rb +84 -0
  13. data/app/controllers/questions_controller.rb +187 -0
  14. data/app/controllers/survey_sections_controller.rb +80 -0
  15. data/app/controllers/surveyforms_controller.rb +4 -0
  16. data/app/controllers/surveyor_controller.rb +89 -0
  17. data/app/controllers/surveyor_gui/reports_controller.rb +339 -0
  18. data/app/controllers/surveyor_gui/responses_controller.rb +39 -0
  19. data/app/controllers/surveyor_gui/survey_controller.rb +16 -0
  20. data/app/facades/report_formatter.rb +44 -0
  21. data/app/facades/report_preview_wrapper.rb +11 -0
  22. data/app/facades/report_response_generator.rb +147 -0
  23. data/app/helpers/application_helper.rb +2 -0
  24. data/app/helpers/dependency_helper.rb +5 -0
  25. data/app/helpers/question_helper.rb +22 -0
  26. data/app/helpers/surveyform_helper.rb +179 -0
  27. data/app/helpers/surveyor_gui/report_helper.rb +19 -0
  28. data/app/helpers/surveyor_helper.rb +4 -0
  29. data/app/inputs/currency_input.rb +5 -0
  30. data/app/inputs/date_picker_input.rb +7 -0
  31. data/app/inputs/datetime_picker_input.rb +5 -0
  32. data/app/inputs/percent_input.rb +5 -0
  33. data/app/inputs/time_picker_input.rb +5 -0
  34. data/app/mailers/.gitkeep +0 -0
  35. data/app/models/.gitkeep +0 -0
  36. data/app/models/answer.rb +4 -0
  37. data/app/models/column.rb +3 -0
  38. data/app/models/dependency.rb +4 -0
  39. data/app/models/dependency_condition.rb +4 -0
  40. data/app/models/permitted_params_decorator.rb +80 -0
  41. data/app/models/question.rb +4 -0
  42. data/app/models/question_group.rb +4 -0
  43. data/app/models/question_type.rb +7 -0
  44. data/app/models/response.rb +4 -0
  45. data/app/models/response_set.rb +4 -0
  46. data/app/models/row.rb +3 -0
  47. data/app/models/survey.rb +4 -0
  48. data/app/models/survey_section.rb +4 -0
  49. data/app/models/surveyform.rb +103 -0
  50. data/app/uploaders/blob_uploader.rb +48 -0
  51. data/app/views/dependencys/_column.html.erb +1 -0
  52. data/app/views/dependencys/_dependency.html.erb +22 -0
  53. data/app/views/dependencys/_dependency_condition_fields.html.erb +48 -0
  54. data/app/views/dependencys/_form.html.erb +20 -0
  55. data/app/views/dependencys/blank.html.erb +0 -0
  56. data/app/views/dependencys/edit.html.erb +1 -0
  57. data/app/views/dependencys/new.html.erb +1 -0
  58. data/app/views/layouts/application.html.erb +14 -0
  59. data/app/views/layouts/surveyor_gui_blank.html.erb +12 -0
  60. data/app/views/layouts/surveyor_gui_default.html.erb +16 -0
  61. data/app/views/layouts/surveyor_modified.html.erb +14 -0
  62. data/app/views/partials/_answer.html.haml +33 -0
  63. data/app/views/partials/_question.html.haml +33 -0
  64. data/app/views/partials/_question_group.html.haml +73 -0
  65. data/app/views/partials/_section.html.haml +13 -0
  66. data/app/views/question_groups/_form.html.erb +56 -0
  67. data/app/views/question_groups/_group_inline_field.html.erb +21 -0
  68. data/app/views/question_groups/_group_inline_fields.html.erb +25 -0
  69. data/app/views/question_groups/blank.html.erb +0 -0
  70. data/app/views/question_groups/edit.html.erb +1 -0
  71. data/app/views/question_groups/new.html.erb +1 -0
  72. data/app/views/questions/_answer_fields.html.erb +23 -0
  73. data/app/views/questions/_answer_options.html.erb +28 -0
  74. data/app/views/questions/_form.html.erb +65 -0
  75. data/app/views/questions/_grid_dropdown_columns.html.erb +10 -0
  76. data/app/views/questions/_grid_dropdown_fields.html.erb +42 -0
  77. data/app/views/questions/_grid_fields.html.erb +9 -0
  78. data/app/views/questions/_no_picks.html.erb +29 -0
  79. data/app/views/questions/_pick.html +21 -0
  80. data/app/views/questions/_picks.html.erb +12 -0
  81. data/app/views/questions/blank.html.erb +0 -0
  82. data/app/views/questions/edit.html.erb +1 -0
  83. data/app/views/questions/new.html.erb +1 -0
  84. data/app/views/survey_sections/_form.html.erb +13 -0
  85. data/app/views/survey_sections/blank.html.erb +0 -0
  86. data/app/views/survey_sections/edit.html.erb +1 -0
  87. data/app/views/survey_sections/new.html.erb +1 -0
  88. data/app/views/surveyforms/_form.html.erb +50 -0
  89. data/app/views/surveyforms/_question_field.html.erb +148 -0
  90. data/app/views/surveyforms/_question_group.html.erb +116 -0
  91. data/app/views/surveyforms/_question_group_fields.html.erb +3 -0
  92. data/app/views/surveyforms/_question_name_and_number.html.erb +6 -0
  93. data/app/views/surveyforms/_question_section.html.erb +15 -0
  94. data/app/views/surveyforms/_question_wrapper.html.erb +109 -0
  95. data/app/views/surveyforms/_survey_section_fields.html.erb +138 -0
  96. data/app/views/surveyforms/clone_survey.html.erb +13 -0
  97. data/app/views/surveyforms/edit.html.erb +5 -0
  98. data/app/views/surveyforms/index.html.erb +40 -0
  99. data/app/views/surveyforms/new.html.erb +1 -0
  100. data/app/views/surveyforms/show.html.erb +5 -0
  101. data/app/views/surveyor_gui/reports/_graphs.html.haml +21 -0
  102. data/app/views/surveyor_gui/reports/_grid.html.haml +42 -0
  103. data/app/views/surveyor_gui/reports/_grid_dropdown.html.haml +56 -0
  104. data/app/views/surveyor_gui/reports/_repeater.html.haml +28 -0
  105. data/app/views/surveyor_gui/reports/_show_report.html.haml +33 -0
  106. data/app/views/surveyor_gui/reports/_single_question.html.haml +70 -0
  107. data/app/views/surveyor_gui/reports/show.html.erb +14 -0
  108. data/app/views/surveyor_gui/responses/_grid.html.haml +20 -0
  109. data/app/views/surveyor_gui/responses/_grid_dropdown.html.haml +20 -0
  110. data/app/views/surveyor_gui/responses/_repeater.html.haml +22 -0
  111. data/app/views/surveyor_gui/responses/_survey_results.html.haml +40 -0
  112. data/app/views/surveyor_gui/responses/index.html.haml +24 -0
  113. data/app/views/surveyor_gui/responses/show.html.haml +42 -0
  114. data/app/views/surveyor_gui/shared/_grid_comments.html.haml +10 -0
  115. data/app/views/surveyor_gui/shared/_new_line.html.haml +2 -0
  116. data/app/views/surveyor_gui/shared/_pick_comments.html.haml +15 -0
  117. data/app/views/surveyor_gui/shared/_question_number.html.haml +9 -0
  118. data/app/views/surveyor_gui/shared/_report_data.html.haml +24 -0
  119. data/app/views/surveyor_gui/shared/_stars_report_data.html.haml +14 -0
  120. data/config.ru +4 -0
  121. data/config/environment.rb +0 -0
  122. data/config/routes.rb +71 -0
  123. data/db/migrate/20140307204049_add_template_to_surveys.rb +5 -0
  124. data/db/migrate/20140307235607_add_test_data_to_response_sets.rb +5 -0
  125. data/db/migrate/20140308171947_add_original_choice_to_answers.rb +5 -0
  126. data/db/migrate/20140308172118_add_blob_to_responses.rb +5 -0
  127. data/db/migrate/20140308172417_add_modifiable_to_survey_section.rb +5 -0
  128. data/db/migrate/20140308174532_add_modifiable_to_question.rb +5 -0
  129. data/db/migrate/20140308175305_add_dynamically_generate_to_questions.rb +5 -0
  130. data/db/migrate/20140311032923_add_dummy_blob_to_questions.rb +5 -0
  131. data/db/migrate/20140311160609_add_dynamic_source_to_questions.rb +5 -0
  132. data/db/migrate/20140311161714_add_report_code_to_questions.rb +5 -0
  133. data/db/migrate/20140530181134_add_is_comment_to_questions.rb +5 -0
  134. data/db/migrate/20140531012006_add_is_comment_to_answers.rb +5 -0
  135. data/db/migrate/20140531225529_create_rows.rb +9 -0
  136. data/db/migrate/20140601011151_create_columns.rb +11 -0
  137. data/db/migrate/20140602030330_add_column_id_to_answers.rb +5 -0
  138. data/db/migrate/20140603155606_add_column_id_to_responses.rb +5 -0
  139. data/db/migrate/20140606023527_add_column_id_to_dependency_conditions.rb +5 -0
  140. data/db/migrate/20140815165307_add_user_id_to_survey.rb +5 -0
  141. data/lib/assets/.gitkeep +0 -0
  142. data/lib/assets/images/addicon.png +0 -0
  143. data/lib/assets/images/datepicker.gif +0 -0
  144. data/lib/assets/images/delete.gif +0 -0
  145. data/lib/assets/images/delete.png +0 -0
  146. data/lib/assets/images/images/border.png +0 -0
  147. data/lib/assets/images/images/controls.png +0 -0
  148. data/lib/assets/images/images/loading.gif +0 -0
  149. data/lib/assets/images/images/loading_background.png +0 -0
  150. data/lib/assets/images/images/overlay.png +0 -0
  151. data/lib/assets/images/rails.png +0 -0
  152. data/lib/assets/images/star.gif +0 -0
  153. data/lib/assets/javascripts/.gitkeep +0 -0
  154. data/lib/assets/javascripts/surveyor_gui/jquery.MetaData.js +121 -0
  155. data/lib/assets/javascripts/surveyor_gui/jquery.blockUI.js +619 -0
  156. data/lib/assets/javascripts/surveyor_gui/jquery.rating.js +377 -0
  157. data/lib/assets/javascripts/surveyor_gui/jquery.validate.js +1188 -0
  158. data/lib/assets/javascripts/surveyor_gui/surveyor_add_ons.js +10 -0
  159. data/lib/assets/javascripts/surveyor_gui/surveyor_gui.js +1417 -0
  160. data/lib/assets/stylesheets/.gitkeep +0 -0
  161. data/lib/assets/stylesheets/surveyor_gui/jquery.rating.css +12 -0
  162. data/lib/assets/stylesheets/surveyor_gui/surveyor_add_ons.css +3 -0
  163. data/lib/assets/stylesheets/surveyor_gui/surveyor_gui.sass +650 -0
  164. data/lib/enumerable_extenders.rb +31 -0
  165. data/lib/generators/surveyor_gui/install_generator.rb +57 -0
  166. data/lib/generators/surveyor_gui/templates/app/assets/javascripts/surveyor_add_ons.js +2 -0
  167. data/lib/generators/surveyor_gui/templates/app/assets/javascripts/surveyor_gui_all.js +24 -0
  168. data/lib/generators/surveyor_gui/templates/app/assets/stylesheets/surveyor_add_ons.css.sass +1 -0
  169. data/lib/generators/surveyor_gui/templates/app/assets/stylesheets/surveyor_gui_all.css.sass +8 -0
  170. data/lib/generators/surveyor_gui/templates/app/helpers/surveyor_helper.rb +4 -0
  171. data/lib/generators/surveyor_gui/templates/app/models/response_set_user.rb +13 -0
  172. data/lib/generators/surveyor_gui/templates/app/views/layouts/surveyor_gui_default.html.erb +16 -0
  173. data/lib/generators/surveyor_gui/templates/config/initializers/simple_form.rb +140 -0
  174. data/lib/generators/surveyor_gui/templates/config/locales/en.yml +5 -0
  175. data/lib/surveyor_gui.rb +17 -0
  176. data/lib/surveyor_gui/engine.rb +30 -0
  177. data/lib/surveyor_gui/helpers/surveyor_helper_methods.rb +19 -0
  178. data/lib/surveyor_gui/models/answer_methods.rb +24 -0
  179. data/lib/surveyor_gui/models/column_methods.rb +43 -0
  180. data/lib/surveyor_gui/models/dependency_condition_methods.rb +53 -0
  181. data/lib/surveyor_gui/models/dependency_methods.rb +83 -0
  182. data/lib/surveyor_gui/models/question_and_group_shared_methods.rb +11 -0
  183. data/lib/surveyor_gui/models/question_group_methods.rb +55 -0
  184. data/lib/surveyor_gui/models/question_methods.rb +435 -0
  185. data/lib/surveyor_gui/models/question_type_methods.rb +493 -0
  186. data/lib/surveyor_gui/models/response_methods.rb +67 -0
  187. data/lib/surveyor_gui/models/response_set_methods.rb +54 -0
  188. data/lib/surveyor_gui/models/row_methods.rb +11 -0
  189. data/lib/surveyor_gui/models/survey_methods.rb +32 -0
  190. data/lib/surveyor_gui/models/survey_section_methods.rb +32 -0
  191. data/lib/surveyor_gui/surveyforms_controller_methods.rb +258 -0
  192. data/lib/surveyor_gui/version.rb +3 -0
  193. data/lib/tasks/.gitkeep +0 -0
  194. data/lib/tasks/surveyor_gui_tasks.rake +4 -0
  195. data/lib/templates/erb/scaffold/_form.html.erb +13 -0
  196. data/spec/controllers/surveyforms_controller_spec.rb +361 -0
  197. data/spec/controllers/surveyor_controller_spec.rb +303 -0
  198. data/spec/factories.rb +181 -0
  199. data/spec/features/create_survey_spec.rb +418 -0
  200. data/spec/features/dependencies_spec.rb +61 -0
  201. data/spec/features/rearrange_survey_spec.rb +118 -0
  202. data/spec/features/ui_spec.rb +469 -0
  203. data/spec/fixtures/REDCapDemoDatabase_DataDictionary.csv +127 -0
  204. data/spec/fixtures/chinese_survey.rb +14 -0
  205. data/spec/fixtures/everything.rb +215 -0
  206. data/spec/fixtures/favorites-ish.rb +22 -0
  207. data/spec/fixtures/favorites.rb +22 -0
  208. data/spec/fixtures/feelings.rb +38 -0
  209. data/spec/fixtures/lifestyle.rb +55 -0
  210. data/spec/fixtures/numbers.rb +21 -0
  211. data/spec/fixtures/redcap_new_headers.csv +1 -0
  212. data/spec/fixtures/redcap_siblings.csv +1 -0
  213. data/spec/fixtures/redcap_whitespace.csv +1 -0
  214. data/spec/helpers/formtastic_custom_input_spec.rb +15 -0
  215. data/spec/helpers/surveyor_helper_spec.rb +116 -0
  216. data/spec/lib/common_spec.rb +37 -0
  217. data/spec/lib/parser_spec.rb +393 -0
  218. data/spec/lib/rake_kitchen_sink.rb +42 -0
  219. data/spec/lib/redcap_parser_spec.rb +129 -0
  220. data/spec/lib/unparser_spec.rb +126 -0
  221. data/spec/models/answer_spec.rb +144 -0
  222. data/spec/models/dependency_condition_spec.rb +428 -0
  223. data/spec/models/dependency_spec.rb +90 -0
  224. data/spec/models/question_group_spec.rb +66 -0
  225. data/spec/models/question_spec.rb +176 -0
  226. data/spec/models/response_set_spec.rb +452 -0
  227. data/spec/models/response_spec.rb +208 -0
  228. data/spec/models/survey_section_spec.rb +58 -0
  229. data/spec/models/survey_spec.rb +155 -0
  230. data/spec/models/surveyor_gui/question_spec.rb +60 -0
  231. data/spec/models/surveyor_gui/question_type_spec.rb +268 -0
  232. data/spec/models/validation_condition_spec.rb +98 -0
  233. data/spec/models/validation_spec.rb +64 -0
  234. data/spec/spec.opts +4 -0
  235. data/spec/spec_helper.rb +119 -0
  236. data/spec/support/scenario_outline_helper.rb +39 -0
  237. data/spec/support/shared.rb +10 -0
  238. data/spec/support/surveyforms_creation_helpers.rb +312 -0
  239. data/spec/support/surveyforms_rearrangement_helpers.rb +170 -0
  240. data/spec/support/surveyor_api_helpers.rb +15 -0
  241. data/spec/support/surveyor_ui_helpers.rb +108 -0
  242. data/spec/support/wait_for_ajax.rb +11 -0
  243. data/spec/views/questions/edit.html.erb_spec.rb +73 -0
  244. data/spec/views/surveyforms/edit.html.erb_spec.rb +126 -0
  245. data/surveyor_gui.gemspec +52 -0
  246. data/test/dummy/README.rdoc +261 -0
  247. data/test/dummy/Rakefile +7 -0
  248. data/test/dummy/app/assets/javascripts/application.js +15 -0
  249. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  250. data/test/dummy/app/controllers/application_controller.rb +3 -0
  251. data/test/dummy/app/helpers/application_helper.rb +2 -0
  252. data/test/dummy/app/mailers/.gitkeep +0 -0
  253. data/test/dummy/app/models/.gitkeep +0 -0
  254. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  255. data/test/dummy/config.ru +4 -0
  256. data/test/dummy/config/application.rb +59 -0
  257. data/test/dummy/config/boot.rb +10 -0
  258. data/test/dummy/config/database.yml +25 -0
  259. data/test/dummy/config/environment.rb +5 -0
  260. data/test/dummy/config/environments/development.rb +37 -0
  261. data/test/dummy/config/environments/production.rb +67 -0
  262. data/test/dummy/config/environments/test.rb +37 -0
  263. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  264. data/test/dummy/config/initializers/inflections.rb +15 -0
  265. data/test/dummy/config/initializers/mime_types.rb +5 -0
  266. data/test/dummy/config/initializers/secret_token.rb +7 -0
  267. data/test/dummy/config/initializers/session_store.rb +8 -0
  268. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  269. data/test/dummy/config/locales/en.yml +5 -0
  270. data/test/dummy/config/routes.rb +58 -0
  271. data/test/dummy/lib/assets/.gitkeep +0 -0
  272. data/test/dummy/log/.gitkeep +0 -0
  273. data/test/dummy/public/404.html +26 -0
  274. data/test/dummy/public/422.html +26 -0
  275. data/test/dummy/public/500.html +25 -0
  276. data/test/dummy/public/favicon.ico +0 -0
  277. data/test/dummy/script/rails +6 -0
  278. data/test/surveyor-gui_test.rb +7 -0
  279. data/test/test_helper.rb +15 -0
  280. data/vendor/assets/stylesheets/.gitkeep +0 -0
  281. data/vendor/assets/stylesheets/custom.sass +5 -0
  282. data/vendor/plugins/.gitkeep +0 -0
  283. metadata +664 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 01ff64c99fbe1b160d2a285be9d7542b78ae1475
4
+ data.tar.gz: 5446a1b7ec3ed1a52075fe7581f303930c61b518
5
+ SHA512:
6
+ metadata.gz: 7483d8876d1d10aa8b685ae2f554443d5c3912b7af468a086f260adf0fc6de5d4579c1ed9799140b04bfd8a9c7e5d96223a575e2353640d2e21562d9c5142db0
7
+ data.tar.gz: 8d7b4471e2a80f408842d765bc1421c233a0bc6ea6180f4fa66dac81e2bd5b21fc0f0ce839046e1fd10e11736f0c0c513ae94ff1eda8b5a4b13ec715eaf198bf
@@ -0,0 +1,44 @@
1
+ *~
2
+ *.rbc
3
+ *.sassc
4
+ .sass-cache
5
+ capybara-*.html
6
+ .rspec
7
+ .rvmrc
8
+ /vendor/bundle
9
+ /log/*
10
+ log/*
11
+ /tmp/*
12
+ /public/system/*
13
+ /coverage/
14
+ /spec/tmp/*
15
+ **.orig
16
+ **.swp
17
+ rerun.txt
18
+ pickle-email-*.html
19
+ .project
20
+ config/initializers/secret_token.rb
21
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
22
+ #
23
+ # If you find yourself ignoring temporary files generated by your text editor
24
+ # or operating system, you probably want to add a global ignore instead:
25
+ # git config --global core.excludesfile ~/.gitignore_global
26
+
27
+ # Ignore bundler config
28
+ /.bundle
29
+
30
+ # Ignore the default SQLite database.
31
+ /db/*.sqlite3
32
+
33
+ # Ignore all logfiles and tempfiles.
34
+ /log/*.log
35
+ /tmp
36
+
37
+ # Ignore testbed
38
+ testbed
39
+
40
+ # Ignore RVM directives
41
+ .ruby-version
42
+ .ruby-gemset
43
+
44
+ Gemfile.lock
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.1
5
+ env:
6
+ - "RAILS_VERSION=4.0.8"
7
+ - "RAILS_VERSION=4.1.4"
8
+ script:
9
+ - bundle exec rake gui_testbed
10
+ - bundle exec rspec
11
+ notifications:
12
+ email:
13
+ recipients:
14
+ - kjayma@gmail.com
15
+ on_success: change # [always|never|change] # default: change
16
+ on_failure: always # [always|never|change] # default: always
17
+
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'surveyor', github: 'NUBIC/surveyor'
4
+
5
+ # Bundler will treat runtime dependencies like base dependencies, and
6
+ # development dependencies will be added by default to the :development group.
7
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,20 @@
1
+ Copyright 2014 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,159 @@
1
+ surveyor_gui
2
+ ============
3
+
4
+ Surveyor_gui complements the surveyor gem.
5
+
6
+ The surveyor gem is used to create surveys by parsing a file written in the Surveyor DSL. It does not include a gui for creating surveys, although it does provide a gui for taking surveys.
7
+
8
+ The lack of a gui front-end limits the utility of surveyor for certain applications.
9
+
10
+ Surveyor_gui meets this need by providing a gui to create surveys from scratch. Surveyor_gui bypasses the need to create a Surveyor DSL file, and directly updates the Surveyor tables to build a survey.
11
+
12
+ Surveyor is feature-rich and can create very complex surveys. Surveyor-gui supports most of the features in Surveyor.
13
+
14
+ This gem will also provide a reporting capability for Surveyor.
15
+
16
+ ## Requirements
17
+
18
+ SurveyorGui works with:
19
+
20
+ * Ruby 1.9.3
21
+ * Rails 4, 4.1
22
+
23
+
24
+ Some key dependencies are:
25
+
26
+ * Surveyor
27
+ * HAML
28
+ * Sass
29
+ * Formtastic
30
+
31
+ A more exhaustive list can be found in the gemspecs for Surveyor [surveyor] and Surveyor_gui [surveyor-gui][].
32
+
33
+ [surveyor]: https://github.com/NUBIC/surveyor/blob/master/surveyor.gemspec
34
+ [surveyor-gui]: https://github.com/kjayma/surveyor_gui/blob/master/surveyor_gui.gemspec
35
+ [policy]: http://weblog.rubyonrails.org/2013/2/24/maintenance-policy-for-ruby-on-rails/
36
+
37
+ ## Install
38
+
39
+ Add surveyor and surveyor-gui to your Gemfile:
40
+
41
+ gem 'surveyor', github: 'NUBIC/surveyor'
42
+ gem 'surveyor_gui'
43
+
44
+ You will also need a javascript runtime, like node.js or therubyracer. If you
45
+ have not yet installed one, add
46
+
47
+ gem "therubyracer"
48
+
49
+ to your Gemfile.
50
+
51
+ Bundle, install, and migrate:
52
+
53
+ bundle install
54
+ rails g surveyor_gui:install
55
+
56
+ Note that the installer will run db:migrate (so any un-applied migrations you have in your project will be pulled in).
57
+ The survey editor can be found at '/surveyforms'. Users can take surveys at the '/surveys' url.
58
+
59
+ ## Limitations
60
+
61
+ This gem provides support for a subset of the Surveyor functionality. It supports all of the basic question types, and
62
+ most of the complicated question types, but does not currently support the following:
63
+
64
+ - Questions with multiple entries (e.g., the "Get me started on an improv sketch" question in the kitchen_sink_survey.rb that comes
65
+ with the Surveyor gem.
66
+ - Input masks
67
+ - Quizzes
68
+
69
+ It adds some new question types:
70
+
71
+ - Star rating (1-5 stars)
72
+ - File upload
73
+ - Grid dropdown (a grid of dropdowns with up to ten columns.)
74
+
75
+ Dependencies are partially supported. The following are not currently supported:
76
+
77
+ - counts (count the number of answers checked or entered)
78
+ - Regexp validations
79
+
80
+ You can open the kitchen_sink survey that comes with Surveyor, but a few of the questions will not behave as expected
81
+ because of the discrepancies noted above.
82
+
83
+ ## Locking
84
+
85
+ This gem enforces locking on surveys. A survey may be modified up until a user submits a response. At that point, the survey
86
+ can no longer be edited for structural changes (i.e., /surveyform/edit will not permit any changes). This protects the
87
+ data integrity of the survey response data.
88
+
89
+ ## Templates
90
+
91
+ Surveys may be saved as templates. This allows them to be cloned when creating a new survey (cloning is a pending feature). It is
92
+ possible to mark certain parts of a survey as unmodifiable so that they will always be present when a survey is cloned.
93
+
94
+ A template library feature is pending.
95
+
96
+ ## Test environment
97
+
98
+ If you want to try out surveyor-gui before incorporating it into an application, or contribute, clone the repository.
99
+ Then run
100
+
101
+ bundle install
102
+ bundle exec rake gui_testbed
103
+ cd testbed
104
+
105
+ Start the rails server and go to /surveyforms
106
+
107
+ Before contributing, please run the tests:
108
+ bundle exec rspec spec
109
+
110
+ ## Taking surveys
111
+
112
+ Go to /surveys (or click the link at the bottom of the surveyforms home page) to see the surveys and take one.
113
+
114
+ ## Reports
115
+
116
+ Surveyor_gui now provides reports!
117
+
118
+ You can see a report of all survey responses, or view an individual response.
119
+
120
+ Highcharts.js is used for graphics, and must be licensed for commercial use. Future development will replace Highcharts with Rickshawgraphs.
121
+
122
+ To see reports, try using the "Preview Reports" button on the survey editor, or take the survey and try
123
+ "localhost:3000/surveyor_gui/reports/:id/show" where :id is the survey id. Preview reports will create some dummy
124
+ responses using randomized answers.
125
+
126
+ You can also view an individual response at "localhost:3000/surveyor_gui/results/:id/show".
127
+
128
+ ## Devise etc.
129
+
130
+ Surveyor_Gui will work with Devise or like gems.
131
+
132
+ Surveyor_gui adds a user_id attribute to the Survey model. It will try to set user_id to current_user when a new survey
133
+ is defined. The gem does not provide any access control over survey creation and update, but you can add that to your
134
+ application using the user_id attribute.
135
+
136
+ In addition, the underlying Surveyor gem provides a user_id attribute in the ResponseSet model. When responses are created, it will
137
+ try to set the user_id to current_user.
138
+
139
+ Surveyor_gui reports assume there will be a unique user for eash Survey response, and reports on results by user.
140
+ If the response set has a user id, (which will be the case if you've setup Devise in the typical way) it will identify the response by user_id. If no user_id is available, it will
141
+ default to the response_set.id.
142
+
143
+ You may want to identify users by something other than id on reports. This can be done easily.
144
+
145
+ Surveyor_gui creates a response_set_user.rb file in your app/models directory. Edit it to define the identifier you would like to use for users in reports. For instance, if your user model is User, and you would like to see the user's email address on reports, edit the file as follows...
146
+
147
+ In the initialize method, add the following line:
148
+
149
+ @user = User.find(user_id)
150
+
151
+ In the report_user_name method, add the following line:
152
+
153
+ @user ? @user.email : nil
154
+
155
+ If you wanted the users full name, you could add something like this:
156
+
157
+ @user ? @user.last_name + ', ' + @user.first_name : nil
158
+
159
+ Note that SurveyorGui controllers expect to use surveyor_gui's own layout view, surveyor_gui_default.rb. A copy will be placed in your application's app/views/layouts directory. You may need edit it for various reasons, such as adding a Devise login/logout link.
@@ -0,0 +1,66 @@
1
+ $LOAD_PATH << File.expand_path('../lib', __FILE__)
2
+
3
+
4
+ require 'bundler/gem_tasks'
5
+ require 'rspec/core/rake_task'
6
+
7
+ ###### RSPEC
8
+
9
+ RSpec::Core::RakeTask.new(:spec)
10
+
11
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
12
+ spec.rcov = true
13
+ end
14
+
15
+ task :default => :spec
16
+
17
+
18
+ ###### TESTBED
19
+
20
+ desc 'Set up the rails app that the specs and features use'
21
+ task :gui_testbed => 'gui_testbed:rebuild'
22
+
23
+ namespace :gui_testbed do
24
+ desc 'Generate a minimal surveyor_gui/surveyor rails app'
25
+ task :generate do
26
+ sh "bundle exec rails new testbed --skip-bundle" # don't run bundle install until the Gemfile modifications
27
+
28
+ chdir('testbed') do
29
+ gem_file_contents = File.read('Gemfile')
30
+ gem_file_contents.sub!(/^(gem 'rails'.*)$/, %Q{ \\1\nplugin_root = File.expand_path('../..', __FILE__)\ngem 'surveyor_gui', :path => plugin_root\ngem 'therubyracer'\ngem 'surveyor', github: 'NUBIC/surveyor'})
31
+
32
+ File.open('Gemfile', 'w'){|f| f.write(gem_file_contents) }
33
+
34
+ # not sure why turbolinks gives test problems, anyway better to avoid it?
35
+ js_file_contents = File.read('app/assets/javascripts/application.js')
36
+ js_file_contents.sub!('//= require turbolinks', '')
37
+ File.open('app/assets/javascripts/application.js', 'w'){|f| f.write(js_file_contents) }
38
+
39
+ Bundler.with_clean_env do
40
+ sh 'bundle install' # run bundle install after Gemfile modifications
41
+ end
42
+ end
43
+ end
44
+
45
+ desc 'Remove the testbed entirely'
46
+ task :remove do
47
+ rm_rf 'testbed'
48
+ end
49
+
50
+ desc 'Prepare the databases for the testbed'
51
+ task :migrate do
52
+ chdir('testbed') do
53
+ Bundler.with_clean_env do
54
+ sh 'bundle exec rails generate simple_form:install'
55
+ sh 'bundle exec rake highcharts:update'
56
+ sh 'bundle exec rails generate surveyor:install'
57
+ sh 'bundle exec rake db:migrate db:test:prepare'
58
+ sh 'bundle exec rails generate surveyor_gui:install'
59
+ sh 'bundle exec rake db:migrate db:test:prepare'
60
+ sh 'bundle exec rake surveyor FILE=surveys/kitchen_sink_survey.rb'
61
+ end
62
+ end
63
+ end
64
+
65
+ task :rebuild => [:remove, :generate, :migrate]
66
+ end
@@ -0,0 +1,3 @@
1
+ class AnswersController < ApplicationController
2
+ layout 'surveyor_gui_blank'
3
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+ end
@@ -0,0 +1,286 @@
1
+ class DependencysController < ApplicationController
2
+ layout 'surveyor_gui_blank'
3
+
4
+ def new
5
+ prep_variables
6
+ @title = "Add Logic for "+@this_question
7
+ if @question.part_of_group?
8
+ @question.question_group.build_dependency(:rule=>'A')
9
+ else
10
+ @question.build_dependency(:rule=>'A')
11
+ end
12
+ end
13
+
14
+ def edit
15
+ prep_variables
16
+ @title = "Edit Logic for Question "+@this_question
17
+ end
18
+
19
+ def create
20
+ @question = Question.new(question_params)
21
+ if @question.save
22
+ redirect_to :back
23
+ else
24
+ render :action => 'new', :layout => 'surveyor_gui_blank'
25
+ end
26
+ end
27
+
28
+ def update
29
+ @title = "Update Question"
30
+ @question = Question.includes(:answers).find(params[:id])
31
+ if @question.part_of_group?
32
+ update_object = @question.question_group
33
+ update_params = question_group_params
34
+ else
35
+ update_object = @question
36
+ update_params = question_params
37
+ end
38
+ if update_object.update_attributes(update_params)
39
+ update_object.dependency.destroy if update_object.dependency.dependency_conditions.blank?
40
+ render :blank, :layout => 'surveyor_gui_blank'
41
+ else
42
+ prep_variables
43
+ render :action => 'edit', :layout => 'surveyor_gui_blank'
44
+ end
45
+ end
46
+
47
+ def destroy
48
+ question = Question.find(params[:id])
49
+ if question.part_of_group?
50
+ question.question_group.dependency.destroy
51
+ else
52
+ question.dependency.destroy
53
+ end
54
+ render :nothing=>true
55
+ end
56
+
57
+ def render_dependency_conditions_partial
58
+ prep_variables
59
+ @question_or_group = @question.part_of_group? ? @question.question_group : @question
60
+ @dependency = Dependency.find(params[:dependency_id]) if !params[:dependency_id].blank?
61
+ if @dependency.nil?
62
+ @question_or_group.build_dependency(:rule=>'A').dependency_conditions.build()
63
+ end
64
+ if @question_or_group.dependency.dependency_conditions.empty?
65
+ @question_or_group.dependency.dependency_conditions.build()
66
+ else
67
+ if params[:add_row]
68
+ @question_or_group = eval(@question_or_group.class.name).new
69
+ @question_or_group.build_dependency.dependency_conditions.build()
70
+ end
71
+ end
72
+ render :partial => 'dependency_condition_fields'
73
+ end
74
+
75
+ def get_answers
76
+ options=""
77
+ question_id = params[:question_id]
78
+ question = Question.find(question_id)
79
+ column_id = params[:column_id].blank? ? _default_column_id(question) : params[:column_id]
80
+ dependency_condition_id = params[:dependency_condition_id]
81
+ dependency_condition = dependency_condition_id.blank? ? nil : DependencyCondition.find(dependency_condition_id)
82
+ if question && question.answers
83
+ question.answers.where('column_id = ? OR column_id IS NULL',column_id.to_i).each_with_index do |a, index|
84
+ options += '<option ' + _get_selected_answer(index, dependency_condition, a, column_id) +
85
+ 'value="' + a.id.to_s + '"' +
86
+ '>'+a.text.to_s+"</option>"
87
+ end
88
+ end
89
+ render :inline=>options
90
+ end
91
+
92
+ def get_columns
93
+ options=""
94
+ question_id = params[:question_id]
95
+ dependency_condition_id = params[:dependency_condition_id]
96
+ dependency_condition = dependency_condition_id.blank? ? nil : DependencyCondition.find(dependency_condition_id)
97
+ question = Question.find(question_id)
98
+ if question && question.question_group
99
+ question.question_group.columns.each_with_index do |c, index|
100
+ options += '<option ' +
101
+ _get_selected_column(index, dependency_condition, c) +
102
+ 'value="' + c.id.to_s + '"' +
103
+ '>'+c.text.to_s+"</option>"
104
+ end
105
+ end
106
+ render :inline=>options
107
+ end
108
+
109
+ def get_question_type
110
+ question_id = params[:question_id]
111
+ question = Question.find(question_id)
112
+ response=question.pick
113
+ response += ','+question.question_type_id.to_s
114
+ response += ','+question_id
115
+ render :inline=>response
116
+ end
117
+
118
+ private
119
+
120
+ def prep_variables
121
+ @question = Question.includes(:dependency).find(params[:id]) unless @question
122
+ controlling_questions = get_controlling_question_collection(@question)
123
+ @controlling_questions = controlling_questions.collection
124
+ @this_question = @question.part_of_group? ? @question.question_group.text : @question.question_description
125
+ @operators = get_operators
126
+ end
127
+
128
+ def get_controlling_question_collection(dependent_question)
129
+ all_questions_in_survey = _get_all_questions_in_survey(dependent_question)
130
+ _get_question_collection(all_questions_in_survey, dependent_question)
131
+ end
132
+
133
+ def _get_all_questions_in_survey(question)
134
+ PossibleControllingQuestion.unscoped
135
+ .joins(:survey_section)
136
+ .where('survey_id = ?', question.survey_section.survey_id)
137
+ .order('survey_sections.display_order','survey_sections.id','questions.display_order')
138
+ end
139
+
140
+ def _get_question_collection(all_questions, dependent_question)
141
+ return QuestionCollection.new(dependent_question).add_questions(all_questions)
142
+ end
143
+
144
+ def get_operators
145
+ return [
146
+ ['equal to (=)','=='],
147
+ ['not equal to','!='],
148
+ ['less than (<)','<'],
149
+ ['less than or equal to (<=)','<='],
150
+ ['greater than or equal to (>=)','>='],
151
+ ['greater than','>']
152
+ ]
153
+ end
154
+
155
+ def question_params
156
+ ::PermittedParams.new(params[:question]).question
157
+ end
158
+
159
+ def question_group_params
160
+ ::PermittedParams.new(params[:question_group]).question_group
161
+ end
162
+
163
+ def _default_column_id(question)
164
+ if question.part_of_group?
165
+ columns = question.question_group.columns
166
+ columns.first ? columns.first.id.to_s : ""
167
+ else
168
+ ""
169
+ end
170
+ end
171
+
172
+ def _get_selected_answer(index, dependency_condition, a, column_id)
173
+ if _matches_dependency_condition(dependency_condition, a, column_id)
174
+ 'selected="selected" '
175
+ else
176
+ ''
177
+ end
178
+ end
179
+
180
+ def _get_selected_column(index, dependency_condition, column)
181
+ if _matches_dependency_condition_column(dependency_condition, column)
182
+ 'selected="selected"'
183
+ else
184
+ ''
185
+ end
186
+ end
187
+
188
+ def _matches_dependency_condition (dependency_condition, a, column_id)
189
+ if dependency_condition.nil?
190
+ false
191
+ else
192
+ (dependency_condition.answer_id == a.id && (column_id.blank? || dependency_condition.column_id == column_id.to_i ))
193
+ end
194
+ end
195
+
196
+ def _matches_dependency_condition_column(dependency_condition, column)
197
+ if dependency_condition.nil?
198
+ false
199
+ else
200
+ dependency_condition.column_id == column.id
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+ class QuestionCollection
207
+ ## QuestionCollection provides a 2 dimensional array consisting of a question id
208
+ ## and a question description. The collection may be used in a view's select field.
209
+ ##
210
+ ## Its membership is determined by a base question.
211
+ ## The base question is the one from which other questions in the collection are derived.
212
+ ## E.g., in a dependency, the question that is shown or hidden based on the answers to others
213
+ ## is the base question. It shouldn't show up in the collection.
214
+ ##
215
+ ## Other questions may or may not show up in the collection depending on their eligibility.
216
+ ##
217
+ ## Some questions should have a question number and
218
+ ## some should not. The QuestionCollection numbers questions that should be numbered
219
+ ## and keeps track of the numbering. If a question is numbered, the question number
220
+ ## is included in the description, e.g. "3) What is your name?". Otherwise,
221
+ ## the description is just the question text, e.g. "Don't forget to use your middle initial".
222
+ ##
223
+ ## Incoming questions may be duck typed, but should respond to is_numbered? and is_eligible?
224
+ ## messages.
225
+
226
+ attr_accessor :collection, :dependency_question_description
227
+
228
+ def initialize(base_question)
229
+ @collection = []
230
+ @question_number = 1
231
+ @base_question = base_question
232
+ @dependency_question_description = nil
233
+ end
234
+
235
+ def collection
236
+ @collection
237
+ end
238
+
239
+ def add_questions(questions)
240
+ questions.each {|q| add_question(q)}
241
+ return self
242
+ end
243
+
244
+ def add_question(question)
245
+ _add_to_collection_if_eligible(question)
246
+ if question.is_numbered?
247
+ _increment_question_number
248
+ end
249
+ return self
250
+ end
251
+
252
+ private
253
+
254
+ def _get_description(question)
255
+ @question_number.to_s + ') ' + (question.part_of_group? ? question.question_group.text + ": " : "") +question.text
256
+ end
257
+
258
+ def _add_to_collection(question)
259
+ description = _get_description(question)
260
+ @collection.push([description, question.id])
261
+ end
262
+
263
+ def _add_to_collection_if_eligible(question)
264
+ _add_to_collection(question) if question.is_eligible? && _this_is_not_the_base_question?(question)
265
+ end
266
+
267
+ def _this_is_not_the_base_question?(question)
268
+ if question.part_of_group?
269
+ question.question_group_id != @base_question.question_group_id
270
+ else
271
+ question.id != @base_question.id
272
+ end
273
+ end
274
+
275
+ def _increment_question_number
276
+ @question_number += 1
277
+ end
278
+ end
279
+
280
+ ## This shouldn't be here but breaks saving nested attributes on question when put
281
+ ## in QuestionMethods. Not sure why, but leave for now and revisit later.
282
+ class PossibleControllingQuestion < Question
283
+ def is_eligible?
284
+ question_type_id!=:label && question_type_id!=:file
285
+ end
286
+ end