diff --git a/CHANGES.md b/CHANGES.md index 7cde86d..2cbaee4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,39 @@ +## 3.5.4 ## + +* Missing language strings in settings page + +## 3.5.3 ## + +* New instances load in the 'content' area of the Dashboard automagically. +* New option to select default tab +* Performance improvements. User's course list is only loaded once for both tabs. + +## 3.3.6 ## + +* Now displays hidden courses (to Teachers et al) as 'dimmed' +* Layout a bit better on legacy Bootstrap 2 themes (e.g. Clean). + +## 3.3.5 ## + +* Some support for bootstrapbase themes added +* favourites shown with correct 'star' in course list + +## 3.3.4 ## + +* Layout of courses improved using Bootstrap grids +* Option to keep favourites in 'normal' course list added to block settings +* Option to have a fixed sort order for courses tab +* Code tidied up somewhat + +## 3.3.3 ## + +* All javascript changed from YUI to jquery amd modules +* Rendering now using mustache templates +* Course overviews displayed by clicking icon +* Favourites tab added +* Limit on courses displayed and child course display dropped. +* print_overview() still in use (for now) + ## 3.3.1 ## * Debugging messages raised by using deprecated `print_overview()` are not diff --git a/amd/build/edit.min.js b/amd/build/edit.min.js new file mode 100644 index 0000000..319e595 --- /dev/null +++ b/amd/build/edit.min.js @@ -0,0 +1 @@ +define(["jquery","jqueryui"],function(a,b){return{init:function(){a(".courseovbox a").removeAttr("href"),a(".tab-pane .course-list").sortable({update:function(b,c){var d=a(".tab-pane.active .course-list").children(),e=[];a.each(d,function(a,b){var c=b.getAttribute("id");e[a]=c.substring(7)});var f=a(".block_course_overview .nav-item.active a").data("tabname");if(!f)var f=a(".block_course_overview .nav-tabs .active").data("tabname");var g={sesskey:M.cfg.sesskey,tab:f,sortorder:e};a.post(M.cfg.wwwroot+"/blocks/course_overview/save.php",g)}})}}}); \ No newline at end of file diff --git a/amd/build/popup.min.js b/amd/build/popup.min.js new file mode 100644 index 0000000..71da834 --- /dev/null +++ b/amd/build/popup.min.js @@ -0,0 +1 @@ +define(["jquery","jqueryui","core/config"],function(a,b,c){return{init:function(){a(".dialogue").dialog({autoOpen:!1,minWidth:400,classes:{"ui-dialog":"course-overview-dialog"},closeText:"",modal:!0}),a(".overview-icon").click(function(){var b=a(this).data("id");a(b).dialog("open")})}}}); \ No newline at end of file diff --git a/amd/src/edit.js b/amd/src/edit.js new file mode 100644 index 0000000..8c67c23 --- /dev/null +++ b/amd/src/edit.js @@ -0,0 +1,62 @@ +// 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 . + +/** + * A javascript module to allow drag-and-drop control of course order + * + * @module block_course_overview + * @class block + * @package block_course_overview + * @copyright 2017 Howard Miller + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define(['jquery', 'jqueryui'], function($, UI) { + + return { + init: function() { + + // Change non-js links to be inactive. + $(".courseovbox a").removeAttr("href"); + + // Make the course list sort. + $(".tab-pane .course-list").sortable({ + update: function(event, ui) { + var kids = $(".tab-pane.active .course-list").children(); + var sortorder = []; + $.each(kids, function(index, value) { + var id = value.getAttribute('id'); + sortorder[index] = id.substring(7); + }); + + // Send new sortorder. + var activetab = $(".block_course_overview .nav-item.active a").data("tabname"); + if (!activetab) { + var activetab = $(".block_course_overview .nav-tabs .active").data("tabname"); + } + var data = { + sesskey : M.cfg.sesskey, + tab : activetab, + sortorder : sortorder + }; + $.post( + M.cfg.wwwroot + '/blocks/course_overview/save.php', + data + ); + } + }); + } + }; +}); diff --git a/amd/src/popup.js b/amd/src/popup.js new file mode 100644 index 0000000..fd5e2f7 --- /dev/null +++ b/amd/src/popup.js @@ -0,0 +1,54 @@ +// 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 . + +/** + * A javascript module to popup activity overviews + * + * @module block_course_overview + * @class block + * @package block_course_overview + * @copyright 2017 Howard Miller + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define(['jquery', 'jqueryui', 'core/config'], function($, UI, mdlconfig) { + + return { + init: function() { + + // Dialogues on activity icons. + $(".dialogue").dialog({ + autoOpen: false, + minWidth: 400, + classes: { + 'ui-dialog': 'course-overview-dialog' + }, + closeText: '', + modal: true + }); + + // Opens the appropriate dialog. + $(".overview-icon").click(function () { + + // Takes the ID of appropriate dialogue. + var id = $(this).data('id'); + + // Open dialogue. + $(id).dialog("open"); + }); + + } + }; +}); diff --git a/block_course_overview.php b/block_course_overview.php index 292a8dc..335d6d2 100644 --- a/block_course_overview.php +++ b/block_course_overview.php @@ -21,7 +21,8 @@ * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -require_once($CFG->dirroot.'/blocks/course_overview/locallib.php'); + +defined('MOODLE_INTERNAL') || die(); /** * Course overview block @@ -48,10 +49,12 @@ public function init() { * @return stdClass contents of block */ public function get_content() { - global $USER, $CFG, $DB; + global $USER, $CFG, $DB, $SESSION; + + require_once($CFG->dirroot.'/blocks/course_overview/locallib.php'); require_once($CFG->dirroot.'/user/profile/lib.php'); - if($this->content !== NULL) { + if ($this->content !== null) { return $this->content; } @@ -63,6 +66,8 @@ public function get_content() { $content = array(); + $isediting = $this->page->user_is_editing(); + $updatemynumber = optional_param('mynumber', -1, PARAM_INT); if ($updatemynumber >= 0 && optional_param('sesskey', '', PARAM_RAW) && confirm_sesskey()) { block_course_overview_update_mynumber($updatemynumber); @@ -70,30 +75,65 @@ public function get_content() { profile_load_custom_fields($USER); - $showallcourses = ($updatemynumber === self::SHOW_ALL_COURSES); - list($sortedcourses, $sitecourses, $totalcourses) = block_course_overview_get_sorted_courses($showallcourses); - $overviews = block_course_overview_get_overviews($sitecourses); + // Check if favourite added/removed. + $favourite = optional_param('favourite', 0, PARAM_INT); + if ($favourite) { + block_course_overview_add_favourite($favourite); + } + $unfavourite = optional_param('unfavourite', 0, PARAM_INT); + if ($unfavourite) { + block_course_overview_remove_favourite($unfavourite); + } - $renderer = $this->page->get_renderer('block_course_overview'); - if (!empty($config->showwelcomearea)) { - require_once($CFG->dirroot.'/message/lib.php'); - $msgcount = message_count_unread_messages(); - $this->content->text = $renderer->welcome_area($msgcount); + // Check if sortorder updated. + $soparam = optional_param('sortorder', -1, PARAM_INT); + if ($soparam == -1) { + $sortorder = block_course_overview_get_sortorder(); + } else { + $sortorder = $soparam; + block_course_overview_update_sortorder($sortorder); } - // Number of sites to display. - if ($this->page->user_is_editing() && empty($config->forcedefaultmaxcourses)) { - $this->content->text .= $renderer->editing_bar_head($totalcourses); + // Check if number of courses to display was updated. + $usersetmaxcourses = optional_param('usersetmaxcourses', null, PARAM_INT); + if ( $usersetmaxcourses === null ) { + $usersetmaxcourses = block_course_overview_get_usersetmaxcourses(); + } else { + block_course_overview_update_usersetmaxcourses($usersetmaxcourses); } - if (empty($sortedcourses)) { - $this->content->text .= get_string('nocourses','my'); + // Get data for favourites and course tab. + $tabs = array(); + $ftab = new stdClass; + $ftab->tab = 'favourites'; + list($ftab->sortedcourses, $ftab->sitecourses, $ftab->totalcourses) = block_course_overview_get_sorted_courses(true); + $ftab->overviews = block_course_overview_get_overviews($ftab->sortedcourses); + $ctab = new stdClass; + $ctab->tab = 'courses'; + list($ctab->sortedcourses, $ctab->sitecourses, $ctab->totalcourses) + = block_course_overview_get_sorted_courses(false, $config->keepfavourites, array_keys($ftab->sortedcourses)); + $ctab->overviews = block_course_overview_get_overviews($ctab->sortedcourses); + $tabs = array( + 'favourites' => $ftab, + 'courses' => $ctab, + ); + + // Get list of favourites. + $favourites = array_keys($ftab->sortedcourses); + + // Default tab. One with something in it or selected default. + if (($config->defaulttab == BLOCKS_COURSE_OVERVIEW_DEFAULT_FAVOURITES) && $ftab->totalcourses) { + $tab = 'favourites'; } else { - // For each course, build category cache. - $this->content->text .= $renderer->course_overview($sortedcourses, $overviews); - $this->content->text .= $renderer->hidden_courses($totalcourses - count($sortedcourses)); + $tab = 'courses'; } + $renderer = $this->page->get_renderer('block_course_overview'); + + // Render block. + $main = new block_course_overview\output\main( + $config, $tabs, $isediting, $tab, $sortorder, $favourites, $usersetmaxcourses); + $this->content->text .= $renderer->render($main); return $this->content; } @@ -121,8 +161,22 @@ public function applicable_formats() { * @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'); - return !empty($config->showwelcomearea); + return false; + } + + /** + * Do any additional initialization you may need at the time a new block instance is created + * @return boolean + */ + public function instance_create() { + global $DB; + + // Bodge? Modify our own instance to make the default region the + // content area, not the side bar. + $instance = $this->instance; + $instance->defaultregion = 'content'; + $DB->update_record('block_instances', $instance); + + return true; } } diff --git a/classes/output/main.php b/classes/output/main.php new file mode 100644 index 0000000..2fa1f46 --- /dev/null +++ b/classes/output/main.php @@ -0,0 +1,294 @@ +. + +/** + * Main class for course listing + * + * @package block_course_overview + * @copyright 2017 Howard Miller + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_course_overview\output; + +defined('MOODLE_INTERNAL') || die; + +use renderable; +use renderer_base; +use templatable; + +/** + * Class contains data for course_overview + * + * @copyright 2017 Howard Miller + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class main implements renderable, templatable { + + private $config; + + private $tabs; + + private $isediting; + + private $selectedtab; + + private $sortorder; + + private $favourites; + + private $usersetmaxcourses; + + /** + * Constructor + * @param object $config block configuration + * @param array $tabs data for favourites/courses + * @param boolean $isediting + * @param string $selectedtab + * @param int $sortorder + * @param array list of favourites + */ + public function __construct($config, $tabs, $isediting, $selectedtab, $sortorder, $favourites, $usersetmaxcourses) { + $this->config = $config; + $this->tabs = $tabs; + $this->isediting = $isediting; + $this->selectedtab = $selectedtab; + $this->sortorder = $sortorder; + $this->favourites = $favourites; + $this->usersetmaxcourses = $usersetmaxcourses; + } + + /** + * Get course data into suitable construct + * @param \renderer_base $output + * @param boolean $favtab (is this favourites tab) + * @param object $tab data for tab + * @return array of courses + */ + private function process_tab($output, $favtab, $tab) { + + // Add extra info (and make zero indexed). + $courselist = []; + foreach ($tab->sortedcourses as $course) { + $course->link = new \moodle_url('/course/view.php', array('id' => $course->id)); + $course->categories = implode(' / ', $this->categories($course->category)); + if (in_array($course->id, $this->favourites)) { + $course->favouritelink = new \moodle_url('/my', array('unfavourite' => $course->id)); + $course->favouriteicon = 'fa-star'; + $course->favouritealt = get_string('unfavourite', 'block_course_overview'); + } else { + $course->favouritelink = new \moodle_url('/my', array('favourite' => $course->id)); + $course->favouriteicon = 'fa-star-o'; + $course->favouritealt = get_string('makefavourite', 'block_course_overview'); + } + if (!empty($tab->overviews[$course->id])) { + $course->hasoverviews = true; + $overviews = array(); + foreach ($tab->overviews[$course->id] as $activity => $overviewtext) { + $overview = new \stdClass; + $overview->coursename = $course->fullname; + $overview->visible = $course->visible; + $overview->activity = $activity; + $overview->text = str_replace('p-y-1', '', $overviewtext); + $description = get_string('activityoverview', 'block_course_overview', + get_string('pluginname', 'mod_' . $activity)); + $overviewid = $activity . '_' . $course->id; + $overview->overviewid = $overviewid; + $overview->icon = $output->pix_icon('icon', $description, 'mod_' . $activity); + $overviews[] = $overview; + } + $course->overviews = $overviews; + } else { + $course->hasoverviews = false; + } + $courselist[] = $course; + } + + return $courselist; + } + + /** + * Get (if required) category string for course + * @param int $id course's category id + * @return string category path + */ + private function categories($id) { + $categories = array(); + + if ($this->config->showcategories != BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_NONE) { + + // List category parent or categories path here. + $currentcategory = \coursecat::get($id, IGNORE_MISSING); + if ($currentcategory !== null) { + if ($this->config->showcategories == BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_FULL_PATH) { + foreach ($currentcategory->get_parents() as $categoryid) { + $category = \coursecat::get($categoryid, IGNORE_MISSING); + if ($category !== null) { + $categories[] = $category->get_formatted_name(); + } + } + } + $categories[] = $currentcategory->get_formatted_name(); + } + } + + return $categories; + } + + /** + * Build select for course list reorder + * @param object $output + * @return string html + */ + private function reorder_select(renderer_base $output) { + + $options = [ + BLOCKS_COURSE_OVERVIEW_REORDER_NONE => get_string('reordernone', 'block_course_overview'), + BLOCKS_COURSE_OVERVIEW_REORDER_FULLNAME => get_string('reorderfullname', 'block_course_overview'), + BLOCKS_COURSE_OVERVIEW_REORDER_SHORTNAME => get_string('reordershortname', 'block_course_overview'), + BLOCKS_COURSE_OVERVIEW_REORDER_ID => get_string('reorderid', 'block_course_overview'), + BLOCKS_COURSE_OVERVIEW_REORDER_IDDESC => get_string('reorderiddesc', 'block_course_overview'), + ]; + + // Courses reorder select. + $select = $output->single_select( + new \moodle_url('/my', array('sesskey' => sesskey())), + 'sortorder', + $options, + $this->sortorder, + null + ); + + return $select; + } + + /** + * Build select for user to choose max number of courses to show in course_overview block + * @param object $output + * @return string html + */ + private function user_select_maxcourses(renderer_base $output) { + // Site setting - max possible courses. + $setmaxcoursesmax = get_config('block_course_overview')->setmaxcoursesmax; + // User total enrolled courses. + $usercount = count(enrol_get_my_courses()); + // Number of courses to display for user to choose from. + $max = $usercount > $setmaxcoursesmax ? $setmaxcoursesmax : $usercount; + + $options = range(0, $max); + $options[0] = "0".get_string('userchoosezero', 'block_course_overview'); + + $select = $output->single_select( + new \moodle_url('/my', array('sesskey' => sesskey())), + 'usersetmaxcourses', + $options, + block_course_overview_get_usersetmaxcourses(), + null + ); + + return $select; + } + + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param \renderer_base $output + * @return stdClass + */ + public function export_for_template(renderer_base $output) { + + // Implement pagination. + $maxcourses = block_course_overview_get_usersetmaxcourses(); + $currpagef = optional_param('ssf_pagenum', 0, PARAM_INT); + $currpagec = optional_param('ssc_pagenum', 0, PARAM_INT); + $numfavpages = (int)ceil($this->tabs['favourites']->totalcourses / $maxcourses) - 1; + $numfavpages = $numfavpages <= 0 ? 0 : $numfavpages; + $numcoursepages = (int)ceil($this->tabs['courses']->totalcourses / $maxcourses) - 1; + $numcoursepages = $numcoursepages <= 0 ? 0 : $numcoursepages; + $nextpagef = $currpagef + 1; + $nextpagec = $currpagec + 1; + $prevpagef = $currpagef - 1; + $prevpagec = $currpagec - 1; + + $favpages = range(0, $numfavpages); + foreach ($favpages as $k => $v) { + $favpages[$k] = [ + "pagelink" => new \moodle_url('/my/index.php', ['ssf_pagenum' => $v]), + "pagetext" => $v + 1, + "current" => ($v == $currpagef), + ]; + } + $coursepages = range(0, $numcoursepages); + foreach ($coursepages as $k => $v) { + $coursepages[$k] = [ + "pagelink" => new \moodle_url('/my/index.php', ['ssc_pagenum' => $v]), + "pagetext" => $v + 1, + "current" => ($v == $currpagec), + ]; + } + + // Defaults to favourites. + if (optional_param('ssc_pagenum', null, PARAM_INT) !== null) { + $this->selectedtab = 'courses'; + } + + // Generate array for tabs 0=favs, 1=courses. + $tabs = array( + 0 => (object) [ + 'tab' => 'favourites', + 'show' => $this->selectedtab == 'favourites' ? 'show active' : '', + 'data' => $this->process_tab($output, true, $this->tabs['favourites']), + 'morecourses' => [ + 'nextpage' => new \lang_string('nextpage', 'block_course_overview'), + 'prevpage' => new \lang_string('prevpage', 'block_course_overview'), + 'shownextpage' => !(end($favpages)['current']), + 'showprevpage' => !($favpages[0]['current']), + 'text' => new \lang_string('morecoursestext', 'block_course_overview'), + 'linknext' => new \moodle_url('/my/index.php', ['ssf_pagenum' => $nextpagef]), + 'linkprev' => new \moodle_url('/my/index.php', ['ssf_pagenum' => $prevpagef]), + 'pages' => $favpages, + ], + 'showmorecourses' => ($numfavpages > 0), + ], + 1 => (object) [ + 'tab' => 'courses', + 'show' => $this->selectedtab == 'courses' ? 'show active' : '', + 'data' => $this->process_tab($output, false, $this->tabs['courses']), + 'morecourses' => [ + 'nextpage' => new \lang_string('nextpage', 'block_course_overview'), + 'prevpage' => new \lang_string('prevpage', 'block_course_overview'), + 'shownextpage' => !(end($coursepages)['current']), + 'showprevpage' => !($coursepages[0]['current']), + 'text' => new \lang_string('morecoursestext', 'block_course_overview'), + 'linknext' => new \moodle_url('/my/index.php', ['ssc_pagenum' => $nextpagec]), + 'linkprev' => new \moodle_url('/my/index.php', ['ssc_pagenum' => $prevpagec]), + 'pages' => $coursepages, + ], + 'showmorecourses' => ($numcoursepages > 0), + ], + ); + + return [ + 'tabs' => $tabs, + 'isediting' => $this->isediting, + 'help' => $output->help_icon('help', 'block_course_overview', true), + 'viewingfavourites' => $this->selectedtab == 'favourites', + 'select' => $this->reorder_select($output), + 'selectmaxcourses' => $this->user_select_maxcourses($output), + ]; + } + +} diff --git a/classes/output/renderer.php b/classes/output/renderer.php new file mode 100644 index 0000000..f155f63 --- /dev/null +++ b/classes/output/renderer.php @@ -0,0 +1,45 @@ +. + +/** + * course_overview block rendrer + * + * @package block_course_overview + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_course_overview\output; + +defined('MOODLE_INTERNAL') || die; + +use plugin_renderer_base; + +/** + * Course_overview block rendrer + * + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class renderer extends plugin_renderer_base { + + /** + * Render main part of course listing + * @param main $main + */ + public function render_main(main $main) { + return $this->render_from_template('block_course_overview/main', $main->export_for_template($this)); + } + +} diff --git a/classes/privacy/provider.php b/classes/privacy/provider.php new file mode 100755 index 0000000..8a9f5bb --- /dev/null +++ b/classes/privacy/provider.php @@ -0,0 +1,76 @@ +. + +/** + * Privacy Subsystem implementation for block_myoverview. + * + * @package block_course_overview + * @copyright 2018 Howard Miller + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_course_overview\privacy; + +defined('MOODLE_INTERNAL') || die(); + +use \core_privacy\local\request\writer; +use \core_privacy\local\metadata\collection; + +/** + * Privacy Subsystem for block_course_overview. + * + * @copyright 2018 Howard Miller + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\user_preference_provider { + + /** + * Returns meta-data information about the course_overview block. + * + * @param collection $collection A collection of meta-data. + * @return collection Return the collection of meta-data. + */ + public static function get_metadata(collection $collection) : collection { + $collection->add_user_preference('block_course_overview_number_of_courses', 'privacy:metadata:numberofcourses'); + $collection->add_user_preference('block_course_overview_course_sortorder', 'privacy:metadata:coursesortorder'); + $collection->add_user_preference('block_course_overview_course_order', 'privacy:metadata:courseorder'); + $collection->add_user_preference('block_course_overview_favourites', 'privacy:metadata:favourites'); + $collection->add_user_preference('block_course_overview_sortorder', 'privacy:metadata:sortorder'); + return $collection; + } + + /** + * Export all user preferences for the myoverview block + * + * @param int $userid The userid of the user whose data is to be exported. + */ + public static function export_user_preferences(int $userid) { + $preferences = [ + 'number_of_courses' => 'numberofcourses', + 'course_sortorder' => 'coursesortorder', + 'course_order' => 'courseorder', + 'favourites' => 'favourites', + 'sortorder' => 'sortorder', + ]; + foreach ($preferences as $name => $metadata) { + $preference = get_user_preferences('block_course_overview_' . $name, null, $userid); + if (isset($preference)) { + writer::export_user_preference('block_course_overview', 'block_course_overview_' . $name, + $preference, get_string('privacy:metadata:' . $metadata, 'block_course_overview')); + } + } + } +} diff --git a/db/upgrade.php b/db/upgrade.php new file mode 100644 index 0000000..c864172 --- /dev/null +++ b/db/upgrade.php @@ -0,0 +1,38 @@ +. + +/** + * Upgrade + * + * @package block_course_overview + * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +function xmldb_block_course_overview_upgrade($oldversion, $block) { + global $CFG; + + // Implement pagination. + if ($oldversion < 2018070400.2) { + set_config('setmaxcourses', 10, 'block_course_overview'); + set_config('setmaxcoursesmax', 50, 'block_course_overview'); + upgrade_block_savepoint(true, 2018070400.2, 'course_overview', true); + } + + return true; +} diff --git a/lang/en/block_course_overview.php b/lang/en/block_course_overview.php index 4761f0c..062f86d 100644 --- a/lang/en/block_course_overview.php +++ b/lang/en/block_course_overview.php @@ -23,45 +23,66 @@ */ $string['activityoverview'] = 'You have {$a}s that need attention'; +$string['addfavourite'] = 'Add favourite'; $string['alwaysshowall'] = 'Always show all'; $string['collapseall'] = 'Collapse all course lists'; $string['configotherexpanded'] = 'If enabled, other courses will be expanded by default unless overridden by user preferences.'; $string['configpreservestates'] = 'If enabled, the collapsed/expanded states set by the user are stored and used on each load.'; $string['course_overview:addinstance'] = 'Add a new course overview block'; $string['course_overview:myaddinstance'] = 'Add a new course overview block to Dashboard'; -$string['defaultmaxcourses'] = 'Default maximum courses'; -$string['defaultmaxcoursesdesc'] = 'Maximum courses which should be displayed on course overview block, 0 will show all courses'; +$string['courses'] = 'Courses'; +$string['defaulttab'] = 'Default tab'; +$string['defaulttabdesc'] = 'Which tab will be displayed by default when the Dashboard is opened'; $string['expandall'] = 'Expand all course lists'; -$string['forcedefaultmaxcourses'] = 'Force maximum courses'; -$string['forcedefaultmaxcoursesdesc'] = 'If set then user will not be able to change his/her personal setting'; +$string['favourites'] = 'Favourites'; $string['fullpath'] = 'All categories and subcategories'; -$string['hiddencoursecount'] = 'You have {$a} hidden course'; -$string['hiddencoursecountplural'] = 'You have {$a} hidden courses'; -$string['hiddencoursecountwithshowall'] = 'You have {$a->coursecount} hidden course ({$a->showalllink})'; -$string['hiddencoursecountwithshowallplural'] = 'You have {$a->coursecount} hidden courses ({$a->showalllink})'; +$string['help'] = 'Help'; +$string['help_help'] = '\'Customise this page\', then drag-and-drop to reorder courses. Click activity icons for overview'; +$string['keepfavourites'] = 'Keep favourites in course list'; +$string['keepfavouritesdesc'] = 'Show courses in main course tab even if they are also in the favourites tab'; +$string['makefavourite'] = 'Make favourite'; $string['message'] = 'message'; $string['messages'] = 'messages'; +$string['morecoursestext'] = "List More Courses"; $string['movecourse'] = 'Move course: {$a}'; $string['movecoursehere'] = 'Move course here'; $string['movetofirst'] = 'Move {$a} course to top'; $string['moveafterhere'] = 'Move {$a->movingcoursename} course after {$a->currentcoursename}'; $string['movingcourse'] = 'You are moving: {$a->fullname} ({$a->cancellink})'; +$string['nextpage'] = "Next page"; +$string['nocourses'] = 'There are no courses to show'; $string['none'] = 'None'; $string['numtodisplay'] = 'Number of courses to display: '; $string['onlyparentname'] = 'Parent category only'; $string['otherexpanded'] = 'Other courses expanded'; -$string['pluginname'] = 'Course overview (legacy)'; +$string['pluginname'] = 'Course tabbed overview'; $string['preservestates'] = 'Preserve expanded states'; +$string['prevpage'] = "Previous page"; +$string['privacy:metadata:courseorder'] = 'Ordered list of displayed courses'; +$string['privacy:metadata:coursesortorder'] = 'Course sort order (old version)'; +$string['privacy:metadata:favourites'] = 'Ordered list of favourite courses'; +$string['privacy:metadata:numberofcourses'] = 'Number of courses displayed'; +$string['privacy:metadata:sortorder'] = 'Sort order'; +$string['removefavourite'] = 'Remove favourite'; +$string['reorderfullname'] = 'Course full name'; +$string['reorderid'] = 'Course id'; +$string['reorderiddesc'] = 'Course id desc'; +$string['reordernone'] = 'Drag-and-drop order'; +$string['reordershortname'] = 'Course short name'; +$string['setmaxcourses'] = "Set maximum courses"; +$string['setmaxcoursesdesc'] = "Set the default user maximum number of courses to show at once in the Course Summary Block."; +$string['setmaxcoursesmax'] = "Set maximum possible courses"; +$string['setmaxcoursesmaxdesc'] = "Set the maximum number possible of courses users can choose to show in the Course Summary Block."; $string['shortnameprefix'] = 'Includes {$a}'; $string['shortnamesufixsingular'] = ' (and {$a} other)'; $string['shortnamesufixprural'] = ' (and {$a} others)'; $string['showcategories'] = 'Categories to show'; $string['showcategoriesdesc'] = 'Should course categories be displayed below each course?'; -$string['showchildren'] = 'Show children'; -$string['showchildrendesc'] = 'Should child courses be listed underneath the main course title?'; -$string['showwelcomearea'] = 'Show welcome area'; -$string['showwelcomeareadesc'] = 'Show the welcome area above the course list?'; -$string['title'] = 'Course overview'; +$string['sortorder'] = 'Sort order'; +$string['title'] = 'Course tabbed overview'; +$string['unfavourite'] = 'Remove favourite'; +$string['userchoosezero'] = " (use default)"; +$string['usersetmaxcourses'] = "Number of courses to display:"; $string['view_edit_profile'] = '(View and edit your profile.)'; $string['welcome'] = 'Welcome {$a}'; $string['youhavemessages'] = 'You have {$a} unread '; diff --git a/locallib.php b/locallib.php index f681086..1b4a1e3 100644 --- a/locallib.php +++ b/locallib.php @@ -22,10 +22,21 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +defined('MOODLE_INTERNAL') || die(); + define('BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_NONE', '0'); define('BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_ONLY_PARENT_NAME', '1'); define('BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_FULL_PATH', '2'); +define('BLOCKS_COURSE_OVERVIEW_REORDER_NONE', '0'); +define('BLOCKS_COURSE_OVERVIEW_REORDER_FULLNAME', '1'); +define('BLOCKS_COURSE_OVERVIEW_REORDER_SHORTNAME', '2'); +define('BLOCKS_COURSE_OVERVIEW_REORDER_ID', '3'); +define('BLOCKS_COURSE_OVERVIEW_REORDER_IDDESC', '4'); + +define('BLOCKS_COURSE_OVERVIEW_DEFAULT_FAVOURITES', '1'); +define('BLOCKS_COURSE_OVERVIEW_DEFAULT_COURSES', '2'); + /** * Display overview for courses * @@ -35,11 +46,17 @@ function block_course_overview_get_overviews($courses) { global $CFG; + // Tab may not have any courses. + if (!$courses) { + return array(); + } + // Disable debugging mode because all course modules show debugging message in their print_overview. $debugmode = $CFG->debug; $CFG->debug ^= E_DEPRECATED; $htmlarray = array(); + if ($modules = get_plugin_list_with_function('mod', 'print_overview')) { // Split courses list into batches with no more than MAX_MODINFO_CACHE_SIZE courses in one batch. // Otherwise we exceed the cache limit in get_fast_modinfo() and rebuild it too often. @@ -75,7 +92,8 @@ function block_course_overview_update_mynumber($number) { function block_course_overview_update_myorder($sortorder) { $value = implode(',', $sortorder); if (core_text::strlen($value) > 1333) { - // The value won't fit into the user preference. Remove courses in the end of the list (mostly likely user won't even notice). + // The value won't fit into the user preference. + // Remove courses in the end of the list (mostly likely user won't even notice). $value = preg_replace('/,[\d]*$/', '', core_text::substr($value, 0, 1334)); } set_user_preference('course_overview_course_sortorder', $value); @@ -101,140 +119,237 @@ function block_course_overview_get_myorder() { } /** - * Returns shortname of activities in course + * Get the list of course favourites * - * @param int $courseid id of course for which activity shortname is needed - * @return string|bool list of child shortname + * @return array list of course ids */ -function block_course_overview_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', $diff); - } else { - $suffix = get_string('shortnamesufixsingular', 'block_course_overview', $diff); - } - } - $shortnames = get_string('shortnameprefix', 'block_course_overview', implode('; ', $shortnames)); - $shortnames .= $suffix; +function block_course_overview_get_favourites() { + if ($value = get_user_preferences('course_overview_favourites')) { + return explode(',', $value); + } else { + return array(); } - - return isset($shortnames) ? $shortnames : false; } /** - * Returns maximum number of courses which will be displayed in course_overview block + * Sets favourites * - * @param bool $showallcourses if set true all courses will be visible. - * @return int maximum number of courses + * @param array $favourites list of course ids */ -function block_course_overview_get_max_user_courses($showallcourses = false) { - // Get block configuration - $config = get_config('block_course_overview'); - $limit = $config->defaultmaxcourses; - - // If max course is not set then try get user preference - if (empty($config->forcedefaultmaxcourses)) { - if ($showallcourses) { - $limit = 0; - } else { - $limit = get_user_preferences('course_overview_number_of_courses', $limit); - } +function block_course_overview_update_favourites($favourites) { + $value = implode(',', $favourites); + if (core_text::strlen($value) > 1333) { + // The value won't fit into the user preference. + // Remove courses in the end of the list (mostly likely user won't even notice). + $value = preg_replace('/,[\d]*$/', '', core_text::substr($value, 0, 1334)); + } + set_user_preference('course_overview_favourites', $value); +} + +/** + * Get sort order preference + * @return int + */ +function block_course_overview_get_sortorder() { + if ($value = get_user_preferences('course_overview_sortorder')) { + return $value; + } else { + return BLOCKS_COURSE_OVERVIEW_REORDER_NONE; + } +} + +/** + * Set sort order preference + * @param int $sortorder + */ +function block_course_overview_update_sortorder($sortorder) { + set_user_preference('course_overview_sortorder', $sortorder); +} + +/** + * Sets user preference for max number of courses to show in course_overview block + * @param int $usersetmaxcourses + */ +function block_course_overview_update_usersetmaxcourses($usersetmaxcourses) { + set_user_preference('course_overview_usersetmaxcourses', $usersetmaxcourses); +} + +/** + * Gets user preference for max number of courses to show in course_overview block + * @return int + */ +function block_course_overview_get_usersetmaxcourses() { + if ($value = get_user_preferences('course_overview_usersetmaxcourses')) { + return $value; + } else { + return get_config('block_course_overview')->setmaxcourses; } - return $limit; } /** * Return sorted list of user courses * - * @param bool $showallcourses if set true all courses will be visible. + * @param bool $favourites tab selected + * @param bool $keepfavourites setting, show favs in course tab + * @param array $exlude list of courses not to include (i.e. favs in courses list)A * @return array list of sorted courses and count of courses. */ -function block_course_overview_get_sorted_courses($showallcourses = false) { +function block_course_overview_get_sorted_courses($favourites, $keepfavourites = false, $exclude = []) { global $USER; - $limit = block_course_overview_get_max_user_courses($showallcourses); + // Bodge... don't regenerate course list. + static $courses = []; - $courses = enrol_get_my_courses(); - $site = get_site(); + $sortorder = block_course_overview_get_sortorder(); - if (array_key_exists($site->id,$courses)) { - unset($courses[$site->id]); - } + if (!$courses) { - foreach ($courses as $c) { - if (isset($USER->lastcourseaccess[$c->id])) { - $courses[$c->id]->lastaccess = $USER->lastcourseaccess[$c->id]; + // Get courses in order. + if ($sortorder == BLOCKS_COURSE_OVERVIEW_REORDER_FULLNAME) { + $sort = 'fullname ASC'; + } else if ($sortorder == BLOCKS_COURSE_OVERVIEW_REORDER_SHORTNAME) { + $sort = 'shortname ASC'; + } else if ($sortorder == BLOCKS_COURSE_OVERVIEW_REORDER_ID) { + $sort = 'id ASC'; + } else if ($sortorder == BLOCKS_COURSE_OVERVIEW_REORDER_IDDESC) { + $sort = 'id DESC'; } else { - $courses[$c->id]->lastaccess = 0; + $sort = 'visible DESC,sortorder ASC'; } - } + $courses = enrol_get_my_courses(null, $sort); + $site = get_site(); - // Get remote courses. - $remotecourses = array(); - if (is_enabled_auth('mnet')) { - $remotecourses = get_my_remotecourses(); - } - // Remote courses will have -ve remoteid as key, so it can be differentiated from normal courses - foreach ($remotecourses as $id => $val) { - $remoteid = $val->remoteid * -1; - $val->id = $remoteid; - $courses[$remoteid] = $val; + 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; + } + } + + // Get remote courses. + $remotecourses = array(); + if (is_enabled_auth('mnet')) { + $remotecourses = get_my_remotecourses(); + } + + // Remote courses will have -ve remoteid as key, so it can be differentiated from normal courses. + foreach ($remotecourses as $id => $val) { + $remoteid = $val->remoteid * -1; + $val->id = $remoteid; + $courses[$remoteid] = $val; + } } - $order = block_course_overview_get_myorder(); + if ($favourites) { + $order = block_course_overview_get_favourites(); + } else { + $order = block_course_overview_get_myorder(); + } $sortedcourses = array(); - $counter = 0; - // Get courses in sort order into list. - foreach ($order as $key => $cid) { - if (($counter >= $limit) && ($limit != 0)) { - break; + + // Accept list as-is or order by preference list. + if (!$favourites && ($sortorder != BLOCKS_COURSE_OVERVIEW_REORDER_NONE)) { + $sortedcourses = $courses; + } else { + $counter = 0; + + // Get courses in sort order into list. + foreach ($order as $key => $cid) { + + // Make sure user is still enroled. + if (isset($courses[$cid])) { + $sortedcourses[$cid] = $courses[$cid]; + $counter++; + } } - // Make sure user is still enroled. - if (isset($courses[$cid])) { - $sortedcourses[$cid] = $courses[$cid]; - $counter++; + // Append unsorted courses if limit allows & not favourites. + if (!$favourites) { + foreach ($courses as $c) { + if (!in_array($c->id, $order)) { + $sortedcourses[$c->id] = $c; + $counter++; + } + } } } - // Append unsorted courses if limit allows - foreach ($courses as $c) { - if (($limit != 0) && ($counter >= $limit)) { - break; - } - if (!in_array($c->id, $order)) { - $sortedcourses[$c->id] = $c; - $counter++; + + // If this is the courses tab and we are excluding favourites. + if (!$favourites && !$keepfavourites) { + foreach ($sortedcourses as $c) { + if (in_array($c->id, $exclude)) { + unset($sortedcourses[$c->id]); + } } } - // From list extract site courses for overview + // From list extract site courses for overview. $sitecourses = array(); foreach ($sortedcourses as $key => $course) { if ($course->id > 0) { $sitecourses[$key] = $course; } } - return array($sortedcourses, $sitecourses, count($courses)); + + // Implement pagination. + $maxcourses = block_course_overview_get_usersetmaxcourses(); + if ($favourites) { + $page = optional_param('ssf_pagenum', 0, PARAM_INT); + } else { + $page = optional_param('ssc_pagenum', 0, PARAM_INT); + } + $page = $page <= 0 ? 0 : $page; + $first = $page * $maxcourses; + $sortedcoursessliced = array_slice($sortedcourses, $first, $maxcourses, true); + return array($sortedcoursessliced, $sitecourses, count($sortedcourses)); +} + +/** + * Add a course to favourites + * @param int $favourite id of course + */ +function block_course_overview_add_favourite($favourite) { + + // Add to fabourites list. + $favourites = block_course_overview_get_favourites(); + if (!in_array($favourite, $favourites)) { + array_unshift($favourites, $favourite); + } + block_course_overview_update_favourites($favourites); + + // Remove from courses list. + $order = block_course_overview_get_myorder(); + $key = array_search($favourite, $order); + if ($key !== false) { + unset($order[$key]); + } + block_course_overview_update_myorder($order); +} + +/** + * Remove course from favourites + * @param int $favourite id of course + */ +function block_course_overview_remove_favourite($favourite) { + + // Remove from favourites list. + $order = block_course_overview_get_favourites(); + $key = array_search($favourite, $order); + if ($key !== false) { + unset($order[$key]); + } + block_course_overview_update_favourites($order); + + // Add to courses list. + $order = block_course_overview_get_myorder(); + if (!in_array($favourite, $order)) { + $order[] = $favourite; + } + block_course_overview_update_myorder($order); } diff --git a/module.js b/module.js deleted file mode 100644 index e900df8..0000000 --- a/module.js +++ /dev/null @@ -1,230 +0,0 @@ -M.block_course_overview = {} - -M.block_course_overview.add_handles = function(Y) { - M.block_course_overview.Y = Y; - var MOVEICON = { - pix: "i/move_2d", - component: 'moodle' - }; - - YUI().use('dd-constrain', 'dd-proxy', 'dd-drop', 'dd-plugin', function(Y) { - //Static Vars - var goingUp = false, lastY = 0; - - var list = Y.Node.all('.course_list .coursebox'); - list.each(function(v, k) { - // Replace move link and image with move_2d image. - var imagenode = v.one('.course_title .move a img'); - imagenode.setAttribute('src', M.util.image_url(MOVEICON.pix, MOVEICON.component)); - imagenode.addClass('cursor'); - v.one('.course_title .move a').replace(imagenode); - - var dd = new Y.DD.Drag({ - node: v, - target: { - padding: '0 0 0 20' - } - }).plug(Y.Plugin.DDProxy, { - moveOnEnd: false - }).plug(Y.Plugin.DDConstrained, { - constrain2node: '.course_list' - }); - dd.addHandle('.course_title .move'); - }); - - Y.DD.DDM.on('drag:start', function(e) { - //Get our drag object - var drag = e.target; - //Set some styles here - drag.get('node').setStyle('opacity', '.25'); - drag.get('dragNode').addClass('block_course_overview'); - drag.get('dragNode').set('innerHTML', drag.get('node').get('innerHTML')); - drag.get('dragNode').setStyles({ - opacity: '.5', - borderColor: drag.get('node').getStyle('borderColor'), - backgroundColor: drag.get('node').getStyle('backgroundColor') - }); - }); - - Y.DD.DDM.on('drag:end', function(e) { - var drag = e.target; - //Put our styles back - drag.get('node').setStyles({ - visibility: '', - opacity: '1' - }); - M.block_course_overview.save(Y); - }); - - Y.DD.DDM.on('drag:drag', function(e) { - //Get the last y point - var y = e.target.lastXY[1]; - //is it greater than the lastY var? - if (y < lastY) { - //We are going up - goingUp = true; - } else { - //We are going down. - goingUp = false; - } - //Cache for next check - lastY = y; - }); - - Y.DD.DDM.on('drop:over', function(e) { - //Get a reference to our drag and drop nodes - var drag = e.drag.get('node'), - drop = e.drop.get('node'); - - //Are we dropping on a li node? - if (drop.hasClass('coursebox')) { - //Are we not going up? - if (!goingUp) { - drop = drop.get('nextSibling'); - } - //Add the node to this list - e.drop.get('node').get('parentNode').insertBefore(drag, drop); - //Resize this nodes shim, so we can drop on it later. - e.drop.sizeShim(); - } - }); - - Y.DD.DDM.on('drag:drophit', function(e) { - var drop = e.drop.get('node'), - drag = e.drag.get('node'); - - //if we are not on an li, we must have been dropped on a ul - if (!drop.hasClass('coursebox')) { - if (!drop.contains(drag)) { - drop.appendChild(drag); - } - } - }); - }); -} - -M.block_course_overview.save = function() { - var Y = M.block_course_overview.Y; - var sortorder = Y.one('.course_list').get('children').getAttribute('id'); - for (var i = 0; i < sortorder.length; i++) { - sortorder[i] = sortorder[i].substring(7); - } - var params = { - sesskey : M.cfg.sesskey, - sortorder : sortorder - }; - Y.io(M.cfg.wwwroot+'/blocks/course_overview/save.php', { - method: 'POST', - data: build_querystring(params), - context: this - }); -} - -/** - * 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.collapsible = function(Y, id, userpref, strtooltip) { - if (userpref) { - M.block_course_overview.userpref = true; - } - Y.use('anim', function(Y) { - new M.block_course_overview.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.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(''); - // 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.userpref = false; - -/** - * The user preference that stores the state of this box. - * @property userpref - * @type String - */ -M.block_course_overview.CollapsibleRegion.prototype.userpref = null; - -/** - * The key divs that make up this - * @property div - * @type Y.Node - */ -M.block_course_overview.CollapsibleRegion.prototype.div = null; - -/** - * The key divs that make up this - * @property icon - * @type Y.Node - */ -M.block_course_overview.CollapsibleRegion.prototype.icon = null; - diff --git a/move.php b/move.php deleted file mode 100644 index b6f042d..0000000 --- a/move.php +++ /dev/null @@ -1,60 +0,0 @@ -. - -/** - * Move/order course functionality for course_overview block. - * - * @package block_course_overview - * @copyright 2012 Adam Olley - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -require_once(__DIR__ . '/../../config.php'); -require_once(__DIR__ . '/locallib.php'); - -require_sesskey(); -require_login(); - -$coursetomove = required_param('courseid', PARAM_INT); -$moveto = required_param('moveto', PARAM_INT); - -list($courses, $sitecourses, $coursecount) = block_course_overview_get_sorted_courses(); -$sortedcourses = array_keys($courses); - -$currentcourseindex = array_search($coursetomove, $sortedcourses); -// If coursetomove is not found or moveto < 0 or > count($sortedcourses) then throw error. -if ($currentcourseindex === false) { - print_error("invalidcourseid", null, null, $coursetomove); -} else if (($moveto < 0) || ($moveto >= count($sortedcourses))) { - print_error("invalidaction"); -} - -// If current course index is same as destination index then don't do anything. -if ($currentcourseindex === $moveto) { - redirect(new moodle_url('/my/index.php')); -} - -// Create neworder list for courses. -$neworder = array(); - -unset($sortedcourses[$currentcourseindex]); -$neworder = array_slice($sortedcourses, 0, $moveto, true); -$neworder[] = $coursetomove; -$remaningcourses = array_slice($sortedcourses, $moveto); -foreach ($remaningcourses as $courseid) { - $neworder[] = $courseid; -} -block_course_overview_update_myorder(array_values($neworder)); -redirect(new moodle_url('/my/index.php')); diff --git a/renderer.php b/renderer.php deleted file mode 100644 index 6977eca..0000000 --- a/renderer.php +++ /dev/null @@ -1,348 +0,0 @@ -. - -/** - * course_overview block rendrer - * - * @package block_course_overview - * @copyright 2012 Adam Olley - * @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 - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class block_course_overview_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'); - if ($config->showcategories != BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_NONE) { - global $CFG; - require_once($CFG->libdir.'/coursecatlib.php'); - } - $ismovingcourse = false; - $courseordernumber = 0; - $maxcourses = count($courses); - $userediting = false; - // Intialise string/icon etc if user is editing and courses > 1 - if ($this->page->user_is_editing() && (count($courses) > 1)) { - $userediting = true; - $this->page->requires->js_init_call('M.block_course_overview.add_handles'); - - // Check if course is moving - $ismovingcourse = optional_param('movecourse', FALSE, PARAM_BOOL); - $movingcourseid = optional_param('courseid', 0, PARAM_INT); - } - - // Render first movehere icon. - if ($ismovingcourse) { - // Remove movecourse param from url. - $this->page->ensure_param_not_in_url('movecourse'); - - // Show moving course notice, so user knows what is being moved. - $html .= $this->output->box_start('notice'); - $a = new stdClass(); - $a->fullname = $courses[$movingcourseid]->fullname; - $a->cancellink = html_writer::link($this->page->url, get_string('cancel')); - $html .= get_string('movingcourse', 'block_course_overview', $a); - $html .= $this->output->box_end(); - - $moveurl = new moodle_url('/blocks/course_overview/move.php', - array('sesskey' => sesskey(), 'moveto' => 0, 'courseid' => $movingcourseid)); - // Create move icon, so it can be used. - $name = $courses[$movingcourseid]->fullname; - $movetofirsticon = $this->output->pix_icon('movehere', get_string('movetofirst', 'block_course_overview', $name)); - $moveurl = html_writer::link($moveurl, $movetofirsticon); - $html .= html_writer::tag('div', $moveurl, array('class' => 'movehere')); - } - - foreach ($courses as $key => $course) { - // If moving course, then don't show course which needs to be moved. - if ($ismovingcourse && ($course->id == $movingcourseid)) { - continue; - } - $html .= $this->output->box_start('coursebox', "course-{$course->id}"); - $html .= html_writer::start_tag('div', array('class' => 'course_title')); - // If user is editing, then add move icons. - if ($userediting && !$ismovingcourse) { - $moveicon = $this->output->pix_icon('t/move', get_string('movecourse', 'block_course_overview', $course->fullname)); - $moveurl = new moodle_url($this->page->url, array('sesskey' => sesskey(), 'movecourse' => 1, 'courseid' => $course->id)); - $moveurl = html_writer::link($moveurl, $moveicon); - $html .= html_writer::tag('div', $moveurl, array('class' => 'move')); - - } - - // No need to pass title through s() here as it will be done automatically by html_writer. - $attributes = array('title' => $course->fullname); - if ($course->id > 0) { - if (empty($course->visible)) { - $attributes['class'] = 'dimmed'; - } - $courseurl = new moodle_url('/course/view.php', array('id' => $course->id)); - $coursefullname = format_string(get_course_display_name_for_list($course), true, $course->id); - $link = html_writer::link($courseurl, $coursefullname, $attributes); - $html .= $this->output->heading($link, 2, 'title'); - } else { - $html .= $this->output->heading(html_writer::link( - new moodle_url('/auth/mnet/jump.php', array('hostid' => $course->hostid, 'wantsurl' => '/course/view.php?id='.$course->remoteid)), - format_string($course->shortname, true), $attributes) . ' (' . format_string($course->hostname) . ')', 2, 'title'); - } - $html .= $this->output->container('', 'flush'); - $html .= html_writer::end_tag('div'); - - if (!empty($config->showchildren) && ($course->id > 0)) { - // List children here. - if ($children = block_course_overview_get_child_shortnames($course->id)) { - $html .= html_writer::tag('span', $children, array('class' => 'coursechildren')); - } - } - - // If user is moving courses, then down't show overview. - if (isset($overviews[$course->id]) && !$ismovingcourse) { - $html .= $this->activity_display($course->id, $overviews[$course->id]); - } - - if ($config->showcategories != BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_NONE) { - // List category parent or categories path here. - $currentcategory = coursecat::get($course->category, IGNORE_MISSING); - if ($currentcategory !== null) { - $html .= html_writer::start_tag('div', array('class' => 'categorypath')); - if ($config->showcategories == BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_FULL_PATH) { - foreach ($currentcategory->get_parents() as $categoryid) { - $category = coursecat::get($categoryid, IGNORE_MISSING); - if ($category !== null) { - $html .= $category->get_formatted_name().' / '; - } - } - } - $html .= $currentcategory->get_formatted_name(); - $html .= html_writer::end_tag('div'); - } - } - - $html .= $this->output->container('', 'flush'); - $html .= $this->output->box_end(); - $courseordernumber++; - if ($ismovingcourse) { - $moveurl = new moodle_url('/blocks/course_overview/move.php', - array('sesskey' => sesskey(), 'moveto' => $courseordernumber, 'courseid' => $movingcourseid)); - $a = new stdClass(); - $a->movingcoursename = $courses[$movingcourseid]->fullname; - $a->currentcoursename = $course->fullname; - $movehereicon = $this->output->pix_icon('movehere', get_string('moveafterhere', 'block_course_overview', $a)); - $moveurl = html_writer::link($moveurl, $movehereicon); - $html .= html_writer::tag('div', $moveurl, array('class' => 'movehere')); - } - } - // Wrap course list in a div and return. - return html_writer::tag('div', $html, array('class' => 'course_list')); - } - - /** - * 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->image_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], '', 'region_'.$cid.'_'.$module, $icontext, '', true); - - $output .= html_writer::end_tag('div'); - } - $output .= html_writer::end_tag('div'); - return $output; - } - - /** - * Constructs header in editing mode - * - * @param int $max maximum number of courses - * @return string html of header bar. - */ - public function editing_bar_head($max = 0) { - $output = $this->output->box_start('notice'); - - $options = array('0' => get_string('alwaysshowall', 'block_course_overview')); - for ($i = 1; $i <= $max; $i++) { - $options[$i] = $i; - } - $url = new moodle_url('/my/index.php', ['sesskey' => sesskey()]); - $select = new single_select($url, 'mynumber', $options, block_course_overview_get_max_user_courses(), array()); - $select->set_label(get_string('numtodisplay', 'block_course_overview')); - $output .= $this->output->render($select); - - $output .= $this->output->box_end(); - return $output; - } - - /** - * Show hidden courses count - * - * @param int $total count of hidden courses - * @return string html - */ - public function hidden_courses($total) { - if ($total <= 0) { - return; - } - $output = $this->output->box_start('notice'); - $plural = $total > 1 ? 'plural' : ''; - $config = get_config('block_course_overview'); - // Show view all course link to user if forcedefaultmaxcourses is not empty. - if (!empty($config->forcedefaultmaxcourses)) { - $output .= get_string('hiddencoursecount'.$plural, 'block_course_overview', $total); - } else { - $a = new stdClass(); - $a->coursecount = $total; - $a->showalllink = html_writer::link(new moodle_url('/my/index.php', array('mynumber' => block_course_overview::SHOW_ALL_COURSES)), - get_string('showallcourses')); - $output .= get_string('hiddencoursecountwithshowall'.$plural, 'block_course_overview', $a); - } - - $output .= $this->output->box_end(); - 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 .= '
'; - $output .= '
'; - $output .= '
'; - $output .= $caption . ' '; - $output .= '
'; - $this->page->requires->js_init_call('M.block_course_overview.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 = '
'; - 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 $CFG, $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)); - - if (!empty($CFG->messaging)) { - $plural = 's'; - if ($msgcount > 0) { - $output .= get_string('youhavemessages', 'block_course_overview', $msgcount); - if ($msgcount == 1) { - $plural = ''; - } - } else { - $output .= get_string('youhavenomessages', 'block_course_overview'); - } - $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->container('', 'flush'); - $output .= $this->output->box_end(); - - return $output; - } -} diff --git a/save.php b/save.php index b4bb175..e8a2b4f 100644 --- a/save.php +++ b/save.php @@ -30,5 +30,11 @@ require_login(); $sortorder = required_param_array('sortorder', PARAM_INT); +$activetab = required_param('tab', PARAM_ALPHA); -block_course_overview_update_myorder($sortorder); +if ($activetab == 'courses') { + block_course_overview_update_myorder($sortorder); + block_course_overview_update_sortorder(0); +} else if ($activetab == "favourites") { + block_course_overview_update_favourites($sortorder); +} diff --git a/settings.php b/settings.php index d1c4275..e3a703b 100644 --- a/settings.php +++ b/settings.php @@ -23,20 +23,50 @@ */ defined('MOODLE_INTERNAL') || die; +require_once(dirname(__FILE__) . '/locallib.php'); + if ($ADMIN->fulltree) { - $settings->add(new admin_setting_configtext('block_course_overview/defaultmaxcourses', new lang_string('defaultmaxcourses', 'block_course_overview'), - new lang_string('defaultmaxcoursesdesc', 'block_course_overview'), 10, PARAM_INT)); - $settings->add(new admin_setting_configcheckbox('block_course_overview/forcedefaultmaxcourses', new lang_string('forcedefaultmaxcourses', 'block_course_overview'), - new lang_string('forcedefaultmaxcoursesdesc', 'block_course_overview'), 1, PARAM_INT)); - $settings->add(new admin_setting_configcheckbox('block_course_overview/showchildren', new lang_string('showchildren', 'block_course_overview'), - new lang_string('showchildrendesc', 'block_course_overview'), 1, PARAM_INT)); - $settings->add(new admin_setting_configcheckbox('block_course_overview/showwelcomearea', new lang_string('showwelcomearea', 'block_course_overview'), - new lang_string('showwelcomeareadesc', 'block_course_overview'), 1, PARAM_INT)); $showcategories = array( BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_NONE => new lang_string('none', 'block_course_overview'), BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_ONLY_PARENT_NAME => new lang_string('onlyparentname', 'block_course_overview'), BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_FULL_PATH => new lang_string('fullpath', 'block_course_overview') ); - $settings->add(new admin_setting_configselect('block_course_overview/showcategories', new lang_string('showcategories', 'block_course_overview'), - new lang_string('showcategoriesdesc', 'block_course_overview'), BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_NONE, $showcategories)); + $settings->add(new admin_setting_configselect( + 'block_course_overview/showcategories', + new lang_string('showcategories', 'block_course_overview'), + new lang_string('showcategoriesdesc', 'block_course_overview'), + BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_NONE, + $showcategories + )); + $settings->add(new admin_setting_configcheckbox( + 'block_course_overview/keepfavourites', + new lang_string('keepfavourites', 'block_course_overview'), + new lang_string('keepfavouritesdesc', 'block_course_overview'), + 0 + )); + $defaulttabs = [ + BLOCKS_COURSE_OVERVIEW_DEFAULT_FAVOURITES => new lang_string('favourites', 'block_course_overview'), + BLOCKS_COURSE_OVERVIEW_DEFAULT_COURSES => new lang_string('courses', 'block_course_overview'), + ]; + $settings->add(new admin_setting_configselect( + 'block_course_overview/defaulttab', + new lang_string('defaulttab', 'block_course_overview'), + new lang_string('defaulttabdesc', 'block_course_overview'), + BLOCKS_COURSE_OVERVIEW_DEFAULT_FAVOURITES, + $defaulttabs + )); + $settings->add(new admin_setting_configtext( + 'block_course_overview/setmaxcourses', + new lang_string('setmaxcourses', 'block_course_overview'), + new lang_string('setmaxcoursesdesc', 'block_course_overview'), + 10, + PARAM_INT, + 5)); + $settings->add(new admin_setting_configtext( + 'block_course_overview/setmaxcoursesmax', + new lang_string('setmaxcoursesmax', 'block_course_overview'), + new lang_string('setmaxcoursesmaxdesc', 'block_course_overview'), + 50, + PARAM_INT, + 5)); } diff --git a/styles.css b/styles.css index 2aab2a3..36ac9aa 100644 --- a/styles.css +++ b/styles.css @@ -1,87 +1,89 @@ -.block_course_overview .coursechildren { - font-weight: normal; - font-style: italic; +.block-course-overview .courseovbox { + border-bottom: 1px solid #d3d8dc; + padding-top: 12px; + padding-bottom: 4px; } -.block_course_overview .categorypath { - text-align: right; +.block-course-overview .course-list { + padding-top: 4px; } -.block_course_overview .content { - margin: 0 20px; +.overview-icon .icon { + height: 25px; + width: 25px; } -.block_course_overview .content .notice { - margin: 5px 0; -} -.block_course_overview .coursebox { - padding: 15px; - width: auto; +.course-overview-dialog { + display: none; + background-color: #fff; + padding: 20px; + border: 1px solid #d3d8dc; + z-index: 9999 !important; + box-shadow: 10px 10px 5px rgba(128, 128, 128, 0.5); } -.block_course_overview .profilepicture { - float: left; +.course-overview-dialog .ui-dialog-titlebar-close { + border: 0; } -.block_course_overview .welcome_area { - width: 100%; - padding-bottom: 5px; +.course-overview-dialog .ui-dialog-titlebar-close:after { + position: absolute; + font-family: FontAwesome; + font-size: 2.0em; + top:8px; + right:8px; + content: "\f00d "; } -.block_course_overview .welcome_message { - float: left; - padding: 10px; - border-collapse: separate; - clear: none; +.dialogue h3 { + font-size: 1.5rem; } -.block_course_overview .content h2.title { - float: left; - margin: 0 0 .5em 0; - position: relative; +a.favourite_icon:hover { + text-decoration: none; } -.block_course_overview .course_title { - position: relative; +.block-course-overview .overview-help { + margin-top: 10px; } -.editing .block_course_overview .coursebox .cursor { - cursor: move; - margin-bottom: 2px; +.block-course-overview .overview-help i { + font-size: 1.5em; } -.editing .block_course_overview .move { - float: left; - padding: 2px 10px 0 0; +div.courseovbox { + margin-left: -15px !important; } -.block_course_overview .course_list { - width: 100%; +.course-overview-dialog .ui-dialog-titlebar button{ + background-color: #fff; + background-image:none; + height: 25px; + position: absolute; + top: 8px; + right: 13px; } - -.block_course_overview div.flush { - clear: both; +.course-overview-dialog .ui-dialog-titlebar-close::after{ + top: 1px; + left: 1px; } -.block_course_overview .activity_info { - clear: both; +.block-course-overview .morecoursesdiv { + margin-top: 10px; } - -.block_course_overview .activity_overview { - padding: 2px; +.block-course-overview .morecoursesdiv .morecourseslink { + margin-left: 20px; } - -.block_course_overview .activity_overview img.iconlarge { - vertical-align: text-bottom; - margin-right: 6px; +.block-course-overview .morecoursesdiv a { + text-decoration: none; } - -.block_course_overview .singleselect { - text-align: left; - margin: 0; +.block-course-overview .morecoursesdiv .pageslink { + margin-left: 10px; } - -.block_course_overview .content .course_list .movehere { - margin-bottom: 15px; +.block-course-overview .morecoursesdiv a, .block-course-overview .morecoursesdiv .current { + padding: 5px; } +.block-course-overview .tab-content { + overflow: hidden; +} \ No newline at end of file diff --git a/templates/courselist.mustache b/templates/courselist.mustache new file mode 100644 index 0000000..f083514 --- /dev/null +++ b/templates/courselist.mustache @@ -0,0 +1,58 @@ +{{! + 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 . +}} +{{! + @template block_course_overview/courselist + + This template renders the course list for the course_overview block + + Example context (json): + {} +}} +
+ {{# data }} +
+
+ {{# isediting }} + + {{/ isediting }} + {{^ isediting }} + + + + {{/ isediting }} +
+
+ {{ fullname }}
+ {{ categories }} +
+ {{# hasoverviews }} +
+ {{# overviews }} + + {{{ icon }}} + + {{/ overviews }} +
+ {{/ hasoverviews }} +
+ {{/ data }} + {{^ data }} +
+ {{# str }}nocourses, block_course_overview{{/ str }} +
+ {{/ data }} +
diff --git a/templates/main.mustache b/templates/main.mustache new file mode 100644 index 0000000..590ef63 --- /dev/null +++ b/templates/main.mustache @@ -0,0 +1,112 @@ +{{! + 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 . +}} +{{! + @template block_course_overview/main + + This template renders the main content area for the course_overview block + + Example context (json): + {} +}} + +
+ + {{# isediting }} +
+ {{# str }}sortorder, block_course_overview{{/ str }} {{{ select }}} +
+
+ {{# str }}usersetmaxcourses, block_course_overview{{/ str }} {{{ selectmaxcourses }}} +
+ {{/ isediting }} + + + +
+ {{# tabs }} +
+ {{> block_course_overview/courselist }} + {{# showmorecourses }} +
+ {{{ morecourses.text }}} + {{# morecourses.showprevpage }}{{{ morecourses.prevpage }}}{{/ morecourses.showprevpage }} + {{# morecourses.pages }} + {{^ current }} + + {{/ current }} + {{{ pagetext }}} + {{^ current }} + + {{/ current }} + {{/ morecourses.pages }} + {{# morecourses.shownextpage }}{{{ morecourses.nextpage }}}{{/ morecourses.shownextpage }} +
+ {{/ showmorecourses }} +
+ {{/ tabs }} +
+ + {{^ isediting }} + + {{/ isediting }} + +
+ {{{ help }}} +
+
+ +{{# isediting }} + {{# js }} + require(['jquery', 'block_course_overview/edit'], function($, Edit) { + Edit.init(); + }); + {{/ js }} +{{/ isediting }} +{{^ isediting }} + {{# js }} + require(['jquery', 'block_course_overview/popup'], function($, Popup) { + Popup.init({{ viewingfavourites }}); + }); + {{/ js }} +{{/ isediting }} + diff --git a/tests/behat/block_course_overview.feature b/tests/behat/block_course_overview.feature index 389b6c5..e998892 100644 --- a/tests/behat/block_course_overview.feature +++ b/tests/behat/block_course_overview.feature @@ -18,10 +18,13 @@ Feature: View the course overview block on the dashboard and test it's functiona | Course 1 | C1 | 0 | | Course 2 | C2 | CAT1 | | Course 3 | C3 | CAT2 | - - Scenario: View the block by a user without any enrolments - Given I log in as "student1" - Then I should see "No course information to show" in the "Course overview" "block" + And I log in as "student1" + When I press "Customise this page" + And I add the "Course overview (legacy)" block + And I configure the "Course overview (legacy)" block + And I set the field "Region" to "content" + And I press "Save changes" + And I log out Scenario: View the block by a user with several enrolments Given the following "course enrolments" exist: @@ -29,92 +32,10 @@ Feature: View the course overview block on the dashboard and test it's functiona | student1 | C1 | student | | student1 | C2 | student | When I log in as "student1" - Then I should see "Course 1" in the "Course overview" "block" - And I should see "Course 2" in the "Course overview" "block" - - Scenario: View the block by a user with several enrolments and limit the number of courses. - Given the following "course enrolments" exist: - | user | course | role | - | student1 | C1 | student | - | student1 | C2 | student | - | student1 | C3 | student | - When I log in as "student1" - And I press "Customise this page" - And I select "1" from the "Number of courses to display:" singleselect - Then I should see "Course 1" in the "Course overview" "block" - And I should see "You have 2 hidden courses" - And I should not see "Course 2" in the "Course overview" "block" - And I should not see "Course 3" in the "Course overview" "block" - And I follow "Show all courses" - And I should see "Course 1" in the "Course overview" "block" - And I should see "Course 2" in the "Course overview" "block" - And I should see "Course 3" in the "Course overview" "block" - - Scenario: View the block by a user with several enrolments and an admin set default max courses. - Given the following config values are set as admin: - | defaultmaxcourses | 2 | block_course_overview | - And the following "course enrolments" exist: - | user | course | role | - | student1 | C1 | student | - | student1 | C2 | student | - | student1 | C3 | student | - When I log in as "student1" - Then I should see "Course 1" in the "Course overview" "block" - And I should see "Course 2" in the "Course overview" "block" - And I should see "You have 1 hidden course" - And I press "Customise this page" - And I select "Always show all" from the "Number of courses to display:" singleselect - And I should see "Course 3" in the "Course overview" "block" - And I should not see "You have 1 hidden course" - - Scenario: View the block by a user with several enrolments and an admin enforced maximum displayed courses. - Given the following config values are set as admin: - | defaultmaxcourses | 2 | block_course_overview | - | forcedefaultmaxcourses | 1 | block_course_overview | - And the following "course enrolments" exist: - | user | course | role | - | student1 | C1 | student | - | student1 | C2 | student | - | student1 | C3 | student | - When I log in as "student1" - Then I should see "Course 1" in the "Course overview" "block" - And I should see "Course 2" in the "Course overview" "block" - And I should see "You have 1 hidden course" - And I press "Customise this page" - And I should not see "Always show all" - - Scenario: View the block by a user with the welcome area enabled and messaging disabled. - Given the following config values are set as admin: - | showwelcomearea | 1 | block_course_overview | - | messaging | 0 | | - When I log in as "student1" - Then I should see "Welcome Student" in the "Course overview" "block" - And I should not see "messages" in the "Course overview" "block" - - Scenario: View the block by a user with both the welcome area and messaging enabled. - Given the following config values are set as admin: - | showwelcomearea | 1 | block_course_overview | - When I log in as "student1" - Then I should see "Welcome Student" in the "Course overview" "block" - And I should see "You have no unread messages" in the "Course overview" "block" - And I follow "messages" - And I should see "No messages" + Then I should see "Course 1" in the "Course overview (legacy)" "block" + And I should see "Course 2" in the "Course overview (legacy)" "block" @javascript - Scenario: View the block by a user with the welcome area and the user having messages. - Given the following config values are set as admin: - | showwelcomearea | 1 | block_course_overview | - And I log in as "student1" - And I should see "Welcome Student" in the "Course overview" "block" - And I should see "You have no unread messages" in the "Course overview" "block" - And I follow "messages" - And I send "This is message 1" message to "Teacher 1" user - And I send "This is message 2" message to "Teacher 1" user - When I log out - And I log in as "teacher1" - Then I should see "Welcome Teacher" in the "Course overview" "block" - And I should see "You have 2 unread messages" in the "Course overview" "block" - Scenario: View the block by a user with the parent categories displayed. Given the following config values are set as admin: | showcategories | Parent category only | block_course_overview | @@ -124,10 +45,10 @@ Feature: View the course overview block on the dashboard and test it's functiona | student1 | C2 | student | | student1 | C3 | student | When I log in as "student1" - Then I should see "Miscellaneous" in the "Course overview" "block" - And I should see "Category 1" in the "Course overview" "block" - And I should see "Category 2" in the "Course overview" "block" - And I should not see "Category 1 / Category 1" in the "Course overview" "block" + Then I should see "Miscellaneous" in the "Course overview (legacy)" "block" + And I should see "Category 1" in the "Course overview (legacy)" "block" + And I should see "Category 2" in the "Course overview (legacy)" "block" + And I should not see "Category 1 / Category 1" in the "Course overview (legacy)" "block" Scenario: View the block by a user with the full categories displayed. Given the following config values are set as admin: @@ -138,25 +59,6 @@ Feature: View the course overview block on the dashboard and test it's functiona | student1 | C2 | student | | student1 | C3 | student | When I log in as "student1" - Then I should see "Miscellaneous" in the "Course overview" "block" - And I should see "Category 1 / Category 2" in the "Course overview" "block" + Then I should see "Miscellaneous" in the "Course overview (legacy)" "block" + And I should see "Category 1 / Category 2" in the "Course overview (legacy)" "block" - @javascript - Scenario: View the block by a user with the show children option enabled. - Given the following config values are set as admin: - | showchildren | 1 | block_course_overview | - And the following "course enrolments" exist: - | user | course | role | - | student1 | C1 | student | - And I log in as "admin" - And I navigate to "Manage enrol plugins" node in "Site administration > Plugins > Enrolments" - And I click on "Enable" "link" in the "Course meta link" "table_row" - And I am on site homepage - And I follow "Course 2" - And I add "Course meta link" enrolment method with: - | Link course | C1 | - And I log out - When I log in as "student1" - Then I should see "Course 1" in the "Course overview" "block" - And I should see "Course 2" in the "Course overview" "block" - And I should see "Includes C1" in the "Course overview" "block" diff --git a/tests/behat/block_course_overview_student.feature b/tests/behat/block_course_overview_student.feature new file mode 100644 index 0000000..fdf7b28 --- /dev/null +++ b/tests/behat/block_course_overview_student.feature @@ -0,0 +1,28 @@ +@block @block_course_overview +Feature: Add the course overview (legacy) block on the dashboard and check it's there + In order to view the course overview (legacy) block on the dashboard + As a user + I can add the block to the dashboard page + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | idnumber | + | student1 | Student | 1 | student1@example.com | S1 | + | teacher1 | Teacher | 1 | teacher1@example.com | T1 | + And the following "categories" exist: + | name | category | idnumber | + | Category 1 | 0 | CAT1 | + | Category 2 | CAT1 | CAT2 | + And I log in as "student1" + + Scenario: Add course overview (legacy) block to page + When I press "Customise this page" + And I add the "Course overview (legacy)" block + And I configure the "Course overview (legacy)" block + And I set the field "Region" to "content" + And I press "Save changes" + Then I should see "Course overview (legacy)" in the "Course overview (legacy)" "block" + And I should see "There are no courses to show" in the "Course overview (legacy)" "block" + + + diff --git a/tests/behat/quiz_overview.feature b/tests/behat/quiz_overview.feature deleted file mode 100644 index c91c551..0000000 --- a/tests/behat/quiz_overview.feature +++ /dev/null @@ -1,93 +0,0 @@ -@block @block_course_overview @mod_quiz -Feature: View the quiz being due - In order to know what quizzes are due - As a student - I can visit my dashboard - - Background: - Given the following "users" exist: - | username | firstname | lastname | email | - | student1 | Student | 1 | student1@example.com | - | student2 | Student | 2 | student2@example.com | - | teacher1 | Teacher | 1 | teacher1@example.com | - And the following "courses" exist: - | fullname | shortname | - | Course 1 | C1 | - | Course 2 | C2 | - And the following "course enrolments" exist: - | user | course | role | - | student1 | C1 | student | - | student2 | C2 | student | - | teacher1 | C1 | editingteacher | - | teacher1 | C2 | editingteacher | - And the following "activities" exist: - | activity | course | idnumber | name | timeclose | - | quiz | C1 | Q1A | Quiz 1A No deadline | 0 | - | quiz | C1 | Q1B | Quiz 1B Past deadline | 1337 | - | quiz | C1 | Q1C | Quiz 1C Future deadline | 9000000000 | - | quiz | C1 | Q1D | Quiz 1D Future deadline | 9000000000 | - | quiz | C1 | Q1E | Quiz 1E Future deadline | 9000000000 | - | quiz | C2 | Q2A | Quiz 2A Future deadline | 9000000000 | - And the following "question categories" exist: - | contextlevel | reference | name | - | Course | C1 | Test questions | - And the following "questions" exist: - | qtype | name | questiontext | questioncategory | - | truefalse | First question | Answer the first question | Test questions | - And quiz "Quiz 1A No deadline" contains the following questions: - | question | page | - | First question | 1 | - And quiz "Quiz 1B Past deadline" contains the following questions: - | question | page | - | First question | 1 | - And quiz "Quiz 1C Future deadline" contains the following questions: - | question | page | - | First question | 1 | - And quiz "Quiz 1D Future deadline" contains the following questions: - | question | page | - | First question | 1 | - And quiz "Quiz 1E Future deadline" contains the following questions: - | question | page | - | First question | 1 | - And quiz "Quiz 2A Future deadline" contains the following questions: - | question | page | - | First question | 1 | - - Scenario: View my quizzes that are due - Given I log in as "student1" - When I am on homepage - Then I should see "You have quizzes that are due" in the "Course overview" "block" - And I should see "Quiz 1C Future deadline" in the "Course overview" "block" - And I should see "Quiz 1D Future deadline" in the "Course overview" "block" - And I should see "Quiz 1E Future deadline" in the "Course overview" "block" - And I should not see "Quiz 1A No deadline" in the "Course overview" "block" - And I should not see "Quiz 1B Past deadline" in the "Course overview" "block" - And I should not see "Quiz 2A Future deadline" in the "Course overview" "block" - And I log out - And I log in as "student2" - And I should see "You have quizzes that are due" in the "Course overview" "block" - And I should not see "Quiz 1C Future deadline" in the "Course overview" "block" - And I should not see "Quiz 1D Future deadline" in the "Course overview" "block" - And I should not see "Quiz 1E Future deadline" in the "Course overview" "block" - And I should not see "Quiz 1A No deadline" in the "Course overview" "block" - And I should not see "Quiz 1B Past deadline" in the "Course overview" "block" - And I should see "Quiz 2A Future deadline" in the "Course overview" "block" - - Scenario: View my quizzes that are due and never finished - Given I log in as "student1" - And I follow "Course 1" - And I follow "Quiz 1D Future deadline" - And I press "Attempt quiz now" - And I follow "Finish attempt ..." - And I press "Submit all and finish" - And I follow "Course 1" - And I follow "Quiz 1E Future deadline" - And I press "Attempt quiz now" - When I am on homepage - Then I should see "You have quizzes that are due" in the "Course overview" "block" - And I should see "Quiz 1C Future deadline" in the "Course overview" "block" - And I should see "Quiz 1E Future deadline" in the "Course overview" "block" - And I should not see "Quiz 1A No deadline" in the "Course overview" "block" - And I should not see "Quiz 1B Past deadline" in the "Course overview" "block" - And I should not see "Quiz 1D Future deadline" in the "Course overview" "block" - And I should not see "Quiz 2A Future deadline" in the "Course overview" "block" diff --git a/version.php b/version.php index 6b2e73e..54807cb 100644 --- a/version.php +++ b/version.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'block_course_overview'; -$plugin->version = 2017051200; -$plugin->requires = 2017042100; +$plugin->version = 2019021300; +$plugin->requires = 2017051500; $plugin->maturity = MATURITY_STABLE; -$plugin->release = '3.3.1'; +$plugin->release = '3.5.5';