imlement task oditing for Questtype ?Multiplechoice? (Issue #36)

This commit is contained in:
coderkun 2014-08-29 15:29:07 +02:00
commit 2577779f80
6 changed files with 384 additions and 5 deletions

View file

@ -226,6 +226,10 @@
'choice' => array(
'minlength' => 1,
'maxlength' => 128
),
'answer' => array(
'minlength' => 1,
'maxlength' => 255
)
);

View file

@ -1,8 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: The Legend of Z\n"
"POT-Creation-Date: 2014-08-17 20:38+0100\n"
"PO-Revision-Date: 2014-08-17 20:39+0100\n"
"POT-Creation-Date: 2014-08-29 15:17+0100\n"
"PO-Revision-Date: 2014-08-29 15:17+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de_DE\n"
@ -106,7 +106,7 @@ msgid "Choice input invalid"
msgstr "Die Auswahleingabe ist ungültig"
#: questtypes/choiceinput/html/edittask.tpl:29
#: questtypes/choiceinput/html/edittask.tpl:57
#: questtypes/choiceinput/html/edittask.tpl:58
#, php-format
msgid "Please select correct choice"
msgstr "Bitte wähle die richtige Auswahleingabe aus"
@ -133,6 +133,7 @@ msgid "Preview"
msgstr "Vorschau"
#: questtypes/choiceinput/html/edittask.tpl:83
#: questtypes/multiplechoice/html/edittask.tpl:79
#: questtypes/textinput/html/edittask.tpl:44
#: views/html/achievements/conditions.tpl:151
#: views/html/achievements/create.tpl:109 views/html/achievements/edit.tpl:112
@ -153,6 +154,41 @@ msgstr "vertikal"
msgid "horizontal"
msgstr "horizontal"
#: questtypes/multiplechoice/html/edittask.tpl:12
#: questtypes/multiplechoice/html/edittask.tpl:44
#, php-format
msgid "Answer input is too short (min. %d chars)"
msgstr "Die Antwort ist zu kurz (min. %d Zeichen)"
#: questtypes/multiplechoice/html/edittask.tpl:14
#: questtypes/multiplechoice/html/edittask.tpl:46
#, php-format
msgid "Answer input is too long (max. %d chars)"
msgstr "Die Antwort ist zu lang (max. %d Zeichen)"
#: questtypes/multiplechoice/html/edittask.tpl:16
#: questtypes/multiplechoice/html/edittask.tpl:48
msgid "Answer input invalid"
msgstr "Die Anwort ist ungültig"
#: questtypes/multiplechoice/html/edittask.tpl:30
msgid "Questions"
msgstr "Fragen"
#: questtypes/multiplechoice/html/edittask.tpl:34
#: questtypes/multiplechoice/html/edittask.tpl:88
msgid "Question"
msgstr "Frage"
#: questtypes/multiplechoice/html/edittask.tpl:71
#: questtypes/multiplechoice/html/edittask.tpl:90
msgid "Remove question"
msgstr "Frage entfernen"
#: questtypes/multiplechoice/html/edittask.tpl:75
msgid "Add question"
msgstr "Frage hinzufügen"
#: questtypes/multiplechoice/html/quest.tpl:3
#, php-format
msgid "Question %d of %d"

View file

@ -19,6 +19,12 @@
*/
class MultiplechoiceQuesttypeController extends \hhu\z\controllers\QuesttypeController
{
/**
* Required components
*
* @var array
*/
public $components = array('validation');
@ -219,7 +225,7 @@
/**
* TODO Action: edittask.
* Action: edittask.
*
* Edit the task of a Quest.
*
@ -229,6 +235,94 @@
*/
public function edittask($seminary, $questgroup, $quest)
{
// Get questions
$questions = $this->Multiplechoice->getQuestionsOfQuest($quest['id']);
foreach($questions as &$question) {
$question['answers'] = $this->Multiplechoice->getAnswersOfQuestion($question['id']);
}
// Values
$validations = array();
// Save data
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('save')))
{
// Get params and validate them
$questions = $this->request->getPostParam('questions');
if(is_null($questions)) {
$questions = array();
}
$questions = array_values($questions);
foreach($questions as $questionIndex => &$question)
{
// Validate answers
$question['answers'] = array_values($question['answers']);
foreach($question['answers'] as $answerIndex => &$answer)
{
$answerValidation = $this->Validation->validate($answer['answer'], \nre\configs\AppConfig::$validation['answer']);
if($answerValidation !== true)
{
if(!array_key_exists($questionIndex, $validations) || !is_array($validations[$questionIndex])) {
$validations[$questionIndex] = array();
}
if(!array_key_exists('answers', $validations[$questionIndex])) {
$validations[$questionIndex]['answers'] = array();
}
$validations[$questionIndex]['answers'][$answerIndex] = $answerValidation;
}
}
}
// Save and redirect
if(empty($validations))
{
// Save questions
foreach($questions as $questionIndex => &$question)
{
// Save question
$this->Multiplechoice->setQuestionForQuest(
$this->Auth->getUserId(),
$quest['id'],
$questionIndex + 1,
$question['question']
);
// Save answers
foreach($question['answers'] as $answerIndex => &$answer)
{
$this->Multiplechoice->setAnswerForQuestion(
$this->Auth->getUserId(),
$quest['id'],
$questionIndex + 1,
$answerIndex + 1,
$answer['answer'],
array_key_exists('tick', $answer)
);
}
// Delete deleted answers
$this->Multiplechoice->deleteAnswersOfQuestion(
$quest['id'],
$questionIndex + 1,
count($question['answers'])
);
}
// Delete deleted questions
$this->Multiplechoice->deleteQuestionsOfQuest(
$quest['id'],
count($questions)
);
// Redirect
$this->redirect($this->linker->link(array('quest', $seminary['url'], $questgroup['url'], $quest['url']), 1));
}
}
// Pass data to view
$this->set('questions', $questions);
$this->set('validations', $validations);
}

