Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'MDL-25981'

  • Loading branch information...
commit 46df3c605996743dfde18d75ee2c576e5bf26be8 2 parents eb18317 + 4714815
@skodak skodak authored
View
3  blocks/activity_modules/block_activity_modules.php
@@ -27,7 +27,8 @@ function get_content() {
$archetypes = array();
foreach($modinfo->cms as $cm) {
- if (!$cm->uservisible or $cm->modname === 'label') {
+ // Exclude activities which are not visible or have no link (=label)
+ if (!$cm->uservisible or !$cm->has_view()) {
continue;
}
if (array_key_exists($cm->modname, $modfullnames)) {
View
42 blocks/site_main_menu/block_site_main_menu.php
@@ -40,21 +40,19 @@ function get_content() {
if (!$cm->uservisible) {
continue;
}
- if ($cm->modname == 'label') {
- $this->content->items[] = format_text($cm->extra, FORMAT_HTML, $options);
+
+ list($content, $instancename) =
+ get_print_section_cm_text($cm, $course);
+
+ if (!($url = $cm->get_url())) {
+ $this->content->items[] = $content;
$this->content->icons[] = '';
} else {
$linkcss = $cm->visible ? '' : ' class="dimmed" ';
- $instancename = format_string($cm->name, true, $course->id);
//Accessibility: incidental image - should be empty Alt text
- if (!empty($cm->icon)) {
- $icon = $OUTPUT->pix_url($cm->icon);
- } else {
- $icon = $OUTPUT->pix_url('icon', $cm->modname);
- }
- $icon = '<img src="'.$icon.'" class="icon" alt="" />&nbsp;';
+ $icon = '<img src="' . $cm->get_icon_url() . '" class="icon" alt="" />&nbsp;';
$this->content->items[] = '<a title="'.$cm->modplural.'" '.$linkcss.' '.$cm->extra.
- ' href="'.$CFG->wwwroot.'/mod/'.$cm->modname.'/view.php?id='.$cm->id.'">'.$icon.$instancename.'</a>';
+ ' href="' . $url . '">' . $icon . $instancename . '</a>';
}
}
}
@@ -114,28 +112,18 @@ function get_content() {
'<img style="height:16px; width:80px; border:0px" src="'.$OUTPUT->pix_url('movehere') . '" alt="'.$strmovehere.'" /></a>';
$this->content->icons[] = '';
}
- $instancename = $modinfo->cms[$modnumber]->name;
- $instancename = format_string($instancename, true, $course->id);
+ list($content, $instancename) =
+ get_print_section_cm_text($modinfo->cms[$modnumber], $course);
$linkcss = $mod->visible ? '' : ' class="dimmed" ';
- if (!empty($modinfo->cms[$modnumber]->extra)) {
- $extra = $modinfo->cms[$modnumber]->extra;
- } else {
- $extra = '';
- }
- if (!empty($modinfo->cms[$modnumber]->icon)) {
- $icon = $OUTPUT->pix_url($modinfo->cms[$modnumber]->icon);
- } else {
- $icon = $OUTPUT->pix_url('icon', $mod->modname);
- }
- if ($mod->modname == 'label') {
- $this->content->items[] = format_text($extra, FORMAT_HTML,$options).$editbuttons;
+ if (!($url = $mod->get_url())) {
+ $this->content->items[] = $content . $editbuttons;
$this->content->icons[] = '';
} else {
//Accessibility: incidental image - should be empty Alt text
- $icon = '<img src="'.$icon.'" class="icon" alt="" />&nbsp;';
- $this->content->items[] = '<a title="'.$mod->modfullname.'" '.$linkcss.' '.$extra.
- ' href="'.$CFG->wwwroot.'/mod/'.$mod->modname.'/view.php?id='.$mod->id.'">'.$icon.$instancename.'</a>'.$editbuttons;
+ $icon = '<img src="' . $mod->get_icon_url() . '" class="icon" alt="" />&nbsp;';
+ $this->content->items[] = '<a title="' . $mod->modfullname . '" ' . $linkcss . ' ' . $mod->extra .
+ ' href="' . $url . '">' . $icon . $instancename . '</a>' . $editbuttons;
}
}
}
View
43 blocks/social_activities/block_social_activities.php
@@ -42,21 +42,19 @@ function get_content() {
if (!$cm->uservisible) {
continue;
}
- if ($cm->modname == 'label') {
- $this->content->items[] = format_text($cm->extra, FORMAT_HTML, $options);
+
+ list($content, $instancename) =
+ get_print_section_cm_text($cm, $course);
+
+ if (!($url = $cm->get_url())) {
+ $this->content->items[] = $content;
$this->content->icons[] = '';
} else {
$linkcss = $cm->visible ? '' : ' class="dimmed" ';
- $instancename = format_string($cm->name, true, $course->id);
//Accessibility: incidental image - should be empty Alt text
- if (!empty($cm->icon)) {
- $icon = $OUTPUT->pix_url($cm->icon);
- } else {
- $icon = $OUTPUT->pix_url('icon', $cm->modname);
- }
- $icon = '<img src="'.$icon.'" class="icon" alt="" />&nbsp;';
+ $icon = '<img src="' . $cm->get_icon_url() . '" class="icon" alt="" />&nbsp;';
$this->content->items[] = '<a title="'.$cm->modplural.'" '.$linkcss.' '.$cm->extra.
- ' href="'.$CFG->wwwroot.'/mod/'.$cm->modname.'/view.php?id='.$cm->id.'">'.$icon.$instancename.'</a>';
+ ' href="' . $url . '">' . $icon . $instancename . '</a>';
}
}
}
@@ -123,28 +121,19 @@ function get_content() {
'<img style="height:16px; width:80px; border:0px" src="'.$OUTPUT->pix_url('movehere') . '" alt="'.$strmovehere.'" /></a>';
$this->content->icons[] = '';
}
- $instancename = $modinfo->cms[$modnumber]->name;
- $instancename = format_string($instancename, true, $course->id);
+ list($content, $instancename) =
+ get_print_section_cm_text($modinfo->cms[$modnumber], $course);
+
$linkcss = $mod->visible ? '' : ' class="dimmed" ';
- if (!empty($modinfo->cms[$modnumber]->extra)) {
- $extra = $modinfo->cms[$modnumber]->extra;
- } else {
- $extra = '';
- }
- if (!empty($modinfo->cms[$modnumber]->icon)) {
- $icon = $OUTPUT->pix_url($modinfo->cms[$modnumber]->icon);
- } else {
- $icon = $OUTPUT->pix_url('icon', $mod->modname);
- }
- if ($mod->modname == 'label') {
- $this->content->items[] = format_text($extra, FORMAT_HTML, $options).$editbuttons;
+ if (!($url = $mod->get_url())) {
+ $this->content->items[] = $content . $editbuttons;
$this->content->icons[] = '';
} else {
//Accessibility: incidental image - should be empty Alt text
- $icon = '<img src="'.$icon.'" class="icon" alt="" />&nbsp;';
- $this->content->items[] = '<a title="'.$mod->modfullname.'" '.$linkcss.' '.$extra.
- ' href="'.$CFG->wwwroot.'/mod/'.$mod->modname.'/view.php?id='.$mod->id.'">'.$icon.$instancename.'</a>'.$editbuttons;
+ $icon = '<img src="' . $mod->get_icon_url() . '" class="icon" alt="" />&nbsp;';
+ $this->content->items[] = '<a title="' . $mod->modfullname . '" ' . $linkcss . ' ' . $mod->extra .
+ ' href="' . $url . '">' . $icon . $instancename . '</a>' . $editbuttons;
}
}
}
View
287 course/lib.php
@@ -48,10 +48,6 @@
define('MOD_CLASS_ACTIVITY', 0);
define('MOD_CLASS_RESOURCE', 1);
-if (!defined('MAX_MODINFO_CACHE_SIZE')) {
- define('MAX_MODINFO_CACHE_SIZE', 10);
-}
-
function make_log_url($module, $url) {
switch ($module) {
case 'course':
@@ -959,6 +955,9 @@ function print_recent_activity($course) {
}
$info = explode(' ', $log->info);
+ // note: in most cases I replaced hardcoding of label with use of
+ // $cm->has_view() but it was not possible to do this here because
+ // we don't necessarily have the $cm for it
if ($info[0] == 'label') { // Labels are ignored in recent activity
continue;
}
@@ -1112,9 +1111,6 @@ function get_array_of_activities($courseid) {
if (function_exists($functionname)) {
if ($info = $functionname($rawmods[$seq])) {
- if (!empty($info->extra)) {
- $mod[$seq]->extra = $info->extra;
- }
if (!empty($info->icon)) {
$mod[$seq]->icon = $info->icon;
}
@@ -1124,11 +1120,45 @@ function get_array_of_activities($courseid) {
if (!empty($info->name)) {
$mod[$seq]->name = $info->name;
}
+ if ($info instanceof cached_cm_info) {
+ // When using cached_cm_info you can include three new fields
+ // that aren't available for legacy code
+ if (!empty($info->content)) {
+ $mod[$seq]->content = $info->content;
+ }
+ if (!empty($info->extraclasses)) {
+ $mod[$seq]->extraclasses = $info->extraclasses;
+ }
+ if (!empty($info->onclick)) {
+ $mod[$seq]->onclick = $info->onclick;
+ }
+ if (!empty($info->customdata)) {
+ $mod[$seq]->customdata = $info->customdata;
+ }
+ } else {
+ // When using a stdclass, the (horrible) deprecated ->extra field
+ // is available for BC
+ if (!empty($info->extra)) {
+ $mod[$seq]->extra = $info->extra;
+ }
+ }
}
}
if (!isset($mod[$seq]->name)) {
$mod[$seq]->name = $DB->get_field($rawmods[$seq]->modname, "name", array("id"=>$rawmods[$seq]->instance));
}
+
+ // Minimise the database size by unsetting default options when they are
+ // 'empty'. This list corresponds to code in the cm_info constructor.
+ foreach(array('idnumber', 'groupmode', 'groupingid', 'groupmembersonly',
+ 'indent', 'completion', 'extra', 'extraclasses', 'onclick', 'content',
+ 'icon', 'iconcomponent', 'customdata', 'availablefrom', 'availableuntil',
+ 'conditionscompletion', 'conditionsgrade') as $property) {
+ if (property_exists($mod[$seq], $property) &&
+ empty($mod[$seq]->{$property})) {
+ unset($mod[$seq]->{$property});
+ }
+ }
}
}
}
@@ -1251,6 +1281,44 @@ function set_section_visible($courseid, $sectionnumber, $visibility) {
}
/**
+ * Obtains shared data that is used in print_section when displaying a
+ * course-module entry.
+ *
+ * Calls format_text or format_string as appropriate, and obtains the correct icon.
+ *
+ * This data is also used in other areas of the code.
+ * @param cm_info $cm Course-module data (must come from get_fast_modinfo)
+ * @param object $course Moodle course object
+ * @return array An array with the following values in this order:
+ * $content (optional extra content for after link),
+ * $instancename (text of link)
+ */
+function get_print_section_cm_text(cm_info $cm, $course) {
+ global $OUTPUT;
+
+ // Get course context
+ $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
+
+ // Get content from modinfo if specified. Content displays either
+ // in addition to the standard link (below), or replaces it if
+ // the link is turned off by setting ->url to null.
+ if (($content = $cm->get_content()) !== '') {
+ $labelformatoptions = new stdClass();
+ $labelformatoptions->noclean = true;
+ $labelformatoptions->overflowdiv = true;
+ $labelformatoptions->context = $coursecontext;
+ $content = format_text($content, FORMAT_HTML, $labelformatoptions);
+ } else {
+ $content = '';
+ }
+
+ $stringoptions = new stdClass;
+ $stringoptions->context = $coursecontext;
+ $instancename = format_string($cm->name, true, $stringoptions);
+ return array($content, $instancename);
+}
+
+/**
* Prints a section full of activity modules
*/
function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false) {
@@ -1265,8 +1333,8 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
static $strmovehere;
static $strmovefull;
static $strunreadpostsone;
- static $usetracking;
static $groupings;
+ static $modulenames;
if (!isset($initialised)) {
$groupbuttons = ($course->groupmode or (!$course->groupmodeforce));
@@ -1277,18 +1345,12 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
$strmovehere = get_string("movehere");
$strmovefull = strip_tags(get_string("movefull", "", "'$USER->activitycopyname'"));
}
- include_once($CFG->dirroot.'/mod/forum/lib.php');
- if ($usetracking = forum_tp_can_track_forums()) {
- $strunreadpostsone = get_string('unreadpostsone', 'forum');
- }
+ $modulenames = array();
$initialised = true;
}
- $labelformatoptions = new stdClass();
- $labelformatoptions->noclean = true;
- $labelformatoptions->overflowdiv = true;
+ $tl = textlib_get_instance();
-/// Casting $course->modinfo to string prevents one notice when the field is null
$modinfo = get_fast_modinfo($course);
$completioninfo = new completion_info($course);
@@ -1304,6 +1366,9 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
continue;
}
+ /**
+ * @var cm_info
+ */
$mod = $mods[$modnumber];
if ($ismoving and $mod->id == $USER->activitycopy) {
@@ -1341,6 +1406,11 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
}
}
+ if (!isset($modulenames[$mod->modname])) {
+ $modulenames[$mod->modname] = get_string('modulename', $mod->modname);
+ }
+ $modulename = $modulenames[$mod->modname];
+
// In some cases the activity is visible to user, but it is
// dimmed. This is done if viewhiddenactivities is true and if:
// 1. the activity is not visible, or
@@ -1366,6 +1436,10 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
$liclasses[] = 'activity';
$liclasses[] = $mod->modname;
$liclasses[] = 'modtype_'.$mod->modname;
+ $extraclasses = $mod->get_extra_classes();
+ if ($extraclasses) {
+ $liclasses = array_merge($liclasses, explode(' ', $extraclasses));
+ }
echo html_writer::start_tag('li', array('class'=>join(' ', $liclasses), 'id'=>'module-'.$modnumber));
if ($ismoving) {
echo '<a title="'.$strmovefull.'"'.
@@ -1384,105 +1458,122 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
}
echo html_writer::start_tag('div', array('class'=>join(' ', $classes)));
- $extra = '';
- if (!empty($modinfo->cms[$modnumber]->extra)) {
- $extra = $modinfo->cms[$modnumber]->extra;
+ // Get data about this course-module
+ list($content, $instancename) =
+ get_print_section_cm_text($modinfo->cms[$modnumber], $course);
+
+ //Accessibility: for files get description via icon, this is very ugly hack!
+ $altname = '';
+ $altname = $mod->modfullname;
+ if (!empty($customicon)) {
+ $archetype = plugin_supports('mod', $mod->modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
+ if ($archetype == MOD_ARCHETYPE_RESOURCE) {
+ $mimetype = mimeinfo_from_icon('type', $customicon);
+ $altname = get_mimetype_description($mimetype);
+ }
+ }
+ // Avoid unnecessary duplication: if e.g. a forum name already
+ // includes the word forum (or Forum, etc) then it is unhelpful
+ // to include that in the accessible description that is added.
+ if (false !== strpos($tl->strtolower($instancename),
+ $tl->strtolower($altname))) {
+ $altname = '';
+ }
+ // File type after name, for alphabetic lists (screen reader).
+ if ($altname) {
+ $altname = get_accesshide(' '.$altname);
}
- if ($mod->modname == "label") {
- if ($accessiblebutdim || !$mod->uservisible) {
- echo '<div class="dimmed_text"><span class="accesshide">'.
- get_string('hiddenfromstudents').'</span>';
+ // We may be displaying this just in order to show information
+ // about visibility, without the actual link
+ $contentpart = '';
+ if ($mod->uservisible) {
+ // Nope - in this case the link is fully working for user
+ $linkclasses = '';
+ $textclasses = '';
+ if ($accessiblebutdim) {
+ $linkclasses .= ' dimmed';
+ $textclasses .= ' dimmed_text';
+ $accesstext = '<span class="accesshide">'.
+ get_string('hiddenfromstudents').': </span>';
} else {
- echo '<div>';
+ $accesstext = '';
}
- echo format_text($extra, FORMAT_HTML, $labelformatoptions);
- echo "</div>";
- if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
- if (!isset($groupings)) {
- $groupings = groups_get_all_groupings($course->id);
- }
- echo " <span class=\"groupinglabel\">(".format_string($groupings[$mod->groupingid]->name).')</span>';
+ if ($linkclasses) {
+ $linkcss = 'class="' . trim($linkclasses) . '" ';
+ } else {
+ $linkcss = '';
+ }
+ if ($textclasses) {
+ $textcss = 'class="' . trim($textclasses) . '" ';
+ } else {
+ $textcss = '';
}
- } else { // Normal activity
- $instancename = format_string($modinfo->cms[$modnumber]->name, true, $course->id);
+ // Get on-click attribute value if specified
+ $onclick = $mod->get_on_click();
+ if ($onclick) {
+ $onclick = ' onclick="' . $onclick . '"';
+ }
- $customicon = $modinfo->cms[$modnumber]->icon;
- if (!empty($customicon)) {
- if (substr($customicon, 0, 4) === 'mod/') {
- list($modname, $iconname) = explode('/', substr($customicon, 4), 2);
- $icon = $OUTPUT->pix_url($iconname, $modname);
- } else {
- $icon = $OUTPUT->pix_url($customicon);
+ if ($url = $mod->get_url()) {
+ // Display link itself
+ echo '<a ' . $linkcss . $mod->extra . $onclick .
+ ' href="' . $url . '"><img src="' . $mod->get_icon_url() .
+ '" class="activityicon" alt="' .
+ $modulename . '" /> ' .
+ $accesstext . '<span class="instancename">' .
+ $instancename . $altname . '</span></a>';
+
+ // If specified, display extra content after link
+ if ($content) {
+ $contentpart = '<div class="contentafterlink' .
+ trim($textclasses) . '">' . $content . '</div>';
}
} else {
- $icon = $OUTPUT->pix_url('icon', $mod->modname);
+ // No link, so display only content
+ $contentpart = '<div ' . $textcss . $mod->extra . '>' .
+ $accesstext . $content . '</div>';
}
- //Accessibility: for files get description via icon, this is very ugly hack!
- $altname = '';
- $altname = $mod->modfullname;
- if (!empty($customicon)) {
- $archetype = plugin_supports('mod', $mod->modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
- if ($archetype == MOD_ARCHETYPE_RESOURCE) {
- $mimetype = mimeinfo_from_icon('type', $customicon);
- $altname = get_mimetype_description($mimetype);
+ if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
+ if (!isset($groupings)) {
+ $groupings = groups_get_all_groupings($course->id);
}
+ echo " <span class=\"groupinglabel\">(".format_string($groupings[$mod->groupingid]->name).')</span>';
}
- // Avoid unnecessary duplication.
- if (false !== stripos($instancename, $altname)) {
- $altname = '';
- }
- // File type after name, for alphabetic lists (screen reader).
- if ($altname) {
- $altname = get_accesshide(' '.$altname);
+ } else {
+ $textclasses = $extraclasses;
+ $textclasses .= ' dimmed_text';
+ if ($textclasses) {
+ $textcss = 'class="' . trim($textclasses) . '" ';
+ } else {
+ $textcss = '';
}
+ $accesstext = '<span class="accesshide">' .
+ get_string('notavailableyet', 'condition') .
+ ': </span>';
- // We may be displaying this just in order to show information
- // about visibility, without the actual link
- if ($mod->uservisible) {
- // Display normal module link
- if (!$accessiblebutdim) {
- $linkcss = '';
- $accesstext ='';
- } else {
- $linkcss = ' class="dimmed" ';
- $accesstext = '<span class="accesshide">'.
- get_string('hiddenfromstudents').': </span>';
- }
-
- echo '<a '.$linkcss.' '.$extra.
- ' href="'.$CFG->wwwroot.'/mod/'.$mod->modname.'/view.php?id='.$mod->id.'">'.
- '<img src="'.$icon.'" class="activityicon" alt="'.get_string('modulename',$mod->modname).'" /> '.
- $accesstext.'<span class="instancename">'.$instancename.$altname.'</span></a>';
-
- if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
- if (!isset($groupings)) {
- $groupings = groups_get_all_groupings($course->id);
- }
- echo " <span class=\"groupinglabel\">(".format_string($groupings[$mod->groupingid]->name).')</span>';
- }
- } else {
+ if ($url = $mod->get_url()) {
// Display greyed-out text of link
- echo '<span class="dimmed_text" '.$extra.' ><span class="accesshide">'.
- get_string('notavailableyet','condition').': </span>'.
- '<img src="'.$icon.'" class="activityicon" alt="'.get_string('modulename', $mod->modname).'" /> <span>'.
- $instancename.$altname.'</span></span>';
- }
- }
- if ($usetracking && $mod->modname == 'forum') {
- if ($unread = forum_tp_count_forum_unread_posts($mod, $course)) {
- echo '<span class="unread"> <a href="'.$CFG->wwwroot.'/mod/forum/view.php?id='.$mod->id.'">';
- if ($unread == 1) {
- echo $strunreadpostsone;
- } else {
- print_string('unreadpostsnumber', 'forum', $unread);
- }
- echo '</a></span>';
+ echo '<div ' . $textcss . $mod->extra .
+ ' >' . '<img src="' . $mod->get_icon_url() .
+ '" class="activityicon" alt="' .
+ $modulename .
+ '" /> <span>'. $instancename . $altname .
+ '</span></div>';
+
+ // Do not display content after link when it is greyed out like this.
+ } else {
+ // No link, so display only content (also greyed)
+ $contentpart = '<div ' . $textcss . $mod->extra . '>' .
+ $accesstext . $content . '</div>';
}
}
+ // Module can put text after the link (e.g. forum unread)
+ echo $mod->get_after_link();
+
if ($isediting) {
if ($groupbuttons and plugin_supports('mod', $mod->modname, FEATURE_GROUPS, 0)) {
if (! $mod->groupmodelink = $groupbuttonslink) {
@@ -1494,6 +1585,7 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
}
echo '&nbsp;&nbsp;';
echo make_editing_buttons($mod, $absolute, true, $mod->indent, $section->section);
+ echo $mod->get_after_edit_icons();
}
// Completion
@@ -1566,6 +1658,9 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
}
}
+ // Display the content (if any) at this part of the html
+ echo $contentpart;
+
// Show availability information (for someone who isn't allowed to
// see the activity itself, or for staff)
if (!$mod->uservisible) {
View
2  course/report/outline/index.php
@@ -74,7 +74,7 @@
foreach ($modinfo->sections as $sectionnum=>$section) {
foreach ($section as $cmid) {
$cm = $modinfo->cms[$cmid];
- if ($cm->modname == 'label') {
+ if (!$cm->has_view()) {
continue;
}
if (!$cm->uservisible) {
View
10 course/report/participation/index.php
@@ -63,7 +63,7 @@
$modinfo = get_fast_modinfo($course);
- $modules = $DB->get_records_select('modules', "visible = 1 AND name <> 'label'", null, 'name ASC');
+ $modules = $DB->get_records_select('modules', "visible = 1", null, 'name ASC');
$instanceoptions = array();
foreach ($modules as $module) {
@@ -72,8 +72,16 @@
}
$instances = array();
foreach ($modinfo->instances[$module->name] as $cm) {
+ // Skip modules such as label which do not actually have links;
+ // this means there's nothing to participate in
+ if (!$cm->has_view()) {
+ continue;
+ }
$instances[$cm->id] = format_string($cm->name);
}
+ if (count($instances) == 0) {
+ continue;
+ }
$instanceoptions[] = array(get_string('modulenameplural', $module->name)=>$instances);
}
View
7 course/resources.php
@@ -37,9 +37,6 @@
$modules = array();
foreach ($allmodules as $key=>$module) {
$modname = $module->name;
- if ($modname === 'label') {
- continue;
- }
$libfile = "$CFG->dirroot/mod/$modname/lib.php";
if (!file_exists($libfile)) {
continue;
@@ -80,6 +77,10 @@
if (!array_key_exists($cm->modname, $modules)) {
continue;
}
+ if (!$cm->has_view()) {
+ // Exclude label and similar
+ continue;
+ }
$cms[$cm->id] = $cm;
$resources[$cm->modname][] = $cm->instance;
}
View
1,092 lib/modinfolib.php
@@ -0,0 +1,1092 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * modinfolib.php - Functions/classes relating to cached information about module instances on
+ * a course.
+ * @package core
+ * @subpackage lib
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author sam marshall
+ */
+
+
+// Maximum number of modinfo items to keep in memory cache. Do not increase this to a large
+// number because:
+// a) modinfo can be big (megabyte range) for some courses
+// b) performance of cache will deteriorate if there are very many items in it
+if (!defined('MAX_MODINFO_CACHE_SIZE')) {
+ define('MAX_MODINFO_CACHE_SIZE', 10);
+}
+
+
+/**
+ * Information about a course that is cached in the course table 'modinfo' field (and then in
+ * memory) in order to reduce the need for other database queries.
+ *
+ * This includes information about the course-modules and the sections on the course. It can also
+ * include dynamic data that has been updated for the current user.
+ */
+class course_modinfo {
+ // For convenience we store the course object here as it is needed in other parts of code
+ private $course;
+
+ // Existing data fields
+ ///////////////////////
+
+ // These are public for backward compatibility. Note: it is not possible to retain BC
+ // using PHP magic get methods because behaviour is different with regard to empty().
+
+ /**
+ * Course ID
+ * @var int
+ * @deprecated For new code, use get_course_id instead.
+ */
+ public $courseid;
+
+ /**
+ * User ID
+ * @var int
+ * @deprecated For new code, use get_user_id instead.
+ */
+ public $userid;
+
+ /**
+ * Array from int (section num, e.g. 0) => array of int (course-module id); this list only
+ * includes sections that actually contain at least one course-module
+ * @var array
+ * @deprecated For new code, use get_sections instead
+ */
+ public $sections;
+
+ /**
+ * Array from int (cm id) => cm_info object
+ * @var array
+ * @deprecated For new code, use get_cms or get_cm instead.
+ */
+ public $cms;
+
+ /**
+ * Array from string (modname) => int (instance id) => cm_info object
+ * @var array
+ * @deprecated For new code, use get_instances or get_instances_of instead.
+ */
+ public $instances;
+
+ /**
+ * Groups that the current user belongs to. This value is usually not available (set to null)
+ * unless the course has activities set to groupmembersonly. When set, it is an array of
+ * grouping id => array of group id => group id. Includes grouping id 0 for 'all groups'.
+ * @var array
+ * @deprecated Don't use this! For new code, use get_groups.
+ */
+ public $groups;
+
+ // Get methods for data
+ ///////////////////////
+
+ /**
+ * @return object Moodle course object that was used to construct this data
+ */
+ public function get_course() {
+ return $this->course;
+ }
+
+ /**
+ * @return int Course ID
+ */
+ public function get_course_id() {
+ return $this->courseid;
+ }
+
+ /**
+ * @return int User ID
+ */
+ public function get_user_id() {
+ return $this->userid;
+ }
+
+ /**
+ * @return array Array from section number (e.g. 0) to array of course-module IDs in that
+ * section; this only includes sections that contain at least one course-module
+ */
+ public function get_sections() {
+ return $this->sections;
+ }
+
+ /**
+ * @return array Array from course-module instance to cm_info object within this course, in
+ * order of appearance
+ */
+ public function get_cms() {
+ return $this->cms;
+ }
+
+ /**
+ * Obtains a single course-module object (for a course-module that is on this course).
+ * @param int $cmid Course-module ID
+ * @return cm_info Information about that course-module
+ * @throws moodle_exception If the course-module does not exist
+ */
+ public function get_cm($cmid) {
+ if (empty($this->cms[$cmid])) {
+ throw new moodle_exception('invalidcoursemodule', 'error');
+ }
+ return $this->cms[$cmid];
+ }
+
+ /**
+ * Obtains all module instances on this course.
+ * @return array Array from module name => array from instance id => cm_info
+ */
+ public function get_instances() {
+ return $this->instances;
+ }
+
+ /**
+ * Obtains all instances of a particular module on this course.
+ * @param $modname Name of module (not full frankenstyle) e.g. 'label'
+ * @return array Array from instance id => cm_info for modules on this course; empty if none
+ */
+ public function get_instances_of($modname) {
+ if (empty($this->instances[$modname])) {
+ return array();
+ }
+ return $this->instances[$modname];
+ }
+
+ /**
+ * Returns groups that the current user belongs to on the course. Note: If not already
+ * available, this may make a database query.
+ * @param int $groupingid Grouping ID or 0 (default) for all groups
+ * @return array Array of int (group id) => int (same group id again); empty array if none
+ */
+ public function get_groups($groupingid=0) {
+ if (is_null($this->groups)) {
+ // NOTE: Performance could be improved here. The system caches user groups
+ // in $USER->groupmember[$courseid] => array of groupid=>groupid. Unfortunately this
+ // structure does not include grouping information. It probably could be changed to
+ // do so, without a significant performance hit on login, thus saving this one query
+ // each request.
+ $this->groups = groups_get_user_groups($this->courseid, $this->userid);
+ }
+ if (!isset($this->groups[$groupingid])) {
+ return array();
+ }
+ return $this->groups[$groupingid];
+ }
+
+ /**
+ * Constructs based on course.
+ * Note: This constructor should not usually be called directly.
+ * Use get_fast_modinfo($course) instead as this maintains a cache.
+ * @param object $course Moodle course object, which may include modinfo
+ * @param int $userid User ID
+ */
+ public function __construct($course, $userid) {
+ global $CFG, $DB;
+
+ // Set initial values
+ $this->courseid = $course->id;
+ $this->userid = $userid;
+ $this->sections = array();
+ $this->cms = array();
+ $this->instances = array();
+ $this->groups = null;
+ $this->course = $course;
+
+ // Check modinfo field is set. If not, build and load it.
+ if (empty($course->modinfo)) {
+ rebuild_course_cache($course->id);
+ $course->modinfo = $DB->get_field('course', 'modinfo', array('id'=>$course->id));
+ }
+
+ // Load modinfo field into memory as PHP object and check it's valid
+ $info = unserialize($course->modinfo);
+ if (!is_array($info)) {
+ // hmm, something is wrong - lets try to fix it
+ rebuild_course_cache($course->id);
+ $course->modinfo = $DB->get_field('course', 'modinfo', array('id'=>$course->id));
+ $info = unserialize($course->modinfo);
+ if (!is_array($info)) {
+ // If it still fails, abort
+ debugging('Problem with "modinfo" data for this course');
+ return;
+ }
+ }
+
+ // If we haven't already preloaded contexts for the course, do it now
+ preload_course_contexts($course->id);
+
+ // Loop through each piece of module data, constructing it
+ $modexists = array();
+ foreach ($info as $mod) {
+ if (empty($mod->name)) {
+ // something is wrong here
+ continue;
+ }
+
+ // Skip modules which don't exist
+ if (empty($modexists[$mod->mod])) {
+ if (!file_exists("$CFG->dirroot/mod/$mod->mod/lib.php")) {
+ continue;
+ }
+ $modexists[$mod->mod] = true;
+ }
+
+ // Construct info for this module
+ $cm = new cm_info($this, $course, $mod, $info);
+
+ // Store module in instances and cms array
+ if (!isset($this->instances[$cm->modname])) {
+ $this->instances[$cm->modname] = array();
+ }
+ $this->instances[$cm->modname][$cm->instance] = $cm;
+ $this->cms[$cm->id] = $cm;
+
+ // Reconstruct sections. This works because modules are stored in order
+ if (!isset($this->sections[$cm->sectionnum])) {
+ $this->sections[$cm->sectionnum] = array();
+ }
+ $this->sections[$cm->sectionnum][] = $cm->id;
+ }
+
+ // We need at least 'dynamic' data from each course-module (this is basically the remaining
+ // data which was always present in previous version of get_fast_modinfo, so it's required
+ // for BC). Creating it in a second pass is necessary because obtain_dynamic_data sometimes
+ // needs to be able to refer to a 'complete' (with basic data) modinfo.
+ foreach ($this->cms as $cm) {
+ $cm->obtain_dynamic_data();
+ }
+ }
+}
+
+
+/**
+ * Data about a single module on a course. This contains most of the fields in the course_modules
+ * table, plus additional data when required.
+ *
+ * This object has many public fields; code should treat all these fields as read-only and set
+ * data only using the supplied set functions. Setting the fields directly is not supported
+ * and may cause problems later.
+ */
+class cm_info {
+ /**
+ * State: Only basic data from modinfo cache is available.
+ */
+ const STATE_BASIC = 0;
+
+ /**
+ * State: Dynamic data is available too.
+ */
+ const STATE_DYNAMIC = 1;
+
+ /**
+ * State: View data (for course page) is available.
+ */
+ const STATE_VIEW = 2;
+
+ /**
+ * Parent object
+ * @var course_modinfo
+ */
+ private $modinfo;
+
+ /**
+ * Level of information stored inside this object (STATE_xx constant)
+ * @var int
+ */
+ private $state;
+
+ // Existing data fields
+ ///////////////////////
+
+ /**
+ * Course-module ID - from course_modules table
+ * @var int
+ */
+ public $id;
+
+ /**
+ * Module instance (ID within module table) - from course_modules table
+ * @var int
+ */
+ public $instance;
+
+ /**
+ * Course ID - from course_modules table
+ * @var int
+ */
+ public $course;
+
+ /**
+ * 'ID number' from course-modules table (arbitrary text set by user) - from
+ * course_modules table
+ * @var string
+ */
+ public $idnumber;
+
+ /**
+ * Visible setting (0 or 1; if this is 0, students cannot see/access the activity) - from
+ * course_modules table
+ * @var int
+ */
+ public $visible;
+
+ /**
+ * Group mode (one of the constants NONE, SEPARATEGROUPS, or VISIBLEGROUPS) - from
+ * course_modules table
+ * @var int
+ */
+ public $groupmode;
+
+ /**
+ * Grouping ID (0 = all groupings)
+ * @var int
+ */
+ public $groupingid;
+
+ /**
+ * Group members only (if set to 1, only members of a suitable group see this link on the
+ * course page; 0 = everyone sees it even if they don't belong to a suitable group) - from
+ * course_modules table
+ * @var int
+ */
+ public $groupmembersonly;
+
+ /**
+ * Indent level on course page (0 = no indent) - from course_modules table
+ * @var int
+ */
+ public $indent;
+
+ /**
+ * Activity completion setting for this activity, COMPLETION_TRACKING_xx constant - from
+ * course_modules table
+ * @var int
+ */
+ public $completion;
+
+ /**
+ * Available date for this activity (0 if not set, or set to seconds since epoch; before this
+ * date, activity does not display to students) - from course_modules table
+ * @var int
+ */
+ public $availablefrom;
+
+ /**
+ * Available until date for this activity (0 if not set, or set to seconds since epoch; from
+ * this date, activity does not display to students) - from course_modules table
+ * @var int
+ */
+ public $availableuntil;
+
+ /**
+ * When activity is unavailable, this field controls whether it is shown to students (0 =
+ * hide completely, 1 = show greyed out with information about when it will be available) -
+ * from course_modules table
+ * @var int
+ */
+ public $showavailability;
+
+ /**
+ * Extra HTML that is put in an unhelpful part of the HTML when displaying this module in
+ * course page - from cached data in modinfo field
+ * @deprecated This is crazy, don't use it. Replaced by ->extraclasses and ->onclick
+ * @var string
+ */
+ public $extra;
+
+ /**
+ * Name of icon to use - from cached data in modinfo field
+ * @var string
+ */
+ public $icon;
+
+ /**
+ * Component that contains icon - from cached data in modinfo field
+ * @var string
+ */
+ public $iconcomponent;
+
+ /**
+ * Name of module e.g. 'forum' (this is the same name as the module's main database
+ * table) - from cached data in modinfo field
+ * @var string
+ */
+ public $modname;
+
+ /**
+ * Name of module instance for display on page e.g. 'General discussion forum' - from cached
+ * data in modinfo field
+ * @var string
+ */
+ public $name;
+
+ /**
+ * Section number that this course-module is in (section 0 = above the calendar, section 1
+ * = week/topic 1, etc) - from cached data in modinfo field
+ * @var string
+ */
+ public $sectionnum;
+
+ /**
+ * Availability conditions for this course-module based on the completion of other
+ * course-modules (array from other course-module id to required completion state for that
+ * module) - from cached data in modinfo field
+ * @var array
+ */
+ public $conditionscompletion;
+
+ /**
+ * Availability conditions for this course-module based on course grades (array from
+ * grade item id to object with ->min, ->max fields) - from cached data in modinfo field
+ * @var array
+ */
+ public $conditionsgrade;
+
+ /**
+ * Plural name of module type, e.g. 'Forums' - from lang file
+ * @deprecated Do not use this value (you can obtain it by calling get_string instead); it
+ * will be removed in a future version (see later TODO in this file)
+ * @var string
+ */
+ public $modplural;
+
+ /**
+ * True if this course-module is available to students i.e. if all availability conditions
+ * are met - obtained dynamically
+ * @var bool
+ */
+ public $available;
+
+ /**
+ * If course-module is not available to students, this string gives information about
+ * availability which can be displayed to students and/or staff (e.g. 'Available from 3
+ * January 2010') for display on main page - obtained dynamically
+ * @var string
+ */
+ public $availableinfo;
+
+ /**
+ * True if this course-module is available to the CURRENT user (for example, if current user
+ * has viewhiddenactivities capability, they can access the course-module even if it is not
+ * visible or not available, so this would be true in that case)
+ * @var bool
+ */
+ public $uservisible;
+
+ // New data available only via functions
+ ////////////////////////////////////////
+
+ /**
+ * @var moodle_url
+ */
+ private $url;
+
+ /**
+ * @var string
+ */
+ private $content;
+
+ /**
+ * @var string
+ */
+ private $extraclasses;
+
+ /**
+ * @var string
+ */
+ private $onclick;
+
+ /**
+ * @var mixed
+ */
+ private $customdata;
+
+ /**
+ * @var string
+ */
+ private $afterlink;
+
+ /**
+ * @var string
+ */
+ private $afterediticons;
+
+ /**
+ * @return bool True if this module has a 'view' page that should be linked to in navigation
+ * etc (note: modules may still have a view.php file, but return false if this is not
+ * intended to be linked to from 'normal' parts of the interface; this is what label does).
+ */
+ public function has_view() {
+ return !is_null($this->url);
+ }
+
+ /**
+ * @return moodle_url URL to link to for this module, or null if it doesn't have a view page
+ */
+ public function get_url() {
+ return $this->url;
+ }
+
+ /**
+ * Obtains content to display on main (view) page.
+ * Note: Will collect view data, if not already obtained.
+ * @return string Content to display on main page below link, or empty string if none
+ */
+ public function get_content() {
+ $this->obtain_view_data();
+ return $this->content;
+ }
+
+ /**
+ * Note: Will collect view data, if not already obtained.
+ * @return string Extra CSS classes to add to html output for this activity on main page
+ */
+ public function get_extra_classes() {
+ $this->obtain_view_data();
+ return $this->extraclasses;
+ }
+
+ /**
+ * @return string Content of HTML on-click attribute. This string will be used literally
+ * as a string so should be pre-escaped.
+ */
+ public function get_on_click() {
+ // Does not need view data; may be used by navigation
+ return $this->onclick;
+ }
+ /**
+ * @return mixed Optional custom data stored in modinfo cache for this activity, or null if none
+ */
+ public function get_custom_data() {
+ return $this->customdata;
+ }
+
+ /**
+ * Note: Will collect view data, if not already obtained.
+ * @return string Extra HTML code to display after link
+ */
+ public function get_after_link() {
+ $this->obtain_view_data();
+ return $this->afterlink;
+ }
+
+ /**
+ * Note: Will collect view data, if not already obtained.
+ * @return string Extra HTML code to display after editing icons (e.g. more icons)
+ */
+ public function get_after_edit_icons() {
+ $this->obtain_view_data();
+ return $this->afterediticons;
+ }
+
+ /**
+ * @param moodle_core_renderer $output Output render to use, or null for default (global)
+ * @return moodle_url Icon URL for a suitable icon to put beside this cm
+ */
+ public function get_icon_url($output = null) {
+ global $OUTPUT;
+ if (!$output) {
+ $output = $OUTPUT;
+ }
+ if (!empty($this->icon)) {
+ if (substr($this->icon, 0, 4) === 'mod/') {
+ list($modname, $iconname) = explode('/', substr($this->icon, 4), 2);
+ $icon = $output->pix_url($iconname, $modname);
+ } else {
+ if (!empty($this->iconcomponent)) {
+ // Icon has specified component
+ $icon = $output->pix_url($this->icon, $this->iconcomponent);
+ } else {
+ // Icon does not have specified component, use default
+ $icon = $output->pix_url($this->icon);
+ }
+ }
+ } else {
+ $icon = $output->pix_url('icon', $this->modname);
+ }
+ return $icon;
+ }
+
+ /**
+ * @return course_modinfo Modinfo object that this came from
+ */
+ public function get_modinfo() {
+ return $this->modinfo;
+ }
+
+ /**
+ * @return object Moodle course object that was used to construct this data
+ */
+ public function get_course() {
+ return $this->modinfo->get_course();
+ }
+
+ // Set functions
+ ////////////////
+
+ /**
+ * Sets content to display on course view page below link (if present).
+ * @param string $content New content as HTML string (empty string if none)
+ * @return void
+ */
+ public function set_content($content) {
+ $this->content = $content;
+ }
+
+ /**
+ * Sets extra classes to include in CSS.
+ * @param string $extraclasses Extra classes (empty string if none)
+ * @return void
+ */
+ public function set_extra_classes($extraclasses) {
+ $this->extraclasses = $extraclasses;
+ }
+
+ /**
+ * Sets value of on-click attribute for JavaScript.
+ * Note: May not be called from _cm_info_view (only _cm_info_dynamic).
+ * @param string $onclick New onclick attribute which should be HTML-escaped
+ * (empty string if none)
+ * @return void
+ */
+ public function set_on_click($onclick) {
+ $this->check_not_view_only();
+ $this->onclick = $onclick;
+ }
+
+ /**
+ * Sets HTML that displays after link on course view page.
+ * @param string $afterlink HTML string (empty string if none)
+ * @return void
+ */
+ public function set_after_link($afterlink) {
+ $this->afterlink = $afterlink;
+ }
+
+ /**
+ * Sets HTML that displays after edit icons on course view page.
+ * @param string $afterediticons HTML string (empty string if none)
+ * @return void
+ */
+ public function set_after_edit_icons($afterediticons) {
+ $this->afterediticons = $afterediticons;
+ }
+
+ /**
+ * Changes the name (text of link) for this module instance.
+ * Note: May not be called from _cm_info_view (only _cm_info_dynamic).
+ * @param string $name Name of activity / link text
+ * @return void
+ */
+ public function set_name($name) {
+ $this->update_user_visible();
+ $this->name = $name;
+ }
+
+ /**
+ * Turns off the view link for this module instance.
+ * Note: May not be called from _cm_info_view (only _cm_info_dynamic).
+ * @return void
+ */
+ public function set_no_view_link() {
+ $this->check_not_view_only();
+ $url = null;
+ }
+
+ /**
+ * Sets the 'uservisible' flag. This can be used (by setting false) to prevent access and
+ * display of this module link for the current user.
+ * Note: May not be called from _cm_info_view (only _cm_info_dynamic).
+ * @param bool $uservisible
+ * @return void
+ */
+ public function set_user_visible($uservisible) {
+ $this->check_not_view_only();
+ $this->uservisible = $uservisible;
+ }
+
+ /**
+ * Sets the 'available' flag and related details. This flag is normally used to make
+ * course modules unavailable until a certain date or condition is met. (When a course
+ * module is unavailable, it is still visible to users who have viewhiddenactivities
+ * permission.)
+ *
+ * When this is function is called, user-visible status is recalculated automatically.
+ *
+ * Note: May not be called from _cm_info_view (only _cm_info_dynamic).
+ * @param bool $available False if this item is not 'available'
+ * @param int $showavailability 0 = do not show this item at all if it's not available,
+ * 1 = show this item greyed out with the following message
+ * @param string $availableinfo Information about why this is not available which displays
+ * to those who have viewhiddenactivities, and to everyone if showavailability is set;
+ * note that this function replaces the existing data (if any)
+ * @return void
+ */
+ public function set_available($available, $showavailability=0, $availableinfo='') {
+ $this->check_not_view_only();
+ $this->available = $available;
+ $this->showavailability = $showavailability;
+ $this->availableinfo = $availableinfo;
+ $this->update_user_visible();
+ }
+
+ /**
+ * Some set functions can only be called from _cm_info_dynamic and not _cm_info_view.
+ * This is because they may affect parts of this object which are used on pages other
+ * than the view page (e.g. in the navigation block, or when checking access on
+ * module pages).
+ * @return void
+ */
+ private function check_not_view_only() {
+ if ($this->state >= self::STATE_DYNAMIC) {
+ throw new coding_exception('Cannot set this data from _cm_info_view because it may ' .
+ 'affect other pages as well as view');
+ }
+ }
+
+ /**
+ * Constructor should not be called directly; use get_fast_modinfo.
+ * @param course_modinfo $modinfo Parent object
+ * @param object $course Course row
+ * @param object $mod Module object from the modinfo field of course table
+ * @param object $info Entire object from modinfo field of course table
+ */
+ public function __construct(course_modinfo $modinfo, $course, $mod, $info) {
+ global $CFG;
+ $this->modinfo = $modinfo;
+
+ $this->id = $mod->cm;
+ $this->instance = $mod->id;
+ $this->course = $course->id;
+ $this->modname = $mod->mod;
+ $this->idnumber = isset($mod->idnumber) ? $mod->idnumber : '';
+ $this->name = $mod->name;
+ $this->visible = $mod->visible;
+ $this->sectionnum = $mod->section;
+ $this->groupmode = isset($mod->groupmode) ? $mod->groupmode : 0;
+ $this->groupingid = isset($mod->groupingid) ? $mod->groupingid : 0;
+ $this->groupmembersonly = isset($mod->groupmembersonly) ? $mod->groupmembersonly : 0;
+ $this->indent = isset($mod->indent) ? $mod->indent : 0;
+ $this->completion = isset($mod->completion) ? $mod->completion : 0;
+ $this->extra = isset($mod->extra) ? $mod->extra : '';
+ $this->extraclasses = isset($mod->extraclasses) ? $mod->extraclasses : '';
+ $this->onclick = isset($mod->onclick) ? $mod->onclick : '';
+ $this->content = isset($mod->content) ? $mod->content : '';
+ $this->icon = isset($mod->icon) ? $mod->icon : '';
+ $this->iconcomponent = isset($mod->iconcomponent) ? $mod->iconcomponent : '';
+ $this->customdata = isset($mod->customdata) ? $mod->customdata : '';
+ $this->state = self::STATE_BASIC;
+
+ // This special case handles old label data. Labels used to use the 'name' field for
+ // content
+ if ($this->modname === 'label' && $this->content === '') {
+ $this->content = $this->extra;
+ $this->extra = '';
+ }
+
+ if (!empty($CFG->enableavailability)) {
+ // We must have completion information from modinfo. If it's not
+ // there, cache needs rebuilding
+ if (!isset($mod->showavailability)) {
+ throw new modinfo_rebuild_cache_exception(
+ 'enableavailability option was changed; rebuilding '.
+ 'cache for course ' . $course->id);
+ }
+ $this->showavailability = $mod->showavailability;
+ $this->availablefrom = isset($mod->availablefrom) ? $mod->availablefrom : 0;
+ $this->availableuntil = isset($mod->availableuntil) ? $mod->availableuntil : 0;
+ $this->conditionscompletion = isset($mod->conditionscompletion)
+ ? $mod->conditionscompletion : array();
+ $this->conditionsgrade = isset($mod->conditionsgrade)
+ ? $mod->conditionsgrade : array();
+ }
+
+ // Get module plural name.
+ // TODO This was a very old performance hack and should now be removed as the information
+ // certainly doesn't belong in modinfo. On a 'normal' page this is only used in the
+ // activity_modules block, so if it needs caching, it should be cached there.
+ static $modplurals;
+ if (!isset($modplurals[$this->modname])) {
+ $modplurals[$this->modname] = get_string('modulenameplural', $this->modname);
+ }
+ $this->modplural = $modplurals[$this->modname];
+
+ static $modviews;
+ if (!isset($modviews[$this->modname])) {
+ $modviews[$this->modname] = !plugin_supports('mod', $this->modname,
+ FEATURE_NO_VIEW_LINK);
+ }
+ $this->url = $modviews[$this->modname]
+ ? new moodle_url('/mod/' . $this->modname . '/view.php', array('id'=>$this->id))
+ : null;
+ }
+
+ /**
+ * If dynamic data for this course-module is not yet available, gets it.
+ *
+ * This function is automatically called when constructing course_modinfo, so users don't
+ * need to call it.
+ *
+ * Dynamic data is data which does not come directly from the cache but is calculated at
+ * runtime based on the current user. Primarily this concerns whether the user can access
+ * the module or not.
+ *
+ * As part of this function, the module's _cm_info_dynamic function from its lib.php will
+ * be called (if it exists).
+ * @return void
+ */
+ public function obtain_dynamic_data() {
+ global $CFG;
+ if ($this->state >= self::STATE_DYNAMIC) {
+ return;
+ }
+ $userid = $this->modinfo->get_user_id();
+
+ if (!empty($CFG->enableavailability)) {
+ // Get availability information
+ $ci = new condition_info($this);
+ // Note that the modinfo currently available only includes minimal details (basic data)
+ // so passing it to this function is a bit dangerous as it would cause infinite
+ // recursion if it tried to get dynamic data, however we know that this function only
+ // uses basic data.
+ $this->available = $ci->is_available($this->availableinfo, true,
+ $userid, $this->modinfo);
+ } else {
+ $this->available = true;
+ }
+
+ // Update visible state for current user
+ $this->update_user_visible();
+
+ // Let module make dynamic changes at this point
+ $this->call_mod_function('cm_info_dynamic');
+ $this->state = self::STATE_DYNAMIC;
+ }
+
+ /**
+ * Works out whether activity is visible *for current user* - if this is false, they
+ * aren't allowed to access it.
+ * @return void
+ */
+ private function update_user_visible() {
+ global $CFG;
+ $modcontext = get_context_instance(CONTEXT_MODULE, $this->id);
+ $userid = $this->modinfo->get_user_id();
+ $this->uservisible = true;
+ if ((!$this->visible or !$this->available) and
+ !has_capability('moodle/course:viewhiddenactivities', $modcontext, $userid)) {
+ // If the activity is hidden or unavailable, and you don't have viewhiddenactivities,
+ // set it so that user can't see or access it
+ $this->uservisible = false;
+ } else if (!empty($CFG->enablegroupmembersonly) and !empty($this->groupmembersonly)
+ and !has_capability('moodle/site:accessallgroups', $modcontext, $userid)) {
+ // If the activity has 'group members only' and you don't have accessallgroups...
+ $groups = $this->modinfo->get_groups();
+ if (empty($this->groups[$this->groupingid])) {
+ // ...and you don't belong to a group, then set it so you can't see/access it
+ $this->uservisible = false;
+ }
+ }
+ }
+
+ /**
+ * Calls a module function (if exists), passing in one parameter: this object.
+ * @param string $type Name of function e.g. if this is 'grooblezorb' and the modname is
+ * 'forum' then it will try to call 'mod_forum_grooblezorb' or 'forum_grooblezorb'
+ * @return void
+ */
+ private function call_mod_function($type) {
+ global $CFG;
+ $libfile = $CFG->dirroot . '/mod/' . $this->modname . '/lib.php';
+ if (file_exists($libfile)) {
+ include_once($libfile);
+ $function = 'mod_' . $this->modname . '_' . $type;
+ if (function_exists($function)) {
+ $function($this);
+ } else {
+ $function = $this->modname . '_' . $type;
+ if (function_exists($function)) {
+ $function($this);
+ }
+ }
+ }
+ }
+
+ /**
+ * If view data for this course-module is not yet available, obtains it.
+ *
+ * This function is automatically called if any of the functions (marked) which require
+ * view data are called.
+ *
+ * View data is data which is needed only for displaying the course main page (& any similar
+ * functionality on other pages) but is not needed in general. Obtaining view data may have
+ * a performance cost.
+ *
+ * As part of this function, the module's _cm_info_view function from its lib.php will
+ * be called (if it exists).
+ * @return void
+ */
+ private function obtain_view_data() {
+ if ($this->state >= self::STATE_VIEW) {
+ return;
+ }
+
+ // Let module make changes at this point
+ $this->call_mod_function('cm_info_view');
+ $this->state = self::STATE_VIEW;
+ }
+}
+
+
+/**
+ * Special exception that may only be thrown within the constructor for course_modinfo to
+ * indicate that the cache needs to be rebuilt. Not for use anywhere else.
+ */
+class modinfo_rebuild_cache_exception extends coding_exception {
+ function __construct($why) {
+ // If it ever escapes, that's a code bug
+ parent::__construct('This exception should be caught by code', $why);
+ }
+}
+
+
+/**
+ * Returns reference to full info about modules in course (including visibility).
+ * Cached and as fast as possible (0 or 1 db query).
+ *
+ * @global object
+ * @global object
+ * @global moodle_database
+ * @uses MAX_MODINFO_CACHE_SIZE
+ * @param mixed $course object or 'reset' string to reset caches, modinfo may be updated in db
+ * @param int $userid Defaults to current user id
+ * @return course_modinfo Module information for course, or null if resetting
+ */
+function get_fast_modinfo(&$course, $userid=0) {
+ global $CFG, $USER, $DB;
+ require_once($CFG->dirroot.'/course/lib.php');
+
+ if (!empty($CFG->enableavailability)) {
+ require_once($CFG->libdir.'/conditionlib.php');
+ }
+
+ static $cache = array();
+
+ if ($course === 'reset') {
+ $cache = array();
+ return null;
+ }
+
+ if (empty($userid)) {
+ $userid = $USER->id;
+ }
+
+ if (array_key_exists($course->id, $cache) and $cache[$course->id]->userid == $userid) {
+ return $cache[$course->id];
+ }
+
+ if (!property_exists($course, 'modinfo')) {
+ debugging('Coding problem - missing course modinfo property in get_fast_modinfo() call');
+ }
+
+ unset($cache[$course->id]); // prevent potential reference problems when switching users
+
+ try {
+ $cache[$course->id] = new course_modinfo($course, $userid);
+ } catch (modinfo_rebuild_cache_exception $e) {
+ debugging($e->debuginfo);
+ rebuild_course_cache($course->id, true);
+ $course = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST);
+ // This second time we don't catch the exception - if you request cache rebuild twice
+ // in a row, that's a bug => coding_exception
+ $cache[$course->id] = new course_modinfo($course, $userid);
+ }
+
+ // Ensure cache does not use too much RAM
+ if (count($cache) > MAX_MODINFO_CACHE_SIZE) {
+ reset($cache);
+ $key = key($cache);
+ unset($cache[$key]);
+ }
+
+ return $cache[$course->id];
+}
+
+
+/**
+ * Class that is the return value for the _get_coursemodule_info module API function.
+ *
+ * Note: For backward compatibility, you can also return a stdclass object from that function.
+ * The difference is that the stdclass object may contain an 'extra' field (deprecated because
+ * it was crazy, except for label which uses it differently). The stdclass object may not contain
+ * the new fields defined here (content, extraclasses, customdata).
+ */
+class cached_cm_info {
+ /**
+ * Name (text of link) for this activity; Leave unset to accept default name
+ * @var string
+ */
+ public $name;
+
+ /**
+ * Name of icon for this activity. Normally, this should be used together with $iconcomponent
+ * to define the icon, as per pix_url function.
+ * For backward compatibility, if this value is of the form 'mod/forum/icon' then an icon
+ * within that module will be used.
+ * @see cm_info::get_icon_url()
+ * @see renderer_base::pix_url()
+ * @var string
+ */
+ public $icon;
+
+ /**
+ * Component for icon for this activity, as per pix_url; leave blank to use default 'moodle'
+ * component
+ * @see renderer_base::pix_url()
+ * @var string
+ */
+ public $iconcomponent;
+
+ /**
+ * HTML content to be displayed on the main page below the link (if any) for this course-module
+ * @var string
+ */
+ public $content;
+
+ /**
+ * Custom data to be stored in modinfo for this activity; useful if there are cases when
+ * internal information for this activity type needs to be accessible from elsewhere on the
+ * course without making database queries. May be of any type but should be short.
+ * @var mixed
+ */
+ public $customdata;
+
+ /**
+ * Extra CSS class or classes to be added when this activity is displayed on the main page;
+ * space-separated string
+ * @var string
+ */
+ public $extraclasses;
+
+ /**
+ * Content of onclick JavaScript; escaped HTML to be inserted as attribute value
+ * @var string
+ */
+ public $onclick;
+}
View
268 lib/moodlelib.php
@@ -352,6 +352,8 @@
/** True if module has custom completion rules */
define('FEATURE_COMPLETION_HAS_RULES', 'completion_has_rules');
+/** True if module has no 'view' page (like label) */
+define('FEATURE_NO_VIEW_LINK', 'viewlink');
/** True if module supports outcomes */
define('FEATURE_IDNUMBER', 'idnumber');
/** True if module supports groups */
@@ -2312,6 +2314,14 @@ function require_login($courseorid = NULL, $autologinguest = true, $cm = NULL, $
if ($cm->course != $course->id) {
throw new coding_exception('course and cm parameters in require_login() call do not match!!');
}
+ // make sure we have a $cm from get_fast_modinfo as this contains activity access details
+ if (!($cm instanceof cm_info)) {
+ // note: nearly all pages call get_fast_modinfo anyway and it does not make any
+ // db queries so this is not really a performance concern, however it is obviously
+ // better if you use get_fast_modinfo to get the cm before calling this.
+ $modinfo = get_fast_modinfo($course);
+ $cm = $modinfo->get_cm($cm->id);
+ }
$PAGE->set_cm($cm, $course); // set's up global $COURSE
$PAGE->set_pagelayout('incourse');
} else {
@@ -2583,47 +2593,15 @@ function require_login($courseorid = NULL, $autologinguest = true, $cm = NULL, $
}
}
- // test visibility
- if ($cm && !$cm->visible && !has_capability('moodle/course:viewhiddenactivities', $cmcontext)) {
+ // Check visibility of activity to current user; includes visible flag, groupmembersonly,
+ // conditional availability, etc
+ if ($cm && !$cm->uservisible) {
if ($preventredirect) {
throw new require_login_exception('Activity is hidden');
}
redirect($CFG->wwwroot, get_string('activityiscurrentlyhidden'));
}
- // groupmembersonly access control
- if (!empty($CFG->enablegroupmembersonly) and $cm and $cm->groupmembersonly and !has_capability('moodle/site:accessallgroups', get_context_instance(CONTEXT_MODULE, $cm->id))) {
- if (isguestuser() or !groups_has_membership($cm)) {
- if ($preventredirect) {
- throw new require_login_exception('Not member of a group');
- }
- print_error('groupmembersonlyerror', 'group', $CFG->wwwroot.'/course/view.php?id='.$cm->course);
- }
- }
-
- // Conditional activity access control
- if (!empty($CFG->enableavailability) and $cm) {
- // TODO: this is going to work with login-as-user, sorry!
- // We cache conditional access in session
- if (!isset($SESSION->conditionaccessok)) {
- $SESSION->conditionaccessok = array();
- }
- // If you have been allowed into the module once then you are allowed
- // in for rest of session, no need to do conditional checks
- if (!array_key_exists($cm->id, $SESSION->conditionaccessok)) {
- // Get condition info (does a query for the availability table)
- require_once($CFG->libdir.'/conditionlib.php');
- $ci = new condition_info($cm, CONDITION_MISSING_EXTRATABLE);
- // Check condition for user (this will do a query if the availability
- // information depends on grade or completion information)
- if ($ci->is_available($junk) || has_capability('moodle/course:viewhiddenactivities', $cmcontext)) {
- $SESSION->conditionaccessok[$cm->id] = true;
- } else {
- print_error('activityiscurrentlyhidden');
- }
- }
- }
-
// Finally access granted, update lastaccess times
user_accesstime_log($course->id);
}
@@ -2674,16 +2652,29 @@ function require_logout() {
*/
function require_course_login($courseorid, $autologinguest = true, $cm = NULL, $setwantsurltome = true, $preventredirect = false) {
global $CFG, $PAGE, $SITE;
+ $issite = (is_object($courseorid) and $courseorid->id == SITEID)
+ or (!is_object($courseorid) and $courseorid == SITEID);
+ if ($issite && !empty($cm) && !($cm instanceof cm_info)) {
+ // note: nearly all pages call get_fast_modinfo anyway and it does not make any
+ // db queries so this is not really a performance concern, however it is obviously
+ // better if you use get_fast_modinfo to get the cm before calling this.
+ if (is_object($courseorid)) {
+ $course = $courseorid;
+ } else {
+ $course = clone($SITE);
+ }
+ $modinfo = get_fast_modinfo($course);
+ $cm = $modinfo->get_cm($cm->id);
+ }
if (!empty($CFG->forcelogin)) {
// login required for both SITE and courses
require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
- } else if (!empty($cm) and !$cm->visible) {
+ } else if ($issite && !empty($cm) and !$cm->uservisible) {
// always login for hidden activities
require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
- } else if ((is_object($courseorid) and $courseorid->id == SITEID)
- or (!is_object($courseorid) and $courseorid == SITEID)) {
+ } else if ($issite) {
//login for SITE not required
if ($cm and empty($cm->visible)) {
// hidden activities are not accessible without login
@@ -3007,207 +2998,6 @@ function reset_login_count() {
}
/**
- * Returns reference to full info about modules in course (including visibility).
- * Cached and as fast as possible (0 or 1 db query).
- *
- * @global object
- * @global object
- * @global object
- * @uses CONTEXT_MODULE
- * @uses MAX_MODINFO_CACHE_SIZE
- * @param mixed $course object or 'reset' string to reset caches, modinfo may be updated in db
- * @param int $userid Defaults to current user id
- * @return mixed courseinfo object or nothing if resetting
- */
-function &get_fast_modinfo(&$course, $userid=0) {
- global $CFG, $USER, $DB;
- require_once($CFG->dirroot.'/course/lib.php');
-
- if (!empty($CFG->enableavailability)) {
- require_once($CFG->libdir.'/conditionlib.php');
- }
-
- static $cache = array();
-
- if ($course === 'reset') {
- $cache = array();
- $nothing = null;
- return $nothing; // we must return some reference
- }
-
- if (empty($userid)) {
- $userid = $USER->id;
- }
-
- if (array_key_exists($course->id, $cache) and $cache[$course->id]->userid == $userid) {
- return $cache[$course->id];
- }
-
- if (!property_exists($course, 'modinfo')) {
- debugging('Coding problem - missing course modinfo property in get_fast_modinfo() call');
- }
-
- if (empty($course->modinfo)) {
- // no modinfo yet - load it
- rebuild_course_cache($course->id);
- $course->modinfo = $DB->get_field('course', 'modinfo', array('id'=>$course->id));
- }
-
- $modinfo = new stdClass();
- $modinfo->courseid = $course->id;
- $modinfo->userid = $userid;
- $modinfo->sections = array();
- $modinfo->cms = array();
- $modinfo->instances = array();
- $modinfo->groups = null; // loaded only when really needed - the only one db query
-
- $info = unserialize($course->modinfo);
- if (!is_array($info)) {
- // hmm, something is wrong - lets try to fix it
- rebuild_course_cache($course->id);
- $course->modinfo = $DB->get_field('course', 'modinfo', array('id'=>$course->id));
- $info = unserialize($course->modinfo);
- if (!is_array($info)) {
- return $modinfo;
- }
- }
-
- if ($info) {
- // detect if upgrade required
- $first = reset($info);
- if (!isset($first->id)) {
- rebuild_course_cache($course->id);
- $course->modinfo = $DB->get_field('course', 'modinfo', array('id'=>$course->id));
- $info = unserialize($course->modinfo);
- if (!is_array($info)) {
- return $modinfo;
- }
- }
- }
-
- $modlurals = array();
-
- // If we haven't already preloaded contexts for the course, do it now
- preload_course_contexts($course->id);
-
- foreach ($info as $mod) {
- if (empty($mod->name)) {
- // something is wrong here
- continue;
- }
- // reconstruct minimalistic $cm
- $cm = new stdClass();
- $cm->id = $mod->cm;
- $cm->instance = $mod->id;
- $cm->course = $course->id;
- $cm->modname = $mod->mod;
- $cm->idnumber = $mod->idnumber;
- $cm->name = $mod->name;
- $cm->visible = $mod->visible;
- $cm->sectionnum = $mod->section;
- $cm->groupmode = $mod->groupmode;
- $cm->groupingid = $mod->groupingid;
- $cm->groupmembersonly = $mod->groupmembersonly;
- $cm->indent = $mod->indent;
- $cm->completion = $mod->completion;
- $cm->extra = isset($mod->extra) ? $mod->extra : '';
- $cm->icon = isset($mod->icon) ? $mod->icon : '';
- $cm->iconcomponent = isset($mod->iconcomponent) ? $mod->iconcomponent : '';
- $cm->uservisible = true;
- if (!empty($CFG->enableavailability)) {
- // We must have completion information from modinfo. If it's not
- // there, cache needs rebuilding
- if(!isset($mod->availablefrom)) {
- debugging('enableavailability option was changed; rebuilding '.
- 'cache for course '.$course->id);
- rebuild_course_cache($course->id,true);
- // Re-enter this routine to do it all properly
- return get_fast_modinfo($course, $userid);
- }
- $cm->availablefrom = $mod->availablefrom;
- $cm->availableuntil = $mod->availableuntil;
- $cm->showavailability = $mod->showavailability;
- $cm->conditionscompletion = $mod->conditionscompletion;
- $cm->conditionsgrade = $mod->conditionsgrade;
- }
-
- // preload long names plurals and also check module is installed properly
- if (!isset($modlurals[$cm->modname])) {
- if (!file_exists("$CFG->dirroot/mod/$cm->modname/lib.php")) {
- continue;
- }
- $modlurals[$cm->modname] = get_string('modulenameplural', $cm->modname);
- }
- $cm->modplural = $modlurals[$cm->modname];
- $modcontext = get_context_instance(CONTEXT_MODULE,$cm->id);
-
- if (!empty($CFG->enableavailability)) {
- // Unfortunately the next call really wants to call
- // get_fast_modinfo, but that would be recursive, so we fake up a
- // modinfo for it already
- if (empty($minimalmodinfo)) { //TODO: this is suspicious (skodak)
- $minimalmodinfo = new stdClass();
- $minimalmodinfo->cms = array();
- foreach($info as $mod) {
- if (empty($mod->name)) {
- // something is wrong here
- continue;
- }
- $minimalcm = new stdClass();
- $minimalcm->id = $mod->cm;
- $minimalcm->name = $mod->name;
- $minimalmodinfo->cms[$minimalcm->id]=$minimalcm;
- }
- }
-
- // Get availability information
- $ci = new condition_info($cm);
- $cm->available = $ci->is_available($cm->availableinfo, true, $userid, $minimalmodinfo);
- } else {
- $cm->available = true;
- }
- if ((!$cm->visible or !$cm->available) and !has_capability('moodle/course:viewhiddenactivities', $modcontext, $userid)) {
- $cm->uservisible = false;
-
- } else if (!empty($CFG->enablegroupmembersonly) and !empty($cm->groupmembersonly)
- and !has_capability('moodle/site:accessallgroups', $modcontext, $userid)) {
- if (is_null($modinfo->groups)) {
- $modinfo->groups = groups_get_user_groups($course->id, $userid);
- }
- if (empty($modinfo->groups[$cm->groupingid])) {
- $cm->uservisible = false;
- }
- }
-
- if (!isset($modinfo->instances[$cm->modname])) {
- $modinfo->instances[$cm->modname] = array();
- }
- $modinfo->instances[$cm->modname][$cm->instance] =& $cm;
- $modinfo->cms[$cm->id] =& $cm;
-
- // reconstruct sections
- if (!isset($modinfo->sections[$cm->sectionnum])) {
- $modinfo->sections[$cm->sectionnum] = array();
- }
- $modinfo->sections[$cm->sectionnum][] = $cm->id;
-
- unset($cm);
- }
-
- unset($cache[$course->id]); // prevent potential reference problems when switching users
- $cache[$course->id] = $modinfo;
-
- // Ensure cache does not use too much RAM
- if (count($cache) > MAX_MODINFO_CACHE_SIZE) {
- reset($cache);
- $key = key($cache);
- unset($cache[$key]);
- }
-
- return $cache[$course->id];
-}
-
-/**
* Determines if the currently logged in user is in editing mode.
* Note: originally this function had $userid parameter - it was not usable anyway
*
View
28 lib/navigationlib.php
@@ -1026,10 +1026,14 @@ public function initialise() {
if ($course->id !== SITEID) {
// Find the section for the $CM associated with the page and collect
// its section number.
- foreach ($sections as $section) {
- if ($section->id == $cm->section) {
- $cm->sectionnumber = $section->section;
- break;
+ if (isset($cm->sectionnum)) {
+ $cm->sectionnumber = $cm->sectionnum;
+ } else {
+ foreach ($sections as $section) {
+ if ($section->id == $cm->section) {
+ $cm->sectionnumber = $section->section;
+ break;
+ }
}
}
@@ -1429,10 +1433,10 @@ public function load_generic_course_sections(stdClass $course, navigation_node $
*
* @param navigation_node $sectionnode
* @param int $sectionnumber
- * @param stdClass $modinfo Object returned from {@see get_fast_modinfo()}
+ * @param course_modinfo $modinfo Object returned from {@see get_fast_modinfo()}
* @return array Array of activity nodes
*/
- protected function load_section_activities(navigation_node $sectionnode, $sectionnumber, $modinfo) {
+ protected function load_section_activities(navigation_node $sectionnode, $sectionnumber, course_modinfo $modinfo) {
if (!array_key_exists($sectionnumber, $modinfo->sections)) {
return true;
}
@@ -1449,11 +1453,12 @@ protected function load_section_activities(navigation_node $sectionnode, $sectio
} else {
$icon = new pix_icon('icon', get_string('modulename', $cm->modname), $cm->modname);
}
- $url = new moodle_url('/mod/'.$cm->modname.'/view.php', array('id'=>$cm->id));
+ $url = $cm->get_url();
$activitynode = $sectionnode->add(format_string($cm->name), $url, navigation_node::TYPE_ACTIVITY, null, $cm->id, $icon);
$activitynode->title(get_string('modulename', $cm->modname));
$activitynode->hidden = (!$cm->visible);
- if ($cm->modname == 'label') {
+ if (!$url) {
+ // Do not show activities that don't have links!
$activitynode->display = false;
} else if ($this->module_extends_navigation($cm->modname)) {
$activitynode->nodetype = navigation_node::NODETYPE_BRANCH;
@@ -1482,11 +1487,12 @@ protected function load_stealth_activity(navigation_node $coursenode, $modinfo)
} else {
$icon = new pix_icon('icon', get_string('modulename', $cm->modname), $cm->modname);
}
- $url = new moodle_url('/mod/'.$cm->modname.'/view.php', array('id'=>$cm->id));
+ $url = $cm->get_url();
$activitynode = $coursenode->add(format_string($cm->name), $url, navigation_node::TYPE_ACTIVITY, null, $cm->id, $icon);
$activitynode->title(get_string('modulename', $cm->modname));
$activitynode->hidden = (!$cm->visible);
- if ($cm->modname == 'label') {
+ if (!$url) {
+ // Don't show activities that don't have links!
$activitynode->display = false;
} else if ($this->module_extends_navigation($cm->modname)) {
$activitynode->nodetype = navigation_node::NODETYPE_BRANCH;
@@ -1509,7 +1515,7 @@ protected function load_stealth_activity(navigation_node $coursenode, $modinfo)
* @param navigation_node $activity
* @return bool
*/
- protected function load_activity(stdClass $cm, stdClass $course, navigation_node $activity) {
+ protected function load_activity($cm, stdClass $course, navigation_node $activity) {
global $CFG, $DB;
$activity->make_active();
View
1  lib/setup.php
@@ -414,6 +414,7 @@
require_once($CFG->libdir .'/sessionlib.php'); // All session and cookie related stuff
require_once($CFG->libdir .'/editorlib.php'); // All text editor related functions and classes
require_once($CFG->libdir .'/messagelib.php'); // Messagelib functions
+require_once($CFG->libdir .'/modinfolib.php'); // Cached information on course-module instances
// make sure PHP is not severly misconfigured
setup_validate_php_configuration();
View
3  lib/weblib.php
@@ -2181,7 +2181,8 @@ function navmenulist($course, $sections, $modinfo, $strsection, $strjumpto, $wid
$menu[] = '<ul class="navmenulist"><li class="jumpto section"><span>'.$strjumpto.'</span><ul>';
foreach ($modinfo->cms as $mod) {
- if ($mod->modname == 'label') {
+ if (!$mod->has_view()) {
+ // Don't show modules which you can't link to!
continue;
}
View
32 mod/forum/lib.php
@@ -7792,3 +7792,35 @@ public function find_users($search) {
}
}
+
+/**
+ * Adds information about unread messages, that is only required for the course view page (and
+ * similar), to the course-module object.
+ * @param cm_info $cm Course-module object
+ */
+function forum_cm_info_view(cm_info $cm) {
+ global $CFG;
+
+ // Get tracking status (once per request)
+ static $initialised;
+ static $usetracking, $strunreadpostsone;
+ if (!isset($initialised)) {
+ if ($usetracking = forum_tp_can_track_forums()) {
+ $strunreadpostsone = get_string('unreadpostsone', 'forum');
+ }
+ $initialised = true;
+ }
+
+ if ($usetracking) {
+ if ($unread = forum_tp_count_forum_unread_posts($cm, $cm->get_course())) {
+ $out = '<span class="unread"> <a href="' . $cm->get_url() . '">';
+ if ($unread == 1) {
+ $out .= $strunreadpostsone;
+ } else {
+ $out .= get_string('unreadpostsnumber', 'forum', $unread);
+ }
+ $out .= '</a></span>';
+ $cm->set_after_link($out);
+ }
+ }
+}
View
1  mod/label/lib.php
@@ -209,6 +209,7 @@ function label_supports($feature) {
case FEATURE_GRADE_OUTCOMES: return false;
case FEATURE_MOD_ARCHETYPE: return MOD_ARCHETYPE_RESOURCE;
case FEATURE_BACKUP_MOODLE2: return true;
+ case FEATURE_NO_VIEW_LINK: return true;
default: return null;
}
Please sign in to comment.
Something went wrong with that request. Please try again.