yl_survey_fs/internal.lua
2024-10-08 13:39:06 +02:00

466 lines
17 KiB
Lua

-- Logging
local function log(text)
local logmessage = yl_survey_fs.t("log_prefix", yl_survey_fs.modname, text)
if yl_survey_fs.settings.debug then minetest.log("action", logmessage) end
return logmessage
end
function yl_survey_fs.log(text) return log(text) end
-- Helper
local function get_next_q_id_and_sort(questions, current_sort)
if current_sort == nil then current_sort = 0 end
local ret_id, ret_sort
local ret_maxsort = 0
local temp = math.huge
for _, q in pairs(questions) do
if ((q.sort > current_sort) and (q.sort < temp) and (q.enabled == true)) then
temp = q.sort
ret_id = q.id
ret_sort = q.sort
end
if ((q.sort >= ret_maxsort) and (q.enabled == true)) then
ret_maxsort = q.sort
end
end
return ret_id, ret_sort, ret_maxsort
end
function yl_survey_fs.get_next_q_id_and_sort(questions, current_sort)
return get_next_q_id_and_sort(questions, current_sort)
end
local function get_previous_q_id_and_sort(questions, current_sort)
if current_sort == nil then current_sort = 0 end
local ret_id, ret_sort
local ret_minsort = math.huge
local temp = 0
for _, q in pairs(questions) do
if ((q.sort < current_sort) and (q.sort > temp) and (q.enabled == true)) then
temp = q.sort
ret_id = q.id
ret_sort = q.sort
end
if ((q.sort <= ret_minsort) and (q.enabled == true)) then
ret_minsort = q.sort
end
end
return ret_id, ret_sort, ret_minsort
end
function yl_survey_fs.get_previous_q_id_and_sort(questions, current_sort)
return get_previous_q_id_and_sort(questions, current_sort)
end
local function get_cache(survey_id, question_id, playername)
local _, responses = yl_survey.get_response(survey_id, question_id,
playername, true, true)
-- q obj
local q_success = yl_survey.get_question(survey_id, question_id, true,
playername)
if (q_success == false) then return responses end
local cache = {}
for k, v in pairs(responses) do
local n_key = tonumber(k)
if (n_key > 0) then cache[k] = true end
end
return cache
end
-- Validation
local function validate(value, expect_type, allow_nil)
if ((allow_nil == true) and (value == nil)) then return true end
if ((allow_nil == false) and (value == nil)) then return false end
if (type(value) == expect_type) then return true end
return false
end
function yl_survey_fs.validate(value, expect_type, allow_nil)
return validate(value, expect_type, allow_nil)
end
-- Formspecs
-- construct_frame_formspec
--
yl_survey_fs.frame_formspec = table.concat({
"formspec_version[6]", "size[16.18,10]",
"button_exit[15.03,0.15;1,1;btn_quit;X]",
"button[6.68,8.5;3,1;btn_start;Start]", "label[0.5,0.75;%s]",
"textarea[0.5,1.5;15.03,6.5;;;%s]"
}, "")
local string_replacements = {
["@allow_anonymous@"] = "allow_anonymous",
["@allow_changes@"] = "allow_changes",
["@allow_names@"] = "allow_names",
["@creation_date@"] = "creation_date",
["@id@"] = "id",
["@modification_date@"] = "modification_date",
["@owner@"] = "owner",
["@title@"] = "title"
}
local function construct_frame_formspec(playername, survey_id)
local record = yl_survey.get_record(survey_id)
-- local owner = record["metadata"].owner
local title = record["metadata"].title or ""
local description = record["metadata"].description or ""
for replaceme, replacemewith in pairs(string_replacements) do
local r = record["metadata"][replacemewith] or "N/A"
description = string.gsub(description, replaceme, tostring(r))
end
-- local fs_owner = minetest.formspec_escape(owner)
local fs_title = minetest.formspec_escape(title)
local fs_description = minetest.formspec_escape(description)
return
string.format(yl_survey_fs.frame_formspec, fs_title, fs_description) or
""
end
function yl_survey_fs.construct_frame_formspec(playername, survey_id)
return construct_frame_formspec(playername, survey_id)
end
-- construct_answer_formspec
--
yl_survey_fs.single_answer_formspec = table.concat({
"checkbox[0,%s;checkbox_%s;;%s]", -- answer ID
"textarea[0.5,%s;14,1;;;%s]" -- answer text
}, "")
yl_survey_fs.single_freetext_formspec =
"textarea[0.5,2.5;15.03,1;input_freetext;;%s]" -- Freetext
yl_survey_fs.answers_formspec = table.concat({
"formspec_version[6]", "size[16.18,10]", -- buttons
"button_exit[15.03,0.15;1,1;btn_quit;X]",
"button[6.68,8.5;3,1;btn_save;Save]",
"button[12.68,8.5;3,1;btn_skip;Skip >]",
"button[0.68,8.5;3,1;btn_back;< Back]", -- Content
"label[0.5,0.75;%s]", -- Title
"textarea[0.5,1.5;15.03,1;;;%s]", -- Question
"%s", -- "textarea[0.5,2.5;15.03,1;input_freetext;;%s]", -- Freetext
"scrollbaroptions[arrows=show]",
"scrollbar[15.35,3.75;0.5,4.5;vertical;scroll_options;]",
"scroll_container[0.5,3.75;14.53,4.5;scroll_options;vertical;]", "%s", -- Answers
"scroll_container_end[]"
}, "")
local function construct_answer_formspec(playername, survey_id, question_id)
local record = yl_survey.get_record(survey_id)
if (record == nil) then return end
local title = record["metadata"].title or ""
local fs_title = minetest.formspec_escape(title)
local q_success, q = yl_survey.get_question(survey_id, question_id, true,
playername)
if (q_success == false) then return end
if (q["enabled"] ~= true) then return end
local fs_question = minetest.formspec_escape(q.question or "N/A")
-- error:
if (yl_survey.table_contains(q.allowed_types, "singlechoice") == true) and
(yl_survey.table_contains(q.allowed_types, "multiplechoice") == true) then
return
end
-- singlechoice
if (yl_survey.table_contains(q.allowed_types, "singlechoice") == true) then
fs_question = "singlechoice : " .. fs_question
end
-- multiplechoice
if (yl_survey.table_contains(q.allowed_types, "multiplechoice") == true) then
fs_question = "multiplechoice : " .. fs_question
end
local r_success, responses = yl_survey.get_response(survey_id, question_id,
playername, false, true)
if (r_success == false) then return end
local answers = q.answers or {}
local freetext_default = yl_survey_fs.t("freetext_default")
local fs_freetext = minetest.formspec_escape(responses["0"] or
freetext_default)
local insert_freetext = ""
if (yl_survey.table_contains(q.allowed_types, "freetext") == true) then
insert_freetext = string.format(yl_survey_fs.single_freetext_formspec,
fs_freetext)
end
local t_answers = {}
local spacer = 0
local checkbox_spacer = 0.3
local textarea_spacer = 0
for key, answer in pairs(answers) do
local fs_answer = minetest.formspec_escape(answer)
local checkbox_y = checkbox_spacer + spacer
local textarea_y = textarea_spacer + spacer
local checked = responses[tostring(key)] and true or false
local s_new = string.format(yl_survey_fs.single_answer_formspec,
tostring(checkbox_y), tostring(key),
tostring(checked), tostring(textarea_y),
fs_answer)
spacer = spacer + 1
table.insert(t_answers, s_new)
end
local s_answers = table.concat(t_answers, "")
return string.format(yl_survey_fs.answers_formspec, fs_title, fs_question,
insert_freetext, s_answers) or ""
end
function yl_survey_fs.construct_answer_formspec(playername, survey_id,
question_id)
return construct_answer_formspec(playername, survey_id, question_id)
end
-- Cache
minetest.register_on_leaveplayer(function(player)
local playername = player:get_player_name()
yl_survey_fs.data[playername] = nil
end)
--[[
yl_survey_fs.data =
{
AliasAlreadyTaken = {
survey_id = "somecrazy UUID",
q_id = 4,
response = {}
}
}
]] --
-- on_player_receive_fields
--
minetest.register_on_player_receive_fields(
function(player, formname, fields)
local playername = player:get_player_name()
local survey_id = yl_survey_fs and yl_survey_fs.data and
yl_survey_fs.data[playername] and
yl_survey_fs.data[playername].survey_id or ""
--[[ if (string.sub(formname,1,12) ~= "yl_survey_fs") then
return
end ]] --
if (formname ~= "yl_survey_fs:" .. survey_id) then return end
if fields == nil then
yl_survey_fs.data[playername] = nil
return
end
if fields.quit then
yl_survey_fs.data[playername] = nil
return
end
if fields.btn_start then
local q_success, questions =
yl_survey.list_questions(survey_id, false)
if (q_success == false) then
minetest.log("warning", yl_survey_fs.t("cannot find questions"))
return
end
-- local current_q_id = 0
local current_sort = 0
local next_q_id, next_sort =
yl_survey_fs.get_next_q_id_and_sort(questions, current_sort)
if (next_q_id == nil) then
minetest.log("warning", yl_survey_fs.t("cannot find next q_id"))
return
end
if (next_sort == nil) then
minetest.log("warning", yl_survey_fs.t("cannot find next sort"))
return
end
local formspec = yl_survey_fs.construct_answer_formspec(playername,
survey_id,
next_q_id)
if (formspec == nil) then
minetest.log("warning", yl_survey_fs.t("cannot create formspec"))
return
end
-- The survey ID won't change. We know it already and if it's different, THEN there's a problem
-- yl_survey_fs.data[playername].survey_id = survey_id
yl_survey_fs.data[playername].q_id = next_q_id
yl_survey_fs.data[playername].sort = next_sort
yl_survey_fs.data[playername].response =
get_cache(survey_id, next_q_id, playername)
minetest.show_formspec(playername, formname, formspec)
elseif fields.btn_back then
local q_success, questions =
yl_survey.list_questions(survey_id, false)
if (q_success == false) then
minetest.log("warning", yl_survey_fs.t("cannot find questions"))
return
end
-- local current_q_id = yl_survey_fs.data[playername].q_id
local current_sort = yl_survey_fs.data[playername].sort
local previous_q_id, previous_sort, min_sort =
yl_survey_fs.get_previous_q_id_and_sort(questions, current_sort)
local formspec
if (current_sort == min_sort) then
-- Back button on first question
yl_survey_fs.data[playername].q_id = 0
yl_survey_fs.data[playername].sort = 0
yl_survey_fs.data[playername].response = {}
formspec = yl_survey_fs.construct_frame_formspec(playername,
survey_id)
else
if (previous_q_id == nil) then
minetest.log("warning",
yl_survey_fs.t("cannot find previous q_id"))
return
end
if (previous_sort == nil) then
minetest.log("warning",
yl_survey_fs.t("cannot find previous sort"))
return
end
formspec = yl_survey_fs.construct_answer_formspec(playername,
survey_id,
previous_q_id)
yl_survey_fs.data[playername].q_id = previous_q_id
yl_survey_fs.data[playername].sort = previous_sort
yl_survey_fs.data[playername].response =
get_cache(survey_id, previous_q_id, playername)
end
if (formspec == nil) then
minetest.log("warning", yl_survey_fs.t("cannot create formspec"))
return
end
minetest.show_formspec(playername, formname, formspec)
elseif fields.btn_skip then
local q_success, questions =
yl_survey.list_questions(survey_id, false)
if (q_success == false) then
minetest.log("warning", yl_survey_fs.t("cannot find questions"))
return
end
-- local current_q_id = yl_survey_fs.data[playername].q_id
local current_sort = yl_survey_fs.data[playername].sort
local next_q_id, next_sort, max_sort =
yl_survey_fs.get_next_q_id_and_sort(questions, current_sort)
local formspec
if (current_sort == max_sort) then
-- Skip button on last question
yl_survey_fs.data[playername].q_id = 0
yl_survey_fs.data[playername].sort = 0
yl_survey_fs.data[playername].response = {}
formspec = yl_survey_fs.construct_frame_formspec(playername,
survey_id)
else
if (next_q_id == nil) then
minetest.log("warning",
yl_survey_fs.t("cannot find next q_id"))
return
end
if (next_sort == nil) then
minetest.log("warning",
yl_survey_fs.t("cannot find next sort"))
return
end
formspec = yl_survey_fs.construct_answer_formspec(playername,
survey_id,
next_q_id)
yl_survey_fs.data[playername].q_id = next_q_id
yl_survey_fs.data[playername].sort = next_sort
yl_survey_fs.data[playername].response =
get_cache(survey_id, next_q_id, playername)
end
if (formspec == nil) then
minetest.log("warning", yl_survey_fs.t("cannot create formspec"))
return
end
minetest.show_formspec(playername, formname, formspec)
elseif fields.btn_save then
-- storeme
-- Cache
if (yl_survey_fs.data[playername] == nil) then
yl_survey_fs.data[playername] = {}
end
-- Stored previously
local question_id = yl_survey_fs.data[playername].q_id
-- local cache = get_cache(survey_id, question_id, playername)
local q_success, q = yl_survey.get_question(survey_id, question_id,
true, playername)
if (q_success == false) then return end
local response = {}
for k, v in pairs(yl_survey_fs.data[playername].response) do
local n_key = tonumber(k)
if ((n_key > 0) and (v == true)) then
response[k] = q.answers[n_key]
end
end
-- Add freetext if applicable
if ((fields.input_freetext) and
(yl_survey.table_contains(q.allowed_types, "freetext") == true)) then
response["0"] = fields.input_freetext
end
-- store it!
local a_success =
yl_survey.answer_question(survey_id, question_id, playername,
response, true)
if (a_success == false) then
minetest.log("warning", yl_survey_fs.t("cannot store responses"))
return
end
else
for k, v in pairs(fields) do
local checkbox_id = string.sub(k, 9 + 1)
if ((string.sub(k, 1, 9) == "checkbox_") and
(tonumber(checkbox_id) ~= nil)) then
if v == "true" then
yl_survey_fs.data[playername].response[checkbox_id] =
true
else
yl_survey_fs.data[playername].response[checkbox_id] =
false
end
end
end
end
end)