diff --git a/modules/mod_survey/dispatch/survey b/modules/mod_survey/dispatch/survey
index af6e4c3873..4528501b38 100644
--- a/modules/mod_survey/dispatch/survey
+++ b/modules/mod_survey/dispatch/survey
@@ -1,4 +1,7 @@
[
- {survey, ["survey", id], resource_page, [ {template, "survey.tpl"} ]},
- {survey, ["survey", id, slug], resource_page, [ {template, "survey.tpl"} ]}
+ {survey_results, ["survey", "results", id], resource_page, [ {template, "survey_results.tpl"} ]},
+ {survey_results, ["survey", "results", id, slug], resource_page, [ {template, "survey_results.tpl"} ]},
+
+ {survey, ["survey", id], resource_page, [ {template, "survey.tpl"} ]},
+ {survey, ["survey", id, slug], resource_page, [ {template, "survey.tpl"} ]}
].
diff --git a/modules/mod_survey/mod_survey.erl b/modules/mod_survey/mod_survey.erl
index 0d1717c134..8d6b6746f1 100644
--- a/modules/mod_survey/mod_survey.erl
+++ b/modules/mod_survey/mod_survey.erl
@@ -29,7 +29,10 @@
-export([
event/2,
redraw_questions/2,
- delete_question/3
+ delete_question/3,
+
+ question_to_props/1,
+ module_name/1
]).
-include_lib("zotonic.hrl").
@@ -43,8 +46,26 @@ init(Context) ->
%% @doc Handle drag/drop events from the survey admin
event({sort, Items, {dragdrop, {survey, [{id,Id}]}, _Delegate, "survey"}}, Context) ->
event_sort(Id, Items, Context);
+
event({submit, {survey_submit, [{id,SurveyId}]}, FormId, _FormId}, Context) ->
- survey_submit:submit(SurveyId, FormId, Context).
+ survey_submit:submit(SurveyId, FormId, Context);
+
+event({postback, {survey_start, [{id, SurveyId}]}, _, _}, Context) ->
+ render_next_page(SurveyId, 1, [], Context);
+
+event({submit, {survey_next, Args}, _, _}, Context) ->
+ {id, SurveyId} = proplists:lookup(id, Args),
+ {page_nr, PageNr} = proplists:lookup(page_nr, Args),
+ {answers, Answers} = proplists:lookup(answers, Args),
+ render_next_page(SurveyId, PageNr+1, Answers, Context);
+
+event({postback, {survey_back, Args}, _, _}, Context) ->
+ {id, SurveyId} = proplists:lookup(id, Args),
+ {page_nr, PageNr} = proplists:lookup(page_nr, Args),
+ {answers, Answers} = proplists:lookup(answers, Args),
+ render_next_page(SurveyId, PageNr-1, Answers, Context).
+
+
%%====================================================================
%% support functions
@@ -139,6 +160,121 @@ new_question(Type) ->
Mod:new().
+%% @doc Fetch the next page from the survey, update the page view
+render_next_page(Id, 0, Answers, Context) ->
+ z_render:update("survey-question", #render{template="_survey_start.tpl", vars=[{id,Id},{answers,Answers}]}, Context);
+render_next_page(Id, PageNr, Answers, Context) ->
+ As = z_context:get_q_all_noz(Context),
+ Answers1 = lists:foldl(fun({Arg,_Val}, Acc) -> proplists:delete(Arg, Acc) end, Answers, As),
+ Answers2 = Answers1 ++ As,
+ case m_rsc:p(Id, survey, Context) of
+ {survey, QuestionIds, Questions} ->
+ Qs = [ proplists:get_value(QId, Questions) || QId <- QuestionIds ],
+ Qs1 = [ Q || Q <- Qs, Q /= undefined ],
+
+ case fetch_page(PageNr, Qs1) of
+ {L,NewPageNr} when is_list(L) ->
+ % A new list of questions, PageNr might be another than expected
+ Vars = [ {id, Id},
+ {page_nr, NewPageNr},
+ {questions, [ question_to_props(Q) || Q <- L ]},
+ {pages, count_pages(Qs1)},
+ {answers, Answers2}],
+ z_render:update("survey-question", #render{template="_survey_question_page.tpl", vars=Vars}, Context);
+ last ->
+ % That was the last page. Show a thank you and save the result.
+ case do_submit(Id, QuestionIds, Questions, Answers2, Context) of
+ ok ->
+ z_render:update("survey-question", #render{template="_survey_end.tpl", vars=[{id,Id}]}, Context);
+ {error, _Reason} ->
+ z_render:update("survey-question", #render{template="_survey_error.tpl", vars=[{id,Id}]}, Context)
+ end
+ end;
+ _NoSurvey ->
+ % No survey defined, show an error page.
+ z_render:update("survey-question", #render{template="_survey_empty.tpl", vars=[{id,Id}]}, Context)
+ end.
+
+
+ %% @doc Count the number of pages in the survey
+ count_pages([]) ->
+ 0;
+ count_pages(L) ->
+ count_pages(L, 1).
+
+ count_pages([], N) ->
+ N;
+ count_pages([#survey_question{type=pagebreak}|L], N) ->
+ L1 = lists:dropwhile(fun(#survey_question{type=pagebreak}) -> true; (_) -> false end, L),
+ count_pages(L1, N+1);
+ count_pages([_|L], N) ->
+ count_pages(L, N).
+
+ %% @doc Fetch the Nth page. Could return another page due to jumps in the pagebreaks.
+ fetch_page(_Nr, []) ->
+ last;
+ fetch_page(Nr, L) ->
+ fetch_page(1, Nr, L).
+
+ fetch_page(_, _, []) ->
+ last;
+ fetch_page(N, Nr, L) when N >= Nr ->
+ L1 = lists:takewhile(fun(#survey_question{type=pagebreak}) -> false; (_) -> true end, L),
+ {L1, N};
+ fetch_page(N, Nr, [#survey_question{type=pagebreak}|L]) when N < Nr ->
+ L1 = lists:dropwhile(fun(#survey_question{type=pagebreak}) -> true; (_) -> false end, L),
+ fetch_page(N+1, Nr, L1);
+ fetch_page(N, Nr, [_|L]) ->
+ fetch_page(N, Nr, L).
+
+
+%% @doc Map a question to template friendly properties
+question_to_props(Q) ->
+ [
+ {name, Q#survey_question.name},
+ {type, Q#survey_question.type},
+ {question, Q#survey_question.question},
+ {text, Q#survey_question.text},
+ {parts, Q#survey_question.parts},
+ {html, Q#survey_question.html},
+ {is_required, Q#survey_question.is_required}
+ ].
+
+
+%% @doc Collect all answers per question, save to the database.
+do_submit(SurveyId, QuestionIds, Questions, Answers, Context) ->
+ {FoundAnswers, Missing} = collect_answers(QuestionIds, Questions, Answers),
+ case Missing of
+ [] ->
+ m_survey:insert_survey_submission(SurveyId, FoundAnswers, Context),
+ ok;
+ _ ->
+ {error, notfound}
+ end.
+
+
+%% @doc Collect all answers, report any missing answers.
+%% @type collect_answers(proplist(), Context) -> {AnswerList, MissingIdsList}
+collect_answers(QIds, Qs, Answers) ->
+ collect_answers(QIds, Qs, Answers, [], []).
+
+
+collect_answers([], _Qs, _Answers, FoundAnswers, Missing) ->
+ {FoundAnswers, Missing};
+collect_answers([QId|QIds], Qs, Answers, FoundAnswers, Missing) ->
+ Q = proplists:get_value(QId, Qs),
+ Module = module_name(Q),
+ case Module:answer(Q, Answers) of
+ {ok, none} -> collect_answers(QIds, Qs, Answers, FoundAnswers, Missing);
+ {ok, AnswerList} -> collect_answers(QIds, Qs, Answers, [{QId, AnswerList}|FoundAnswers], Missing);
+ {error, missing} -> collect_answers(QIds, Qs, Answers, FoundAnswers, [QId|Missing])
+ end.
+
+module_name(#survey_question{type=Type}) ->
+ list_to_atom("survey_q_"++atom_to_list(Type)).
+
+
+
datamodel() ->
[
{categories, [
diff --git a/modules/mod_survey/models/m_survey.erl b/modules/mod_survey/models/m_survey.erl
index 0cc58bd4a5..a283ad8f2d 100644
--- a/modules/mod_survey/models/m_survey.erl
+++ b/modules/mod_survey/models/m_survey.erl
@@ -47,7 +47,12 @@ m_find_value(Id, #m{value=questions}, Context) ->
question_to_value(QuestionIds, Questions, []);
undefined ->
undefined
- end.
+ end;
+m_find_value(results, #m{value=undefined} = M, _Context) ->
+ M#m{value=results};
+m_find_value(Id, #m{value=results}, Context) ->
+ prepare_results(Id, Context).
+
%% @doc Transform a m_config value to a list, used for template loops
%% @spec m_to_list(Source, Context)
@@ -61,45 +66,79 @@ m_value(#m{value=undefined}, _Context) ->
-%% @doc Transform a list of survey questions to template friendly proplists
+%% @doc Transform a list of survey questions to admin template friendly proplists
question_to_value([], _, Acc) ->
lists:reverse(Acc);
question_to_value([Id|Ids], Qs, Acc) ->
Q = proplists:get_value(Id, Qs),
question_to_value(Ids, Qs, [question_to_value1(Id, Q)|Acc]).
- question_to_value1(Id, #survey_question{type=Type, name=Name, html=Html}) ->
- {Id, [{id, Id}, {type, Type}, {name, Name}, {html, Html}]};
- question_to_value1(Id, undefined) ->
- {Id, [{id, Id}, {type, undefined}]}.
+ question_to_value1(Id, Q) ->
+ {Id, [{id, Id} | mod_survey:question_to_props(Q)]}.
-%% @doc Save a survey, connect to the current visitor and user (if any)
+%% @doc Save a survey, connect to the current user (if any)
insert_survey_submission(SurveyId, Answers, Context) ->
UserId = z_acl:user(Context),
%% Delete previous answers of this user, if any
case UserId of
- undefined -> nop;
- _Other -> z_db:q("delete from survey_answer where survey_id = $1 and user_id = $2", [SurveyId, UserId], Context)
+ undefined ->
+ PersistentId = z_context:persistent_id(Context),
+ z_db:q("delete from survey_answer where survey_id = $1 and persistent = $2", [SurveyId, PersistentId], Context);
+ _Other ->
+ z_db:q("delete from survey_answer where survey_id = $1 and user_id = $2", [SurveyId, UserId], Context),
+ PersistentId = undefined
end,
- insert_questions(SurveyId, UserId, Answers, Context).
+ insert_questions(SurveyId, UserId, PersistentId, Answers, Context).
- insert_questions(_SurveyId, _UserId, [], _Context) ->
+ insert_questions(_SurveyId, _UserId, _PersistentId, [], _Context) ->
ok;
- insert_questions(SurveyId, UserId, [{QuestionId, Answers}|Rest], Context) ->
- insert_answers(SurveyId, UserId, QuestionId, Answers, Context),
- insert_questions(SurveyId, UserId, Rest, Context).
+ insert_questions(SurveyId, UserId, PersistentId, [{QuestionId, Answers}|Rest], Context) ->
+ insert_answers(SurveyId, UserId, PersistentId, QuestionId, Answers, Context),
+ insert_questions(SurveyId, UserId, PersistentId, Rest, Context).
- insert_answers(_SurveyId, _UserId, _QuestionId, [], _Context) ->
+ insert_answers(_SurveyId, _UserId, _PersistentId, _QuestionId, [], _Context) ->
ok;
- insert_answers(SurveyId, UserId, QuestionId, [{Name, Answer}|As], Context) ->
+ insert_answers(SurveyId, UserId, PersistentId, QuestionId, [{Name, Answer}|As], Context) ->
Args = case Answer of
- {text, Text} -> [SurveyId, UserId, QuestionId, Name, undefined, Text];
- Value -> [SurveyId, UserId, QuestionId, Name, z_convert:to_list(Value), undefined]
+ {text, Text} -> [SurveyId, UserId, PersistentId, QuestionId, Name, undefined, Text];
+ Value -> [SurveyId, UserId, PersistentId, QuestionId, Name, z_convert:to_list(Value), undefined]
end,
- z_db:q("insert into survey_answer (survey_id, user_id, question, name, value, text) values ($1, $2, $3, $4, $5, $6)", Args, Context),
- insert_answers(SurveyId, UserId, QuestionId, As, Context).
+ z_db:q("insert into survey_answer (survey_id, user_id, persistent, question, name, value, text)
+ values ($1, $2, $3, $4, $5, $6, $7)",
+ Args,
+ Context),
+ insert_answers(SurveyId, UserId, PersistentId, QuestionId, As, Context).
+
+
+prepare_results(SurveyId, Context) ->
+ case m_rsc:p(SurveyId, survey, Context) of
+ {survey, QuestionIds, Questions} ->
+ Stats = survey_stats(SurveyId, Context),
+ [
+ prepare_result(proplists:get_value(QId, Questions),
+ proplists:get_value(z_convert:to_binary(QId), Stats))
+ || QId <- QuestionIds
+ ];
+ undefined ->
+ undefined
+ end.
+
+ prepare_result(Question, Stats) ->
+ [
+ Stats,
+ prep_chart(Question, Stats),
+ mod_survey:question_to_props(Question)
+ ].
+
+
+prep_chart(_Q, undefined) ->
+ undefined;
+prep_chart(Q, Stats) ->
+ M = mod_survey:module_name(Q),
+ M:prep_chart(Q, Stats).
+
%% @doc Fetch the aggregate answers of a survey, omitting the open text answers.
@@ -137,6 +176,7 @@ install(Context) ->
#column_def{name=id, type="serial", is_nullable=false},
#column_def{name=survey_id, type="integer", is_nullable=false},
#column_def{name=user_id, type="integer", is_nullable=true},
+ #column_def{name=persistent, type="character varying", length=32, is_nullable=true},
#column_def{name=question, type="character varying", length=32, is_nullable=false},
#column_def{name=name, type="character varying", length=32, is_nullable=false},
#column_def{name=value, type="character varying", length=80, is_nullable=true},
@@ -153,11 +193,12 @@ install(Context) ->
z_db:equery("alter table survey_answer add
constraint fk_survey_answer_user_id foreign key (user_id) references rsc(id)
on update cascade on delete cascade", Context),
-
+
%% For aggregating answers to survey questions (group by name)
z_db:equery("create index survey_answer_survey_name_key on survey_answer(survey_id, name)", Context),
z_db:equery("create index survey_answer_survey_question_key on survey_answer(survey_id, question)", Context),
z_db:equery("create index survey_answer_survey_user_key on survey_answer(survey_id, user_id)", Context),
+ z_db:equery("create index survey_answer_survey_persistent_key on survey_answer(survey_id, persistent)", Context),
ok.
diff --git a/modules/mod_survey/questions/survey_q_likert.erl b/modules/mod_survey/questions/survey_q_likert.erl
index d04356f167..ab648ac07f 100644
--- a/modules/mod_survey/questions/survey_q_likert.erl
+++ b/modules/mod_survey/questions/survey_q_likert.erl
@@ -4,9 +4,11 @@
new/0,
question_props/1,
render/1,
- answer/2
+ answer/2,
+ prep_chart/2
]).
+-include("zotonic.hrl").
-include("../survey.hrl").
new() ->
@@ -54,8 +56,24 @@ render(Q) ->
])
}.
-answer(#survey_question{name=Name}, Context) ->
- case z_context:get_q(Name, Context) of
+answer(#survey_question{name=Name}, Answers) ->
+ case proplists:get_value(Name, Answers) of
[C] when C >= $1, C =< $5 -> {ok, [{Name, C - $0}]};
undefined -> {error, missing}
end.
+
+
+prep_chart(_Q, []) ->
+ undefined;
+prep_chart(_Q, [{_, Vals}]) ->
+ Labels = [<<"1">>,<<"2">>,<<"3">>,<<"4">>,<<"5">>],
+ LabelsDisplay = [<<"Strongly agree">>,<<"Agree">>,<<"Neutral">>,<<"Disagree">>,<<"Strongly disagree">>],
+
+ Values = [ proplists:get_value(C, Vals, 0) || C <- Labels ],
+ Sum = case lists:sum(Values) of 0 -> 1; N -> N end,
+ Perc = [ round(V*100/Sum) || V <- Values ],
+ [
+ {values, lists:zip(LabelsDisplay, Values)},
+ {type, "pie"},
+ {data, lists:zip(LabelsDisplay, Perc)}
+ ].
diff --git a/modules/mod_survey/questions/survey_q_longanswer.erl b/modules/mod_survey/questions/survey_q_longanswer.erl
index 5721cedfec..dacabf6f42 100644
--- a/modules/mod_survey/questions/survey_q_longanswer.erl
+++ b/modules/mod_survey/questions/survey_q_longanswer.erl
@@ -49,9 +49,9 @@ render(Q) ->
])
}.
-answer(Q, Context) ->
+answer(Q, Answers) ->
Name = Q#survey_question.name,
- case z_context:get_q(Name, Context) of
+ case proplists:get_value(Name, Answers) of
undefined -> {error, missing};
Value -> case z_string:trim(Value) of
[] -> {error, missing};
diff --git a/modules/mod_survey/questions/survey_q_narrative.erl b/modules/mod_survey/questions/survey_q_narrative.erl
index 76a3045732..9a43335753 100644
--- a/modules/mod_survey/questions/survey_q_narrative.erl
+++ b/modules/mod_survey/questions/survey_q_narrative.erl
@@ -39,54 +39,65 @@ Use [name=first|second|third] for a drop down menu named \"name\" with the given
].
render(Q) ->
- {Html, _Inputs} = parse(z_convert:to_list(Q#survey_question.text)),
+ {Parts, _Inputs} = parse(z_convert:to_list(Q#survey_question.text)),
Q#survey_question{
name = "",
text = iolist_to_binary(Q#survey_question.text),
question = "",
- html = iolist_to_binary(Html)
+ parts = Parts,
+ html = iolist_to_binary([build(P) || P <- Parts])
}.
-answer(Q, Context) ->
+answer(Q, Answers) ->
{_Html, Inputs} = parse(z_convert:to_list(Q#survey_question.text)),
- answer_inputs(Inputs, Context, []).
+ answer_inputs(Inputs, Answers, []).
-answer_inputs([], _Context, Acc) ->
+answer_inputs([], _Answers, Acc) ->
{ok, Acc};
-answer_inputs([{IsSelect,Name}|Rest], Context, Acc) ->
- case z_context:get_q(Name, Context) of
+answer_inputs([{IsSelect,Name}|Rest], Answers, Acc) ->
+ case proplists:get_value(Name, Answers) of
undefined -> {error, missing};
Value -> case z_string:trim(Value) of
[] -> {error, missing};
V ->
V1 = case IsSelect of true -> V; false -> {text, V} end,
- answer_inputs(Rest, Context, [{Name,V1}|Acc])
+ answer_inputs(Rest, Answers, [{Name,V1}|Acc])
end
end.
parse(Text) ->
- parse(Text, in_text, [], [], []).
+ parse(Text, [], []).
-parse([], _State, _Buff, Acc, InputAcc) ->
+parse([], Acc, InputAcc) ->
{lists:reverse(Acc), InputAcc};
-parse([$[|T], in_text, [], Acc, InputAcc) ->
- parse(T, in_input, [], Acc, InputAcc);
-parse([$]|T], in_input, Input, Acc, InputAcc) ->
- Input1 = lists:reverse(Input),
+parse([$[|T], Acc, InputAcc) ->
+ {Input1,T1} = lists:splitwith(fun(C) -> C /= $] end, T),
IsSelect = is_select(Input1),
- {Name, Elt} = case IsSelect of
- true -> build_select(Input1);
- false -> build_input(Input1)
+ Elt = case IsSelect of
+ true ->
+ {Name, Options} = split_select(Input1),
+ {select, Name, Options};
+ false ->
+ Name = z_string:trim(Input1),
+ Length = length(Input1),
+ {input, Name, Length}
end,
- parse(T, in_text, [], [Elt|Acc], [{IsSelect, Name}|InputAcc]);
-parse([H|T], in_input, Input, Acc, InputAcc) ->
- parse(T, in_input, [H|Input], Acc, InputAcc);
-parse([10|T], in_text, [], Acc, InputAcc) ->
- parse(T, in_text, [], [10,"
"|Acc], InputAcc);
-parse([H|T], in_text, [], Acc, InputAcc) ->
- parse(T, in_text, [], [H|Acc], InputAcc).
+ Acc1 = [Elt|Acc],
+ InputAcc1 = [{IsSelect, Name}|InputAcc],
+ case T1 of
+ [] -> parse([], Acc1, InputAcc1);
+ [$]|T2] -> parse(T2, Acc1, InputAcc1)
+ end;
+parse(T, Acc, InputAcc) ->
+ {Text,Rest} = lists:splitwith(fun(C) -> C /= $[ end, T),
+ Text1 = lists:map(fun(10) -> "
";
+ (C) -> C
+ end,
+ z_convert:to_list(z_html:escape(Text))),
+ Acc1 = [{html, [], iolist_to_binary(Text1)}|Acc],
+ parse(Rest, Acc1, InputAcc).
is_select([]) -> false;
@@ -94,20 +105,20 @@ is_select([$=|_]) -> true;
is_select([$||_]) -> true;
is_select([_|T]) -> is_select(T).
-build_select(I) ->
- {Name, Options} = split_select(I),
- {Name, [
+
+build({input, Name, Length}) ->
+ [
+ ""
+ ];
+build({select, Name, Options}) ->
+ [
""
- ]}.
+ ];
+build({html, [], Html}) ->
+ Html.
-build_input(I) ->
- Name = z_string:trim(I),
- Length = length(I),
- {Name, [
- ""
- ]}.
options([], Acc) ->
lists:reverse(Acc);
diff --git a/modules/mod_survey/questions/survey_q_pagebreak.erl b/modules/mod_survey/questions/survey_q_pagebreak.erl
new file mode 100644
index 0000000000..bda593854e
--- /dev/null
+++ b/modules/mod_survey/questions/survey_q_pagebreak.erl
@@ -0,0 +1,58 @@
+-module(survey_q_pagebreak).
+
+-export([
+ new/0,
+ question_props/1,
+ render/1,
+ answer/2
+]).
+
+-include("../survey.hrl").
+
+new() ->
+ Q = #survey_question{
+ type = pagebreak,
+ name = z_ids:identifier(5),
+ text = "",
+ question = ""
+ },
+ render(Q).
+
+question_props(Q) ->
+ [
+ {explanation, "Enter the optional condition for next page."},
+
+ {has_question, true},
+ {has_text, true},
+ {has_name, true},
+
+ {question_label, "To question"},
+ {text_label, "Condition"},
+
+ {type, Q#survey_question.type},
+ {name, Q#survey_question.name},
+ {question, Q#survey_question.question},
+ {text, Q#survey_question.text}
+ ].
+
+render(Q) ->
+ Q#survey_question{
+ question = iolist_to_binary(Q#survey_question.question),
+ html = iolist_to_binary([
+ "Pagebreak
", z_html:escape(Q#survey_question.question), "
"]) }. -answer(_Q, _Context) -> - {ok, []}. +answer(_Q, _Answers) -> + {ok, none}. diff --git a/modules/mod_survey/questions/survey_q_shortanswer.erl b/modules/mod_survey/questions/survey_q_shortanswer.erl index b845197d5a..1b46bd22f1 100644 --- a/modules/mod_survey/questions/survey_q_shortanswer.erl +++ b/modules/mod_survey/questions/survey_q_shortanswer.erl @@ -49,9 +49,9 @@ render(Q) -> ]) }. -answer(Q, Context) -> +answer(Q, Answers) -> Name = Q#survey_question.name, - case z_context:get_q(Name, Context) of + case proplists:get_value(Name, Answers) of undefined -> {error, missing}; Value -> case z_string:trim(Value) of [] -> {error, missing}; diff --git a/modules/mod_survey/questions/survey_q_subhead.erl b/modules/mod_survey/questions/survey_q_subhead.erl index a0f4b3c8c3..0536d3a92d 100644 --- a/modules/mod_survey/questions/survey_q_subhead.erl +++ b/modules/mod_survey/questions/survey_q_subhead.erl @@ -12,7 +12,7 @@ new() -> Q = #survey_question{ type = subhead, - name = "", + name = z_ids:identifier(5), text = "", question = <<"This is a subhead">> }, @@ -24,7 +24,7 @@ question_props(Q) -> {has_question, true}, {has_text, false}, - {has_name, false}, + {has_name, true}, {question_label, "Subhead"}, {text_label, ""}, @@ -37,13 +37,12 @@ question_props(Q) -> render(Q) -> Q#survey_question{ - name = "", text = "", question = iolist_to_binary(Q#survey_question.question), html = iolist_to_binary(["", z_html:escape(Q#survey_question.question), "
"]) }. -answer(_Q, Context) -> - {ok, []}. +answer(_Q, _Answers) -> + {ok, none}. diff --git a/modules/mod_survey/questions/survey_q_thurstone.erl b/modules/mod_survey/questions/survey_q_thurstone.erl index 94ba16aeee..6211b45073 100644 --- a/modules/mod_survey/questions/survey_q_thurstone.erl +++ b/modules/mod_survey/questions/survey_q_thurstone.erl @@ -4,9 +4,11 @@ new/0, question_props/1, render/1, - answer/2 + answer/2, + prep_chart/2 ]). +-include("zotonic.hrl"). -include("../survey.hrl"). new() -> @@ -46,6 +48,7 @@ render(Q) -> Rs = radio(Options, 1, Name, []), Q#survey_question{ question = iolist_to_binary(Q#survey_question.question), + parts = [ z_html:escape(Opt) || Opt <- Options ], html = iolist_to_binary([ "", z_html:escape(Q#survey_question.question), "
", "", @@ -69,12 +72,26 @@ radio([H|T], N, Name, Acc) -> radio(T, N+1, Name, [R|Acc]). -answer(Q, Context) -> +answer(Q, Answers) -> Name = Q#survey_question.name, Options = split_options(Q#survey_question.text), - case z_context:get_q(Name, Context) of + case proplists:get_value(Name, Answers) of undefined -> {error, missing}; N -> {ok, [{Name, lists:nth(list_to_integer(N), Options)}]} end. + +prep_chart(_Q, []) -> + undefined; +prep_chart(Q, [{_, Vals}]) -> + Labels = [ z_convert:to_binary(Lab) || Lab <- split_options(Q#survey_question.text) ], + Values = [ proplists:get_value(C, Vals, 0) || C <- Labels ], + Sum = case lists:sum(Values) of 0 -> 1; N -> N end, + Perc = [ round(V*100/Sum) || V <- Values ], + [ + {values, lists:zip(Labels, Values)}, + {type, "pie"}, + {data, lists:zip(Labels, Perc)} + ]. + \ No newline at end of file diff --git a/modules/mod_survey/questions/survey_q_truefalse.erl b/modules/mod_survey/questions/survey_q_truefalse.erl index 660aea85d7..0f13a99f0e 100644 --- a/modules/mod_survey/questions/survey_q_truefalse.erl +++ b/modules/mod_survey/questions/survey_q_truefalse.erl @@ -4,7 +4,8 @@ new/0, question_props/1, render/1, - answer/2 + answer/2, + prep_chart/2 ]). -include("../survey.hrl"). @@ -49,10 +50,25 @@ render(Q) -> ]) }. -answer(#survey_question{name=Name}, Context) -> - case z_context:get_q(Name, Context) of - "true" -> {ok, [{Name, true}]}; - "false" -> {ok, [{Name, false}]}; +answer(#survey_question{name=Name}, Answers) -> + case proplists:get_value(Name, Answers) of + "1" -> {ok, [{Name, true}]}; + "0" -> {ok, [{Name, false}]}; undefined -> {error, missing} end. + + +prep_chart(_Q, []) -> + undefined; +prep_chart(_Q, [{_, Vals}]) -> + True = proplists:get_value(<<"true">>, Vals, 0), + False = proplists:get_value(<<"false">>, Vals, 0), + Total = True + False, + TrueP = round(True * 100 / Total), + FalseP = 100 - TrueP, + [ + {values, [{"true", True}, {"false", False}]}, + {type, "pie"}, + {data, [["true", TrueP], ["false", FalseP]]} + ]. diff --git a/modules/mod_survey/questions/survey_q_yesno.erl b/modules/mod_survey/questions/survey_q_yesno.erl index e3bf689aa8..e8c7002b49 100644 --- a/modules/mod_survey/questions/survey_q_yesno.erl +++ b/modules/mod_survey/questions/survey_q_yesno.erl @@ -4,7 +4,8 @@ new/0, question_props/1, render/1, - answer/2 + answer/2, + prep_chart/2 ]). -include("../survey.hrl"). @@ -50,9 +51,24 @@ render(Q) -> ]) }. -answer(#survey_question{name=Name}, Context) -> - case z_context:get_q(Name, Context) of - "yes" -> {ok, [{Name, yes}]}; - "no" -> {ok, [{Name, no}]}; +answer(#survey_question{name=Name}, Answers) -> + case proplists:get_value(Name, Answers) of + "1" -> {ok, [{Name, yes}]}; + "0" -> {ok, [{Name, no}]}; undefined -> {error, missing} end. + + +prep_chart(_Q, []) -> + undefined; +prep_chart(_Q, [{_, Vals}]) -> + Yes = proplists:get_value(<<"yes">>, Vals, 0), + No = proplists:get_value(<<"no">>, Vals, 0), + Total = Yes + No, + YesP = round(Yes * 100 / Total), + NoP = 100 - YesP, + [ + {values, [{"yes", Yes}, {"no", No}]}, + {type, "pie"}, + {data, [["yes", YesP], ["no", NoP]]} + ]. diff --git a/modules/mod_survey/survey.hrl b/modules/mod_survey/survey.hrl index 2d8ab232fe..162982e27a 100644 --- a/modules/mod_survey/survey.hrl +++ b/modules/mod_survey/survey.hrl @@ -19,4 +19,4 @@ %% @doc A question for in a survey --record(survey_question, {type, name, question, text, html}). +-record(survey_question, {type, name, question, text, html, parts=[], is_required=true}). diff --git a/modules/mod_survey/templates/_admin_edit_content.survey.tpl b/modules/mod_survey/templates/_admin_edit_content.survey.tpl index 57c9d3f8da..8c7b485936 100644 --- a/modules/mod_survey/templates/_admin_edit_content.survey.tpl +++ b/modules/mod_survey/templates/_admin_edit_content.survey.tpl @@ -43,7 +43,7 @@
{{ q.name|escape }}
- {{ q.html|replace:['class="', 'class="nosubmit '] }} + {{ question.html|replace:['class="', 'class="nosubmit '] }}{_ Thank you for filling in our survey. Be sure to come back for other surveys! _}
\ No newline at end of file diff --git a/modules/mod_survey/templates/_survey_error.tpl b/modules/mod_survey/templates/_survey_error.tpl new file mode 100644 index 0000000000..429c84af55 --- /dev/null +++ b/modules/mod_survey/templates/_survey_error.tpl @@ -0,0 +1,3 @@ +{_ There was an error while handling your answers. We are terribly sorry about this. _}
\ No newline at end of file diff --git a/modules/mod_survey/templates/_survey_question_likert.tpl b/modules/mod_survey/templates/_survey_question_likert.tpl new file mode 100644 index 0000000000..94c857f77c --- /dev/null +++ b/modules/mod_survey/templates/_survey_question_likert.tpl @@ -0,0 +1,14 @@ +{% with answers[name] as ans %} +{{ question.question|escape }}
+{{ question.question|escape }}
+ + +{% validate id=#long name=question.name type={presence} %} diff --git a/modules/mod_survey/templates/_survey_question_narrative.tpl b/modules/mod_survey/templates/_survey_question_narrative.tpl new file mode 100644 index 0000000000..f53e408a70 --- /dev/null +++ b/modules/mod_survey/templates/_survey_question_narrative.tpl @@ -0,0 +1,21 @@ ++ {% for type,name,value in question.parts %} + {% with forloop.counter, answers[name] as index, ans %} + {% if type == "html" %} + {{ value }} + {% endif %} + {% if type == "input" %} + + {% validate id=#inp.index name=name type={presence} %} + {% endif %} + {% if type == "select" %} + + {% validate id=#sel.index name=name type={presence} %} + {% endif %} + {% endwith %} + {% endfor %} +
\ No newline at end of file diff --git a/modules/mod_survey/templates/_survey_question_page.tpl b/modules/mod_survey/templates/_survey_question_page.tpl new file mode 100644 index 0000000000..abd6146ca3 --- /dev/null +++ b/modules/mod_survey/templates/_survey_question_page.tpl @@ -0,0 +1,52 @@ +{{ question.question|escape }}
diff --git a/modules/mod_survey/templates/_survey_question_shortanswer.tpl b/modules/mod_survey/templates/_survey_question_shortanswer.tpl new file mode 100644 index 0000000000..741a72902d --- /dev/null +++ b/modules/mod_survey/templates/_survey_question_shortanswer.tpl @@ -0,0 +1,4 @@ +{{ question.question|escape }}
+ + +{% validate id=#short name=question.name type={presence} %} diff --git a/modules/mod_survey/templates/_survey_question_subhead.tpl b/modules/mod_survey/templates/_survey_question_subhead.tpl new file mode 100644 index 0000000000..531d0a95b2 --- /dev/null +++ b/modules/mod_survey/templates/_survey_question_subhead.tpl @@ -0,0 +1 @@ +{{ question.question|escape }}
diff --git a/modules/mod_survey/templates/_survey_question_thurstone.tpl b/modules/mod_survey/templates/_survey_question_thurstone.tpl new file mode 100644 index 0000000000..87dc3d3acf --- /dev/null +++ b/modules/mod_survey/templates/_survey_question_thurstone.tpl @@ -0,0 +1,12 @@ +{% with answers[name] as ans %} +{{ question.question|escape }}
+{{ question.question|escape }}
+{{ label }} | {{ value }} |
---|
+ {{ m.rsc[id].summary }} +
+ +{{ m.rsc[id].body|show_media }} + + + + diff --git a/modules/mod_survey/templates/survey.tpl b/modules/mod_survey/templates/survey.tpl index 2fd4262a51..4c5c6a5dcb 100644 --- a/modules/mod_survey/templates/survey.tpl +++ b/modules/mod_survey/templates/survey.tpl @@ -17,25 +17,8 @@ } -{% wire id=#survey type="submit" postback={survey_submit id=id} delegate="mod_survey" %} - - -