View file

@ -153,6 +153,115 @@
return false;
}
/**
* Set a question for a multiplechoice Quest.
*
* @param int $userId ID of user
* @param int $questId ID of Quest to set question for
* @param int $pos Position of question
* @param string $question Question text
*/
public function setQuestionForQuest($userId, $questId, $pos, $question)
{
$this->db->query(
'INSERT INTO questtypes_multiplechoice '.
'(created_user_id, quest_id, pos, question) '.
'VALUES '.
'(?, ?, ?, ?) '.
'ON DUPLICATE KEY UPDATE '.
'question = ?',
'iiiss',
$userId,
$questId,
$pos,
$question,
$question
);
}
/**
* Delete questions of a Quest.
*
* @param int $questId ID of Quest to delete question of
* @param int $offset Only delete questions after this position
*/
public function deleteQuestionsOfQuest($questId, $offset)
{
$this->db->query(
'DELETE FROM questtypes_multiplechoice '.
'WHERE quest_id = ? AND pos > ?',
'ii',
$questId,
$offset
);
}
/**
* Set an answer for a question.
*
* @param int $userId ID of user
* @param int $questId ID of Quest to set answer for
* @param int $questionPos Position of question
* @param int $answerPos Position of answer
* @param string $answer Answer text
* @param boolean $tick Whether answer is correct or not
*/
public function setAnswerForQuestion($userId, $questId, $questionPos, $answerPos, $answer, $tick)
{
// Get question
$question = $this->getQuestionOfQuest($questId, $questionPos);
if(is_null($question)) {
return;
}
// Add answer
$this->db->query(
'INSERT INTO questtypes_multiplechoice_answers '.
'(created_user_id, questtypes_multiplechoice_id, pos, answer, tick) '.
'VALUES '.
'(?, ?, ?, ?, ?) '.
'ON DUPLICATE KEY UPDATE '.
'answer = ?, tick = ?',
'iiisisi',
$userId,
$question['id'],
$answerPos,
$answer,
$tick,
$answer,
$tick
);
}
/**
* Delete answers of a question.
*
* @param int $questId ID of Quest to delete answers for
* @param int $questionPos Position of question
* @param int $offset Only delete answers after this position
*/
public function deleteAnswersOfQuestion($questId, $questionPos, $offset)
{
// Get question
$question = $this->getQuestionOfQuest($questId, $questionPos);
if(is_null($question)) {
return;
}
// Delete answer
$this->db->query(
'DELETE FROM questtypes_multiplechoice_answers '.
'WHERE questtypes_multiplechoice_id = ? AND pos > ?',
'ii',
$question['id'],
$offset
);
}
}

View file

