diff --git a/block_course_overview_uwmoodle.php b/block_course_overview_uwmoodle.php index 5c5c0cbbf7aeed6f745b6244e99042d9188bbd45..346bd92f2db5ecc7041e383c5c3fb86f92df45bb 100644 --- a/block_course_overview_uwmoodle.php +++ b/block_course_overview_uwmoodle.php @@ -21,12 +21,13 @@ * 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. + * The block is dependent on the UW enrollment plugins and is largely coped from the existing course_overview block. + * I've left copyright statements for the original authors on most files. * * @author Matt Petro */ -require_once($CFG->dirroot.'/lib/weblib.php'); +require_once($CFG->dirroot.'/blocks/course_overview_uwmoodle/locallib.php'); class block_course_overview_uwmoodle extends block_base { /** @@ -36,7 +37,7 @@ class block_course_overview_uwmoodle extends block_base { $this->title = get_string('pluginname', 'block_course_overview_uwmoodle'); } - const TERM_OTHER = 0; // UW "term_code" for non-timetable classes + const TERM_OTHER = 0; // our "term_code" for non-timetable classes /** * block contents @@ -44,272 +45,57 @@ class block_course_overview_uwmoodle extends block_base { * @return object */ public function get_content() { - global $USER, $CFG, $PAGE, $OUTPUT, $DB; + global $USER, $CFG, $DB; + if($this->content !== NULL) { return $this->content; } - ob_start(); + $config = get_config('block_course_overview_uwmoodle'); - $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 + $this->content = new stdClass(); + $this->content->text = ''; + $this->content->footer = "<a href=\"$CFG->wwwroot/course/index.php\">".get_string("fulllistofcourses")."</a> ...";; - // Keep track of hideable items for initializing javascript - $yuiitems = array(); + $content = array();$this->content->text .= - // 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); - } + profile_load_custom_fields($USER); + $courses = block_course_overview_uwmoodle_get_sorted_courses(); - $currentterm = get_config('block_course_overview_uwmoodle', 'currentterm'); - if (!$currentterm) { - $currentterm = self::TERM_OTHER; - } + $terms = block_course_overview_uwmoodle_group_courses_by_term($courses); - // 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; - } - } + $currentterm = block_course_overview_uwmoodle_get_current_term(); + $selectedterm = optional_param('term', $currentterm, PARAM_INT); - // Sort terms with the current term and Misc terms first, followed by others in decreasing order - $sortedterms = array(); - if (isset($terms[$currentterm])) { - $sortedterms[$currentterm] = $terms[$currentterm]; - unset($terms[$currentterm]); + if (!isset($terms[$currentterm])) { + $terms[$currentterm] = array(); } - if (isset($terms[self::TERM_OTHER])) { - $sortedterms[self::TERM_OTHER] = $terms[self::TERM_OTHER]; - unset($terms[self::TERM_OTHER]); + if (!isset($terms[self::TERM_OTHER])) { + $terms[self::TERM_OTHER] = array(); } - ksort($terms); - $terms = array_reverse($terms, true); - // can't use array_merge as the termCodes are numeric, and we want them preserved - foreach ($terms as $termCode=>$term) { - $sortedterms[$termCode] = $term; - } - $terms = $sortedterms; - - // 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">'; - $incurrentterms = true; - foreach ($terms as $termcode=>$termcourses) { - - if ($incurrentterms && $termcode != $currentterm && $termcode != self::TERM_OTHER) { - //display the separator between current and other terms - echo '<hr />'; - echo '<h3>Other semesters</h3>'; - $incurrentterms = false; - } - if ($termcode != $currentterm) { - $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 ($termcode == $currentterm) { - $showterm = true; // force current term to be visible - } - 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(true, array('uwmterm' => $termcode, 'uwmshow' => ($showterm)? 0 : 1 )); - - echo "<li class='$class'>"; - if ($termcode == $currentterm) { - echo "<h3 class='$termclass'>$termname</h3>"; - } else { - 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, $defaultshownews); - $yuiitems[] = "coursenews-$course->id"; - $showhidenewsurl = $PAGE->url->out(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>"; - + if (!isset($terms[$selectedterm])) { + $selectedterm = $currentterm; } - // 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)); + $displayedcourses = $terms[self::TERM_OTHER] + $terms[$selectedterm]; + $overviews = block_course_overview_uwmoodle_get_overviews($displayedcourses); - foreach ($yuiitems as $item) { - user_preference_allow_ajax_update('block_course_overview_uwmoodle-show-'.$item, PARAM_INT); - } + $renderer = $this->page->get_renderer('block_course_overview_uwmoodle'); + if (!empty($config->showwelcomearea)) { + require_once($CFG->dirroot.'/message/lib.php'); + $msgcount = message_count_unread_messages(); + $this->content->text = $renderer->welcome_area($msgcount); } - // 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> ..."; + $this->content->text .= $renderer->course_header($terms, $selectedterm); + $this->content->text .= $renderer->course_overview($terms[$selectedterm], $overviews); + if (!empty($terms[self::TERM_OTHER])) { + $this->content->text .= $renderer->other_header(); + $this->content->text .= $renderer->course_overview($terms[self::TERM_OTHER], $overviews); } - 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. * @@ -381,7 +167,7 @@ class block_course_overview_uwmoodle extends block_base { * @return boolean */ public function has_config() { - return false; + return true; } /** @@ -401,4 +187,15 @@ class block_course_overview_uwmoodle extends block_base { public function cron() { return $this->update_current_term(); } + + /** + * Sets block header to be hidden or visible + * + * @return bool if true then header will be visible. + */ + public function hide_header() { + // Hide header if welcome area is show. + $config = get_config('block_course_overview_uwmoodle'); + return !empty($config->showwelcomearea); + } } \ No newline at end of file diff --git a/db/access.php b/db/access.php new file mode 100644 index 0000000000000000000000000000000000000000..6944b7ebd39257e0480f54b9ab09d8eb9c5fb6d0 --- /dev/null +++ b/db/access.php @@ -0,0 +1,38 @@ +<?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 caps. + * + * @package block_course_overview + * @copyright Mark Nelson <markn@moodle.com> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = array( + + 'block/course_overview_uwmoodle:myaddinstance' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_SYSTEM, + 'archetypes' => array( + 'user' => CAP_ALLOW + ), + + 'clonepermissionsfrom' => 'moodle/my:manageblocks' + ) +); diff --git a/lang/en/block_course_overview_uwmoodle.php b/lang/en/block_course_overview_uwmoodle.php index 18394bd23f58b65c1b6442c3119d3ada8722ba9e..6bb6514dad2955f95a9d6a990429e22b6827e040 100644 --- a/lang/en/block_course_overview_uwmoodle.php +++ b/lang/en/block_course_overview_uwmoodle.php @@ -18,3 +18,6 @@ defined('MOODLE_INTERNAL') || die(); $string['pluginname'] = 'UW Moodle course overview'; +$string['mycoursesinterm'] = 'My courses in term:'; +$string['othercourses'] = 'Other courses'; +$string['nocourses'] = 'You are not enrolled in any courses for this term.'; \ No newline at end of file diff --git a/locallib.php b/locallib.php new file mode 100644 index 0000000000000000000000000000000000000000..97f25280717668a7f852fc7a1938363fd9b189ca --- /dev/null +++ b/locallib.php @@ -0,0 +1,188 @@ +<?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/>. + +/** + * Helper functions for course_overview block + * + * @package block_course_overview_uwmoodle + * @copyright 2012 Adam Olley <adam.olley@netspot.com.au> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * Display overview for courses + * + * @param array $courses courses for which overview needs to be shown + * @return array html overview + */ +function block_course_overview_uwmoodle_get_overviews($courses) { + $htmlarray = array(); + if ($modules = get_plugin_list_with_function('mod', 'print_overview')) { + foreach ($modules as $fname) { + $fname($courses,$htmlarray); + } + } + return $htmlarray; +} + +/** + * Returns shortname of activities in course + * + * @param int $courseid id of course for which activity shortname is needed + * @return string|bool list of child shortname + */ +function block_course_overview_uwmoodle_get_child_shortnames($courseid) { + global $DB; + $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); + $sql = "SELECT c.id, c.shortname, $ctxselect + FROM {enrol} e + JOIN {course} c ON (c.id = e.customint1) + JOIN {context} ctx ON (ctx.instanceid = e.customint1) + WHERE e.courseid = :courseid AND e.enrol = :method AND ctx.contextlevel = :contextlevel ORDER BY e.sortorder"; + $params = array('method' => 'meta', 'courseid' => $courseid, 'contextlevel' => CONTEXT_COURSE); + + if ($results = $DB->get_records_sql($sql, $params)) { + $shortnames = array(); + // Preload the context we will need it to format the category name shortly. + foreach ($results as $res) { + context_helper::preload_from_record($res); + $context = context_course::instance($res->id); + $shortnames[] = format_string($res->shortname, true, $context); + } + $total = count($shortnames); + $suffix = ''; + if ($total > 10) { + $shortnames = array_slice($shortnames, 0, 10); + $diff = $total - count($shortnames); + if ($diff > 1) { + $suffix = get_string('shortnamesufixprural', 'block_course_overview_uwmoodle', $diff); + } else { + $suffix = get_string('shortnamesufixsingular', 'block_course_overview_uwmoodle', $diff); + } + } + $shortnames = get_string('shortnameprefix', 'block_course_overview_uwmoodle', implode('; ', $shortnames)); + $shortnames .= $suffix; + } + + return isset($shortnames) ? $shortnames : false; +} + +/** + * Return sorted list of user courses + * + * @return array list of sorted courses grouped by term. + */ +function block_course_overview_uwmoodle_get_sorted_courses() { + global $USER, $DB; + + $courses = enrol_get_my_courses('id, shortname, fullname, modinfo, sectioncache', 'fullname', 0); + $site = get_site(); + + if (array_key_exists($site->id,$courses)) { + unset($courses[$site->id]); + } + + foreach ($courses as $c) { + if (isset($USER->lastcourseaccess[$c->id])) { + $courses[$c->id]->lastaccess = $USER->lastcourseaccess[$c->id]; + } else { + $courses[$c->id]->lastaccess = 0; + } + } + + // 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; + } + } + } + return $courses; +} + +/** + * Group courses by term + * + * @param array $courses user courses + * @return array + */ +function block_course_overview_uwmoodle_group_courses_by_term($courses) { + // Organize courses into terms, maintaining existing sorting inside each term + $terms = array(); + foreach ($courses as $course) { + if (!empty($course->term)) { + $terms[$course->term][$course->id] = $course; + } else { + $terms[block_course_overview_uwmoodle::TERM_OTHER][$course->id] = $course; + } + } + + return $terms; +} + +/** + * Get the current term from our settings + * + * @return string termcode + */ +function block_course_overview_uwmoodle_get_current_term() { + $currentterm = get_config('block_course_overview_uwmoodle', 'currentterm'); + if (!$currentterm) { + $currentterm = 1136; // Just set it to something in the past, until cron runs and updates the term. + } + return $currentterm; +} + +/** + * Return a string representing the term (e.g. "Fall 2010") + * This function doesn't make any remote calls. + * + * @param string $termCode + * @return string $termName + */ +function block_course_overview_uwmoodle_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", $year-1); + break; + case 3: + $name = sprintf("Winter %d", $year); + break; + case 4: + $name = sprintf("Spring %d", $year); + break; + case 6: + $name = sprintf("Summer %d", $year); + break; + default: + $name = "Other"; + } + return $name; +} \ No newline at end of file diff --git a/module.js b/module.js new file mode 100644 index 0000000000000000000000000000000000000000..820ae47246780618e56e9cf95de6da99c1021216 --- /dev/null +++ b/module.js @@ -0,0 +1,110 @@ +M.block_course_overview_uwmoodle = {} + +/** + * Init a collapsible region, see print_collapsible_region in weblib.php + * @param {YUI} Y YUI3 instance with all libraries loaded + * @param {String} id the HTML id for the div. + * @param {String} userpref the user preference that records the state of this box. false if none. + * @param {String} strtooltip + */ +M.block_course_overview_uwmoodle.collapsible = function(Y, id, userpref, strtooltip) { + if (userpref) { + M.block_course_overview_uwmoodle.userpref = true; + } + Y.use('anim', function(Y) { + new M.block_course_overview_uwmoodle.CollapsibleRegion(Y, id, userpref, strtooltip); + }); +}; + +/** + * Object to handle a collapsible region : instantiate and forget styled object + * + * @class + * @constructor + * @param {YUI} Y YUI3 instance with all libraries loaded + * @param {String} id The HTML id for the div. + * @param {String} userpref The user preference that records the state of this box. false if none. + * @param {String} strtooltip + */ +M.block_course_overview_uwmoodle.CollapsibleRegion = function(Y, id, userpref, strtooltip) { + // Record the pref name + this.userpref = userpref; + + // Find the divs in the document. + this.div = Y.one('#'+id); + + // Get the caption for the collapsible region + var caption = this.div.one('#'+id + '_caption'); + caption.setAttribute('title', strtooltip); + + // Create a link + var a = Y.Node.create('<a href="#"></a>'); + // Create a local scoped lamba function to move nodes to a new link + var movenode = function(node){ + node.remove(); + a.append(node); + }; + // Apply the lamba function on each of the captions child nodes + caption.get('children').each(movenode, this); + caption.prepend(a); + + // Get the height of the div at this point before we shrink it if required + var height = this.div.get('offsetHeight'); + if (this.div.hasClass('collapsed')) { + // Shrink the div as it is collapsed by default + this.div.setStyle('height', caption.get('offsetHeight')+'px'); + } + + // Create the animation. + var animation = new Y.Anim({ + node: this.div, + duration: 0.3, + easing: Y.Easing.easeBoth, + to: {height:caption.get('offsetHeight')}, + from: {height:height} + }); + + // Handler for the animation finishing. + animation.on('end', function() { + this.div.toggleClass('collapsed'); + }, this); + + // Hook up the event handler. + caption.on('click', function(e, animation) { + e.preventDefault(); + // Animate to the appropriate size. + if (animation.get('running')) { + animation.stop(); + } + animation.set('reverse', this.div.hasClass('collapsed')); + // Update the user preference. + if (this.userpref) { + M.util.set_user_preference(this.userpref, !this.div.hasClass('collapsed')); + } + animation.run(); + }, this, animation); +}; + +M.block_course_overview_uwmoodle.userpref = false; + +/** + * The user preference that stores the state of this box. + * @property userpref + * @type String + */ +M.block_course_overview_uwmoodle.CollapsibleRegion.prototype.userpref = null; + +/** + * The key divs that make up this + * @property div + * @type Y.Node + */ +M.block_course_overview_uwmoodle.CollapsibleRegion.prototype.div = null; + +/** + * The key divs that make up this + * @property icon + * @type Y.Node + */ +M.block_course_overview_uwmoodle.CollapsibleRegion.prototype.icon = null; + diff --git a/renderer.php b/renderer.php new file mode 100644 index 0000000000000000000000000000000000000000..1cf32645c9d81aaf1e26d52e2bd89a3701075c75 --- /dev/null +++ b/renderer.php @@ -0,0 +1,236 @@ +<?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 rendrer + * + * @package block_course_overview + * @copyright 2012 Adam Olley <adam.olley@netspot.com.au> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die; + +/** + * Course_overview block rendrer + * + * @copyright 2012 Adam Olley <adam.olley@netspot.com.au> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class block_course_overview_uwmoodle_renderer extends plugin_renderer_base { + + /** + * Construct contents of course_overview block + * + * @param array $courses list of courses in sorted order + * @param array $overviews list of course overviews + * @return string html to be displayed in course_overview block + */ + public function course_overview($courses, $overviews) { + $html = ''; + $config = get_config('block_course_overview_uwmoodle'); + + $html .= html_writer::start_tag('div', array('id' => 'course_list_uwmoodle')); + if (empty($courses)) { + $html .= $this->output->box_start('coursebox'); + $html .= get_string('nocourses','block_course_overview_uwmoodle'); + $html .= $this->output->box_end(); + } else { + foreach ($courses as $key => $course) { + $html .= $this->output->box_start('coursebox', "course-{$course->id}"); + $html .= html_writer::start_tag('div', array('class' => 'course_title')); + + // No need to pass title through s() here as it will be done automatically by html_writer. + $attributes = array('title' => $course->fullname); + if (empty($course->visible)) { + $attributes['class'] = 'dimmed'; + } + $courseurl = new moodle_url('/course/view.php', array('id' => $course->id)); + $coursefullname = format_string($course->fullname, true, $course->id); + $link = html_writer::link($courseurl, $coursefullname, $attributes); + $html .= $this->output->heading($link, 2, 'title'); + $html .= $this->output->box('', 'flush'); + $html .= html_writer::end_tag('div'); + + if (isset($overviews[$course->id])) { + $html .= $this->activity_display($course->id, $overviews[$course->id]); + } + + $html .= $this->output->box('', 'flush'); + $html .= $this->output->box_end(); + } + } + $html .= html_writer::end_tag('div'); + return $html; + } + + public function course_header($terms, $selectedterm) { + $output = $this->output->box_start('notice'); + + $options = array(); + foreach ($terms as $termcode => $courses) { + if ($termcode == block_course_overview_uwmoodle::TERM_OTHER) { + // non-term courses are shown regardless + continue; + } + $options[$termcode] = block_course_overview_uwmoodle_get_term_name($termcode); + } + + $url = new moodle_url('/my/index.php'); + $select = new single_select($url, 'term', $options, $selectedterm, array()); + $select->set_label(get_string('mycoursesinterm', 'block_course_overview_uwmoodle')); + $output .= $this->output->render($select); + + $output .= $this->output->box_end(); + return $output; + } + + public function other_header() { + $output = $this->output->box_start('notice'); + $output .= $this->output->heading(get_string('othercourses', 'block_course_overview_uwmoodle'), 2, 'sectiontitle'); + $output .= $this->output->box_end(); + return $output; + } + + /** + * Coustuct activities overview for a course + * + * @param int $cid course id + * @param array $overview overview of activities in course + * @return string html of activities overview + */ + protected function activity_display($cid, $overview) { + $output = html_writer::start_tag('div', array('class' => 'activity_info')); + foreach (array_keys($overview) as $module) { + $output .= html_writer::start_tag('div', array('class' => 'activity_overview')); + $url = new moodle_url("/mod/$module/index.php", array('id' => $cid)); + $modulename = get_string('modulename', $module); + $icontext = html_writer::link($url, $this->output->pix_icon('icon', $modulename, 'mod_'.$module, array('class'=>'iconlarge'))); + if (get_string_manager()->string_exists("activityoverview", $module)) { + $icontext .= get_string("activityoverview", $module); + } else { + $icontext .= get_string("activityoverview", 'block_course_overview', $modulename); + } + + // Add collapsible region with overview text in it. + $output .= $this->collapsible_region($overview[$module], '', 'uwmm_region_'.$cid.'_'.$module, $icontext, '', true); + + $output .= html_writer::end_tag('div'); + } + $output .= html_writer::end_tag('div'); + return $output; + } + + /** + * Creates collapsable region + * + * @param string $contents existing contents + * @param string $classes class names added to the div that is output. + * @param string $id id added to the div that is output. Must not be blank. + * @param string $caption text displayed at the top. Clicking on this will cause the region to expand or contract. + * @param string $userpref the name of the user preference that stores the user's preferred default state. + * (May be blank if you do not wish the state to be persisted. + * @param bool $default Initial collapsed state to use if the user_preference it not set. + * @return bool if true, return the HTML as a string, rather than printing it. + */ + protected function collapsible_region($contents, $classes, $id, $caption, $userpref = '', $default = false) { + $output = $this->collapsible_region_start($classes, $id, $caption, $userpref, $default); + $output .= $contents; + $output .= $this->collapsible_region_end(); + + return $output; + } + + /** + * Print (or return) the start of a collapsible region, that has a caption that can + * be clicked to expand or collapse the region. If JavaScript is off, then the region + * will always be expanded. + * + * @param string $classes class names added to the div that is output. + * @param string $id id added to the div that is output. Must not be blank. + * @param string $caption text displayed at the top. Clicking on this will cause the region to expand or contract. + * @param string $userpref the name of the user preference that stores the user's preferred default state. + * (May be blank if you do not wish the state to be persisted. + * @param bool $default Initial collapsed state to use if the user_preference it not set. + * @return bool if true, return the HTML as a string, rather than printing it. + */ + protected function collapsible_region_start($classes, $id, $caption, $userpref = '', $default = false) { + // Work out the initial state. + if (!empty($userpref) and is_string($userpref)) { + user_preference_allow_ajax_update($userpref, PARAM_BOOL); + $collapsed = get_user_preferences($userpref, $default); + } else { + $collapsed = $default; + $userpref = false; + } + + if ($collapsed) { + $classes .= ' collapsed'; + } + + $output = ''; + $output .= '<div id="' . $id . '" class="collapsibleregion ' . $classes . '">'; + $output .= '<div id="' . $id . '_sizer">'; + $output .= '<div id="' . $id . '_caption" class="collapsibleregioncaption">'; + $output .= $caption . ' '; + $output .= '</div><div id="' . $id . '_inner" class="collapsibleregioninner">'; + $this->page->requires->js_init_call('M.block_course_overview_uwmoodle.collapsible', array($id, $userpref, get_string('clicktohideshow'))); + + return $output; + } + + /** + * Close a region started with print_collapsible_region_start. + * + * @return string return the HTML as a string, rather than printing it. + */ + protected function collapsible_region_end() { + $output = '</div></div></div>'; + return $output; + } + + /** + * Cretes html for welcome area + * + * @param int $msgcount number of messages + * @return string html string for welcome area. + */ + public function welcome_area($msgcount) { + global $USER; + $output = $this->output->box_start('welcome_area'); + + $picture = $this->output->user_picture($USER, array('size' => 75, 'class' => 'welcome_userpicture')); + $output .= html_writer::tag('div', $picture, array('class' => 'profilepicture')); + + $output .= $this->output->box_start('welcome_message'); + $output .= $this->output->heading(get_string('welcome', 'block_course_overview', $USER->firstname)); + + $plural = 's'; + if ($msgcount > 0) { + $output .= get_string('youhavemessages', 'block_course_overview', $msgcount); + } else { + $output .= get_string('youhavenomessages', 'block_course_overview'); + if ($msgcount == 1) { + $plural = ''; + } + } + $output .= html_writer::link(new moodle_url('/message/index.php'), get_string('message'.$plural, 'block_course_overview')); + $output .= $this->output->box_end(); + $output .= $this->output->box('', 'flush'); + $output .= $this->output->box_end(); + + return $output; + } +} diff --git a/settings.php b/settings.php new file mode 100644 index 0000000000000000000000000000000000000000..975d7538a32f495fb28d1f4c5456b93d82897b61 --- /dev/null +++ b/settings.php @@ -0,0 +1,29 @@ +<?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 settings + * + * @package block_course_overview + * @copyright 2012 Adam Olley <adam.olley@netspot.com.au> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die; + +if ($ADMIN->fulltree) { + $settings->add(new admin_setting_configcheckbox('block_course_overview_uwmoodle/showwelcomearea', new lang_string('showwelcomearea', 'block_course_overview'), + new lang_string('showwelcomeareadesc', 'block_course_overview'), 1)); +} diff --git a/styles.css b/styles.css index 2cb704aae2af52a72f645a628b924c6c08ee0ca8..a6494edd65c61d0653f02e610148251dbbdbe09b 100644 --- a/styles.css +++ b/styles.css @@ -1,24 +1,167 @@ -.block_course_overview_uwmoodle .treeitem { +.block_course_overview_uwmoodle .coursechildren { + font-weight: normal; + font-style: italic; +} + +.block_course_overview_uwmoodle .content { + margin: 0 20px; +} +.block_course_overview_uwmoodle .content .notice { + margin: 5px 0; +} + +.block_course_overview_uwmoodle .coursebox { + padding: 15px; + width: auto; +} + +.block_course_overview_uwmoodle .profilepicture { + float: left; +} +.dir-rtl.block_course_overview_uwmoodle .profilepicture { + float:right; +} +.block_course_overview_uwmoodle .welcome_area { + width: 100%; + padding-bottom: 5px; +} + +.block_course_overview_uwmoodle .welcome_message { + float: left; + padding: 10px; + vertical-align: middle; + border-collapse: separate; + clear: none; +} +.dir-rtl .block_course_overview_uwmoodle .welcome_message { + float:right; +} + +.block_course_overview_uwmoodle .content h2.title { + float: left; + margin: 0 0 .5em 0; + position: relative; +} +.block_course_overview_uwmoodle .content h2.sectiontitle { + color: #444444; + margin: 2em 0 0; +} +.block_course_overview_uwmoodle .content label { + color: #444444; + font-size: 120%; + font-weight: bold; +} +.collapsibleregioncaption { + cursor: pointer; +} +font-size: 123.1%; +.dir-rtl .block_course_overview_uwmoodle .content h2.title { + float:right; +} + +.block_course_overview_uwmoodle .course_title { + position: relative; +} + +.editing .block_course_overview_uwmoodle .coursebox .cursor { + cursor: move; + margin-bottom: 2px; +} + +.editing .block_course_overview_uwmoodle .move { + float: left; + padding: 2px 10px 0 0; +} +.dir-rtl.editing .block_course_overview_uwmoodle .move { + float:right; + padding: 2px 10px; +} + +.editing .block_course_overview_uwmoodle .moveicons { + display: block; + float: left; + padding-right: 5px; +} +.dir-rtl.editing .block_course_overview_uwmoodle .moveicons { + float:right; +} + +.editing .block_course_overview_uwmoodle .moveup { + padding-right: 5px; +} + +.editing .block_course_overview_uwmoodle .movedownspacer { + float: left; + width: 14px; +}.block_course_overview_uwmoodle_uwmoodle .treeitem { background-position: 0 40%; background-repeat: no-repeat; padding-left: 18px; text-align: left; } -.block_course_overview_uwmoodle .treeitem.term {background-image: url([[pix:t/expanded]]);} -.block_course_overview_uwmoodle li.collapsed .treeitem.term {background-image: url([[pix:t/collapsed]]);} -.block_course_overview_uwmoodle .treeitem.coursenews {background-image: url([[pix:t/switch_minus]]);} -.block_course_overview_uwmoodle li.collapsed .treeitem.coursenews {background-image: url([[pix:t/switch_plus]]);} -.block_course_overview_uwmoodle li.collapsed ul {display: none;} -.block_course_overview_uwmoodle li ul {margin: 0;padding-left:16px;} -.block_course_overview_uwmoodle .coursebox h3 {margin-left:10px;} -.block_course_overview_uwmoodle h3 {font-size:1.1em;} -/*.block_course_overview_uwmoodle .miscterm .term {font-weight:bold;}*/ -.block_course_overview_uwmoodle .term {color:#000;font-weight:normal;} -.block_course_overview_uwmoodle .shownews {float:right;color:#333;font-weight:normal;margin-right:1em;font-size:91%;} -.block_course_overview_uwmoodle a:focus, -.block_course_overview_uwmoodle a:hover, -.block_course_overview_uwmoodle a:active {outline:none;} -.block_course_overview_uwmoodle ul.treelist {list-style:none outside none;} -.block_course_overview_uwmoodle .courselist {margin:0;padding:0;} -.block_course_overview_uwmoodle ul {margin:0 1em 0 0;} \ No newline at end of file +.block_course_overview_uwmoodle_uwmoodle .treeitem.term {background-image: url([[pix:t/expanded]]);} +.block_course_overview_uwmoodle_uwmoodle li.collapsed .treeitem.term {background-image: url([[pix:t/collapsed]]);} +.block_course_overview_uwmoodle_uwmoodle .treeitem.coursenews {background-image: url([[pix:t/switch_minus]]);} +.block_course_overview_uwmoodle_uwmoodle li.collapsed .treeitem.coursenews {background-image: url([[pix:t/switch_plus]]);} +.block_course_overview_uwmoodle_uwmoodle li.collapsed ul {display: none;} +.block_course_overview_uwmoodle_uwmoodle li ul {margin: 0;padding-left:16px;} +.block_course_overview_uwmoodle_uwmoodle .coursebox h3 {margin-left:10px;} +.block_course_overview_uwmoodle_uwmoodle h3 {font-size:1.1em;} +/*.block_course_overview_uwmoodle_uwmoodle .miscterm .term {font-weight:bold;}*/ +.block_course_overview_uwmoodle_uwmoodle .term {color:#000;font-weight:normal;} +.block_course_overview_uwmoodle_uwmoodle .shownews {float:right;color:#333;font-weight:normal;margin-right:1em;font-size:91%;} +.block_course_overview_uwmoodle_uwmoodle a:focus, +.block_course_overview_uwmoodle_uwmoodle a:hover, +.block_course_overview_uwmoodle_uwmoodle a:active {outline:none;} +.block_course_overview_uwmoodle_uwmoodle ul.treelist {list-style:none outside none;} +.block_course_overview_uwmoodle_uwmoodle .courselist {margin:0;padding:0;} +.block_course_overview_uwmoodle_uwmoodle ul {margin:0 1em 0 0;} +.dir-rtl.editing .block_course_overview_uwmoodle .movedownspacer { + float:right; +} + +.editing .block_course_overview_uwmoodle .moveupspacer { + float: right; + width: 14px; +} +.dir-rtl.editing .block_course_overview_uwmoodle .moveupspacer { + float:left; +} + +.block_course_overview_uwmoodle #course_list { + width: 100%; +} + +.block_course_overview_uwmoodle div.flush { + clear: both; +} + +.block_course_overview_uwmoodle .activity_info { + clear: both; +} +.dir-rtl .block_course_overview_uwmoodle .activity_info { + margin-right: 25px; +} + +.block_course_overview_uwmoodle .activity_overview { + padding: 2px; +} +.block_course_overview_uwmoodle .activity_overview img.iconlarge { vertical-align: text-bottom; margin-right: 6px; } +.dir-rtl .block_course_overview_uwmoodle .activity_overview img.iconlarge { margin-left: 6px; margin-right: 0;} + +.block_course_overview_uwmoodle .singleselect { + text-align: left; + margin: 0; +} +.dir-rtl .block_course_overview_uwmoodle .singleselect { + text-align: right; +} + +.block_course_overview_uwmoodle .coursemovetarget { + display: block; + height: 1em; + margin-bottom: 1em; + border-width: 2px; + border-style: dashed; +} diff --git a/version.php b/version.php index f79fc33164cdfb676cc298915d99cccbf7674ee0..79a0d22f173ad819eea51fa4f4ffe6e395925c8b 100644 --- a/version.php +++ b/version.php @@ -18,13 +18,13 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'block_course_overview_uwmoodle'; -$plugin->version = 2013031500; -$plugin->release = '1.0'; +$plugin->version = 2013071801; +$plugin->release = '1.1'; $plugin->requires = 2012062500; $plugin->maturity = MATURITY_RC; $plugin->cron = 43200; // Set min time between cron executions to 12 hours $plugin->dependencies = array( - 'enrol_wisc' => 2013030400, + 'enrol_wisc' => 2012112900, ); diff --git a/yui/showhide/showhide.js b/yui/showhide/showhide.js deleted file mode 100644 index e1d9a645495de552229023ce3de55a92f2dc6d35..0000000000000000000000000000000000000000 --- a/yui/showhide/showhide.js +++ /dev/null @@ -1,78 +0,0 @@ -YUI.add('moodle-block_course_overview_uwmoodle-showhide', function(Y) { - -var ShowHide = function() { - ShowHide.superclass.constructor.apply(this, arguments); -}; -ShowHide.prototype = { - id : null, - - initializer : function(config) { - this.id = config.id; - - var node = Y.one('#inst'+config.id); - - // Can't find the block instance within the page - if (node === null) { - return; - } - - var items = config.items.split(" "); - for(i=0; i<items.length; i++){ - node.one('#uwm-'+this.id+'-'+items[i]).on('click', this.toggleExpansion, this, items[i]); - } - }, - - toggleExpansion : function(e, item) { - // First check if they managed to click on the li iteslf, then find the closest - // LI ancestor and use that -/* - if (e.target.test('a')) { - // A link has been clicked (or keypress is 'enter') don't fire any more events just do the default. - e.stopPropagation(); - return; - } -*/ - // Get the LI containing the branch. - var target = e.target; - if (!target.test('li')) { - target = target.ancestor('li') - } - if (!target) { - return; - } - - // Get the A for the control (for aria) - var control = e.target; - if (!control.test('a')) { - control = control.ancestor('a') - } - if (!control) { - return; - } - - e.preventDefault(); - - // Toggle expand/collapse - target.toggleClass('collapsed'); - control.set('aria-expanded', !target.hasClass('collapsed')); - - // update a show/hide text control, if any - var textcontrol = control.one('.showhidetext'); - if (textcontrol) { - textcontrol.setHTML(target.hasClass('collapsed')? "Show" : "Hide"); - } - M.util.set_user_preference('block_course_overview_uwmoodle-show-'+item, target.hasClass('collapsed')? 0 : 1); - } -}; -Y.extend(ShowHide, Y.Base, ShowHide.prototype, { - NAME : 'Course Overview UWMoodle Tree Navigation' -}); - - -M.block_course_overview_uwmoodle = M.block_course_overview_uwmoodle || { - initialize:function(properties) { - new ShowHide(properties); - } -}; - -}, '@VERSION@', {requires:['base','node']});