|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00027 defined('MOODLE_INTERNAL') || die(); 00028 00030 define("LESSON_PAGE_MULTICHOICE", "3"); 00031 00032 class lesson_page_type_multichoice extends lesson_page { 00033 00034 protected $type = lesson_page::TYPE_QUESTION; 00035 protected $typeidstring = 'multichoice'; 00036 protected $typeid = LESSON_PAGE_MULTICHOICE; 00037 protected $string = null; 00038 00039 public function get_typeid() { 00040 return $this->typeid; 00041 } 00042 public function get_typestring() { 00043 if ($this->string===null) { 00044 $this->string = get_string($this->typeidstring, 'lesson'); 00045 } 00046 return $this->string; 00047 } 00048 public function get_idstring() { 00049 return $this->typeidstring; 00050 } 00051 00057 public function get_jumps() { 00058 global $DB; 00059 $jumps = array(); 00060 if ($answers = $this->get_answers()) { 00061 foreach ($answers as $answer) { 00062 if ($answer->answer === '') { 00063 // show only jumps for real branches (==have description) 00064 continue; 00065 } 00066 $jumps[] = $this->get_jump_name($answer->jumpto); 00067 } 00068 } else { 00069 // We get here is the lesson was created on a Moodle 1.9 site and 00070 // the lesson contains question pages without any answers. 00071 $jumps[] = $this->get_jump_name($this->properties->nextpageid); 00072 } 00073 return $jumps; 00074 } 00075 00076 public function get_used_answers() { 00077 $answers = $this->get_answers(); 00078 foreach ($answers as $key=>$answer) { 00079 if ($answer->answer === '') { 00080 unset($answers[$key]); 00081 } 00082 } 00083 return $answers; 00084 } 00085 00086 public function display($renderer, $attempt) { 00087 global $CFG, $PAGE; 00088 $answers = $this->get_used_answers(); 00089 shuffle($answers); 00090 $action = $CFG->wwwroot.'/mod/lesson/continue.php'; 00091 $params = array('answers'=>$answers, 'lessonid'=>$this->lesson->id, 'contents'=>$this->get_contents(), 'attempt'=>$attempt); 00092 if ($this->properties->qoption) { 00093 $mform = new lesson_display_answer_form_multichoice_multianswer($action, $params); 00094 } else { 00095 $mform = new lesson_display_answer_form_multichoice_singleanswer($action, $params); 00096 } 00097 $data = new stdClass; 00098 $data->id = $PAGE->cm->id; 00099 $data->pageid = $this->properties->id; 00100 $mform->set_data($data); 00101 return $mform->display(); 00102 } 00103 00104 public function check_answer() { 00105 global $DB, $CFG, $PAGE; 00106 $result = parent::check_answer(); 00107 00108 $formattextdefoptions = new stdClass(); 00109 $formattextdefoptions->noclean = true; 00110 $formattextdefoptions->para = false; 00111 00112 $answers = $this->get_used_answers(); 00113 shuffle($answers); 00114 $action = $CFG->wwwroot.'/mod/lesson/continue.php'; 00115 $params = array('answers'=>$answers, 'lessonid'=>$this->lesson->id, 'contents'=>$this->get_contents()); 00116 if ($this->properties->qoption) { 00117 $mform = new lesson_display_answer_form_multichoice_multianswer($action, $params); 00118 } else { 00119 $mform = new lesson_display_answer_form_multichoice_singleanswer($action, $params); 00120 } 00121 $data = $mform->get_data(); 00122 require_sesskey(); 00123 00124 if (!$data) { 00125 redirect(new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id, 'pageid'=>$this->properties->id))); 00126 } 00127 00128 if ($this->properties->qoption) { 00129 // MULTIANSWER allowed, user's answer is an array 00130 00131 if (empty($data->answer) || !is_array($data->answer)) { 00132 $result->noanswer = true; 00133 return $result; 00134 } 00135 00136 $studentanswers = array(); 00137 foreach ($data->answer as $key=>$value) { 00138 $studentanswers[] = (int)$key; 00139 } 00140 00141 // get what the user answered 00142 $result->userresponse = implode(",", $studentanswers); 00143 00144 // get the answers in a set order, the id order 00145 $answers = $this->get_used_answers(); 00146 $ncorrect = 0; 00147 $nhits = 0; 00148 $correctresponse = ''; 00149 $wrongresponse = ''; 00150 $correctanswerid = 0; 00151 $wronganswerid = 0; 00152 // store student's answers for displaying on feedback page 00153 $result->studentanswer = ''; 00154 foreach ($answers as $answer) { 00155 foreach ($studentanswers as $answerid) { 00156 if ($answerid == $answer->id) { 00157 $result->studentanswer .= '<br />'.format_text($answer->answer, $answer->answerformat, $formattextdefoptions); 00158 } 00159 } 00160 } 00161 $correctpageid = null; 00162 $wrongpageid = null; 00163 // this is for custom scores. If score on answer is positive, it is correct 00164 if ($this->lesson->custom) { 00165 $ncorrect = 0; 00166 $nhits = 0; 00167 foreach ($answers as $answer) { 00168 if ($answer->score > 0) { 00169 $ncorrect++; 00170 00171 foreach ($studentanswers as $answerid) { 00172 if ($answerid == $answer->id) { 00173 $nhits++; 00174 } 00175 } 00176 // save the first jumpto page id, may be needed!... 00177 if (!isset($correctpageid)) { 00178 // leave in its "raw" state - will converted into a proper page id later 00179 $correctpageid = $answer->jumpto; 00180 } 00181 // save the answer id for scoring 00182 if ($correctanswerid == 0) { 00183 $correctanswerid = $answer->id; 00184 } 00185 // ...also save any response from the correct answers... 00186 if (trim(strip_tags($answer->response))) { 00187 $correctresponse = format_text($answer->response, $answer->responseformat, $formattextdefoptions); 00188 } 00189 } else { 00190 // save the first jumpto page id, may be needed!... 00191 if (!isset($wrongpageid)) { 00192 // leave in its "raw" state - will converted into a proper page id later 00193 $wrongpageid = $answer->jumpto; 00194 } 00195 // save the answer id for scoring 00196 if ($wronganswerid == 0) { 00197 $wronganswerid = $answer->id; 00198 } 00199 // ...and from the incorrect ones, don't know which to use at this stage 00200 if (trim(strip_tags($answer->response))) { 00201 $wrongresponse = format_text($answer->response, $answer->responseformat, $formattextdefoptions); 00202 } 00203 } 00204 } 00205 } else { 00206 foreach ($answers as $answer) { 00207 if ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto)) { 00208 $ncorrect++; 00209 foreach ($studentanswers as $answerid) { 00210 if ($answerid == $answer->id) { 00211 $nhits++; 00212 } 00213 } 00214 // save the first jumpto page id, may be needed!... 00215 if (!isset($correctpageid)) { 00216 // leave in its "raw" state - will converted into a proper page id later 00217 $correctpageid = $answer->jumpto; 00218 } 00219 // save the answer id for scoring 00220 if ($correctanswerid == 0) { 00221 $correctanswerid = $answer->id; 00222 } 00223 // ...also save any response from the correct answers... 00224 if (trim(strip_tags($answer->response))) { 00225 $correctresponse = format_text($answer->response, $answer->responseformat, $formattextdefoptions); 00226 } 00227 } else { 00228 // save the first jumpto page id, may be needed!... 00229 if (!isset($wrongpageid)) { 00230 // leave in its "raw" state - will converted into a proper page id later 00231 $wrongpageid = $answer->jumpto; 00232 } 00233 // save the answer id for scoring 00234 if ($wronganswerid == 0) { 00235 $wronganswerid = $answer->id; 00236 } 00237 // ...and from the incorrect ones, don't know which to use at this stage 00238 if (trim(strip_tags($answer->response))) { 00239 $wrongresponse = format_text($answer->response, $answer->responseformat, $formattextdefoptions); 00240 } 00241 } 00242 } 00243 } 00244 if ((count($studentanswers) == $ncorrect) and ($nhits == $ncorrect)) { 00245 $result->correctanswer = true; 00246 $result->response = $correctresponse; 00247 $result->newpageid = $correctpageid; 00248 $result->answerid = $correctanswerid; 00249 } else { 00250 $result->response = $wrongresponse; 00251 $result->newpageid = $wrongpageid; 00252 $result->answerid = $wronganswerid; 00253 } 00254 } else { 00255 // only one answer allowed 00256 if (empty($data->answerid) && !is_int($data->answerid)) { 00257 $result->noanswer = true; 00258 return $result; 00259 } 00260 $result->answerid = $data->answerid; 00261 if (!$answer = $DB->get_record("lesson_answers", array("id" => $result->answerid))) { 00262 print_error("Continue: answer record not found"); 00263 } 00264 if ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto)) { 00265 $result->correctanswer = true; 00266 } 00267 if ($this->lesson->custom) { 00268 if ($answer->score > 0) { 00269 $result->correctanswer = true; 00270 } else { 00271 $result->correctanswer = false; 00272 } 00273 } 00274 $result->newpageid = $answer->jumpto; 00275 $result->response = format_text($answer->response, $answer->responseformat, $formattextdefoptions); 00276 $result->userresponse = format_text($answer->answer, $answer->answerformat, $formattextdefoptions); 00277 $result->studentanswer = $result->userresponse; 00278 } 00279 return $result; 00280 } 00281 00282 public function option_description_string() { 00283 if ($this->properties->qoption) { 00284 return " - ".get_string("multianswer", "lesson"); 00285 } 00286 return parent::option_description_string(); 00287 } 00288 00289 public function display_answers(html_table $table) { 00290 $answers = $this->get_used_answers(); 00291 $options = new stdClass; 00292 $options->noclean = true; 00293 $options->para = false; 00294 $i = 1; 00295 foreach ($answers as $answer) { 00296 $cells = array(); 00297 if ($this->lesson->custom && $answer->score > 0) { 00298 // if the score is > 0, then it is correct 00299 $cells[] = '<span class="labelcorrect">'.get_string("answer", "lesson")." $i</span>: \n"; 00300 } else if ($this->lesson->custom) { 00301 $cells[] = '<span class="label">'.get_string("answer", "lesson")." $i</span>: \n"; 00302 } else if ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto)) { 00303 // underline correct answers 00304 $cells[] = '<span class="correct">'.get_string("answer", "lesson")." $i</span>: \n"; 00305 } else { 00306 $cells[] = '<span class="labelcorrect">'.get_string("answer", "lesson")." $i</span>: \n"; 00307 } 00308 $cells[] = format_text($answer->answer, $answer->answerformat, $options); 00309 $table->data[] = new html_table_row($cells); 00310 00311 $cells = array(); 00312 $cells[] = "<span class=\"label\">".get_string("response", "lesson")." $i</span>"; 00313 $cells[] = format_text($answer->response, $answer->responseformat, $options); 00314 $table->data[] = new html_table_row($cells); 00315 00316 $cells = array(); 00317 $cells[] = "<span class=\"label\">".get_string("score", "lesson").'</span>'; 00318 $cells[] = $answer->score; 00319 $table->data[] = new html_table_row($cells); 00320 00321 $cells = array(); 00322 $cells[] = "<span class=\"label\">".get_string("jump", "lesson").'</span>'; 00323 $cells[] = $this->get_jump_name($answer->jumpto); 00324 $table->data[] = new html_table_row($cells); 00325 if ($i === 1){ 00326 $table->data[count($table->data)-1]->cells[0]->style = 'width:20%;'; 00327 } 00328 $i++; 00329 } 00330 return $table; 00331 } 00332 public function stats(array &$pagestats, $tries) { 00333 if(count($tries) > $this->lesson->maxattempts) { // if there are more tries than the max that is allowed, grab the last "legal" attempt 00334 $temp = $tries[$this->lesson->maxattempts - 1]; 00335 } else { 00336 // else, user attempted the question less than the max, so grab the last one 00337 $temp = end($tries); 00338 } 00339 if ($this->properties->qoption) { 00340 $userresponse = explode(",", $temp->useranswer); 00341 foreach ($userresponse as $response) { 00342 if (isset($pagestats[$temp->pageid][$response])) { 00343 $pagestats[$temp->pageid][$response]++; 00344 } else { 00345 $pagestats[$temp->pageid][$response] = 1; 00346 } 00347 } 00348 } else { 00349 if (isset($pagestats[$temp->pageid][$temp->answerid])) { 00350 $pagestats[$temp->pageid][$temp->answerid]++; 00351 } else { 00352 $pagestats[$temp->pageid][$temp->answerid] = 1; 00353 } 00354 } 00355 if (isset($pagestats[$temp->pageid]["total"])) { 00356 $pagestats[$temp->pageid]["total"]++; 00357 } else { 00358 $pagestats[$temp->pageid]["total"] = 1; 00359 } 00360 return true; 00361 } 00362 00363 public function report_answers($answerpage, $answerdata, $useranswer, $pagestats, &$i, &$n) { 00364 $answers = $this->get_used_answers(); 00365 $formattextdefoptions = new stdClass; 00366 $formattextdefoptions->para = false; //I'll use it widely in this page 00367 00368 foreach ($answers as $answer) { 00369 if ($this->properties->qoption) { 00370 if ($useranswer == NULL) { 00371 $userresponse = array(); 00372 } else { 00373 $userresponse = explode(",", $useranswer->useranswer); 00374 } 00375 if (in_array($answer->id, $userresponse)) { 00376 // make checked 00377 $data = "<input readonly=\"readonly\" disabled=\"disabled\" name=\"answer[$i]\" checked=\"checked\" type=\"checkbox\" value=\"1\" />"; 00378 if (!isset($answerdata->response)) { 00379 if ($answer->response == NULL) { 00380 if ($useranswer->correct) { 00381 $answerdata->response = get_string("thatsthecorrectanswer", "lesson"); 00382 } else { 00383 $answerdata->response = get_string("thatsthewronganswer", "lesson"); 00384 } 00385 } else { 00386 $answerdata->response = $answer->response; 00387 } 00388 } 00389 if (!isset($answerdata->score)) { 00390 if ($this->lesson->custom) { 00391 $answerdata->score = get_string("pointsearned", "lesson").": ".$answer->score; 00392 } elseif ($useranswer->correct) { 00393 $answerdata->score = get_string("receivedcredit", "lesson"); 00394 } else { 00395 $answerdata->score = get_string("didnotreceivecredit", "lesson"); 00396 } 00397 } 00398 } else { 00399 // unchecked 00400 $data = "<input type=\"checkbox\" readonly=\"readonly\" name=\"answer[$i]\" value=\"0\" disabled=\"disabled\" />"; 00401 } 00402 if (($answer->score > 0 && $this->lesson->custom) || ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto) && !$this->lesson->custom)) { 00403 $data = "<div class=highlight>".$data.' '.format_text($answer->answer,$answer->answerformat,$formattextdefoptions)."</div>"; 00404 } else { 00405 $data .= format_text($answer->answer,$answer->answerformat,$formattextdefoptions); 00406 } 00407 } else { 00408 if ($useranswer != NULL and $answer->id == $useranswer->answerid) { 00409 // make checked 00410 $data = "<input readonly=\"readonly\" disabled=\"disabled\" name=\"answer[$i]\" checked=\"checked\" type=\"checkbox\" value=\"1\" />"; 00411 if ($answer->response == NULL) { 00412 if ($useranswer->correct) { 00413 $answerdata->response = get_string("thatsthecorrectanswer", "lesson"); 00414 } else { 00415 $answerdata->response = get_string("thatsthewronganswer", "lesson"); 00416 } 00417 } else { 00418 $answerdata->response = $answer->response; 00419 } 00420 if ($this->lesson->custom) { 00421 $answerdata->score = get_string("pointsearned", "lesson").": ".$answer->score; 00422 } elseif ($useranswer->correct) { 00423 $answerdata->score = get_string("receivedcredit", "lesson"); 00424 } else { 00425 $answerdata->score = get_string("didnotreceivecredit", "lesson"); 00426 } 00427 } else { 00428 // unchecked 00429 $data = "<input type=\"checkbox\" readonly=\"readonly\" name=\"answer[$i]\" value=\"0\" disabled=\"disabled\" />"; 00430 } 00431 if (($answer->score > 0 && $this->lesson->custom) || ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto) && !$this->lesson->custom)) { 00432 $data = "<div class=\"highlight\">".$data.' '.format_text($answer->answer,FORMAT_MOODLE,$formattextdefoptions)."</div>"; 00433 } else { 00434 $data .= format_text($answer->answer,$answer->answerformat,$formattextdefoptions); 00435 } 00436 } 00437 if (isset($pagestats[$this->properties->id][$answer->id])) { 00438 $percent = $pagestats[$this->properties->id][$answer->id] / $pagestats[$this->properties->id]["total"] * 100; 00439 $percent = round($percent, 2); 00440 $percent .= "% ".get_string("checkedthisone", "lesson"); 00441 } else { 00442 $percent = get_string("noonecheckedthis", "lesson"); 00443 } 00444 00445 $answerdata->answers[] = array($data, $percent); 00446 $answerpage->answerdata = $answerdata; 00447 } 00448 return $answerpage; 00449 } 00450 } 00451 00452 00453 class lesson_add_page_form_multichoice extends lesson_add_page_form_base { 00454 00455 public $qtype = 'multichoice'; 00456 public $qtypestring = 'multichoice'; 00457 00458 public function custom_definition() { 00459 00460 $this->_form->addElement('checkbox', 'qoption', get_string('options', 'lesson'), get_string('multianswer', 'lesson')); 00461 $this->_form->setDefault('qoption', 0); 00462 $this->_form->addHelpButton('qoption', 'multianswer', 'lesson'); 00463 00464 for ($i = 0; $i < $this->_customdata['lesson']->maxanswers; $i++) { 00465 $this->_form->addElement('header', 'answertitle'.$i, get_string('answer').' '.($i+1)); 00466 $this->add_answer($i, NULL, ($i<2)); 00467 $this->add_response($i); 00468 $this->add_jumpto($i, NULL, ($i == 0 ? LESSON_NEXTPAGE : LESSON_THISPAGE)); 00469 $this->add_score($i, null, ($i===0)?1:0); 00470 } 00471 } 00472 } 00473 00474 class lesson_display_answer_form_multichoice_singleanswer extends moodleform { 00475 00476 public function definition() { 00477 global $USER, $OUTPUT; 00478 $mform = $this->_form; 00479 $answers = $this->_customdata['answers']; 00480 $lessonid = $this->_customdata['lessonid']; 00481 $contents = $this->_customdata['contents']; 00482 if (array_key_exists('attempt', $this->_customdata)) { 00483 $attempt = $this->_customdata['attempt']; 00484 } else { 00485 $attempt = new stdClass(); 00486 $attempt->answerid = null; 00487 } 00488 00489 $mform->addElement('header', 'pageheader'); 00490 00491 $mform->addElement('html', $OUTPUT->container($contents, 'contents')); 00492 00493 $hasattempt = false; 00494 $disabled = ''; 00495 if (isset($USER->modattempts[$lessonid]) && !empty($USER->modattempts[$lessonid])) { 00496 $hasattempt = true; 00497 $disabled = array('disabled' => 'disabled'); 00498 } 00499 00500 $options = new stdClass; 00501 $options->para = false; 00502 $options->noclean = true; 00503 00504 $mform->addElement('hidden', 'id'); 00505 $mform->setType('id', PARAM_INT); 00506 00507 $mform->addElement('hidden', 'pageid'); 00508 $mform->setType('pageid', PARAM_INT); 00509 00510 $i = 0; 00511 foreach ($answers as $answer) { 00512 $mform->addElement('html', '<div class="answeroption">'); 00513 $mform->addElement('radio','answerid',null,format_text($answer->answer, $answer->answerformat, $options),$answer->id, $disabled); 00514 $mform->setType('answer'.$i, PARAM_INT); 00515 if ($hasattempt && $answer->id == $USER->modattempts[$lessonid]->answerid) { 00516 $mform->setDefault('answerid', $USER->modattempts[$lessonid]->answerid); 00517 } 00518 $mform->addElement('html', '</div>'); 00519 $i++; 00520 } 00521 00522 if ($hasattempt) { 00523 $this->add_action_buttons(null, get_string("nextpage", "lesson")); 00524 } else { 00525 $this->add_action_buttons(null, get_string("submit", "lesson")); 00526 } 00527 } 00528 00529 } 00530 00531 class lesson_display_answer_form_multichoice_multianswer extends moodleform { 00532 00533 public function definition() { 00534 global $USER, $OUTPUT; 00535 $mform = $this->_form; 00536 $answers = $this->_customdata['answers']; 00537 00538 $lessonid = $this->_customdata['lessonid']; 00539 $contents = $this->_customdata['contents']; 00540 00541 $mform->addElement('header', 'pageheader'); 00542 00543 $mform->addElement('html', $OUTPUT->container($contents, 'contents')); 00544 00545 $hasattempt = false; 00546 $disabled = ''; 00547 $useranswers = array(); 00548 if (isset($USER->modattempts[$lessonid]) && !empty($USER->modattempts[$lessonid])) { 00549 $hasattempt = true; 00550 $disabled = array('disabled' => 'disabled'); 00551 $useranswers = explode(',', $USER->modattempts[$lessonid]->useranswer); 00552 } 00553 00554 $options = new stdClass; 00555 $options->para = false; 00556 $options->noclean = true; 00557 00558 $mform->addElement('hidden', 'id'); 00559 $mform->setType('id', PARAM_INT); 00560 00561 $mform->addElement('hidden', 'pageid'); 00562 $mform->setType('pageid', PARAM_INT); 00563 00564 foreach ($answers as $answer) { 00565 $mform->addElement('html', '<div class="answeroption">'); 00566 $answerid = 'answer['.$answer->id.']'; 00567 if ($hasattempt && in_array($answer->id, $useranswers)) { 00568 $answerid = 'answer_'.$answer->id; 00569 $mform->addElement('hidden', 'answer['.$answer->id.']', $answer->answer); 00570 $mform->setType('answer['.$answer->id.']', PARAM_TEXT); 00571 $mform->setDefault($answerid, true); 00572 $mform->setDefault('answer['.$answer->id.']', true); 00573 } 00574 // NOTE: our silly checkbox supports only value '1' - we can not use it like the radiobox above!!!!!! 00575 $mform->addElement('checkbox', $answerid, null, format_text($answer->answer, $answer->answerformat, $options), $disabled); 00576 $mform->setType($answerid, PARAM_INT); 00577 00578 $mform->addElement('html', '</div>'); 00579 } 00580 00581 if ($hasattempt) { 00582 $this->add_action_buttons(null, get_string("nextpage", "lesson")); 00583 } else { 00584 $this->add_action_buttons(null, get_string("submit", "lesson")); 00585 } 00586 } 00587 00588 }