|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // This file is part of Moodle - http://moodle.org/ 00003 // 00004 // Moodle is free software: you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation, either version 3 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // Moodle is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00016 00027 defined('MOODLE_INTERNAL') || die(); 00028 00029 00036 class mod_quiz_renderer extends plugin_renderer_base { 00049 public function review_page(quiz_attempt $attemptobj, $slots, $page, $showall, 00050 $lastpage, mod_quiz_display_options $displayoptions, 00051 $summarydata) { 00052 00053 $output = ''; 00054 $output .= $this->header(); 00055 $output .= $this->review_summary_table($summarydata, $page); 00056 $output .= $this->review_form($page, $showall, $displayoptions, 00057 $this->questions($attemptobj, true, $slots, $page, $showall, $displayoptions), 00058 $attemptobj); 00059 00060 $output .= $this->review_next_navigation($attemptobj, $page, $lastpage); 00061 $output .= $this->footer(); 00062 return $output; 00063 } 00064 00075 public function review_question_page(quiz_attempt $attemptobj, $slot, $seq, 00076 mod_quiz_display_options $displayoptions, $summarydata) { 00077 00078 $output = ''; 00079 $output .= $this->header(); 00080 $output .= $this->review_summary_table($summarydata, 0); 00081 00082 if (!is_null($seq)) { 00083 $output .= $attemptobj->render_question_at_step($slot, $seq, true); 00084 } else { 00085 $output .= $attemptobj->render_question($slot, true); 00086 } 00087 00088 $output .= $this->close_window_button(); 00089 $output .= $this->footer(); 00090 return $output; 00091 } 00092 00099 public function review_question_not_allowed($message) { 00100 $output = ''; 00101 $output .= $this->header(); 00102 $output .= $this->notification($message); 00103 $output .= $this->close_window_button(); 00104 $output .= $this->footer(); 00105 return $output; 00106 } 00107 00115 protected function filter_summary_table($summarydata, $page) { 00116 if ($page == 0) { 00117 return $summarydata; 00118 } 00119 00120 // Only show some of summary table on subsequent pages. 00121 foreach ($summarydata as $key => $rowdata) { 00122 if (!in_array($key, array('user', 'attemptlist'))) { 00123 unset($summarydata[$key]); 00124 } 00125 } 00126 00127 return $summarydata; 00128 } 00129 00136 public function review_summary_table($summarydata, $page) { 00137 $summarydata = $this->filter_summary_table($summarydata, $page); 00138 if (empty($summarydata)) { 00139 return ''; 00140 } 00141 00142 $output = ''; 00143 $output .= html_writer::start_tag('table', array( 00144 'class' => 'generaltable generalbox quizreviewsummary')); 00145 $output .= html_writer::start_tag('tbody'); 00146 foreach ($summarydata as $rowdata) { 00147 if ($rowdata['title'] instanceof renderable) { 00148 $title = $this->render($rowdata['title']); 00149 } else { 00150 $title = $rowdata['title']; 00151 } 00152 00153 if ($rowdata['content'] instanceof renderable) { 00154 $content = $this->render($rowdata['content']); 00155 } else { 00156 $content = $rowdata['content']; 00157 } 00158 00159 $output .= html_writer::tag('tr', 00160 html_writer::tag('th', $title, array('class' => 'cell', 'scope' => 'row')) . 00161 html_writer::tag('td', $content, array('class' => 'cell')) 00162 ); 00163 } 00164 00165 $output .= html_writer::end_tag('tbody'); 00166 $output .= html_writer::end_tag('table'); 00167 return $output; 00168 } 00169 00180 public function questions(quiz_attempt $attemptobj, $reviewing, $slots, $page, $showall, 00181 mod_quiz_display_options $displayoptions) { 00182 $output = ''; 00183 foreach ($slots as $slot) { 00184 $output .= $attemptobj->render_question($slot, $reviewing, 00185 $attemptobj->review_url($slot, $page, $showall)); 00186 } 00187 return $output; 00188 } 00189 00200 public function review_form($page, $showall, $displayoptions, $content, $attemptobj) { 00201 if ($displayoptions->flags != question_display_options::EDITABLE) { 00202 return $content; 00203 } 00204 00205 $this->page->requires->js_init_call('M.mod_quiz.init_review_form', null, false, 00206 quiz_get_js_module()); 00207 00208 $output = ''; 00209 $output .= html_writer::start_tag('form', array('action' => $attemptobj->review_url(null, 00210 $page, $showall), 'method' => 'post', 'class' => 'questionflagsaveform')); 00211 $output .= html_writer::start_tag('div'); 00212 $output .= $content; 00213 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 00214 'value' => sesskey())); 00215 $output .= html_writer::start_tag('div', array('class' => 'submitbtns')); 00216 $output .= html_writer::empty_tag('input', array('type' => 'submit', 00217 'class' => 'questionflagsavebutton', 'name' => 'savingflags', 00218 'value' => get_string('saveflags', 'question'))); 00219 $output .= html_writer::end_tag('div'); 00220 $output .= html_writer::end_tag('div'); 00221 $output .= html_writer::end_tag('form'); 00222 00223 return $output; 00224 } 00225 00231 public function finish_review_link($url) { 00232 if ($this->page->pagelayout == 'popup') { 00233 // In a 'secure' popup window. 00234 $this->page->requires->js_init_call('M.mod_quiz.secure_window.init_close_button', 00235 array($url), quiz_get_js_module()); 00236 return html_writer::empty_tag('input', array('type' => 'button', 00237 'value' => get_string('finishreview', 'quiz'), 00238 'id' => 'secureclosebutton')); 00239 } else { 00240 return html_writer::link($url, get_string('finishreview', 'quiz')); 00241 } 00242 } 00243 00251 public function review_next_navigation(quiz_attempt $attemptobj, $page, $lastpage) { 00252 if ($lastpage) { 00253 $nav = $this->finish_review_link($attemptobj->view_url()); 00254 } else { 00255 $nav = link_arrow_right(get_string('next'), $attemptobj->review_url(null, $page + 1)); 00256 } 00257 return html_writer::tag('div', $nav, array('class' => 'submitbtns')); 00258 } 00259 00264 public function countdown_timer() { 00265 return html_writer::tag('div', get_string('timeleft', 'quiz') . ' ' . 00266 html_writer::tag('span', '', array('id' => 'quiz-time-left')), 00267 array('id' => 'quiz-timer')); 00268 } 00269 00275 public function restart_preview_button($url) { 00276 return $this->single_button($url, get_string('startnewpreview', 'quiz')); 00277 } 00278 00284 public function navigation_panel(quiz_nav_panel_base $panel) { 00285 00286 $output = ''; 00287 $userpicture = $panel->user_picture(); 00288 if ($userpicture) { 00289 $output .= html_writer::tag('div', $this->render($userpicture), 00290 array('id' => 'user-picture', 'class' => 'clearfix')); 00291 } 00292 $output .= $panel->render_before_button_bits($this); 00293 00294 $output .= html_writer::start_tag('div', array('class' => 'qn_buttons')); 00295 foreach ($panel->get_question_buttons() as $button) { 00296 $output .= $this->render($button); 00297 } 00298 $output .= html_writer::end_tag('div'); 00299 00300 $output .= html_writer::tag('div', $panel->render_end_bits($this), 00301 array('class' => 'othernav')); 00302 00303 $this->page->requires->js_init_call('M.mod_quiz.nav.init', null, false, 00304 quiz_get_js_module()); 00305 00306 return $output; 00307 } 00308 00314 protected function render_quiz_nav_question_button(quiz_nav_question_button $button) { 00315 $classes = array('qnbutton', $button->stateclass); 00316 $attributes = array(); 00317 00318 if ($button->currentpage) { 00319 $classes[] = 'thispage'; 00320 $attributes[] = get_string('onthispage', 'quiz'); 00321 } 00322 00323 // Flagged? 00324 if ($button->flagged) { 00325 $classes[] = 'flagged'; 00326 $flaglabel = get_string('flagged', 'question'); 00327 } else { 00328 $flaglabel = ''; 00329 } 00330 $attributes[] = html_writer::tag('span', $flaglabel, array('class' => 'flagstate')); 00331 00332 if (is_numeric($button->number)) { 00333 $qnostring = 'questionnonav'; 00334 } else { 00335 $qnostring = 'questionnonavinfo'; 00336 } 00337 00338 $a = new stdClass(); 00339 $a->number = $button->number; 00340 $a->attributes = implode(' ', $attributes); 00341 00342 return html_writer::link($button->url, 00343 html_writer::tag('span', '', array('class' => 'thispageholder')) . 00344 html_writer::tag('span', '', array('class' => 'trafficlight')) . 00345 get_string($qnostring, 'quiz', $a), 00346 array('class' => implode(' ', $classes), 'id' => $button->id, 00347 'title' => $button->statestring)); 00348 } 00349 00355 protected function render_mod_quiz_links_to_other_attempts( 00356 mod_quiz_links_to_other_attempts $links) { 00357 $attemptlinks = array(); 00358 foreach ($links->links as $attempt => $url) { 00359 if ($url) { 00360 $attemptlinks[] = html_writer::link($url, $attempt); 00361 } else { 00362 $attemptlinks[] = html_writer::tag('strong', $attempt); 00363 } 00364 } 00365 return implode(', ', $attemptlinks); 00366 } 00367 00368 public function start_attempt_page(quiz $quizobj, mod_quiz_preflight_check_form $mform) { 00369 $output = ''; 00370 $output .= $this->header(); 00371 $output .= $this->quiz_intro($quizobj->get_quiz(), $quizobj->get_cm()); 00372 ob_start(); 00373 $mform->display(); 00374 $output .= ob_get_clean(); 00375 $output .= $this->footer(); 00376 return $output; 00377 } 00378 00390 public function attempt_page($attemptobj, $page, $accessmanager, $messages, $slots, $id, 00391 $nextpage) { 00392 $output = ''; 00393 $output .= $this->header(); 00394 $output .= $this->quiz_notices($messages); 00395 $output .= $this->attempt_form($attemptobj, $page, $slots, $id, $nextpage); 00396 $output .= $this->footer(); 00397 return $output; 00398 } 00399 00405 public function quiz_notices($messages) { 00406 if (!$messages) { 00407 return ''; 00408 } 00409 return $this->box($this->heading(get_string('accessnoticesheader', 'quiz'), 3) . 00410 $this->access_messages($messages), 'quizaccessnotices'); 00411 } 00412 00422 public function attempt_form($attemptobj, $page, $slots, $id, $nextpage) { 00423 $output = ''; 00424 00425 //Start Form 00426 $output .= html_writer::start_tag('form', 00427 array('action' => $attemptobj->processattempt_url(), 'method' => 'post', 00428 'enctype' => 'multipart/form-data', 'accept-charset' => 'utf-8', 00429 'id' => 'responseform')); 00430 $output .= html_writer::start_tag('div'); 00431 00432 // Print all the questions 00433 foreach ($slots as $slot) { 00434 $output .= $attemptobj->render_question($slot, false, 00435 $attemptobj->attempt_url($slot, $page)); 00436 } 00437 00438 $output .= html_writer::start_tag('div', array('class' => 'submitbtns')); 00439 $output .= html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'next', 00440 'value' => get_string('next'))); 00441 $output .= html_writer::end_tag('div'); 00442 00443 // Some hidden fields to trach what is going on. 00444 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'attempt', 00445 'value' => $attemptobj->get_attemptid())); 00446 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'thispage', 00447 'value' => $page, 'id' => 'followingpage')); 00448 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'nextpage', 00449 'value' => $nextpage)); 00450 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'timeup', 00451 'value' => '0', 'id' => 'timeup')); 00452 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 00453 'value' => sesskey())); 00454 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'scrollpos', 00455 'value' => '', 'id' => 'scrollpos')); 00456 00457 // Add a hidden field with questionids. Do this at the end of the form, so 00458 // if you navigate before the form has finished loading, it does not wipe all 00459 // the student's answers. 00460 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'slots', 00461 'value' => implode(',', $slots))); 00462 00463 //Finish form 00464 $output .= html_writer::end_tag('div'); 00465 $output .= html_writer::end_tag('form'); 00466 00467 return $output; 00468 } 00469 00474 public function initialise_timer($timerstartvalue) { 00475 $this->page->requires->js_init_call('M.mod_quiz.timer.init', 00476 array($timerstartvalue), false, quiz_get_js_module()); 00477 } 00478 00486 public function close_attempt_popup($url, $message = '') { 00487 $output = ''; 00488 $output .= $this->header(); 00489 $output .= $this->box_start(); 00490 00491 if ($message) { 00492 $output .= html_writer::tag('p', $message); 00493 $output .= html_writer::tag('p', get_string('windowclosing', 'quiz')); 00494 $delay = 5; 00495 } else { 00496 $output .= html_writer::tag('p', get_string('pleaseclose', 'quiz')); 00497 $delay = 0; 00498 } 00499 $this->page->requires->js_function_call('M.mod_quiz.secure_window.close', 00500 array($url, $delay)); 00501 00502 $output .= $this->box_end(); 00503 $output .= $this->footer(); 00504 return $output; 00505 } 00506 00515 public function access_messages($messages) { 00516 $output = ''; 00517 foreach ($messages as $message) { 00518 $output .= html_writer::tag('p', $message) . "\n"; 00519 } 00520 return $output; 00521 } 00522 00523 /* 00524 * Summary Page 00525 */ 00532 public function summary_page($attemptobj, $displayoptions) { 00533 $output = ''; 00534 $output .= $this->header(); 00535 $output .= $this->heading(format_string($attemptobj->get_quiz_name())); 00536 $output .= $this->heading(get_string('summaryofattempt', 'quiz'), 3); 00537 $output .= $this->summary_table($attemptobj, $displayoptions); 00538 $output .= $this->summary_page_controls($attemptobj); 00539 $output .= $this->footer(); 00540 return $output; 00541 } 00542 00549 public function summary_table($attemptobj, $displayoptions) { 00550 // Prepare the summary table header 00551 $table = new html_table(); 00552 $table->attributes['class'] = 'generaltable quizsummaryofattempt boxaligncenter'; 00553 $table->head = array(get_string('question', 'quiz'), get_string('status', 'quiz')); 00554 $table->align = array('left', 'left'); 00555 $table->size = array('', ''); 00556 $markscolumn = $displayoptions->marks >= question_display_options::MARK_AND_MAX; 00557 if ($markscolumn) { 00558 $table->head[] = get_string('marks', 'quiz'); 00559 $table->align[] = 'left'; 00560 $table->size[] = ''; 00561 } 00562 $table->data = array(); 00563 00564 // Get the summary info for each question. 00565 $slots = $attemptobj->get_slots(); 00566 foreach ($slots as $slot) { 00567 if (!$attemptobj->is_real_question($slot)) { 00568 continue; 00569 } 00570 $flag = ''; 00571 if ($attemptobj->is_question_flagged($slot)) { 00572 $flag = html_writer::empty_tag('img', array('src' => $this->pix_url('i/flagged'), 00573 'alt' => get_string('flagged', 'question'), 'class' => 'questionflag')); 00574 } 00575 $row = array(html_writer::link($attemptobj->attempt_url($slot), 00576 $attemptobj->get_question_number($slot) . $flag), 00577 $attemptobj->get_question_status($slot, $displayoptions->correctness)); 00578 if ($markscolumn) { 00579 $row[] = $attemptobj->get_question_mark($slot); 00580 } 00581 $table->data[] = $row; 00582 $table->rowclasses[] = $attemptobj->get_question_state_class( 00583 $slot, $displayoptions->correctness); 00584 } 00585 00586 // Print the summary table. 00587 $output = html_writer::table($table); 00588 00589 return $output; 00590 } 00591 00597 public function summary_page_controls($attemptobj) { 00598 $output = ''; 00599 // countdown timer 00600 $output .= $this->countdown_timer(); 00601 00602 // Finish attempt button. 00603 $options = array( 00604 'attempt' => $attemptobj->get_attemptid(), 00605 'finishattempt' => 1, 00606 'timeup' => 0, 00607 'slots' => '', 00608 'sesskey' => sesskey(), 00609 ); 00610 00611 $button = new single_button( 00612 new moodle_url($attemptobj->processattempt_url(), $options), 00613 get_string('submitallandfinish', 'quiz')); 00614 $button->id = 'responseform'; 00615 $button->add_action(new confirm_action(get_string('confirmclose', 'quiz'), null, 00616 get_string('submitallandfinish', 'quiz'))); 00617 00618 $output .= $this->container($this->container($this->render($button), 00619 'controls'), 'submitbtns mdl-align'); 00620 00621 return $output; 00622 } 00623 00624 /* 00625 * View Page 00626 */ 00641 public function view_page($course, $quiz, $cm, $context, $viewobj) { 00642 $output = ''; 00643 $output .= $this->view_information($quiz, $cm, $context, $viewobj->infomessages); 00644 $output .= $this->view_table($quiz, $context, $viewobj); 00645 $output .= $this->view_best_score($viewobj); 00646 $output .= $this->view_result_info($quiz, $context, $cm, $viewobj); 00647 $output .= $this->box($this->view_page_buttons($viewobj), 'quizattempt'); 00648 return $output; 00649 } 00650 00658 public function view_page_buttons(mod_quiz_view_object $viewobj) { 00659 $output = ''; 00660 00661 if (!$viewobj->quizhasquestions) { 00662 $output .= $this->no_questions_message($viewobj->canedit, $viewobj->editurl); 00663 } 00664 00665 $output .= $this->access_messages($viewobj->preventmessages); 00666 00667 if ($viewobj->buttontext) { 00668 $output .= $this->start_attempt_button($viewobj->buttontext, 00669 $viewobj->startattempturl, $viewobj->startattemptwarning, 00670 $viewobj->popuprequired, $viewobj->popupoptions); 00671 00672 } else if ($viewobj->buttontext === '') { 00673 // We should show a 'back to the course' button. 00674 $output .= $this->single_button($viewobj->backtocourseurl, 00675 get_string('backtocourse', 'quiz'), 'get', 00676 array('class' => 'continuebutton')); 00677 } 00678 00679 return $output; 00680 } 00681 00692 public function start_attempt_button($buttontext, moodle_url $url, 00693 $startattemptwarning, $popuprequired, $popupoptions) { 00694 00695 $button = new single_button($url, $buttontext); 00696 $button->class .= ' quizstartbuttondiv'; 00697 00698 $warning = ''; 00699 if ($popuprequired) { 00700 $this->page->requires->js_module(quiz_get_js_module()); 00701 $this->page->requires->js('/mod/quiz/module.js'); 00702 $popupaction = new popup_action('click', $url, 'quizpopup', $popupoptions); 00703 00704 $button->class .= ' quizsecuremoderequired'; 00705 $button->add_action(new component_action('click', 00706 'M.mod_quiz.secure_window.start_attempt_action', array( 00707 'url' => $url->out(false), 00708 'windowname' => 'quizpopup', 00709 'options' => $popupaction->get_js_options(), 00710 'fullscreen' => true, 00711 'startattemptwarning' => $startattemptwarning, 00712 ))); 00713 00714 $warning = html_writer::tag('noscript', $this->heading(get_string('noscript', 'quiz'))); 00715 00716 } else if ($startattemptwarning) { 00717 $button->add_action(new confirm_action($startattemptwarning, null, 00718 get_string('startattempt', 'quiz'))); 00719 } 00720 00721 return $this->render($button) . $warning; 00722 } 00723 00732 public function no_questions_message($canedit, $editurl) { 00733 $output = ''; 00734 $output .= $this->notification(get_string('noquestions', 'quiz')); 00735 if ($canedit) { 00736 $output .= $this->single_button($editurl, get_string('editquiz', 'quiz'), 'get'); 00737 } 00738 00739 return $output; 00740 } 00741 00751 public function view_page_guest($course, $quiz, $cm, $context, $messages) { 00752 $output = ''; 00753 $output .= $this->view_information($quiz, $cm, $context, $messages); 00754 $guestno = html_writer::tag('p', get_string('guestsno', 'quiz')); 00755 $liketologin = html_writer::tag('p', get_string('liketologin')); 00756 $output .= $this->confirm($guestno."\n\n".$liketologin."\n", get_login_url(), 00757 get_referer(false)); 00758 return $output; 00759 } 00760 00770 public function view_page_notenrolled($course, $quiz, $cm, $context, $messages) { 00771 global $CFG; 00772 $output = ''; 00773 $output .= $this->view_information($quiz, $cm, $context, $messages); 00774 $youneedtoenrol = html_writer::tag('p', get_string('youneedtoenrol', 'quiz')); 00775 $button = html_writer::tag('p', 00776 $this->continue_button($CFG->wwwroot . '/course/view.php?id=' . $course->id)); 00777 $output .= $this->box($youneedtoenrol."\n\n".$button."\n", 'generalbox', 'notice'); 00778 return $output; 00779 } 00780 00790 public function view_information($quiz, $cm, $context, $messages) { 00791 global $CFG; 00792 00793 $output = ''; 00794 // Print quiz name and description 00795 $output .= $this->heading(format_string($quiz->name)); 00796 if (trim(strip_tags($quiz->intro))) { 00797 $output .= $this->box(format_module_intro('quiz', $quiz, $cm->id), 'generalbox', 00798 'intro'); 00799 } 00800 00801 $output .= $this->box($this->access_messages($messages), 'quizinfo'); 00802 00803 // Show number of attempts summary to those who can view reports. 00804 if (has_capability('mod/quiz:viewreports', $context)) { 00805 if ($strattemptnum = $this->quiz_attempt_summary_link_to_reports($quiz, $cm, 00806 $context)) { 00807 $output .= html_writer::tag('div', $strattemptnum, 00808 array('class' => 'quizattemptcounts')); 00809 } 00810 } 00811 return $output; 00812 } 00813 00820 public function quiz_intro($quiz, $cm) { 00821 if (trim(strip_tags($quiz->intro))) { 00822 return $this->box(format_module_intro('quiz', $quiz, $cm->id), 00823 'generalbox', 'intro'); 00824 00825 } else { 00826 return ''; 00827 } 00828 } 00829 00833 public function view_table_heading() { 00834 return $this->heading(get_string('summaryofattempts', 'quiz')); 00835 } 00836 00844 public function view_table($quiz, $context, $viewobj) { 00845 $output = ''; 00846 if (!$viewobj->attempts) { 00847 return $output; 00848 } 00849 $output .= $this->view_table_heading(); 00850 00851 // Prepare table header 00852 $table = new html_table(); 00853 $table->attributes['class'] = 'generaltable quizattemptsummary'; 00854 $table->head = array(); 00855 $table->align = array(); 00856 $table->size = array(); 00857 if ($viewobj->attemptcolumn) { 00858 $table->head[] = get_string('attemptnumber', 'quiz'); 00859 $table->align[] = 'center'; 00860 $table->size[] = ''; 00861 } 00862 $table->head[] = get_string('timecompleted', 'quiz'); 00863 $table->align[] = 'left'; 00864 $table->size[] = ''; 00865 if ($viewobj->markcolumn) { 00866 $table->head[] = get_string('marks', 'quiz') . ' / ' . 00867 quiz_format_grade($quiz, $quiz->sumgrades); 00868 $table->align[] = 'center'; 00869 $table->size[] = ''; 00870 } 00871 if ($viewobj->gradecolumn) { 00872 $table->head[] = get_string('grade') . ' / ' . 00873 quiz_format_grade($quiz, $quiz->grade); 00874 $table->align[] = 'center'; 00875 $table->size[] = ''; 00876 } 00877 if ($viewobj->canreviewmine) { 00878 $table->head[] = get_string('review', 'quiz'); 00879 $table->align[] = 'center'; 00880 $table->size[] = ''; 00881 } 00882 if ($viewobj->feedbackcolumn) { 00883 $table->head[] = get_string('feedback', 'quiz'); 00884 $table->align[] = 'left'; 00885 $table->size[] = ''; 00886 } 00887 if (isset($quiz->showtimetaken)) { 00888 $table->head[] = get_string('timetaken', 'quiz'); 00889 $table->align[] = 'left'; 00890 $table->size[] = ''; 00891 } 00892 00893 // One row for each attempt 00894 foreach ($viewobj->attempts as $attempt) { 00895 $attemptoptions = quiz_get_review_options($quiz, $attempt, $context); 00896 $row = array(); 00897 00898 // Add the attempt number, making it a link, if appropriate. 00899 if ($viewobj->attemptcolumn) { 00900 if ($attempt->preview) { 00901 $row[] = get_string('preview', 'quiz'); 00902 } else { 00903 $row[] = $attempt->attempt; 00904 } 00905 } 00906 00907 // prepare strings for time taken and date completed 00908 $timetaken = ''; 00909 $datecompleted = ''; 00910 if ($attempt->timefinish > 0) { 00911 // attempt has finished 00912 $timetaken = format_time($attempt->timefinish - $attempt->timestart); 00913 $datecompleted = userdate($attempt->timefinish); 00914 } else if (!$quiz->timeclose || $viewobj->timenow < $quiz->timeclose) { 00915 // The attempt is still in progress. 00916 $timetaken = format_time($viewobj->timenow - $attempt->timestart); 00917 $datecompleted = get_string('inprogress', 'quiz'); 00918 } else { 00919 $timetaken = format_time($quiz->timeclose - $attempt->timestart); 00920 $datecompleted = userdate($quiz->timeclose); 00921 } 00922 $row[] = $datecompleted; 00923 00924 if ($viewobj->markcolumn) { 00925 if ($attemptoptions->marks >= question_display_options::MARK_AND_MAX && 00926 $attempt->timefinish > 0) { 00927 $row[] = quiz_format_grade($quiz, $attempt->sumgrades); 00928 } else { 00929 $row[] = ''; 00930 } 00931 } 00932 00933 // Ouside the if because we may be showing feedback but not grades. 00934 $attemptgrade = quiz_rescale_grade($attempt->sumgrades, $quiz, false); 00935 00936 if ($viewobj->gradecolumn) { 00937 if ($attemptoptions->marks >= question_display_options::MARK_AND_MAX && 00938 $attempt->timefinish > 0) { 00939 $formattedgrade = quiz_format_grade($quiz, $attemptgrade); 00940 // highlight the highest grade if appropriate 00941 if ($viewobj->overallstats && !$attempt->preview 00942 && $viewobj->numattempts > 1 && !is_null($viewobj->mygrade) 00943 && $attemptgrade == $viewobj->mygrade 00944 && $quiz->grademethod == QUIZ_GRADEHIGHEST) { 00945 $table->rowclasses[$attempt->attempt] = 'bestrow'; 00946 } 00947 00948 $row[] = $formattedgrade; 00949 } else { 00950 $row[] = ''; 00951 } 00952 } 00953 00954 if ($viewobj->canreviewmine) { 00955 $row[] = $viewobj->accessmanager->make_review_link($attempt, 00956 $attemptoptions, $this); 00957 } 00958 00959 if ($viewobj->feedbackcolumn && $attempt->timefinish > 0) { 00960 if ($attemptoptions->overallfeedback) { 00961 $row[] = quiz_feedback_for_grade($attemptgrade, $quiz, $context); 00962 } else { 00963 $row[] = ''; 00964 } 00965 } 00966 00967 if (isset($quiz->showtimetaken)) { 00968 $row[] = $timetaken; 00969 } 00970 00971 if ($attempt->preview) { 00972 $table->data['preview'] = $row; 00973 } else { 00974 $table->data[$attempt->attempt] = $row; 00975 } 00976 } // End of loop over attempts. 00977 $output .= html_writer::table($table); 00978 00979 return $output; 00980 } 00981 00987 public function view_best_score($viewobj) { 00988 $output = ''; 00989 // Print information about the student's best score for this quiz if possible. 00990 if (!$viewobj->moreattempts) { 00991 $output .= $this->heading(get_string('nomoreattempts', 'quiz')); 00992 } 00993 return $output; 00994 } 00995 01004 public function view_result_info($quiz, $context, $cm, $viewobj) { 01005 $output = ''; 01006 if (!$viewobj->numattempts && !$viewobj->gradecolumn && is_null($viewobj->mygrade)) { 01007 return $output; 01008 } 01009 $resultinfo = ''; 01010 01011 if ($viewobj->overallstats) { 01012 if ($viewobj->moreattempts) { 01013 $a = new stdClass(); 01014 $a->method = quiz_get_grading_option_name($quiz->grademethod); 01015 $a->mygrade = quiz_format_grade($quiz, $viewobj->mygrade); 01016 $a->quizgrade = quiz_format_grade($quiz, $quiz->grade); 01017 $resultinfo .= $this->heading(get_string('gradesofar', 'quiz', $a), 2, 'main'); 01018 } else { 01019 $a = new stdClass(); 01020 $a->grade = quiz_format_grade($quiz, $viewobj->mygrade); 01021 $a->maxgrade = quiz_format_grade($quiz, $quiz->grade); 01022 $a = get_string('outofshort', 'quiz', $a); 01023 $resultinfo .= $this->heading(get_string('yourfinalgradeis', 'quiz', $a), 2, 01024 'main'); 01025 } 01026 } 01027 01028 if ($viewobj->mygradeoverridden) { 01029 01030 $resultinfo .= html_writer::tag('p', get_string('overriddennotice', 'grades'), 01031 array('class' => 'overriddennotice'))."\n"; 01032 } 01033 if ($viewobj->gradebookfeedback) { 01034 $resultinfo .= $this->heading(get_string('comment', 'quiz'), 3, 'main'); 01035 $resultinfo .= '<p class="quizteacherfeedback">'.$viewobj->gradebookfeedback. 01036 "</p>\n"; 01037 } 01038 if ($viewobj->feedbackcolumn) { 01039 $resultinfo .= $this->heading(get_string('overallfeedback', 'quiz'), 3, 'main'); 01040 $resultinfo .= html_writer::tag('p', 01041 quiz_feedback_for_grade($viewobj->mygrade, $quiz, $context), 01042 array('class' => 'quizgradefeedback'))."\n"; 01043 } 01044 01045 if ($resultinfo) { 01046 $output .= $this->box($resultinfo, 'generalbox', 'feedback'); 01047 } 01048 return $output; 01049 } 01050 01060 public function review_link($url, $reviewinpopup, $popupoptions) { 01061 if ($reviewinpopup) { 01062 $button = new single_button($url, get_string('review', 'quiz')); 01063 $button->add_action(new popup_action('click', $url, 'quizpopup', $popupoptions)); 01064 return $this->render($button); 01065 01066 } else { 01067 return html_writer::link($url, get_string('review', 'quiz'), 01068 array('title' => get_string('reviewthisattempt', 'quiz'))); 01069 } 01070 } 01071 01078 public function no_review_message($message) { 01079 return html_writer::nonempty_tag('span', $message, 01080 array('class' => 'noreviewmessage')); 01081 } 01082 01098 public function quiz_attempt_summary_link_to_reports($quiz, $cm, $context, 01099 $returnzero = false, $currentgroup = 0) { 01100 global $CFG; 01101 $summary = quiz_num_attempt_summary($quiz, $cm, $returnzero, $currentgroup); 01102 if (!$summary) { 01103 return ''; 01104 } 01105 01106 require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php'); 01107 $url = new moodle_url('/mod/quiz/report.php', array( 01108 'id' => $cm->id, 'mode' => quiz_report_default_report($context))); 01109 return html_writer::link($url, $summary); 01110 } 01111 } 01112 01113 class mod_quiz_links_to_other_attempts implements renderable { 01117 public $links = array(); 01118 } 01119 01120 class mod_quiz_view_object { 01122 public $infomessages; 01124 public $attempts; 01126 public $accessmanager; 01129 public $canreviewmine; 01131 public $canedit; 01133 public $editurl; 01135 public $attemptcolumn; 01137 public $gradecolumn; 01139 public $markcolumn; 01141 public $overallstats; 01143 public $feedbackcolumn; 01145 public $timenow; 01147 public $numattempts; 01149 public $mygrade; 01151 public $moreattempts; 01153 public $mygradeoverridden; 01155 public $gradebookfeedback; 01157 public $unfinished; 01159 public $lastfinishedattempt; 01162 public $preventmessages; 01165 public $buttontext; 01167 public $startattemptwarning; 01169 public $startattempturl; 01171 public $backtocourseurl; 01173 public $popuprequired; 01175 public $popupoptions; 01177 public $quizhasquestions; 01178 }