Menu,several choice,resize for Fill the blank question 1.9.10

1.9.x
baelmyhu 11 years ago
parent fb7aa5cef7
commit badd895cd9
  1. 170
      main/exercice/exercise.class.php
  2. 171
      main/exercice/exercise.lib.php
  3. 841
      main/exercice/fill_blanks.class.php
  4. 3
      main/exercice/stats.php
  5. 15
      main/inc/lib/exercise_show_functions.lib.php

@ -2464,144 +2464,74 @@ class Exercise
break; break;
// for fill in the blanks // for fill in the blanks
case FILL_IN_BLANKS: case FILL_IN_BLANKS:
// the question is encoded like this // insert the student result in the track_e_attempt table, field answer
// [A] B [C] D [E] F::10,10,10@1 // $answer is the answer like in the c_quiz_answer table for the question
// number 1 before the "@" means that is a switchable fill in blank question // student datas are choice[]
// [A] B [C] D [E] F::10,10,10@ or [A] B [C] D [E] F::10,10,10
// means that is a normal fill blank question
// first we explode the "::"
$pre_array = explode('::', $answer);
// is switchable fill blank or not
$last = count($pre_array) - 1;
$is_set_switchable = explode('@', $pre_array[$last]);
$switchable_answer_set = false;
if (isset ($is_set_switchable[1]) && $is_set_switchable[1] == 1) {
$switchable_answer_set = true;
}
$answer = '';
for ($k = 0; $k < $last; $k++) {
$answer .= $pre_array[$k];
}
// splits weightings that are joined with a comma
$answerWeighting = explode(',', $is_set_switchable[0]);
// we save the answer because it will be modified $listCorrectAnswers = FillBlanks::getAnswerInfo($answer);
$temp = $answer; $switchableAnswerSet = $listCorrectAnswers["switchable"];
$answerWeighting = $listCorrectAnswers["tabweighting"];
$answer = ''; // user choices is an array $choice
$j = 0;
//initialise answer tags
$user_tags = $correct_tags = $real_text = array();
// the loop will stop at the end of the text
while (1) {
// quits the loop if there are no more blanks (detect '[')
if (($pos = api_strpos($temp, '[')) === false) {
// adds the end of the text
$answer = $temp;
$real_text[] = $answer;
break; //no more "blanks", quit the loop
}
// adds the piece of text that is before the blank
//and ends with '[' into a general storage array
$real_text[] = api_substr($temp, 0, $pos +1);
$answer .= api_substr($temp, 0, $pos +1);
//take the string remaining (after the last "[" we found)
$temp = api_substr($temp, $pos +1);
// quit the loop if there are no more blanks, and update $pos to the position of next ']'
if (($pos = api_strpos($temp, ']')) === false) {
// adds the end of the text
$answer .= $temp;
break;
}
// get existing user data in n the BDD
if ($from_database) { if ($from_database) {
$queryfill = "SELECT answer FROM ".$TBL_TRACK_ATTEMPT." $queryfill = "SELECT answer
WHERE FROM $TBL_TRACK_ATTEMPT
exe_id = '".$exeId."' AND WHERE exe_id = $exeId
question_id= ".intval($questionId).""; AND question_id= ".intval($questionId);
$resfill = Database::query($queryfill); $resfill = Database::query($queryfill);
$str = Database::result($resfill, 0, 'answer'); $str = Database::result($resfill,0,'answer');
api_preg_match_all('#\[([^[]*)\]#', $str, $arr);
$str = str_replace('\r\n', '', $str);
$choice = $arr[1];
if (isset($choice[$j])) {
$tmp = api_strrpos($choice[$j], ' / ');
$choice[$j] = api_substr($choice[$j], 0, $tmp);
$choice[$j] = trim($choice[$j]);
// Needed to let characters ' and " to work as part of an answer $listStudentResults = FillBlanks::getAnswerInfo($str, true);
$choice[$j] = stripslashes($choice[$j]); $choice = $listStudentResults['studentanswer'];
} else {
$choice[$j] = null;
}
} else {
// This value is the user input, not escaped while correct answer is escaped by fckeditor
$choice[$j] = api_htmlentities(trim($choice[$j]));
} }
// loop other all blanks words
$user_tags[] = $choice[$j]; if (!$switchableAnswerSet) {
//put the contents of the [] answer tag into correct_tags[] // not switchable answer, must be in the same place than teacher order
$correct_tags[] = api_substr($temp, 0, $pos); for ($i=0; $i < count($listCorrectAnswers['tabwords']); $i++) {
$j++; $studentAnswer = trim($choice[$i]);
$temp = api_substr($temp, $pos +1); $correctAnswer = $listCorrectAnswers['tabwords'][$i];
} $isAnswerCorrect = 0;
if (FillBlanks::isGoodStudentAnswer($studentAnswer, $correctAnswer)) {
$answer = '';
$real_correct_tags = $correct_tags;
$chosen_list = array();
for ($i = 0; $i < count($real_correct_tags); $i++) {
if ($i == 0) {
$answer .= $real_text[0];
}
if (!$switchable_answer_set) {
// Needed to parse ' and " characters
$user_tags[$i] = stripslashes($user_tags[$i]);
if ($correct_tags[$i] == $user_tags[$i]) {
// gives the related weighting to the student // gives the related weighting to the student
$questionScore += $answerWeighting[$i]; $questionScore += $answerWeighting[$i];
// increments total score // increments total score
$totalScore += $answerWeighting[$i]; $totalScore += $answerWeighting[$i];
// adds the word in green at the end of the string $isAnswerCorrect = 1;
$answer .= $correct_tags[$i]; }
} elseif (!empty($user_tags[$i])) { $listCorrectAnswers['studentanswer'][$i] = $studentAnswer;
// else if the word entered by the student IS NOT the same as the one defined by the professor $listCorrectAnswers['studentscore'][$i] = $isAnswerCorrect;
// adds the word in red at the end of the string, and strikes it
$answer .= '<font color="red"><s>' . $user_tags[$i] . '</s></font>';
} else {
// adds a tabulation if no word has been typed by the student
$answer .= ''; // remove &nbsp; that causes issue
} }
} else { } else {
// switchable fill in the blanks // switchable answer
if (in_array($user_tags[$i], $correct_tags)) { $listStudentAsnwerTemp = $choice;
$chosen_list[] = $user_tags[$i]; $listTeacherAnswerTemp = $listCorrectAnswers['tabwords'];
$correct_tags = array_diff($correct_tags, $chosen_list); $listBadAnswerIndice = array();
// for every teacher answer, check if there is a student answer
// gives the related weighting to the student for ($i=0; $i < count($listStudentAsnwerTemp); $i++) {
$studentAnswer = trim($listStudentAsnwerTemp[$i]);
$found = false;
for ($j=0; $j < count($listTeacherAnswerTemp); $j++) {
$correctAnswer = $listTeacherAnswerTemp[$j];
if (!$found) {
if (FillBlanks::isGoodStudentAnswer($studentAnswer, $correctAnswer)) {
$questionScore += $answerWeighting[$i]; $questionScore += $answerWeighting[$i];
// increments total score
$totalScore += $answerWeighting[$i]; $totalScore += $answerWeighting[$i];
// adds the word in green at the end of the string $listTeacherAnswerTemp[$j] = "";
$answer .= $user_tags[$i]; $found = true;
} elseif (!empty ($user_tags[$i])) {
// else if the word entered by the student IS NOT the same as the one defined by the professor
// adds the word in red at the end of the string, and strikes it
$answer .= '<font color="red"><s>' . $user_tags[$i] . '</s></font>';
} else {
// adds a tabulation if no word has been typed by the student
$answer .= ''; // remove &nbsp; that causes issue
} }
} }
// adds the correct word, followed by ] to close the blank }
$answer .= ' / <font color="green"><b>' . $real_correct_tags[$i] . '</b></font>]'; $listCorrectAnswers['studentanswer'][$i] = $studentAnswer;
if (isset($real_text[$i +1])) { if (!$found) {
$answer .= $real_text[$i +1]; $listCorrectAnswers['studentscore'][$i] = 0;
} else {
$listCorrectAnswers['studentscore'][$i] = 1;
}
} }
} }
$answer = FillBlanks::getAnswerInStudentAttempt($listCorrectAnswers);
break; break;
// for calculated answer // for calculated answer
case CALCULATED_ANSWER: case CALCULATED_ANSWER:
@ -2932,7 +2862,7 @@ class Exercise
ExerciseShowFunctions::display_multiple_answer_combination_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect,0,0,0, $results_disabled); ExerciseShowFunctions::display_multiple_answer_combination_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect,0,0,0, $results_disabled);
//} //}
} elseif ($answerType == FILL_IN_BLANKS) { } elseif ($answerType == FILL_IN_BLANKS) {
//if ($origin!='learnpath') { // if ($origin!='learnpath') {
ExerciseShowFunctions::display_fill_in_blanks_answer($feedback_type, $answer,0,0); ExerciseShowFunctions::display_fill_in_blanks_answer($feedback_type, $answer,0,0);
// } // }
} elseif ($answerType == CALCULATED_ANSWER) { } elseif ($answerType == CALCULATED_ANSWER) {

@ -436,124 +436,73 @@ function showQuestion(
$s .='</tr>'; $s .='</tr>';
} elseif ($answerType == FILL_IN_BLANKS) { } elseif ($answerType == FILL_IN_BLANKS) {
/* // display the question, with field empty, for student to fill it,
* In the FILL_IN_BLANKS test // or filled to display the answer in the Question preview of the exercice/admin.php page
* you mustn't have [ and ] in the textarea $displayForStudent = true;
* you mustn't have :: in the textarea $listAnswerInformations = FillBlanks::getAnswerInfo($answer);
* the text to find mustn't be empty or contains only spaces $separatorStartRegexp = FillBlanks::escapeForRegexp($listAnswerInformations['blankseparatorstart']);
* the text to find mustn't contains HTML tags $separatorEndRegexp = FillBlanks::escapeForRegexp($listAnswerInformations['blankseparatorend']);
* the text to find mustn't contains char "
*/
list($answer) = explode('::', $answer); list($answer) = explode('::', $answer);
// $correct_answer_list array of array with correct anwsers 0=> [0=>[\p] 1=>[plop]] //Correct answer
api_preg_match_all('/\[[^]]+\]/', $answer, $correct_answer_list); $correctAnswerList = $listAnswerInformations['tabwords'];
// get student answer to display it if student go back to previous fillBlank answer question in a test //Student's answer
$studentAnswerList = array();
if (isset($user_choice[0]['answer'])) { if (isset($user_choice[0]['answer'])) {
api_preg_match_all('/\[[^]]+\]/', $user_choice[0]['answer'], $student_answer_list); $arrayStudentAnswer = FillBlanks::getAnswerInfo($user_choice[0]['answer'], true);
$student_answer_list_tobecleaned = $student_answer_list[0]; $studentAnswerList = $arrayStudentAnswer['studentanswer'];
$student_answer_list = array();
// here we got the student answer in a test
// let's clean up the results
/*
Array
(
[0] => Array
(
[0] => [<font color="red"><s>yer</s></font> / <font color="green"><b>ici</b></font>]
[1] => [<font color="red"><s>plop</s></font> / <font color="green"><b>/p</b></font>]
)
)
*/
for ($i=0; $i < count($student_answer_list_tobecleaned); $i++) {
$answer_corrected = $student_answer_list_tobecleaned[$i];
/*
* we got if student answer is wrong
* [<font color="red"><s>rrr</s></font> / <font color="green"><b>/p</b></font>]
* or if student answer is good
* [plop / <font color="green"><b>plop</b></font>]
* or if student didn't answer []
*/
$answer_corrected = api_preg_replace('| / <font color="green"><b>.*$|', '', $answer_corrected);
/*
* we got [<font color="red"><s>rrr</s></font> or [plop or [
*/
$answer_corrected = api_preg_replace('/^\[/', '', $answer_corrected);
/*
* we got <font color="red"><s>rrr</s></font> or plop
* non breakable spaces &nbsp;&nbsp;&nbsp; from /main/exercice/exercise.class.php have been removed l 2391 and l 2370
*/
$answer_corrected = api_preg_replace('|^<font color="red"><s>|', '', $answer_corrected);
$answer_corrected = api_preg_replace('|</s></font>$|', '', $answer_corrected);
$answer_corrected = '['.$answer_corrected.']';
/*
* we got [rrr] or [plop] or []
*/
$student_answer_list[] = $answer_corrected;
}
} }
// If display preview of answer in test view for exemple, set the student answer to the correct answers // If display the question with answer (in page exercice/admin.php) for teacher preview
// set the student-answer to the correct answer
if ($debug_mark_answer) { if ($debug_mark_answer) {
// contain the rights answers surronded with brackets $studentAnswerList = $correctAnswerList;
$student_answer_list = $correct_answer_list[0]; $displayForStudent = false;
} }
/* if (!empty($correctAnswerList) && !empty($studentAnswerList)) {
Split the response by bracket
tab_comments is an array with text surrounding the text to find
we add a space before and after the answer_question to be sure to
have a block of text before and after [xxx] patterns
so we have n text to find ([xxx]) and n+1 block of texts before,
between and after the text to find
*/
$tab_comments = api_preg_split('/\[[^]]+\]/', ' '.$answer.' ');
if (!empty($correct_answer_list) && !empty($student_answer_list)) {
$answer = ""; $answer = "";
$i = 0; for ($i = 0; $i < count($listAnswerInformations["commonwords"]) - 1; $i++) {
foreach ($student_answer_list as $student_item) { // display the common word
// remove surronding brackets $answer .= $listAnswerInformations["commonwords"][$i];
$student_response = api_substr($student_item, 1, api_strlen($student_item) - 2); // display the blank word
$correctItem = $listAnswerInformations["tabwords"][$i];
$size = strlen($student_item); $correctItemRegexp = $correctItem;
$attributes['class'] = detectInputAppropriateClass($size); // replace / with \/ to allow the preg_replace bellow and all the regexp char
$correctItemRegexp = FillBlanks::getRegexpProtected($correctItemRegexp);
$answer .= $tab_comments[$i]. if (isset($studentAnswerList[$i])) {
Display::input( // student already start this test and this question
'text', // fill the blank with his previous answers
"choice[$questionId][]", // may be "" if student did the question, but not fill the blanks
$student_response, $correctItem = $studentAnswerList[$i];
$attributes }
); $attributes["style"] = "width:".$listAnswerInformations["tabinputsize"][$i]."px";
$i++; $answer .= FillBlanks::getFillTheBlankHtml($separatorStartRegexp, $separatorEndRegexp, $correctItemRegexp, $questionId, $correctItem, $attributes, $answer, $listAnswerInformations, $displayForStudent, $i);
} }
$answer .= $tab_comments[$i]; // display the last common word
$answer .= $listAnswerInformations["commonwords"][$i];
} else { } else {
// display exercise with empty input fields // display empty [input] with the right width for student to fill it
// every [xxx] are replaced with an empty input field $separatorStartRegexp = FillBlanks::escapeForRegexp($listAnswerInformations['blankseparatorstart']);
foreach ($correct_answer_list[0] as $item) { $separatorEndRegexp = FillBlanks::escapeForRegexp($listAnswerInformations['blankseparatorend']);
$size = strlen($item); $answer = "";
$attributes['class'] = detectInputAppropriateClass($size); for ($i = 0; $i < count($listAnswerInformations["commonwords"]) - 1; $i++) {
$answer = str_replace( // display the common words
$item, $answer .= $listAnswerInformations["commonwords"][$i];
Display::input('text', "choice[$questionId][]", '', $attributes), // display the blank word
$answer $attributes["style"] = "width:".$listAnswerInformations["tabinputsize"][$i]."px";
); $correctItem = $listAnswerInformations["tabwords"][$i];
} $correctItemRegexp = $correctItem;
/*$answer = api_preg_replace( // replace / with \/ to allow the preg_replace bellow and all the regexp char
'/\[[^]]+\]/', $correctItemRegexp = FillBlanks::getRegexpProtected($correctItemRegexp);
Display::input( $answer .= FillBlanks::getFillTheBlankHtml($separatorStartRegexp, $separatorEndRegexp, $correctItemRegexp, $questionId, '', $attributes, $answer, $listAnswerInformations, $displayForStudent, $i);
'text', }
"choice[$questionId][]", // display the last common word
'', $answer .= $listAnswerInformations["commonwords"][$i];
$attributes
), $answer);*/
} }
$s .= $answer; $s .= $answer;
} elseif ($answerType == CALCULATED_ANSWER) { } elseif ($answerType == CALCULATED_ANSWER) {
/* /*
* In the CALCULATED_ANSWER test * In the CALCULATED_ANSWER test
@ -2250,7 +2199,7 @@ function get_student_stats_by_question($question_id, $exercise_id, $course_code
* @param int $session_id * @param int $session_id
* @return int * @return int
*/ */
function get_number_students_question_with_answer_count($question_id, $exercise_id, $course_code, $session_id) function get_number_students_question_with_answer_count($question_id, $exercise_id, $course_code, $session_id, $questionType = '')
{ {
$track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES); $track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
$track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); $track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
@ -2262,6 +2211,18 @@ function get_number_students_question_with_answer_count($question_id, $exercise_
$course_code = Database::escape_string($course_code); $course_code = Database::escape_string($course_code);
$session_id = intval($session_id); $session_id = intval($session_id);
if ($questionType == FILL_IN_BLANKS) {
$listStudentsId = array();
$listAllStudentInfo = CourseManager::get_student_list_from_course_code(api_get_course_id(), true);
foreach ($listAllStudentInfo as $i => $listStudentInfo ) {
$listStudentsId[] = $listStudentInfo['user_id'];
}
$listFillTheBlankResult = getFillTheBlankTabResult($exercise_id, $question_id, $listStudentsId, '1970-01-01', '3000-01-01');
return getNbResultFillBlankAll($listFillTheBlankResult);
}
if (empty($session_id)) { if (empty($session_id)) {
$courseCondition = " $courseCondition = "
INNER JOIN $courseUser cu INNER JOIN $courseUser cu

@ -13,6 +13,10 @@ class FillBlanks extends Question
static $typePicture = 'fill_in_blanks.png'; static $typePicture = 'fill_in_blanks.png';
static $explanationLangVar = 'FillBlanks'; static $explanationLangVar = 'FillBlanks';
const FILL_THE_BLANK_STANDARD = 0;
const FILL_THE_BLANK_MENU = 1;
const FILL_THE_BLANK_SEVERAL_ANSWER = 2;
/** /**
* Constructor * Constructor
*/ */
@ -27,42 +31,36 @@ class FillBlanks extends Question
* function which redefines Question::createAnswersForm * function which redefines Question::createAnswersForm
* @param the formvalidator instance * @param the formvalidator instance
*/ */
function createAnswersForm($form) function createAnswersForm ($form) {
{ $fillBlanksAllowedSeparator = self::getAllowedSeparator();
$defaults = array(); $defaults = array();
if (!empty($this->id)) { if (!empty($this->id)) {
$objAnswer = new answer($this->id); $objectAnswer = new answer($this->id);
$answer = $objectAnswer->selectAnswer(1);
// the question is encoded like this $listAnswersInfo = FillBlanks::getAnswerInfo($answer);
// [A] B [C] D [E] F::10,10,10@1
// number 1 before the "@" means that is a switchable fill in blank question
// [A] B [C] D [E] F::10,10,10@ or [A] B [C] D [E] F::10,10,10
// means that is a normal fill blank question
$pre_array = explode('::', $objAnswer->selectAnswer(1));
//make sure we only take the last bit to find special marks
$sz = count($pre_array);
$is_set_switchable = explode('@', $pre_array[$sz-1]);
if ($is_set_switchable[1]) { if ($listAnswersInfo["switchable"]) {
$defaults['multiple_answer'] = 1; $defaults['multiple_answer'] = 1;
} else { } else {
$defaults['multiple_answer'] = 0; $defaults['multiple_answer'] = 0;
} }
//take the complete string except after the last '::'
//Take the complete string except after the last '::' $defaults['answer'] = $listAnswersInfo["text"];
$defaults['select_separator'] = $listAnswersInfo["blankseparatornumber"];
$defaults['answer'] = ''; $blanksepartornumber = $listAnswersInfo["blankseparatornumber"];
for ($i=0; $i<($sz-1); $i++) {
$defaults['answer'] .= $pre_array[$i];
}
$a_weightings = explode(',', $is_set_switchable[0]);
} else { } else {
$defaults['answer'] = get_lang('DefaultTextInBlanks'); $defaults['answer'] = get_lang('DefaultTextInBlanks');
$defaults['select_separator'] = 0;
$blanksepartornumber = 0;
} }
$blankSeparatortStart = self::getStartSeparator($blanksepartornumber);
$blankSeparatortEnd = self::getEndSeparator($blanksepartornumber);
$blankSeparatortStartRegexp = self::escapeForRegexp($blankSeparatortStart);
$blankSeparatortEndRegexp = self::escapeForRegexp($blankSeparatortEnd);
$setValues = null; $setValues = null;
if (isset($a_weightings) && count($a_weightings) > 0) { if (isset($a_weightings) && count($a_weightings) > 0) {
@ -74,11 +72,16 @@ class FillBlanks extends Question
// javascript // javascript
echo '<script> echo '<script>
function FCKeditor_OnComplete(editorInstance) { var blankSeparatortStart = "'.$blankSeparatortStart.'";
var blankSeparatortEnd = "'.$blankSeparatortEnd.'";
var blankSeparatortStartRegexp = getBlankSeparatorRegexp(blankSeparatortStart);
var blankSeparatortEndRegexp = getBlankSeparatorRegexp(blankSeparatortEnd);
function FCKeditor_OnComplete( editorInstance ) {
if (window.attachEvent) { if (window.attachEvent) {
editorInstance.EditorDocument.attachEvent("onkeyup", updateBlanks) ; editorInstance.EditorDocument.attachEvent("onkeyup", updateBlanks) ;
} else { } else {
editorInstance.EditorDocument.addEventListener("keyup", updateBlanks, true); editorInstance.EditorDocument.addEventListener("keyup",updateBlanks,true);
} }
} }
@ -86,57 +89,193 @@ class FillBlanks extends Question
function updateBlanks() { function updateBlanks() {
if (firstTime) { if (firstTime) {
field = document.getElementById("answer"); var field = document.getElementById("answer");
var answer = field.value; var answer = field.value;
} else { } else {
var oEditor = FCKeditorAPI.GetInstance("answer"); var oEditor = FCKeditorAPI.GetInstance("answer");
//var answer = oEditor.GetXHTML(true);
var answer = oEditor.EditorDocument.body.innerHTML; var answer = oEditor.EditorDocument.body.innerHTML;
} }
var blanks = answer.match(/\[[^\]]*\]/g); // disable the save button, if not blanks have been created
var fields = "<div class=\"control-group\"><label class=\"control-label\">'.get_lang('Weighting').'</label><div class=\"controls\"><table>"; $("button").attr("disabled", "disabled");
if (blanks!=null) { $("#defineoneblank").show();
for (i=0 ; i<blanks.length ; i++){
if (document.getElementById("weighting["+i+"]")) var blanksRegexp = "/"+blankSeparatortStartRegexp+"[^"+blankSeparatortStartRegexp+"]*"+blankSeparatortEndRegexp+"/g";
value = document.getElementById("weighting["+i+"]").value;
else var blanks = answer.match(eval(blanksRegexp));
value = "10"; var fields = "<div class=\"control-group\">";
fields += "<tr><td><label>"+blanks[i]+"</label></td><td><input style=\"margin-left: 0em;\" size=\"5\" value=\""+value+"\" type=\"text\" id=\"weighting["+i+"]\" name=\"weighting["+i+"]\" /></td></tr>"; fields += "<label class=\"control-label\">'.get_lang('Weighting').'</label>";
fields += "<div class=\"controls\">";
fields += "<table>";
fields += "<tr><th style=\"padding:0 20px\">'.get_lang("WordTofind").'</th><th style=\"padding:0 20px\">'.get_lang("QuestionWeighting").'</th><th style=\"padding:0 20px\">'.get_lang("BlankInputSize").'</th></tr>";
if (blanks != null) {
for (var i=0 ; i < blanks.length ; i++){
// remove forbidden characters that causes bugs
blanks[i] = removeForbiddenChars(blanks[i]);
// trim blanks between brackets
blanks[i] = trimBlanksBetweenSeparator(blanks[i], blankSeparatortStart, blankSeparatortEnd);
// if the word is empty []
if (blanks[i] == blankSeparatortStartRegexp+blankSeparatortEndRegexp) {
break;
}
// get input size
var lainputsize = 200;
if ($("#samplesize\\\["+i+"\\\]").width()) {
lainputsize = $("#samplesize\\\["+i+"\\\]").width();
}
if (document.getElementById("weighting["+i+"]")) {
var value = document.getElementById("weighting["+i+"]").value;
} else {
var value = "10";
}
fields += "<tr>";
fields += "<td>"+blanks[i]+"</td>";
fields += "<td><input style=\"width:20px\" value=\""+value+"\" type=\"text\" id=\"weighting["+i+"]\" name=\"weighting["+i+"]\" /></td>";
fields += "<td>";
fields += "<input type=\"button\" value=\"-\" onclick=\"changeInputSize(-1, "+i+")\">";
fields += "<input type=\"button\" value=\"+\" onclick=\"changeInputSize(1, "+i+")\">";
fields += "<input value=\""+blanks[i].substr(1, blanks[i].length - 2)+"\" style=\"width:"+lainputsize+"px\" disabled=disabled id=\"samplesize["+i+"]\"/>";
fields += "<input type=\"hidden\" id=\"sizeofinput["+i+"]\" name=\"sizeofinput["+i+"]\" value=\""+lainputsize+"\" \"/>";
fields += "</td>";
fields += "</tr>";
// enable the save button
$("button").removeAttr("disabled");
$("#defineoneblank").hide();
} }
} }
document.getElementById("blanks_weighting").innerHTML = fields + "</table></div></div>"; document.getElementById("blanks_weighting").innerHTML = fields + "</table></div></div>";
if (firstTime) { if (firstTime) {
firstTime = false; firstTime = false;
'.$setValues.' ';
if (count($listAnswersInfo["tabweighting"]) > 0) {
foreach ($listAnswersInfo["tabweighting"] as $i => $weighting) {
echo 'document.getElementById("weighting['.$i.']").value = "'.$weighting.'";';
} }
foreach ($listAnswersInfo["tabinputsize"] as $i => $sizeOfInput) {
echo 'document.getElementById("sizeofinput['.$i.']").value = "'.$sizeOfInput.'";';
echo '$("#samplesize\\\['.$i.'\\\]").width('.$sizeOfInput.');';
} }
}
echo '}
';
echo '
}
window.onload = updateBlanks; window.onload = updateBlanks;
function getInputSize() {
var outTabSize = new Array();
$("input").each(function() {
if ($(this).attr("id") && $(this).attr("id").match(/samplesize/)) {
var tabidnum = $(this).attr("id").match(/\d+/);
var idnum = tabidnum[0];
var thewidth = $(this).next().attr("value");
tabInputSize[idnum] = thewidth;
}
});
}
function changeInputSize(inCoef, inIdNum)
{
var currentWidth = $("#samplesize\\\["+inIdNum+"\\\]").width();
var newWidth = currentWidth + inCoef * 20;
newWidth = Math.max(20, newWidth);
newWidth = Math.min(newWidth, 600);
$("#samplesize\\\["+inIdNum+"\\\]").width(newWidth);
$("#sizeofinput\\\["+inIdNum+"\\\]").attr("value", newWidth);
}
function removeForbiddenChars(inTxt) {
outTxt = inTxt;
outTxt = outTxt.replace(/&quot;/g, ""); // remove the char
outTxt = outTxt.replace(/\x22/g, ""); // remove the char
outTxt = outTxt.replace(/"/g, ""); // remove the char
outTxt = outTxt.replace(/\\\\/g, ""); // remove the \ char
outTxt = outTxt.replace(/&nbsp;/g, " ");
outTxt = outTxt.replace(/^ +/, "");
outTxt = outTxt.replace(/ +$/, "");
return outTxt;
}
function changeBlankSeparator()
{
var separatorNumber = $("#select_separator").val();
var tabSeparator = getSeparatorFromNumber(separatorNumber);
blankSeparatortStart = tabSeparator[0];
blankSeparatortEnd = tabSeparator[1];
blankSeparatortStartRegexp = getBlankSeparatorRegexp(blankSeparatortStart);
blankSeparatortEndRegexp = getBlankSeparatorRegexp(blankSeparatortEnd);
updateBlanks();
}
// this function is the same than the PHP one
// if modify it modify the php one escapeForRegexp
function getBlankSeparatorRegexp(inTxt)
{
var tabSpecialChar = new Array(".", "+", "*", "?", "[", "^", "]", "$", "(", ")",
"{", "}", "=", "!", "<", ">", "|", ":", "-", ")");
for (var i=0; i < tabSpecialChar.length; i++) {
if (inTxt == tabSpecialChar[i]) {
return "\\\"+inTxt;
}
}
return inTxt;
}
// this function is the same than the PHP one
// if modify it modify the php one getAllowedSeparator
function getSeparatorFromNumber(innumber)
{
tabSeparator = new Array();
tabSeparator[0] = new Array("[", "]");
tabSeparator[1] = new Array("{", "}");
tabSeparator[2] = new Array("(", ")");
tabSeparator[3] = new Array("*", "*");
tabSeparator[4] = new Array("#", "#");
tabSeparator[5] = new Array("%", "%");
tabSeparator[6] = new Array("$", "$");
return tabSeparator[innumber];
}
function trimBlanksBetweenSeparator(inTxt, inSeparatorStart, inSeparatorEnd)
{
// blankSeparatortStartRegexp
// blankSeparatortEndRegexp
var result = inTxt
result = result.replace(inSeparatorStart, "");
result = result.replace(inSeparatorEnd, "");
result = result.trim();
return inSeparatorStart+result+inSeparatorEnd;
}
</script>'; </script>';
// answer // answer
$form->addElement('label', null, '<br /><br />'.get_lang('TypeTextBelow').', '.get_lang('And').' '.get_lang('UseTagForBlank')); $form->addElement ('label', null, '<br /><br />'.get_lang('TypeTextBelow').', '.get_lang('And').' '.get_lang('UseTagForBlank'));
$form->addElement('html_editor', 'answer', '<img src="../img/fill_field.png">','id="answer" cols="122" rows="6" onkeyup="javascript: updateBlanks(this);"', array('ToolbarSet' => 'TestQuestionDescription', 'Width' => '100%', 'Height' => '350')); $form->addElement ('html_editor', 'answer', '<img src="../img/fill_field.png">','id="answer" cols="122" rows="6" onkeyup="javascript: updateBlanks(this);"', array('ToolbarSet' => 'TestQuestionDescription', 'Width' => '100%', 'Height' => '350'));
$form -> addRule ('answer',get_lang('GiveText'),'required');
$form->addRule('answer', get_lang('GiveText'),'required');
$form->addRule('answer', get_lang('DefineBlanks'),'regex','/\[.*\]/');
//added multiple answers //added multiple answers
$form->addElement('checkbox', 'multiple_answer','', get_lang('FillInBlankSwitchable')); $form->addElement ('checkbox','multiple_answer','', get_lang('FillInBlankSwitchable'));
$form->addElement('select', 'select_separator', get_lang("SelectFillTheBlankSeparator"), self::getAllowedSeparatorForSelect(), ' id="select_separator" style="width:150px" onchange="changeBlankSeparator()" ');
$form->addElement('html', '<div id="blanks_weighting"></div>'); $form->addElement ('label', null, '<input type="button" onclick="updateBlanks()" value="'.get_lang('RefreshBlanks').'" class="btn" />');
$form->addElement('html','<div id="blanks_weighting"></div>');
global $text, $class; global $text, $class;
// setting the save button here and not in the question class.php // setting the save button here and not in the question class.php
$form->addElement('style_submit_button', 'submitQuestion', $text, 'class="'.$class.'"'); $form->addElement('html','<div id="defineoneblank" style="color:#D04A66; margin-left:160px">'.get_lang('DefineBlanks').'</div>');
$form->addElement('style_submit_button','submitQuestion',$text, 'class="'.$class.'"');
if (!empty($this->id)) { if (!empty($this -> id)) {
$form -> setDefaults($defaults); $form -> setDefaults($defaults);
} else { } else {
if ($this->isContent == 1) { if ($this -> isContent == 1) {
$form->setDefaults($defaults); $form -> setDefaults($defaults);
} }
} }
} }
@ -148,37 +287,109 @@ class FillBlanks extends Question
function processAnswersCreation($form) function processAnswersCreation($form)
{ {
global $charset; global $charset;
$answer = $form->getSubmitValue('answer'); $answer = $form->getSubmitValue('answer');
//remove the :: eventually written by the user // Due the fckeditor transform the elements to their HTML value
$answer = str_replace('::', '', $answer); $answer = api_html_entity_decode($answer, ENT_QUOTES, $charset);
// remove the :: eventually written by the user
$answer = str_replace('::','',$answer);
// remove starting and ending space and &nbsp;
$answer = api_preg_replace("/\xc2\xa0/", " ", $answer);
// start and end separator
$blankStartSeparator = self::getStartSeparator($form->getSubmitValue('select_separator'));
$blankEndSeparator = self::getEndSeparator($form->getSubmitValue('select_separator'));
$blankStartSeparatorRegexp = self::escapeForRegexp($blankStartSeparator);
$blankEndSeparatorRegexp = self::escapeForRegexp($blankEndSeparator);
// remove spaces at the beginning and the end of text in square brackets
$answer = preg_replace_callback("/".$blankStartSeparatorRegexp."[^]]+".$blankEndSeparatorRegexp."/",
function ($matches) use ($blankStartSeparator, $blankEndSeparator) {
$matchingResult = $matches[0];
$matchingResult = trim($matchingResult, $blankStartSeparator);
$matchingResult = trim($matchingResult, $blankEndSeparator);
$matchingResult = trim($matchingResult);
// remove forbidden chars
$matchingResult = str_replace("/\\/", "", $matchingResult);
$matchingResult = str_replace('/"/', "", $matchingResult);
return $blankStartSeparator.$matchingResult.$blankEndSeparator;
},
$answer);
// get the blanks weightings // get the blanks weightings
$nb = preg_match_all('/\[[^\]]*\]/', $answer, $blanks); $nb = preg_match_all('/'.$blankStartSeparatorRegexp.'[^'.$blankStartSeparatorRegexp.']*'.$blankEndSeparatorRegexp.'/', $answer, $blanks);
if (isset($_GET['editQuestion'])) { if(isset($_GET['editQuestion']))
$this ->weighting = 0; {
$this -> weighting = 0;
} }
if ($nb > 0) { /* if we have some [tobefound] in the text
build the string to save the following in the answers table
<p>I use a [computer] and a [pen].</p>
becomes
<p>I use a [computer] and a [pen].</p>::100,50:100,50@1
++++++++-------**
--- -- --- -- -
A B (C) (D)(E)
+++++++ : required, weighting of each words
------- : optional, input width to display, 200 if not present
** : equal @1 if "Allow answers order switches" has been checked, @ otherwise
A : weighting for the word [computer]
B : weighting for the word [pen]
C : input width for the word [computer]
D : input width for the word [pen]
E : equal @1 if "Allow answers order switches" has been checked, @ otherwise
*/
if($nb > 0) {
$answer .= '::'; $answer .= '::';
for ($i=0 ; $i < $nb; ++$i) { // weighting
$blankItem = $blanks[0][$i]; for($i=0 ; $i < $nb ; ++$i) {
$replace = array("[", "]"); // enter the weighting of word $i
$newBlankItem = str_replace($replace, "", $blankItem); $answer .= $form->getSubmitValue('weighting['.$i.']');
$newBlankItem = "[".trim($newBlankItem)."]"; // not the last word, add ","
$answer = str_replace($blankItem, $newBlankItem, $answer); if ($i != $nb - 1) {
$answer .= $form->getSubmitValue('weighting['.$i.']').','; $answer .= ",";
}
// calculate the global weightning for the question
$this -> weighting += $form->getSubmitValue('weighting['.$i.']'); $this -> weighting += $form->getSubmitValue('weighting['.$i.']');
} }
$answer = api_substr($answer, 0, -1);
// input width
$answer .= ":";
for ($i=0 ; $i < $nb ; ++$i) {
// enter the width of input for word $i
$answer .= $form->getSubmitValue('sizeofinput['.$i.']');
// not the last word, add ","
if ($i != $nb - 1) {
$answer .= ",";
}
}
} }
$is_multiple = $form->getSubmitValue('multiple_answer'); // write the blank separator code number
$answer.= '@'.$is_multiple; // see function getAllowedSeparator
/*
0 [...]
1 {...}
2 (...)
3 *...*
4 #...#
5 %...%
6 $...$
*/
$answer .= ":".$form->getSubmitValue('select_separator');
// Allow answers order switches
$is_multiple = $form -> getSubmitValue('multiple_answer');
$answer.='@'.$is_multiple;
$this->save(); $this -> save();
$objAnswer = new answer($this->id); $objAnswer = new answer($this->id);
$objAnswer->createAnswer($answer, 0, '', 0, '1'); $objAnswer->createAnswer($answer, 0, '', 0, 1);
$objAnswer->save(); $objAnswer->save();
} }
@ -197,4 +408,496 @@ class FillBlanks extends Question
</tr>'; </tr>';
return $header; return $header;
} }
/**
* @param $separatorStartRegexp
* @param $separatorEndRegexp
* @param $correctItemRegexp
* @param $questionId
* @param $correctItem
* @param $attributes
* @param $answer
* @param $listAnswersInfo
* @param $displayForStudent
* @return string
*/
public static function getFillTheBlankHtml($separatorStartRegexp, $separatorEndRegexp, $correctItemRegexp, $questionId, $correctItem, $attributes, $answer, $listAnswersInfo, $displayForStudent, $inBlankNumber)
{
$result = "";
$inTabTeacherSolution = $listAnswersInfo['tabwords'];
$inTeacherSolution = $inTabTeacherSolution[$inBlankNumber];
switch (self::getFillTheBlankAnswerType($inTeacherSolution)) {
case self::FILL_THE_BLANK_MENU:
$selected = "";
// the blank menu
$optionMenu = "";
// display a menu from answer separated with |
// if display for student, shuffle the correct answer menu
$listMenu = self::getFillTheBlankMenuAnswers($inTeacherSolution, $displayForStudent);
$result .= '<select name="choice['.$questionId.'][]">';
for ($k=0; $k < count($listMenu); $k++) {
$selected = "";
if ($correctItem == $listMenu[$k]) {
$selected = " selected=selected ";
}
// if in teacher view, display the first item by default, which is the right answer
if ($k==0 && !$displayForStudent) {
$selected = " selected=selected ";
}
$optionMenu .= '<option '.$selected.' value="'.$listMenu[$k].'">'.$listMenu[$k].'</option>';
}
if ($selected == "") {
// no good answer have been found...
$selected = " selected=selected ";
}
$result .= "<option $selected value=''>--</option>";
$result .= $optionMenu;
$result .= '</select>';
break;
case self::FILL_THE_BLANK_SEVERAL_ANSWER:
case self::FILL_THE_BLANK_STANDARD:
default:
$result = Display::input('text', "choice[$questionId][]", $correctItem, $attributes);
break;
}
return $result;
}
/**
* Return an array with the differents choice avaliable when the bracket is a menu
* @param $correctAnswer
* @param $displayForStudent true if we want to shuffle the choices of the menu for students
* @return array
*/
public static function getFillTheBlankMenuAnswers($correctAnswer, $displayForStudent)
{
// if $inDisplayForStudent, then shuffle the result array
$listChoises = api_preg_split("/\|/", $correctAnswer);
if ($displayForStudent) {
shuffle($listChoises);
}
return $listChoises;
}
/**
* Return the array indice of the student answer
* @param $correctAnswer the menu Choice1|Choice2|Choice3
* @param $studentAnswer the student answer must be Choice1 or Choice2 or Choice3
* @return int in the exemple 0 1 or 2 depending of the choice of the student
*/
public static function getFillTheBlankMenuAnswerNum($correctAnswer, $studentAnswer)
{
$listChoices = self::getFillTheBlankMenuAnswers($correctAnswer, false);
foreach ($listChoices as $num => $value) {
if ($value == $studentAnswer) {
return $num;
}
}
return -1; // should not happened, because student choose the answer in a menu of possible answers
}
/**
* return the possible answer if bracket is a multiple choice menu
* @param $correctAnswer
* @return array
*/
public static function getFillTheBlankSeveralAnswers($correctAnswer)
{
// is answer||Answer||response||Response , mean answer or Answer ...
$listSeveral = api_preg_split("/\|\|/", $correctAnswer);
return $listSeveral;
}
/**
* Return true if student answer is right according to the correctAnswer
* it is not so simple as equality, because of the type of Fill The Blank question
* eg : studentNaswer = 'Un' and correctAnswer = 'Un||1||un'
* @param $studentAnswer the [studentanswer] of the info array of the answer field
* @param $correctAnswer the [tabwords] of the info array of the answer field
* @return bool
*/
public static function isGoodStudentAnswer($studentAnswer, $correctAnswer)
{
switch (self::getFillTheBlankAnswerType($correctAnswer)) {
case self::FILL_THE_BLANK_MENU:
$listMenu = self::getFillTheBlankMenuAnswers($correctAnswer, false);
return ($listMenu[0] == $studentAnswer);
break;
case self::FILL_THE_BLANK_SEVERAL_ANSWER:
// the answer must be one of the choice made
$listSeveral = self::getFillTheBlankSeveralAnswers($correctAnswer);
return (in_array($studentAnswer, $listSeveral));
break;
case self::FILL_THE_BLANK_STANDARD:
default:
return ($studentAnswer == $correctAnswer);
}
}
public static function getFillTheBlankAnswerType($correctAnswer)
{
if (api_strpos($correctAnswer, "|") && !api_strpos($correctAnswer, "||")) {
return self::FILL_THE_BLANK_MENU;
} elseif (api_strpos($correctAnswer, "||")) {
return self::FILL_THE_BLANK_SEVERAL_ANSWER;
} else {
return self::FILL_THE_BLANK_STANDARD;
}
}
/**
* Return information about the answer
* @param string $answer : the text of the answer of the question
* @param bool $inIsStudentAnswer : true if it is a student answer and not the empty question model
* @return array of information about the answer
*/
public static function getAnswerInfo($userAnswer = "", $isStudentAnswer = false)
{
$listAnswerResults = array();
$listAnswerResults['text'] = "";
$listAnswerResults['wordsCount'] = 0;
$listAnswerResults['tabwordsbracket'] = array();
$listAnswerResults['tabwords'] = array();
$listAnswerResults['tabweighting'] = array();
$listAnswerResults['tabinputsize'] = array();
$listAnswerResults['switchable'] = "";
$listAnswerResults['studentanswer'] = array();
$listAnswerResults['studentscore'] = array();
$listAnswerResults['blankseparatornumber'] = 0;
api_preg_match("/(.*)::(.*)$/s", $userAnswer, $listResult);
if (count($listResult) < 2) {
$listDoubleColon[] = $listResult;
$listDoubleColon[] = "";
} else {
$listDoubleColon[] = $listResult[1];
$listDoubleColon[] = $listResult[2];
}
$listAnswerResults['systemstring'] = $listDoubleColon[1];
//make sure we only take the last bit to find special marks
$listArobaseSplit = explode('@', $listDoubleColon[1]);
if (count($listArobaseSplit) < 2) {
$listArobaseSplit[1] = "";
}
//take the complete string except after the last '::'
$listDetails = explode(":", $listArobaseSplit[0]);
// < number of item after the ::[score]:[size]:[separator_id]@ , here there are 3
if (count($listDetails) < 3) {
$listWeightings = explode(',', $listDetails[0]);
$listSizeOfInput = array();
for ($i=0; $i < count($listWeightings); $i++) {
$listSizeOfInput[] = 200;
}
$blankSeparatorNumber = 0; // 0 is [...]
} else {
$listWeightings = explode(',', $listDetails[0]);
$listSizeOfInput = explode(',', $listDetails[1]);
$blankSeparatorNumber = $listDetails[2];
}
$listAnswerResults['text'] = $listDoubleColon[0];
$listAnswerResults['tabweighting'] = $listWeightings;
$listAnswerResults['tabinputsize'] = $listSizeOfInput;
$listAnswerResults['switchable'] = $listArobaseSplit[1];
$listAnswerResults['blankseparatorstart'] = self::getStartSeparator($blankSeparatorNumber);
$listAnswerResults['blankseparatorend'] = self::getEndSeparator($blankSeparatorNumber);
$listAnswerResults['blankseparatornumber'] = $blankSeparatorNumber;
$blankCharStart = self::getStartSeparator($blankSeparatorNumber);
$blankCharEnd = self::getEndSeparator($blankSeparatorNumber);
$blankCharStartForRegexp = self::escapeForRegexp($blankCharStart);
$blankCharEndForRegexp = self::escapeForRegexp($blankCharEnd);
// get all blanks words
$listAnswerResults['wordsCount'] = preg_match_all('/'.$blankCharStartForRegexp.'[^'.$blankCharEndForRegexp.']*'.$blankCharEndForRegexp.'/', $listDoubleColon[0], $listWords);
if ($listAnswerResults['wordsCount'] > 0) {
$listAnswerResults['tabwordsbracket'] = $listWords[0];
// remove [ and ] in string
array_walk($listWords[0],function (&$value, $key, $tabBlankChar)
{
$trimChars = "";
for ($i=0; $i < count($tabBlankChar); $i++) {
$trimChars .= $tabBlankChar[$i];
}
$value = trim($value, $trimChars);
},
array($blankCharStart, $blankCharEnd)
);
$listAnswerResults['tabwords'] = $listWords[0];
}
// get all common words
$commonWords = preg_replace('/'.$blankCharStartForRegexp.'[^'.$blankCharEndForRegexp.']*'.$blankCharEndForRegexp.'/', "::", $listDoubleColon[0]);
// if student answer, the second [] is the student answer, the third is if student scored or not
$listBrackets = array();
$listWords = array();
if ($isStudentAnswer) {
for ($i=0; $i < count($listAnswerResults['tabwords']); $i++) {
$listBrackets[] = $listAnswerResults['tabwordsbracket'][$i];
$listWords[] = $listAnswerResults['tabwords'][$i];
if ($i+1 < count($listAnswerResults['tabwords'])) { // should always be
$i++;
}
$listAnswerResults['studentanswer'][] = $listAnswerResults['tabwords'][$i];
if ($i+1 < count($listAnswerResults['tabwords'])) { // should always be
$i++;
}
$listAnswerResults['studentscore'][] = $listAnswerResults['tabwords'][$i];
}
$listAnswerResults['tabwords'] = $listWords;
$listAnswerResults['tabwordsbracket'] = $listBrackets;
// if we are in student view, we've got 3 times :::::: for common words
$commonWords = preg_replace("/::::::/", "::", $commonWords);
}
$listAnswerResults['commonwords'] = explode("::", $commonWords);
return $listAnswerResults;
}
/**
* Replace the occurence of blank word with [correct answer][student answer][answer is correct]
* @param array $listWithStudentAnswer
* @return string
*/
public static function getAnswerInStudentAttempt($listWithStudentAnswer)
{
$separatorStart = $listWithStudentAnswer['blankseparatorstart'];
$separatorEnd = $listWithStudentAnswer['blankseparatorend'];
// lets rebuild the sentence with [correct answer][student answer][answer is correct]
$result = "";
for ($i=0; $i < count($listWithStudentAnswer['commonwords']) - 1; $i++) {
$result .= $listWithStudentAnswer['commonwords'][$i];
$result .= $listWithStudentAnswer['tabwordsbracket'][$i];
$result .= $separatorStart.$listWithStudentAnswer['studentanswer'][$i].$separatorEnd;
$result .= $separatorStart.$listWithStudentAnswer['studentscore'][$i].$separatorEnd;
}
$result .= $listWithStudentAnswer['commonwords'][$i];
$result .= "::";
// add the system string
$result .= $listWithStudentAnswer['systemstring'];
return $result;
}
/**
* This function is the same than the js one above getBlankSeparatorRegexp
* @param $inChar
* @return string
*/
public static function escapeForRegexp($inChar)
{
if (in_array($inChar, array(".", "+", "*", "?", "[", "^", "]", "$", "(", ")", "{", "}", "=", "!", ">", "|", ":", "-", ")"))) {
return "\\".$inChar;
} else {
return $inChar;
}
}
/**
* return $text protected for use in regexp
* @param $text
* @return mixed
*/
public static function getRegexpProtected($text)
{
$listRegexpCharacters = array("/", ".", "+", "*", "?", "[", "^", "]", "$", "(", ")", "{", "}", "=", "!", ">", "|", ":", "-", ")");
$result = $text;
for ($i=0; $i < count($listRegexpCharacters); $i++) {
$result = str_replace($listRegexpCharacters[$i], "\\".$listRegexpCharacters[$i], $result);
}
return $result;
}
/**
* This function must be the same than the js one getSeparatorFromNumber above
* @return array
*/
public static function getAllowedSeparator()
{
$fillBlanksAllowedSeparator = array(
array('[', ']'),
array('{', '}'),
array('(', ')'),
array('*', '*'),
array('#', '#'),
array('%', '%'),
array('$', '$'),
);
return $fillBlanksAllowedSeparator;
}
/**
* return the start separator for answer
* @param $number
* @return mixed
*/
public static function getStartSeparator($number)
{
$listSeparators = self::getAllowedSeparator();
return $listSeparators[$number][0];
}
/**
* return the end separator for answer
* @param $number
* @return mixed
*/
public static function getEndSeparator($number)
{
$listSeparators = self::getAllowedSeparator();
return $listSeparators[$number][1];
}
/**
* return as a desciption text, array of allowed separtors for question eg: array("[...]", "(...)")
* @return array
*/
public static function getAllowedSeparatorForSelect()
{
$listResults = array();
$fillBlanksAllowedSeparator = self::getAllowedSeparator();
for ($i=0; $i < count($fillBlanksAllowedSeparator); $i++) {
$listResults[] = $fillBlanksAllowedSeparator[$i][0]."...".$fillBlanksAllowedSeparator[$i][1];
}
return $listResults;
}
/**
* return the code number of the separator for the question
* @param $startSeparator
* @param $endSeparator
* @return int
*/
public function getDefaultSeparatorNumber($startSeparator, $endSeparator)
{
$listSeparators = self::getAllowedSeparator();
$result = 0;
for ($i=0; $i < count($listSeparators); $i++) {
if ($listSeparators[$i][0] == $startSeparator && $listSeparators[$i][1] == $endSeparator) {
$result = $i;
}
}
return $result;
}
/**
* return the HTML display of the answer
* @param $answer
* @return string
*/
public static function getHtmlDisplayForAsnwer($answer, $resultsDisabled = false)
{
$result = "";
$listStudentAnswerInfo = self::getAnswerInfo($answer, true);
// rebluid the answer with good HTML style
// this is the student answer, right or wrong
for ($i=0; $i < count($listStudentAnswerInfo['studentanswer']); $i++) {
if ($listStudentAnswerInfo['studentscore'][$i] == 1) {
$listStudentAnswerInfo['studentanswer'][$i] = self::getHtmlRightAsnwer($listStudentAnswerInfo['studentanswer'][$i], $listStudentAnswerInfo['tabwords'][$i], $resultsDisabled);
} else {
$listStudentAnswerInfo['studentanswer'][$i] = self::getHtmlWrongAnswer($listStudentAnswerInfo['studentanswer'][$i], $listStudentAnswerInfo['tabwords'][$i], $resultsDisabled);
}
}
// rebuild the sentence with student answer inserted
for ($i=0; $i < count($listStudentAnswerInfo['commonwords']); $i++) {
$result .= $listStudentAnswerInfo['commonwords'][$i];
$result .= $listStudentAnswerInfo['studentanswer'][$i];
}
// the last common word (should be </p>)
$result .= $listStudentAnswerInfo['commonwords'][$i];
return $result;
}
/**
* return the HTML code of answer for correct and wrong answer
* @param $answer
* @param $correct
* @param $right
* @return string
*/
public static function getHtmlAnswer($answer, $correct, $right, $resultsDisabled = false)
{
$style = "color: green";
if (!$right) {
$style = "color: red; text-decoration: line-through;";
}
$type = FillBlanks::getFillTheBlankAnswerType($correct);
switch ($type) {
case self::FILL_THE_BLANK_MENU:
$correctAnswerHtml = "";
$listPossibleAnswers = FillBlanks::getFillTheBlankMenuAnswers($correct, false);
$correctAnswerHtml .= "<span style='color: green'>".$listPossibleAnswers[0]."</span>";
$correctAnswerHtml .= " <span style='font-weight:normal'>(";
for ($i=1; $i < count($listPossibleAnswers); $i++) {
$correctAnswerHtml .= $listPossibleAnswers[$i];
if ($i != count($listPossibleAnswers) - 1) {
$correctAnswerHtml .= " | ";
}
}
$correctAnswerHtml .= ")</span>";
break;
case self::FILL_THE_BLANK_SEVERAL_ANSWER:
$listCorrects = explode("||", $correct);
$firstCorrect = $correct;
if (count($listCorrects) > 0) {
$firstCorrect = $listCorrects[0];
}
$correctAnswerHtml = "<span style='color: green'>".$firstCorrect."</span>";
break;
case self::FILL_THE_BLANK_STANDARD:
default:
$correctAnswerHtml = "<span style='color: green'>".$correct."</span>";
}
if ($resultsDisabled) {
$correctAnswerHtml = "<span title='".get_lang("ExerciseWithFeedbackWithoutCorrectionComment")."'> - </span>";
}
$result = "<span style='border:1px solid black; border-radius:5px; padding:2px; font-weight:bold;'>";
$result .= "<span style='$style'>".$answer."</span>";
$result .= "&nbsp;<span style='font-size:120%;'>/</span>&nbsp;";
$result .= $correctAnswerHtml;
$result .= "</span>";
return $result;
}
/**
* return HTML code for correct answer
* @param $answer
* @param $correct
* @return string
*/
public static function getHtmlRightAsnwer($answer, $correct, $resultsDisabled = false)
{
return self::getHtmlAnswer($answer, $correct, true, $resultsDisabled);
}
/**
* return HTML code for wrong answer
* @param $answer
* @param $correct
* @return string
*/
public static function getHtmlWrongAnswer($answer, $correct, $resultsDisabled = false)
{
return self::getHtmlAnswer($answer, $correct, false, $resultsDisabled);
}
} }

@ -57,7 +57,8 @@ if (!empty($question_list)) {
$question_id, $question_id,
$exercise_id, $exercise_id,
$courseCode, $courseCode,
$sessionId $sessionId,
$question_obj->type
); );
$data[$question_id]['name'] = cut($question_obj->question, 100); $data[$question_id]['name'] = cut($question_obj->question, 100);

@ -19,26 +19,27 @@ class ExerciseShowFunctions
{ {
/** /**
* Shows the answer to a fill-in-the-blanks question, as HTML * Shows the answer to a fill-in-the-blanks question, as HTML
* Display in the student result page, with score and comm
* @param string Answer text * @param string Answer text
* @param int Exercise ID * @param int Exercise ID
* @param int Question ID * @param int Question ID
* @return void * @return void
*/ */
static function display_fill_in_blanks_answer($feedback_type, $answer, $id, $questionId) static function display_fill_in_blanks_answer($feedbackType, $answer, $id, $questionId, $inResultsDisabled) {
{ $answerHTML = FillBlanks::getHtmlDisplayForAsnwer($answer, $inResultsDisabled);
if (empty($id)) { if (empty($id)) {
echo '<tr><td>'. (Security::remove_XSS($answer)).'</td></tr>'; echo '<tr><td>';
echo Security::remove_XSS($answerHTML, COURSEMANAGERLOWSECURITY);
echo '</td></tr>';
} else { } else {
?> ?>
<tr> <tr>
<td> <td>
<?php <?php echo nl2br(Security::remove_XSS($answerHTML, COURSEMANAGERLOWSECURITY)); ?>
echo (Security::remove_XSS($answer));
?>
</td> </td>
<?php <?php
if (!api_is_allowed_to_edit(null,true) && $feedback_type != EXERCISE_FEEDBACK_TYPE_EXAM) { ?> if (!api_is_allowed_to_edit(null,true) && $feedbackType != EXERCISE_FEEDBACK_TYPE_EXAM) { ?>
<td> <td>
<?php <?php
$comm = get_comments($id,$questionId); $comm = get_comments($id,$questionId);

Loading…
Cancel
Save