@ -1 +1,137 @@
<p>TODO</p>
<?php if(!empty($validations)) : ?>
<ul>
<?php foreach($validations as &$question) : ?>
<li>
<?php if(!empty($question['answers'])) : ?>
<?php foreach($question['answers'] as &$answer) : ?>
<ul>
<?php foreach($answer as $setting => $value) : ?>
<li>
<?php
switch($setting) {
case 'minlength': printf(_('Answer input is too short (min. %d chars)'), $value);
break;
case 'maxlength': printf(_('Answer input is too long (max. %d chars)'), $value);
break;
default: echo _('Answer input invalid');
}
?>
</li>
<?php endforeach ?>
</ul>
<?php endforeach ?>
<?php endif ?>
</li>
<?php endforeach ?>
</ul>
<?php endif ?>
<form method="post">
<fieldset>
<legend><?=_('Questions')?></legend>
<ol id="questions">
<?php foreach($questions as $questionIndex => &$question) : ?>
<li id="question-<?=$questionIndex?>">
<?=_('Question')?>:
<textarea id="question-<?=$questionIndex?>-question" name="questions[<?=$questionIndex?>][question]"><?=$question['question']?></textarea>
<?php if(!empty($validations) && array_key_exists($questionIndex, $validations) && !empty($validations[$questionIndex]) && $validations[$questionIndex]['answers'] !== true) : ?>
<ul>
<?php foreach($validations[$questionIndex]['answers'] as &$answer) : ?>
<?php foreach($answer as $setting => $value) : ?>
<li>
<?php
switch($setting) {
case 'minlength': printf(_('Answer input is too short (min. %d chars)'), $value);
break;
case 'maxlength': printf(_('Answer input is too long (max. %d chars)'), $value);
break;
default: echo _('Answer input invalid');
}
?>
</li>
<?php endforeach ?>
<?php endforeach ?>
</ul>
<?php endif ?>
<ul>
<?php foreach($question['answers'] as $answerIndex => &$answer) : ?>
<li>
<input id="question-<?=$questionIndex?>-answer-<?=$answerIndex?>-tick" type="checkbox" name="questions[<?=$questionIndex?>][answers][<?=$answerIndex?>][tick]" <?php if(array_key_exists('tick', $answer) && $answer['tick']) : ?>checked="checked"<?php endif ?> />
<label for="questions[<?=$questionIndex?>][answers][<?=$answerIndex?>][tick]">
<input id="question-<?=$questionIndex?>-answer-<?=$answerIndex?>" type="text" name="questions[<?=$questionIndex?>][answers][<?=$answerIndex?>][answer]" value="<?=$answer['answer']?>" <?php if(!empty($validations) && array_key_exists($questionIndex, $validations) && !empty($validations[$questionIndex]) && array_key_exists($answerIndex, $validations[$questionIndex]['answers']) && $validations[$questionIndex]['answers'][$answerIndex] !== true) : ?>class="invalid"<?php endif ?> />
</label>
<button class="remove-answer" type="button"></button>
</li>
<?php endforeach ?>
<li>
<button class="add-answer" type="button">+</button>
</li>
</ul>
<button class="remove-question" type="button"><?=_('Remove question')?></button>
</li>
<?php endforeach ?>
<li>
<button class="add-question" type="button"><?=_('Add question')?></button>
</li>
</ol>
</fieldset>
<input type="submit" name="save" value="<?=_('save')?>" />
</form>
<script>
var questionIndex = <?=count($questions)?>;
var answerIndices = new Array(<?=count($questions)?>);
<?php foreach($questions as $index => &$question) : ?>
answerIndices[<?=$index?>] = <?=count($question['answers'])?>;
<?php endforeach?>
var questionElement = '<?=_('Question')?>: <textarea name="questions[QUESTIONINDEX][question]"></textarea>' +
'<ul><li><button class="add-answer" type="button">+</button></li></ul>' +
'<button class="remove-question" type="button"><?=_('Remove question')?></button>';
var answerElement = '<input id="question-QUESTIONINDEX-answer-ANSWERINDEX-tick" type="checkbox" name="questions[QUESTIONINDEX][answers][ANSWERINDEX][tick]" />' +
'<label for="questions[QUESTIONINDEX][answers][ANSWERINDEX][tick]">' +
'<input id="question-QUESTIONINDEX-answer-ANSWERINDEX" type="text" name="questions[QUESTIONINDEX][answers][ANSWERINDEX][answer]" value="" />' +
'</label>' +
'<button class="remove-answer" type="button"></button>';
$(".add-question").click(addQuestion);
$(".remove-question").click(removeQuestion);
$(".add-answer").click(addAnswer);
$(".remove-answer").click(removeAnswer);
function addQuestion(event)
{
event.preventDefault();
answerIndices.push(0);
var element = '<li id="question-'+questionIndex+'">' + questionElement.replace(/QUESTIONINDEX/g, questionIndex) + '</li>';
$(event.target).parent().before(element);
$("#question-"+questionIndex+" .remove-question").click(removeQuestion);
$("#question-"+questionIndex+" .add-answer").click(addAnswer);
$("#question-"+questionIndex+" .remove-answer").click(removeAnswer);
questionIndex++;
}
function removeQuestion(event)
{
event.preventDefault();
$(event.target).parent().remove();
}
function addAnswer(event)
{
event.preventDefault();
var parent = $(event.target).parent();
var index = parent.parent().parent().attr('id').substring(9);
var element = '<li>' + answerElement.replace(/QUESTIONINDEX/g, index).replace(/ANSWERINDEX/g, answerIndices[index]) + '</li>';
$(event.target).parent().before(element);
$(".remove-answer").click(removeAnswer);
answerIndices[index]++;
}
function removeAnswer(event)
{
event.preventDefault();
$(event.target).parent().remove();
}
</script>