See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
1 <?php 2 3 // This file is part of Moodle - http://moodle.org/ 4 // 5 // Moodle is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Moodle is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 17 18 /** 19 * True/false 20 * 21 * @package mod_lesson 22 * @copyright 2009 Sam Hemelryk 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 **/ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 /** True/False question type */ 29 define("LESSON_PAGE_TRUEFALSE", "2"); 30 31 class lesson_page_type_truefalse extends lesson_page { 32 33 protected $type = lesson_page::TYPE_QUESTION; 34 protected $typeidstring = 'truefalse'; 35 protected $typeid = LESSON_PAGE_TRUEFALSE; 36 protected $string = null; 37 38 public function get_typeid() { 39 return $this->typeid; 40 } 41 public function get_typestring() { 42 if ($this->string===null) { 43 $this->string = get_string($this->typeidstring, 'lesson'); 44 } 45 return $this->string; 46 } 47 public function get_idstring() { 48 return $this->typeidstring; 49 } 50 public function display($renderer, $attempt) { 51 global $USER, $CFG, $PAGE; 52 $answers = $this->get_answers(); 53 foreach ($answers as $key => $answer) { 54 $answers[$key] = parent::rewrite_answers_urls($answer); 55 } 56 shuffle($answers); 57 58 $params = array('answers'=>$answers, 'lessonid'=>$this->lesson->id, 'contents'=>$this->get_contents(), 'attempt'=>$attempt); 59 $mform = new lesson_display_answer_form_truefalse($CFG->wwwroot.'/mod/lesson/continue.php', $params); 60 $data = new stdClass; 61 $data->id = $PAGE->cm->id; 62 $data->pageid = $this->properties->id; 63 $mform->set_data($data); 64 65 // Trigger an event question viewed. 66 $eventparams = array( 67 'context' => context_module::instance($PAGE->cm->id), 68 'objectid' => $this->properties->id, 69 'other' => array( 70 'pagetype' => $this->get_typestring() 71 ) 72 ); 73 74 $event = \mod_lesson\event\question_viewed::create($eventparams); 75 $event->trigger(); 76 return $mform->display(); 77 } 78 public function check_answer() { 79 global $DB, $CFG; 80 $formattextdefoptions = new stdClass(); 81 $formattextdefoptions->noclean = true; 82 $formattextdefoptions->para = false; 83 84 $answers = $this->get_answers(); 85 shuffle($answers); 86 $params = array('answers'=>$answers, 'lessonid'=>$this->lesson->id, 'contents'=>$this->get_contents()); 87 $mform = new lesson_display_answer_form_truefalse($CFG->wwwroot.'/mod/lesson/continue.php', $params); 88 $data = $mform->get_data(); 89 require_sesskey(); 90 91 $result = parent::check_answer(); 92 93 if (empty($data->answerid)) { 94 $result->noanswer = true; 95 return $result; 96 } 97 $result->answerid = $data->answerid; 98 $answer = $DB->get_record("lesson_answers", array("id" => $result->answerid), '*', MUST_EXIST); 99 $answer = parent::rewrite_answers_urls($answer); 100 if ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto)) { 101 $result->correctanswer = true; 102 } 103 if ($this->lesson->custom) { 104 if ($answer->score > 0) { 105 $result->correctanswer = true; 106 } else { 107 $result->correctanswer = false; 108 } 109 } 110 $result->newpageid = $answer->jumpto; 111 $result->response = format_text($answer->response, $answer->responseformat, $formattextdefoptions); 112 $result->studentanswer = $result->userresponse = $answer->answer; 113 return $result; 114 } 115 116 public function display_answers(html_table $table) { 117 $answers = $this->get_answers(); 118 $options = new stdClass(); 119 $options->noclean = true; 120 $options->para = false; 121 $i = 1; 122 foreach ($answers as $answer) { 123 $answer = parent::rewrite_answers_urls($answer); 124 $cells = array(); 125 if ($this->lesson->custom && $answer->score > 0) { 126 // if the score is > 0, then it is correct 127 $cells[] = '<label class="correct">' . get_string('answer', 'lesson') . " {$i}</label>: \n"; 128 } else if ($this->lesson->custom) { 129 $cells[] = '<label>' . get_string('answer', 'lesson') . " {$i}</label>: \n"; 130 } else if ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto)) { 131 // underline correct answers 132 $cells[] = '<span class="correct">' . get_string('answer', 'lesson') . " {$i}</span>: \n"; 133 } else { 134 $cells[] = '<label class="correct">' . get_string('answer', 'lesson') . " {$i}</label>: \n"; 135 } 136 $cells[] = format_text($answer->answer, $answer->answerformat, $options); 137 $table->data[] = new html_table_row($cells); 138 139 $cells = array(); 140 $cells[] = '<label>' . get_string('response', 'lesson') . ' ' . $i . '</label>:'; 141 $cells[] = format_text($answer->response, $answer->responseformat, $options); 142 $table->data[] = new html_table_row($cells); 143 144 $cells = array(); 145 $cells[] = '<label>' . get_string('score', 'lesson') . '</label>:'; 146 $cells[] = $answer->score; 147 $table->data[] = new html_table_row($cells); 148 149 $cells = array(); 150 $cells[] = '<label>' . get_string('jump', 'lesson') . '</label>:'; 151 $cells[] = $this->get_jump_name($answer->jumpto); 152 $table->data[] = new html_table_row($cells); 153 154 if ($i === 1){ 155 $table->data[count($table->data)-1]->cells[0]->style = 'width:20%;'; 156 } 157 158 $i++; 159 } 160 return $table; 161 } 162 163 /** 164 * Updates the page and its answers 165 * 166 * @global moodle_database $DB 167 * @global moodle_page $PAGE 168 * @param stdClass $properties 169 * @return bool 170 */ 171 public function update($properties, $context = null, $maxbytes = null) { 172 global $DB, $PAGE; 173 $answers = $this->get_answers(); 174 $properties->id = $this->properties->id; 175 $properties->lessonid = $this->lesson->id; 176 $properties->timemodified = time(); 177 $properties = file_postupdate_standard_editor($properties, 'contents', array('noclean'=>true, 'maxfiles'=>EDITOR_UNLIMITED_FILES, 'maxbytes'=>$PAGE->course->maxbytes), context_module::instance($PAGE->cm->id), 'mod_lesson', 'page_contents', $properties->id); 178 $DB->update_record("lesson_pages", $properties); 179 180 // Trigger an event: page updated. 181 \mod_lesson\event\page_updated::create_from_lesson_page($this, $context)->trigger(); 182 183 // need to reset offset for correct and wrong responses 184 $this->lesson->maxanswers = 2; 185 for ($i = 0; $i < $this->lesson->maxanswers; $i++) { 186 if (!array_key_exists($i, $this->answers)) { 187 $this->answers[$i] = new stdClass; 188 $this->answers[$i]->lessonid = $this->lesson->id; 189 $this->answers[$i]->pageid = $this->id; 190 $this->answers[$i]->timecreated = $this->timecreated; 191 } 192 193 if (!empty($properties->answer_editor[$i]) && is_array($properties->answer_editor[$i])) { 194 $this->answers[$i]->answer = $properties->answer_editor[$i]['text']; 195 $this->answers[$i]->answerformat = $properties->answer_editor[$i]['format']; 196 } 197 198 if (!empty($properties->response_editor[$i]) && is_array($properties->response_editor[$i])) { 199 $this->answers[$i]->response = $properties->response_editor[$i]['text']; 200 $this->answers[$i]->responseformat = $properties->response_editor[$i]['format']; 201 } 202 203 // we don't need to check for isset here because properties called it's own isset method. 204 if ($this->answers[$i]->answer != '') { 205 if (isset($properties->jumpto[$i])) { 206 $this->answers[$i]->jumpto = $properties->jumpto[$i]; 207 } 208 if ($this->lesson->custom && isset($properties->score[$i])) { 209 $this->answers[$i]->score = $properties->score[$i]; 210 } 211 if (!isset($this->answers[$i]->id)) { 212 $this->answers[$i]->id = $DB->insert_record("lesson_answers", $this->answers[$i]); 213 } else { 214 $DB->update_record("lesson_answers", $this->answers[$i]->properties()); 215 } 216 // Save files in answers and responses. 217 $this->save_answers_files($context, $maxbytes, $this->answers[$i], 218 $properties->answer_editor[$i], $properties->response_editor[$i]); 219 } else if (isset($this->answers[$i]->id)) { 220 $DB->delete_records('lesson_answers', array('id'=>$this->answers[$i]->id)); 221 unset($this->answers[$i]); 222 } 223 } 224 return true; 225 } 226 227 public function stats(array &$pagestats, $tries) { 228 if(count($tries) > $this->lesson->maxattempts) { // if there are more tries than the max that is allowed, grab the last "legal" attempt 229 $temp = $tries[$this->lesson->maxattempts - 1]; 230 } else { 231 // else, user attempted the question less than the max, so grab the last one 232 $temp = end($tries); 233 } 234 if ($this->properties->qoption) { 235 $userresponse = explode(",", $temp->useranswer); 236 foreach ($userresponse as $response) { 237 if (isset($pagestats[$temp->pageid][$response])) { 238 $pagestats[$temp->pageid][$response]++; 239 } else { 240 $pagestats[$temp->pageid][$response] = 1; 241 } 242 } 243 } else { 244 if (isset($pagestats[$temp->pageid][$temp->answerid])) { 245 $pagestats[$temp->pageid][$temp->answerid]++; 246 } else { 247 $pagestats[$temp->pageid][$temp->answerid] = 1; 248 } 249 } 250 if (isset($pagestats[$temp->pageid]["total"])) { 251 $pagestats[$temp->pageid]["total"]++; 252 } else { 253 $pagestats[$temp->pageid]["total"] = 1; 254 } 255 return true; 256 } 257 258 public function report_answers($answerpage, $answerdata, $useranswer, $pagestats, &$i, &$n) { 259 $answers = $this->get_answers(); 260 $formattextdefoptions = new stdClass(); //I'll use it widely in this page 261 $formattextdefoptions->para = false; 262 $formattextdefoptions->noclean = true; 263 $formattextdefoptions->context = $answerpage->context; 264 265 foreach ($answers as $answer) { 266 $answer = parent::rewrite_answers_urls($answer); 267 if ($this->properties->qoption) { 268 if ($useranswer == null) { 269 $userresponse = array(); 270 } else { 271 $userresponse = explode(",", $useranswer->useranswer); 272 } 273 if (in_array($answer->id, $userresponse)) { 274 // make checked 275 $data = "<input readonly=\"readonly\" disabled=\"disabled\" name=\"answer[$i]\" checked=\"checked\" type=\"checkbox\" value=\"1\" />"; 276 if (!isset($answerdata->response)) { 277 if ($answer->response == null) { 278 if ($useranswer->correct) { 279 $answerdata->response = get_string("thatsthecorrectanswer", "lesson"); 280 } else { 281 $answerdata->response = get_string("thatsthewronganswer", "lesson"); 282 } 283 } else { 284 $answerdata->response = format_text($answer->response, $answer->responseformat, $formattextdefoptions); 285 } 286 } 287 if (!isset($answerdata->score)) { 288 if ($this->lesson->custom) { 289 $answerdata->score = get_string("pointsearned", "lesson").": ".$answer->score; 290 } elseif ($useranswer->correct) { 291 $answerdata->score = get_string("receivedcredit", "lesson"); 292 } else { 293 $answerdata->score = get_string("didnotreceivecredit", "lesson"); 294 } 295 } 296 } else { 297 // unchecked 298 $data = "<input type=\"checkbox\" readonly=\"readonly\" name=\"answer[$i]\" value=\"0\" disabled=\"disabled\" />"; 299 } 300 if (($answer->score > 0 && $this->lesson->custom) || ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto) && !$this->lesson->custom)) { 301 $data .= "<div class=highlight>".format_text($answer->answer, $answer->answerformat, $formattextdefoptions)."</div>"; 302 } else { 303 $data .= format_text($answer->answer, $answer->answerformat, $formattextdefoptions); 304 } 305 } else { 306 if ($useranswer != null and $answer->id == $useranswer->answerid) { 307 // make checked 308 $data = "<input readonly=\"readonly\" disabled=\"disabled\" name=\"answer[$i]\" checked=\"checked\" type=\"checkbox\" value=\"1\" />"; 309 if ($answer->response == null) { 310 if ($useranswer->correct) { 311 $answerdata->response = get_string("thatsthecorrectanswer", "lesson"); 312 } else { 313 $answerdata->response = get_string("thatsthewronganswer", "lesson"); 314 } 315 } else { 316 $answerdata->response = format_text($answer->response, $answer->responseformat, $formattextdefoptions); 317 } 318 if ($this->lesson->custom) { 319 $answerdata->score = get_string("pointsearned", "lesson").": ".$answer->score; 320 } elseif ($useranswer->correct) { 321 $answerdata->score = get_string("receivedcredit", "lesson"); 322 } else { 323 $answerdata->score = get_string("didnotreceivecredit", "lesson"); 324 } 325 } else { 326 // unchecked 327 $data = "<input type=\"checkbox\" readonly=\"readonly\" name=\"answer[$i]\" value=\"0\" disabled=\"disabled\" />"; 328 } 329 if (($answer->score > 0 && $this->lesson->custom) || ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto) && !$this->lesson->custom)) { 330 $data .= "<div class=\"highlight\">".format_text($answer->answer, $answer->answerformat, $formattextdefoptions)."</div>"; 331 } else { 332 $data .= format_text($answer->answer, $answer->answerformat, $formattextdefoptions); 333 } 334 } 335 if (isset($pagestats[$this->properties->id][$answer->id])) { 336 $percent = $pagestats[$this->properties->id][$answer->id] / $pagestats[$this->properties->id]["total"] * 100; 337 $percent = round($percent, 2); 338 $percent .= "% ".get_string("checkedthisone", "lesson"); 339 } else { 340 $percent = get_string("noonecheckedthis", "lesson"); 341 } 342 343 $answerdata->answers[] = array($data, $percent); 344 $answerpage->answerdata = $answerdata; 345 } 346 return $answerpage; 347 } 348 } 349 350 class lesson_add_page_form_truefalse extends lesson_add_page_form_base { 351 352 public $qtype = 'truefalse'; 353 public $qtypestring = 'truefalse'; 354 protected $answerformat = LESSON_ANSWER_HTML; 355 protected $responseformat = LESSON_ANSWER_HTML; 356 357 public function custom_definition() { 358 $this->_form->addElement('header', 'answertitle0', get_string('correctresponse', 'lesson')); 359 $this->add_answer(0, null, true, $this->get_answer_format()); 360 $this->add_response(0); 361 $this->add_jumpto(0, get_string('correctanswerjump', 'lesson'), LESSON_NEXTPAGE); 362 $this->add_score(0, get_string('correctanswerscore', 'lesson'), 1); 363 364 $this->_form->addElement('header', 'answertitle1', get_string('wrongresponse', 'lesson')); 365 $this->add_answer(1, null, true, $this->get_answer_format()); 366 $this->add_response(1); 367 $this->add_jumpto(1, get_string('wronganswerjump', 'lesson'), LESSON_THISPAGE); 368 $this->add_score(1, get_string('wronganswerscore', 'lesson'), 0); 369 } 370 } 371 372 class lesson_display_answer_form_truefalse extends moodleform { 373 374 public function definition() { 375 global $USER, $OUTPUT; 376 $mform = $this->_form; 377 $answers = $this->_customdata['answers']; 378 $lessonid = $this->_customdata['lessonid']; 379 $contents = $this->_customdata['contents']; 380 if (array_key_exists('attempt', $this->_customdata)) { 381 $attempt = $this->_customdata['attempt']; 382 } else { 383 $attempt = new stdClass(); 384 $attempt->answerid = null; 385 } 386 387 // Disable shortforms. 388 $mform->setDisableShortforms(); 389 390 $mform->addElement('header', 'pageheader'); 391 392 $mform->addElement('html', $OUTPUT->container($contents, 'contents')); 393 394 $hasattempt = false; 395 $disabled = ''; 396 if (isset($USER->modattempts[$lessonid]) && !empty($USER->modattempts[$lessonid])) { 397 $hasattempt = true; 398 $disabled = array('disabled' => 'disabled'); 399 } 400 401 $options = new stdClass(); 402 $options->para = false; 403 $options->noclean = true; 404 405 $mform->addElement('hidden', 'id'); 406 $mform->setType('id', PARAM_INT); 407 408 $mform->addElement('hidden', 'pageid'); 409 $mform->setType('pageid', PARAM_INT); 410 411 $i = 0; 412 $radiobuttons = array(); 413 foreach ($answers as $answer) { 414 $ansid = 'answerid'; 415 if ($hasattempt) { 416 $ansid = 'answer_id'; 417 } 418 419 $answer = lesson_page_type_truefalse::rewrite_answers_urls($answer); 420 $radiobuttons[] = $mform->createElement('radio', $ansid, null, 421 format_text($answer->answer, $answer->answerformat, $options), $answer->id, $disabled); 422 423 $mform->setType($ansid, PARAM_INT); 424 if ($hasattempt && $answer->id == $USER->modattempts[$lessonid]->answerid) { 425 $mform->setDefault($ansid, $attempt->answerid); 426 $mform->addElement('hidden', 'answerid', $answer->id); 427 $mform->setType('answerid', PARAM_INT); 428 } 429 $i++; 430 } 431 432 $radiogroup = $mform->addGroup($radiobuttons, $ansid, '', array(''), false); 433 $radiogroup->setAttributes(array('class' => 'answeroptiongroup')); 434 435 if ($hasattempt) { 436 $this->add_action_buttons(null, get_string("nextpage", "lesson")); 437 } else { 438 $this->add_action_buttons(null, get_string("submit", "lesson")); 439 } 440 441 } 442 443 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body