surveyor 0.21.0 → 0.22.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +0 -6
- data/README.md +40 -14
- data/app/helpers/surveyor_helper.rb +1 -85
- data/app/views/partials/_answer.html.haml +5 -4
- data/app/views/partials/_question.html.haml +7 -5
- data/app/views/partials/_question_group.html.haml +2 -2
- data/app/views/surveyor/export.json.rabl +75 -0
- data/app/views/surveyor/show.html.haml +75 -13
- data/app/views/surveyor/show.json.rabl +14 -0
- data/config/routes.rb +2 -3
- data/doc/surveyor reject or delete decision matrix.png +0 -0
- data/features/export_to_json.feature +96 -0
- data/features/show_survey.feature +42 -0
- data/features/step_definitions/{common_setps.rb → common_steps.rb} +0 -0
- data/features/step_definitions/surveyor_steps.rb +46 -12
- data/features/step_definitions/web_steps.rb +15 -5
- data/features/support/paths.rb +2 -1
- data/features/surveyor.feature +192 -41
- data/features/surveyor_parser.feature +10 -10
- data/features/{redcap_parser.feature → z_redcap_parser.feature} +9 -6
- data/lib/formtastic/surveyor_builder.rb +1 -4
- data/lib/generators/surveyor/install_generator.rb +6 -5
- data/lib/generators/surveyor/templates/db/migrate/add_api_id_to_question_groups.rb +9 -0
- data/lib/generators/surveyor/templates/db/migrate/add_api_ids_to_response_sets_and_responses.rb +11 -0
- data/lib/generators/surveyor/templates/public/javascripts/surveyor/jquery-ui-timepicker-addon.js +1277 -0
- data/lib/generators/surveyor/templates/public/javascripts/surveyor/jquery-ui.js +11729 -0
- data/lib/generators/surveyor/templates/public/javascripts/surveyor/jquery.surveyor.js +54 -10
- data/lib/generators/surveyor/templates/public/stylesheets/sass/surveyor.sass +1 -1
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/jquery-ui-timepicker-addon.css +6 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/jquery-ui.custom.css +572 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-icons_ef8c08_256x240.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-icons_ffffff_256x240.png +0 -0
- data/lib/generators/surveyor/templates/surveys/EXTENDING_SURVEYOR.md +14 -0
- data/lib/generators/surveyor/templates/surveys/MODIFYING_SURVEYOR.md +91 -0
- data/lib/generators/surveyor/templates/surveys/date_survey.rb +15 -0
- data/lib/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +2 -2
- data/lib/surveyor/common.rb +31 -4
- data/lib/surveyor/helpers/surveyor_helper_methods.rb +99 -0
- data/lib/surveyor/models/answer_methods.rb +6 -5
- data/lib/surveyor/models/dependency_condition_methods.rb +0 -1
- data/lib/surveyor/models/dependency_methods.rb +1 -1
- data/lib/surveyor/models/question_group_methods.rb +5 -0
- data/lib/surveyor/models/question_methods.rb +5 -2
- data/lib/surveyor/models/response_methods.rb +44 -3
- data/lib/surveyor/models/response_set_methods.rb +14 -4
- data/lib/surveyor/models/survey_methods.rb +8 -2
- data/lib/surveyor/models/survey_section_methods.rb +13 -1
- data/lib/surveyor/parser.rb +18 -11
- data/lib/surveyor/render_text.rb +19 -0
- data/lib/surveyor/surveyor_controller_methods.rb +19 -1
- data/lib/surveyor/unparser.rb +1 -1
- data/lib/surveyor/version.rb +1 -1
- data/lib/tasks/surveyor_tasks.rake +1 -1
- data/spec/controllers/surveyor_controller_spec.rb +7 -3
- data/spec/helpers/surveyor_helper_spec.rb +104 -9
- data/spec/lib/chinese_survey.rb +14 -0
- data/spec/lib/common_spec.rb +52 -1
- data/spec/lib/rake_kitchen_sink.rb +40 -0
- data/spec/models/answer_spec.rb +11 -0
- data/spec/models/question_spec.rb +15 -0
- data/spec/models/response_set_spec.rb +45 -1
- data/spec/models/response_spec.rb +7 -4
- data/surveyor.gemspec +4 -2
- metadata +99 -40
- data/app/controllers/results_controller.rb +0 -13
- data/app/views/results/index.html.erb +0 -17
- data/app/views/results/show.html.erb +0 -25
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -3,9 +3,3 @@ source :rubygems
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
eval(File.read File.expand_path('../Gemfile.rails_version', __FILE__))
|
6
|
-
|
7
|
-
group :development do
|
8
|
-
# use git version for the ci:setup:rspecbase task; not there in
|
9
|
-
# 1.6.5, but might be in a later version.
|
10
|
-
gem 'ci_reporter', :git => 'git://github.com/nicksieger/ci_reporter.git'
|
11
|
-
end
|
data/README.md
CHANGED
@@ -55,34 +55,32 @@ The first question is "pick one" (radio buttons) with "other". The second questi
|
|
55
55
|
|
56
56
|
# Installation
|
57
57
|
|
58
|
-
1. Add surveyor to your Gemfile
|
58
|
+
1. Add surveyor to your Gemfile:
|
59
59
|
|
60
|
-
gem "surveyor"
|
61
|
-
gem "haml"
|
60
|
+
gem "surveyor"
|
62
61
|
|
63
62
|
Then run:
|
64
63
|
|
65
|
-
|
64
|
+
bundle install
|
66
65
|
|
67
66
|
2. Generate assets, run migrations:
|
68
67
|
|
69
|
-
|
70
|
-
|
68
|
+
script/rails generate surveyor:install
|
69
|
+
rake db:migrate
|
71
70
|
|
72
71
|
3. Try out the "kitchen sink" survey. The rake task above generates surveys from our custom survey DSL (a good format for end users and stakeholders).
|
73
72
|
|
74
|
-
|
73
|
+
rake surveyor FILE=surveys/kitchen_sink_survey.rb
|
75
74
|
|
76
|
-
4. Start up your app and visit:
|
77
|
-
|
78
|
-
http://localhost:3000/surveys
|
75
|
+
4. Start up your app and visit http://localhost:3000/surveys
|
79
76
|
|
80
77
|
Try taking the survey and compare it to the contents of the DSL file kitchen\_sink\_survey.rb. See how the DSL maps to what you see.
|
81
78
|
|
82
|
-
There are two other useful rake tasks
|
79
|
+
There are two other useful rake tasks:
|
83
80
|
|
84
|
-
`
|
85
|
-
`rake surveyor:unparse`
|
81
|
+
* `surveyor:remove` removes all unused surveys.
|
82
|
+
* `rake surveyor:unparse` exports a survey from the application into a
|
83
|
+
file in the surveyor DSL.
|
86
84
|
|
87
85
|
# Customizing surveyor
|
88
86
|
|
@@ -92,12 +90,40 @@ Surveyor's controller, models, and views may be customized via classes in your a
|
|
92
90
|
|
93
91
|
and read surveys/EXTENDING\_SURVEYOR
|
94
92
|
|
93
|
+
# PDF support
|
94
|
+
|
95
|
+
* Add the following lines to your Gemfile:
|
96
|
+
|
97
|
+
<pre>
|
98
|
+
gem 'pdfkit'
|
99
|
+
gem 'wkhtmltopdf'
|
100
|
+
</pre>
|
101
|
+
|
102
|
+
or on OSX:
|
103
|
+
|
104
|
+
<pre>
|
105
|
+
gem 'pdfkit'
|
106
|
+
gem 'wkhtmltopdf-binary'
|
107
|
+
</pre>
|
108
|
+
|
109
|
+
* Add the following to your application.rb:
|
110
|
+
|
111
|
+
<pre>
|
112
|
+
config.middleware.use PDFKit::Middleware
|
113
|
+
</pre>
|
114
|
+
|
115
|
+
* Create links with :format => 'pdf' in them, for example:
|
116
|
+
|
117
|
+
<pre>
|
118
|
+
%li= link_to "PDF", view_my_survey_path(:survey_code => response_set.survey.access_code, :response_set_code => response_set.access_code, :format => 'pdf')
|
119
|
+
</pre>
|
120
|
+
|
95
121
|
# Requirements
|
96
122
|
|
97
123
|
Surveyor depends on:
|
98
124
|
|
99
125
|
* Ruby (1.8.7 - 1.9.2)
|
100
|
-
* Rails 3.
|
126
|
+
* Rails 3.0-3.1
|
101
127
|
* HAML
|
102
128
|
* SASS
|
103
129
|
* fastercsv (or CSV for ruby 1.9) for csv exports
|
@@ -1,87 +1,3 @@
|
|
1
1
|
module SurveyorHelper
|
2
|
-
|
3
|
-
def surveyor_includes
|
4
|
-
surveyor_stylsheets + surveyor_javascripts
|
5
|
-
end
|
6
|
-
def surveyor_stylsheets
|
7
|
-
stylesheet_link_tag 'surveyor/reset', 'surveyor/dateinput', 'surveyor', 'custom'
|
8
|
-
end
|
9
|
-
def surveyor_javascripts
|
10
|
-
javascript_include_tag 'surveyor/jquery.tools.min', 'surveyor/jquery.surveyor', 'surveyor/jquery.blockUI'
|
11
|
-
end
|
12
|
-
# Helper for displaying warning/notice/error flash messages
|
13
|
-
def flash_messages(types)
|
14
|
-
types.map{|type| content_tag(:div, "#{flash[type]}".html_safe, :class => type.to_s)}.join.html_safe
|
15
|
-
end
|
16
|
-
# Section: dependencies, menu, previous and next
|
17
|
-
def dependency_explanation_helper(question,response_set)
|
18
|
-
# Attempts to explain why this dependent question needs to be answered by referenced the dependent question and users response
|
19
|
-
trigger_responses = []
|
20
|
-
dependent_questions = Question.find_all_by_id(question.dependency.dependency_conditions.map(&:question_id)).uniq
|
21
|
-
response_set.responses.find_all_by_question_id(dependent_questions.map(&:id)).uniq.each do |resp|
|
22
|
-
trigger_responses << resp.to_s
|
23
|
-
end
|
24
|
-
" You answered "#{trigger_responses.join("" and "")}" to the question "#{dependent_questions.map(&:text).join("","")}""
|
25
|
-
end
|
26
|
-
def menu_button_for(section)
|
27
|
-
submit_tag(section.title, :name => "section[#{section.id}]")
|
28
|
-
end
|
29
|
-
def previous_section
|
30
|
-
# use copy in memory instead of making extra db calls
|
31
|
-
submit_tag(t('surveyor.previous_section').html_safe, :name => "section[#{@sections[@sections.index(@section)-1].id}]") unless @sections.first == @section
|
32
|
-
end
|
33
|
-
def next_section
|
34
|
-
# use copy in memory instead of making extra db calls
|
35
|
-
@sections.last == @section ? submit_tag(t('surveyor.click_here_to_finish').html_safe, :name => "finish") : submit_tag(t('surveyor.next_section').html_safe, :name => "section[#{@sections[@sections.index(@section)+1].id}]")
|
36
|
-
end
|
37
|
-
|
38
|
-
# Questions
|
39
|
-
def q_text(obj)
|
40
|
-
@n ||= 0
|
41
|
-
return image_tag(obj.text) if obj.is_a?(Question) and obj.display_type == "image"
|
42
|
-
return obj.text if obj.is_a?(Question) and (obj.dependent? or obj.display_type == "label" or obj.part_of_group?)
|
43
|
-
"#{@n += 1}) #{obj.text}"
|
44
|
-
end
|
45
|
-
# def split_text(text = "") # Split text into with "|" delimiter - parts to go before/after input element
|
46
|
-
# {:prefix => text.split("|")[0].blank? ? " " : text.split("|")[0], :postfix => text.split("|")[1] || " "}
|
47
|
-
# end
|
48
|
-
# def question_help_helper(question)
|
49
|
-
# question.help_text.blank? ? "" : %Q(<span class="question-help">#{question.help_text}</span>)
|
50
|
-
# end
|
51
|
-
|
52
|
-
# Answers
|
53
|
-
def a_text(obj, pos=nil)
|
54
|
-
return image_tag(obj.text) if obj.is_a?(Answer) and obj.display_type == "image"
|
55
|
-
obj.split_or_hidden_text(pos)
|
56
|
-
end
|
57
|
-
def rc_to_attr(type_sym)
|
58
|
-
case type_sym.to_s
|
59
|
-
when /^date|time$/ then :datetime_value
|
60
|
-
when /(string|text|integer|float|datetime)/ then "#{type_sym.to_s}_value".to_sym
|
61
|
-
else :answer_id
|
62
|
-
end
|
63
|
-
end
|
64
|
-
def rc_to_as(type_sym)
|
65
|
-
case type_sym.to_s
|
66
|
-
when /(integer|float)/ then :string
|
67
|
-
else type_sym
|
68
|
-
end
|
69
|
-
end
|
70
|
-
def generate_pick_none_input_html(response_class, default_value, css_class)
|
71
|
-
html = {}
|
72
|
-
html[:class] = css_class unless css_class.blank?
|
73
|
-
html[:value] = default_value if response_class.blank?
|
74
|
-
html
|
75
|
-
end
|
76
|
-
|
77
|
-
# Responses
|
78
|
-
def response_for(response_set, question, answer = nil, response_group = nil)
|
79
|
-
return nil unless response_set && question && question.id
|
80
|
-
result = response_set.responses.detect{|r| (r.question_id == question.id) && (answer.blank? ? true : r.answer_id == answer.id) && (r.response_group.blank? ? true : r.response_group.to_i == response_group.to_i)}
|
81
|
-
result.blank? ? response_set.responses.build(:question_id => question.id, :response_group => response_group) : result
|
82
|
-
end
|
83
|
-
def response_idx(increment = true)
|
84
|
-
@rc ||= 0
|
85
|
-
(increment ? @rc += 1 : @rc).to_s
|
86
|
-
end
|
2
|
+
include Surveyor::Helpers::SurveyorHelperMethods
|
87
3
|
end
|
@@ -2,18 +2,19 @@
|
|
2
2
|
- rg ||= nil
|
3
3
|
- r = response_for(@response_set, q, a, rg)
|
4
4
|
- i = response_idx(q.pick != "one") # argument will be false (don't increment i) if we're on radio buttons
|
5
|
+
- disabled = defined?(disableFlag) ? disableFlag : false
|
5
6
|
= f.semantic_fields_for i, r do |ff|
|
6
7
|
= ff.quiet_input :question_id unless q.pick == "one" # don't repeat question_id if we're on radio buttons
|
7
8
|
= ff.quiet_input :id unless q.pick == "one" or r.new_record?
|
8
9
|
= ff.quiet_input :response_group, :value => rg if q.pick != "one" && g && g.display_type == "repeater"
|
9
10
|
- case q.pick
|
10
11
|
- when "one"
|
11
|
-
= ff.input :answer_id, :as => :surveyor_radio, :collection => [[a_text(a), a.id]], :label => false, :input_html => {:class => a.css_class}, :response_class => a.response_class
|
12
|
+
= ff.input :answer_id, :as => :surveyor_radio, :collection => [[a_text(a, nil, @render_context), a.id]], :label => false, :input_html => {:class => a.css_class, :disabled => disabled}, :response_class => a.response_class
|
12
13
|
- when "any"
|
13
|
-
= ff.input :answer_id, :as => :surveyor_check_boxes, :collection => [[a_text(a), a.id]], :label => false, :input_html => {:class => a.css_class}, :response_class => a.response_class
|
14
|
+
= ff.input :answer_id, :as => :surveyor_check_boxes, :collection => [[a_text(a, nil, @render_context), a.id]], :label => false, :input_html => {:class => a.css_class, :disabled => disabled}, :response_class => a.response_class
|
14
15
|
- when "none"
|
15
16
|
- if %w(date datetime time float integer string text).include? a.response_class
|
16
17
|
= ff.quiet_input :answer_id, :input_html => {:class => a.css_class, :value => a.id}
|
17
|
-
= ff.input rc_to_attr(a.response_class), :as => rc_to_as(a.response_class), :label => a_text(a, :pre).blank? ? false : a_text(a, :pre), :hint => a_text(a, :post), :input_html => generate_pick_none_input_html(r.as(a.response_class), a.default_value, a.css_class)
|
18
|
+
= ff.input rc_to_attr(a.response_class), :as => rc_to_as(a.response_class), :label => a_text(a, :pre, @render_context).blank? ? false : a_text(a, :pre, @render_context), :hint => a_text(a, :post, @render_context), :input_html => generate_pick_none_input_html(r.as(a.response_class), a.default_value, a.css_class, a.response_class, disabled)
|
18
19
|
- else
|
19
|
-
= a_text(a)
|
20
|
+
= a_text(a, nil, @render_context)
|
@@ -1,18 +1,19 @@
|
|
1
1
|
-# TODO: js for slider
|
2
2
|
- rg ||= nil
|
3
3
|
- renderer = q.renderer(g ||= nil)
|
4
|
-
=
|
5
|
-
|
4
|
+
- disabled = defined?(disableFlag) ? disableFlag : false
|
5
|
+
= f.inputs q_text(q, @render_context), :id => rg ? "q_#{q.id}_#{rg}" : "q_#{q.id}", :class => "q_#{renderer} #{q.css_class(@response_set)}" do
|
6
|
+
%span.help= render_help_text(q, @render_context)
|
6
7
|
- case renderer
|
7
8
|
- when :image, :label
|
8
|
-
- when :dropdown, :inline_dropdown, :slider, :repeater_dropdown
|
9
|
+
- when :dropdown, :inline_dropdown, :default_dropdown, :slider, :repeater_dropdown
|
9
10
|
- r = response_for(@response_set, q, nil, rg)
|
10
11
|
- i = response_idx
|
11
12
|
= f.semantic_fields_for i, r do |ff|
|
12
13
|
= ff.quiet_input :question_id
|
13
14
|
= ff.quiet_input :response_group, :value => rg if g && g.display_type == "repeater"
|
14
15
|
= ff.quiet_input :id unless r.new_record?
|
15
|
-
= ff.input :answer_id, :as => :select, :collection => q.answers.map{|a| [a.text, a.id]}, :label => q.text
|
16
|
+
= ff.input :answer_id, :as => :select, :collection => q.answers.map{|a| [a.text, a.id]}, :label => q.text, :input_html => { :disabled => disabled }
|
16
17
|
- else # :default, :inline, :inline_default
|
17
18
|
- if q.pick == "one"
|
18
19
|
- r = response_for(@response_set, q, nil, rg)
|
@@ -22,4 +23,5 @@
|
|
22
23
|
= ff.quiet_input :response_group, :value => rg if g && g.display_type == "repeater"
|
23
24
|
= ff.quiet_input :id unless r.new_record?
|
24
25
|
- q.answers.each do |a|
|
25
|
-
|
26
|
+
- next if (q.pick == "one" or q.pick == "any") and disabled and @response_set.responses.where( :question_id => q.id, :answer_id => a.id).empty?
|
27
|
+
= render a.custom_renderer || '/partials/answer', :q => q, :a => a, :f => f, :rg => rg, :g => g, :disableFlag => disabled
|
@@ -1,6 +1,6 @@
|
|
1
1
|
- renderer = g.renderer
|
2
|
-
= f.inputs q_text(g), :id => "g_#{g.id}", :class => "g_#{renderer} #{g.css_class(@response_set)}" do
|
3
|
-
%li.help= g
|
2
|
+
= f.inputs q_text(g, @render_context), :id => "g_#{g.id}", :class => "g_#{renderer} #{g.css_class(@response_set)}" do
|
3
|
+
%li.help= render_help_text(g, @render_context)
|
4
4
|
- case renderer
|
5
5
|
- when :grid
|
6
6
|
%li
|
@@ -0,0 +1,75 @@
|
|
1
|
+
object @survey
|
2
|
+
attribute :title
|
3
|
+
attribute :api_id => :uuid
|
4
|
+
node(:description, :if => lambda {|s| !s.description.blank? }){|s| s.description }
|
5
|
+
node(:reference_identifier, :if => lambda {|s| !s.reference_identifier.blank? }){|s| s.reference_identifier }
|
6
|
+
|
7
|
+
child :sections => :sections do
|
8
|
+
attributes :title, :display_order
|
9
|
+
node(:description, :if => lambda {|s| !s.description.blank? }){|s| s.description }
|
10
|
+
node(:reference_identifier, :if => lambda {|s| !s.reference_identifier.blank? }){|s| s.reference_identifier }
|
11
|
+
|
12
|
+
child :questions_and_groups => :questions_and_groups do
|
13
|
+
# both questions and question_groups have uuid, text, help_text, reference_identifier, and type
|
14
|
+
attribute :api_id => :uuid
|
15
|
+
node(:text, :if => lambda { |q| q.is_a?(Question)}){ |q| q.split_text(:pre) }
|
16
|
+
node(:text, :if => lambda { |q| q.is_a?(QuestionGroup)}){ |q| q.text }
|
17
|
+
node(:help_text, :if => lambda { |q| !q.help_text.blank? }){ |q| q.help_text }
|
18
|
+
node(:reference_identifier, :if => lambda { |q| !q.reference_identifier.blank? }){ |q| q.reference_identifier }
|
19
|
+
node(:type, :if => lambda { |q| q.display_type != "default" }){ |q| q.display_type }
|
20
|
+
|
21
|
+
# only questions
|
22
|
+
node(:pick, :if => lambda { |q| q.is_a?(Question) && q.pick != "none" }){ |q| q.pick }
|
23
|
+
node(:post_text, :if => lambda { |q| q.is_a?(Question) && !q.split_text(:post).blank? }){ |q| q.split_text(:post) }
|
24
|
+
|
25
|
+
child :answers, :if => lambda { |q| q.is_a?(Question) && !q.answers.blank? } do
|
26
|
+
attribute :api_id => :uuid
|
27
|
+
node(:help_text, :if => lambda { |a| !a.help_text.blank? }){ |a| a.help_text }
|
28
|
+
node(:exclusive, :if => lambda { |a| a.is_exclusive }){ |a| a.is_exclusive }
|
29
|
+
node(:text){ |a| a.split_or_hidden_text(:pre) }
|
30
|
+
node(:post_text, :if => lambda { |a| !a.split_or_hidden_text(:post).blank? }){ |a| a.split_or_hidden_text(:post) }
|
31
|
+
node(:type, :if => lambda { |a| a.response_class != "answer" }){ |a| a.response_class }
|
32
|
+
end
|
33
|
+
|
34
|
+
# both questions and question_groups have dependencies
|
35
|
+
child :dependency, :if => lambda { |q| q.dependency } do
|
36
|
+
attributes :rule
|
37
|
+
child :dependency_conditions => :conditions do
|
38
|
+
attributes :rule_key, :operator
|
39
|
+
node(:question){ |d| d.question.api_id }
|
40
|
+
node(:answer, :if => lambda { |d| d.answer }){ |d| d.answer.api_id }
|
41
|
+
node(:value, :if => lambda { |d| d.answer && d.answer.response_class != "answer" && d.as(d.answer.response_class) }){ |d| d.as(d.answer.response_class)}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
child(:questions, :if => lambda{|x| x.is_a?(QuestionGroup)}) do
|
46
|
+
attributes :api_id => :uuid
|
47
|
+
node(:text){ |q| q.split_text(:pre) }
|
48
|
+
node(:post_text, :if => lambda { |q| !q.split_text(:post).blank? }){ |q| q.split_text(:post) }
|
49
|
+
node(:help_text, :if => lambda { |q| !q.help_text.blank? }){ |q| q.help_text }
|
50
|
+
node(:reference_identifier, :if => lambda { |q| !q.reference_identifier.blank? }){ |q| q.reference_identifier }
|
51
|
+
node(:type, :if => lambda { |q| q.display_type != "default" }){ |q| q.display_type }
|
52
|
+
node(:pick, :if => lambda { |q| q.pick != "none" }){ |q| q.pick }
|
53
|
+
|
54
|
+
child :answers, :if => lambda { |q| !q.answers.blank? } do
|
55
|
+
attributes :api_id => :uuid
|
56
|
+
node(:help_text, :if => lambda { |a| !a.help_text.blank? }){ |a| a.help_text }
|
57
|
+
node(:is_exclusive, :if => lambda { |a| a.is_exclusive }){ |a| a.is_exclusive }
|
58
|
+
node(:text){ |a| a.split_or_hidden_text(:pre) }
|
59
|
+
node(:post_text, :if => lambda { |a| !a.split_or_hidden_text(:post).blank? }){ |a| a.split_or_hidden_text(:post) }
|
60
|
+
node(:type, :if => lambda { |a| a.response_class != "answer" }){ |a| a.response_class }
|
61
|
+
end
|
62
|
+
|
63
|
+
child :dependency, :if => lambda { |q| q.dependency } do
|
64
|
+
attributes :rule
|
65
|
+
child :dependency_conditions => :conditions do
|
66
|
+
attributes :rule_key, :operator
|
67
|
+
node(:question){ |d| d.question.api_id }
|
68
|
+
node(:answer, :if => lambda { |d| d.answer }){ |d| d.answer.api_id }
|
69
|
+
node(:value, :if => lambda { |d| d.answer && d.answer.response_class != "answer" && d.as(d.answer.response_class) }){ |d| d.as(d.answer.response_class)}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -1,15 +1,77 @@
|
|
1
1
|
#surveyor
|
2
|
-
-
|
3
|
-
|
4
|
-
|
5
|
-
.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
2
|
+
- unless (types = flash.keys.select{|k| [:notice, :error, :warning].include?(k)}).blank?
|
3
|
+
.surveyor_flash
|
4
|
+
= flash_messages(types)
|
5
|
+
.close
|
6
|
+
= semantic_form_for(@response_set, :as => :r, :url => update_my_survey_path, :html => {:id => "survey_form", :class => @survey.custom_class}) do |f|
|
7
|
+
.survey_title= @survey.title
|
8
|
+
- @survey.sections.each do |section|
|
9
|
+
= div_for section do
|
10
|
+
%span.title= strip_tags(section.title)
|
11
|
+
- group_questions = []
|
12
|
+
- answered_questions = []
|
13
|
+
- label = nil
|
14
|
+
- answered_count = 0
|
15
|
+
- (questions = section.questions).each_with_index do |q, i|
|
16
|
+
- if q.part_of_group?
|
17
|
+
- group_questions << q # gather up the group questions
|
18
|
+
- unless @response_set.responses.where( :question_id => q.id).empty?
|
19
|
+
- answered_questions << q
|
20
|
+
- answered_count = answered_count + 1
|
21
|
+
- if (i+1 >= questions.size) or (q.question_group_id != questions[i+1].question_group_id) # this is the last question of the section, or the group
|
22
|
+
- if answered_questions.length > 0 # there are answered questions in this section or group
|
23
|
+
- g = q.question_group
|
24
|
+
- renderer = g.renderer
|
25
|
+
|
26
|
+
- unless label.blank?
|
27
|
+
= render q.custom_renderer || "/partials/question", :q => label, :f => f, :disableFlag => true
|
28
|
+
- label = nil
|
29
|
+
= f.inputs q_text(g), :id => "g_#{g.id}", :class => "g_#{renderer} #{g.css_class(@response_set)}" do
|
30
|
+
%li.help= g.help_text
|
31
|
+
- case renderer
|
32
|
+
- when :grid
|
33
|
+
%li
|
34
|
+
%table
|
35
|
+
%col.pre
|
36
|
+
- group_questions.first.answers.each do |a|
|
37
|
+
%col{:class => cycle("odd", "even")}
|
38
|
+
%col.post
|
39
|
+
%tbody
|
40
|
+
- group_questions.each_slice(10) do |ten_questions| # header row every 10
|
41
|
+
%tr
|
42
|
+
%th
|
43
|
+
- ten_questions.first.answers.each do |a|
|
44
|
+
%th= a_text(a)
|
45
|
+
%th
|
46
|
+
- ten_questions.each_with_index do |q, j|
|
47
|
+
%tr{:id => "q_#{q.id}", :class => "q_#{renderer} #{q.css_class(@response_set)}"}
|
48
|
+
- if q.pick == "one"
|
49
|
+
- r = response_for(@response_set, q, nil, g)
|
50
|
+
- j = response_idx # increment the response index since the answer partial skips for q.pick == one
|
51
|
+
%th= q.split_text(:pre)
|
52
|
+
- q.answers.each do |a|
|
53
|
+
%td= render a.custom_renderer || '/partials/answer', :g => g, :q => q, :a => a, :f => f, :disableFlag => true
|
54
|
+
%th= q.split_text(:post)
|
55
|
+
- when :repeater
|
56
|
+
- (@response_set.count_group_responses(group_questions) + 1).times do |rg|
|
57
|
+
%li
|
58
|
+
- group_questions.each do |q|
|
59
|
+
= render q.custom_renderer || "/partials/question", :g => g, :rg => rg, :q => q, :f => f, :disableFlag => true
|
60
|
+
- else # :inline
|
61
|
+
- answered_questions.each do |q|
|
62
|
+
= render q.custom_renderer || "/partials/question", :g => g, :q => q, :f => f, :disableFlag => true
|
63
|
+
|
13
64
|
- group_questions = []
|
14
|
-
|
15
|
-
|
65
|
+
- answered_questions = []
|
66
|
+
- else
|
67
|
+
- if q.display_type == 'label'
|
68
|
+
- label = q
|
69
|
+
- unless @response_set.responses.where( :question_id => q.id).empty?
|
70
|
+
- unless label.blank?
|
71
|
+
= render q.custom_renderer || "/partials/question", :q => label, :f => f, :disableFlag => true
|
72
|
+
- label = nil
|
73
|
+
= render q.custom_renderer || "/partials/question", :q => q, :f => f, :disableFlag => true
|
74
|
+
- answered_count = answered_count + 1
|
75
|
+
- if (i+1 >= questions.size) and (answered_count == 0)
|
76
|
+
#{"--- No data ---"}
|
77
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
object @response_set
|
2
|
+
attribute :api_id => :uuid
|
3
|
+
attribute :created_at
|
4
|
+
attribute :completed_at
|
5
|
+
node(:survey_id){|rs| rs.survey.api_id }
|
6
|
+
|
7
|
+
child :responses do
|
8
|
+
attribute :api_id => :uuid
|
9
|
+
attribute :created_at
|
10
|
+
attribute :updated_at => :modified_at
|
11
|
+
node(:answer_id){|r| r.answer.api_id }
|
12
|
+
node(:question_id){|r| r.question.api_id }
|
13
|
+
node(:value, :if => lambda{|r| r.answer.response_class != "answer"}){|r| r.as(r.answer.response_class) }
|
14
|
+
end
|
data/config/routes.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
Rails.application.routes.draw do
|
2
|
-
match 'results', :to => 'results#index', :as => 'results', :via => :get
|
3
|
-
match 'results/:survey_code', :to => 'results#show', :as => 'result', :via => :get
|
4
2
|
match 'surveys', :to => 'surveyor#new', :as => 'available_surveys', :via => :get
|
5
3
|
match 'surveys/:survey_code', :to => 'surveyor#create', :as => 'take_survey', :via => :post
|
4
|
+
match 'surveys/:survey_code', :to => 'surveyor#export', :as => 'export_survey', :via => :get
|
6
5
|
match 'surveys/:survey_code/:response_set_code', :to => 'surveyor#show', :as => 'view_my_survey', :via => :get
|
7
6
|
match 'surveys/:survey_code/:response_set_code/take', :to => 'surveyor#edit', :as => 'edit_my_survey', :via => :get
|
8
7
|
match 'surveys/:survey_code/:response_set_code', :to => 'surveyor#update', :as => 'update_my_survey', :via => :put
|
9
|
-
end
|
8
|
+
end
|