<?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/>. /** * Course overview block for UW Moodle * * This block improves on the course_summary block by presenting courses sorted by term. * It also allows showing/hiding of terms and course news summaries. * * The block is dependent on the UW enrollment plugins. * * @author Matt Petro */ require_once($CFG->dirroot.'/lib/weblib.php'); class block_course_overview_uwmoodle extends block_base { /** * block initializations */ public function init() { $this->title = get_string('pluginname', 'block_course_overview_uwmoodle'); } const TERM_OTHER = 0; // UW "term_code" for non-timetable classes /** * block contents * * @return object */ public function get_content() { global $USER, $CFG, $PAGE, $OUTPUT, $DB; if($this->content !== NULL) { return $this->content; } ob_start(); $courses = enrol_get_my_courses('id, shortname, modinfo, sectioncache', 'visible DESC,sortorder ASC', 0); $site = get_site(); $course = $site; //just in case we need the old global $course hack // Keep track of hideable items for initializing javascript $yuiitems = array(); // Process GET parameters. Generally AJAX will be used instead of these. $uwmterm = optional_param('uwmterm', null, PARAM_INT); $uwmcourse = optional_param('uwmcourse', null, PARAM_INT); $uwmshow = optional_param('uwmshow', 1, PARAM_INT); if (!is_null($uwmterm)) { set_user_preference('block_course_overview_uwmoodle-show-term-'.$uwmterm, $uwmshow); } if (!is_null($uwmcourse)) { set_user_preference('block_course_overview_uwmoodle-show-coursenews-'.$uwmcourse, $uwmshow); } $currentterm = get_config('block_course_overview_uwmoodle', 'currentterm'); if (!$currentterm) { $currentterm = self::TERM_OTHER; } // Find the termcode for each course if (!empty($courses)) { $courseids = array(); foreach ($courses as $course) { $courseids[] = $course->id; } list ($insql, $inparams) = $DB->get_in_or_equal($courseids); $select = "enrol='wisc' AND courseid $insql"; $enrols = $DB->get_records_select('enrol', $select, $inparams, '', 'id,courseid,customchar1'); foreach ($enrols as $enrol) { if (empty($courses[$enrol->courseid]->term) || $courses[$enrol->courseid]->term < $enrol->customchar1) { $courses[$enrol->courseid]->term = $enrol->customchar1; } } } // Sort courses by course shortname uasort($courses, function($a,$b) { if ($a->shortname == $b->shortname) {return 0;} return ($a->shortname > $b->shortname)? 1 : -1;} ); // Organize courses into terms, maintaining shortname sorting inside each term $terms = array(); foreach ($courses as $course) { if (!empty($course->term)) { $terms[$course->term][] = $course; } else { $terms[self::TERM_OTHER][] = $course; } } // Sort terms, descending // TERM_OTHER courses get ordered right after current term $sortfcn = function($a,$b) use ($currentterm) { if ($a == self::TERM_OTHER) { $a = $currentterm - 0.5; } if ($b == self::TERM_OTHER) { $b = $currentterm - 0.5; } if ($a == $b) {return 0;} return ($a > $b)? -1 : 1; }; uksort($terms, $sortfcn); // Update lastaccess for news summary foreach ($courses as $c) { if (isset($USER->lastcourseaccess[$c->id])) { $courses[$c->id]->lastaccess = $USER->lastcourseaccess[$c->id]; } else { $courses[$c->id]->lastaccess = 0; } } if (empty($courses)) { echo get_string('nocourses','my'); } else { // Get modinfo -- copied from print_overview() $htmlarray = array(); if ($modules = $DB->get_records('modules')) { foreach ($modules as $mod) { if (file_exists($CFG->dirroot.'/mod/'.$mod->name.'/lib.php')) { include_once($CFG->dirroot.'/mod/'.$mod->name.'/lib.php'); $fname = $mod->name.'_print_overview'; if (function_exists($fname)) { $fname($courses,$htmlarray); } } } } // display courses echo '<div class="courselist">'; echo '<ul class="treelist">'; foreach ($terms as $termcode=>$termcourses) { $yuiitems[] = "term-$termcode"; $termname = $this->get_term_name($termcode); $defaultshowterm = ($termcode == $currentterm || $termcode == self::TERM_OTHER)? 1 : 0; $showterm = get_user_preferences("block_course_overview_uwmoodle-show-term-$termcode", $defaultshowterm); if (!$showterm) { $class = 'collapsed'; $ariaexpanded = "aria-expanded='false'"; } else { $class = ''; $ariaexpanded = "aria-expanded='true'"; } if ($termcode == $currentterm) { $termclass = 'currentterm'; } else if ($termcode == self::TERM_OTHER) { $termclass = 'miscterm'; } else { $termclass = 'noncurrentterm'; } $aria = "$ariaexpanded aria-controls='uwm-{$this->instance->id}-term-$termcode-list' role='button'"; $showhidetermurl = $PAGE->url->out_as_local_url(true, array('uwmterm' => $termcode, 'uwmshow' => ($showterm)? 0 : 1 )); echo "<li class='$class'>"; echo "<h3 class='$termclass'>"; // The data-ajax attribute prevents the Moodle mobile theme from overriding the AJAX behavior echo "<a class='showhide' data-ajax='false' $aria href='$showhidetermurl' id='uwm-{$this->instance->id}-term-$termcode'><span class='term treeitem'>$termname</span></a>"; echo "</h3>"; echo "<ul class='treelist' id='uwm-{$this->instance->id}-term-$termcode-list' role='region'>"; foreach ($termcourses as $course) { $fullname = format_string($course->fullname, true, array('context' => get_context_instance(CONTEXT_COURSE, $course->id))); $hasnews = !empty($htmlarray[$course->id]); $attributes = array('title' => s($fullname)); if (empty($course->visible)) { $attributes['class'] = 'dimmed'; } $newsclass = ''; $showhidehtml = ''; if ($hasnews) { $defaultshownews = ($termcode == $currentterm || $termcode == self::TERM_OTHER)? 1 : 0; $shownews = get_user_preferences('block_course_overview_uwmoodle-show-coursenews-'.$course->id, 1); $yuiitems[] = "coursenews-$course->id"; $showhidenewsurl = $PAGE->url->out_as_local_url(true, array('uwmcourse' => $course->id, 'uwmshow' => ($shownews)? 0 : 1)); if (!$shownews) { $newsclass = 'collapsed'; $showhidetext = "Show"; $ariaexpanded = "aria-expanded='false'"; } else { $newsclass = ''; $showhidetext = "Hide"; $ariaexpanded = "aria-expanded='true'"; } $aria = "$ariaexpanded aria-controls='uwm-{$this->instance->id}-coursenews-{$course->id}-list' role='button'"; // The data-ajax attribute prevents the Moodle mobile theme from overriding the AJAX behavior $showhidehtml = "<div class='shownews'><a data-ajax='false' $aria href='$showhidenewsurl' id='uwm-{$this->instance->id}-coursenews-$course->id' >"; $showhidehtml .= "<span class='coursenews treeitem'><span class='showhidetext'>$showhidetext</span> news"; $showhidehtml .= "</span></a></div>"; } echo "<li class='$newsclass'>"; echo $OUTPUT->box_start("coursebox"); echo $OUTPUT->heading(html_writer::link( new moodle_url('/course/view.php', array('id' => $course->id)), $fullname, $attributes) . $showhidehtml, 3); if ($hasnews) { echo "<ul class='treelist' id='uwm-{$this->instance->id}-coursenews-{$course->id}-list' role='region'>"; foreach ($htmlarray[$course->id] as $modname => $html) { echo "<li>$html</li>"; } echo "</ul>"; } echo $OUTPUT->box_end(); echo "</li>"; } echo "</ul>"; echo '</li>'; } echo '</ul>'; echo "</div>"; } // Initialize YUI module if needed if (!empty($yuiitems)) { $arguments = array( 'id' => $this->instance->id, 'items' => implode(' ', $yuiitems), ); $PAGE->requires->yui_module('moodle-block_course_overview_uwmoodle-showhide', 'M.block_course_overview_uwmoodle.initialize', array($arguments)); foreach ($yuiitems as $item) { user_preference_allow_ajax_update('block_course_overview_uwmoodle-show-'.$item, PARAM_INT); } } // Get and end output buffer $content = ob_get_contents(); ob_end_clean(); $this->content = new stdClass(); $this->content->footer = ''; $this->content->text = $content; // Show "more courses" link if appropriate if (has_capability('moodle/course:update', get_context_instance(CONTEXT_SYSTEM)) || empty($CFG->block_course_list_hideallcourseslink)) { $this->content->footer = "<a href=\"$CFG->wwwroot/course/index.php\">".get_string("fulllistofcourses")."</a> ..."; } return $this->content; } /** * Return a string representing the term (e.g. "Fall 2010") * This function doesn't make any remote calls. * * @param string $termCode * @return string $termName */ public function get_term_name($termCode) { $termCode = (string)$termCode; $c = substr($termCode,0,1); $yy = substr($termCode,1,2); $year = 1900+100*$c+$yy; $semester = substr($termCode,3,1); switch($semester) { case 2: $name = sprintf("Fall %d courses", $year-1); break; case 3: $name = sprintf("Winter %d courses", $year); break; case 4: $name = sprintf("Spring %d courses", $year); break; case 6: $name = sprintf("Summer %d courses", $year); break; default: $name = "Miscellaneous courses"; } return $name; } /** * Get the current term from the datastore, and update user show/hide preferences when it changes. * * @return boolean true on success */ public function update_current_term() { global $CFG, $DB; $oldcurrentterm = get_config('block_course_overview_uwmoodle', 'currentterm'); try { $currentterm = $this->get_current_term(); } catch (Exception $e) { mtrace("Error fetching current term: ".$e->getMessage()); return false; } if ($currentterm === false) { mtrace("No current term found"); return false; } if ($currentterm === $oldcurrentterm) { // no change, so return return true; } mtrace('new current term: '.$currentterm); // New term, so clear user preferences for both current and previous term if ($oldcurrentterm) { $DB->delete_records('user_preferences', array('name'=> 'block_course_overview_uwmoodle-show-term-'.$oldcurrentterm)); } $DB->delete_records('user_preferences', array('name'=> 'block_course_overview_uwmoodle-show-term-'.$currentterm)); set_config('currentterm', $currentterm, 'block_course_overview_uwmoodle'); return true; } /** * Fetch current term from CHUB. Throw exception on CHUB error. * * @return string|false term_code or false if none found. */ public function get_current_term() { global $CFG; require_once($CFG->dirroot.'/enrol/wisc/lib/datastore.php'); $datastore = wisc_timetable_datastore::get_timetable_datastore(); $terms = $datastore->getAvailableTerms(); $now = time(); $futureterms = array(); foreach ($terms as $term) { // check that term hasn't ended and doesn't have an odd termCode // odd term codes (e.g. Winter) are never considered the current term if ($term->endDate > $now && ($term->termCode % 2 != 1)) { $futureterms[] = $term->termCode; } } if (!empty($futureterms)) { $currentterm = min($futureterms); } else { $currentterm = false; } return $currentterm; } /** * allow the block to have a configuration page * * @return boolean */ public function has_config() { return false; } /** * locations where block can be displayed * * @return array */ public function applicable_formats() { return array('my-index'=>true); } /** * Block cron to update currentterm * * @return boolean true on success */ public function cron() { return $this->update_current_term(); } }