PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/mod/lesson/pagetypes/truefalse.php

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