/** * Makes sure value is a valid grade value. * @param float $gradevalue * @return mixed float or int fixed grade value */ function bounded_grade($gradevalue) { global $CFG; if (is_null($gradevalue)) { return null; } if ($this->gradetype == GRADE_TYPE_SCALE) { // no >100% grades hack for scale grades! // 1.5 is rounded to 2 ;-) return (int) bounded_number($this->grademin, round($gradevalue + 1.0E-5), $this->grademax); } $grademax = $this->grademax; // NOTE: if you change this value you must manually reset the needsupdate flag in all grade items $maxcoef = isset($CFG->gradeoverhundredprocentmax) ? $CFG->gradeoverhundredprocentmax : 10; // 1000% max by default if (!empty($CFG->unlimitedgrades)) { // NOTE: if you change this value you must manually reset the needsupdate flag in all grade items $grademax = $grademax * $maxcoef; } else { if ($this->is_category_item() or $this->is_course_item()) { $category = $this->load_item_category(); if ($category->aggregation >= 100) { // grade >100% hack $grademax = $grademax * $maxcoef; } } } return (double) bounded_number($this->grademin, $gradevalue, $grademax); }
/** * Print footer on admin page - please use normal print_footer() instead */ function admin_externalpage_print_footer() { global $CFG, $PAGE, $SITE, $THEME; define('ADMIN_EXT_FOOTER_PRINTED', 'true'); if (!empty($SITE->fullname)) { $pageblocks = blocks_setup($PAGE); $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]), BLOCK_L_MAX_WIDTH); $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]), BLOCK_R_MAX_WIDTH); $lt = empty($THEME->layouttable) ? array('left', 'middle', 'right') : $THEME->layouttable; foreach ($lt as $column) { if ($column != 'middle') { array_shift($lt); } else { if ($column == 'middle') { break; } } } foreach ($lt as $column) { switch ($column) { case 'left': echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">'; print_container_start(); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT); print_container_end(); echo '</td>'; break; case 'middle': print_container_end(); $THEME->open_header_containers--; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages echo '</td>'; break; case 'right': if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) { echo '<td style="width: ' . $preferred_width_right . 'px;" id="right-column">'; print_container_start(); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT); print_container_end(); echo '</td>'; } break; } } echo '</tr></table>'; } print_footer(); }
function admin_externalpage_print_footer($adminroot) { global $CFG, $PAGE, $SITE, $THEME; if (!empty($SITE->fullname)) { $pageblocks = blocks_setup($PAGE); $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]), BLOCK_R_MAX_WIDTH); $lt = empty($THEME->layouttable) ? array('left', 'middle', 'right') : $THEME->layouttable; foreach ($lt as $column) { if ($column != 'middle') { array_shift($lt); } else { if ($column == 'middle') { break; } } } foreach ($lt as $column) { switch ($column) { case 'left': echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">'; if (!empty($THEME->customcorners)) { print_custom_corners_start(); } blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT); if (!empty($THEME->customcorners)) { print_custom_corners_end(); } echo '</td>'; break; case 'middle': if (!empty($THEME->customcorners)) { print_custom_corners_end(); } echo '</td>'; break; case 'right': if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) { echo '<td style="width: ' . $preferred_width_right . 'px;" id="right-column">'; if (!empty($THEME->customcorners)) { print_custom_corners_start(); } blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT); if (!empty($THEME->customcorners)) { print_custom_corners_end(); } echo '</td>'; } break; } } echo '</tr></table>'; } print_footer(); }
/** * Prints blocks for a given position * * @param array $pageblocks An array of blocks organized by position * @param char $position Position that we are currently printing * @return void **/ function page_print_position($pageblocks, $position, $width) { global $PAGE, $THEME; $editing = $PAGE->user_is_editing(); /// Figure out an appropriate ID switch ($position) { case BLOCK_POS_LEFT: $id = 'left'; break; case BLOCK_POS_RIGHT: $id = 'right'; break; case BLOCK_POS_CENTER: $id = 'middle'; break; default: $id = $position; break; } /// Figure out the width - more for routine than being functional. May want to impose a minimum width though $width = bounded_number($width, blocks_preferred_width($pageblocks[$position]), $width); $widthstyle = ""; if ($width > 1) { $widthstyle = 'style="width: ' . $width . 'px"'; } if ($editing || blocks_have_content($pageblocks, $position)) { /// Print it echo "<td {$widthstyle} id=\"{$id}-column\">"; print_spacer(1, $width, false); if (!empty($THEME->roundcorners)) { echo '<div class="bt"><div></div></div>'; echo '<div class="i1"><div class="i2"><div class="i3">'; } page_blocks_print_group($pageblocks, $position); if (!empty($THEME->roundcorners)) { echo '</div></div></div>'; echo '<div class="bb"><div></div></div>'; } echo '</td>'; } else { // just print space to keep width consistent echo "<td {$widthstyle} id=\"{$id}-column\">"; print_spacer(1, $width, false); echo "</td>"; } }
/** * Returns a letter grade representation of a grade value * The array of grade letters used is produced by {@link grade_get_letters()} using the course context * * @param float $value The grade value * @param object $grade_item Grade item object * @return string */ function grade_format_gradevalue_letter($value, $grade_item) { $context = get_context_instance(CONTEXT_COURSE, $grade_item->courseid); if (!($letters = grade_get_letters($context))) { return ''; // no letters?? } if (is_null($value)) { return '-'; } $value = grade_grade::standardise_score($value, $grade_item->grademin, $grade_item->grademax, 0, 100); $value = bounded_number(0, $value, 100); // just in case foreach ($letters as $boundary => $letter) { if ($value >= $boundary) { return format_string($letter); } } return '-'; // no match? maybe '' would be more correct }
/** * Returns string representation of grade value * @param float $value grade value * @param object $grade_item - by reference to prevent scale reloading * @param bool $localized use localised decimal separator * @param int $display type of display - raw, letter, percentage * @param int $decimalplaces number of decimal places when displaying float values * @return string */ function grade_format_gradevalue($value, &$grade_item, $localized = true, $displaytype = null, $decimals = null) { if ($grade_item->gradetype == GRADE_TYPE_NONE or $grade_item->gradetype == GRADE_TYPE_TEXT) { return ''; } // no grade yet? if (is_null($value)) { return '-'; } if ($grade_item->gradetype != GRADE_TYPE_VALUE and $grade_item->gradetype != GRADE_TYPE_SCALE) { //unknown type?? return ''; } if (is_null($displaytype)) { $displaytype = $grade_item->get_displaytype(); } if (is_null($decimals)) { $decimals = $grade_item->get_decimals(); } switch ($displaytype) { case GRADE_DISPLAY_TYPE_REAL: if ($grade_item->gradetype == GRADE_TYPE_SCALE) { $scale = $grade_item->load_scale(); $value = (int) bounded_number($grade_item->grademin, $value, $grade_item->grademax); return format_string($scale->scale_items[$value - 1]); } else { return format_float($value, $decimals, $localized); } case GRADE_DISPLAY_TYPE_PERCENTAGE: $min = $grade_item->grademin; $max = $grade_item->grademax; if ($min == $max) { return ''; } $value = bounded_number($min, $value, $max); $percentage = ($value - $min) * 100 / ($max - $min); return format_float($percentage, $decimals, $localized) . ' %'; case GRADE_DISPLAY_TYPE_LETTER: $context = get_context_instance(CONTEXT_COURSE, $grade_item->courseid); if (!($letters = grade_get_letters($context))) { return ''; // no letters?? } $value = grade_grade::standardise_score($value, $grade_item->grademin, $grade_item->grademax, 0, 100); $value = bounded_number(0, $value, 100); // just in case foreach ($letters as $boundary => $letter) { if ($value >= $boundary) { return format_string($letter); } } return '-'; // no match? maybe '' would be more correct // no match? maybe '' would be more correct default: return ''; } }
/** * internal function for category grades summing * * @param object $grade * @param int $userid * @param float $oldfinalgrade * @param array $items * @param array $grade_values * @param bool $excluded * @return boolean (just plain return;) */ function sum_grades(&$grade, $oldfinalgrade, $items, $grade_values, $excluded) { // ungraded and exluded items are not used in aggregation foreach ($grade_values as $itemid => $v) { if (is_null($v)) { unset($grade_values[$itemid]); } else { if (in_array($itemid, $excluded)) { unset($grade_values[$itemid]); } } } $max = 0; //find max grade foreach ($items as $item) { if ($item->gradetype != GRADE_TYPE_VALUE) { continue; // sum only items with value grades, no scales and outcomes! } $max += $item->grademax; } if ($this->grade_item->grademax != $max or $this->grade_item->grademin != 0 or $this->grade_item->gradetype != GRADE_TYPE_VALUE) { $this->grade_item->grademax = $max; $this->grade_item->grademin = 0; $this->grade_item->gradetype = GRADE_TYPE_VALUE; $this->grade_item->update('aggregation'); } $this->apply_limit_rules($grade_values); $sum = array_sum($grade_values); $grade->finalgrade = (double) bounded_number($this->grade_item->grademin, $sum, $this->grade_item->grademax); // update in db if changed if ($grade->finalgrade !== $oldfinalgrade) { $grade->update('aggregation'); } return; }
/** * internal function - does the final grade calculation */ function use_formula($userid, $params, $useditems, $oldgrade) { if (empty($userid)) { return true; } // add missing final grade values // not graded (null) is counted as 0 - the spreadsheet way foreach ($useditems as $gi) { if (!array_key_exists('gi' . $gi, $params)) { $params['gi' . $gi] = 0; } else { $params['gi' . $gi] = (double) $params['gi' . $gi]; } } // can not use own final grade during calculation unset($params['gi' . $this->id]); // insert final grade - will be needed later anyway if ($oldgrade) { $oldfinalgrade = $oldgrade->finalgrade; $grade = new grade_grade($oldgrade, false); // fetching from db is not needed $grade->grade_item =& $this; } else { $grade = new grade_grade(array('itemid' => $this->id, 'userid' => $userid), false); $grade->grade_item =& $this; $grade->insert('system'); $oldfinalgrade = null; } // no need to recalculate locked or overridden grades if ($grade->is_locked() or $grade->is_overridden()) { return true; } // do the calculation $this->formula->set_params($params); $result = $this->formula->evaluate(); if ($result === false) { $grade->finalgrade = null; } else { // normalize $result = bounded_number($this->grademin, $result, $this->grademax); if ($this->gradetype == GRADE_TYPE_SCALE) { $result = round($result + 1.0E-5); // round scales upwards } $grade->finalgrade = $result; } // update in db if changed if (grade_floats_different($grade->finalgrade, $oldfinalgrade)) { $grade->update('compute'); } if ($result !== false) { //lock grade if needed } if ($result === false) { return false; } else { return true; } }
/** * Builds and return the HTML rows of the table (grades headed by student). * @return string HTML */ function get_studentshtml() { global $CFG, $USER; $studentshtml = ''; $strfeedback = $this->get_lang_string("feedback"); $strgrade = $this->get_lang_string('grade'); $gradetabindex = 1; $showuserimage = $this->get_pref('showuserimage'); $showuseridnumber = $this->get_pref('showuseridnumber'); $numusers = count($this->users); // Preload scale objects for items with a scaleid $scales_list = ''; $tabindices = array(); foreach ($this->gtree->items as $item) { if (!empty($item->scaleid)) { $scales_list .= "{$item->scaleid},"; } $tabindices[$item->id]['grade'] = $gradetabindex; $tabindices[$item->id]['feedback'] = $gradetabindex + $numusers; $gradetabindex += $numusers * 2; } $scales_array = array(); if (!empty($scales_list)) { $scales_list = substr($scales_list, 0, -1); $scales_array = get_records_list('scale', 'id', $scales_list); } $row_classes = array(' even ', ' odd '); $row_classes = array(' even ', ' odd '); foreach ($this->users as $userid => $user) { if ($this->canviewhidden) { $altered = array(); $unknown = array(); } else { $hiding_affected = grade_grade::get_hiding_affected($this->grades[$userid], $this->gtree->items); $altered = $hiding_affected['altered']; $unknown = $hiding_affected['unknown']; unset($hiding_affected); } $columncount = 0; // Student name and link $user_pic = null; if ($showuserimage) { $user_pic = '<div class="userpic">' . print_user_picture($user, $this->courseid, NULL, 0, true) . '</div>'; } $studentshtml .= '<tr class="r' . $this->rowcount++ . $row_classes[$this->rowcount % 2] . '">' . '<th class="header c' . $columncount++ . ' user" scope="row" onclick="set_row(this.parentNode.rowIndex);">' . $user_pic . '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $user->id . '&course=' . $this->course->id . '">' . fullname($user) . '</a></th>'; if ($showuseridnumber) { $studentshtml .= '<th class="header c' . $columncount++ . ' useridnumber" onclick="set_row(this.parentNode.rowIndex);">' . $user->idnumber . '</a></th>'; } foreach ($this->gtree->items as $itemid => $unused) { $item =& $this->gtree->items[$itemid]; $grade = $this->grades[$userid][$item->id]; // Get the decimal points preference for this item $decimalpoints = $item->get_decimals(); if (in_array($itemid, $unknown)) { $gradeval = null; } else { if (array_key_exists($itemid, $altered)) { $gradeval = $altered[$itemid]; } else { $gradeval = $grade->finalgrade; } } // MDL-11274 // Hide grades in the grader report if the current grader doesn't have 'moodle/grade:viewhidden' if (!$this->canviewhidden and $grade->is_hidden()) { if (!empty($CFG->grade_hiddenasdate) and $grade->get_datesubmitted() and !$item->is_category_item() and !$item->is_course_item()) { // the problem here is that we do not have the time when grade value was modified, 'timemodified' is general modification date for grade_grades records $studentshtml .= '<td class="cell c' . $columncount++ . '"><span class="datesubmitted">' . userdate($grade->get_datesubmitted(), get_string('strftimedatetimeshort')) . '</span></td>'; } else { $studentshtml .= '<td class="cell c' . $columncount++ . '">-</td>'; } continue; } // emulate grade element $eid = $this->gtree->get_grade_eid($grade); $element = array('eid' => $eid, 'object' => $grade, 'type' => 'grade'); $cellclasses = 'cell c' . $columncount++; if ($item->is_category_item()) { $cellclasses .= ' cat'; } if ($item->is_course_item()) { $cellclasses .= ' course'; } if ($grade->is_overridden()) { $cellclasses .= ' overridden'; } if ($grade->is_excluded()) { $cellclasses .= ' excluded'; } $studentshtml .= '<td class="' . $cellclasses . '">'; if ($grade->is_excluded()) { $studentshtml .= get_string('excluded', 'grades') . ' '; } // Do not show any icons if no grade (no record in DB to match) if (!$item->needsupdate and $USER->gradeediting[$this->courseid]) { $studentshtml .= $this->get_icons($element); } $hidden = ''; if ($grade->is_hidden()) { $hidden = ' hidden '; } $gradepass = '******'; if ($grade->is_passed($item)) { $gradepass = '******'; } elseif (is_null($grade->is_passed($item))) { $gradepass = ''; } // if in editting mode, we need to print either a text box // or a drop down (for scales) // grades in item of type grade category or course are not directly editable if ($item->needsupdate) { $studentshtml .= '<span class="gradingerror' . $hidden . '">' . get_string('error') . '</span>'; } else { if ($USER->gradeediting[$this->courseid]) { if ($item->scaleid && !empty($scales_array[$item->scaleid])) { $scale = $scales_array[$item->scaleid]; $gradeval = (int) $gradeval; // scales use only integers $scales = explode(",", $scale->scale); // reindex because scale is off 1 // MDL-12104 some previous scales might have taken up part of the array // so this needs to be reset $scaleopt = array(); $i = 0; foreach ($scales as $scaleoption) { $i++; $scaleopt[$i] = $scaleoption; } if ($this->get_pref('quickgrading') and $grade->is_editable()) { $oldval = empty($gradeval) ? -1 : $gradeval; if (empty($item->outcomeid)) { $nogradestr = $this->get_lang_string('nograde'); } else { $nogradestr = $this->get_lang_string('nooutcome', 'grades'); } $studentshtml .= '<input type="hidden" name="oldgrade_' . $userid . '_' . $item->id . '" value="' . $oldval . '"/>'; $studentshtml .= choose_from_menu($scaleopt, 'grade_' . $userid . '_' . $item->id, $gradeval, $nogradestr, '', '-1', true, false, $tabindices[$item->id]['grade']); } elseif (!empty($scale)) { $scales = explode(",", $scale->scale); // invalid grade if gradeval < 1 if ($gradeval < 1) { $studentshtml .= '<span class="gradevalue' . $hidden . $gradepass . '">-</span>'; } else { $gradeval = (int) bounded_number($grade->grade_item->grademin, $gradeval, $grade->grade_item->grademax); //just in case somebody changes scale $studentshtml .= '<span class="gradevalue' . $hidden . $gradepass . '">' . $scales[$gradeval - 1] . '</span>'; } } else { // no such scale, throw error? } } else { if ($item->gradetype != GRADE_TYPE_TEXT) { // Value type if ($this->get_pref('quickgrading') and $grade->is_editable()) { $value = format_float($gradeval, $decimalpoints); $studentshtml .= '<input type="hidden" name="oldgrade_' . $userid . '_' . $item->id . '" value="' . $value . '" />'; $studentshtml .= '<input size="6" tabindex="' . $tabindices[$item->id]['grade'] . '" type="text" title="' . $strgrade . '" name="grade_' . $userid . '_' . $item->id . '" value="' . $value . '" />'; } else { $studentshtml .= '<span class="gradevalue' . $hidden . $gradepass . '">' . format_float($gradeval, $decimalpoints) . '</span>'; } } } // If quickfeedback is on, print an input element if ($this->get_pref('showquickfeedback') and $grade->is_editable()) { if ($this->get_pref('quickgrading')) { $studentshtml .= '<br />'; } $studentshtml .= '<input type="hidden" name="oldfeedback_' . $userid . '_' . $item->id . '" value="' . s($grade->feedback) . '" />'; $studentshtml .= '<input class="quickfeedback" tabindex="' . $tabindices[$item->id]['feedback'] . '" size="6" title="' . $strfeedback . '" type="text" name="feedback_' . $userid . '_' . $item->id . '" value="' . s($grade->feedback) . '" />'; } } else { // Not editing $gradedisplaytype = $item->get_displaytype(); // If feedback present, surround grade with feedback tooltip: Open span here if (!empty($grade->feedback)) { $overlib = ''; $feedback = addslashes_js(trim(format_string($grade->feedback, $grade->feedbackformat))); $overlib = "return overlib('{$feedback}', BORDER, 0, FGCLASS, 'feedback', " . "CAPTIONFONTCLASS, 'caption', CAPTION, '{$strfeedback}');"; $studentshtml .= '<span onmouseover="' . s($overlib) . '" onmouseout="return nd();">'; } if ($item->needsupdate) { $studentshtml .= '<span class="gradingerror' . $hidden . $gradepass . '">' . get_string('error') . '</span>'; } else { $studentshtml .= '<span class="gradevalue' . $hidden . $gradepass . '">' . grade_format_gradevalue($gradeval, $item, true, $gradedisplaytype, null) . '</span>'; } // Close feedback span if (!empty($grade->feedback)) { $studentshtml .= '</span>'; } } } if (!empty($this->gradeserror[$item->id][$userid])) { $studentshtml .= $this->gradeserror[$item->id][$userid]; } $studentshtml .= '</td>' . "\n"; } $studentshtml .= '</tr>'; } return $studentshtml; }
/** * hook function from inside the theme. * in this case, detect lack of $PAGE and do a horrible hack * to get a consistent page format. */ function tao_local_header_hook() { global $CFG; require_once $CFG->libdir . '/blocklib.php'; require_once $CFG->libdir . '/pagelib.php'; global $PAGE; if (!empty($PAGE)) { return true; } if (defined('ADMIN_STICKYBLOCKS')) { return true; } if (optional_param('inpopup')) { return true; } $lmin = empty($THEME->block_l_min_width) ? 100 : $THEME->block_l_min_width; $lmax = empty($THEME->block_l_max_width) ? 210 : $THEME->block_l_max_width; $rmin = empty($THEME->block_r_min_width) ? 100 : $THEME->block_r_min_width; $rmax = empty($THEME->block_r_max_width) ? 210 : $THEME->block_r_max_width; !defined('BLOCK_L_MIN_WIDTH') && define('BLOCK_L_MIN_WIDTH', $lmin); !defined('BLOCK_L_MAX_WIDTH') && define('BLOCK_L_MAX_WIDTH', $lmax); !defined('BLOCK_R_MIN_WIDTH') && define('BLOCK_R_MIN_WIDTH', $rmin); !defined('BLOCK_R_MAX_WIDTH') && define('BLOCK_R_MAX_WIDTH', $rmax); $PAGE = new tao_page_class_hack(); $pageblocks = blocks_setup($PAGE, true); // we could replace this with a stickyblocks implementation, this is a proof of concept. $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]), BLOCK_L_MAX_WIDTH); echo '<table id="layout-table" summary="layout"> <tr> '; echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">'; ob_start(); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT); $blockscontent = ob_get_clean(); if (!$blockscontent) { $rec = (object) array('id' => 0, 'blockid' => 0, 'pageid' => 0, 'pagetype' => tao_page_class_hack::get_type(), 'position' => BLOCK_POS_LEFT, 'visible' => true, 'configdata' => '', 'weight' => 0); $pageblocks = array(BLOCK_POS_LEFT => array(0 => $rec)); $pageblocks[BLOCK_POS_LEFT][0]->rec = $rec; $pageblocks[BLOCK_POS_LEFT][0]->obj = new tao_dummy_block($rec); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT); } else { echo $blockscontent; } echo '</td>'; echo '<td id="middle-column">'; define('TAO_HEADER_OVERRIDDEN', 1); }
/** * Return array of grade item ids that are either hidden or indirectly depend * on hidden grades, excluded grades are not returned. * THIS IS A REALLY BIG HACK! to be replaced by conditional aggregation of hidden grades in 2.0 * * @static * @param array $grades all course grades of one user, & used for better internal caching * @param array $items $grade_items array of grade items, & used for better internal caching * @return array */ function get_hiding_affected(&$grade_grades, &$grade_items) { global $CFG; if (count($grade_grades) !== count($grade_items)) { error('Incorrect size of arrays in params of grade_grade::get_hiding_affected()!'); } $dependson = array(); $todo = array(); $unknown = array(); // can not find altered $altered = array(); // altered grades $hiddenfound = false; foreach ($grade_grades as $itemid => $unused) { $grade_grade =& $grade_grades[$itemid]; if ($grade_grade->is_excluded()) { //nothing to do, aggregation is ok } else { if ($grade_grade->is_hidden()) { $hiddenfound = true; $altered[$grade_grade->itemid] = null; } else { if ($grade_grade->is_locked() or $grade_grade->is_overridden()) { // no need to recalculate locked or overridden grades } else { $dependson[$grade_grade->itemid] = $grade_items[$grade_grade->itemid]->depends_on(); if (!empty($dependson[$grade_grade->itemid])) { $todo[] = $grade_grade->itemid; } } } } } if (!$hiddenfound) { return array('unknown' => array(), 'altered' => array()); } $max = count($todo); for ($i = 0; $i < $max; $i++) { $found = false; foreach ($todo as $key => $do) { if (array_intersect($dependson[$do], $unknown)) { // this item depends on hidden grade indirectly $unknown[$do] = $do; unset($todo[$key]); $found = true; continue; } else { if (!array_intersect($dependson[$do], $todo)) { if (!array_intersect($dependson[$do], array_keys($altered))) { // hiding does not affect this grade unset($todo[$key]); $found = true; continue; } else { // depends on altered grades - we should try to recalculate if possible if ($grade_items[$do]->is_calculated() or !$grade_items[$do]->is_category_item() and !$grade_items[$do]->is_course_item()) { $unknown[$do] = $do; unset($todo[$key]); $found = true; continue; } else { $grade_category = $grade_items[$do]->load_item_category(); $values = array(); foreach ($dependson[$do] as $itemid) { if (array_key_exists($itemid, $altered)) { $values[$itemid] = $altered[$itemid]; } else { $values[$itemid] = $grade_grades[$itemid]->finalgrade; } } foreach ($values as $itemid => $value) { if ($grade_grades[$itemid]->is_excluded()) { unset($values[$itemid]); continue; } $values[$itemid] = grade_grade::standardise_score($value, $grade_items[$itemid]->grademin, $grade_items[$itemid]->grademax, 0, 1); } if ($grade_category->aggregateonlygraded) { foreach ($values as $itemid => $value) { if (is_null($value)) { unset($values[$itemid]); } } } else { foreach ($values as $itemid => $value) { if (is_null($value)) { $values[$itemid] = 0; } } } // limit and sort $grade_category->apply_limit_rules($values); asort($values, SORT_NUMERIC); // let's see we have still enough grades to do any statistics if (count($values) == 0) { // not enough attempts yet $altered[$do] = null; unset($todo[$key]); $found = true; continue; } $agg_grade = $grade_category->aggregate_values($values, $grade_items); // recalculate the rawgrade back to requested range $finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $grade_items[$do]->grademin, $grade_items[$do]->grademax); if (!is_null($finalgrade)) { $finalgrade = bounded_number($grade_items[$do]->grademin, $finalgrade, $grade_items[$do]->grademax); } $altered[$do] = $finalgrade; unset($todo[$key]); $found = true; continue; } } } } } if (!$found) { break; } } return array('unknown' => $unknown, 'altered' => $altered); }
/** * Prints blocks for a given position * * @param array $pageblocks An array of blocks organized by position * @param char $position Position that we are currently printing * @return void **/ function page_print_position($pageblocks, $position, $width) { global $PAGE, $THEME; $editing = $PAGE->user_is_editing(); if ($editing || blocks_have_content($pageblocks, $position)) { /// Figure out an appropriate ID switch ($position) { case BLOCK_POS_LEFT: $id = 'left'; break; case BLOCK_POS_RIGHT: $id = 'right'; break; case BLOCK_POS_CENTER: $id = 'middle'; break; default: $id = $position; break; } /// Figure out the width - more for routine than being functional. May want to impose a minimum width though $width = bounded_number($width, blocks_preferred_width($pageblocks[$position]), $width); /// Print it if (is_numeric($width)) { // default to px MR-263 $tdwidth = $width . 'px'; } else { $tdwidth = $width; } echo "<td style=\"width: {$tdwidth}\" id=\"{$id}-column\">"; if (is_numeric($width) or strpos($width, 'px')) { print_spacer(1, $width, false); } print_container_start(); if ($position == BLOCK_POS_CENTER) { echo skip_main_destination(); page_frontpage_settings(); } page_blocks_print_group($pageblocks, $position); print_container_end(); echo '</td>'; } else { // Empty column - no class, style or width /// Figure out an appropriate ID switch ($position) { case BLOCK_POS_LEFT: $id = 'left'; break; case BLOCK_POS_RIGHT: $id = 'right'; break; case BLOCK_POS_CENTER: $id = 'middle'; break; default: $id = $position; break; } // we still want to preserve values unles if ($width != '0') { if (is_numeric($width)) { // default to px MR-263 $tdwidth = $width . 'px'; } else { $tdwidth = $width; } echo '<td style="width:' . $tdwidth . '" id="' . $id . '-column" > '; if ($width != '0' and is_numeric($width) or strpos($width, 'px')) { print_spacer(1, $width, false); } echo "</td>"; } else { echo '<td></td>'; // 0 means no column anyway } } }
/** * Builds and return the HTML rows of the table (grades headed by student). * @return string HTML */ function get_studentshtml() { global $CFG, $USER; $studentshtml = ''; $strfeedback = $this->get_lang_string("feedback"); $strgrade = $this->get_lang_string('grade'); $gradetabindex = 1; $showuserimage = $this->get_pref('showuserimage'); $numusers = count($this->users); // Preload scale objects for items with a scaleid $scales_list = ''; $tabindices = array(); foreach ($this->items as $item) { if (!empty($item->scaleid)) { $scales_list .= "{$item->scaleid},"; } $tabindices[$item->id]['grade'] = $gradetabindex; $tabindices[$item->id]['feedback'] = $gradetabindex + $numusers; $gradetabindex += $numusers * 2; } $scales_array = array(); if (!empty($scales_list)) { $scales_list = substr($scales_list, 0, -1); $scales_array = get_records_list('scale', 'id', $scales_list); } $canviewhidden = has_capability('moodle/grade:viewhidden', get_context_instance(CONTEXT_COURSE, $this->course->id)); foreach ($this->users as $userid => $user) { $columncount = 0; // Student name and link $user_pic = null; if ($showuserimage) { $user_pic = '<div class="userpic">' . print_user_picture($user->id, $this->courseid, true, 0, true) . '</div>'; } $studentshtml .= '<tr class="r' . $this->rowcount++ . '"><th class="header c' . $columncount++ . ' user" scope="row">' . $user_pic . '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $user->id . '">' . fullname($user) . '</a></th>'; foreach ($this->items as $itemid => $item) { // Get the decimal points preference for this item $decimalpoints = $item->get_decimals(); if (isset($this->finalgrades[$userid][$item->id])) { $gradeval = $this->finalgrades[$userid][$item->id]->finalgrade; $grade = new grade_grade($this->finalgrades[$userid][$item->id], false); $grade->feedback = stripslashes_safe($this->finalgrades[$userid][$item->id]->feedback); $grade->feedbackformat = $this->finalgrades[$userid][$item->id]->feedbackformat; } else { $gradeval = null; $grade = new grade_grade(array('userid' => $userid, 'itemid' => $item->id), false); $grade->feedback = ''; } // MDL-11274 // Hide grades in the grader report if the current grader doesn't have 'moodle/grade:viewhidden' if ($grade->is_hidden() && !$canviewhidden) { if (isset($grade->finalgrade)) { $studentshtml .= '<td class="cell c' . $columncount++ . '">' . userdate($grade->timecreated, get_string('strftimedatetimeshort')) . '</td>'; } else { $studentshtml .= '<td class="cell c' . $columncount++ . '">-</td>'; } continue; } $grade->courseid = $this->courseid; $grade->grade_item =& $this->items[$itemid]; // this speedsup is_hidden() and other grade_grade methods // emulate grade element $eid = $this->gtree->get_grade_eid($grade); $element = array('eid' => $eid, 'object' => $grade, 'type' => 'grade'); if ($grade->is_overridden()) { $studentshtml .= '<td class="overridden cell c' . $columncount++ . '">'; } else { $studentshtml .= '<td class="cell c' . $columncount++ . '">'; } if ($grade->is_excluded()) { $studentshtml .= get_string('excluded', 'grades'); // TODO: improve visual representation of excluded grades } // Do not show any icons if no grade (no record in DB to match) if (!$item->needsupdate and $USER->gradeediting[$this->courseid]) { $studentshtml .= $this->get_icons($element); } // if in editting mode, we need to print either a text box // or a drop down (for scales) // grades in item of type grade category or course are not directly editable if ($item->needsupdate) { $studentshtml .= '<span class="gradingerror">' . get_string('error') . '</span>'; } else { if ($USER->gradeediting[$this->courseid]) { // We need to retrieve each grade_grade object from DB in order to // know if they are hidden/locked if ($item->scaleid && !empty($scales_array[$item->scaleid])) { $scale = $scales_array[$item->scaleid]; $scales = explode(",", $scale->scale); // reindex because scale is off 1 $i = 0; foreach ($scales as $scaleoption) { $i++; $scaleopt[$i] = $scaleoption; } if ($this->get_pref('quickgrading') and $grade->is_editable()) { $oldval = empty($gradeval) ? -1 : $gradeval; if (empty($item->outcomeid)) { $nogradestr = $this->get_lang_string('nograde'); } else { $nogradestr = $this->get_lang_string('nooutcome', 'grades'); } $studentshtml .= '<input type="hidden" name="oldgrade_' . $userid . '_' . $item->id . '" value="' . $oldval . '"/>'; $studentshtml .= choose_from_menu($scaleopt, 'grade_' . $userid . '_' . $item->id, $gradeval, $nogradestr, '', '-1', true, false, $tabindices[$item->id]['grade']); } elseif (!empty($scale)) { $scales = explode(",", $scale->scale); // invalid grade if gradeval < 1 if ((int) $gradeval < 1) { $studentshtml .= '-'; } else { $gradeval = (int) bounded_number($grade->grade_item->grademin, $gradeval, $grade->grade_item->grademax); //just in case somebody changes scale $studentshtml .= $scales[$gradeval - 1]; } } else { // no such scale, throw error? } } else { if ($item->gradetype != GRADE_TYPE_TEXT) { // Value type if ($this->get_pref('quickgrading') and $grade->is_editable()) { $value = format_float($gradeval, $decimalpoints); $studentshtml .= '<input type="hidden" name="oldgrade_' . $userid . '_' . $item->id . '" value="' . $value . '" />'; $studentshtml .= '<input size="6" tabindex="' . $tabindices[$item->id]['grade'] . '" type="text" title="' . $strgrade . '" name="grade_' . $userid . '_' . $item->id . '" value="' . $value . '" />'; } else { $studentshtml .= format_float($gradeval, $decimalpoints); } } } // If quickfeedback is on, print an input element if ($this->get_pref('quickfeedback') and $grade->is_editable()) { if ($this->get_pref('quickgrading')) { $studentshtml .= '<br />'; } $studentshtml .= '<input type="hidden" name="oldfeedback_' . $userid . '_' . $item->id . '" value="' . s($grade->feedback) . '" />'; $studentshtml .= '<input class="quickfeedback" tabindex="' . $tabindices[$item->id]['feedback'] . '" size="6" title="' . $strfeedback . '" type="text" name="feedback_' . $userid . '_' . $item->id . '" value="' . s($grade->feedback) . '" />'; } } else { // Not editing $gradedisplaytype = $item->get_displaytype(); $percentsign = ''; $grademin = $item->grademin; $grademax = $item->grademax; // If feedback present, surround grade with feedback tooltip: Open span here if (!empty($grade->feedback)) { $overlib = ''; if ($grade->feedbackformat == 1) { $overlib = "return overlib('" . s(ltrim($grade->feedback)) . "', FULLHTML);"; } else { $overlib = "return overlib('" . s($grade->feedback) . "', BORDER, 0, FGCLASS, 'feedback', " . "CAPTIONFONTCLASS, 'caption', CAPTION, '{$strfeedback}');"; } $studentshtml .= '<span onmouseover="' . $overlib . '" onmouseout="return nd();">'; } if ($item->needsupdate) { $studentshtml .= '<span class="gradingerror">' . get_string('error') . '</span>'; } elseif ($item->scaleid && !empty($scales_array[$item->scaleid])) { $scale = $scales_array[$item->scaleid]; $scales = explode(",", $scale->scale); // invalid grade if gradeval < 1 if ((int) $gradeval < 1) { $studentshtml .= '-'; } else { $studentshtml .= $scales[$gradeval - 1]; } } else { if (is_null($gradeval)) { $studentshtml .= '-'; } else { $studentshtml .= grade_format_gradevalue($gradeval, $item, true, $gradedisplaytype, null); } } // Close feedback span if (!empty($grade->feedback)) { $studentshtml .= '</span>'; } } } if (!empty($this->gradeserror[$item->id][$userid])) { $studentshtml .= $this->gradeserror[$item->id][$userid]; } $studentshtml .= '</td>' . "\n"; } $studentshtml .= '</tr>'; } return $studentshtml; }
/** * Finish displaying the resource with the course blocks */ function display_course_blocks_end() { global $CFG; global $THEME; $PAGE = $this->PAGE; $pageblocks = blocks_setup($PAGE); $blocks_preferred_width = bounded_number(180, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]), 210); $lt = empty($THEME->layouttable) ? array('left', 'middle', 'right') : $THEME->layouttable; foreach ($lt as $column) { if ($column != 'middle') { array_shift($lt); } else { if ($column == 'middle') { break; } } } foreach ($lt as $column) { switch ($column) { case 'left': if (blocks_have_content($pageblocks, BLOCK_POS_LEFT) || $PAGE->user_is_editing()) { echo '<td style="width: ' . $blocks_preferred_width . 'px;" id="left-column">'; print_container_start(); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT); print_container_end(); echo '</td>'; } break; case 'middle': echo '</div>'; print_container_end(); echo '</td>'; break; case 'right': if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT) || $PAGE->user_is_editing()) { echo '<td style="width: ' . $blocks_preferred_width . 'px;" id="right-column">'; print_container_start(); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT); print_container_end(); echo '</td>'; } break; } } echo '</tr></table>'; print_footer($this->course); }
// for choose_from_menu $options = array(); foreach ($pagetypes as $p) { $options[$p['id']] = $p['name']; } require_login(); require_capability('moodle/site:manageblocks', get_context_instance(CONTEXT_SYSTEM, SITEID)); // first thing to do is print the dropdown menu $strtitle = get_string('stickyblocks', 'admin'); $strheading = get_string('adminhelpstickyblocks'); if (!empty($pt)) { require_once $CFG->dirroot . $pagetypes[$pt]['lib']; define('ADMIN_STICKYBLOCKS', $pt); $PAGE = page_create_object($pt, SITEID); $blocks = blocks_setup($PAGE, BLOCKS_PINNED_TRUE); $blocks_preferred_width = bounded_number(180, blocks_preferred_width($blocks[BLOCK_POS_LEFT]), 210); $navlinks = array(array('name' => get_string('administration'), 'link' => "{$CFG->wwwroot}/{$CFG->admin}/index.php", 'type' => 'misc')); $navlinks[] = array('name' => $strtitle, 'link' => null, 'type' => 'misc'); $navigation = build_navigation($navlinks); print_header($strtitle, $strtitle, $navigation); echo '<table border="0" cellpadding="3" cellspacing="0" width="100%" id="layout-table">'; echo '<tr valign="top">'; echo '<td valign="top" style="width: ' . $blocks_preferred_width . 'px;" id="left-column">'; if (!empty($THEME->customcorners)) { print_custom_corners_start(); } blocks_print_group($PAGE, $blocks, BLOCK_POS_LEFT); if (!empty($THEME->customcorners)) { print_custom_corners_end(); } echo '</td>';
/** * internal function for category grades summing * * @param object $grade * @param int $userid * @param float $oldfinalgrade * @param array $items * @param array $grade_values * @param bool $excluded * @return boolean (just plain return;) */ function sum_grades(&$grade, $oldfinalgrade, $items, $grade_values, $excluded) { // ungraded and exluded items are not used in aggregation foreach ($grade_values as $itemid => $v) { if (is_null($v)) { unset($grade_values[$itemid]); } else { if (in_array($itemid, $excluded)) { unset($grade_values[$itemid]); } } } // use 0 if grade missing, droplow used and aggregating all items if (!$this->aggregateonlygraded and !empty($this->droplow)) { foreach ($items as $itemid => $value) { if (!isset($grade_values[$itemid]) and !in_array($itemid, $excluded)) { $grade_values[$itemid] = 0; } } } $max = 0; //find max grade foreach ($items as $item) { if ($item->aggregationcoef > 0) { // extra credit from this activity - does not affect total continue; } if ($item->gradetype == GRADE_TYPE_VALUE) { $max += $item->grademax; } else { if ($item->gradetype == GRADE_TYPE_SCALE) { $max += $item->grademax - 1; // scales min is 1 } } } if ($this->grade_item->grademax != $max or $this->grade_item->grademin != 0 or $this->grade_item->gradetype != GRADE_TYPE_VALUE) { $this->grade_item->grademax = $max; $this->grade_item->grademin = 0; $this->grade_item->gradetype = GRADE_TYPE_VALUE; $this->grade_item->update('aggregation'); } $this->apply_limit_rules($grade_values); $sum = array_sum($grade_values); $grade->finalgrade = bounded_number($this->grade_item->grademin, $sum, $this->grade_item->grademax); // update in db if changed if (grade_floats_different($grade->finalgrade, $oldfinalgrade)) { $grade->update('aggregation'); } return; }
/** * Finish displaying the resource with the course blocks */ function display_course_blocks_end() { global $CFG; $PAGE = $this->PAGE; $pageblocks = blocks_setup($PAGE); $blocks_preferred_width = bounded_number(180, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]), 210); echo '</div>'; if (!empty($THEME->customcorners)) { print_custom_corners_end(); } echo '</td>'; if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT) || $PAGE->user_is_editing()) { echo '<td style="width: ' . $blocks_preferred_width . 'px;" id="right-column">'; if (!empty($THEME->customcorners)) { print_custom_corners_start(); } blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT); if (!empty($THEME->customcorners)) { print_custom_corners_end(); } echo '</td>'; } echo '</tr></table>'; print_footer($this->course); }
/** * Prints the page footer. */ public function print_footer() { global $PAGE; // Can only register if not logged in... echo '</td>'; $blocks_preferred_width = bounded_number(180, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]), 210); if (blocks_have_content($this->pageblocks, BLOCK_POS_RIGHT) || $PAGE->user_is_editing()) { echo '<td style="vertical-align: top; width: ' . $blocks_preferred_width . 'px;" id="right-column">'; blocks_print_group($PAGE, $this->pageblocks, BLOCK_POS_RIGHT); echo '</td>'; } /// Finish the page echo '</tr></table>'; print_footer(); }
/** * Retuns the HTML table cell for a user's grade for a grade_item * * @param object $user * @param int $itemid * @param int $columncount * @param int $nexttabindex * @param array $altered * @param array $unknown * * @return string */ function get_gradecellhtml($user, $itemid, $columncount, $nexttabindex, $altered = array(), $unknown = array()) { global $CFG, $USER; $strfeedback = $this->get_lang_string("feedback"); $strgrade = $this->get_lang_string('grade'); // Preload scale objects for items with a scaleid $scales_array = $this->get_scales_array(); $userid = $user->id; $item =& $this->gtree->items[$itemid]; $grade = $this->grades[$userid][$item->id]; // Get the decimal points preference for this item $decimalpoints = $item->get_decimals(); if (in_array($itemid, $unknown)) { $gradeval = null; } else { if (array_key_exists($itemid, $altered)) { $gradeval = $altered[$itemid]; } else { $gradeval = $grade->finalgrade; } } $gradecellhtml = ''; // MDL-11274 // Hide grades in the grader report if the current grader doesn't have 'moodle/grade:viewhidden' if (!$this->canviewhidden and $grade->is_hidden()) { if (!empty($CFG->grade_hiddenasdate) and $grade->get_datesubmitted() and !$item->is_category_item() and !$item->is_course_item()) { // the problem here is that we do not have the time when grade value was modified, 'timemodified' is general modification date for grade_grades records $gradecellhtml .= '<td class="cell c' . $columncount++ . '"><span class="datesubmitted">' . userdate($grade->get_datesubmitted(), get_string('strftimedatetimeshort')) . '</span></td>'; } else { $gradecellhtml .= '<td class="cell c' . $columncount++ . '">-</td>'; } continue; } // emulate grade element $eid = $this->gtree->get_grade_eid($grade); $element = array('eid' => $eid, 'object' => $grade, 'type' => 'grade'); $cellclasses = 'grade ajax cell c' . $columncount++; if ($item->is_category_item()) { $cellclasses .= ' cat'; } if ($item->is_course_item()) { $cellclasses .= ' course'; } if ($grade->is_overridden()) { $cellclasses .= ' overridden'; } if ($grade->is_excluded()) { $cellclasses .= ' excluded'; } $grade_title = '<div class="fullname">' . fullname($user) . '</div>'; $grade_title .= '<div class="itemname">' . $item->get_name(true) . '</div>'; if (!empty($grade->feedback) && !$USER->gradeediting[$this->courseid]) { $grade_title .= '<div class="feedback">' . wordwrap(trim(format_string($grade->feedback, $grade->feedbackformat)), 34, '<br/ >') . '</div>'; } $gradecellhtml .= "<td id=\"gradecell_u{$userid}-i{$itemid}\" class=\"{$cellclasses}\" title=\"{$grade_title}\">"; if ($grade->is_excluded()) { $gradecellhtml .= get_string('excluded', 'grades') . ' '; } // Do not show any icons if no grade (no record in DB to match) if (!$item->needsupdate and $USER->gradeediting[$this->courseid]) { $gradecellhtml .= $this->get_icons($element); // Add a class to the icon so that it floats left $gradecellhtml = str_replace('class="iconsmall"', 'class="iconsmall ajax"', $gradecellhtml); } $hidden = ''; if ($grade->is_hidden()) { $hidden = ' hidden '; } $gradepass = '******'; if ($grade->is_passed($item)) { $gradepass = '******'; } elseif (is_null($grade->is_passed($item))) { $gradepass = ''; } // if in editting mode, we need to print either a text box // or a drop down (for scales) // grades in item of type grade category or course are not directly editable if ($item->needsupdate) { $gradecellhtml .= '<span class="gradingerror' . $hidden . '">' . get_string('error') . '</span>'; } else { if ($USER->gradeediting[$this->courseid]) { $anchor_id = "gradevalue_{$userid}-i{$itemid}"; if ($item->scaleid && !empty($scales_array[$item->scaleid])) { $scale = $scales_array[$item->scaleid]; $gradeval = (int) $gradeval; // scales use only integers $scales = explode(",", $scale->scale); // reindex because scale is off 1 // MDL-12104 some previous scales might have taken up part of the array // so this needs to be reset $scaleopt = array(); $i = 0; foreach ($scales as $scaleoption) { $i++; $scaleopt[$i] = $scaleoption; } if ($this->get_pref('quickgrading') and $grade->is_editable()) { $oldval = empty($gradeval) ? -1 : $gradeval; if (empty($item->outcomeid)) { $nogradestr = $this->get_lang_string('nograde'); } else { $nogradestr = $this->get_lang_string('nooutcome', 'grades'); } $gradecellhtml .= '<select name="grade_' . $userid . '_' . $item->id . '" class="gradescale editable" ' . 'id="gradescale_' . $userid . '-i' . $item->id . '" tabindex="' . $nexttabindex . '">' . "\n"; $gradecellhtml .= '<option value="-1">' . $nogradestr . "</option>\n"; foreach ($scaleopt as $val => $label) { $selected = ''; if ($val == $oldval) { $selected = 'selected="selected"'; } $gradecellhtml .= "<option value=\"{$val}\" {$selected}>{$label}</option>\n"; } $gradecellhtml .= "</select>\n"; } elseif (!empty($scale)) { $scales = explode(",", $scale->scale); // invalid grade if gradeval < 1 if ($gradeval < 1) { $gradecellhtml .= '<a tabindex="' . $nexttabindex . '" id="' . $anchor_id . '" class="gradevalue' . $hidden . $gradepass . '">-</a>'; } else { //just in case somebody changes scale $gradeval = (int) bounded_number($grade->grade_item->grademin, $gradeval, $grade->grade_item->grademax); $gradecellhtml .= '<a tabindex="' . $nexttabindex . '" id="' . $anchor_id . '" class="gradevalue' . $hidden . $gradepass . '">' . $scales[$gradeval - 1] . '</a>'; } } else { // no such scale, throw error? } } else { if ($item->gradetype != GRADE_TYPE_TEXT) { // Value type $value = $gradeval; if ($this->get_pref('quickgrading') and $grade->is_editable()) { $gradecellhtml .= '<a tabindex="' . $nexttabindex . '" id="' . $anchor_id . '" class="gradevalue' . $hidden . $gradepass . ' editable">' . $value . '</a>'; } else { $gradecellhtml .= '<a tabindex="' . $nexttabindex . '" id="' . $anchor_id . '" class="gradevalue' . $hidden . $gradepass . '">' . $value . '</a>'; } } } // If quickfeedback is on, print an input element if ($this->get_pref('showquickfeedback') and $grade->is_editable()) { if ($this->get_pref('quickgrading')) { $gradecellhtml .= '<br />'; } $feedback = s($grade->feedback); $anchor_id = "gradefeedback_{$userid}-i{$itemid}"; $gradecellhtml .= '<a '; if (empty($feedback)) { $feedback = get_string('addfeedback', 'grades'); } $feedback_tabindex = $nexttabindex + $this->numusers; $short_feedback = shorten_text($feedback, $this->feedback_trunc_length); $gradecellhtml .= ' tabindex="' . $feedback_tabindex . '" id="' . $anchor_id . '" class="gradefeedback editable">' . $short_feedback . '</a>'; $this->feedbacks[$userid][$item->id] = $feedback; } } else { // Not editing $gradedisplaytype = $item->get_displaytype(); if ($item->needsupdate) { $gradecellhtml .= '<span class="gradingerror' . $hidden . $gradepass . '">' . get_string('error') . '</span>'; } else { $gradecellhtml .= '<span class="gradevalue' . $hidden . $gradepass . '">' . grade_format_gradevalue($gradeval, $item, true, $gradedisplaytype, null) . '</span>'; } // Close feedback span if (!empty($grade->feedback)) { $gradecellhtml .= '</span>'; } } } if (!empty($this->gradeserror[$item->id][$userid])) { $gradecellhtml .= $this->gradeserror[$item->id][$userid]; } $gradecellhtml .= '</td>' . "\n"; return $gradecellhtml; }
} else { $courses[$c->id]->lastaccess = 0; } } if (empty($courses)) { print_simple_box(get_string('nocourses', 'my'), 'center'); } else { print_overview($courses); } // if more than 20 courses if (count($courses) > 20) { echo '<br />...'; } print_container_end(); echo '</td>'; break; case 'right': $blocks_preferred_width = bounded_number(180, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]), 210); if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT) || $PAGE->user_is_editing()) { echo '<td style="vertical-align: top; width: ' . $blocks_preferred_width . 'px;" id="right-column">'; print_container_start(); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT); print_container_end(); echo '</td>'; } break; } } /// Finish the page echo '</tr></table>'; print_footer();
/** * Returns a letter grade representation of a grade value * The array of grade letters used is produced by {@link grade_get_letters()} using the course context * * @param float $value The grade value * @param object $grade_item Grade item object * @return string */ function grade_format_gradevalue_letter($value, $grade_item) { global $CFG; $context = context_course::instance($grade_item->courseid, IGNORE_MISSING); if (!($letters = grade_get_letters($context))) { return ''; // no letters?? } if (is_null($value)) { return '-'; } $value = grade_grade::standardise_score($value, $grade_item->grademin, $grade_item->grademax, 0, 100); $value = bounded_number(0, $value, 100); // just in case $gradebookcalculationsfreeze = 'gradebook_calculations_freeze_' . $grade_item->courseid; foreach ($letters as $boundary => $letter) { if (property_exists($CFG, $gradebookcalculationsfreeze) && (int) $CFG->{$gradebookcalculationsfreeze} <= 20160518) { // Do nothing. } else { // The boundary is a percentage out of 100 so use 0 as the min and 100 as the max. $boundary = grade_grade::standardise_score($boundary, 0, 100, 0, 100); } if ($value >= $boundary) { return format_string($letter); } } return '-'; // no match? maybe '' would be more correct }
if (!empty($USER->id)) { add_to_log(SITEID, 'course', 'view', 'view.php?id=' . SITEID, SITEID); } if (empty($CFG->langmenu)) { $langmenu = ''; } else { $currlang = current_language(); $langs = get_list_of_languages(); $langlabel = get_accesshide(get_string('language')); $langmenu = popup_form($CFG->wwwroot . '/index.php?lang=', $langs, 'chooselang', $currlang, '', '', '', true, 'self', $langlabel); } $PAGE = page_create_object(PAGE_COURSE_VIEW, SITEID); $pageblocks = blocks_setup($PAGE); $editing = $PAGE->user_is_editing(); $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]), BLOCK_L_MAX_WIDTH); $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]), BLOCK_R_MAX_WIDTH); print_header($SITE->fullname, $SITE->fullname, 'home', '', '<meta name="description" content="' . strip_tags(format_text($SITE->summary, FORMAT_HTML)) . '" />', true, '', user_login_string($SITE) . $langmenu); ?> <table id="layout-table" summary="layout"> <tr> <?php $lt = empty($THEME->layouttable) ? array('left', 'middle', 'right') : $THEME->layouttable; foreach ($lt as $column) { switch ($column) { case 'left': if (blocks_have_content($pageblocks, BLOCK_POS_LEFT) || $editing) { echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">'; print_container_start(); blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
/** * internal function for category grades aggregation */ function aggregate_grades($userid, $items, $grade_values, $oldgrade, $excluded) { global $CFG; if (empty($userid)) { //ignore first call return; } if ($oldgrade) { $grade = new grade_grade($oldgrade, false); $grade->grade_item =& $this->grade_item; } else { // insert final grade - it will be needed later anyway $grade = new grade_grade(array('itemid' => $this->grade_item->id, 'userid' => $userid), false); $grade->insert('system'); $grade->grade_item =& $this->grade_item; $oldgrade = new object(); $oldgrade->finalgrade = $grade->finalgrade; $oldgrade->rawgrade = $grade->rawgrade; $oldgrade->rawgrademin = $grade->rawgrademin; $oldgrade->rawgrademax = $grade->rawgrademax; $oldgrade->rawscaleid = $grade->rawscaleid; } // no need to recalculate locked or overridden grades if ($grade->is_locked() or $grade->is_overridden()) { return; } // can not use own final category grade in calculation unset($grade_values[$this->grade_item->id]); // if no grades calculation possible or grading not allowed clear both final and raw if (empty($grade_values) or empty($items) or $this->grade_item->gradetype != GRADE_TYPE_VALUE and $this->grade_item->gradetype != GRADE_TYPE_SCALE) { $grade->finalgrade = null; $grade->rawgrade = null; if ($grade->finalgrade !== $oldgrade->finalgrade or $grade->rawgrade !== $oldgrade->rawgrade) { $grade->update('system'); } return; } /// normalize the grades first - all will have value 0...1 // ungraded items are not used in aggregation foreach ($grade_values as $itemid => $v) { if (is_null($v)) { // null means no grade unset($grade_values[$itemid]); continue; } else { if (in_array($itemid, $excluded)) { unset($grade_values[$itemid]); continue; } } $grade_values[$itemid] = grade_grade::standardise_score($v, $items[$itemid]->grademin, $items[$itemid]->grademax, 0, 1); } // If global aggregateonlygraded is set, override category value if ($CFG->grade_aggregateonlygraded != -1) { $this->aggregateonlygraded = $CFG->grade_aggregateonlygraded; } // use min grade if grade missing for these types if (!$this->aggregateonlygraded) { foreach ($items as $itemid => $value) { if (!isset($grade_values[$itemid]) and !in_array($itemid, $excluded)) { $grade_values[$itemid] = 0; } } } // limit and sort $this->apply_limit_rules($grade_values); asort($grade_values, SORT_NUMERIC); // let's see we have still enough grades to do any statistics if (count($grade_values) == 0) { // not enough attempts yet $grade->finalgrade = null; $grade->rawgrade = null; if ($grade->finalgrade !== $oldgrade->finalgrade or $grade->rawgrade !== $oldgrade->rawgrade) { $grade->update('system'); } return; } /// start the aggregation switch ($this->aggregation) { case GRADE_AGGREGATE_MEDIAN: // Middle point value in the set: ignores frequencies $num = count($grade_values); $grades = array_values($grade_values); if ($num % 2 == 0) { $agg_grade = ($grades[intval($num / 2) - 1] + $grades[intval($num / 2)]) / 2; } else { $agg_grade = $grades[intval($num / 2 - 0.5)]; } break; case GRADE_AGGREGATE_MIN: $agg_grade = reset($grade_values); break; case GRADE_AGGREGATE_MAX: $agg_grade = array_pop($grade_values); break; case GRADE_AGGREGATE_MODE: // the most common value, average used if multimode $freq = array_count_values($grade_values); arsort($freq); // sort by frequency keeping keys $top = reset($freq); // highest frequency count $modes = array_keys($freq, $top); // search for all modes (have the same highest count) rsort($modes, SORT_NUMERIC); // get highes mode $agg_grade = reset($modes); break; case GRADE_AGGREGATE_WEIGHTED_MEAN: // Weighted average of all existing final grades $weightsum = 0; $sum = 0; foreach ($grade_values as $itemid => $grade_value) { if ($items[$itemid]->aggregationcoef <= 0) { continue; } $weightsum += $items[$itemid]->aggregationcoef; $sum += $items[$itemid]->aggregationcoef * $grade_value; } if ($weightsum == 0) { $agg_grade = null; } else { $agg_grade = $sum / $weightsum; } break; case GRADE_AGGREGATE_EXTRACREDIT_MEAN: // special average $num = 0; $sum = 0; foreach ($grade_values as $itemid => $grade_value) { if ($items[$itemid]->aggregationcoef == 0) { $num += 1; $sum += $grade_value; } else { if ($items[$itemid]->aggregationcoef > 0) { $sum += $items[$itemid]->aggregationcoef * $grade_value; } } } if ($num == 0) { $agg_grade = $sum; // only extra credits or wrong coefs } else { $agg_grade = $sum / $num; } break; case GRADE_AGGREGATE_MEAN: // Arithmetic average of all grade items (if ungraded aggregated, NULL counted as minimum) // Arithmetic average of all grade items (if ungraded aggregated, NULL counted as minimum) default: $num = count($grade_values); $sum = array_sum($grade_values); $agg_grade = $sum / $num; break; } /// prepare update of new raw grade $grade->rawgrademin = $this->grade_item->grademin; $grade->rawgrademax = $this->grade_item->grademax; $grade->rawscaleid = $this->grade_item->scaleid; $grade->rawgrade = null; // categories do not use raw grades // recalculate the rawgrade back to requested range $finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $this->grade_item->grademin, $this->grade_item->grademax); if (!is_null($finalgrade)) { $grade->finalgrade = bounded_number($this->grade_item->grademin, $finalgrade, $this->grade_item->grademax); } else { $grade->finalgrade = $finalgrade; } // update in db if changed if ($grade->finalgrade !== $oldgrade->finalgrade or $grade->rawgrade !== $oldgrade->rawgrade or $grade->rawgrademin !== $oldgrade->rawgrademin or $grade->rawgrademax !== $oldgrade->rawgrademax or $grade->rawscaleid !== $oldgrade->rawscaleid) { $grade->update('system'); } return; }