fe 0.0.3

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.
Files changed (260) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +20 -0
  4. data/Rakefile +48 -0
  5. data/app/assets/images/fe/ajax-loader.gif +0 -0
  6. data/app/assets/images/fe/butgrad.png +0 -0
  7. data/app/assets/images/fe/icons/add.png +0 -0
  8. data/app/assets/images/fe/icons/application_form.png +0 -0
  9. data/app/assets/images/fe/icons/application_form_add.png +0 -0
  10. data/app/assets/images/fe/icons/arrow-move.png +0 -0
  11. data/app/assets/images/fe/icons/arrow_out.png +0 -0
  12. data/app/assets/images/fe/icons/asterisk_yellow.png +0 -0
  13. data/app/assets/images/fe/icons/book-open-list.png +0 -0
  14. data/app/assets/images/fe/icons/book_open.png +0 -0
  15. data/app/assets/images/fe/icons/briefcase.png +0 -0
  16. data/app/assets/images/fe/icons/calendar_view_day.png +0 -0
  17. data/app/assets/images/fe/icons/checkbox.png +0 -0
  18. data/app/assets/images/fe/icons/copy_paste.gif +0 -0
  19. data/app/assets/images/fe/icons/disk.png +0 -0
  20. data/app/assets/images/fe/icons/document--pencil.png +0 -0
  21. data/app/assets/images/fe/icons/document-copy.png +0 -0
  22. data/app/assets/images/fe/icons/map_magnify.png +0 -0
  23. data/app/assets/images/fe/icons/minus-button.png +0 -0
  24. data/app/assets/images/fe/icons/move.png +0 -0
  25. data/app/assets/images/fe/icons/page_error.png +0 -0
  26. data/app/assets/images/fe/icons/page_valid.png +0 -0
  27. data/app/assets/images/fe/icons/page_white.png +0 -0
  28. data/app/assets/images/fe/icons/page_white_add.png +0 -0
  29. data/app/assets/images/fe/icons/page_white_error.png +0 -0
  30. data/app/assets/images/fe/icons/paper-clip.png +0 -0
  31. data/app/assets/images/fe/icons/pencil-small.png +0 -0
  32. data/app/assets/images/fe/icons/pencil.png +0 -0
  33. data/app/assets/images/fe/icons/question-balloon.png +0 -0
  34. data/app/assets/images/fe/icons/radio.png +0 -0
  35. data/app/assets/images/fe/icons/star-small.png +0 -0
  36. data/app/assets/images/fe/icons/table.png +0 -0
  37. data/app/assets/images/fe/icons/text_align_left.png +0 -0
  38. data/app/assets/images/fe/icons/text_horizontalrule.png +0 -0
  39. data/app/assets/images/fe/icons/textfield.png +0 -0
  40. data/app/assets/images/fe/indent.png +0 -0
  41. data/app/assets/images/fe/overlay.png +0 -0
  42. data/app/assets/images/fe/selected_bg.jpg +0 -0
  43. data/app/assets/images/fe/status.gif +0 -0
  44. data/app/assets/images/fe/tooltip/black.png +0 -0
  45. data/app/assets/images/fe/tooltip/black_arrow.png +0 -0
  46. data/app/assets/images/fe/tooltip/black_arrow_big.png +0 -0
  47. data/app/assets/images/fe/tooltip/black_big.png +0 -0
  48. data/app/assets/images/fe/tooltip/white.png +0 -0
  49. data/app/assets/images/fe/tooltip/white_arrow.png +0 -0
  50. data/app/assets/images/fe/tooltip/white_arrow_big.png +0 -0
  51. data/app/assets/images/fe/tooltip/white_big.png +0 -0
  52. data/app/assets/images/fe/uploadify/cancel.png +0 -0
  53. data/app/assets/images/fe/uploadify/uploadify.swf +0 -0
  54. data/app/assets/javascripts/fe/admin.js +7 -0
  55. data/app/assets/javascripts/fe/jquery.metadata.js +122 -0
  56. data/app/assets/javascripts/fe/jquery.scrollTo-min.js +7 -0
  57. data/app/assets/javascripts/fe/jquery.uploadify.v2.1.0.js +258 -0
  58. data/app/assets/javascripts/fe/jquery.validate.pack.js +15 -0
  59. data/app/assets/javascripts/fe/qe.admin.js +115 -0
  60. data/app/assets/javascripts/fe/qe.common.js +57 -0
  61. data/app/assets/javascripts/fe/qe.public.js +331 -0
  62. data/app/assets/javascripts/fe/swfobject.js +4 -0
  63. data/app/assets/stylesheets/fe/qe.screen.css.scss.erb +552 -0
  64. data/app/assets/stylesheets/fe/reset.css +55 -0
  65. data/app/assets/stylesheets/fe/validation.css +91 -0
  66. data/app/controllers/fe/admin/elements_controller.rb +185 -0
  67. data/app/controllers/fe/admin/email_templates_controller.rb +61 -0
  68. data/app/controllers/fe/admin/question_pages_controller.rb +113 -0
  69. data/app/controllers/fe/admin/question_sheets_controller.rb +106 -0
  70. data/app/controllers/fe/answer_pages_controller.rb +3 -0
  71. data/app/controllers/fe/answer_sheets_controller.rb +3 -0
  72. data/app/controllers/fe/concerns/answer_pages_controller_concern.rb +80 -0
  73. data/app/controllers/fe/concerns/answer_sheets_controller_concern.rb +84 -0
  74. data/app/controllers/fe/reference_sheets_controller.rb +29 -0
  75. data/app/helpers/fe/answer_pages_helper.rb +19 -0
  76. data/app/helpers/fe/application_helper.rb +49 -0
  77. data/app/mailers/fe/notifier.rb +22 -0
  78. data/app/models/fe/answer.rb +13 -0
  79. data/app/models/fe/answer_pages_presenter.rb +13 -0
  80. data/app/models/fe/answer_sheet.rb +10 -0
  81. data/app/models/fe/answer_sheet_question_sheet.rb +7 -0
  82. data/app/models/fe/attachment_field.rb +7 -0
  83. data/app/models/fe/choice_field.rb +7 -0
  84. data/app/models/fe/concerns/answer_concern.rb +36 -0
  85. data/app/models/fe/concerns/answer_pages_presenter_concern.rb +99 -0
  86. data/app/models/fe/concerns/answer_sheet_concern.rb +61 -0
  87. data/app/models/fe/concerns/choice_field_concern.rb +131 -0
  88. data/app/models/fe/condition.rb +53 -0
  89. data/app/models/fe/date_field.rb +52 -0
  90. data/app/models/fe/element.rb +164 -0
  91. data/app/models/fe/email_template.rb +7 -0
  92. data/app/models/fe/option.rb +10 -0
  93. data/app/models/fe/option_group.rb +10 -0
  94. data/app/models/fe/page.rb +101 -0
  95. data/app/models/fe/page_element.rb +9 -0
  96. data/app/models/fe/page_link.rb +15 -0
  97. data/app/models/fe/paragraph.rb +10 -0
  98. data/app/models/fe/payment.rb +52 -0
  99. data/app/models/fe/payment_question.rb +22 -0
  100. data/app/models/fe/presenter.rb +23 -0
  101. data/app/models/fe/question.rb +256 -0
  102. data/app/models/fe/question_grid.rb +26 -0
  103. data/app/models/fe/question_grid_with_total.rb +11 -0
  104. data/app/models/fe/question_set.rb +82 -0
  105. data/app/models/fe/question_sheet.rb +73 -0
  106. data/app/models/fe/reference_question.rb +42 -0
  107. data/app/models/fe/reference_sheet.rb +149 -0
  108. data/app/models/fe/section.rb +12 -0
  109. data/app/models/fe/state_chooser.rb +10 -0
  110. data/app/models/fe/text_field.rb +29 -0
  111. data/app/views/fe/admin/elements/_errors.html.erb +1 -0
  112. data/app/views/fe/admin/elements/create.js.erb +11 -0
  113. data/app/views/fe/admin/elements/destroy.js.erb +4 -0
  114. data/app/views/fe/admin/elements/drop.js.erb +2 -0
  115. data/app/views/fe/admin/elements/duplicate.js.erb +2 -0
  116. data/app/views/fe/admin/elements/edit.js.erb +4 -0
  117. data/app/views/fe/admin/elements/error.js.erb +4 -0
  118. data/app/views/fe/admin/elements/new.js.erb +10 -0
  119. data/app/views/fe/admin/elements/reorder.js.erb +0 -0
  120. data/app/views/fe/admin/elements/update.js.erb +9 -0
  121. data/app/views/fe/admin/email_templates/_form.html.erb +8 -0
  122. data/app/views/fe/admin/email_templates/edit.html.erb +13 -0
  123. data/app/views/fe/admin/email_templates/index.html.erb +20 -0
  124. data/app/views/fe/admin/email_templates/new.html.erb +11 -0
  125. data/app/views/fe/admin/panels/_advanced_options.html.erb +16 -0
  126. data/app/views/fe/admin/panels/_common_fields.html.erb +24 -0
  127. data/app/views/fe/admin/panels/_condition.html.erb +6 -0
  128. data/app/views/fe/admin/panels/_insert.html.erb +39 -0
  129. data/app/views/fe/admin/panels/_nav_controls.html.erb +6 -0
  130. data/app/views/fe/admin/panels/_page.html.erb +3 -0
  131. data/app/views/fe/admin/panels/_pages_list.html.erb +16 -0
  132. data/app/views/fe/admin/panels/_prop_attachment_field.html.erb +2 -0
  133. data/app/views/fe/admin/panels/_prop_choice_field.html.erb +46 -0
  134. data/app/views/fe/admin/panels/_prop_date_field.html.erb +7 -0
  135. data/app/views/fe/admin/panels/_prop_element.html.erb +30 -0
  136. data/app/views/fe/admin/panels/_prop_page.html.erb +21 -0
  137. data/app/views/fe/admin/panels/_prop_paragraph.html.erb +32 -0
  138. data/app/views/fe/admin/panels/_prop_question_grid.html.erb +23 -0
  139. data/app/views/fe/admin/panels/_prop_question_grid_with_total.html.erb +14 -0
  140. data/app/views/fe/admin/panels/_prop_reference_question.html.erb +12 -0
  141. data/app/views/fe/admin/panels/_prop_section.html.erb +2 -0
  142. data/app/views/fe/admin/panels/_prop_sheet.html.erb +17 -0
  143. data/app/views/fe/admin/panels/_prop_text_field.html.erb +20 -0
  144. data/app/views/fe/admin/question_pages/_element.html.erb +18 -0
  145. data/app/views/fe/admin/question_pages/_element_show.html.erb +10 -0
  146. data/app/views/fe/admin/question_pages/_errors.html.erb +1 -0
  147. data/app/views/fe/admin/question_pages/_question_page.html.erb +13 -0
  148. data/app/views/fe/admin/question_pages/create.js.erb +11 -0
  149. data/app/views/fe/admin/question_pages/destroy.js.erb +5 -0
  150. data/app/views/fe/admin/question_pages/edit.js.erb +3 -0
  151. data/app/views/fe/admin/question_pages/error.js.erb +4 -0
  152. data/app/views/fe/admin/question_pages/show.js.erb +8 -0
  153. data/app/views/fe/admin/question_pages/show_panel.js.erb +3 -0
  154. data/app/views/fe/admin/question_pages/update.js.erb +2 -0
  155. data/app/views/fe/admin/question_sheets/_errors.html.erb +1 -0
  156. data/app/views/fe/admin/question_sheets/edit.js.erb +3 -0
  157. data/app/views/fe/admin/question_sheets/error.js.erb +5 -0
  158. data/app/views/fe/admin/question_sheets/index.html.erb +41 -0
  159. data/app/views/fe/admin/question_sheets/new.html.erb +15 -0
  160. data/app/views/fe/admin/question_sheets/show.html.erb +27 -0
  161. data/app/views/fe/admin/question_sheets/update.js.erb +2 -0
  162. data/app/views/fe/answer_pages/_answer_page.html.erb +56 -0
  163. data/app/views/fe/answer_pages/_element.html.erb +9 -0
  164. data/app/views/fe/answer_pages/update.js.erb +5 -0
  165. data/app/views/fe/answer_sheets/_answer_sheet.html.erb +24 -0
  166. data/app/views/fe/answer_sheets/_element.html.erb +54 -0
  167. data/app/views/fe/answer_sheets/_incomplete.html.erb +10 -0
  168. data/app/views/fe/answer_sheets/_page_link.html.erb +7 -0
  169. data/app/views/fe/answer_sheets/_pages_list.html.erb +11 -0
  170. data/app/views/fe/answer_sheets/_title.html.erb +1 -0
  171. data/app/views/fe/answer_sheets/edit.html.erb +60 -0
  172. data/app/views/fe/answer_sheets/incomplete.js.erb +5 -0
  173. data/app/views/fe/answer_sheets/index.html.erb +18 -0
  174. data/app/views/fe/answer_sheets/send_reference_invite.js.erb +8 -0
  175. data/app/views/fe/answer_sheets/show.html.erb +13 -0
  176. data/app/views/fe/help/builder.html +33 -0
  177. data/app/views/fe/help/question_grid.html +18 -0
  178. data/app/views/fe/questions/_acceptance.html.erb +13 -0
  179. data/app/views/fe/questions/_attachment_field.html.erb +42 -0
  180. data/app/views/fe/questions/_checkbox_field.html.erb +49 -0
  181. data/app/views/fe/questions/_country.html.erb +7 -0
  182. data/app/views/fe/questions/_date_field.html.erb +7 -0
  183. data/app/views/fe/questions/_date_field_mmyy.html.erb +9 -0
  184. data/app/views/fe/questions/_drop_down_field.html.erb +7 -0
  185. data/app/views/fe/questions/_paragraph.html.erb +1 -0
  186. data/app/views/fe/questions/_question_grid.html.erb +65 -0
  187. data/app/views/fe/questions/_question_grid_with_total.html.erb +57 -0
  188. data/app/views/fe/questions/_questions.html.erb +9 -0
  189. data/app/views/fe/questions/_radio_button_field.html.erb +41 -0
  190. data/app/views/fe/questions/_rating.html.erb +25 -0
  191. data/app/views/fe/questions/_reference_discipler.html.erb +1 -0
  192. data/app/views/fe/questions/_reference_friend.html.erb +1 -0
  193. data/app/views/fe/questions/_reference_parent.html.erb +1 -0
  194. data/app/views/fe/questions/_reference_peer.html.erb +1 -0
  195. data/app/views/fe/questions/_reference_question.html.erb +38 -0
  196. data/app/views/fe/questions/_reference_roommate.html.erb +1 -0
  197. data/app/views/fe/questions/_reference_spiritual.html.erb +1 -0
  198. data/app/views/fe/questions/_reference_staff.html.erb +1 -0
  199. data/app/views/fe/questions/_section.html.erb +1 -0
  200. data/app/views/fe/questions/_state_chooser.html.erb +7 -0
  201. data/app/views/fe/questions/_text_area_field.html.erb +6 -0
  202. data/app/views/fe/questions/_text_field.html.erb +8 -0
  203. data/app/views/fe/questions/_yes_no.html.erb +17 -0
  204. data/app/views/fe/questions/_yes_no_field.erb +17 -0
  205. data/app/views/fe/reference_sheets/not_found.html.erb +5 -0
  206. data/app/views/layouts/fe/application.html.erb +31 -0
  207. data/app/views/layouts/fe/qe.admin.html.erb +30 -0
  208. data/config/routes.rb +49 -0
  209. data/db/migrate/20131003041856_core.rb +91 -0
  210. data/db/migrate/20131003044250_create_reference_sheets.rb +23 -0
  211. data/db/migrate/20131003044436_add_element_and_answer_fields.rb +10 -0
  212. data/db/migrate/20131003044518_create_email_templates.rb +17 -0
  213. data/db/migrate/20131003044621_add_max_lengths.rb +8 -0
  214. data/db/migrate/20131003044714_create_join_table.rb +11 -0
  215. data/db/migrate/20131016162128_remove_question_id_from_element.rb +9 -0
  216. data/lib/fe.rb +22 -0
  217. data/lib/fe/engine.rb +19 -0
  218. data/lib/fe/version.rb +3 -0
  219. data/lib/generators/fe/install_generator.rb +132 -0
  220. data/lib/tasks/qe_tasks.rake +4 -0
  221. data/spec/controllers/fe/admin/elements_controller_spec.rb +4 -0
  222. data/spec/controllers/fe/admin/email_templates_controller_spec.rb +4 -0
  223. data/spec/controllers/fe/admin/question_pages_controller_spec.rb +4 -0
  224. data/spec/controllers/fe/admin/question_sheets_controller_spec.rb +4 -0
  225. data/spec/controllers/fe/answer_pages_controller_spec.rb +4 -0
  226. data/spec/controllers/fe/answer_sheets_controller_spec.rb +4 -0
  227. data/spec/controllers/fe/reference_sheets_controller_spec.rb +4 -0
  228. data/spec/factories/answer_sheets.rb +5 -0
  229. data/spec/factories/answers.rb +4 -0
  230. data/spec/factories/paragraphs.rb +4 -0
  231. data/spec/factories/question_sheet.rb +5 -0
  232. data/spec/factories/reference_questions.rb +4 -0
  233. data/spec/models/fe/answer_sheet_question_sheet_spec.rb +6 -0
  234. data/spec/models/fe/answer_sheet_spec.rb +8 -0
  235. data/spec/models/fe/answer_spec.rb +13 -0
  236. data/spec/models/fe/attachment_field_spec.rb +4 -0
  237. data/spec/models/fe/choice_field_spec.rb +5 -0
  238. data/spec/models/fe/condition_spec.rb +8 -0
  239. data/spec/models/fe/date_field_spec.rb +49 -0
  240. data/spec/models/fe/element_spec.rb +12 -0
  241. data/spec/models/fe/email_template_spec.rb +5 -0
  242. data/spec/models/fe/option_group_spec.rb +4 -0
  243. data/spec/models/fe/option_spec.rb +4 -0
  244. data/spec/models/fe/page_element_spec.rb +6 -0
  245. data/spec/models/fe/page_link_spec.rb +4 -0
  246. data/spec/models/fe/page_spec.rb +14 -0
  247. data/spec/models/fe/paragraph_spec.rb +17 -0
  248. data/spec/models/fe/question_grid_spec.rb +4 -0
  249. data/spec/models/fe/question_grid_with_total_spec.rb +4 -0
  250. data/spec/models/fe/question_set_spec.rb +4 -0
  251. data/spec/models/fe/question_sheet_spec.rb +8 -0
  252. data/spec/models/fe/question_spec.rb +20 -0
  253. data/spec/models/fe/reference_question_spec.rb +17 -0
  254. data/spec/models/fe/reference_sheet_spec.rb +11 -0
  255. data/spec/models/fe/section_spec.rb +4 -0
  256. data/spec/models/fe/state_chooser_spec.rb +4 -0
  257. data/spec/models/fe/text_field_spec.rb +17 -0
  258. data/spec/spec_helper.rb +66 -0
  259. data/spec/support/database.txt +28 -0
  260. metadata +508 -0
