Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/mod/quiz/renderer.php
Go to the documentation of this file.
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 }
 All Data Structures Namespaces Files Functions Variables Enumerations