Checking in the code for the "improvements to the quiz results overview page"
project, commissioned by the University of York. Enjoy!
This commit is contained in:
@@ -1,72 +1,104 @@
|
||||
<?php // $Id$
|
||||
|
||||
require_once($CFG->libdir.'/tablelib.php');
|
||||
|
||||
/// Overview report just displays a big table of all the attempts
|
||||
|
||||
class quiz_report extends quiz_default_report {
|
||||
|
||||
function display($quiz, $cm, $course) { /// This function just displays the report
|
||||
|
||||
global $CFG, $QUIZ_GRADE_METHOD, $del;
|
||||
global $CFG, $SESSION, $db;
|
||||
|
||||
$strreallydel = addslashes(get_string('deleteattemptcheck','quiz'));
|
||||
$strdeleteselected = get_string('deleteselected');
|
||||
$strdeleteall = get_string('deleteall');
|
||||
$strname = get_string("name");
|
||||
$strattempts = get_string("attempts", "quiz");
|
||||
$strreallydel = addslashes(get_string('deleteattemptcheck','quiz'));
|
||||
$strnoattempts = get_string('noattempts','quiz');
|
||||
$strbestgrade = $QUIZ_GRADE_METHOD[$quiz->grademethod];
|
||||
$strtimeformat = get_string('strftimedatetime');
|
||||
|
||||
|
||||
if (!empty($del)) { /// Some attempts need to be deleted
|
||||
$action = optional_param('action', '');
|
||||
|
||||
if (record_exists('quiz_attempts', 'quiz', $quiz->id)) {
|
||||
switch($action) {
|
||||
case 'delete': /// Some attempts need to be deleted
|
||||
|
||||
if ($del == 'all'){ /// Delete all the attempts
|
||||
$attempts = get_records('quiz_attempts','quiz',$quiz->id);
|
||||
delete_records('quiz_attempts','quiz',$quiz->id);
|
||||
delete_records('quiz_grades','quiz',$quiz->id);
|
||||
if ($attempts) {
|
||||
foreach ($attempts as $thisattempt){
|
||||
delete_records('quiz_responses','attempt',$thisattempt->id);
|
||||
}
|
||||
$attemptids = isset($_POST['attemptid']) ? $_POST['attemptid'] : array();
|
||||
if(!is_array($attemptids) || empty($attemptids)) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($attemptids as $num => $attemptid) {
|
||||
if(empty($attemptid)) {
|
||||
unset($attemptids[$num]);
|
||||
}
|
||||
}
|
||||
|
||||
} else { /// Delete selected attempts
|
||||
foreach($attemptids as $attemptid) {
|
||||
if ($todelete = get_record('quiz_attempts', 'id', $attemptid)) {
|
||||
|
||||
$items = (array)data_submitted();
|
||||
delete_records('quiz_attempts', 'id', $attemptid);
|
||||
delete_records('quiz_responses', 'attempt', $attemptid);
|
||||
|
||||
unset($items['del']);
|
||||
unset($items['id']);
|
||||
// Search quiz_attempts for other instances by this user.
|
||||
// If none, then delete record for this quiz, this user from quiz_grades
|
||||
// else recalculate best grade
|
||||
|
||||
if ($items) {
|
||||
foreach ($items as $attemptid) {
|
||||
if ($todelete = get_record('quiz_attempts', 'id', $attemptid)) {
|
||||
delete_records('quiz_attempts', 'id', $attemptid);
|
||||
delete_records('quiz_responses', 'attempt', $attemptid);
|
||||
|
||||
// Search quiz_attempts for other instances by this user.
|
||||
// If none, then delete record for this quiz, this user from quiz_grades
|
||||
// else recalculate best grade
|
||||
|
||||
$userid = $todelete->userid;
|
||||
if (!record_exists('quiz_attempts', 'userid', $userid, 'quiz',$quiz->id)) {
|
||||
delete_records('quiz_grades', 'userid', $userid,'quiz',$quiz->id);
|
||||
} else {
|
||||
quiz_save_best_grade($quiz, $userid);
|
||||
}
|
||||
}
|
||||
$userid = $todelete->userid;
|
||||
if (!record_exists('quiz_attempts', 'userid', $userid, 'quiz', $quiz->id)) {
|
||||
delete_records('quiz_grades', 'userid', $userid,'quiz', $quiz->id);
|
||||
} else {
|
||||
quiz_save_best_grade($quiz, $userid);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(!isset($SESSION->quiz_overview_table)) {
|
||||
$SESSION->quiz_overview_table = array('noattempts' => false, 'teacherattempts' => true, 'detailedmarks' => false);
|
||||
}
|
||||
|
||||
foreach($SESSION->quiz_overview_table as $option => $value) {
|
||||
$urlparam = optional_param($option, NULL);
|
||||
if($urlparam === NULL) {
|
||||
$$option = $value;
|
||||
}
|
||||
else {
|
||||
$$option = $SESSION->quiz_overview_table[$option] = $urlparam;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$grades = quiz_get_grade_records($quiz)) {
|
||||
print_heading($strnoattempts);
|
||||
return true;
|
||||
$tablecolumns = array('checkbox', 'picture', 'fullname', 'timefinish', 'duration', 'sumgrades');
|
||||
$tableheaders = array(NULL, '', get_string('fullname'), get_string('attemptedon', 'quiz'), get_string('attemptduration', 'quiz'), get_string('grade', 'quiz').'/'.$quiz->grade);
|
||||
|
||||
if($detailedmarks) {
|
||||
$questions = explode(',', $quiz->questions);
|
||||
foreach($questions as $number => $questionid) {
|
||||
$tablecolumns[] = '$'.$questionid;
|
||||
$tableheaders[] = '#'.($number + 1);
|
||||
}
|
||||
}
|
||||
|
||||
$table = new flexible_table('mod-quiz-report-overview-report');
|
||||
|
||||
$table->define_columns($tablecolumns);
|
||||
$table->define_headers($tableheaders);
|
||||
$table->define_baseurl($CFG->wwwroot.'/mod/quiz/report.php?id='.$cm->id);
|
||||
|
||||
$table->sortable(true);
|
||||
$table->collapsible(true);
|
||||
$table->initialbars(true);
|
||||
|
||||
$table->column_suppress('picture');
|
||||
$table->column_suppress('fullname');
|
||||
|
||||
$table->column_class('picture', 'picture');
|
||||
|
||||
$table->set_attribute('cellspacing', '0');
|
||||
$table->set_attribute('id', 'attempts');
|
||||
$table->set_attribute('class', 'generaltable generalbox');
|
||||
|
||||
// Start working -- this is necessary as soon as the niceties are over
|
||||
$table->setup();
|
||||
|
||||
|
||||
/// Check to see if groups are being used in this quiz
|
||||
if ($groupmode = groupmode($course, $cm)) { // Groups are being used
|
||||
$currentgroup = setup_and_print_groups($course, $groupmode, "report.php?id=$cm->id&mode=overview");
|
||||
@@ -78,54 +110,135 @@ class quiz_report extends quiz_default_report {
|
||||
if ($currentgroup) {
|
||||
$users = get_group_users($currentgroup);
|
||||
}
|
||||
|
||||
|
||||
$table->head = array(" ", $strname, $strattempts, "$strbestgrade /$quiz->grade");
|
||||
$table->align = array("center", "left", "left", "center");
|
||||
$table->wrap = array("nowrap", "nowrap", "nowrap", "nowrap");
|
||||
$table->width = 10;
|
||||
$table->size = array(10, "*", "80%", "*");
|
||||
|
||||
foreach ($grades as $grade) {
|
||||
if ($currentgroup) {
|
||||
if (empty($users[$grade->userid])) { /// Using groups, but this user not in group
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$picture = print_user_picture($grade->userid, $course->id, $grade->picture, false, true);
|
||||
|
||||
if ($attempts = quiz_get_user_attempts($quiz->id, $grade->userid)) {
|
||||
$userattempts = $this->quiz_get_user_attempts_list($quiz, $attempts, $grade->grade, $strtimeformat);
|
||||
} else {
|
||||
$userattempts = "";
|
||||
}
|
||||
|
||||
$table->data[] = array ($picture,
|
||||
"<a href=\"$CFG->wwwroot/user/view.php?id=$grade->userid&course=$course->id\">".
|
||||
fullname($grade).'</a>',
|
||||
"$userattempts", format_float($grade->grade,$quiz->decimalpoints));
|
||||
else {
|
||||
$users = get_course_users($course->id);
|
||||
}
|
||||
|
||||
//Embed script for warning
|
||||
echo "\n<script language=\"javascript\" type=\"text/javascript\">\n<!--\nfunction delcheck(){\n ";
|
||||
echo "if (confirm('$strreallydel')) {\n";
|
||||
echo " document.delform.del.value='all';\n return true;\n";
|
||||
echo " } else {\n";
|
||||
echo " return false;\n }\n}\n";
|
||||
echo "//-->\n</script>\n";
|
||||
|
||||
$onsub = "return confirm('$strreallydel')";
|
||||
if(!$teacherattempts) {
|
||||
$teachers = get_course_teachers($course->id);
|
||||
if(!empty($teachers)) {
|
||||
$keys = array_keys($teachers);
|
||||
}
|
||||
foreach($keys as $key) {
|
||||
unset($users[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
echo "<form method=\"post\" action=\"report.php\" name=\"delform\" onsubmit=\"$onsub\">\n";
|
||||
echo "<input type=\"hidden\" name=\"del\" value=\"selection\" />\n";
|
||||
echo "<input type=\"hidden\" name=\"id\" value=\"$cm->id\" />\n";
|
||||
if(empty($users)) {
|
||||
print_heading($strnoattempts);
|
||||
return true;
|
||||
}
|
||||
|
||||
print_table($table);
|
||||
// Construct the SQL
|
||||
|
||||
if($where = $table->get_sql_where()) {
|
||||
$where .= ' AND ';
|
||||
}
|
||||
|
||||
if($sort = $table->get_sql_sort()) {
|
||||
if(substr($sort, 0, 1) == '$') {
|
||||
$qnum = intval(substr($sort, 1));
|
||||
$where.= '('.sql_isnull('qr.question').' OR qr.question = '.$qnum.') AND ';
|
||||
$sort = ' ORDER BY grade '.(strpos($sort, 'ASC')? 'ASC' : 'DESC');
|
||||
}
|
||||
else {
|
||||
$sort = ' ORDER BY '.$sort;
|
||||
}
|
||||
}
|
||||
|
||||
$select = 'SELECT '.$db->Concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).' AS uvsa, u.id AS userid, u.firstname, u.lastname, u.picture, qa.id AS attempt, qa.sumgrades, qa.timefinish, qa.timefinish - qa.timestart AS duration ';
|
||||
$group = 'GROUP BY uvsa';
|
||||
$sql = 'FROM '.$CFG->prefix.'user u '.
|
||||
'LEFT JOIN '.$CFG->prefix.'quiz_attempts qa ON u.id = qa.userid '.
|
||||
'LEFT JOIN '.$CFG->prefix.'quiz_responses qr ON qr.attempt = qa.id '.
|
||||
'WHERE '.$where.'u.id IN ('.implode(',', array_keys($users)).') AND ('.($noattempts ? sql_isnull('qa.quiz').' OR ' : '') . 'qa.quiz = '.$quiz->id.') ';
|
||||
|
||||
$total = count_records_sql('SELECT COUNT(DISTINCT('.$db->Concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).')) '.$sql);
|
||||
$table->pagesize(10, $total);
|
||||
|
||||
if($table->get_page_start() !== '' && $table->get_page_size() !== '') {
|
||||
$limit = ' '.sql_paging_limit($table->get_page_start(), $table->get_page_size());
|
||||
}
|
||||
else {
|
||||
$limit = '';
|
||||
}
|
||||
|
||||
$attempts = get_records_sql($select.$sql.$group.$sort.$limit);
|
||||
|
||||
if(!empty($attempts)) {
|
||||
|
||||
foreach ($attempts as $attempt) {
|
||||
|
||||
//There might be a more elegant way than using the <center> tag for this
|
||||
echo "<center><input type=\"submit\" value=\"$strdeleteselected\" /> ";
|
||||
echo "<input type=\"button\" value=\"$strdeleteall\" onclick=\"if(delcheck()){document.delform.submit()}\" />\n</center>\n";
|
||||
echo "</form>\n";
|
||||
$picture = print_user_picture($attempt->userid, $course->id, $attempt->picture, false, true);
|
||||
|
||||
$row = array(
|
||||
'<input type="checkbox" name="attemptid[]" value="'.$attempt->attempt.'" />',
|
||||
$picture,
|
||||
'<a href="'.$CFG->wwwroot.'/user/view.php?id='.$attempt->userid.'&course='.$course->id.'">'.fullname($attempt).'</a>',
|
||||
empty($attempt->attempt) ? '-' : '<a href="review.php?q='.$quiz->id.'&attempt='.$attempt->attempt.'">'.userdate($attempt->timefinish, $strtimeformat).'</a>',
|
||||
empty($attempt->attempt) ? '-' : format_time($attempt->duration),
|
||||
$attempt->sumgrades === NULL ? '-' : format_float($attempt->sumgrades / $quiz->sumgrades * $quiz->grade,$quiz->decimalpoints)
|
||||
);
|
||||
|
||||
if($detailedmarks) {
|
||||
if(empty($attempt->attempt)) {
|
||||
foreach($questions as $question) {
|
||||
$row[] = '-';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$responses = get_records('quiz_responses', 'attempt', $attempt->attempt, 'question');
|
||||
foreach($responses as $response) {
|
||||
$row[] = $response->grade;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$table->add_data($row);
|
||||
}
|
||||
|
||||
echo '<script type="text/javascript" src="'.$CFG->wwwroot.'/mod/quiz/report/overview/utility.js" />';
|
||||
echo '<form id="attemptsform" method="post" action="report.php" onsubmit="var menu = document.getElementById(\'actionmenu\'); return confirm_if(menu.options[menu.selectedIndex].value == \'delete\', \''.$strreallydel.'\');">';
|
||||
echo '<input type="hidden" name="id" value="'.$cm->id.'" />';
|
||||
|
||||
}
|
||||
|
||||
$table->print_html();
|
||||
|
||||
if(!empty($attempts)) {
|
||||
//There might be a more elegant way than using the <center> tag for this
|
||||
echo '<table id="commands">';
|
||||
echo '<tr><td>';
|
||||
echo '<a href="javascript:select_all();">'.get_string('selectall', 'quiz').'</a> / ';
|
||||
echo '<a href="javascript:deselect_all();">'.get_string('selectnone', 'quiz').'</a> ';
|
||||
echo '</td><td style="text-align: right;">';
|
||||
$options = array('dummy' => ' ', 'delete' => get_string('delete'));
|
||||
$menu = str_replace('<select', '<select id="actionmenu"', choose_from_menu($options, 'action', '', get_string('selectedattempts', 'quiz'), 'if(this.selectedIndex > 1) submitFormById(\'attemptsform\');', '', true));
|
||||
echo $menu;
|
||||
echo '</td></tr></table>';
|
||||
//echo '<noscript id="noscriptactionmenu" style="display: inline;">';
|
||||
//echo '<input type="submit" value="'.get_string('go').'" /></noscript>';
|
||||
//echo '<script type="text/javascript">'."\n<!--\n".'document.getElementById("noscriptactionmenu").style.display = "none";'."\n-->\n".'</script>';
|
||||
echo '</form>';
|
||||
}
|
||||
else {
|
||||
print_heading(get_string('noattemptsmatchingfilter', 'quiz', strtolower($course->students)));
|
||||
}
|
||||
|
||||
echo '<div class="controls">';
|
||||
echo '<form method="report.php">';
|
||||
echo '<p>'.get_string('displayoptions', 'quiz').': ';
|
||||
echo '<input type="hidden" name="id" value="'.$cm->id.'" />';
|
||||
echo '<input type="hidden" name="noattempts" value="0" />';
|
||||
echo '<input type="hidden" name="teacherattempts" value="0" />';
|
||||
echo '<input type="hidden" name="detailedmarks" value="0" />';
|
||||
echo '<input type="checkbox" id="checknoattempts" name="noattempts" '.($noattempts?'checked="checked" ':'').'value="1" /> <label for="checknoattempts">'.get_string('shownoattempts', 'quiz').'</label> ';
|
||||
echo '<input type="checkbox" id="checkteacherattempts" name="teacherattempts" '.($teacherattempts?'checked="checked" ':'').'value="1" /> <label for="checkteacherattempts">'.get_string('showteacherattempts', 'quiz').'</label> ';
|
||||
echo '<input type="checkbox" id="checkdetailedmarks" name="detailedmarks" '.($detailedmarks?'checked="checked" ':'').'value="1" /> <label for="checkdetailedmarks">'.get_string('showdetailedmarks', 'quiz').'</label> ';
|
||||
echo '<input type="submit" value="'.get_string('go').'" />';
|
||||
echo '</p>';
|
||||
echo '</form>';
|
||||
echo '</div>';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
function select_all() {
|
||||
var inputs = document.getElementsByTagName('INPUT');
|
||||
for(var i = 0; i < inputs.length; ++i) {
|
||||
if(inputs[i].type == 'checkbox') {
|
||||
inputs[i].checked = 'checked';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function deselect_all() {
|
||||
var inputs = document.getElementsByTagName('INPUT');
|
||||
for(var i = 0; i < inputs.length; ++i) {
|
||||
if(inputs[i].type == 'checkbox') {
|
||||
inputs[i].checked = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function confirm_if(expr, message) {
|
||||
if(!expr) {
|
||||
return true;
|
||||
}
|
||||
return confirm(message);
|
||||
}
|
||||
Reference in New Issue
Block a user