@@ -0,0 +1,7 @@
1
+ module Fe
2
+ class AnswerSheetQuestionSheet < ActiveRecord::Base
3
+ self.table_name = self.table_name.sub('fe_', Fe.table_name_prefix)
4
+ belongs_to :answer_sheet, class_name: Fe.answer_sheet_class
5
+ belongs_to :question_sheet, class_name: 'Fe::QuestionSheet'
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # AttachmentField
2
+ # - a file upload question
3
+ module Fe
4
+ class AttachmentField < Question
5
+
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # ChoiceField
2
+ # - a question that allows the selection of one or more choices
3
+ module Fe
4
+ class ChoiceField < Question
5
+ include ChoiceFieldConcern
6
+ end
7
+ end
@@ -0,0 +1,36 @@
1
+ module Fe
2
+ module AnswerConcern
3
+ extend ActiveSupport::Concern
4
+ include ActionView::Helpers::TextHelper
5
+
6
+ included do
7
+
8
+ belongs_to :answer_sheet
9
+ belongs_to :question, :class_name => "Element", :foreign_key => "question_id"
10
+
11
+ # validates_presence_of :value
12
+ validates_length_of :short_value, :maximum => 255, :allow_nil => true
13
+
14
+ before_save :set_value_from_filename
15
+ end
16
+
17
+ def set(value, short_value = value)
18
+ self.value = value
19
+ self.short_value = truncate(short_value, :length => 225) # adds ... if truncated (but not if not)
20
+ end
21
+
22
+ def to_s
23
+ self.value
24
+ end
25
+
26
+ def set_value_from_filename
27
+ self.value = self.short_value = self.attachment_file_name if self[:attachment_file_name].present?
28
+ end
29
+
30
+ module ClassMethods
31
+ def table_name
32
+ "#{Fe.table_name_prefix}answers"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,99 @@
1
+ module Fe
2
+ module AnswerPagesPresenterConcern
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ attr_accessor :active_answer_sheet, :page_links, :active_page, :pages
7
+ end
8
+
9
+ def initialize(controller, answer_sheets, a = nil, custom_pages = nil)
10
+ super(controller)
11
+ @answer_sheets = Array.wrap(answer_sheets)
12
+ @active_answer_sheet = @answer_sheets.first
13
+ initialize_pages(@active_answer_sheet)
14
+
15
+ @page_links = page_list(@answer_sheets, a, custom_pages)
16
+ end
17
+
18
+ def questions_for_page(page_id=:first)
19
+ @active_page = page_id == :first ? pages.first : pages.detect {|p| p.id == page_id.to_i}
20
+ @active_page ||= @active_answer_sheet.pages.visible.includes(:elements).find(page_id)
21
+ Fe::QuestionSet.new(@active_page ? @active_page.elements : [], @active_answer_sheet)
22
+ end
23
+
24
+ def all_questions_for_page(page_id=:first)
25
+ @active_page = page_id == :first ? pages.first : pages.detect {|p| p.id == page_id.to_i}
26
+ @active_page ||= @active_answer_sheet.pages.visible.find(page_id)
27
+ Fe::QuestionSet.new(@active_page ? @active_page.all_elements : [], @active_answer_sheet)
28
+ end
29
+
30
+ # title
31
+ def sheet_title
32
+ @active_answer_sheet.question_sheet.label
33
+ end
34
+
35
+ def active_page_link
36
+ return unless @active_page
37
+ link = new_page_link(@active_answer_sheet, @active_page)
38
+ link.save_path = answer_sheet_page_path(@active_answer_sheet, @active_page)
39
+ link
40
+ end
41
+
42
+ def next_page
43
+ active_page_dom_id = active_page_link.dom_id
44
+
45
+ this_page = @page_links.find {|p| p.dom_id == active_page_dom_id}
46
+ @page_links.at( @page_links.index(this_page) + 1 ) unless this_page.nil?
47
+ end
48
+
49
+ def reference?
50
+ if @active_answer_sheet.respond_to?(:apply_sheet)
51
+ @active_answer_sheet.apply_sheet.sleeve_sheet.assign_to == 'reference'
52
+ else
53
+ false
54
+ end
55
+ end
56
+
57
+ def initialize_pages(answer_sheet)
58
+ @pages = []
59
+ answer_sheet.question_sheets.each do |qs|
60
+ qs.pages.visible.each do |page|
61
+ @pages << page
62
+ end
63
+ end
64
+ end
65
+
66
+ def started?
67
+ active_answer_sheet.question_sheets.each do |qs|
68
+ qs.pages.visible.each do |page|
69
+ return true if page.started?(active_answer_sheet)
70
+ end
71
+ end
72
+ end
73
+
74
+ def new_page_link(answer_sheet, page, a = nil)
75
+ Fe::PageLink.new(page.label, edit_answer_sheet_page_path(answer_sheet, page, :a => a), dom_page(answer_sheet, page), page) if page
76
+ end
77
+
78
+ protected
79
+
80
+ # for pages_list sidebar
81
+ def page_list(answer_sheets, a = nil, custom_pages = nil)
82
+ page_list = []
83
+ answer_sheets.each do |answer_sheet|
84
+ pages.each do |page|
85
+ page_list << new_page_link(answer_sheet, page, a)
86
+ end
87
+ end
88
+ page_list = page_list + custom_pages unless custom_pages.nil?
89
+ page_list
90
+ end
91
+
92
+ # page is identified by answer sheet, so can have multiple sheets loaded at once
93
+ def dom_page(answer_sheet, page)
94
+ dom = "#{dom_id(answer_sheet)}-#{dom_id(page)}"
95
+ dom += "-no_cache" if page.no_cache
96
+ dom
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,61 @@
1
+ module Fe
2
+ module AnswerSheetConcern
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_many :answer_sheet_question_sheets,
7
+ :class_name => "Fe::AnswerSheetQuestionSheet",
8
+ :foreign_key => 'answer_sheet_id'
9
+
10
+ has_many :question_sheets,
11
+ :through => :answer_sheet_question_sheets
12
+
13
+ has_many :answers,
14
+ :class_name => 'Fe::Answer',
15
+ :foreign_key => 'answer_sheet_id'
16
+
17
+ has_many :reference_sheets,
18
+ :class_name => "Fe::ReferenceSheet",
19
+ :foreign_key => "applicant_answer_sheet_id"
20
+ end
21
+
22
+ def complete?
23
+ !completed_at.nil?
24
+ end
25
+
26
+ # answers for this sheet, grouped by question id
27
+ def answers_by_question
28
+ @answers_by_question ||= answers.group_by { |answer| answer.question_id }
29
+ end
30
+
31
+ # Convenience method if there is only one question sheet in your system
32
+ def question_sheet
33
+ question_sheets.first
34
+ end
35
+
36
+ def pages
37
+ Page.where(:question_sheet_id => question_sheets.collect(&:id))
38
+ end
39
+
40
+ def completely_filled_out?
41
+ pages.all? {|p| p.complete?(self)}
42
+ end
43
+
44
+ def has_answer_for?(question_id)
45
+ !answers_by_question[question_id].nil?
46
+ end
47
+
48
+ def reference?
49
+ false
50
+ end
51
+
52
+ def percent_complete
53
+ num_questions = question_sheets.inject(0.0) { |sum, qs| qs.nil? ? sum : qs.questions.length + sum }
54
+ return 0 if num_questions == 0
55
+ num_answers = answers.where("value IS NOT NULL && value != ''").select("DISTINCT question_id").count
56
+ [ [ (num_answers.to_f / num_questions.to_f * 100.0).to_i, 100 ].min, 0 ].max
57
+ end
58
+
59
+ def collat_title() "" end
60
+ end
61
+ end
@@ -0,0 +1,131 @@
1
+ require 'net/http'
2
+ begin
3
+ require 'xml/libxml'
4
+ rescue LoadError
5
+ require 'rexml/document'
6
+ end
7
+
8
+ module Fe
9
+ module ChoiceFieldConcern
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ has_many :elements, :class_name => "Element", :foreign_key => "conditional_id", :dependent => :nullify#, :order => :position
14
+ end
15
+
16
+ # Returns choices stored one per line in content field
17
+ def choices
18
+ retVal = Array.new
19
+ if ['yes-no', 'acceptance'].include?(self.style)
20
+ return [["Yes",1],["No",0]]
21
+ elsif !source.blank?
22
+ begin
23
+ doc = XML::Document.file(source)
24
+ options = doc.find(text_xpath).collect { |n| n.content }
25
+ values = doc.find(value_xpath).collect { |n| n.content }
26
+ retVal = [options, values].transpose
27
+ rescue NameError
28
+ doc = REXML::Document.new Net::HTTP.get_response(URI.parse(source)).body
29
+ retVal = [ doc.elements.collect(text_xpath){|c|c.text}, doc.elements.collect(value_xpath){|c|c.text} ].transpose.sort
30
+ end
31
+ elsif !content.nil?
32
+ content.split("\n").each do |opt|
33
+ pair = opt.strip.split(";").reverse!
34
+ pair[1] ||= pair[0]
35
+ retVal << pair
36
+ end
37
+ end
38
+ return retVal
39
+ end
40
+
41
+ def has_answer?(choice, app)
42
+ responses(app).each do |r| # loop through Answers
43
+ # legacy field type choices may be int or tinyint
44
+ # raise r.inspect + ' - ' + choice.inspect if id == 1137 && r != 1
45
+ # r = r.to_s
46
+ return true if case true
47
+ when is_true(r) then is_true(choice)
48
+ when is_false(r) then is_false(choice)
49
+ else
50
+ r.to_s == choice.to_s
51
+ end
52
+ end
53
+ false
54
+ end
55
+
56
+ # which view to render this element?
57
+ def ptemplate
58
+ if self.style == 'checkbox'
59
+ 'checkbox_field'
60
+ elsif self.style == 'drop-down'
61
+ 'drop_down_field'
62
+ elsif self.style == 'radio'
63
+ 'radio_button_field'
64
+ elsif self.style == 'yes-no'
65
+ 'yes_no'
66
+ elsif self.style == 'rating'
67
+ 'rating'
68
+ elsif self.style == 'acceptance'
69
+ 'acceptance'
70
+ elsif self.style == 'country'
71
+ 'country'
72
+ end
73
+ end
74
+
75
+ # element view provides the element label?
76
+ def default_label?
77
+ if self.style == 'acceptance' || self.hide_option_labels?
78
+ false # template provides its own label
79
+ else
80
+ true
81
+ end
82
+ end
83
+
84
+ # css class names for javascript-based validation
85
+ def validation_class(answer_sheet)
86
+ if self.required?(answer_sheet)
87
+ if self.style == 'drop-down'
88
+ 'validate-selection required'
89
+ elsif self.style == 'rating'
90
+ 'validate-rating required'
91
+ elsif self.style == 'acceptance'
92
+ 'required'
93
+ else
94
+ 'validate-one-required required'
95
+ end
96
+ else
97
+ ''
98
+ end
99
+ end
100
+
101
+ def display_response(app=nil)
102
+ r = responses(app)
103
+ r.reject! {|a| a.class == Answer && a.value.blank?}
104
+ if r.blank?
105
+ ""
106
+ elsif self.style == 'yes-no'
107
+ ans = r.first
108
+ if ans.class == Answer
109
+ is_true(ans.value) ? "Yes" : "No"
110
+ else
111
+ is_true(ans) ? "Yes" : "No"
112
+ end
113
+ elsif self.style == 'acceptance'
114
+ "Accepted" # if not blank, it's accepted
115
+ else
116
+ r.compact.join(", ")
117
+ end
118
+ end
119
+
120
+ protected
121
+ def is_true(val)
122
+ [1,'1',true,'true','Yes','yes'].include?(val) # note: true = anything but false | nil
123
+ end
124
+
125
+ def is_false(val)
126
+ # returns false if false (a bit odd)
127
+ [0,'0',false,'false','No','no'].include?(val)
128
+ end
129
+
130
+ end
131
+ end
@@ -0,0 +1,53 @@
1
+ # :trigger_id - question that controls the state of the dependent pages/questions
2
+ # :expresion - a single expression for eval() by both Javascript and Ruby
3
+ # i.e. "answer == 'yes'"
4
+ # a question can have more than one answer (choose many) in which case ANY answer will do (find)
5
+ module Fe
6
+ class Condition < ActiveRecord::Base
7
+ self.table_name = self.table_name.sub('fe_', Fe.table_name_prefix)
8
+
9
+ belongs_to :question_sheet
10
+
11
+ belongs_to :trigger,
12
+ :class_name => "Question",
13
+ :foreign_key => "trigger_id"
14
+
15
+ validates_presence_of :expression
16
+ validates_length_of :expression, :maximum => 255, :allow_nil => true
17
+
18
+ # evaluate triggering element against expression and return match|nil
19
+ def evaluate?
20
+ true
21
+ # answers = self.trigger.response # answers loaded?
22
+ # expression = self.expression.downcase
23
+ # answers.find {|answer| answer = answer.downcase; eval(expression)}
24
+ end
25
+
26
+ # javascript to toggle pages/elements based on the "response"
27
+ def trigger_js
28
+ # will find the first answer (if multiple/checkboxes) where the expression evaluates to true (downcase both to be case insensitive)
29
+ # if no match, disabled will be true, otherwise false
30
+ js = <<-JS
31
+ disabled = (response.find(function(answer) {
32
+ answer = toLowerCase(answer);
33
+ return eval("#{escape_javascript(self.expression.downcase)}");
34
+ }) == undefined);
35
+ JS
36
+
37
+ if toggle_id.nil?
38
+ # toggling a whole page (link), which will affect final page validation
39
+ else
40
+ # toggling an element (form element)... if page is loaded/cached (if not, the server-side will take care of it on load)
41
+ js = js + <<-JS
42
+ if(page_handler.isPageLoaded('page_#{self.toggle_page_id}'))
43
+ {
44
+ $('element_#{self.toggle_id}').disabled = disabled;
45
+ }
46
+ JS
47
+ end
48
+
49
+ js
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,52 @@
1
+ # DateField
2
+ # - a question that provides a calendar/date picker
3
+ module Fe
4
+ class DateField < Question
5
+
6
+ def validation_class(answer_sheet = nil)
7
+ if self.style == 'mmyy'
8
+ 'validate-selection ' + super
9
+ else
10
+ 'validate-date ' + super
11
+ end
12
+ end
13
+
14
+ def response(answer_sheet = nil)
15
+ r = super
16
+ return nil if r.blank?
17
+ begin
18
+ if r.is_a?(String)
19
+ parts = r.split('/')
20
+ if parts.length == 3
21
+ r = Time.mktime(parts[2], parts[0], parts[1])
22
+ else
23
+ r = Time.parse(r)
24
+ end
25
+ end
26
+ rescue ArgumentError
27
+ r = ''
28
+ end
29
+ r
30
+ end
31
+
32
+ def display_response(answer_sheet = nil)
33
+ return format_date_response(answer_sheet)
34
+ end
35
+
36
+ def format_date_response(answer_sheet = nil)
37
+ r = response(answer_sheet)
38
+ r = r.strftime("%m/%d/%Y") unless r.blank?
39
+ r
40
+ end
41
+
42
+ # which view to render this element?
43
+ def ptemplate
44
+ if self.style == 'mmyy'
45
+ 'date_field_mmyy'
46
+ else
47
+ 'date_field'
48
+ end
49
+ end
50
+
51
+ end
52
+ end