function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG; /// This implementation is also used by question type 'numerical' $readonly = empty($options->readonly) ? '' : 'readonly="readonly"'; $formatoptions = new stdClass(); $formatoptions->noclean = true; $formatoptions->para = false; $nameprefix = $question->name_prefix; /// Print question text and media $questiontext = format_text($question->questiontext, $question->questiontextformat, $formatoptions, $cmoptions->course); $image = get_question_image($question); $this->compute_feedbackperconditions($question, $state); /// Print input controls $values = array(); $params = explode(",", $question->options->parameters); foreach ($params as &$param) { $param = trim($param); $paramparts = explode(" ", $param); $paramname = trim($paramparts[0]); $paramunity = trim($paramparts[1]); if (isset($state->responses[$paramname]) && $state->responses[$paramname] != '') { $value[$paramname] = ' value="' . s($state->responses[$paramname], true) . '" '; } else { $value[$paramname] = ' value="" '; } $inputname[$paramname] = ' name="' . $nameprefix . $paramname . '" '; } $feedback = ''; $class = ''; $feedbackimg = ''; $feedbackperconditions = ''; if ($options->feedback) { $class = question_get_feedback_class($state->raw_grade); $feedbackimg = question_get_feedback_image($state->raw_grade); $feedbackperconditions = $question->options->computedfeedbackperconditions; } include "{$CFG->dirroot}/question/type/multinumerical/display.html"; }
/** * Prints the score obtained and maximum score available plus any penalty * information * * This function prints a summary of the scoring in the most recently * graded state (the question may not have been submitted for marking at * the current state). The default implementation should be suitable for most * question types. * @param object $question The question for which the grading details are * to be rendered. Question type specific information * is included. The maximum possible grade is in * ->maxgrade. * @param object $state The state. In particular the grading information * is in ->grade, ->raw_grade and ->penalty. * @param object $cmoptions * @param object $options An object describing the rendering options. */ function print_question_grading_details(&$question, &$state, $cmoptions, $options) { /* The default implementation prints the number of marks if no attempt has been made. Otherwise it displays the grade obtained out of the maximum grade available and a warning if a penalty was applied for the attempt and displays the overall grade obtained counting all previous responses (and penalties) */ global $QTYPES; // MDL-7496 show correct answer after "Incorrect" $correctanswer = ''; if ($correctanswers = $QTYPES[$question->qtype]->get_correct_responses($question, $state)) { if ($options->readonly && $options->correct_responses) { $delimiter = ''; if ($correctanswers) { foreach ($correctanswers as $ca) { $correctanswer .= $delimiter . $ca; $delimiter = ', '; } } } } if (QUESTION_EVENTDUPLICATE == $state->event) { echo ' '; print_string('duplicateresponse', 'quiz'); } if ($question->maxgrade > 0 && $options->scores) { if (question_state_is_graded($state->last_graded)) { // Display the grading details from the last graded state $grade = new stdClass(); $grade->cur = question_format_grade($cmoptions, $state->last_graded->grade); $grade->max = question_format_grade($cmoptions, $question->maxgrade); $grade->raw = question_format_grade($cmoptions, $state->last_graded->raw_grade); // let student know wether the answer was correct $class = question_get_feedback_class($state->last_graded->raw_grade / $question->maxgrade); echo '<div class="correctness ' . $class . '">' . get_string($class, 'quiz'); if ($correctanswer != '' && ($class == 'partiallycorrect' || $class == 'incorrect')) { echo '<div class="correctness">'; print_string('correctansweris', 'quiz', s($correctanswer)); echo '</div>'; } echo '</div>'; echo '<div class="gradingdetails">'; // print grade for this submission print_string('gradingdetails', 'quiz', $grade); // A unit penalty for numerical was applied so display it // a temporary solution for unit rendering in numerical // waiting for the new question engine code for a permanent one if (isset($state->options->raw_unitpenalty) && $state->options->raw_unitpenalty > 0.0) { echo ' '; print_string('unitappliedpenalty', 'qtype_numerical', question_format_grade($cmoptions, $state->options->raw_unitpenalty)); } if ($cmoptions->penaltyscheme) { // print details of grade adjustment due to penalties if ($state->last_graded->raw_grade > $state->last_graded->grade) { echo ' '; print_string('gradingdetailsadjustment', 'quiz', $grade); } // print info about new penalty // penalty is relevant only if the answer is not correct and further attempts are possible if ($state->last_graded->raw_grade < $question->maxgrade and QUESTION_EVENTCLOSEANDGRADE != $state->event) { if ('' !== $state->last_graded->penalty && (double) $state->last_graded->penalty > 0.0) { echo ' '; print_string('gradingdetailspenalty', 'quiz', question_format_grade($cmoptions, $state->last_graded->penalty)); } else { /* No penalty was applied even though the answer was not correct (eg. a syntax error) so tell the student that they were not penalised for the attempt */ echo ' '; print_string('gradingdetailszeropenalty', 'quiz'); } } } echo '</div>'; } } }
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $QTYPES, $CFG, $USER; $readonly = empty($options->readonly) ? '' : 'readonly="readonly"'; $disabled = empty($options->readonly) ? '' : 'disabled="disabled"'; $formatoptions = new stdClass(); $formatoptions->noclean = true; $formatoptions->para = false; $nameprefix = $question->name_prefix; // adding an icon with alt to warn user this is a fill in the gap question // MDL-7497 if (!empty($USER->screenreader)) { echo "<img src=\"{$CFG->wwwroot}/question/type/{$question->qtype}/icon.gif\" " . "class=\"icon\" alt=\"" . get_string('clozeaid', 'qtype_multichoice') . "\" /> "; } echo '<div class="ablock clearfix">'; // For this question type, we better print the image on top: if ($image = get_question_image($question)) { echo '<img class="qimage" src="' . $image . '" alt="" /><br />'; } $qtextremaining = format_text($question->questiontext, $question->questiontextformat, $formatoptions, $cmoptions->course); $strfeedback = get_string('feedback', 'quiz'); // The regex will recognize text snippets of type {#X} // where the X can be any text not containg } or white-space characters. while (ereg('\\{#([^[:space:]}]*)}', $qtextremaining, $regs)) { $qtextsplits = explode($regs[0], $qtextremaining, 2); echo "<label>"; // MDL-7497 echo $qtextsplits[0]; $qtextremaining = $qtextsplits[1]; $positionkey = $regs[1]; $wrapped =& $question->options->questions[$positionkey]; $answers =& $wrapped->options->answers; $correctanswers = $QTYPES[$wrapped->qtype]->get_correct_responses($wrapped, $state); $inputname = $nameprefix . $positionkey; if (isset($state->responses[$positionkey])) { $response = $state->responses[$positionkey]; } else { $response = null; } // Determine feedback popup if any $popup = ''; $style = ''; $feedbackimg = ''; if ($options->feedback) { $chosenanswer = null; switch ($wrapped->qtype) { case 'numerical': case 'shortanswer': $testedstate = clone $state; $testedstate->responses[''] = $response; foreach ($answers as $answer) { if ($QTYPES[$wrapped->qtype]->test_response($wrapped, $testedstate, $answer)) { $chosenanswer = clone $answer; break; } } break; case 'multichoice': if (isset($answers[$response])) { $chosenanswer = clone $answers[$response]; } break; default: break; } // Set up a default chosenanswer so that all non-empty wrong // answers are highlighted red if (empty($chosenanswer) && !empty($response)) { $chosenanswer = new stdClass(); $chosenanswer->fraction = 0.0; } if (!empty($chosenanswer->feedback)) { $feedback = s(str_replace(array("\\", "'"), array("\\\\", "\\'"), $chosenanswer->feedback)); $popup = " onmouseover=\"return overlib('{$feedback}', STICKY, MOUSEOFF, CAPTION, '{$strfeedback}', FGCOLOR, '#FFFFFF');\" " . " onmouseout=\"return nd();\" "; } /// Determine style if ($options->feedback && $response != '') { $style = 'class = "' . question_get_feedback_class($chosenanswer->fraction) . '"'; $feedbackimg = question_get_feedback_image($chosenanswer->fraction); } else { $style = ''; $feedbackimg = ''; } } // Print the input control switch ($wrapped->qtype) { case 'shortanswer': case 'numerical': echo " <input {$style} {$readonly} {$popup} name=\"{$inputname}\"\n type=\"text\" value=\"" . s($response, true) . "\" size=\"12\" /> "; if (!empty($feedback) && !empty($USER->screenreader)) { echo "<img src=\"{$CFG->pixpath}/i/feedback.gif\" alt=\"{$feedback}\" />"; } echo $feedbackimg; break; case 'multichoice': $outputoptions = '<option></option>'; // Default empty option foreach ($answers as $mcanswer) { $selected = ''; if ($response == $mcanswer->id) { $selected = ' selected="selected"'; } $outputoptions .= "<option value=\"{$mcanswer->id}\"{$selected}>" . s($mcanswer->answer, true) . '</option>'; } // In the next line, $readonly is invalid HTML, but it works in // all browsers. $disabled would be valid, but then the JS for // displaying the feedback does not work. Of course, we should // not be relying on JS (for accessibility reasons), but that is // a bigger problem. // // The span is used for safari, which does not allow styling of // selects. echo "<span {$style}><select {$popup} {$readonly} {$style} name=\"{$inputname}\">"; echo $outputoptions; echo '</select></span>'; if (!empty($feedback) && !empty($USER->screenreader)) { echo "<img src=\"{$CFG->pixpath}/i/feedback.gif\" alt=\"{$feedback}\" />"; } echo $feedbackimg; break; default: error("Unable to recognize questiontype ({$wrapped->qtype}) of\n question part {$positionkey}."); break; } echo "</label>"; // MDL-7497 } // Print the final piece of question text: echo $qtextremaining; $this->print_question_submit_buttons($question, $state, $cmoptions, $options); echo '</div>'; }
/** * @desc Prints the question. Calls question_webwork_derived, and prints out the html associated with derivedid. * @param $question object The question object to print. * @param $state object The state of the responses for the question. * @param $cmoptions object Options containing course ID. * @param $options object */ function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG, $USER; $readonly = empty($options->readonly) ? '' : 'disabled="disabled"'; //Formulate question image and text $questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions); $image = get_question_image($question, $cmoptions->course); $derivationid = $state->responses['derivationid']; $derivation = get_record('question_webwork_derived', 'id', $derivationid); $unparsedhtml = base64_decode($derivation->html); //partial answers $showPartiallyCorrectAnswers = $question->grading; //new array keyed by field $fieldhash = $state->responses['answers']; $answerfields = array(); $parser = new HtmlParser($unparsedhtml); $currentselect = ""; while ($parser->parse()) { //change some attributes of html tags for moodle compliance if ($parser->iNodeType == NODE_TYPE_ELEMENT) { $nodename = $parser->iNodeName; $name = $parser->iNodeAttributes['name']; //handle generic change of node's attribute name if ($nodename == "INPUT" || $nodename == "SELECT" || $nodename == "TEXTAREA") { $parser->iNodeAttributes['name'] = 'resp' . $question->id . '_' . $name; if ($state->event == QUESTION_EVENTGRADE && isset($fieldhash[$name])) { if ($showPartiallyCorrectAnswers) { $parser->iNodeAttributes['class'] = $parser->iNodeAttributes['class'] . ' ' . question_get_feedback_class($fieldhash[$name]['score']); } } if (!strstr($name, 'previous')) { $answerfields[$name] = $fieldhash[$name]; } } //handle specific change if ($nodename == "INPUT") { //put submitted value into field if (isset($fieldhash[$name])) { $parser->iNodeAttributes['value'] = $fieldhash[$name]['answer']; } } else { if ($nodename == "SELECT") { $currentselect = $name; } else { if ($nodename == "OPTION") { if ($parser->iNodeAttributes['value'] == $fieldhash[$currentselect]['answer']) { $parser->iNodeAttributes['selected'] = '1'; } } else { if ($nodename == "TEXTAREA") { } } } } } $problemhtml .= $parser->printTag(); } //for the seed form field $qid = $question->id; $seed = $state->responses['seed']; //if the student has answered include "{$CFG->dirroot}/question/type/webwork/display.html"; }
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $QTYPES, $CFG, $USER; $readonly = empty($options->readonly) ? '' : 'readonly="readonly"'; $disabled = empty($options->readonly) ? '' : 'disabled="disabled"'; $formatoptions = new stdClass(); $formatoptions->noclean = true; $formatoptions->para = false; $nameprefix = $question->name_prefix; // adding an icon with alt to warn user this is a fill in the gap question // MDL-7497 if (!empty($USER->screenreader)) { echo "<img src=\"{$CFG->wwwroot}/question/type/{$question->qtype}/icon.gif\" " . "class=\"icon\" alt=\"" . get_string('clozeaid', 'qtype_multichoice') . "\" /> "; } echo '<div class="ablock clearfix">'; // For this question type, we better print the image on top: if ($image = get_question_image($question)) { echo '<img class="qimage" src="' . $image . '" alt="" /><br />'; } $qtextremaining = format_text($question->questiontext, $question->questiontextformat, $formatoptions, $cmoptions->course); $strfeedback = get_string('feedback', 'quiz'); // The regex will recognize text snippets of type {#X} // where the X can be any text not containg } or white-space characters. while (ereg('\\{#([^[:space:]}]*)}', $qtextremaining, $regs)) { $qtextsplits = explode($regs[0], $qtextremaining, 2); echo $qtextsplits[0]; echo "<label>"; // MDL-7497 $qtextremaining = $qtextsplits[1]; $positionkey = $regs[1]; if (isset($question->options->questions[$positionkey]) && $question->options->questions[$positionkey] != '') { $wrapped =& $question->options->questions[$positionkey]; $answers =& $wrapped->options->answers; // $correctanswers = $QTYPES[$wrapped->qtype]->get_correct_responses($wrapped, $state); $inputname = $nameprefix . $positionkey; if (isset($state->responses[$positionkey])) { $response = $state->responses[$positionkey]; } else { $response = null; } // Determine feedback popup if any $popup = ''; $style = ''; $feedbackimg = ''; $feedback = ''; $correctanswer = ''; $strfeedbackwrapped = $strfeedback; $testedstate = clone $state; if ($correctanswers = $QTYPES[$wrapped->qtype]->get_correct_responses($wrapped, $testedstate)) { if ($options->readonly && $options->correct_responses) { $delimiter = ''; if ($correctanswers) { foreach ($correctanswers as $ca) { switch ($wrapped->qtype) { case 'numerical': case 'shortanswer': $correctanswer .= $delimiter . $ca; break; case 'multichoice': if (isset($answers[$ca])) { $correctanswer .= $delimiter . $answers[$ca]->answer; } break; } $delimiter = ', '; } } } if ($correctanswer != '') { $feedback = '<div class="correctness">'; $feedback .= get_string('correctansweris', 'quiz', s($correctanswer, true)); $feedback .= '</div>'; } } if ($options->feedback) { $chosenanswer = null; switch ($wrapped->qtype) { case 'numerical': case 'shortanswer': $testedstate = clone $state; $testedstate->responses[''] = $response; foreach ($answers as $answer) { if ($QTYPES[$wrapped->qtype]->test_response($wrapped, $testedstate, $answer)) { $chosenanswer = clone $answer; break; } } break; case 'multichoice': if (isset($answers[$response])) { $chosenanswer = clone $answers[$response]; } break; default: break; } // Set up a default chosenanswer so that all non-empty wrong // answers are highlighted red if (empty($chosenanswer) && $response != '') { $chosenanswer = new stdClass(); $chosenanswer->fraction = 0.0; } if (!empty($chosenanswer->feedback)) { $feedback = s(str_replace(array("\\", "'"), array("\\\\", "\\'"), $feedback . $chosenanswer->feedback)); if ($options->readonly && $options->correct_responses) { $strfeedbackwrapped = get_string('correctanswerandfeedback', 'qtype_multianswer'); } else { $strfeedbackwrapped = get_string('feedback', 'quiz'); } $popup = " onmouseover=\"return overlib('{$feedback}', STICKY, MOUSEOFF, CAPTION, '{$strfeedbackwrapped}', FGCOLOR, '#FFFFFF');\" " . " onmouseout=\"return nd();\" "; } /// Determine style if ($options->feedback && $response != '') { $style = 'class = "' . question_get_feedback_class($chosenanswer->fraction) . '"'; $feedbackimg = question_get_feedback_image($chosenanswer->fraction); } else { $style = ''; $feedbackimg = ''; } } if ($feedback != '' && $popup == '') { $strfeedbackwrapped = get_string('correctanswer', 'qtype_multianswer'); $feedback = s(str_replace(array("\\", "'"), array("\\\\", "\\'"), $feedback)); $popup = " onmouseover=\"return overlib('{$feedback}', STICKY, MOUSEOFF, CAPTION, '{$strfeedbackwrapped}', FGCOLOR, '#FFFFFF');\" " . " onmouseout=\"return nd();\" "; } // Print the input control switch ($wrapped->qtype) { case 'shortanswer': case 'numerical': $size = 1; foreach ($answers as $answer) { if (strlen(trim($answer->answer)) > $size) { $size = strlen(trim($answer->answer)); } } if (strlen(trim($response)) > $size) { $size = strlen(trim($response)) + 1; } $size = $size + rand(0, $size * 0.15); $size > 60 ? $size = 60 : ($size = $size); $styleinfo = "size=\"{$size}\""; /** * Uncomment the following lines if you want to limit for small sizes. * Results may vary with browsers see MDL-3274 */ /* if ($size < 2) { $styleinfo = 'style="width: 1.1em;"'; } if ($size == 2) { $styleinfo = 'style="width: 1.9em;"'; } if ($size == 3) { $styleinfo = 'style="width: 2.3em;"'; } if ($size == 4) { $styleinfo = 'style="width: 2.8em;"'; } */ echo "<input {$style} {$readonly} {$popup} name=\"{$inputname}\""; echo " type=\"text\" value=\"" . s($response, true) . "\" " . $styleinfo . " /> "; if (!empty($feedback) && !empty($USER->screenreader)) { echo "<img src=\"{$CFG->pixpath}/i/feedback.gif\" alt=\"{$feedback}\" />"; } echo $feedbackimg; break; case 'multichoice': if ($wrapped->options->layout == 0) { $outputoptions = '<option></option>'; // Default empty option foreach ($answers as $mcanswer) { $selected = ''; if ($response == $mcanswer->id) { $selected = ' selected="selected"'; } $outputoptions .= "<option value=\"{$mcanswer->id}\"{$selected}>" . s($mcanswer->answer, true) . '</option>'; } // In the next line, $readonly is invalid HTML, but it works in // all browsers. $disabled would be valid, but then the JS for // displaying the feedback does not work. Of course, we should // not be relying on JS (for accessibility reasons), but that is // a bigger problem. // // The span is used for safari, which does not allow styling of // selects. echo "<span {$style}><select {$popup} {$readonly} {$style} name=\"{$inputname}\">"; echo $outputoptions; echo '</select></span>'; if (!empty($feedback) && !empty($USER->screenreader)) { echo "<img src=\"{$CFG->pixpath}/i/feedback.gif\" alt=\"{$feedback}\" />"; } echo $feedbackimg; } else { if ($wrapped->options->layout == 1 || $wrapped->options->layout == 2) { $ordernumber = 0; $anss = array(); foreach ($answers as $mcanswer) { $ordernumber++; $checked = ''; $chosen = false; $type = 'type="radio"'; $name = "name=\"{$inputname}\""; if ($response == $mcanswer->id) { $checked = 'checked="checked"'; $chosen = true; } $a = new stdClass(); $a->id = $question->name_prefix . $mcanswer->id; $a->class = ''; $a->feedbackimg = ''; // Print the control $a->control = "<input {$readonly} id=\"{$a->id}\" {$name} {$checked} {$type} value=\"{$mcanswer->id}\" />"; if ($options->correct_responses && $mcanswer->fraction > 0) { $a->class = question_get_feedback_class(1); } if ($options->feedback && $chosen || $options->correct_responses) { if ($type == ' type="checkbox" ') { $a->feedbackimg = question_get_feedback_image($mcanswer->fraction > 0 ? 1 : 0, $chosen && $options->feedback); } else { $a->feedbackimg = question_get_feedback_image($mcanswer->fraction, $chosen && $options->feedback); } } // Print the answer text: no automatic numbering $a->text = format_text($mcanswer->answer, FORMAT_MOODLE, $formatoptions, $cmoptions->course); // Print feedback if feedback is on if (($options->feedback || $options->correct_responses) && $checked) { //|| $options->readonly $a->feedback = format_text($mcanswer->feedback, true, $formatoptions, $cmoptions->course); } else { $a->feedback = ''; } $anss[] = clone $a; } ?> <?php if ($wrapped->options->layout == 1) { ?> <table class="answer"> <?php $row = 1; foreach ($anss as $answer) { ?> <tr class="<?php echo 'r' . ($row = $row ? 0 : 1); ?> "> <td class="c0 control"> <?php echo $answer->control; ?> </td> <td class="c1 text <?php echo $answer->class; ?> "> <label for="<?php echo $answer->id; ?> "> <?php echo $answer->text; ?> <?php echo $answer->feedbackimg; ?> </label> </td> <td class="c0 feedback"> <?php echo $answer->feedback; ?> </td> </tr> <?php } ?> </table> <?php } else { if ($wrapped->options->layout == 2) { ?> <table class="answer"> <tr class="<?php echo 'r' . ($row = $row ? 0 : 1); ?> "> <?php $row = 1; foreach ($anss as $answer) { ?> <td class="c0 control"> <?php echo $answer->control; ?> </td> <td class="c1 text <?php echo $answer->class; ?> "> <label for="<?php echo $answer->id; ?> "> <?php echo $answer->text; ?> <?php echo $answer->feedbackimg; ?> </label> </td> <td class="c0 feedback"> <?php echo $answer->feedback; ?> </td> <?php } ?> </tr> </table> <?php } } } else { echo "no valid layout"; } } break; default: $a = new stdClass(); $a->type = $wrapped->qtype; $a->sub = $positionkey; print_error('unknownquestiontypeofsubquestion', 'qtype_multianswer', '', $a); break; } echo "</label>"; // MDL-7497 } else { if (!isset($question->options->questions[$positionkey])) { echo $regs[0] . "</label>"; } else { echo '</label><div class="error" >' . get_string('questionnotfound', 'qtype_multianswer', $positionkey) . '</div>'; } } } // Print the final piece of question text: echo $qtextremaining; $this->print_question_submit_buttons($question, $state, $cmoptions, $options); echo '</div>'; }
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG, $OUTPUT; $context = $this->get_context_by_category_id($question->category); $subquestions = $state->options->subquestions; $correctanswers = $this->get_correct_responses($question, $state); $nameprefix = $question->name_prefix; $answers = array(); // Answer choices formatted ready for output. $allanswers = array(); // This and the next used to detect identical answers $answerids = array(); // and adjust ids. $responses =& $state->responses; // Prepare a list of answers, removing duplicates. foreach ($subquestions as $subquestion) { foreach ($subquestion->options->answers as $ans) { $allanswers[$ans->id] = $ans->answer; if (!in_array($ans->answer, $answers)) { $answers[$ans->id] = strip_tags(format_string($ans->answer, false)); $answerids[$ans->answer] = $ans->id; } } } // Fix up the ids of any responses that point the the eliminated duplicates. foreach ($responses as $subquestionid => $ignored) { if ($responses[$subquestionid]) { $responses[$subquestionid] = $answerids[$allanswers[$responses[$subquestionid]]]; } } foreach ($correctanswers as $subquestionid => $ignored) { $correctanswers[$subquestionid] = $answerids[$allanswers[$correctanswers[$subquestionid]]]; } // Shuffle the answers $answers = draw_rand_array($answers, count($answers)); // Print formulation $questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions); // Print the input controls foreach ($subquestions as $key => $subquestion) { if ($subquestion->questiontext !== '' && !is_null($subquestion->questiontext)) { // Subquestion text: $a = new stdClass(); $text = $this->format_subquestion_text($subquestion, $state, $context); $a->text = $this->format_text($text, $subquestion->questiontextformat, $cmoptions); // Drop-down list: $menuname = $nameprefix . $subquestion->id; $response = isset($state->responses[$subquestion->id]) ? $state->responses[$subquestion->id] : '0'; $a->class = ' '; $a->feedbackimg = ' '; if ($options->readonly and $options->correct_responses) { if (isset($correctanswers[$subquestion->id]) and $correctanswers[$subquestion->id] == $response) { $correctresponse = 1; } else { $correctresponse = 0; } if ($options->feedback && $response) { $a->class = question_get_feedback_class($correctresponse); $a->feedbackimg = question_get_feedback_image($correctresponse); } } $attributes = array(); $attributes['disabled'] = $options->readonly ? 'disabled' : null; $a->control = html_writer::select($answers, $menuname, $response, array('' => 'choosedots'), $attributes); // Neither the editing interface or the database allow to provide // fedback for this question type. // However (as was pointed out in bug bug 3294) the randomsamatch // type which reuses this method can have feedback defined for // the wrapped shortanswer questions. //if ($options->feedback // && !empty($subquestion->options->answers[$responses[$key]]->feedback)) { // print_comment($subquestion->options->answers[$responses[$key]]->feedback); //} $anss[] = $a; } } include "{$CFG->dirroot}/question/type/match/display.html"; }
/** * Prints the score obtained and maximum score available plus any penalty * information * * This function prints a summary of the scoring in the most recently * graded state (the question may not have been submitted for marking at * the current state). The default implementation should be suitable for most * question types. * @param object $question The question for which the grading details are * to be rendered. Question type specific information * is included. The maximum possible grade is in * ->maxgrade. * @param object $state The state. In particular the grading information * is in ->grade, ->raw_grade and ->penalty. * @param object $cmoptions * @param object $options An object describing the rendering options. */ function print_question_grading_details(&$question, &$state, $cmoptions, $options) { /* The default implementation prints the number of marks if no attempt has been made. Otherwise it displays the grade obtained out of the maximum grade available and a warning if a penalty was applied for the attempt and displays the overall grade obtained counting all previous responses (and penalties) */ if (QUESTION_EVENTDUPLICATE == $state->event) { echo ' '; print_string('duplicateresponse', 'quiz'); } if ($question->maxgrade > 0 && $options->scores) { if (question_state_is_graded($state->last_graded)) { // Display the grading details from the last graded state $grade = new stdClass(); $grade->cur = question_format_grade($cmoptions, $state->last_graded->grade); $grade->max = question_format_grade($cmoptions, $question->maxgrade); $grade->raw = question_format_grade($cmoptions, $state->last_graded->raw_grade); // let student know wether the answer was correct $class = question_get_feedback_class($state->last_graded->raw_grade / $question->maxgrade); echo '<div class="correctness ' . $class . '">' . get_string($class, 'quiz') . '</div>'; echo '<div class="gradingdetails">'; // print grade for this submission print_string('gradingdetails', 'quiz', $grade); if ($cmoptions->penaltyscheme) { // print details of grade adjustment due to penalties if ($state->last_graded->raw_grade > $state->last_graded->grade) { echo ' '; print_string('gradingdetailsadjustment', 'quiz', $grade); } // print info about new penalty // penalty is relevant only if the answer is not correct and further attempts are possible if ($state->last_graded->raw_grade < $question->maxgrade / 1.01 and QUESTION_EVENTCLOSEANDGRADE != $state->event) { if ('' !== $state->last_graded->penalty && (double) $state->last_graded->penalty > 0.0) { // A penalty was applied so display it echo ' '; print_string('gradingdetailspenalty', 'quiz', question_format_grade($cmoptions, $state->last_graded->penalty)); } else { /* No penalty was applied even though the answer was not correct (eg. a syntax error) so tell the student that they were not penalised for the attempt */ echo ' '; print_string('gradingdetailszeropenalty', 'quiz'); } } } echo '</div>'; } } }
/** * Prints the main content of the question including any interactions */ function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG; $readonly = $options->readonly ? ' disabled="disabled"' : ''; $formatoptions = new stdClass(); $formatoptions->noclean = true; $formatoptions->para = false; // Print question formulation $questiontext = format_text($question->questiontext, $question->questiontextformat, $formatoptions, $cmoptions->course); $image = get_question_image($question); $answers =& $question->options->answers; $trueanswer =& $answers[$question->options->trueanswer]; $falseanswer =& $answers[$question->options->falseanswer]; $correctanswer = $trueanswer->fraction == 1 ? $trueanswer : $falseanswer; $trueclass = ''; $falseclass = ''; $truefeedbackimg = ''; $falsefeedbackimg = ''; // Work out which radio button to select (if any) if (isset($state->responses[''])) { $response = $state->responses['']; } else { $response = ''; } $truechecked = $response == $trueanswer->id ? ' checked="checked"' : ''; $falsechecked = $response == $falseanswer->id ? ' checked="checked"' : ''; // Work out visual feedback for answer correctness. if ($options->feedback) { if ($truechecked) { $trueclass = question_get_feedback_class($trueanswer->fraction); } else { if ($falsechecked) { $falseclass = question_get_feedback_class($falseanswer->fraction); } } } if ($options->feedback || $options->correct_responses) { if (isset($answers[$response])) { $truefeedbackimg = question_get_feedback_image($trueanswer->fraction, !empty($truechecked) && $options->feedback); $falsefeedbackimg = question_get_feedback_image($falseanswer->fraction, !empty($falsechecked) && $options->feedback); } } $inputname = ' name="' . $question->name_prefix . '" '; $trueid = $question->name_prefix . 'true'; $falseid = $question->name_prefix . 'false'; $radiotrue = '<input type="radio"' . $truechecked . $readonly . $inputname . 'id="' . $trueid . '" value="' . $trueanswer->id . '" /><label for="' . $trueid . '">' . s($trueanswer->answer) . '</label>'; $radiofalse = '<input type="radio"' . $falsechecked . $readonly . $inputname . 'id="' . $falseid . '" value="' . $falseanswer->id . '" /><label for="' . $falseid . '">' . s($falseanswer->answer) . '</label>'; $feedback = ''; if ($options->feedback and isset($answers[$response])) { $chosenanswer = $answers[$response]; $feedback = format_text($chosenanswer->feedback, true, $formatoptions, $cmoptions->course); } include "{$CFG->dirroot}/question/type/truefalse/display.html"; }
public function render_cell($x, $y, $readonly = false, $showcorrect = false) { $base = $this->render_cell_base($x, $y, $readonly); if (empty($showcorrect)) { return $base; } $class = ''; $hasanswer = $this->has_answer($this->responses, $x, $y); $weight = array_key_exists($x, $this->weights) && array_key_exists($y, $this->weights[$x]) ? $this->weights[$x][$y] : 0; if ($hasanswer && $weight > 0) { $class = question_get_feedback_class(1); } else { if ($hasanswer && $weight < 0) { $class = question_get_feedback_class(0); } else { if (!$hasanswer && $weight > 0) { $class = question_get_feedback_class(0); } } } $weighttext = $weight ? '<span class="smalltext ' . $class . '">(' . $weight * 100 . '%)</span>' : ''; return $base . $weighttext; }
/** * @param string $colname the name of the column. * @param object $attempt the row of data - see the SQL in display() in * mod/quiz/report/overview/report.php to see what fields are present, * and what they are called. * @return string the contents of the cell. */ function other_cols($colname, $attempt) { global $OUTPUT; if (preg_match('/^qsgrade([0-9]+)$/', $colname, $matches)) { $questionid = $matches[1]; $question = $this->questions[$questionid]; if (isset($this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid])) { $stateforqinattempt = $this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid]; } else { $stateforqinattempt = false; } if ($stateforqinattempt && question_state_is_graded($stateforqinattempt)) { $grade = quiz_rescale_grade($stateforqinattempt->grade, $this->quiz, 'question'); if (!$this->is_downloading()) { if (isset($this->regradedqs[$attempt->attemptuniqueid][$questionid])) { $gradefromdb = $grade; $newgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->newgrade, $this->quiz, 'question'); $oldgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->oldgrade, $this->quiz, 'question'); $grade = '<del>' . $oldgrade . '</del><br />' . $newgrade; } $link = new moodle_url("/mod/quiz/reviewquestion.php?attempt={$attempt->attempt}&question={$question->id}"); $action = new popup_action('click', $link, 'reviewquestion', array('height' => 450, 'width' => 650)); $linktopopup = $OUTPUT->action_link($link, $grade, $action, array('title' => get_string('reviewresponsetoq', 'quiz', $question->formattedname))); if ($this->questions[$questionid]->maxgrade != 0) { $fractionofgrade = $stateforqinattempt->grade / $this->questions[$questionid]->maxgrade; $qclass = question_get_feedback_class($fractionofgrade); $feedbackimg = question_get_feedback_image($fractionofgrade); $questionclass = "que"; return "<span class=\"{$questionclass}\"><span class=\"{$qclass}\">" . $linktopopup . "</span></span>{$feedbackimg}"; } else { return $linktopopup; } } else { return $grade; } } else { if ($stateforqinattempt && question_state_is_closed($stateforqinattempt)) { $text = get_string('requiresgrading', 'quiz_overview'); if (!$this->is_downloading()) { $link = new moodle_url("/mod/quiz/reviewquestion.php?attempt={$attempt->attempt}&question={$question->id}"); $action = new popup_action('click', $link, 'reviewquestion', array('height' => 450, 'width' => 650)); return $OUTPUT->action_link($link, $text, $action, array('title' => get_string('reviewresponsetoq', 'quiz', $question->formattedname))); } else { return $text; } } else { return '--'; } } } else { return NULL; } }
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG; $subquestions = $state->options->subquestions; $nameprefix = $question->name_prefix; $answers = array(); $responses =& $state->responses; // Check browser version to see if YUI is supported properly. // This is similar to ajaxenabled() from lib/ajax/ajaxlib.php, // except it doesn't check the site-wide AJAX settings. $fallbackonly = false; $ie = check_browser_version('MSIE', 6.0); $ff = check_browser_version('Gecko', 20051106); $op = check_browser_version('Opera', 9.0); $sa = check_browser_version('Safari', 412); if (!$ie && !$ff && !$op && !$sa or !empty($USER->screenreader)) { $fallbackonly = true; } // Check to see if the defaultresponse option has changed from the previous // submission /*if (isset($responses['defaultresponse'])) { $state->options->defaultresponse = $responses['defaultresponse']; } // If it's not set at all, default is no else if (!isset($state->options->defaultresponse)) { $state->options->defaultresponse = "no"; }*/ if (isset($responses['defaultresponse']) and $responses['defaultresponse'] == 'on') { $state->options->defaultresponse = 'yes'; } else { if (isset($responses['defaultresponse']) and $responses['defaultresponse'] != 'on') { $state->options->defaultresponse = 'no'; } else { $state->options->defaultresponse = 'no'; } } // Determine which responses are correct. $evaluatedresponses = $this->get_evaluated_responses($question, $state); $correctresponses = array(); foreach ($subquestions as $key => $subquestion) { if ($subquestion->questiontext) { if ($evaluatedresponses[$key]) { $correctresponses[$key] = true; } else { $correctresponses[$key] = false; } } } // Generate question intro for both versions $questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions); $image = get_question_image($question); //////////////////////////////// // Generate fallback version //////////////////////////////// // Prepare a list of answers and sort them foreach ($subquestions as $subquestion) { foreach ($subquestion->options->answers as $ans) { $answers[$ans->answer] = $ans->answer; } } asort($answers); // Add each subquestion to the output foreach ($subquestions as $key => $subquestion) { if ($subquestion->questiontext) { // Subquestion text: $a = new stdClass(); $a->text = $this->format_text($subquestion->questiontext, $question->questiontextformat, $cmoptions); // Drop-down list: $menuname = $nameprefix . $subquestion->code; $response = isset($state->responses[$subquestion->code]) ? $state->responses[$subquestion->code] : '0'; $a->class = ' '; $a->feedbackimg = ' '; if ($options->readonly) { if ($correctresponses[$subquestion->code]) { $correctresponse = 1; } else { $correctresponse = 0; } if ($options->feedback && $response) { $a->class = question_get_feedback_class($correctresponse); $a->feedbackimg = question_get_feedback_image($correctresponse); } } $a->control = choose_from_menu($answers, $menuname, $response, 'choose', '', 0, true, $options->readonly); $anss[] = $a; } } ////////////////////////////////// // Generate javascript version ////////////////////////////////// // Initialize variables $ulname = 'ul' . $question->id; $liname = 'li' . $question->id; $defaultresponsename = $nameprefix . 'defaultresponse'; if ($state->options->defaultresponse == 'yes') { $ulclass .= 'deactivateddraglist'; } else { $ulclass = 'draglist'; } // Javascript to initialize variables and event callbacks $jsinit = array(); // HTML to write in javascript version $jswrite = array(); // Javascript Array initialization of list ids $lielems = array(); foreach ($subquestions as $subquestion) { $lielems[] = '"' . $liname . '_' . $subquestion->code . '"'; } $liarraystring = 'Array(' . implode(',', $lielems) . ')'; // Set up event callbacks for interactive version if (!$options->readonly) { $jsinit[] = 'var hiddennames = new Object();'; $jsinit[] = 'hiddennames.ulname = "' . $ulname . '";'; $jsinit[] = 'hiddennames.respname = "hidden' . $nameprefix . '";'; $jsinit[] = 'var checkboxnames = new Object();'; $jsinit[] = 'checkboxnames.defaultresponsename = "cb' . $defaultresponsename . '";'; $jsinit[] = 'checkboxnames.ulname = "' . $ulname . '";'; $jsinit[] = 'YAHOO.util.Event.addListener("responseform", "click", ddOrderingSetHiddens, hiddennames);'; $jsinit[] = 'YAHOO.util.Event.addListener("cb' . $defaultresponsename . '", "click", processGradeCheckbox, checkboxnames);'; } else { $ulclass .= ' readonly'; } // List class options if ($question->options->horizontal) { $ulclass .= ' inline'; } // HTML for javascript version // Generate the hidden variables that store the responses $inputs = array(); $i = 1; foreach ($subquestions as $subquestion) { if (!empty($subquestion->questiontext)) { $inputs[$subquestion->code] = array(); $inputs[$subquestion->code]['id'] = 'hidden' . $nameprefix . $subquestion->code; $inputs[$subquestion->code]['name'] = $nameprefix . $subquestion->code; // If the order is defined by a previous response, use that item order if (isset($responses[$subquestion->code]) && $responses[$subquestion->code] > 0) { $inputs[$subquestion->code]['value'] = $responses[$subquestion->code]; } else { $inputs[$subquestion->code]['value'] = $i; $responses[$subquestion->code] = $i; } $i += 1; } } // Sort the items by response position to display them in the same order as they // were submitted in (or in the default shuffled order for the initial version) $items = array(); foreach ($subquestions as $key => $subquestion) { $items[$responses[$key]] = $subquestion; } ksort($items); $lis = array(); foreach ($items as $subquestion) { $response = isset($responses[$subquestion->code]) ? $responses[$key] : '0'; // If readonly, set up feedback for each item $liclass = ''; if ($options->readonly) { $liclass .= ' readonly'; } $feedbackimg = ''; if ($options->readonly) { if ($correctresponses[$subquestion->code]) { $correctresponse = 1; } else { $correctresponse = 0; } if ($options->feedback && $response) { if ($state->options->defaultresponse == 'no') { $liclass .= ' ' . question_get_feedback_class($correctresponse); $feedbackimg = ' ' . question_get_feedback_image($correctresponse); } } } if ($subquestion->questiontext) { // Clean up text and replace " with \\" for use in javascript $subquestiontext = $this->format_text($subquestion->questiontext, $question->questiontextformat, $cmoptions); $subquestiontext = preg_replace('/\\r\\n/', ' ', $subquestiontext); $subquestiontext = preg_replace('/"/', '\\"', $subquestiontext); // Add the list element to the output $lis[$subquestion->code] = array(); $lis[$subquestion->code]['class'] = $liclass; $lis[$subquestion->code]['id'] = $liname . '_' . $subquestion->code; $lis[$subquestion->code]['text'] = $subquestiontext; if (preg_match('/[<[a-z].*>/', $subquestiontext)) { $lis[$subquestion->code]['ishtml'] = true; } if ($feedbackimg) { preg_match('/src="([^"]*)"/', $feedbackimg, $matches); $lis[$subquestion->code]['feedbackimgsrc'] = $matches[1]; preg_match('/alt="([^"]*)"/', $feedbackimg, $matches); $lis[$subquestion->code]['feedbackimgalt'] = $matches[1]; preg_match('/class="([^"]*)"/', $feedbackimg, $matches); $lis[$subquestion->code]['feedbackimgclass'] = $matches[1]; } } } // Restore defaultresponse option from state $defaultresponsechecked = ''; $defaultresponsevalue = 'no'; if ($state->options->defaultresponse == 'yes') { $defaultresponsechecked = 'checked="checked"'; $defaultresponsevalue = 'yes'; } $defaultresponsestr = get_string('defaultresponse', 'qtype_order'); include "{$CFG->dirroot}/question/type/order/display.html"; }
/** * @desc Generates the HTML for a particular question. * @param integer $seed The seed of the question. * @param array $answers An array of answers that needs to be rendered. * @param object $event The event object. * @return string The HTML question representation. */ public function render($seed, &$answers, $event) { //JIT Derivation creation //Usually we have this from the check answers call if (!isset($this->_derivation)) { $client = WebworkClient::Get(); $env = WebworkQuestion::DefaultEnvironment(); $env->problemSeed = $seed; $result = $client->renderProblem($env, $this->_data->code); $derivation = new stdClass(); $derivation->html = base64_decode($result->output); $derivation->seed = $result->seed; $this->_derivation = $derivation; } $orderedanswers = array(); $tempanswers = array(); foreach ($answers as $answer) { $tempanswers[$answer->field] = $answer; } $answers = $tempanswers; $showpartialanswers = $this->_data->grading; $questionhtml = ""; $parser = new HtmlParser($this->_derivation->html); $currentselect = ""; $textarea = false; $checkboxes = array(); while ($parser->parse()) { //change some attributes of html tags for moodle compliance if ($parser->iNodeType == NODE_TYPE_ELEMENT) { $nodename = $parser->iNodeName; if (isset($parser->iNodeAttributes['name'])) { $name = $parser->iNodeAttributes['name']; } //handle generic change of node's attribute name if ($nodename == "INPUT" || $nodename == "SELECT" || $nodename == "TEXTAREA") { $parser->iNodeAttributes['name'] = 'resp' . $this->_data->question . '_' . $name; if ($event == QUESTION_EVENTGRADE && isset($answers[$name])) { if ($showpartialanswers) { if (isset($parser->iNodeAttributes['class'])) { $class = $parser->iNodeAttributes['class']; } else { $class = ""; } $parser->iNodeAttributes['class'] = $class . ' ' . question_get_feedback_class($answers[$name]->score); } } } //handle specific change if ($nodename == "INPUT") { $nodetype = strtoupper($parser->iNodeAttributes['type']); if ($nodetype == "CHECKBOX") { if (strstr($answers[$name]->answer, $parser->iNodeAttributes['value'])) { //FILLING IN ANSWER (CHECKBOX) array_push($orderedanswers, $answers[$name]); $parser->iNodeAttributes['checked'] = '1'; } $parser->iNodeAttributes['name'] = $parser->iNodeAttributes['name'] . '_' . $parser->iNodeAttributes['value']; } else { if ($nodetype == "TEXT") { if (isset($answers[$name])) { //FILLING IN ANSWER (FIELD) array_push($orderedanswers, $answers[$name]); $parser->iNodeAttributes['value'] = $answers[$name]->answer; } } } } else { if ($nodename == "SELECT") { $currentselect = $name; } else { if ($nodename == "OPTION") { if ($parser->iNodeAttributes['value'] == $answers[$currentselect]->answer) { //FILLING IN ANSWER (DROPDOWN) array_push($orderedanswers, $answers[$currentselect]); $parser->iNodeAttributes['selected'] = '1'; } } else { if ($nodename == "TEXTAREA") { if (isset($answers[$name])) { array_push($orderedanswers, $answers[$name]); $textarea = true; $questionhtml .= $parser->printTag(); $questionhtml .= $answers[$name]->answer; } } } } } } if (!$textarea) { $questionhtml .= $parser->printTag(); } else { $textarea = false; } } $answers = $orderedanswers; return $questionhtml; }
/** * Prints the question body. Since standard moodle question functions set up * variables and prints html in the same function, we cannot call these functions. * So, the most code of this function (specially the type-specific part) is copied * from the standard moodle question types. * **/ function wrsqz_print_question_formulation_and_controls($questionType, $dbType, &$question, &$state, &$cmoptions, &$options) { //COMMON VARIABLES: global $CFG, $QTYPES; //1. Question text $formatoptions = new stdClass; $formatoptions->noclean = true; $formatoptions->para = false; $questiontext = format_text($question->questiontext, $question->questiontextformat, $formatoptions, $cmoptions->course); //2. Question image $image = get_question_image($question); //3. name & strings $inputname = $question->name_prefix; $stranswer = get_string("answer", "quiz").': '; //4. WIRIS CAS applet $wirisCASApplet = ''; $wirisCASForComputationsEnabled = !empty($question->options->wiris->options['wirisCASForComputations']); if($wirisCASForComputationsEnabled){ $wirisCASContent = ''; if (!empty($state->responses['wirisCASHidden'])) { $wirisCASContent = htmlentities(stripslashes_safe($state->responses['wirisCASHidden']), ENT_QUOTES, 'UTF-8'); unset($state->responses['wirisCASHidden']); }else if(!empty($question->options->wiris->options['hiddenInitialCASValue'])){ $wirisCASContent = htmlentities(stripslashes_safe($question->options->wiris->options['hiddenInitialCASValue']), ENT_QUOTES, 'UTF-8'); } $wirisCASApplet = wrsqz_wirisCASAppletHTML($inputname, $wirisCASContent, false, 630, 300); require_js(array('yui_yahoo', 'yui_dom-event')); require_js(array($CFG->wwwroot.'/wiris-quizzes/js/wiris-quizzes.js',$CFG->wwwroot.'/wiris-quizzes/js/constants.js.php')); } //ANSWER FIELDS & FEEDBACK: QUESTION-TYPE specific if($questionType == 'essay'){ // Response if (isset($state->responses[''])) { $value = stripslashes_safe($state->responses['']); }else{ $value = ""; } //answer if($wirisCASForComputationsEnabled){ $wirisCASForComputations = $question->options->wiris->options['wirisCASForComputations']; }else{ $wirisCASForComputations = '0'; } //replace answer by an applet if($wirisCASForComputations == '2'){ $answer = $wirisCASApplet; $answer .= '<input type="hidden" name="'.$inputname.'" id="edit-'.$inputname.'"/>'; $wirisCASApplet = ''; }else{ if (empty($options->readonly)) { static $htmleditorused = false; $usehtmleditor = can_use_html_editor() && !$htmleditorused; // the student needs to type in their answer so print out a text editor echo '<!-- yes we can: '.$usehtmleditor.'-->'; $answer = print_textarea($usehtmleditor, 18, 80, 630, 400, $inputname, $value, $cmoptions->course, true); }else{ //it is read only, so just format the students answer and output it $safeformatoptions = new stdClass; $safeformatoptions->para = false; $answer = format_text($value, FORMAT_MOODLE, $safeformatoptions, $cmoptions->course); $answer = '<div class="answerreview">' . $answer . '</div>'; } if($wirisCASForComputationsEnabled){ $wirisCASApplet = '<tr><td>'.$wirisCASApplet.'</td></tr>'; } } // feedback handling $feedback = ''; if ($options->feedback && !empty($answers)) { foreach ($answers as $answer) { $feedback = format_text($answer->feedback, '', $formatoptions, $cmoptions->course); } } }else if($questionType == 'match'){ $subquestions = $state->options->subquestions; $correctanswers = $QTYPES[$question->qtype]->get_correct_responses($question, $state); $answers = array(); // Answer choices formatted ready for output. $allanswers = array(); // This and the next used to detect identical answers $answerids = array(); // and adjust ids. $responses = &$state->responses; // Prepare a list of answers, removing duplicates. foreach ($subquestions as $subquestion) { foreach ($subquestion->options->answers as $ans) { $allanswers[$ans->id] = $ans->answer; if (!in_array($ans->answer, $answers)) { $answers[$ans->id] = strip_tags(format_string($ans->answer, false)); $answerids[$ans->answer] = $ans->id; } } } // Fix up the ids of any responses that point the the eliminated duplicates. foreach ($responses as $subquestionid => $ignored) { if ($responses[$subquestionid]) { $responses[$subquestionid] = $answerids[$allanswers[$responses[$subquestionid]]]; } } foreach ($correctanswers as $subquestionid => $ignored) { $correctanswers[$subquestionid] = $answerids[$allanswers[$correctanswers[$subquestionid]]]; } // Shuffle the answers $answers = draw_rand_array($answers, count($answers)); // Print the input controls foreach ($subquestions as $key => $subquestion) { if ($subquestion->questiontext !== '' && !is_null($subquestion->questiontext)) { // Subquestion text: $a = new stdClass; $a->text = format_text($subquestion->questiontext, $question->questiontextformat, $cmoptions); // Drop-down list: $menuname = $inputname.$subquestion->id; $response = isset($state->responses[$subquestion->id]) ? $state->responses[$subquestion->id] : '0'; $a->class = ' '; $a->feedbackimg = ' '; if ($options->readonly and $options->correct_responses) { if (isset($correctanswers[$subquestion->id]) and ($correctanswers[$subquestion->id] == $response)) { $correctresponse = 1; } else { $correctresponse = 0; } if ($options->feedback && $response) { $a->class = question_get_feedback_class($correctresponse); $a->feedbackimg = question_get_feedback_image($correctresponse); } } $a->control = choose_from_menu($answers, $menuname, $response, 'choose', '', 0, true, $options->readonly); $anss[] = $a; } } }else if($questionType == 'multianswer'){ }else if($questionType == 'multichoice'){ $answers = &$question->options->answers; $correctanswers = $QTYPES['multichoicewiris']->get_correct_responses($question, $state); $readonly = empty($options->readonly) ? '' : 'disabled="disabled"'; $answerprompt = ($question->options->single) ? get_string('singleanswer', 'quiz') : get_string('multipleanswers', 'quiz'); // Print each answer in a separate row foreach ($state->options->order as $key => $aid) { $answer = &$answers[$aid]; $checked = ''; $chosen = false; if ($question->options->single) { $type = 'type="radio"'; $name = "name=\"{$question->name_prefix}\""; if (isset($state->responses['']) and $aid == $state->responses['']) { $checked = 'checked="checked"'; $chosen = true; } } else { $type = ' type="checkbox" '; $name = "name=\"{$question->name_prefix}{$aid}\""; if (isset($state->responses[$aid])) { $checked = 'checked="checked"'; $chosen = true; } } $a = new stdClass; $a->id = $question->name_prefix . $aid; $a->class = ''; $a->feedbackimg = ''; // Print the control $a->control = "<input $readonly id=\"$a->id\" $name $checked $type value=\"$aid\" />"; if ($options->correct_responses && $answer->fraction > 0) { $a->class = question_get_feedback_class(1); } if (($options->feedback && $chosen) || $options->correct_responses) { if ($type == ' type="checkbox" ') { $a->feedbackimg = question_get_feedback_image($answer->fraction > 0 ? 1 : 0, $chosen && $options->feedback); } else { $a->feedbackimg = question_get_feedback_image($answer->fraction, $chosen && $options->feedback); } } // Print the answer text $a->text = $QTYPES['multichoicewiris']->number_in_style($key, $question->options->answernumbering) . format_text($answer->answer, FORMAT_MOODLE, $formatoptions, $cmoptions->course); // Print feedback if feedback is on if (($options->feedback || $options->correct_responses) && $checked) { $a->feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course); } else { $a->feedback = ''; } $anss[] = clone($a); } $feedback = ''; if ($options->feedback) { if ($state->raw_grade >= $question->maxgrade/1.01) { $feedback = $question->options->correctfeedback; } else if ($state->raw_grade > 0) { $feedback = $question->options->partiallycorrectfeedback; } else { $feedback = $question->options->incorrectfeedback; } $feedback = format_text($feedback, $question->questiontextformat, $formatoptions, $cmoptions->course); } }else if($questionType == 'shortanswer'){ $value = ''; $readonly = (empty($options->readonly)) ? '' : 'readonly="readonly"'; $feedback = ''; $class = ''; $feedbackimg = ''; if (isset($state->responses['']) && $state->responses[''] != '') { $value = s($state->responses[''], true); } mb_parse_str($question->options->wiris->eqoption, $eqoptionArray); $wirisEditorEnabled = (isset($eqoptionArray['editor']) && $eqoptionArray['editor'] == 'true'); if($wirisCASForComputationsEnabled && $wirisEditorEnabled){ //copy button $wirisCASApplet .= '<input id="'.$inputname.'copy_button" name="'.$inputname.'copy_button" type="button" '. 'value="'.wrsqz_get_string('wrsqz_copyresponse') .'" onclick="copyCASSessionToEditor('.$question->id.',\''.$inputname.'\')"/>'; require_js('yui_connection'); } //$wirisCASForComputationsEnabled = (isset($eqoptionArray['wirisCASForComputations']) && $eqoptionArray['wirisCASForComputations'] == 'true'); $multipleAnswers = (isset($eqoptionArray['multipleAnswers']) && $eqoptionArray['multipleAnswers'] == 'true'); if ($multipleAnswers) { $formulaGrammar = 'http://' . $CFG->wirisservicehost . ':' . $CFG->wirisserviceport . $CFG->wirisservicepath . '/test/grammars/grammar-assign.txt'; $formulaGrammarTarget = 'math2'; }else { $formulaGrammar = 'http://' . $CFG->wirisservicehost . ':' . $CFG->wirisserviceport . $CFG->wirisservicepath . '/test/grammars/grammar.txt'; $formulaGrammarTarget = 'math'; } $wirisEditorApplet = wrsqz_wirisEditorAppletHTML($inputname, $formulaGrammar, $formulaGrammarTarget, $value); require_js(array('yui_yahoo', 'yui_dom-event')); require_js(array($CFG->wwwroot.'/wiris-quizzes/js/wiris-quizzes.js', $CFG->wwwroot.'/wiris-quizzes/js/constants.js.php')); // Chose feedback according to current response if ($options->feedback) { $class = question_get_feedback_class(0); $feedbackimg = question_get_feedback_image(0); $i = 0; foreach ($question->options->answers as $answer) { if (wrsqz_testResponse($question, $state, $answer) || (!empty($state->grades) && $state->grades[$i] > 0.0)) { $class = question_get_feedback_class($answer->fraction); $feedbackimg = question_get_feedback_image($answer->fraction); if ($answer->feedback) { $feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course); } break; } ++$i; } } }else if($questionType == 'truefalse'){ $readonly = $options->readonly ? ' disabled="disabled"' : ''; $answers = &$question->options->answers; $trueanswer = &$answers[$question->options->trueanswer]; $falseanswer = &$answers[$question->options->falseanswer]; $correctanswer = ($trueanswer->fraction == 1) ? $trueanswer : $falseanswer; $trueclass = ''; $falseclass = ''; $truefeedbackimg = ''; $falsefeedbackimg = ''; // Work out which radio button to select (if any) if (isset($state->responses[''])) { $response = $state->responses['']; } else { $response = ''; } $truechecked = ($response == $trueanswer->id) ? ' checked="checked"' : ''; $falsechecked = ($response == $falseanswer->id) ? ' checked="checked"' : ''; // Work out visual feedback for answer correctness. if ($options->feedback) { if ($truechecked) { $trueclass = question_get_feedback_class($trueanswer->fraction); } else if ($falsechecked) { $falseclass = question_get_feedback_class($falseanswer->fraction); } } if ($options->feedback || $options->correct_responses) { if (isset($answers[$response])) { $truefeedbackimg = question_get_feedback_image($trueanswer->fraction, !empty($truechecked) && $options->feedback); $falsefeedbackimg = question_get_feedback_image($falseanswer->fraction, !empty($falsechecked) && $options->feedback); } } $inputname = ' name="'.$question->name_prefix.'" '; $trueid = $question->name_prefix.'true'; $falseid = $question->name_prefix.'false'; $radiotrue = '<input type="radio"' . $truechecked . $readonly . $inputname . 'id="'.$trueid . '" value="' . $trueanswer->id . '" /><label for="'.$trueid . '">' . s($trueanswer->answer) . '</label>'; $radiofalse = '<input type="radio"' . $falsechecked . $readonly . $inputname . 'id="'.$falseid . '" value="' . $falseanswer->id . '" /><label for="'.$falseid . '">' . s($falseanswer->answer) . '</label>'; $feedback = ''; if ($options->feedback and isset($answers[$response])) { //choose feedback depending on correctness of response if($answers[$response]->fraction == 1){ $feedback = format_text($trueanswer->feedback, true, $formatoptions, $cmoptions->course); }else{ $feedback = format_text($falseanswer->feedback, true, $formatoptions, $cmoptions->course); } } } //print body include("$CFG->dirroot/question/type/$question->qtype/display.html"); //print buttons $QTYPES[$question->qtype]->print_question_submit_buttons($question, $state, $cmoptions, $options); echo '</div>'; //close <div class="block clearfix"> if($questionType == 'essay' && empty($options->readonly) && !empty($usehtmleditor)){ use_html_editor($inputname); $htmleditorused = true; }else if($questionType == 'truefalse'){ echo '</div>'; //close <div class = "truefalse"/> } }
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG; /// This implementation is also used by question type 'numerical' $readonly = empty($options->readonly) ? '' : 'readonly="readonly"'; $formatoptions = new stdClass(); $formatoptions->noclean = true; $formatoptions->para = false; $nameprefix = $question->name_prefix; /// Print question text and media $questiontext = format_text($question->questiontext, $question->questiontextformat, $formatoptions, $cmoptions->course); $image = get_question_image($question, $cmoptions->course); /// Print input controls if (isset($state->responses['']) && $state->responses[''] != '') { $value = ' value="' . s($state->responses[''], true) . '" '; } else { $value = ' value="" '; } $inputname = ' name="' . $nameprefix . '" '; $feedback = ''; $class = ''; $feedbackimg = ''; if ($options->feedback) { $class = question_get_feedback_class(0); $feedbackimg = question_get_feedback_image(0); foreach ($question->options->answers as $answer) { if ($this->test_response($question, $state, $answer)) { // Answer was correct or partially correct. $class = question_get_feedback_class($answer->fraction); $feedbackimg = question_get_feedback_image($answer->fraction); if ($answer->feedback) { $feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course); } break; } } } /// Removed correct answer, to be displayed later MDL-7496 include "{$CFG->dirroot}/question/type/shortanswer/display.html"; }
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG; $subquestions = $state->options->subquestions; $correctanswers = $this->get_correct_responses($question, $state); $nameprefix = $question->name_prefix; $answers = array(); $allanswers = array(); $answerids = array(); $responses =& $state->responses; // Prepare a list of answers, removing duplicates. foreach ($subquestions as $subquestion) { foreach ($subquestion->options->answers as $ans) { $allanswers[$ans->id] = $ans->answer; if (!in_array($ans->answer, $answers)) { $answers[$ans->id] = $ans->answer; $answerids[$ans->answer] = $ans->id; } } } // Fix up the ids of any responses that point the the eliminated duplicates. foreach ($responses as $subquestionid => $ignored) { if ($responses[$subquestionid]) { $responses[$subquestionid] = $answerids[$allanswers[$responses[$subquestionid]]]; } } foreach ($correctanswers as $subquestionid => $ignored) { $correctanswers[$subquestionid] = $answerids[$allanswers[$correctanswers[$subquestionid]]]; } // Shuffle the answers $answers = draw_rand_array($answers, count($answers)); // Print formulation $questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions); $image = get_question_image($question); // Print the input controls foreach ($subquestions as $key => $subquestion) { if ($subquestion->questiontext != '') { // Subquestion text: $a = new stdClass(); $a->text = $this->format_text($subquestion->questiontext, $question->questiontextformat, $cmoptions); // Drop-down list: $menuname = $nameprefix . $subquestion->id; $response = isset($state->responses[$subquestion->id]) ? $state->responses[$subquestion->id] : '0'; $a->class = ' '; $a->feedbackimg = ' '; if ($options->readonly and $options->correct_responses) { if (isset($correctanswers[$subquestion->id]) and $correctanswers[$subquestion->id] == $response) { $correctresponse = 1; } else { $correctresponse = 0; } if ($options->feedback && $response) { $a->class = question_get_feedback_class($correctresponse); $a->feedbackimg = question_get_feedback_image($correctresponse); } } $a->control = choose_from_menu($answers, $menuname, $response, 'choose', '', 0, true, $options->readonly); // Neither the editing interface or the database allow to provide // fedback for this question type. // However (as was pointed out in bug bug 3294) the randomsamatch // type which reuses this method can have feedback defined for // the wrapped shortanswer questions. //if ($options->feedback // && !empty($subquestion->options->answers[$responses[$key]]->feedback)) { // print_comment($subquestion->options->answers[$responses[$key]]->feedback); //} $anss[] = $a; } } include "{$CFG->dirroot}/question/type/match/display.html"; }
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG; $answers =& $question->options->answers; $correctanswers = $this->get_correct_responses($question, $state); $readonly = empty($options->readonly) ? '' : 'disabled="disabled"'; $formatoptions = new stdClass(); $formatoptions->noclean = true; $formatoptions->para = false; // Print formulation $questiontext = format_text($question->questiontext, $question->questiontextformat, $formatoptions, $cmoptions->course); $image = get_question_image($question); $answerprompt = $question->options->single ? get_string('singleanswer', 'quiz') : get_string('multipleanswers', 'quiz'); // Print each answer in a separate row foreach ($state->options->order as $key => $aid) { $answer =& $answers[$aid]; $checked = ''; $chosen = false; if ($question->options->single) { $type = 'type="radio"'; $name = "name=\"{$question->name_prefix}\""; if (isset($state->responses['']) and $aid == $state->responses['']) { $checked = 'checked="checked"'; $chosen = true; } } else { $type = ' type="checkbox" '; $name = "name=\"{$question->name_prefix}{$aid}\""; if (isset($state->responses[$aid])) { $checked = 'checked="checked"'; $chosen = true; } } $a = new stdClass(); $a->id = $question->name_prefix . $aid; $a->class = ''; $a->feedbackimg = ''; // Print the control $a->control = "<input {$readonly} id=\"{$a->id}\" {$name} {$checked} {$type} value=\"{$aid}\" />"; if ($options->correct_responses && $answer->fraction > 0) { $a->class = question_get_feedback_class(1); } if ($options->feedback && $chosen || $options->correct_responses) { if ($type == ' type="checkbox" ') { $a->feedbackimg = question_get_feedback_image($answer->fraction > 0 ? 1 : 0, $chosen && $options->feedback); } else { $a->feedbackimg = question_get_feedback_image($answer->fraction, $chosen && $options->feedback); } } // Print the answer text $a->text = $this->number_in_style($key, $question->options->answernumbering) . format_text($answer->answer, FORMAT_MOODLE, $formatoptions, $cmoptions->course); // Print feedback if feedback is on if (($options->feedback || $options->correct_responses) && $checked) { $a->feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course); } else { $a->feedback = ''; } $anss[] = clone $a; } $feedback = ''; if ($options->feedback) { if ($state->raw_grade >= $question->maxgrade / 1.01) { $feedback = $question->options->correctfeedback; } else { if ($state->raw_grade > 0) { $feedback = $question->options->partiallycorrectfeedback; } else { $feedback = $question->options->incorrectfeedback; } } $feedback = format_text($feedback, $question->questiontextformat, $formatoptions, $cmoptions->course); } include "{$CFG->dirroot}/question/type/multichoice/display.html"; }
/** * @param string $colname the name of the column. * @param object $attempt the row of data - see the SQL in display() in * mod/quiz/report/overview/report.php to see what fields are present, * and what they are called. * @return string the contents of the cell. */ function other_cols($colname, $attempt) { if (preg_match('/^qsgrade([0-9]+)$/', $colname, $matches)) { $questionid = $matches[1]; $question = $this->questions[$questionid]; if (isset($this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid])) { $stateforqinattempt = $this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid]; } else { $stateforqinattempt = false; } if ($stateforqinattempt && question_state_is_graded($stateforqinattempt)) { $grade = quiz_rescale_grade($stateforqinattempt->grade, $this->quiz, 'question'); if (!$this->is_downloading()) { if (isset($this->regradedqs[$attempt->attemptuniqueid][$questionid])) { $gradefromdb = $grade; $newgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->newgrade, $this->quiz, 'question'); $oldgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->oldgrade, $this->quiz, 'question'); $grade = '<del>' . $oldgrade . '</del><br />' . $newgrade; } $linktopopup = link_to_popup_window('/mod/quiz/reviewquestion.php?attempt=' . $attempt->attempt . '&question=' . $question->id, 'reviewquestion', $grade, 450, 650, get_string('reviewresponse', 'quiz'), 'none', true); if ($this->questions[$questionid]->maxgrade != 0) { $fractionofgrade = $stateforqinattempt->grade / $this->questions[$questionid]->maxgrade; $qclass = question_get_feedback_class($fractionofgrade); $feedbackimg = question_get_feedback_image($fractionofgrade); $questionclass = "que"; return "<span class=\"{$questionclass}\"><span class=\"{$qclass}\">" . $linktopopup . "</span></span>{$feedbackimg}"; } else { return $linktopopup; } } else { return $grade; } } else { return '--'; } } else { return NULL; } }
/** * Prints the main content of the question including any interactions * * This function prints the main content of the question including the * interactions for the question in the state given. The last graded responses * are printed or indicated and the current responses are selected or filled in. * Any names (eg. for any form elements) are prefixed with $question->name_prefix. * This method is called from the print_question method. The algebra question type * changes this from the default method to include a "display formula" button which * interprets the formula in the response box and gives a graphical representation * for the student to check. * * @param object $question The question to be rendered. Question type * specific information is included. The name * prefix for any named elements is in ->name_prefix. * @param object $state The state to render the question in. The grading * information is in ->grade, ->raw_grade and * ->penalty. The current responses are in * ->responses. This is an associative array (or the * empty string or null in the case of no responses * submitted). The last graded state is in * ->last_graded (hence the most recently graded * responses are in ->last_graded->responses). The * question type specific information is also * included. * The state is passed by reference because some adaptive * questions may want to update it during rendering * @param object $cmoptions * @param object $options An object describing the rendering options. */ function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG; /// This implementation is copied from short answer $readonly = empty($options->readonly) ? '' : 'readonly="readonly"'; $formatoptions = new stdClass(); $formatoptions->noclean = true; $formatoptions->para = false; $nameprefix = $question->name_prefix; // Print the text associated with the question $questiontext = format_text($question->questiontext, $question->questiontextformat, $formatoptions, $cmoptions->course); // Get the image, if any, associated with the question $image = get_question_image($question); // Sets the value of the input box for the question to the current student // response if there is one if (isset($state->responses['']) && $state->responses[''] != '') { $value = ' value="' . s($state->responses[''], true) . '" '; } else { $value = ' value="" '; } // Defines the name of the input box where the student enters a response for the question $inputname = ' name="' . $nameprefix . '" '; $feedback = ''; $class = ''; $feedbackimg = ''; if ($options->feedback) { $class = question_get_feedback_class(0); $feedbackimg = question_get_feedback_image(0); // Parse the response here since this saves time parsing once for each comparison $response = $this->parse_expression($state, $question); // Loop over all the answers to the question foreach ($question->options->answers as $answer) { // Compare the response against the current answer if ($this->test_response($question, $response, $answer)) { // Answer was correct or partially correct. $class = question_get_feedback_class($answer->fraction); $feedbackimg = question_get_feedback_image($answer->fraction); if ($answer->feedback) { $feedback = format_text($answer->feedback, true, $formatoptions, $cmoptions->course); } break; } } } // The name for the iframe which displays the rendered formula $iframename = ' name="' . $nameprefix . 'if"'; // Name of the javascript function which causes the entered formula to be rendered $df_name = $nameprefix . '_display'; // Create an array of variable names to use when displaying the function entered $varnames = array(); if ($question and isset($question->options->variables)) { foreach ($question->options->variables as $var) { $varnames[] = $var->name; } } $varnames = implode(',', $varnames); // Javascript function which the button uses to display the rendering // This function sents the source of the iframe to the 'displayformula.php' script giving // it an argument of the formula entered by the student. $displayfunction = 'function ' . $df_name . "() {\n" . ' var text="vars=' . $varnames . '&expr="+escape(document.getElementsByName("' . $nameprefix . '")[0].value);' . "\n" . " if(text.length != 0) {\n" . ' document.getElementsByName("' . $nameprefix . 'if")[0].src="' . $CFG->wwwroot . '/question/type/algebra/displayformula.php?"+' . 'text.replace(/\\+/g,"%2b")' . "\n" . " }\n" . " }\n"; // Include the HTML/php file which uses the variables above to render the question include "{$CFG->dirroot}/question/type/algebra/display.html"; }
/** * Performs response processing and grading * The function was redefined for handling correctly the two parts * number and unit of numerical or calculated questions * The code handles also the case when there no unit defined by the user or * when used in a multianswer (Cloze) question. * This function performs response processing and grading and updates * the state accordingly. * @return boolean Indicates success or failure. * @param object $question The question to be graded. Question type * specific information is included. * @param object $state The state of the question to grade. The current * responses are in ->responses. The last graded state * is in ->last_graded (hence the most recently graded * responses are in ->last_graded->responses). The * question type specific information is also * included. The ->raw_grade and ->penalty fields * must be updated. The method is able to * close the question session (preventing any further * attempts at this question) by setting * $state->event to QUESTION_EVENTCLOSEANDGRADE * @param object $cmoptions */ function grade_responses(&$question, &$state, $cmoptions) { if (isset($state->responses['']) && $state->responses[''] != '' && !isset($state->responses['answer'])) { $this->split_old_answer($state->responses[''], $question->options->units, $state->responses['answer'], $state->responses['unit']); } $state->raw_grade = 0; $valid_numerical_unit = false; $break = 0; $unittested = ''; $hasunits = 0; $answerasterisk = false; $break = 0; foreach ($question->options->answers as $answer) { if ($this->test_response($question, $state, $answer)) { // Answer was correct or partially correct. $state->raw_grade = $answer->fraction; if ($question->options->unitgradingtype == 0 || $answer->answer === '*') { // if * then unit has the $answer->fraction value // if $question->options->unitgradingtype == 0 everything has been checked // if $question->options->showunits == NUMERICALQUESTIONUNITTEXTINPUTDISPLAY // then number - unit combination has been used to test response // so the unit should have same color } else { // so we need to apply unit grading i.e. to check if the number-unit combination // was the rigth one $valid_numerical_unit = false; $class = question_get_feedback_class($answer->fraction); $feedbackimg = question_get_feedback_image($answer->fraction); if (isset($state->responses['unit']) && $state->responses['unit'] != '') { foreach ($question->options->units as $key => $unit) { if ($unit->unit == $state->responses['unit']) { $response = $this->apply_unit($state->responses['answer'] . $state->responses['unit'], array($question->options->units[$key])); if ($response !== false) { $this->get_tolerance_interval($answer); if ($answer->min <= $response && $response <= $answer->max) { $valid_numerical_unit = true; } } break; } } } } break; } } // apply unit penalty $raw_unitpenalty = 0; if ($question->options->unitgradingtype != 0 && !empty($question->options->unitpenalty) && $valid_numerical_unit != true) { if ($question->options->unitgradingtype == 1) { $raw_unitpenalty = $question->options->unitpenalty * $state->raw_grade; } else { $raw_unitpenalty = $question->options->unitpenalty; } $state->raw_grade -= $raw_unitpenalty; } // Make sure we don't assign negative or too high marks. $state->raw_grade = min(max((double) $state->raw_grade, 0.0), 1.0) * $question->maxgrade; // Update the penalty. $state->penalty = $question->penalty * $question->maxgrade; // mark the state as graded $state->event = $state->event == QUESTION_EVENTCLOSE ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE; return true; }
/** * Returns the html for question feedback image. * @param float $fraction value representing the correctness of the user's * response to a question. * @param boolean $selected whether or not the answer is the one that the * user picked. * @return string */ function question_get_feedback_image($fraction, $selected = true) { global $CFG; static $icons = array('correct' => 'tick_green', 'partiallycorrect' => 'tick_amber', 'incorrect' => 'cross_red'); if ($selected) { $size = 'big'; } else { $size = 'small'; } $class = question_get_feedback_class($fraction); return '<img src="' . $CFG->pixpath . '/i/' . $icons[$class] . '_' . $size . '.gif" ' . 'alt="' . get_string($class, 'quiz') . '" class="icon" />'; }
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG, $USER; $subquestions = $state->options->subquestions; $correctanswers = $this->get_correct_responses($question, $state); $nameprefix = $question->name_prefix; $answers = array(); $allanswers = array(); $answerids = array(); $responses =& $state->responses; // Check browser version to see if YUI is supported properly. // This is similar to ajaxenabled() from lib/ajax/ajaxlib.php, // except it doesn't check the site-wide AJAX settings. $fallbackonly = false; $ie = check_browser_version('MSIE', 6.0); $ff = check_browser_version('Gecko', 20051106); $op = check_browser_version('Opera', 9.0); $sa = check_browser_version('Safari', 412); if (!$ie && !$ff && !$op && !$sa or !empty($USER->screenreader)) { $fallbackonly = true; } // Prepare a list of answers, removing duplicates. foreach ($subquestions as $subquestion) { foreach ($subquestion->options->answers as $ans) { $allanswers[$ans->id] = $this->format_text($ans->answer, $question->questiontextformat, $cmoptions); if (!in_array($allanswers[$ans->id], $answers)) { $ans->answer = $allanswers[$ans->id]; $answers[$ans->id] = $ans->answer; $answerids[$ans->answer] = $ans->id; } } } // Fix up the ids of any responses that point the the eliminated duplicates. foreach ($responses as $subquestionid => $ignored) { if ($responses[$subquestionid]) { $responses[$subquestionid] = $answerids[$allanswers[$responses[$subquestionid]]]; } } foreach ($correctanswers as $subquestionid => $ignored) { $correctanswers[$subquestionid] = $answerids[$allanswers[$correctanswers[$subquestionid]]]; } // Shuffle the answers $answers = draw_rand_array($answers, count($answers)); // Print formulation $questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions); $image = get_question_image($question); // Javascript Array initialization of list ids $elems = array(); foreach ($subquestions as $subquestion) { if ($subquestion->questiontext) { $elems[] = '"' . $subquestion->id . '"'; } } $questionsarraystring = 'Array(' . implode(',', $elems) . ')'; $elems = array(); foreach ($answers as $key => $answer) { $elems[] = '"' . $key . '"'; } $answersarraystring = 'Array(' . implode(',', $elems) . ')'; $elems = array(); foreach ($subquestions as $subquestion) { if ($subquestion->questiontext) { $elems[] = '"' . $responses[$subquestion->id] . '"'; } } $responsesarraystring = 'Array(' . implode(',', $elems) . ')'; // Print the input controls foreach ($subquestions as $key => $subquestion) { if ($subquestion->questiontext) { // Subquestion text: $a = new stdClass(); $a->id = $subquestion->id; $a->text = $this->format_text($subquestion->questiontext, $question->questiontextformat, $cmoptions); // Drop-down list: $menuname = $nameprefix . $subquestion->id; $response = isset($state->responses[$subquestion->id]) ? $state->responses[$subquestion->id] : '0'; $a->class = ' '; $a->feedbackimg = ' '; if ($options->readonly and $options->correct_responses) { if (isset($correctanswers[$subquestion->id]) and $correctanswers[$subquestion->id] == $response) { $correctresponse = 1; } else { $correctresponse = 0; } if ($options->feedback && $response) { $a->class = question_get_feedback_class($correctresponse); $a->feedbackimg = question_get_feedback_image($correctresponse); } } if (preg_match('/<img/', $a->feedbackimg)) { preg_match('/src="([^"]*)"/', $a->feedbackimg, $matches); $a->feedbackimgsrc = $matches[1]; preg_match('/alt="([^"]*)"/', $a->feedbackimg, $matches); $a->feedbackimgalt = $matches[1]; preg_match('/class="([^"]*)"/', $a->feedbackimg, $matches); $a->feedbackimgclass = $matches[1]; } $a->control = choose_from_menu($answers, $menuname, $response, 'choose', '', 0, true, $options->readonly); // Neither the editing interface or the database allow to provide // fedback for this question type. // However (as was pointed out in bug bug 3294) the randomsamatch // type which reuses this method can have feedback defined for // the wrapped shortanswer questions. //if ($options->feedback // && !empty($subquestion->options->answers[$responses[$key]]->feedback)) { // print_comment($subquestion->options->answers[$responses[$key]]->feedback); //} $anss[] = $a; } } $dragstring = get_string('draganswerhere', 'qtype_ddmatch'); include "{$CFG->dirroot}/question/type/ddmatch/display.html"; }
function response_summary($question, $state, $length = 80) { $responses = $this->get_actual_response($question, $state); $summaries = ''; foreach ($question->subpart->parts as $idx => $part) { if ($state->subanum == -1 || $state->subanum == $idx) { $c = question_get_feedback_class($state->fractions[$idx]); $summaries .= '<div class="' . $c . '">' . '<i>(' . ($idx + 1) . '.) </i>' . shorten_text($state->responses[$idx], $length) . '</div>'; } } return $summaries; }
/** * Return a summary of the current state of a question in this attempt. You must previously * have called load_question_states to load the state data about this question. * * @param integer $questionid question id of a question that belongs to this quiz. * @return string a brief string (that could be used as a CSS class name, for example) * that describes the current state of a question in this attempt. Possible results are: * open|saved|closed|correct|partiallycorrect|incorrect. */ public function get_question_status($questionid) { $state = $this->states[$questionid]; switch ($state->event) { case QUESTION_EVENTOPEN: return 'open'; case QUESTION_EVENTSAVE: case QUESTION_EVENTGRADE: case QUESTION_EVENTSUBMIT: return 'answered'; case QUESTION_EVENTCLOSEANDGRADE: case QUESTION_EVENTCLOSE: case QUESTION_EVENTMANUALGRADE: $options = $this->get_render_options($questionid); if ($options->scores && $this->questions[$questionid]->maxgrade > 0) { return question_get_feedback_class($state->last_graded->raw_grade / $this->questions[$questionid]->maxgrade); } else { return 'closed'; } default: $a = new stdClass(); $a->event = $state->event; $a->questionid = $questionid; $a->attemptid = $this->attempt->id; throw new moodle_quiz_exception($this, 'errorunexpectedevent', $a); } }
function other_cols($colname, $attempt) { global $QTYPES, $OUTPUT; static $states = array(); if (preg_match('/^qsanswer([0-9]+)$/', $colname, $matches)) { if ($attempt->uniqueid == 0) { return '-'; } $questionid = $matches[1]; if (isset($this->gradedstatesbyattempt[$attempt->uniqueid][$questionid])) { $stateforqinattempt = $this->gradedstatesbyattempt[$attempt->uniqueid][$questionid]; } else { return '-'; } $question = $this->questions[$questionid]; restore_question_state($question, $stateforqinattempt); if (!$this->is_downloading() || $this->is_downloading() == 'xhtml') { $formathtml = true; } else { $formathtml = false; } $summary = $QTYPES[$question->qtype]->response_summary($question, $stateforqinattempt, QUIZ_REPORT_RESPONSES_MAX_LEN_TO_DISPLAY, $formathtml); if (!$this->is_downloading()) { if ($summary) { $link = html_link::make("/mod/quiz/reviewquestion.php?attempt={$attempt->attempt}&question={$question->id}", $summary); $link->add_action(new popup_action('click', $link->url, 'reviewquestion', array('height' => 450, 'width' => 650))); $link->title = $question->formattedname; $summary = $OUTPUT->link($link); if (question_state_is_graded($stateforqinattempt) && $question->maxgrade > 0) { $grade = $stateforqinattempt->grade / $question->maxgrade; $qclass = question_get_feedback_class($grade); $feedbackimg = question_get_feedback_image($grade); $questionclass = "que"; return "<span class=\"{$questionclass}\"><span class=\"{$qclass}\">" . $summary . "</span></span>{$feedbackimg}"; } else { return $summary; } } else { return ''; } } else { return $summary; } } else { return NULL; } }
function other_cols($colname, $attempt) { global $QTYPES; static $states = array(); if (preg_match('/^qsanswer([0-9]+)$/', $colname, $matches)) { if ($attempt->uniqueid == 0) { return '-'; } $questionid = $matches[1]; if (isset($this->gradedstatesbyattempt[$attempt->uniqueid][$questionid])) { $stateforqinattempt = $this->gradedstatesbyattempt[$attempt->uniqueid][$questionid]; } else { return '-'; } $question = $this->questions[$questionid]; restore_question_state($question, $stateforqinattempt); if (!$this->is_downloading() || $this->is_downloading() == 'xhtml') { $formathtml = true; } else { $formathtml = false; } $summary = $QTYPES[$question->qtype]->response_summary($question, $stateforqinattempt, QUIZ_REPORT_RESPONSES_MAX_LEN_TO_DISPLAY, $formathtml); if (!$this->is_downloading()) { if ($summary) { $summary = link_to_popup_window('/mod/quiz/reviewquestion.php?attempt=' . $attempt->attempt . '&question=' . $question->id, 'reviewquestion', $summary, 450, 650, get_string('reviewresponse', 'quiz'), 'none', true); if (question_state_is_graded($stateforqinattempt) && $question->maxgrade > 0) { $grade = $stateforqinattempt->grade / $question->maxgrade; $qclass = question_get_feedback_class($grade); $feedbackimg = question_get_feedback_image($grade); $questionclass = "que"; return "<span class=\"{$questionclass}\"><span class=\"{$qclass}\">" . $summary . "</span></span>{$feedbackimg}"; } else { return $summary; } } else { return ''; } } else { return $summary; } } else { return NULL; } }