From 3a37efa87fde22a12ead43d1c4f7cb7ef77b8fd8 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 20 Dec 2016 11:05:38 +0800 Subject: [PATCH 001/215] MDL-57436 block_myoverview: added infrastructure for new block Part of MDL-55611 epic. --- blocks/myoverview/block_myoverview.php | 68 +++++++++++++++++++ blocks/myoverview/db/access.php | 50 ++++++++++++++ .../myoverview/lang/en/block_myoverview.php | 27 ++++++++ blocks/myoverview/version.php | 29 ++++++++ 4 files changed, 174 insertions(+) create mode 100644 blocks/myoverview/block_myoverview.php create mode 100644 blocks/myoverview/db/access.php create mode 100644 blocks/myoverview/lang/en/block_myoverview.php create mode 100644 blocks/myoverview/version.php diff --git a/blocks/myoverview/block_myoverview.php b/blocks/myoverview/block_myoverview.php new file mode 100644 index 00000000000..92e7f8031f0 --- /dev/null +++ b/blocks/myoverview/block_myoverview.php @@ -0,0 +1,68 @@ +. + +/** + * Contains the class for the My overview block. + * + * @package block_myoverview + * @copyright Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * My overview block class. + * + * @package block_myoverview + * @copyright Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class block_myoverview extends block_base { + + /** + * Init. + */ + public function init() { + $this->title = get_string('pluginname', 'block_myoverview'); + } + + /** + * Returns the contents. + * + * @return stdClass contents of block + */ + public function get_content() { + if (isset($this->content)) { + return $this->content; + } + + $this->content = new stdClass(); + $this->content->text = ''; + $this->content->footer = ''; + + return $this->content; + } + + /** + * Locations where block can be displayed. + * + * @return array + */ + public function applicable_formats() { + return array('my' => true); + } +} diff --git a/blocks/myoverview/db/access.php b/blocks/myoverview/db/access.php new file mode 100644 index 00000000000..d05b432ded9 --- /dev/null +++ b/blocks/myoverview/db/access.php @@ -0,0 +1,50 @@ +. + +/** + * Capabilities for the My overview block. + * + * @package block_myoverview + * @copyright Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = array( + + 'block/myoverview:myaddinstance' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_SYSTEM, + 'archetypes' => array( + 'user' => CAP_ALLOW + ), + + 'clonepermissionsfrom' => 'moodle/my:manageblocks' + ), + + 'block/myoverview:addinstance' => array( + 'riskbitmask' => RISK_SPAM | RISK_XSS, + + 'captype' => 'write', + 'contextlevel' => CONTEXT_BLOCK, + 'archetypes' => array( + 'manager' => CAP_ALLOW + ), + + 'clonepermissionsfrom' => 'moodle/site:manageblocks' + ) +); diff --git a/blocks/myoverview/lang/en/block_myoverview.php b/blocks/myoverview/lang/en/block_myoverview.php new file mode 100644 index 00000000000..4af1ecc8dc2 --- /dev/null +++ b/blocks/myoverview/lang/en/block_myoverview.php @@ -0,0 +1,27 @@ +. + +/** + * Lang strings for the My overview block. + * + * @package block_myoverview + * @copyright Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['myoverview:addinstance'] = 'Add a new my overview block'; +$string['myoverview:myaddinstance'] = 'Add a new my overview block to Dashboard'; +$string['pluginname'] = 'My overview'; diff --git a/blocks/myoverview/version.php b/blocks/myoverview/version.php new file mode 100644 index 00000000000..682aeed95dc --- /dev/null +++ b/blocks/myoverview/version.php @@ -0,0 +1,29 @@ +. + +/** + * Version details for the My overview block. + * + * @package block_myoverview + * @copyright Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->version = 2016122000; // The current plugin version (Date: YYYYMMDDXX). +$plugin->requires = 2016112900; // Requires this Moodle version. +$plugin->component = 'block_myoverview'; // Full name of the plugin (used for diagnostics). From 1c69e1994da744975c7a73d0fbe812d77e3a0534 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 20 Dec 2016 11:16:24 +0800 Subject: [PATCH 002/215] MDL-57436 core: added 'myoverview' block to list of standard plugins Part of MDL-55611 epic. --- lib/classes/plugin_manager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/classes/plugin_manager.php b/lib/classes/plugin_manager.php index 5f54b5621ce..1a1f3fc7848 100644 --- a/lib/classes/plugin_manager.php +++ b/lib/classes/plugin_manager.php @@ -1714,7 +1714,7 @@ class core_plugin_manager { 'calendar_upcoming', 'comments', 'community', 'completionstatus', 'course_list', 'course_overview', 'course_summary', 'feedback', 'globalsearch', 'glossary_random', 'html', - 'login', 'lp', 'mentees', 'messages', 'mnet_hosts', 'myprofile', + 'login', 'lp', 'mentees', 'messages', 'mnet_hosts', 'myoverview', 'myprofile', 'navigation', 'news_items', 'online_users', 'participants', 'private_files', 'quiz_results', 'recent_activity', 'rss_client', 'search_forums', 'section_links', From 932f299bc0cf55c24a294d1d2fba7dde466e1a36 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 20 Dec 2016 16:42:43 +0800 Subject: [PATCH 003/215] MDL-57437 core: upgrade code for introduction of block_myoverview Part of MDL-55611 epic. --- lib/blocklib.php | 2 +- lib/db/upgrade.php | 10 ++++++++++ version.php | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/blocklib.php b/lib/blocklib.php index 296c55d4bba..f002c4ce7e3 100644 --- a/lib/blocklib.php +++ b/lib/blocklib.php @@ -2537,6 +2537,6 @@ function blocks_add_default_system_blocks() { } $newblocks = array('private_files', 'online_users', 'badges', 'calendar_month', 'calendar_upcoming'); - $newcontent = array('lp', 'course_overview'); + $newcontent = array('lp', 'myoverview'); $page->blocks->add_blocks(array(BLOCK_POS_RIGHT => $newblocks, 'content' => $newcontent), 'my-index', $subpagepattern); } diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 69ef988fa08..c86c6cb432e 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2611,5 +2611,15 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2017031400.00); } + if ($oldversion < 2017040300.04) { + + // If the 'Course overview' block is no longer present, replace with the 'My overview' block. + if (!file_exists($CFG->dirroot . '/blocks/course_overview/block_course_overview.php')) { + $DB->set_field('block_instances', 'blockname', 'myoverview', array('blockname' => 'course_overview')); + } + + upgrade_main_savepoint(true, 2017040300.04); + } + return true; } diff --git a/version.php b/version.php index f8fd9032855..9589ae0e0fb 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2017033100.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2017040300.04; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. From 4c5cde31346c8a95ffa04478ddccc1c0f33f75a4 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 20 Dec 2016 13:33:42 +0800 Subject: [PATCH 004/215] MDL-57433 block_course_overview: removed block from core Part of MDL-55611 epic. --- .../course_overview/block_course_overview.php | 128 ------- blocks/course_overview/db/access.php | 50 --- .../lang/en/block_course_overview.php | 67 ---- blocks/course_overview/locallib.php | 233 ------------ blocks/course_overview/module.js | 230 ------------ blocks/course_overview/move.php | 60 --- blocks/course_overview/renderer.php | 348 ------------------ blocks/course_overview/save.php | 34 -- blocks/course_overview/settings.php | 42 --- blocks/course_overview/styles.css | 87 ----- .../tests/behat/block_course_overview.feature | 162 -------- .../tests/behat/quiz_overview.feature | 93 ----- blocks/course_overview/version.php | 29 -- blocks/upgrade.txt | 2 + lib/classes/plugin_manager.php | 5 +- lib/db/upgrade.php | 18 + version.php | 2 +- 17 files changed, 24 insertions(+), 1566 deletions(-) delete mode 100644 blocks/course_overview/block_course_overview.php delete mode 100644 blocks/course_overview/db/access.php delete mode 100644 blocks/course_overview/lang/en/block_course_overview.php delete mode 100644 blocks/course_overview/locallib.php delete mode 100644 blocks/course_overview/module.js delete mode 100644 blocks/course_overview/move.php delete mode 100644 blocks/course_overview/renderer.php delete mode 100644 blocks/course_overview/save.php delete mode 100644 blocks/course_overview/settings.php delete mode 100644 blocks/course_overview/styles.css delete mode 100644 blocks/course_overview/tests/behat/block_course_overview.feature delete mode 100644 blocks/course_overview/tests/behat/quiz_overview.feature delete mode 100644 blocks/course_overview/version.php diff --git a/blocks/course_overview/block_course_overview.php b/blocks/course_overview/block_course_overview.php deleted file mode 100644 index ae244ef1082..00000000000 --- a/blocks/course_overview/block_course_overview.php +++ /dev/null @@ -1,128 +0,0 @@ -. - -/** - * Course overview block - * - * @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 - */ -require_once($CFG->dirroot.'/blocks/course_overview/locallib.php'); - -/** - * Course overview block - * - * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com) - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class block_course_overview extends block_base { - /** - * If this is passed as mynumber then showallcourses, irrespective of limit by user. - */ - const SHOW_ALL_COURSES = -2; - - /** - * Block initialization - */ - public function init() { - $this->title = get_string('pluginname', 'block_course_overview'); - } - - /** - * Return contents of course_overview block - * - * @return stdClass contents of block - */ - public function get_content() { - global $USER, $CFG, $DB; - require_once($CFG->dirroot.'/user/profile/lib.php'); - - if($this->content !== NULL) { - return $this->content; - } - - $config = get_config('block_course_overview'); - - $this->content = new stdClass(); - $this->content->text = ''; - $this->content->footer = ''; - - $content = array(); - - $updatemynumber = optional_param('mynumber', -1, PARAM_INT); - if ($updatemynumber >= 0) { - block_course_overview_update_mynumber($updatemynumber); - } - - 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); - - $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); - } - - // Number of sites to display. - if ($this->page->user_is_editing() && empty($config->forcedefaultmaxcourses)) { - $this->content->text .= $renderer->editing_bar_head($totalcourses); - } - - if (empty($sortedcourses)) { - $this->content->text .= get_string('nocourses','my'); - } else { - // For each course, build category cache. - $this->content->text .= $renderer->course_overview($sortedcourses, $overviews); - $this->content->text .= $renderer->hidden_courses($totalcourses - count($sortedcourses)); - } - - return $this->content; - } - - /** - * Allow the block to have a configuration page - * - * @return boolean - */ - public function has_config() { - return true; - } - - /** - * Locations where block can be displayed - * - * @return array - */ - public function applicable_formats() { - return array('my' => true); - } - - /** - * 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'); - return !empty($config->showwelcomearea); - } -} diff --git a/blocks/course_overview/db/access.php b/blocks/course_overview/db/access.php deleted file mode 100644 index 95abb630e64..00000000000 --- a/blocks/course_overview/db/access.php +++ /dev/null @@ -1,50 +0,0 @@ -. - -/** - * Course overview block caps. - * - * @package block_course_overview - * @copyright Mark Nelson - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$capabilities = array( - - 'block/course_overview:myaddinstance' => array( - 'captype' => 'write', - 'contextlevel' => CONTEXT_SYSTEM, - 'archetypes' => array( - 'user' => CAP_ALLOW - ), - - 'clonepermissionsfrom' => 'moodle/my:manageblocks' - ), - - 'block/course_overview:addinstance' => array( - 'riskbitmask' => RISK_SPAM | RISK_XSS, - - 'captype' => 'write', - 'contextlevel' => CONTEXT_BLOCK, - 'archetypes' => array( - 'manager' => CAP_ALLOW - ), - - 'clonepermissionsfrom' => 'moodle/site:manageblocks' - ) -); diff --git a/blocks/course_overview/lang/en/block_course_overview.php b/blocks/course_overview/lang/en/block_course_overview.php deleted file mode 100644 index d92f3dfdb05..00000000000 --- a/blocks/course_overview/lang/en/block_course_overview.php +++ /dev/null @@ -1,67 +0,0 @@ -. - -/** - * Lang strings 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 - */ - -$string['activityoverview'] = 'You have {$a}s that need attention'; -$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['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['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['message'] = 'message'; -$string['messages'] = 'messages'; -$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['none'] = 'None'; -$string['numtodisplay'] = 'Number of courses to display: '; -$string['onlyparentname'] = 'Parent category only'; -$string['otherexpanded'] = 'Other courses expanded'; -$string['pluginname'] = 'Course overview'; -$string['preservestates'] = 'Preserve expanded states'; -$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['view_edit_profile'] = '(View and edit your profile.)'; -$string['welcome'] = 'Welcome {$a}'; -$string['youhavemessages'] = 'You have {$a} unread '; -$string['youhavenomessages'] = 'You have no unread '; diff --git a/blocks/course_overview/locallib.php b/blocks/course_overview/locallib.php deleted file mode 100644 index 06e6896ce3d..00000000000 --- a/blocks/course_overview/locallib.php +++ /dev/null @@ -1,233 +0,0 @@ -. - -/** - * Helper functions 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 - */ - -define('BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_NONE', '0'); -define('BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_ONLY_PARENT_NAME', '1'); -define('BLOCKS_COURSE_OVERVIEW_SHOWCATEGORIES_FULL_PATH', '2'); - -/** - * Display overview for courses - * - * @param array $courses courses for which overview needs to be shown - * @return array html overview - */ -function block_course_overview_get_overviews($courses) { - $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. - if (defined('MAX_MODINFO_CACHE_SIZE') && MAX_MODINFO_CACHE_SIZE > 0 && count($courses) > MAX_MODINFO_CACHE_SIZE) { - $batches = array_chunk($courses, MAX_MODINFO_CACHE_SIZE, true); - } else { - $batches = array($courses); - } - foreach ($batches as $courses) { - foreach ($modules as $fname) { - $fname($courses, $htmlarray); - } - } - } - return $htmlarray; -} - -/** - * Sets user preference for maximum courses to be displayed in course_overview block - * - * @param int $number maximum courses which should be visible - */ -function block_course_overview_update_mynumber($number) { - set_user_preference('course_overview_number_of_courses', $number); -} - -/** - * Sets user course sorting preference in course_overview block - * - * @param array $sortorder list of course ids - */ -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). - $value = preg_replace('/,[\d]*$/', '', core_text::substr($value, 0, 1334)); - } - set_user_preference('course_overview_course_sortorder', $value); -} - -/** - * Gets user course sorting preference in course_overview block - * - * @return array list of course ids - */ -function block_course_overview_get_myorder() { - if ($value = get_user_preferences('course_overview_course_sortorder')) { - return explode(',', $value); - } - // If preference was not found, look in the old location and convert if found. - $order = array(); - if ($value = get_user_preferences('course_overview_course_order')) { - $order = unserialize_array($value); - block_course_overview_update_myorder($order); - unset_user_preference('course_overview_course_order'); - } - return $order; -} - -/** - * 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_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; - } - - return isset($shortnames) ? $shortnames : false; -} - -/** - * Returns maximum number of courses which will be displayed in course_overview block - * - * @param bool $showallcourses if set true all courses will be visible. - * @return int maximum number of courses - */ -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); - } - } - return $limit; -} - -/** - * Return sorted list of user courses - * - * @param bool $showallcourses if set true all courses will be visible. - * @return array list of sorted courses and count of courses. - */ -function block_course_overview_get_sorted_courses($showallcourses = false) { - global $USER; - - $limit = block_course_overview_get_max_user_courses($showallcourses); - - $courses = enrol_get_my_courses(); - $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; - } - } - - // 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(); - - $sortedcourses = array(); - $counter = 0; - // Get courses in sort order into list. - foreach ($order as $key => $cid) { - if (($counter >= $limit) && ($limit != 0)) { - break; - } - - // Make sure user is still enroled. - if (isset($courses[$cid])) { - $sortedcourses[$cid] = $courses[$cid]; - $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++; - } - } - - // 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)); -} diff --git a/blocks/course_overview/module.js b/blocks/course_overview/module.js deleted file mode 100644 index e900df806fe..00000000000 --- a/blocks/course_overview/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/blocks/course_overview/move.php b/blocks/course_overview/move.php deleted file mode 100644 index b6f042dd7a1..00000000000 --- a/blocks/course_overview/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/blocks/course_overview/renderer.php b/blocks/course_overview/renderer.php deleted file mode 100644 index 78c8b0ef33a..00000000000 --- a/blocks/course_overview/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'); - $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/blocks/course_overview/save.php b/blocks/course_overview/save.php deleted file mode 100644 index b4bb175bfa5..00000000000 --- a/blocks/course_overview/save.php +++ /dev/null @@ -1,34 +0,0 @@ -. - -/** - * Save course order in course_overview block - * - * @package block_course_overview - * @copyright 2012 Adam Olley - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -define('AJAX_SCRIPT', true); - -require_once(__DIR__ . '/../../config.php'); -require_once(__DIR__ . '/locallib.php'); - -require_sesskey(); -require_login(); - -$sortorder = required_param_array('sortorder', PARAM_INT); - -block_course_overview_update_myorder($sortorder); diff --git a/blocks/course_overview/settings.php b/blocks/course_overview/settings.php deleted file mode 100644 index d1c42758135..00000000000 --- a/blocks/course_overview/settings.php +++ /dev/null @@ -1,42 +0,0 @@ -. - -/** - * course_overview block settings - * - * @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; - -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)); -} diff --git a/blocks/course_overview/styles.css b/blocks/course_overview/styles.css deleted file mode 100644 index 2aab2a35d06..00000000000 --- a/blocks/course_overview/styles.css +++ /dev/null @@ -1,87 +0,0 @@ -.block_course_overview .coursechildren { - font-weight: normal; - font-style: italic; -} - -.block_course_overview .categorypath { - text-align: right; -} - -.block_course_overview .content { - margin: 0 20px; -} - -.block_course_overview .content .notice { - margin: 5px 0; -} - -.block_course_overview .coursebox { - padding: 15px; - width: auto; -} - -.block_course_overview .profilepicture { - float: left; -} - -.block_course_overview .welcome_area { - width: 100%; - padding-bottom: 5px; -} - -.block_course_overview .welcome_message { - float: left; - padding: 10px; - border-collapse: separate; - clear: none; -} - -.block_course_overview .content h2.title { - float: left; - margin: 0 0 .5em 0; - position: relative; -} - -.block_course_overview .course_title { - position: relative; -} - -.editing .block_course_overview .coursebox .cursor { - cursor: move; - margin-bottom: 2px; -} - -.editing .block_course_overview .move { - float: left; - padding: 2px 10px 0 0; -} - -.block_course_overview .course_list { - width: 100%; -} - -.block_course_overview div.flush { - clear: both; -} - -.block_course_overview .activity_info { - clear: both; -} - -.block_course_overview .activity_overview { - padding: 2px; -} - -.block_course_overview .activity_overview img.iconlarge { - vertical-align: text-bottom; - margin-right: 6px; -} - -.block_course_overview .singleselect { - text-align: left; - margin: 0; -} - -.block_course_overview .content .course_list .movehere { - margin-bottom: 15px; -} diff --git a/blocks/course_overview/tests/behat/block_course_overview.feature b/blocks/course_overview/tests/behat/block_course_overview.feature deleted file mode 100644 index 389b6c5353b..00000000000 --- a/blocks/course_overview/tests/behat/block_course_overview.feature +++ /dev/null @@ -1,162 +0,0 @@ -@block @block_course_overview -Feature: View the course overview block on the dashboard and test it's functionality - In order to view the course overview block on the dashboard - As an admin - I can configure the course overview block - - 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 the following "courses" exist: - | fullname | shortname | category | - | 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" - - Scenario: View the block by a user with several enrolments - Given the following "course enrolments" exist: - | user | course | role | - | 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" - - @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 | - 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 "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" - - Scenario: View the block by a user with the full categories displayed. - Given the following config values are set as admin: - | showcategories | 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 "Miscellaneous" in the "Course overview" "block" - And I should see "Category 1 / Category 2" in the "Course overview" "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/blocks/course_overview/tests/behat/quiz_overview.feature b/blocks/course_overview/tests/behat/quiz_overview.feature deleted file mode 100644 index c91c551fcf1..00000000000 --- a/blocks/course_overview/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/blocks/course_overview/version.php b/blocks/course_overview/version.php deleted file mode 100644 index dec7d909c67..00000000000 --- a/blocks/course_overview/version.php +++ /dev/null @@ -1,29 +0,0 @@ -. - -/** - * Version details - * - * @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(); - -$plugin->version = 2016120500; // The current plugin version (Date: YYYYMMDDXX) -$plugin->requires = 2016112900; // Requires this Moodle version -$plugin->component = 'block_course_overview'; // Full name of the plugin (used for diagnostics) diff --git a/blocks/upgrade.txt b/blocks/upgrade.txt index e0de186a947..bff229dd2f7 100644 --- a/blocks/upgrade.txt +++ b/blocks/upgrade.txt @@ -4,6 +4,8 @@ information provided here is intended especially for developers. === 3.3 === * block_manager::get_required_by_theme_block_types() is no longer static. +* The 'Course overview' block has been removed from core as it is being replaced by the 'My overview' block. + The 'Course overview' block will be available in the plugins database. === 3.1 === diff --git a/lib/classes/plugin_manager.php b/lib/classes/plugin_manager.php index 1a1f3fc7848..d50e04fada7 100644 --- a/lib/classes/plugin_manager.php +++ b/lib/classes/plugin_manager.php @@ -1647,6 +1647,7 @@ class core_plugin_manager { $plugins = array( 'qformat' => array('blackboard', 'learnwise'), 'auth' => array('radius'), + 'block' => array('course_overview'), 'enrol' => array('authorize'), 'report' => array('search'), 'repository' => array('alfresco'), @@ -1712,8 +1713,8 @@ class core_plugin_manager { 'activity_modules', 'activity_results', 'admin_bookmarks', 'badges', 'blog_menu', 'blog_recent', 'blog_tags', 'calendar_month', 'calendar_upcoming', 'comments', 'community', - 'completionstatus', 'course_list', 'course_overview', - 'course_summary', 'feedback', 'globalsearch', 'glossary_random', 'html', + 'completionstatus', 'course_list', 'course_summary', + 'feedback', 'globalsearch', 'glossary_random', 'html', 'login', 'lp', 'mentees', 'messages', 'mnet_hosts', 'myoverview', 'myprofile', 'navigation', 'news_items', 'online_users', 'participants', 'private_files', 'quiz_results', 'recent_activity', diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index c86c6cb432e..678b86b9693 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2621,5 +2621,23 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2017040300.04); } + if ($oldversion < 2017040300.05) { + + // If the 'Course overview' block is no longer present, remove it. + // Note - we do not need to completely remove the block context etc because we + // have replaced all occurrences of the 'Course overview' block with the 'My overview' + // block in the upgrade step above. + if (!file_exists($CFG->dirroot . '/blocks/course_overview/block_course_overview.php')) { + // Delete the block from the block table. + $DB->delete_records('block', array('name' => 'course_overview')); + // Remove capabilities. + capabilities_cleanup('block_course_overview'); + // Clean config. + unset_all_config_for_plugin('block_course_overview'); + } + + upgrade_main_savepoint(true, 2017040300.05); + } + return true; } diff --git a/version.php b/version.php index 9589ae0e0fb..75869935df8 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2017040300.04; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2017040300.05; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. From e9dfeec94e8e9c956fa0036f62a81b1ee40b0ed6 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 21 Dec 2016 16:51:41 +0800 Subject: [PATCH 005/215] MDL-57434 core: deprecated xxx_print_overview() and related functions Part of MDL-55611 epic. --- course/externallib.php | 15 +++++++++++++++ course/tests/externallib_test.php | 1 + lib/db/services.php | 3 ++- lib/upgrade.txt | 1 + mod/assign/lib.php | 14 +++++++++++++- mod/assign/tests/lib_test.php | 7 +++++++ mod/chat/lib.php | 4 ++++ mod/choice/lib.php | 5 +++++ mod/forum/lib.php | 8 ++++++++ mod/forum/tests/lib_test.php | 6 ++++++ mod/lesson/lib.php | 4 ++++ mod/quiz/lib.php | 6 ++++++ mod/scorm/lib.php | 4 ++++ 13 files changed, 76 insertions(+), 2 deletions(-) diff --git a/course/externallib.php b/course/externallib.php index 73370acc2db..802cfd2fee5 100644 --- a/course/externallib.php +++ b/course/externallib.php @@ -2654,6 +2654,8 @@ class core_course_external extends external_api { /** * Returns description of method parameters * + * @deprecated since 3.3 + * * @return external_function_parameters * @since Moodle 3.2 */ @@ -2668,6 +2670,8 @@ class core_course_external extends external_api { /** * Return activities overview for the given courses. * + * @deprecated since 3.3 + * * @param array $courseids a list of course ids * @return array of warnings and the activities overview * @since Moodle 3.2 @@ -2725,6 +2729,8 @@ class core_course_external extends external_api { /** * Returns description of method result value * + * @deprecated since 3.3 + * * @return external_description * @since Moodle 3.2 */ @@ -2751,6 +2757,15 @@ class core_course_external extends external_api { ); } + /** + * Marking the method as deprecated. + * + * @return bool + */ + public static function get_activities_overview_is_deprecated() { + return true; + } + /** * Returns description of method parameters * diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php index 9616ca2bf15..83f56997cf4 100644 --- a/course/tests/externallib_test.php +++ b/course/tests/externallib_test.php @@ -1823,6 +1823,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase { $courses = array($course1->id , $course2->id); $result = core_course_external::get_activities_overview($courses); + $this->assertDebuggingCalledCount(8); $result = external_api::clean_returnvalue(core_course_external::get_activities_overview_returns(), $result); // There should be one entry for course1, and no others. diff --git a/lib/db/services.php b/lib/db/services.php index 5ff30cdef28..7db4633dadd 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -330,7 +330,8 @@ $functions = array( 'classname' => 'core_course_external', 'methodname' => 'get_activities_overview', 'classpath' => 'course/externallib.php', - 'description' => 'Return activities overview for the given courses.', + 'description' => '** DEPRECATED ** Please do not call this function any more. + Return activities overview for the given courses.', 'type' => 'read', 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), ), diff --git a/lib/upgrade.txt b/lib/upgrade.txt index 1f7edcfdb01..afacc0b0cb7 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -68,6 +68,7 @@ information provided here is intended especially for developers. * New adhoc task refresh_mod_calendar_events_task that updates existing calendar events of modules. * New 'priority' column for the event table to determine which event to show in case of events with user and group overrides. * Webservices core_course_search_courses and core_course_get_courses_by_field will always return the sortorder field. +* core_course_external::get_activities_overview has been deprecated. Please do not call this function any more. === 3.2 === diff --git a/mod/assign/lib.php b/mod/assign/lib.php index 7852c4024b9..6fefd9efdf6 100644 --- a/mod/assign/lib.php +++ b/mod/assign/lib.php @@ -484,14 +484,17 @@ function assign_page_type_list($pagetype, $parentcontext, $currentcontext) { * Print an overview of all assignments * for the courses. * + * @deprecated since 3.3 + * * @param mixed $courses The list of courses to print the overview for * @param array $htmlarray The array of html to return - * * @return true */ function assign_print_overview($courses, &$htmlarray) { global $CFG, $DB; + debugging('The function assign_print_overview() is now deprecated.', DEBUG_DEVELOPER); + if (empty($courses) || !is_array($courses) || count($courses) == 0) { return true; } @@ -624,6 +627,8 @@ function assign_print_overview($courses, &$htmlarray) { * This api generates html to be displayed to students in print overview section, related to their submission status of the given * assignment. * + * @deprecated since 3.3 + * * @param array $mysubmissions list of submissions of current user indexed by assignment id. * @param string $sqlassignmentids sql clause used to filter open assignments. * @param array $assignmentidparams sql params used to filter open assignments. @@ -636,6 +641,8 @@ function assign_get_mysubmission_details_for_print_overview(&$mysubmissions, $sq $assignment) { global $USER, $DB; + debugging('The function assign_get_mysubmission_details_for_print_overview() is now deprecated.', DEBUG_DEVELOPER); + if ($assignment->nosubmissions) { // Offline assignment. No need to display alerts for offline assignments. return false; @@ -710,6 +717,8 @@ function assign_get_mysubmission_details_for_print_overview(&$mysubmissions, $sq * This api generates html to be displayed to teachers in print overview section, related to the grading status of the given * assignment's submissions. * + * @deprecated since 3.3 + * * @param array $unmarkedsubmissions list of submissions of that are currently unmarked indexed by assignment id. * @param string $sqlassignmentids sql clause used to filter open assignments. * @param array $assignmentidparams sql params used to filter open assignments. @@ -722,6 +731,9 @@ function assign_get_mysubmission_details_for_print_overview(&$mysubmissions, $sq function assign_get_grade_details_for_print_overview(&$unmarkedsubmissions, $sqlassignmentids, $assignmentidparams, $assignment, $context) { global $DB; + + debugging('The function assign_get_grade_details_for_print_overview() is now deprecated.', DEBUG_DEVELOPER); + if (!isset($unmarkedsubmissions)) { // Build up and array of unmarked submissions indexed by assignment id/ userid // for use where the user has grading rights on assignment. diff --git a/mod/assign/tests/lib_test.php b/mod/assign/tests/lib_test.php index 7ef88c2885f..a67160203c5 100644 --- a/mod/assign/tests/lib_test.php +++ b/mod/assign/tests/lib_test.php @@ -125,6 +125,7 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase { $this->setUser($this->students[0]); $overview = array(); assign_print_overview($courses, $overview); + $this->assertDebuggingCalledCount(3); $this->assertEquals(1, count($overview)); $this->assertRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']); // No valid submission. $this->assertNotRegExp('/.*Assignment 1.*/', $overview[$this->course->id]['assign']); // Has valid submission. @@ -135,11 +136,13 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase { $overview = array(); assign_print_overview($courses, $overview); + $this->assertDebuggingCalledCount(3); $this->assertEquals(0, count($overview)); $this->setUser($this->teachers[0]); $overview = array(); assign_print_overview($courses, $overview); + $this->assertDebuggingCalledCount(3); $this->assertEquals(1, count($overview)); // Submissions without a grade. $this->assertRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']); @@ -148,6 +151,7 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase { $this->setUser($this->editingteachers[0]); $overview = array(); assign_print_overview($courses, $overview); + $this->assertDebuggingCalledCount(3); $this->assertEquals(1, count($overview)); // Submissions without a grade. $this->assertRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']); @@ -167,6 +171,7 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase { $overview = array(); assign_print_overview($courses, $overview); + $this->assertDebuggingCalledCount(3); $this->assertEquals(1, count($overview)); // Now assignment 4 should not show up. $this->assertNotRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']); @@ -175,6 +180,7 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase { $this->setUser($this->editingteachers[0]); $overview = array(); assign_print_overview($courses, $overview); + $this->assertDebuggingCalledCount(3); $this->assertEquals(1, count($overview)); // Now assignment 4 should not show up. $this->assertNotRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']); @@ -186,6 +192,7 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase { $this->setUser($this->students[0]); $overview = array(); assign_print_overview($courses, $overview); + $this->assertDebuggingCalledCount(4); $this->assertEquals(0, count($overview)); } diff --git a/mod/chat/lib.php b/mod/chat/lib.php index cedafaa93c6..7b9e3795e81 100644 --- a/mod/chat/lib.php +++ b/mod/chat/lib.php @@ -1119,6 +1119,8 @@ function chat_get_post_actions() { } /** + * @deprecated since 3.3 + * * @global object * @global object * @param array $courses @@ -1127,6 +1129,8 @@ function chat_get_post_actions() { function chat_print_overview($courses, &$htmlarray) { global $USER, $CFG; + debugging('The function chat_print_overview() is now deprecated.', DEBUG_DEVELOPER); + if (empty($courses) || !is_array($courses) || count($courses) == 0) { return array(); } diff --git a/mod/choice/lib.php b/mod/choice/lib.php index d3020dbf8f5..30cb2f5360d 100644 --- a/mod/choice/lib.php +++ b/mod/choice/lib.php @@ -918,6 +918,9 @@ function choice_page_type_list($pagetype, $parentcontext, $currentcontext) { * Prints choice name, due date and attempt information on * choice activities that have a deadline that has not already passed * and it is available for completing. + * + * @deprecated since 3.3 + * * @uses CONTEXT_MODULE * @param array $courses An array of course objects to get choice instances from. * @param array $htmlarray Store overview output array( course ID => 'choice' => HTML output ) @@ -925,6 +928,8 @@ function choice_page_type_list($pagetype, $parentcontext, $currentcontext) { function choice_print_overview($courses, &$htmlarray) { global $USER, $DB, $OUTPUT; + debugging('The function choice_print_overview() is now deprecated.', DEBUG_DEVELOPER); + if (empty($courses) || !is_array($courses) || count($courses) == 0) { return; } diff --git a/mod/forum/lib.php b/mod/forum/lib.php index 8c5ec559005..e26deede178 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -1323,12 +1323,16 @@ function forum_user_complete($course, $user, $mod, $forum) { /** * Filters the forum discussions according to groups membership and config. * + * @deprecated since 3.3 + * * @since Moodle 2.8, 2.7.1, 2.6.4 * @param array $discussions Discussions with new posts array * @return array Forums with the number of new posts */ function forum_filter_user_groups_discussions($discussions) { + debugging('The function forum_filter_user_groups_discussions() is now deprecated.', DEBUG_DEVELOPER); + // Group the remaining discussions posts by their forumid. $filteredforums = array(); @@ -1384,6 +1388,8 @@ function forum_is_user_group_discussion(cm_info $cm, $discussiongroupid) { } /** + * @deprecated since 3.3 + * * @global object * @global object * @global object @@ -1393,6 +1399,8 @@ function forum_is_user_group_discussion(cm_info $cm, $discussiongroupid) { function forum_print_overview($courses,&$htmlarray) { global $USER, $CFG, $DB, $SESSION; + debugging('The function forum_print_overview() is now deprecated.', DEBUG_DEVELOPER); + if (empty($courses) || !is_array($courses) || count($courses) == 0) { return array(); } diff --git a/mod/forum/tests/lib_test.php b/mod/forum/tests/lib_test.php index 72c1526059a..88eccabd7c7 100644 --- a/mod/forum/tests/lib_test.php +++ b/mod/forum/tests/lib_test.php @@ -2448,6 +2448,7 @@ class mod_forum_lib_testcase extends advanced_testcase { } $results = array(); forum_print_overview($courses, $results); + $this->assertDebuggingCalledCount(2); // There should be one entry for course1, and no others. $this->assertCount(1, $results); @@ -2499,6 +2500,7 @@ class mod_forum_lib_testcase extends advanced_testcase { $this->setUser($viewer1->id); $results = array(); forum_print_overview($courses, $results); + $this->assertDebuggingCalledCount(2); // There should be one entry for course1. $this->assertCount(1, $results); @@ -2510,6 +2512,7 @@ class mod_forum_lib_testcase extends advanced_testcase { $this->setUser($viewer2->id); $results = array(); forum_print_overview($courses, $results); + $this->assertDebuggingCalledCount(2); // There should be one entry for course1. $this->assertCount(0, $results); @@ -2555,6 +2558,7 @@ class mod_forum_lib_testcase extends advanced_testcase { $this->setUser($viewer->id); $results = array(); forum_print_overview($courses, $results); + $this->assertDebuggingCalledCount(2); if ($hasresult) { // There should be one entry for course1. @@ -2620,6 +2624,7 @@ class mod_forum_lib_testcase extends advanced_testcase { $this->setUser($viewer1->id); $results = array(); forum_print_overview($courses, $results); + $this->assertDebuggingCalledCount(2); if ($hasresult) { // There should be one entry for course1. @@ -2636,6 +2641,7 @@ class mod_forum_lib_testcase extends advanced_testcase { $this->setUser($viewer2->id); $results = array(); forum_print_overview($courses, $results); + $this->assertDebuggingCalledCount(2); // There should be one entry for course1. $this->assertCount(0, $results); diff --git a/mod/lesson/lib.php b/mod/lesson/lib.php index 8f7526e9ed1..687db47d738 100644 --- a/mod/lesson/lib.php +++ b/mod/lesson/lib.php @@ -527,6 +527,8 @@ function lesson_user_complete($course, $user, $mod, $lesson) { * lessons that have a deadline that has not already passed * and it is available for taking. * + * @deprecated since 3.3 + * * @global object * @global stdClass * @global object @@ -538,6 +540,8 @@ function lesson_user_complete($course, $user, $mod, $lesson) { function lesson_print_overview($courses, &$htmlarray) { global $USER, $CFG, $DB, $OUTPUT; + debugging('The function lesson_print_overview() is now deprecated.', DEBUG_DEVELOPER); + if (!$lessons = get_all_instances_in_courses('lesson', $courses)) { return; } diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php index b91c369719e..c644febdef0 100644 --- a/mod/quiz/lib.php +++ b/mod/quiz/lib.php @@ -1543,11 +1543,17 @@ function quiz_reset_userdata($data) { /** * Prints quiz summaries on MyMoodle Page + * + * @deprecated since 3.3 + * * @param arry $courses * @param array $htmlarray */ function quiz_print_overview($courses, &$htmlarray) { global $USER, $CFG; + + debugging('The function quiz_print_overview() is now deprecated.', DEBUG_DEVELOPER); + // These next 6 Lines are constant in all modules (just change module name). if (empty($courses) || !is_array($courses) || count($courses) == 0) { return array(); diff --git a/mod/scorm/lib.php b/mod/scorm/lib.php index b5a5bd09ccf..d4ff57ee15a 100644 --- a/mod/scorm/lib.php +++ b/mod/scorm/lib.php @@ -1088,6 +1088,8 @@ function scorm_debug_log_remove($type, $scoid) { /** * writes overview info for course_overview block - displays upcoming scorm objects that have a due date * + * @deprecated since 3.3 + * * @param object $type - type of log(aicc,scorm12,scorm13) used as prefix for filename * @param array $htmlarray * @return mixed @@ -1095,6 +1097,8 @@ function scorm_debug_log_remove($type, $scoid) { function scorm_print_overview($courses, &$htmlarray) { global $USER, $CFG; + debugging('The function scorm_print_overview() is now deprecated.', DEBUG_DEVELOPER); + if (empty($courses) || !is_array($courses) || count($courses) == 0) { return array(); } From e057f279e4760bece705428b71f2c25ea2f4bb03 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 23 Dec 2016 11:31:06 +0800 Subject: [PATCH 006/215] MDL-57497 core_calendar: added new calendar event class Moved calendar_event class to new location using replaceclasses.php Part of MDL-55611 epic. --- calendar/classes/event.php | 813 ++++++++++++++++++++++++++++ calendar/classes/rrule_manager.php | 7 +- calendar/delete.php | 2 +- calendar/event.php | 4 +- calendar/externallib.php | 8 +- calendar/lib.php | 798 +-------------------------- calendar/renderer.php | 13 +- calendar/tests/externallib_test.php | 2 +- calendar/tests/lib_test.php | 2 +- course/lib.php | 6 +- course/tests/courselib_test.php | 2 +- lib/db/renamedclasses.php | 4 +- lib/deprecatedlib.php | 20 +- lib/upgrade.txt | 1 + mod/assign/lib.php | 4 +- mod/assign/locallib.php | 6 +- mod/chat/lib.php | 14 +- mod/choice/locallib.php | 12 +- mod/data/lib.php | 2 +- mod/data/locallib.php | 12 +- mod/feedback/lib.php | 12 +- mod/lesson/lib.php | 8 +- mod/lesson/locallib.php | 4 +- mod/quiz/lib.php | 10 +- mod/workshop/lib.php | 12 +- 25 files changed, 901 insertions(+), 877 deletions(-) create mode 100644 calendar/classes/event.php diff --git a/calendar/classes/event.php b/calendar/classes/event.php new file mode 100644 index 00000000000..e3cb643a5d4 --- /dev/null +++ b/calendar/classes/event.php @@ -0,0 +1,813 @@ +. + +/** + * Contains the class for the calendar events. + * + * @package core_calendar + * @copyright 2016 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_calendar; + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/calendar/lib.php'); + +/** + * The class for the calendar events. + * + * @package core_calendar + * @copyright 2016 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class event { + + /** @var array An object containing the event properties can be accessed via the magic __get/set methods */ + protected $properties = null; + + /** @var string The converted event discription with file paths resolved. + * This gets populated when someone requests description for the first time */ + protected $_description = null; + + /** @var array The options to use with this description editor */ + protected $editoroptions = array( + 'subdirs' => false, + 'forcehttps' => false, + 'maxfiles' => -1, + 'maxbytes' => null, + 'trusttext' => false); + + /** @var object The context to use with the description editor */ + protected $editorcontext = null; + + /** + * Instantiates a new event and optionally populates its properties with the data provided. + * + * @param \stdClass $data Optional. An object containing the properties to for + * an event + */ + public function __construct($data = null) { + global $CFG, $USER; + + // First convert to object if it is not already (should either be object or assoc array). + if (!is_object($data)) { + $data = (object) $data; + } + + $this->editoroptions['maxbytes'] = $CFG->maxbytes; + + $data->eventrepeats = 0; + + if (empty($data->id)) { + $data->id = null; + } + + if (!empty($data->subscriptionid)) { + $data->subscription = calendar_get_subscription($data->subscriptionid); + } + + // Default to a user event. + if (empty($data->eventtype)) { + $data->eventtype = 'user'; + } + + // Default to the current user. + if (empty($data->userid)) { + $data->userid = $USER->id; + } + + if (!empty($data->timeduration) && is_array($data->timeduration)) { + $data->timeduration = make_timestamp( + $data->timeduration['year'], $data->timeduration['month'], $data->timeduration['day'], + $data->timeduration['hour'], $data->timeduration['minute']) - $data->timestart; + } + + if (!empty($data->description) && is_array($data->description)) { + $data->format = $data->description['format']; + $data->description = $data->description['text']; + } else if (empty($data->description)) { + $data->description = ''; + $data->format = editors_get_preferred_format(); + } + + // Ensure form is defaulted correctly. + if (empty($data->format)) { + $data->format = editors_get_preferred_format(); + } + + $this->properties = $data; + + if (empty($data->context)) { + $this->properties->context = $this->calculate_context(); + } + } + + /** + * Magic set method. + * + * Attempts to call a set_$key method if one exists otherwise falls back + * to simply set the property. + * + * @param string $key property name + * @param mixed $value value of the property + */ + public function __set($key, $value) { + if (method_exists($this, 'set_'.$key)) { + $this->{'set_'.$key}($value); + } + $this->properties->{$key} = $value; + } + + /** + * Magic get method. + * + * Attempts to call a get_$key method to return the property and ralls over + * to return the raw property. + * + * @param string $key property name + * @return mixed property value + * @throws \coding_exception + */ + public function __get($key) { + if (method_exists($this, 'get_'.$key)) { + return $this->{'get_'.$key}(); + } + if (!isset($this->properties->{$key})) { + throw new \coding_exception('Undefined property requested'); + } + return $this->properties->{$key}; + } + + /** + * Magic isset method. + * + * PHP needs an isset magic method if you use the get magic method and + * still want empty calls to work. + * + * @param string $key $key property name + * @return bool|mixed property value, false if property is not exist + */ + public function __isset($key) { + return !empty($this->properties->{$key}); + } + + /** + * Calculate the context value needed for an event. + * + * Event's type can be determine by the available value store in $data + * It is important to check for the existence of course/courseid to determine + * the course event. + * Default value is set to CONTEXT_USER + * + * @return \stdClass The context object. + */ + protected function calculate_context() { + global $USER, $DB; + + $context = null; + if (isset($this->properties->courseid) && $this->properties->courseid > 0) { + $context = \context_course::instance($this->properties->courseid); + } else if (isset($this->properties->course) && $this->properties->course > 0) { + $context = \context_course::instance($this->properties->course); + } else if (isset($this->properties->groupid) && $this->properties->groupid > 0) { + $group = $DB->get_record('groups', array('id' => $this->properties->groupid)); + $context = \context_course::instance($group->courseid); + } else if (isset($this->properties->userid) && $this->properties->userid > 0 + && $this->properties->userid == $USER->id) { + $context = \context_user::instance($this->properties->userid); + } else if (isset($this->properties->userid) && $this->properties->userid > 0 + && $this->properties->userid != $USER->id && + isset($this->properties->instance) && $this->properties->instance > 0) { + $cm = get_coursemodule_from_instance($this->properties->modulename, $this->properties->instance, 0, + false, MUST_EXIST); + $context = \context_course::instance($cm->course); + } else { + $context = \context_user::instance($this->properties->userid); + } + + return $context; + } + + /** + * Returns an array of editoroptions for this event. + * + * @return array event editor options + */ + protected function get_editoroptions() { + return $this->editoroptions; + } + + /** + * Returns an event description: Called by __get + * Please use $blah = $event->description; + * + * @return string event description + */ + protected function get_description() { + global $CFG; + + require_once($CFG->libdir . '/filelib.php'); + + if ($this->_description === null) { + // Check if we have already resolved the context for this event. + if ($this->editorcontext === null) { + // Switch on the event type to decide upon the appropriate context to use for this event. + $this->editorcontext = $this->properties->context; + if ($this->properties->eventtype != 'user' && $this->properties->eventtype != 'course' + && $this->properties->eventtype != 'site' && $this->properties->eventtype != 'group') { + return clean_text($this->properties->description, $this->properties->format); + } + } + + // Work out the item id for the editor, if this is a repeated event + // then the files will be associated with the original. + if (!empty($this->properties->repeatid) && $this->properties->repeatid > 0) { + $itemid = $this->properties->repeatid; + } else { + $itemid = $this->properties->id; + } + + // Convert file paths in the description so that things display correctly. + $this->_description = file_rewrite_pluginfile_urls($this->properties->description, 'pluginfile.php', + $this->editorcontext->id, 'calendar', 'event_description', $itemid); + // Clean the text so no nasties get through. + $this->_description = clean_text($this->_description, $this->properties->format); + } + + // Finally return the description. + return $this->_description; + } + + /** + * Return the number of repeat events there are in this events series. + * + * @return int number of event repeated + */ + public function count_repeats() { + global $DB; + if (!empty($this->properties->repeatid)) { + $this->properties->eventrepeats = $DB->count_records('event', + array('repeatid' => $this->properties->repeatid)); + // We don't want to count ourselves. + $this->properties->eventrepeats--; + } + return $this->properties->eventrepeats; + } + + /** + * Update or create an event within the database + * + * Pass in a object containing the event properties and this function will + * insert it into the database and deal with any associated files + * + * @see self::create() + * @see self::update() + * + * @param \stdClass $data object of event + * @param bool $checkcapability if moodle should check calendar managing capability or not + * @return bool event updated + */ + public function update($data, $checkcapability=true) { + global $DB, $USER; + + foreach ($data as $key => $value) { + $this->properties->$key = $value; + } + + $this->properties->timemodified = time(); + $usingeditor = (!empty($this->properties->description) && is_array($this->properties->description)); + + // Prepare event data. + $eventargs = array( + 'context' => $this->properties->context, + 'objectid' => $this->properties->id, + 'other' => array( + 'repeatid' => empty($this->properties->repeatid) ? 0 : $this->properties->repeatid, + 'timestart' => $this->properties->timestart, + 'name' => $this->properties->name + ) + ); + + if (empty($this->properties->id) || $this->properties->id < 1) { + + if ($checkcapability) { + if (!calendar_add_event_allowed($this->properties)) { + print_error('nopermissiontoupdatecalendar'); + } + } + + if ($usingeditor) { + switch ($this->properties->eventtype) { + case 'user': + $this->properties->courseid = 0; + $this->properties->course = 0; + $this->properties->groupid = 0; + $this->properties->userid = $USER->id; + break; + case 'site': + $this->properties->courseid = SITEID; + $this->properties->course = SITEID; + $this->properties->groupid = 0; + $this->properties->userid = $USER->id; + break; + case 'course': + $this->properties->groupid = 0; + $this->properties->userid = $USER->id; + break; + case 'group': + $this->properties->userid = $USER->id; + break; + default: + // We should NEVER get here, but just incase we do lets fail gracefully. + $usingeditor = false; + break; + } + + // If we are actually using the editor, we recalculate the context because some default values + // were set when calculate_context() was called from the constructor. + if ($usingeditor) { + $this->properties->context = $this->calculate_context(); + $this->editorcontext = $this->properties->context; + } + + $editor = $this->properties->description; + $this->properties->format = $this->properties->description['format']; + $this->properties->description = $this->properties->description['text']; + } + + // Insert the event into the database. + $this->properties->id = $DB->insert_record('event', $this->properties); + + if ($usingeditor) { + $this->properties->description = file_save_draft_area_files( + $editor['itemid'], + $this->editorcontext->id, + 'calendar', + 'event_description', + $this->properties->id, + $this->editoroptions, + $editor['text'], + $this->editoroptions['forcehttps']); + $DB->set_field('event', 'description', $this->properties->description, + array('id' => $this->properties->id)); + } + + // Log the event entry. + $eventargs['objectid'] = $this->properties->id; + $eventargs['context'] = $this->properties->context; + $event = \core\event\calendar_event_created::create($eventargs); + $event->trigger(); + + $repeatedids = array(); + + if (!empty($this->properties->repeat)) { + $this->properties->repeatid = $this->properties->id; + $DB->set_field('event', 'repeatid', $this->properties->repeatid, array('id' => $this->properties->id)); + + $eventcopy = clone($this->properties); + unset($eventcopy->id); + + $timestart = new \DateTime('@' . $eventcopy->timestart); + $timestart->setTimezone(\core_date::get_user_timezone_object()); + + for ($i = 1; $i < $eventcopy->repeats; $i++) { + + $timestart->add(new \DateInterval('P7D')); + $eventcopy->timestart = $timestart->getTimestamp(); + + // Get the event id for the log record. + $eventcopyid = $DB->insert_record('event', $eventcopy); + + // If the context has been set delete all associated files. + if ($usingeditor) { + $fs = get_file_storage(); + $files = $fs->get_area_files($this->editorcontext->id, 'calendar', 'event_description', + $this->properties->id); + foreach ($files as $file) { + $fs->create_file_from_storedfile(array('itemid' => $eventcopyid), $file); + } + } + + $repeatedids[] = $eventcopyid; + + // Trigger an event. + $eventargs['objectid'] = $eventcopyid; + $eventargs['other']['timestart'] = $eventcopy->timestart; + $event = \core\event\calendar_event_created::create($eventargs); + $event->trigger(); + } + } + + // Hook for tracking added events. + self::calendar_event_hook('add_event', array($this->properties, $repeatedids)); + return true; + } else { + + if ($checkcapability) { + if (!calendar_edit_event_allowed($this->properties)) { + print_error('nopermissiontoupdatecalendar'); + } + } + + if ($usingeditor) { + if ($this->editorcontext !== null) { + $this->properties->description = file_save_draft_area_files( + $this->properties->description['itemid'], + $this->editorcontext->id, + 'calendar', + 'event_description', + $this->properties->id, + $this->editoroptions, + $this->properties->description['text'], + $this->editoroptions['forcehttps']); + } else { + $this->properties->format = $this->properties->description['format']; + $this->properties->description = $this->properties->description['text']; + } + } + + $event = $DB->get_record('event', array('id' => $this->properties->id)); + + $updaterepeated = (!empty($this->properties->repeatid) && !empty($this->properties->repeateditall)); + + if ($updaterepeated) { + // Update all. + if ($this->properties->timestart != $event->timestart) { + $timestartoffset = $this->properties->timestart - $event->timestart; + $sql = "UPDATE {event} + SET name = ?, + description = ?, + timestart = timestart + ?, + timeduration = ?, + timemodified = ? + WHERE repeatid = ?"; + $params = array($this->properties->name, $this->properties->description, $timestartoffset, + $this->properties->timeduration, time(), $event->repeatid); + } else { + $sql = "UPDATE {event} SET name = ?, description = ?, timeduration = ?, timemodified = ? WHERE repeatid = ?"; + $params = array($this->properties->name, $this->properties->description, + $this->properties->timeduration, time(), $event->repeatid); + } + $DB->execute($sql, $params); + + // Trigger an update event for each of the calendar event. + $events = $DB->get_records('event', array('repeatid' => $event->repeatid), '', 'id,timestart'); + foreach ($events as $event) { + $eventargs['objectid'] = $event->id; + $eventargs['other']['timestart'] = $event->timestart; + $event = \core\event\calendar_event_updated::create($eventargs); + $event->trigger(); + } + } else { + $DB->update_record('event', $this->properties); + $event = self::load($this->properties->id); + $this->properties = $event->properties(); + + // Trigger an update event. + $event = \core\event\calendar_event_updated::create($eventargs); + $event->trigger(); + } + + // Hook for tracking event updates. + self::calendar_event_hook('update_event', array($this->properties, $updaterepeated)); + return true; + } + } + + /** + * Deletes an event and if selected an repeated events in the same series + * + * This function deletes an event, any associated events if $deleterepeated=true, + * and cleans up any files associated with the events. + * + * @see self::delete() + * + * @param bool $deleterepeated delete event repeatedly + * @return bool succession of deleting event + */ + public function delete($deleterepeated = false) { + global $DB; + + // If $this->properties->id is not set then something is wrong. + if (empty($this->properties->id)) { + debugging('Attempting to delete an event before it has been loaded', DEBUG_DEVELOPER); + return false; + } + $calevent = $DB->get_record('event', array('id' => $this->properties->id), '*', MUST_EXIST); + // Delete the event. + $DB->delete_records('event', array('id' => $this->properties->id)); + + // Trigger an event for the delete action. + $eventargs = array( + 'context' => $this->properties->context, + 'objectid' => $this->properties->id, + 'other' => array( + 'repeatid' => empty($this->properties->repeatid) ? 0 : $this->properties->repeatid, + 'timestart' => $this->properties->timestart, + 'name' => $this->properties->name + )); + $event = \core\event\calendar_event_deleted::create($eventargs); + $event->add_record_snapshot('event', $calevent); + $event->trigger(); + + // If we are deleting parent of a repeated event series, promote the next event in the series as parent. + if (($this->properties->id == $this->properties->repeatid) && !$deleterepeated) { + $newparent = $DB->get_field_sql("SELECT id from {event} where repeatid = ? order by id ASC", + array($this->properties->id), IGNORE_MULTIPLE); + if (!empty($newparent)) { + $DB->execute("UPDATE {event} SET repeatid = ? WHERE repeatid = ?", + array($newparent, $this->properties->id)); + // Get all records where the repeatid is the same as the event being removed. + $events = $DB->get_records('event', array('repeatid' => $newparent)); + // For each of the returned events trigger the event_update hook and an update event. + foreach ($events as $event) { + // Trigger an event for the update. + $eventargs['objectid'] = $event->id; + $eventargs['other']['timestart'] = $event->timestart; + $event = \core\event\calendar_event_updated::create($eventargs); + $event->trigger(); + + self::calendar_event_hook('update_event', array($event, false)); + } + } + } + + // If the editor context hasn't already been set then set it now. + if ($this->editorcontext === null) { + $this->editorcontext = $this->properties->context; + } + + // If the context has been set delete all associated files. + if ($this->editorcontext !== null) { + $fs = get_file_storage(); + $files = $fs->get_area_files($this->editorcontext->id, 'calendar', 'event_description', $this->properties->id); + foreach ($files as $file) { + $file->delete(); + } + } + + // Fire the event deleted hook. + self::calendar_event_hook('delete_event', array($this->properties->id, $deleterepeated)); + + // If we need to delete repeated events then we will fetch them all and delete one by one. + if ($deleterepeated && !empty($this->properties->repeatid) && $this->properties->repeatid > 0) { + // Get all records where the repeatid is the same as the event being removed. + $events = $DB->get_records('event', array('repeatid' => $this->properties->repeatid)); + // For each of the returned events populate an event object and call delete. + // make sure the arg passed is false as we are already deleting all repeats. + foreach ($events as $event) { + $event = new event($event); + $event->delete(false); + } + } + + return true; + } + + /** + * Fetch all event properties. + * + * This function returns all of the events properties as an object and optionally + * can prepare an editor for the description field at the same time. This is + * designed to work when the properties are going to be used to set the default + * values of a moodle forms form. + * + * @param bool $prepareeditor If set to true a editor is prepared for use with + * the mforms editor element. (for description) + * @return \stdClass Object containing event properties + */ + public function properties($prepareeditor = false) { + global $DB; + + // First take a copy of the properties. We don't want to actually change the + // properties or we'd forever be converting back and forwards between an + // editor formatted description and not. + $properties = clone($this->properties); + // Clean the description here. + $properties->description = clean_text($properties->description, $properties->format); + + // If set to true we need to prepare the properties for use with an editor + // and prepare the file area. + if ($prepareeditor) { + + // We may or may not have a property id. If we do then we need to work + // out the context so we can copy the existing files to the draft area. + if (!empty($properties->id)) { + + if ($properties->eventtype === 'site') { + // Site context. + $this->editorcontext = $this->properties->context; + } else if ($properties->eventtype === 'user') { + // User context. + $this->editorcontext = $this->properties->context; + } else if ($properties->eventtype === 'group' || $properties->eventtype === 'course') { + // First check the course is valid. + $course = $DB->get_record('course', array('id' => $properties->courseid)); + if (!$course) { + print_error('invalidcourse'); + } + // Course context. + $this->editorcontext = $this->properties->context; + // We have a course and are within the course context so we had + // better use the courses max bytes value. + $this->editoroptions['maxbytes'] = $course->maxbytes; + } else { + // If we get here we have a custom event type as used by some + // modules. In this case the event will have been added by + // code and we won't need the editor. + $this->editoroptions['maxbytes'] = 0; + $this->editoroptions['maxfiles'] = 0; + } + + if (empty($this->editorcontext) || empty($this->editorcontext->id)) { + $contextid = false; + } else { + // Get the context id that is what we really want. + $contextid = $this->editorcontext->id; + } + } else { + + // If we get here then this is a new event in which case we don't need a + // context as there is no existing files to copy to the draft area. + $contextid = null; + } + + // If the contextid === false we don't support files so no preparing + // a draft area. + if ($contextid !== false) { + // Just encase it has already been submitted. + $draftiddescription = file_get_submitted_draft_itemid('description'); + // Prepare the draft area, this copies existing files to the draft area as well. + $properties->description = file_prepare_draft_area($draftiddescription, $contextid, 'calendar', + 'event_description', $properties->id, $this->editoroptions, $properties->description); + } else { + $draftiddescription = 0; + } + + // Structure the description field as the editor requires. + $properties->description = array('text' => $properties->description, 'format' => $properties->format, + 'itemid' => $draftiddescription); + } + + // Finally return the properties. + return $properties; + } + + /** + * Toggles the visibility of an event + * + * @param null|bool $force If it is left null the events visibility is flipped, + * If it is false the event is made hidden, if it is true it + * is made visible. + * @return bool if event is successfully updated, toggle will be visible + */ + public function toggle_visibility($force = null) { + global $DB; + + // Set visible to the default if it is not already set. + if (empty($this->properties->visible)) { + $this->properties->visible = 1; + } + + if ($force === true || ($force !== false && $this->properties->visible == 0)) { + // Make this event visible. + $this->properties->visible = 1; + // Fire the hook. + self::calendar_event_hook('show_event', array($this->properties)); + } else { + // Make this event hidden. + $this->properties->visible = 0; + // Fire the hook. + self::calendar_event_hook('hide_event', array($this->properties)); + } + + // Update the database to reflect this change. + return $DB->set_field('event', 'visible', $this->properties->visible, array('id' => $this->properties->id)); + } + + /** + * Attempts to call the hook for the specified action should a calendar type + * by set $CFG->calendar, and the appopriate function defined + * + * @param string $action One of `update_event`, `add_event`, `delete_event`, `show_event`, `hide_event` + * @param array $args The args to pass to the hook, usually the event is the first element + * @return bool attempts to call event hook + */ + public static function calendar_event_hook($action, array $args) { + global $CFG; + static $extcalendarinc; + if ($extcalendarinc === null) { + if (!empty($CFG->calendar)) { + if (is_readable($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php')) { + include_once($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php'); + $extcalendarinc = true; + } else { + debugging("Calendar lib file missing or not readable at /calendar/{$CFG->calendar}/lib.php.", + DEBUG_DEVELOPER); + $extcalendarinc = false; + } + } else { + $extcalendarinc = false; + } + } + if ($extcalendarinc === false) { + return false; + } + $hook = $CFG->calendar .'_'.$action; + if (function_exists($hook)) { + call_user_func_array($hook, $args); + return true; + } + return false; + } + + /** + * Returns an event object when provided with an event id. + * + * This function makes use of MUST_EXIST, if the event id passed in is invalid + * it will result in an exception being thrown. + * + * @param int|object $param event object or event id + * @return event + */ + public static function load($param) { + global $DB; + if (is_object($param)) { + $event = new event($param); + } else { + $event = $DB->get_record('event', array('id' => (int)$param), '*', MUST_EXIST); + $event = new event($event); + } + return $event; + } + + /** + * Creates a new event and returns an event object + * + * @param \stdClass|array $properties An object containing event properties + * @param bool $checkcapability Check caps or not + * @throws \coding_exception + * + * @return event|bool The event object or false if it failed + */ + public static function create($properties, $checkcapability = true) { + if (is_array($properties)) { + $properties = (object)$properties; + } + if (!is_object($properties)) { + throw new \coding_exception('When creating an event properties should be either an object or an assoc array'); + } + $event = new event($properties); + if ($event->update($properties, $checkcapability)) { + return $event; + } else { + return false; + } + } + + /** + * Format the text using the external API. + * + * This function should we used when text formatting is required in external functions. + * + * @return array an array containing the text formatted and the text format + */ + public function format_external_text() { + + if ($this->editorcontext === null) { + // Switch on the event type to decide upon the appropriate context to use for this event. + $this->editorcontext = $this->properties->context; + + if ($this->properties->eventtype != 'user' && $this->properties->eventtype != 'course' + && $this->properties->eventtype != 'site' && $this->properties->eventtype != 'group') { + // We don't have a context here, do a normal format_text. + return external_format_text($this->properties->description, $this->properties->format, $this->editorcontext->id); + } + } + + // Work out the item id for the editor, if this is a repeated event then the files will be associated with the original. + if (!empty($this->properties->repeatid) && $this->properties->repeatid > 0) { + $itemid = $this->properties->repeatid; + } else { + $itemid = $this->properties->id; + } + + return external_format_text($this->properties->description, $this->properties->format, $this->editorcontext->id, + 'calendar', 'event_description', $itemid); + } +} diff --git a/calendar/classes/rrule_manager.php b/calendar/classes/rrule_manager.php index f11d89aaf70..f4883e7152c 100644 --- a/calendar/classes/rrule_manager.php +++ b/calendar/classes/rrule_manager.php @@ -24,7 +24,6 @@ namespace core_calendar; -use calendar_event; use DateInterval; use DateTime; use moodle_exception; @@ -224,7 +223,7 @@ class rrule_manager { /** * Create events for specified rrule. * - * @param calendar_event $passedevent Properties of event to create. + * @param event $passedevent Properties of event to create. * @throws moodle_exception */ public function create_events($passedevent) { @@ -246,7 +245,7 @@ class rrule_manager { // Adjust the parent event's timestart, if necessary. if (count($eventtimes) > 0 && !in_array($eventrec->timestart, $eventtimes)) { - $calevent = new calendar_event($eventrec); + $calevent = new event($eventrec); $updatedata = (object)['timestart' => $eventtimes[0], 'repeatid' => $eventrec->id]; $calevent->update($updatedata, false); $eventrec->timestart = $calevent->timestart; @@ -720,7 +719,7 @@ class rrule_manager { $cloneevent->repeatid = $event->id; $cloneevent->timestart = $time; unset($cloneevent->id); - calendar_event::create($cloneevent, false); + event::create($cloneevent, false); } } diff --git a/calendar/delete.php b/calendar/delete.php index 93c6c4d6bce..8ccd294b4d1 100644 --- a/calendar/delete.php +++ b/calendar/delete.php @@ -41,7 +41,7 @@ if(!$site = get_site()) { redirect(new moodle_url('/admin/index.php')); } -$event = calendar_event::load($eventid); +$event = \core_calendar\event::load($eventid); /** * We are going to be picky here, and require that any event types other than diff --git a/calendar/event.php b/calendar/event.php index 66c6a6f18b5..b300af2751b 100644 --- a/calendar/event.php +++ b/calendar/event.php @@ -113,7 +113,7 @@ $calendar->prepare_for_view($course, $courses); $formoptions = new stdClass; if ($eventid !== 0) { $title = get_string('editevent', 'calendar'); - $event = calendar_event::load($eventid); + $event = \core_calendar\event::load($eventid); if (!calendar_edit_event_allowed($event)) { print_error('nopermissions'); } @@ -149,7 +149,7 @@ if ($eventid !== 0) { } } $event->timestart = $time; - $event = new calendar_event($event); + $event = new \core_calendar\event($event); if (!calendar_add_event_allowed($event)) { print_error('nopermissions'); } diff --git a/calendar/externallib.php b/calendar/externallib.php index 2383693de14..4c85df7de4f 100644 --- a/calendar/externallib.php +++ b/calendar/externallib.php @@ -78,7 +78,7 @@ class core_calendar_external extends external_api { $transaction = $DB->start_delegated_transaction(); foreach ($params['events'] as $event) { - $eventobj = calendar_event::load($event['eventid']); + $eventobj = \core_calendar\event::load($event['eventid']); // Let's check if the user is allowed to delete an event. if (!calendar_edit_event_allowed($eventobj)) { @@ -242,7 +242,7 @@ class core_calendar_external extends external_api { foreach ($eventlist as $eventid => $eventobj) { $event = (array) $eventobj; // Description formatting. - $calendareventobj = new calendar_event($event); + $calendareventobj = new \core_calendar\event($event); list($event['description'], $event['format']) = $calendareventobj->format_external_text(); if ($hassystemcap) { @@ -255,7 +255,7 @@ class core_calendar_external extends external_api { } } else { // Can the user actually see this event? - $eventobj = calendar_event::load($eventobj); + $eventobj = \core_calendar\event::load($eventobj); if (($eventobj->courseid == $SITE->id) || (!empty($eventobj->groupid) && in_array($eventobj->groupid, $groups)) || (!empty($eventobj->courseid) && in_array($eventobj->courseid, $courses)) || @@ -370,7 +370,7 @@ class core_calendar_external extends external_api { $event['repeat'] = 0; } - $eventobj = new calendar_event($event); + $eventobj = new \core_calendar\event($event); // Let's check if the user is allowed to delete an event. if (!calendar_add_event_allowed($eventobj)) { diff --git a/calendar/lib.php b/calendar/lib.php index 199cd65aa48..a3dc727d6c4 100644 --- a/calendar/lib.php +++ b/calendar/lib.php @@ -366,7 +366,7 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea if (!isset($events[$eventid])) { continue; } - $event = new calendar_event($events[$eventid]); + $event = new \core_calendar\event($events[$eventid]); $popupalt = ''; $component = 'moodle'; if (!empty($event->modulename)) { @@ -1653,7 +1653,7 @@ function calendar_set_filters(array $courseeventsfrom, $ignorefilters = false) { /** * Return the capability for editing calendar event * - * @param calendar_event $event event object + * @param \core_calendar\event $event event object * @return bool capability to edit event */ function calendar_edit_event_allowed($event) { @@ -1763,7 +1763,7 @@ function calendar_preferences_button(stdClass $course) { /** * Get event format time * - * @param calendar_event $event event object + * @param \core_calendar\event $event event object * @param int $now current time in gmt * @param array $linkparams list of params for event link * @param bool $usecommonwords the words as formatted date/time. @@ -2038,796 +2038,6 @@ function calendar_add_event_allowed($event) { } } -/** - * Manage calendar events - * - * This class provides the required functionality in order to manage calendar events. - * It was introduced as part of Moodle 2.0 and was created in order to provide a - * better framework for dealing with calendar events in particular regard to file - * handling through the new file API - * - * @package core_calendar - * @category calendar - * @copyright 2009 Sam Hemelryk - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * - * @property int $id The id within the event table - * @property string $name The name of the event - * @property string $description The description of the event - * @property int $format The format of the description FORMAT_? - * @property int $courseid The course the event is associated with (0 if none) - * @property int $groupid The group the event is associated with (0 if none) - * @property int $userid The user the event is associated with (0 if none) - * @property int $repeatid If this is a repeated event this will be set to the - * id of the original - * @property string $modulename If added by a module this will be the module name - * @property int $instance If added by a module this will be the module instance - * @property string $eventtype The event type - * @property int $timestart The start time as a timestamp - * @property int $timeduration The duration of the event in seconds - * @property int $visible 1 if the event is visible - * @property int $uuid ? - * @property int $sequence ? - * @property int $timemodified The time last modified as a timestamp - */ -class calendar_event { - - /** @var array An object containing the event properties can be accessed via the magic __get/set methods */ - protected $properties = null; - - /** - * @var string The converted event discription with file paths resolved. This gets populated when someone requests description for the first time */ - protected $_description = null; - - /** @var array The options to use with this description editor */ - protected $editoroptions = array( - 'subdirs'=>false, - 'forcehttps'=>false, - 'maxfiles'=>-1, - 'maxbytes'=>null, - 'trusttext'=>false); - - /** @var object The context to use with the description editor */ - protected $editorcontext = null; - - /** - * Instantiates a new event and optionally populates its properties with the - * data provided - * - * @param stdClass $data Optional. An object containing the properties to for - * an event - */ - public function __construct($data=null) { - global $CFG, $USER; - - // First convert to object if it is not already (should either be object or assoc array) - if (!is_object($data)) { - $data = (object)$data; - } - - $this->editoroptions['maxbytes'] = $CFG->maxbytes; - - $data->eventrepeats = 0; - - if (empty($data->id)) { - $data->id = null; - } - - if (!empty($data->subscriptionid)) { - $data->subscription = calendar_get_subscription($data->subscriptionid); - } - - // Default to a user event - if (empty($data->eventtype)) { - $data->eventtype = 'user'; - } - - // Default to the current user - if (empty($data->userid)) { - $data->userid = $USER->id; - } - - if (!empty($data->timeduration) && is_array($data->timeduration)) { - $data->timeduration = make_timestamp($data->timeduration['year'], $data->timeduration['month'], $data->timeduration['day'], $data->timeduration['hour'], $data->timeduration['minute']) - $data->timestart; - } - if (!empty($data->description) && is_array($data->description)) { - $data->format = $data->description['format']; - $data->description = $data->description['text']; - } else if (empty($data->description)) { - $data->description = ''; - $data->format = editors_get_preferred_format(); - } - // Ensure form is defaulted correctly - if (empty($data->format)) { - $data->format = editors_get_preferred_format(); - } - - if (empty($data->context)) { - $data->context = $this->calculate_context($data); - } - $this->properties = $data; - } - - /** - * Magic property method - * - * Attempts to call a set_$key method if one exists otherwise falls back - * to simply set the property - * - * @param string $key property name - * @param mixed $value value of the property - */ - public function __set($key, $value) { - if (method_exists($this, 'set_'.$key)) { - $this->{'set_'.$key}($value); - } - $this->properties->{$key} = $value; - } - - /** - * Magic get method - * - * Attempts to call a get_$key method to return the property and ralls over - * to return the raw property - * - * @param string $key property name - * @return mixed property value - */ - public function __get($key) { - if (method_exists($this, 'get_'.$key)) { - return $this->{'get_'.$key}(); - } - if (!isset($this->properties->{$key})) { - throw new coding_exception('Undefined property requested'); - } - return $this->properties->{$key}; - } - - /** - * Stupid PHP needs an isset magic method if you use the get magic method and - * still want empty calls to work.... blah ~! - * - * @param string $key $key property name - * @return bool|mixed property value, false if property is not exist - */ - public function __isset($key) { - return !empty($this->properties->{$key}); - } - - /** - * Calculate the context value needed for calendar_event. - * Event's type can be determine by the available value store in $data - * It is important to check for the existence of course/courseid to determine - * the course event. - * Default value is set to CONTEXT_USER - * - * @param stdClass $data information about event - * @return stdClass The context object. - */ - protected function calculate_context(stdClass $data) { - global $USER, $DB; - - $context = null; - if (isset($data->courseid) && $data->courseid > 0) { - $context = context_course::instance($data->courseid); - } else if (isset($data->course) && $data->course > 0) { - $context = context_course::instance($data->course); - } else if (isset($data->groupid) && $data->groupid > 0) { - $group = $DB->get_record('groups', array('id'=>$data->groupid)); - $context = context_course::instance($group->courseid); - } else if (isset($data->userid) && $data->userid > 0 && $data->userid == $USER->id) { - $context = context_user::instance($data->userid); - } else if (isset($data->userid) && $data->userid > 0 && $data->userid != $USER->id && - isset($data->instance) && $data->instance > 0) { - $cm = get_coursemodule_from_instance($data->modulename, $data->instance, 0, false, MUST_EXIST); - $context = context_course::instance($cm->course); - } else { - $context = context_user::instance($data->userid); - } - - return $context; - } - - /** - * Returns an array of editoroptions for this event: Called by __get - * Please use $blah = $event->editoroptions; - * - * @return array event editor options - */ - protected function get_editoroptions() { - return $this->editoroptions; - } - - /** - * Returns an event description: Called by __get - * Please use $blah = $event->description; - * - * @return string event description - */ - protected function get_description() { - global $CFG; - - require_once($CFG->libdir . '/filelib.php'); - - if ($this->_description === null) { - // Check if we have already resolved the context for this event - if ($this->editorcontext === null) { - // Switch on the event type to decide upon the appropriate context - // to use for this event - $this->editorcontext = $this->properties->context; - if ($this->properties->eventtype != 'user' && $this->properties->eventtype != 'course' - && $this->properties->eventtype != 'site' && $this->properties->eventtype != 'group') { - return clean_text($this->properties->description, $this->properties->format); - } - } - - // Work out the item id for the editor, if this is a repeated event then the files will - // be associated with the original - if (!empty($this->properties->repeatid) && $this->properties->repeatid > 0) { - $itemid = $this->properties->repeatid; - } else { - $itemid = $this->properties->id; - } - - // Convert file paths in the description so that things display correctly - $this->_description = file_rewrite_pluginfile_urls($this->properties->description, 'pluginfile.php', $this->editorcontext->id, 'calendar', 'event_description', $itemid); - // Clean the text so no nasties get through - $this->_description = clean_text($this->_description, $this->properties->format); - } - // Finally return the description - return $this->_description; - } - - /** - * Return the number of repeat events there are in this events series - * - * @return int number of event repeated - */ - public function count_repeats() { - global $DB; - if (!empty($this->properties->repeatid)) { - $this->properties->eventrepeats = $DB->count_records('event', array('repeatid'=>$this->properties->repeatid)); - // We don't want to count ourselves - $this->properties->eventrepeats--; - } - return $this->properties->eventrepeats; - } - - /** - * Update or create an event within the database - * - * Pass in a object containing the event properties and this function will - * insert it into the database and deal with any associated files - * - * @see self::create() - * @see self::update() - * - * @param stdClass $data object of event - * @param bool $checkcapability if moodle should check calendar managing capability or not - * @return bool event updated - */ - public function update($data, $checkcapability=true) { - global $DB, $USER; - - foreach ($data as $key=>$value) { - $this->properties->$key = $value; - } - - $this->properties->timemodified = time(); - $usingeditor = (!empty($this->properties->description) && is_array($this->properties->description)); - - // Prepare event data. - $eventargs = array( - 'context' => $this->properties->context, - 'objectid' => $this->properties->id, - 'other' => array( - 'repeatid' => empty($this->properties->repeatid) ? 0 : $this->properties->repeatid, - 'timestart' => $this->properties->timestart, - 'name' => $this->properties->name - ) - ); - - if (empty($this->properties->id) || $this->properties->id < 1) { - - if ($checkcapability) { - if (!calendar_add_event_allowed($this->properties)) { - print_error('nopermissiontoupdatecalendar'); - } - } - - if ($usingeditor) { - switch ($this->properties->eventtype) { - case 'user': - $this->properties->courseid = 0; - $this->properties->course = 0; - $this->properties->groupid = 0; - $this->properties->userid = $USER->id; - break; - case 'site': - $this->properties->courseid = SITEID; - $this->properties->course = SITEID; - $this->properties->groupid = 0; - $this->properties->userid = $USER->id; - break; - case 'course': - $this->properties->groupid = 0; - $this->properties->userid = $USER->id; - break; - case 'group': - $this->properties->userid = $USER->id; - break; - default: - // Ewww we should NEVER get here, but just incase we do lets - // fail gracefully - $usingeditor = false; - break; - } - - // If we are actually using the editor, we recalculate the context because some default values - // were set when calculate_context() was called from the constructor. - if ($usingeditor) { - $this->properties->context = $this->calculate_context($this->properties); - $this->editorcontext = $this->properties->context; - } - - $editor = $this->properties->description; - $this->properties->format = $this->properties->description['format']; - $this->properties->description = $this->properties->description['text']; - } - - // Insert the event into the database - $this->properties->id = $DB->insert_record('event', $this->properties); - - if ($usingeditor) { - $this->properties->description = file_save_draft_area_files( - $editor['itemid'], - $this->editorcontext->id, - 'calendar', - 'event_description', - $this->properties->id, - $this->editoroptions, - $editor['text'], - $this->editoroptions['forcehttps']); - $DB->set_field('event', 'description', $this->properties->description, array('id'=>$this->properties->id)); - } - - // Log the event entry. - $eventargs['objectid'] = $this->properties->id; - $eventargs['context'] = $this->properties->context; - $event = \core\event\calendar_event_created::create($eventargs); - $event->trigger(); - - $repeatedids = array(); - - if (!empty($this->properties->repeat)) { - $this->properties->repeatid = $this->properties->id; - $DB->set_field('event', 'repeatid', $this->properties->repeatid, array('id'=>$this->properties->id)); - - $eventcopy = clone($this->properties); - unset($eventcopy->id); - - $timestart = new DateTime('@' . $eventcopy->timestart); - $timestart->setTimezone(core_date::get_user_timezone_object()); - - for($i = 1; $i < $eventcopy->repeats; $i++) { - - $timestart->add(new DateInterval('P7D')); - $eventcopy->timestart = $timestart->getTimestamp(); - - // Get the event id for the log record. - $eventcopyid = $DB->insert_record('event', $eventcopy); - - // If the context has been set delete all associated files - if ($usingeditor) { - $fs = get_file_storage(); - $files = $fs->get_area_files($this->editorcontext->id, 'calendar', 'event_description', $this->properties->id); - foreach ($files as $file) { - $fs->create_file_from_storedfile(array('itemid'=>$eventcopyid), $file); - } - } - - $repeatedids[] = $eventcopyid; - - // Trigger an event. - $eventargs['objectid'] = $eventcopyid; - $eventargs['other']['timestart'] = $eventcopy->timestart; - $event = \core\event\calendar_event_created::create($eventargs); - $event->trigger(); - } - } - - // Hook for tracking added events - self::calendar_event_hook('add_event', array($this->properties, $repeatedids)); - return true; - } else { - - if ($checkcapability) { - if(!calendar_edit_event_allowed($this->properties)) { - print_error('nopermissiontoupdatecalendar'); - } - } - - if ($usingeditor) { - if ($this->editorcontext !== null) { - $this->properties->description = file_save_draft_area_files( - $this->properties->description['itemid'], - $this->editorcontext->id, - 'calendar', - 'event_description', - $this->properties->id, - $this->editoroptions, - $this->properties->description['text'], - $this->editoroptions['forcehttps']); - } else { - $this->properties->format = $this->properties->description['format']; - $this->properties->description = $this->properties->description['text']; - } - } - - $event = $DB->get_record('event', array('id'=>$this->properties->id)); - - $updaterepeated = (!empty($this->properties->repeatid) && !empty($this->properties->repeateditall)); - - if ($updaterepeated) { - // Update all - if ($this->properties->timestart != $event->timestart) { - $timestartoffset = $this->properties->timestart - $event->timestart; - $sql = "UPDATE {event} - SET name = ?, - description = ?, - timestart = timestart + ?, - timeduration = ?, - timemodified = ? - WHERE repeatid = ?"; - $params = array($this->properties->name, $this->properties->description, $timestartoffset, $this->properties->timeduration, time(), $event->repeatid); - } else { - $sql = "UPDATE {event} SET name = ?, description = ?, timeduration = ?, timemodified = ? WHERE repeatid = ?"; - $params = array($this->properties->name, $this->properties->description, $this->properties->timeduration, time(), $event->repeatid); - } - $DB->execute($sql, $params); - - // Trigger an update event for each of the calendar event. - $events = $DB->get_records('event', array('repeatid' => $event->repeatid), '', 'id,timestart'); - foreach ($events as $event) { - $eventargs['objectid'] = $event->id; - $eventargs['other']['timestart'] = $event->timestart; - $event = \core\event\calendar_event_updated::create($eventargs); - $event->trigger(); - } - } else { - $DB->update_record('event', $this->properties); - $event = calendar_event::load($this->properties->id); - $this->properties = $event->properties(); - - // Trigger an update event. - $event = \core\event\calendar_event_updated::create($eventargs); - $event->trigger(); - } - - // Hook for tracking event updates - self::calendar_event_hook('update_event', array($this->properties, $updaterepeated)); - return true; - } - } - - /** - * Deletes an event and if selected an repeated events in the same series - * - * This function deletes an event, any associated events if $deleterepeated=true, - * and cleans up any files associated with the events. - * - * @see self::delete() - * - * @param bool $deleterepeated delete event repeatedly - * @return bool succession of deleting event - */ - public function delete($deleterepeated=false) { - global $DB; - - // If $this->properties->id is not set then something is wrong - if (empty($this->properties->id)) { - debugging('Attempting to delete an event before it has been loaded', DEBUG_DEVELOPER); - return false; - } - $calevent = $DB->get_record('event', array('id' => $this->properties->id), '*', MUST_EXIST); - // Delete the event - $DB->delete_records('event', array('id'=>$this->properties->id)); - - // Trigger an event for the delete action. - $eventargs = array( - 'context' => $this->properties->context, - 'objectid' => $this->properties->id, - 'other' => array( - 'repeatid' => empty($this->properties->repeatid) ? 0 : $this->properties->repeatid, - 'timestart' => $this->properties->timestart, - 'name' => $this->properties->name - )); - $event = \core\event\calendar_event_deleted::create($eventargs); - $event->add_record_snapshot('event', $calevent); - $event->trigger(); - - // If we are deleting parent of a repeated event series, promote the next event in the series as parent - if (($this->properties->id == $this->properties->repeatid) && !$deleterepeated) { - $newparent = $DB->get_field_sql("SELECT id from {event} where repeatid = ? order by id ASC", array($this->properties->id), IGNORE_MULTIPLE); - if (!empty($newparent)) { - $DB->execute("UPDATE {event} SET repeatid = ? WHERE repeatid = ?", array($newparent, $this->properties->id)); - // Get all records where the repeatid is the same as the event being removed - $events = $DB->get_records('event', array('repeatid' => $newparent)); - // For each of the returned events trigger the event_update hook and an update event. - foreach ($events as $event) { - // Trigger an event for the update. - $eventargs['objectid'] = $event->id; - $eventargs['other']['timestart'] = $event->timestart; - $event = \core\event\calendar_event_updated::create($eventargs); - $event->trigger(); - - self::calendar_event_hook('update_event', array($event, false)); - } - } - } - - // If the editor context hasn't already been set then set it now - if ($this->editorcontext === null) { - $this->editorcontext = $this->properties->context; - } - - // If the context has been set delete all associated files - if ($this->editorcontext !== null) { - $fs = get_file_storage(); - $files = $fs->get_area_files($this->editorcontext->id, 'calendar', 'event_description', $this->properties->id); - foreach ($files as $file) { - $file->delete(); - } - } - - // Fire the event deleted hook - self::calendar_event_hook('delete_event', array($this->properties->id, $deleterepeated)); - - // If we need to delete repeated events then we will fetch them all and delete one by one - if ($deleterepeated && !empty($this->properties->repeatid) && $this->properties->repeatid > 0) { - // Get all records where the repeatid is the same as the event being removed - $events = $DB->get_records('event', array('repeatid'=>$this->properties->repeatid)); - // For each of the returned events populate a calendar_event object and call delete - // make sure the arg passed is false as we are already deleting all repeats - foreach ($events as $event) { - $event = new calendar_event($event); - $event->delete(false); - } - } - - return true; - } - - /** - * Fetch all event properties - * - * This function returns all of the events properties as an object and optionally - * can prepare an editor for the description field at the same time. This is - * designed to work when the properties are going to be used to set the default - * values of a moodle forms form. - * - * @param bool $prepareeditor If set to true a editor is prepared for use with - * the mforms editor element. (for description) - * @return stdClass Object containing event properties - */ - public function properties($prepareeditor=false) { - global $USER, $CFG, $DB; - - // First take a copy of the properties. We don't want to actually change the - // properties or we'd forever be converting back and forwards between an - // editor formatted description and not - $properties = clone($this->properties); - // Clean the description here - $properties->description = clean_text($properties->description, $properties->format); - - // If set to true we need to prepare the properties for use with an editor - // and prepare the file area - if ($prepareeditor) { - - // We may or may not have a property id. If we do then we need to work - // out the context so we can copy the existing files to the draft area - if (!empty($properties->id)) { - - if ($properties->eventtype === 'site') { - // Site context - $this->editorcontext = $this->properties->context; - } else if ($properties->eventtype === 'user') { - // User context - $this->editorcontext = $this->properties->context; - } else if ($properties->eventtype === 'group' || $properties->eventtype === 'course') { - // First check the course is valid - $course = $DB->get_record('course', array('id'=>$properties->courseid)); - if (!$course) { - print_error('invalidcourse'); - } - // Course context - $this->editorcontext = $this->properties->context; - // We have a course and are within the course context so we had - // better use the courses max bytes value - $this->editoroptions['maxbytes'] = $course->maxbytes; - } else { - // If we get here we have a custom event type as used by some - // modules. In this case the event will have been added by - // code and we won't need the editor - $this->editoroptions['maxbytes'] = 0; - $this->editoroptions['maxfiles'] = 0; - } - - if (empty($this->editorcontext) || empty($this->editorcontext->id)) { - $contextid = false; - } else { - // Get the context id that is what we really want - $contextid = $this->editorcontext->id; - } - } else { - - // If we get here then this is a new event in which case we don't need a - // context as there is no existing files to copy to the draft area. - $contextid = null; - } - - // If the contextid === false we don't support files so no preparing - // a draft area - if ($contextid !== false) { - // Just encase it has already been submitted - $draftiddescription = file_get_submitted_draft_itemid('description'); - // Prepare the draft area, this copies existing files to the draft area as well - $properties->description = file_prepare_draft_area($draftiddescription, $contextid, 'calendar', 'event_description', $properties->id, $this->editoroptions, $properties->description); - } else { - $draftiddescription = 0; - } - - // Structure the description field as the editor requires - $properties->description = array('text'=>$properties->description, 'format'=>$properties->format, 'itemid'=>$draftiddescription); - } - - // Finally return the properties - return $properties; - } - - /** - * Toggles the visibility of an event - * - * @param null|bool $force If it is left null the events visibility is flipped, - * If it is false the event is made hidden, if it is true it - * is made visible. - * @return bool if event is successfully updated, toggle will be visible - */ - public function toggle_visibility($force=null) { - global $CFG, $DB; - - // Set visible to the default if it is not already set - if (empty($this->properties->visible)) { - $this->properties->visible = 1; - } - - if ($force === true || ($force !== false && $this->properties->visible == 0)) { - // Make this event visible - $this->properties->visible = 1; - // Fire the hook - self::calendar_event_hook('show_event', array($this->properties)); - } else { - // Make this event hidden - $this->properties->visible = 0; - // Fire the hook - self::calendar_event_hook('hide_event', array($this->properties)); - } - - // Update the database to reflect this change - return $DB->set_field('event', 'visible', $this->properties->visible, array('id'=>$this->properties->id)); - } - - /** - * Attempts to call the hook for the specified action should a calendar type - * by set $CFG->calendar, and the appopriate function defined - * - * @param string $action One of `update_event`, `add_event`, `delete_event`, `show_event`, `hide_event` - * @param array $args The args to pass to the hook, usually the event is the first element - * @return bool attempts to call event hook - */ - public static function calendar_event_hook($action, array $args) { - global $CFG; - static $extcalendarinc; - if ($extcalendarinc === null) { - if (!empty($CFG->calendar)) { - if (is_readable($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php')) { - include_once($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php'); - $extcalendarinc = true; - } else { - debugging("Calendar lib file missing or not readable at /calendar/{$CFG->calendar}/lib.php.", - DEBUG_DEVELOPER); - $extcalendarinc = false; - } - } else { - $extcalendarinc = false; - } - } - if($extcalendarinc === false) { - return false; - } - $hook = $CFG->calendar .'_'.$action; - if (function_exists($hook)) { - call_user_func_array($hook, $args); - return true; - } - return false; - } - - /** - * Returns a calendar_event object when provided with an event id - * - * This function makes use of MUST_EXIST, if the event id passed in is invalid - * it will result in an exception being thrown - * - * @param int|object $param event object or event id - * @return calendar_event|false status for loading calendar_event - */ - public static function load($param) { - global $DB; - if (is_object($param)) { - $event = new calendar_event($param); - } else { - $event = $DB->get_record('event', array('id'=>(int)$param), '*', MUST_EXIST); - $event = new calendar_event($event); - } - return $event; - } - - /** - * Creates a new event and returns a calendar_event object - * - * @param stdClass|array $properties An object containing event properties - * @param bool $checkcapability Check caps or not - * @throws coding_exception - * - * @return calendar_event|bool The event object or false if it failed - */ - public static function create($properties, $checkcapability = true) { - if (is_array($properties)) { - $properties = (object)$properties; - } - if (!is_object($properties)) { - throw new coding_exception('When creating an event properties should be either an object or an assoc array'); - } - $event = new calendar_event($properties); - if ($event->update($properties, $checkcapability)) { - return $event; - } else { - return false; - } - } - - /** - * Format the text using the external API. - * This function should we used when text formatting is required in external functions. - * - * @return array an array containing the text formatted and the text format - */ - public function format_external_text() { - - if ($this->editorcontext === null) { - // Switch on the event type to decide upon the appropriate context to use for this event. - $this->editorcontext = $this->properties->context; - - if ($this->properties->eventtype != 'user' && $this->properties->eventtype != 'course' - && $this->properties->eventtype != 'site' && $this->properties->eventtype != 'group') { - // We don't have a context here, do a normal format_text. - return external_format_text($this->properties->description, $this->properties->format, $this->editorcontext->id); - } - } - - // Work out the item id for the editor, if this is a repeated event then the files will be associated with the original. - if (!empty($this->properties->repeatid) && $this->properties->repeatid > 0) { - $itemid = $this->properties->repeatid; - } else { - $itemid = $this->properties->id; - } - - return external_format_text($this->properties->description, $this->properties->format, $this->editorcontext->id, - 'calendar', 'event_description', $itemid); - } -} - /** * Calendar information class * @@ -3149,7 +2359,7 @@ function calendar_add_icalendar_event($event, $courseid, $subscriptionid, $timez } else { $return = CALENDAR_IMPORT_EVENT_INSERTED; // Insert. } - if ($createdevent = calendar_event::create($eventrecord, false)) { + if ($createdevent = \core_calendar\event::create($eventrecord, false)) { if (!empty($event->properties['RRULE'])) { // Repeating events. date_default_timezone_set($tz); // Change time zone to parse all events. diff --git a/calendar/renderer.php b/calendar/renderer.php index c68ca73608b..527a1585a47 100644 --- a/calendar/renderer.php +++ b/calendar/renderer.php @@ -183,7 +183,7 @@ class core_calendar_renderer extends plugin_renderer_base { $underway = array(); // First, print details about events that start today foreach ($events as $event) { - $event = new calendar_event($event); + $event = new \core_calendar\event($event); $event->calendarcourseid = $calendar->courseid; if ($event->timestart >= $calendar->timestamp_today() && $event->timestart <= $calendar->timestamp_tomorrow()-1) { // Print it now $event->time = calendar_format_event_time($event, time(), null, false, $calendar->timestamp_today()); @@ -212,11 +212,11 @@ class core_calendar_renderer extends plugin_renderer_base { /** * Displays an event * - * @param calendar_event $event + * @param \core_calendar\event $event * @param bool $showactions * @return string */ - public function event(calendar_event $event, $showactions=true) { + public function event(\core_calendar\event $event, $showactions=true) { global $CFG; $event = calendar_add_event_metadata($event); @@ -366,7 +366,7 @@ class core_calendar_renderer extends plugin_renderer_base { $events = calendar_get_events($display->tstart, $display->tend, $calendar->users, $calendar->groups, $calendar->courses); if (!empty($events)) { foreach($events as $eventid => $event) { - $event = new calendar_event($event); + $event = new \core_calendar\event($event); if (!empty($event->modulename)) { $cm = get_coursemodule_from_instance($event->modulename, $event->instance); if (!\core_availability\info_module::is_user_visible($cm, 0, false)) { @@ -539,9 +539,8 @@ class core_calendar_renderer extends plugin_renderer_base { if ($events) { $output .= html_writer::start_tag('div', array('class' => 'eventlist')); foreach ($events as $event) { - // Convert to calendar_event object so that we transform description - // accordingly - $event = new calendar_event($event); + // Convert to \core_calendar\event object so that we transform description accordingly. + $event = new \core_calendar\event($event); $event->calendarcourseid = $calendar->courseid; $output .= $this->event($event); } diff --git a/calendar/tests/externallib_test.php b/calendar/tests/externallib_test.php index 9baf24918be..4a1c7be971d 100644 --- a/calendar/tests/externallib_test.php +++ b/calendar/tests/externallib_test.php @@ -120,7 +120,7 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase { $prop->priority = $priority; } - $event = new calendar_event($prop); + $event = new \core_calendar\event($prop); return $event->create($prop); } diff --git a/calendar/tests/lib_test.php b/calendar/tests/lib_test.php index 3e3bb394824..7b9b3bcf101 100644 --- a/calendar/tests/lib_test.php +++ b/calendar/tests/lib_test.php @@ -157,7 +157,7 @@ class core_calendar_lib_testcase extends advanced_testcase { ]; foreach ($events as $event) { - calendar_event::create($event, false); + \core_calendar\event::create($event, false); } $timestart = time() - 60; diff --git a/course/lib.php b/course/lib.php index 980173f8307..0224c84ba59 100644 --- a/course/lib.php +++ b/course/lib.php @@ -992,10 +992,10 @@ function set_coursemodule_visible($id, $visible, $visibleoncoursepage = 1) { ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $modulename)))) { foreach($events as $event) { if ($visible) { - $event = new calendar_event($event); + $event = new \core_calendar\event($event); $event->toggle_visibility(true); } else { - $event = new calendar_event($event); + $event = new \core_calendar\event($event); $event->toggle_visibility(false); } } @@ -1169,7 +1169,7 @@ function course_delete_module($cmid, $async = false) { // Delete events from calendar. if ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $modulename))) { foreach($events as $event) { - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->delete(); } } diff --git a/course/tests/courselib_test.php b/course/tests/courselib_test.php index c726278b396..348b5964581 100644 --- a/course/tests/courselib_test.php +++ b/course/tests/courselib_test.php @@ -1212,7 +1212,7 @@ class core_course_courselib_testcase extends advanced_testcase { // Check the events visibility. if ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $cm->modname))) { foreach ($events as $event) { - $calevent = new calendar_event($event); + $calevent = new \core_calendar\event($event); $this->assertEquals($visibility, $calevent->visible, "$cm->modname calendar_event visibility"); } } diff --git a/lib/db/renamedclasses.php b/lib/db/renamedclasses.php index 30d4b42fb36..f60c4a126b5 100644 --- a/lib/db/renamedclasses.php +++ b/lib/db/renamedclasses.php @@ -45,5 +45,7 @@ $renamedclasses = array( 'core_competency\\external\\persistent_exporter' => 'core\\external\\persistent_exporter', 'core_competency\\external\\comment_area_exporter' => 'core_comment\\external\\comment_area_exporter', 'core_competency\\external\\stored_file_exporter' => 'core_files\\external\\stored_file_exporter', - 'core_competency\\external\\user_summary_exporter' => 'core_user\\external\\user_summary_exporter' + 'core_competency\\external\\user_summary_exporter' => 'core_user\\external\\user_summary_exporter', + 'core_search\area\base_activity' => 'core_search\base_activity', + 'calendar_event' => 'core_calendar\event' ); diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php index 84068b03c4a..81486e999ff 100644 --- a/lib/deprecatedlib.php +++ b/lib/deprecatedlib.php @@ -1163,41 +1163,41 @@ function navmenu($course, $cm=NULL, $targetwindow='self') { /** - * @deprecated please use calendar_event::create() instead. + * @deprecated please use \core_calendar\event::create() instead. */ function add_event($event) { - throw new coding_exception('add_event() can not be used any more, please use calendar_event::create() instead.'); + throw new coding_exception('add_event() can not be used any more, please use \core_calendar\event::create() instead.'); } /** - * @deprecated please calendar_event->update() instead. + * @deprecated please \core_calendar\event->update() instead. */ function update_event($event) { - throw new coding_exception('update_event() is removed, please use calendar_event->update() instead.'); + throw new coding_exception('update_event() is removed, please use \core_calendar\event->update() instead.'); } /** - * @deprecated please use calendar_event->delete() instead. + * @deprecated please use \core_calendar\event->delete() instead. */ function delete_event($id) { throw new coding_exception('delete_event() can not be used any more, please use '. - 'calendar_event->delete() instead.'); + '\core_calendar\event->delete() instead.'); } /** - * @deprecated please use calendar_event->toggle_visibility(false) instead. + * @deprecated please use \core_calendar\event->toggle_visibility(false) instead. */ function hide_event($event) { throw new coding_exception('hide_event() can not be used any more, please use '. - 'calendar_event->toggle_visibility(false) instead.'); + '\core_calendar\event->toggle_visibility(false) instead.'); } /** - * @deprecated please use calendar_event->toggle_visibility(true) instead. + * @deprecated please use \core_calendar\event->toggle_visibility(true) instead. */ function show_event($event) { throw new coding_exception('show_event() can not be used any more, please use '. - 'calendar_event->toggle_visibility(true) instead.'); + '\core_calendar\event->toggle_visibility(true) instead.'); } /** diff --git a/lib/upgrade.txt b/lib/upgrade.txt index afacc0b0cb7..a557a7b4e85 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -69,6 +69,7 @@ information provided here is intended especially for developers. * New 'priority' column for the event table to determine which event to show in case of events with user and group overrides. * Webservices core_course_search_courses and core_course_get_courses_by_field will always return the sortorder field. * core_course_external::get_activities_overview has been deprecated. Please do not call this function any more. +* Class 'calendar_event' has been renamed and is now deprecated. Please use 'core_calendar\event' instead. === 3.2 === diff --git a/mod/assign/lib.php b/mod/assign/lib.php index 6fefd9efdf6..9b17e3b28ca 100644 --- a/mod/assign/lib.php +++ b/mod/assign/lib.php @@ -300,13 +300,13 @@ function assign_update_events($assign, $override = null) { $event->name = $eventname.' ('.get_string('duedate', 'assign').')'; $event->timestart = $duedate; $event->eventtype = 'due'; - calendar_event::create($event); + \core_calendar\event::create($event); } } // Delete any leftover events. foreach ($oldevents as $badevent) { - $badevent = calendar_event::load($badevent); + $badevent = \core_calendar\event::load($badevent); $badevent->delete(); } } diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php index aec06e8f61e..71b4c9efdc6 100644 --- a/mod/assign/locallib.php +++ b/mod/assign/locallib.php @@ -792,7 +792,7 @@ class assign { } $events = $DB->get_records('event', $conds); foreach ($events as $event) { - $eventold = calendar_event::load($event); + $eventold = \core_calendar\event::load($event); $eventold->delete(); } @@ -1197,7 +1197,7 @@ class assign { } if ($event->id) { - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->update($event); } else { unset($event->id); @@ -1208,7 +1208,7 @@ class assign { $event->instance = $instance->id; $event->eventtype = $eventtype; $event->timeduration = 0; - calendar_event::create($event); + \core_calendar\event::create($event); } } else { $DB->delete_records('event', array('modulename' => 'assign', 'instance' => $instance->id, 'eventtype' => $eventtype)); diff --git a/mod/chat/lib.php b/mod/chat/lib.php index 7b9e3795e81..9afa417c45e 100644 --- a/mod/chat/lib.php +++ b/mod/chat/lib.php @@ -126,7 +126,7 @@ function chat_add_instance($chat) { $event->timestart = $chat->chattime; $event->timeduration = 0; - calendar_event::create($event); + \core_calendar\event::create($event); } return $returnid; } @@ -157,11 +157,11 @@ function chat_update_instance($chat) { $event->description = format_module_intro('chat', $chat, $chat->coursemodule); $event->timestart = $chat->chattime; - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->update($event); } else { // Do not publish this event, so delete it. - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->delete(); } } else { @@ -179,7 +179,7 @@ function chat_update_instance($chat) { $event->timestart = $chat->chattime; $event->timeduration = 0; - calendar_event::create($event); + \core_calendar\event::create($event); } } @@ -446,7 +446,7 @@ function chat_refresh_events($courseid = 0) { $event->timestart = $chat->chattime; if ($event->id = $DB->get_field('event', 'id', array('modulename' => 'chat', 'instance' => $chat->id))) { - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->update($event); } else if ($chat->schedule > 0) { // The chat is scheduled and the event should be published. @@ -459,7 +459,7 @@ function chat_refresh_events($courseid = 0) { $event->timeduration = 0; $event->visible = $DB->get_field('course_modules', 'visible', array('module' => $moduleid, 'instance' => $chat->id)); - calendar_event::create($event); + \core_calendar\event::create($event); } } return true; @@ -665,7 +665,7 @@ function chat_update_chat_times($chatid=0) { if ($event->id = $DB->get_field_select('event', 'id', $cond, $params)) { $event->timestart = $chat->chattime; - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->update($event, false); } } diff --git a/mod/choice/locallib.php b/mod/choice/locallib.php index 4dd6418eae0..e056efc29cd 100644 --- a/mod/choice/locallib.php +++ b/mod/choice/locallib.php @@ -52,11 +52,11 @@ function choice_set_events($choice) { $event->timestart = $choice->timeopen; $event->visible = instance_is_visible('choice', $choice); $event->timeduration = 0; - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->update($event); } else { // Calendar event is on longer needed. - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->delete(); } } else { @@ -73,7 +73,7 @@ function choice_set_events($choice) { $event->timestart = $choice->timeopen; $event->visible = instance_is_visible('choice', $choice); $event->timeduration = 0; - calendar_event::create($event); + \core_calendar\event::create($event); } } @@ -88,11 +88,11 @@ function choice_set_events($choice) { $event->timestart = $choice->timeclose; $event->visible = instance_is_visible('choice', $choice); $event->timeduration = 0; - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->update($event); } else { // Calendar event is on longer needed. - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->delete(); } } else { @@ -110,7 +110,7 @@ function choice_set_events($choice) { $event->timestart = $choice->timeclose; $event->visible = instance_is_visible('choice', $choice); $event->timeduration = 0; - calendar_event::create($event); + \core_calendar\event::create($event); } } } diff --git a/mod/data/lib.php b/mod/data/lib.php index 4498ca6e836..fbc57e725f5 100644 --- a/mod/data/lib.php +++ b/mod/data/lib.php @@ -1054,7 +1054,7 @@ function data_delete_instance($id) { // takes the dataid // Remove old calendar events. $events = $DB->get_records('event', array('modulename' => 'data', 'instance' => $id)); foreach ($events as $event) { - $event = calendar_event::load($event); + $event = \core_calendar\event::load($event); $event->delete(); } diff --git a/mod/data/locallib.php b/mod/data/locallib.php index 8d615440b7b..a32668fa3cc 100644 --- a/mod/data/locallib.php +++ b/mod/data/locallib.php @@ -608,11 +608,11 @@ function data_set_events($data) { $event->timestart = $data->timeavailablefrom; $event->visible = instance_is_visible('data', $data); $event->timeduration = 0; - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->update($event); } else { // Calendar event is on longer needed. - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->delete(); } } else { @@ -629,7 +629,7 @@ function data_set_events($data) { $event->timestart = $data->timeavailablefrom; $event->visible = instance_is_visible('data', $data); $event->timeduration = 0; - calendar_event::create($event); + \core_calendar\event::create($event); } } @@ -644,11 +644,11 @@ function data_set_events($data) { $event->timestart = $data->timeavailableto; $event->visible = instance_is_visible('data', $data); $event->timeduration = 0; - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->update($event); } else { // Calendar event is on longer needed. - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->delete(); } } else { @@ -666,7 +666,7 @@ function data_set_events($data) { $event->timestart = $data->timeavailableto; $event->visible = instance_is_visible('data', $data); $event->timeduration = 0; - calendar_event::create($event); + \core_calendar\event::create($event); } } } diff --git a/mod/feedback/lib.php b/mod/feedback/lib.php index ff21e7a5e1b..0b2a625d4d5 100644 --- a/mod/feedback/lib.php +++ b/mod/feedback/lib.php @@ -811,7 +811,7 @@ function feedback_set_events($feedback) { if ($eventid) { // Calendar event exists so update it. $event->id = $eventid; - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->update($event); } else { // Event doesn't exist so create one. @@ -821,11 +821,11 @@ function feedback_set_events($feedback) { $event->modulename = 'feedback'; $event->instance = $feedback->id; $event->eventtype = 'open'; - calendar_event::create($event); + \core_calendar\event::create($event); } } else if ($eventid) { // Calendar event is on longer needed. - $calendarevent = calendar_event::load($eventid); + $calendarevent = \core_calendar\event::load($eventid); $calendarevent->delete(); } @@ -843,7 +843,7 @@ function feedback_set_events($feedback) { if ($eventid) { // Calendar event exists so update it. $event->id = $eventid; - $calendarevent = calendar_event::load($event->id); + $calendarevent = \core_calendar\event::load($event->id); $calendarevent->update($event); } else { // Event doesn't exist so create one. @@ -853,11 +853,11 @@ function feedback_set_events($feedback) { $event->modulename = 'feedback'; $event->instance = $feedback->id; $event->eventtype = 'close'; - calendar_event::create($event); + \core_calendar\event::create($event); } } else if ($eventid) { // Calendar event is on longer needed. - $calendarevent = calendar_event::load($eventid); + $calendarevent = \core_calendar\event::load($eventid); $calendarevent->delete(); } } diff --git a/mod/lesson/lib.php b/mod/lesson/lib.php index 687db47d738..c87e56466e6 100644 --- a/mod/lesson/lib.php +++ b/mod/lesson/lib.php @@ -206,8 +206,8 @@ function lesson_update_events($lesson, $override = null) { unset($event->id); } $event->name = $eventname.' ('.get_string('lessonopens', 'lesson').')'; - // The method calendar_event::create will reuse a db record if the id field is set. - calendar_event::create($event); + // The method \core_calendar\event::create will reuse a db record if the id field is set. + \core_calendar\event::create($event); } if ($deadline && $addclose) { if ($oldevent = array_shift($oldevents)) { @@ -224,14 +224,14 @@ function lesson_update_events($lesson, $override = null) { $event->priority = $closepriorities[$deadline]; } } - calendar_event::create($event); + \core_calendar\event::create($event); } } } // Delete any leftover events. foreach ($oldevents as $badevent) { - $badevent = calendar_event::load($badevent); + $badevent = \core_calendar\event::load($badevent); $badevent->delete(); } } diff --git a/mod/lesson/locallib.php b/mod/lesson/locallib.php index 4d84afcc4cc..20dc123da3d 100644 --- a/mod/lesson/locallib.php +++ b/mod/lesson/locallib.php @@ -1571,7 +1571,7 @@ class lesson extends lesson_base { $DB->delete_records("lesson_branch", array("lessonid"=>$this->properties->id)); if ($events = $DB->get_records('event', array("modulename"=>'lesson', "instance"=>$this->properties->id))) { foreach($events as $event) { - $event = calendar_event::load($event); + $event = \core_calendar\event::load($event); $event->delete(); } } @@ -1609,7 +1609,7 @@ class lesson extends lesson_base { } $events = $DB->get_records('event', $conds); foreach ($events as $event) { - $eventold = calendar_event::load($event); + $eventold = \core_calendar\event::load($event); $eventold->delete(); } diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php index c644febdef0..2ff39e3399d 100644 --- a/mod/quiz/lib.php +++ b/mod/quiz/lib.php @@ -223,7 +223,7 @@ function quiz_delete_override($quiz, $overrideid) { 'instance' => $quiz->id, 'groupid' => (int)$override->groupid, 'userid' => (int)$override->userid)); foreach ($events as $event) { - $eventold = calendar_event::load($event); + $eventold = \core_calendar\event::load($event); $eventold->delete(); } @@ -1284,8 +1284,8 @@ function quiz_update_events($quiz, $override = null) { unset($event->id); } $event->name = $eventname.' ('.get_string('quizopens', 'quiz').')'; - // The method calendar_event::create will reuse a db record if the id field is set. - calendar_event::create($event); + // The method \core_calendar\event::create will reuse a db record if the id field is set. + \core_calendar\event::create($event); } if ($timeclose && $addclose) { if ($oldevent = array_shift($oldevents)) { @@ -1302,14 +1302,14 @@ function quiz_update_events($quiz, $override = null) { $event->priority = $closepriorities[$timeclose]; } } - calendar_event::create($event); + \core_calendar\event::create($event); } } } // Delete any leftover events. foreach ($oldevents as $badevent) { - $badevent = calendar_event::load($badevent); + $badevent = \core_calendar\event::load($badevent); $badevent->delete(); } } diff --git a/mod/workshop/lib.php b/mod/workshop/lib.php index 2a24779d7c6..b5d8b18f1c7 100644 --- a/mod/workshop/lib.php +++ b/mod/workshop/lib.php @@ -265,7 +265,7 @@ function workshop_delete_instance($id) { // delete the calendar events $events = $DB->get_records('event', array('modulename' => 'workshop', 'instance' => $workshop->id)); foreach ($events as $event) { - $event = calendar_event::load($event); + $event = \core_calendar\event::load($event); $event->delete(); } @@ -1714,7 +1714,7 @@ function workshop_calendar_update(stdClass $workshop, $cmid) { unset($event->id); } // update() will reuse a db record if the id field is set - $eventobj = new calendar_event($event); + $eventobj = new \core_calendar\event($event); $eventobj->update($event, false); } @@ -1729,7 +1729,7 @@ function workshop_calendar_update(stdClass $workshop, $cmid) { unset($event->id); } // update() will reuse a db record if the id field is set - $eventobj = new calendar_event($event); + $eventobj = new \core_calendar\event($event); $eventobj->update($event, false); } @@ -1744,7 +1744,7 @@ function workshop_calendar_update(stdClass $workshop, $cmid) { unset($event->id); } // update() will reuse a db record if the id field is set - $eventobj = new calendar_event($event); + $eventobj = new \core_calendar\event($event); $eventobj->update($event, false); } @@ -1759,13 +1759,13 @@ function workshop_calendar_update(stdClass $workshop, $cmid) { unset($event->id); } // update() will reuse a db record if the id field is set - $eventobj = new calendar_event($event); + $eventobj = new \core_calendar\event($event); $eventobj->update($event, false); } // delete any leftover events foreach ($currentevents as $oldevent) { - $oldevent = calendar_event::load($oldevent); + $oldevent = \core_calendar\event::load($oldevent); $oldevent->delete(); } } From 5019e695883e5dc86cc0254c031422d61e2c1943 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Thu, 5 Jan 2017 13:45:42 +0800 Subject: [PATCH 007/215] MDL-57578 core_calendar: removed the function calendar_event_hook() Part of MDL-55611 epic. --- calendar/classes/event.php | 49 -------------------------------------- calendar/upgrade.txt | 4 ++++ 2 files changed, 4 insertions(+), 49 deletions(-) diff --git a/calendar/classes/event.php b/calendar/classes/event.php index e3cb643a5d4..44640cb42f3 100644 --- a/calendar/classes/event.php +++ b/calendar/classes/event.php @@ -413,8 +413,6 @@ class event { } } - // Hook for tracking added events. - self::calendar_event_hook('add_event', array($this->properties, $repeatedids)); return true; } else { @@ -483,8 +481,6 @@ class event { $event->trigger(); } - // Hook for tracking event updates. - self::calendar_event_hook('update_event', array($this->properties, $updaterepeated)); return true; } } @@ -541,8 +537,6 @@ class event { $eventargs['other']['timestart'] = $event->timestart; $event = \core\event\calendar_event_updated::create($eventargs); $event->trigger(); - - self::calendar_event_hook('update_event', array($event, false)); } } } @@ -561,9 +555,6 @@ class event { } } - // Fire the event deleted hook. - self::calendar_event_hook('delete_event', array($this->properties->id, $deleterepeated)); - // If we need to delete repeated events then we will fetch them all and delete one by one. if ($deleterepeated && !empty($this->properties->repeatid) && $this->properties->repeatid > 0) { // Get all records where the repeatid is the same as the event being removed. @@ -687,55 +678,15 @@ class event { if ($force === true || ($force !== false && $this->properties->visible == 0)) { // Make this event visible. $this->properties->visible = 1; - // Fire the hook. - self::calendar_event_hook('show_event', array($this->properties)); } else { // Make this event hidden. $this->properties->visible = 0; - // Fire the hook. - self::calendar_event_hook('hide_event', array($this->properties)); } // Update the database to reflect this change. return $DB->set_field('event', 'visible', $this->properties->visible, array('id' => $this->properties->id)); } - /** - * Attempts to call the hook for the specified action should a calendar type - * by set $CFG->calendar, and the appopriate function defined - * - * @param string $action One of `update_event`, `add_event`, `delete_event`, `show_event`, `hide_event` - * @param array $args The args to pass to the hook, usually the event is the first element - * @return bool attempts to call event hook - */ - public static function calendar_event_hook($action, array $args) { - global $CFG; - static $extcalendarinc; - if ($extcalendarinc === null) { - if (!empty($CFG->calendar)) { - if (is_readable($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php')) { - include_once($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php'); - $extcalendarinc = true; - } else { - debugging("Calendar lib file missing or not readable at /calendar/{$CFG->calendar}/lib.php.", - DEBUG_DEVELOPER); - $extcalendarinc = false; - } - } else { - $extcalendarinc = false; - } - } - if ($extcalendarinc === false) { - return false; - } - $hook = $CFG->calendar .'_'.$action; - if (function_exists($hook)) { - call_user_func_array($hook, $args); - return true; - } - return false; - } - /** * Returns an event object when provided with an event id. * diff --git a/calendar/upgrade.txt b/calendar/upgrade.txt index 4a37e2c205b..bcec3ba3bb9 100644 --- a/calendar/upgrade.txt +++ b/calendar/upgrade.txt @@ -1,6 +1,10 @@ This files describes API changes in /calendar/* , information provided here is intended especially for developers. +=== 3.3 === +* calendar_event_hook() has been removed. Developers should be using the Moodle events system to achieve this behaviour, + rather than using a hacky calendar specific implementation. + === 3.2 === * calendar_preferences_button() is now depreciated. Calendar preferences have been moved to the user preferences page. From ca622fd9fae3b2fd0e2bc981bb06bf1aa0eee1c7 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 10 Jan 2017 11:05:17 +0800 Subject: [PATCH 008/215] MDL-57435 core: added additional columns to 'event' table Part of MDL-55611 epic. --- lib/db/install.xml | 3 +++ lib/db/upgrade.php | 28 ++++++++++++++++++++++++++++ version.php | 2 +- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/db/install.xml b/lib/db/install.xml index 2e52477544f..2915e60896c 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -431,9 +431,11 @@ + + @@ -449,6 +451,7 @@ + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 678b86b9693..5f50fa4375a 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2639,5 +2639,33 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2017040300.05); } + if ($oldversion < 2017040300.06) { + + // Define fields to be added to the 'event' table. + $table = new xmldb_table('event'); + $fieldtype = new xmldb_field('type', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, 0, 'instance'); + $fieldtimesort = new xmldb_field('timesort', XMLDB_TYPE_INTEGER, '10', null, false, null, null, 'timeduration'); + + // Conditionally launch add field. + if (!$dbman->field_exists($table, $fieldtype)) { + $dbman->add_field($table, $fieldtype); + } + + // Conditionally launch add field. + if (!$dbman->field_exists($table, $fieldtimesort)) { + $dbman->add_field($table, $fieldtimesort); + } + + // Now, define the index we will be adding. + $index = new xmldb_index('type-timesort', XMLDB_INDEX_NOTUNIQUE, array('type', 'timesort')); + + // Conditionally launch add index. + if (!$dbman->index_exists($table, $index)) { + $dbman->add_index($table, $index); + } + + upgrade_main_savepoint(true, 2017040300.06); + } + return true; } diff --git a/version.php b/version.php index 75869935df8..1d6c5a942db 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2017040300.05; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2017040300.06; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. From 1c68e83b1ff521962001452bea4ab04501ba03e8 Mon Sep 17 00:00:00 2001 From: Cameron Ball Date: Mon, 2 Jan 2017 00:53:29 +0800 Subject: [PATCH 009/215] MDL-57445 block_myoverview: Add timeline by date templates Part of MDL-55611 epic. --- .../myoverview/lang/en/block_myoverview.php | 5 ++ .../templates/event-list-item.mustache | 48 ++++++++++++++++++ .../myoverview/templates/event-list.mustache | 34 +++++++++++++ blocks/myoverview/templates/main.mustache | 47 +++++++++++++++++ .../templates/timeline-view-dates.mustache | 46 +++++++++++++++++ .../templates/timeline-view.mustache | 50 +++++++++++++++++++ 6 files changed, 230 insertions(+) create mode 100644 blocks/myoverview/templates/event-list-item.mustache create mode 100644 blocks/myoverview/templates/event-list.mustache create mode 100644 blocks/myoverview/templates/main.mustache create mode 100644 blocks/myoverview/templates/timeline-view-dates.mustache create mode 100644 blocks/myoverview/templates/timeline-view.mustache diff --git a/blocks/myoverview/lang/en/block_myoverview.php b/blocks/myoverview/lang/en/block_myoverview.php index 4af1ecc8dc2..a9bba66546d 100644 --- a/blocks/myoverview/lang/en/block_myoverview.php +++ b/blocks/myoverview/lang/en/block_myoverview.php @@ -24,4 +24,9 @@ $string['myoverview:addinstance'] = 'Add a new my overview block'; $string['myoverview:myaddinstance'] = 'Add a new my overview block to Dashboard'; +$string['next7days'] = 'Next 7 days'; +$string['next30days'] = 'Next 30 days'; $string['pluginname'] = 'My overview'; +$string['sortbycourses'] = 'Sort by courses'; +$string['sortbydates'] = 'Sort by dates'; +$string['timeline'] = 'Timeline'; diff --git a/blocks/myoverview/templates/event-list-item.mustache b/blocks/myoverview/templates/event-list-item.mustache new file mode 100644 index 00000000000..6450ce86f7f --- /dev/null +++ b/blocks/myoverview/templates/event-list-item.mustache @@ -0,0 +1,48 @@ +{{! + 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_myoverview/event-list-item + + This template renders an event list item for the myoverview block. +}} +
  • +
    +
    + {{#itemcount}} +
    + {{.}} +
    + {{/itemcount}} + +
    {{enddate}}
    +
    + {{#icon}}{{#pix}} {{key}}, {{component}}, {{alttext}} {{/pix}}{{/icon}} +
    +
    +
    + +
    + {{coursename}} +
    +
    +
    +
    {{enddate}}
    +
    +
    +
  • diff --git a/blocks/myoverview/templates/event-list.mustache b/blocks/myoverview/templates/event-list.mustache new file mode 100644 index 00000000000..b8ea9f57447 --- /dev/null +++ b/blocks/myoverview/templates/event-list.mustache @@ -0,0 +1,34 @@ +{{! + 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_myoverview/event-list + + This template renders a list of events for the myoverview block. +}} +
    +
    {{$title}}{{/title}}
    +
      + + {{> block_myoverview/event-list-items }} +
    + {{> core/loading }} +
    diff --git a/blocks/myoverview/templates/main.mustache b/blocks/myoverview/templates/main.mustache new file mode 100644 index 00000000000..f7178f4643d --- /dev/null +++ b/blocks/myoverview/templates/main.mustache @@ -0,0 +1,47 @@ +{{! + 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_myoverview/main + + This template renders the main content area for the myoverview block. +}} + +
    + + +
    +
    + {{> block_myoverview/timeline-view }} +
    +
    + {{> block_myoverview/courses-view }} +
    +
    +
    diff --git a/blocks/myoverview/templates/timeline-view-dates.mustache b/blocks/myoverview/templates/timeline-view-dates.mustache new file mode 100644 index 00000000000..1304ac5dc0d --- /dev/null +++ b/blocks/myoverview/templates/timeline-view-dates.mustache @@ -0,0 +1,46 @@ +{{! + 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_myoverview/timeline-view-dates + + This template renders the timeline view by dates for the myoverview block. +}} +
    +
    +
    + {{< block_myoverview/event-list }} + {{$startday}}0{{/startday}} + {{$endday}}7{{/endday}} + {{$limit}}10{{/limit}} + {{$offset}}0{{/offset}} + {{$title}}{{#str}} next7days, block_myoverview {{/str}}{{/title}} + {{/ block_myoverview/event-list }} +
    +
    + {{< block_myoverview/event-list }} + {{$startday}}8{{/startday}} + {{$endday}}30{{/endday}} + {{$limit}}10{{/limit}} + {{$offset}}0{{/offset}} + {{$title}}{{#str}} next30days, block_myoverview {{/str}}{{/title}} + {{/ block_myoverview/event-list }} +
    +
    + +
    +
    +
    diff --git a/blocks/myoverview/templates/timeline-view.mustache b/blocks/myoverview/templates/timeline-view.mustache new file mode 100644 index 00000000000..3fb66335208 --- /dev/null +++ b/blocks/myoverview/templates/timeline-view.mustache @@ -0,0 +1,50 @@ +{{! + 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_myoverview/timeline-view + + This template renders the timeline view for the myoverview block. +}} +
    + + +
    +
    + {{> block_myoverview/timeline-view-dates }} +
    +
    +
    +
    +
    +{{#js}} +require(['jquery', 'core/custom_interaction_events'], function($, customEvents) { + var root = $('#timeline-view-{{uniqid}}'); + customEvents.define(root, [customEvents.events.activate]); + root.on(customEvents.events.activate, '[data-toggle="btns"] > .btn', function() { + root.find('.btn.active').removeClass('active'); + }); +}); +{{/js}} From 41b571a1eac27a4c8744d76a5aa60c9c802b6b85 Mon Sep 17 00:00:00 2001 From: Ryan Wyllie Date: Thu, 22 Dec 2016 03:11:02 +0000 Subject: [PATCH 010/215] MDL-57445 block_myoverview: Add renderer Part of MDL-55611 epic. --- blocks/myoverview/block_myoverview.php | 2 +- blocks/myoverview/renderer.php | 43 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 blocks/myoverview/renderer.php diff --git a/blocks/myoverview/block_myoverview.php b/blocks/myoverview/block_myoverview.php index 92e7f8031f0..7ae666253f7 100644 --- a/blocks/myoverview/block_myoverview.php +++ b/blocks/myoverview/block_myoverview.php @@ -51,7 +51,7 @@ class block_myoverview extends block_base { } $this->content = new stdClass(); - $this->content->text = ''; + $this->content->text = $this->page->get_renderer('block_myoverview')->get_content(); $this->content->footer = ''; return $this->content; diff --git a/blocks/myoverview/renderer.php b/blocks/myoverview/renderer.php new file mode 100644 index 00000000000..248bc54f02e --- /dev/null +++ b/blocks/myoverview/renderer.php @@ -0,0 +1,43 @@ +. + +/** + * myoverview block rendrer + * + * @package block_myoverview + * @copyright 2016 Ryan Wyllie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die; + +/** + * myoverview block rendrer + * + * @package block_myoverview + * @copyright 2016 Ryan Wyllie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class block_myoverview_renderer extends plugin_renderer_base { + + /** + * Return the main content for the block overview. + * + * @return {string} HTML string + */ + public function get_content() { + return $this->render_from_template('block_myoverview/main', []); + } +} From 38c795b2ce90783a35c51d7927d36ec0ffdb4849 Mon Sep 17 00:00:00 2001 From: Cameron Ball Date: Mon, 2 Jan 2017 01:09:21 +0800 Subject: [PATCH 011/215] MDL-57445 block_myoverview: Add timeline sort by dates This patch adds a basic timeline view for the events sorted by date. The events data is stubbed in the calendar events repository. Part of MDL-55611 epic. --- .../amd/src/calendar_events_repository.js | 187 ++++++++++++++++++ blocks/myoverview/amd/src/event_list.js | 68 +++++++ .../myoverview/amd/src/timeline_view_dates.js | 50 +++++ .../templates/event-list-items.mustache | 24 +++ .../templates/timeline-view-dates.mustache | 5 + 5 files changed, 334 insertions(+) create mode 100644 blocks/myoverview/amd/src/calendar_events_repository.js create mode 100644 blocks/myoverview/amd/src/event_list.js create mode 100644 blocks/myoverview/amd/src/timeline_view_dates.js create mode 100644 blocks/myoverview/templates/event-list-items.mustache diff --git a/blocks/myoverview/amd/src/calendar_events_repository.js b/blocks/myoverview/amd/src/calendar_events_repository.js new file mode 100644 index 00000000000..fe3c8dd1dc1 --- /dev/null +++ b/blocks/myoverview/amd/src/calendar_events_repository.js @@ -0,0 +1,187 @@ +// 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 retrieve calendar events from the server. + * + * @module block_myoverview/calendar_events_repository + * @class repository + * @package block_myoverview + * @copyright 2016 Ryan Wyllie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['jquery'], function($) { + + var dataCache = [ + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 1', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 2', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 3', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 4', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 5', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 6', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 7', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 8', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 9', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 10', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 11', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 12', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 13', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 14', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 15', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + { + actionname: 'Submit assignment', + actionurl: 'https://www.google.com', + enddate: 'Nov 4th, 10am', + contextname: 'Assignment due 16', + contexturl: 'https://www.google.com', + coursename: 'Course 1', + itemcount: 1, + }, + ]; + + var queryForUserByDays = function(startDay, endDay, limit, offset) { + var deferred = $.Deferred(); + + setTimeout(function() { + deferred.resolve(dataCache.slice(offset, offset + limit)); + }, 1000); + + return deferred.promise(); + }; + + return { + query_for_user_by_days: queryForUserByDays, + }; +}); diff --git a/blocks/myoverview/amd/src/event_list.js b/blocks/myoverview/amd/src/event_list.js new file mode 100644 index 00000000000..afb5f934fea --- /dev/null +++ b/blocks/myoverview/amd/src/event_list.js @@ -0,0 +1,68 @@ +// 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 . + +/** + * Controller for handling loading calendar events and rendering them in a list + * for the myoverview block. + * + * @module block_myoverview/event_list_controller + * @class controller + * @package block_myoverview + * @copyright 2016 Ryan Wyllie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['jquery', 'core/notification', 'core/templates', + 'block_myoverview/calendar_events_repository'], + function($, Notification, Templates, CalendarEventsRepository) { + + return { + load: function(root) { + root = $(root); + var start = +root.attr('data-start-day'), + end = +root.attr('data-end-day'), + limit = +root.attr('data-limit'), + offset = +root.attr('data-offset'); + + // Don't load twice. + if (root.hasClass('loading')) { + return $.Deferred().resolve(); + } + + root.addClass('loading'); + + // Request data from the server. + return CalendarEventsRepository.query_for_user_by_days( + start, end, limit, offset + ).then(function(calendarEvents) { + // Increment the offset by the number of events returned. + root.attr('data-offset', offset + calendarEvents.length); + + if (calendarEvents.length) { + // Render the events. + return Templates.render( + 'block_myoverview/event-list-items', + {events: calendarEvents} + ).done(function(html, js) { + Templates.appendNodeContents(root, html, js); + }); + } + }).fail( + Notification.exception + ).always(function() { + root.removeClass('loading'); + }); + } + }; +}); diff --git a/blocks/myoverview/amd/src/timeline_view_dates.js b/blocks/myoverview/amd/src/timeline_view_dates.js new file mode 100644 index 00000000000..94cd180d3be --- /dev/null +++ b/blocks/myoverview/amd/src/timeline_view_dates.js @@ -0,0 +1,50 @@ +// 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 . + +/** + * Controller for the timeline dates view in the myoverview block. + * + * @module block_myoverview/timeline_dates_view_controller + * @class controller + * @package block_myoverview + * @copyright 2016 Ryan Wyllie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['core/custom_interaction_events', 'block_myoverview/event_list'], function(CustomEvents, EventList) { + + var SELECTORS = { + VIEW_MORE_BUTTON: '[data-action="view-more"]', + EVENT_LIST: '[data-region="event-list"]', + }; + + var loadForContainers = function(containers) { + containers.each(function() { + EventList.load(this); + }); + }; + + return { + registerEventListeners: function(root) { + var containers = root.find(SELECTORS.EVENT_LIST); + + loadForContainers(containers); + + CustomEvents.define(root, [CustomEvents.events.activate]); + root.on(CustomEvents.events.activate, SELECTORS.VIEW_MORE_BUTTON, function() { + loadForContainers(containers); + }); + } + }; +}); diff --git a/blocks/myoverview/templates/event-list-items.mustache b/blocks/myoverview/templates/event-list-items.mustache new file mode 100644 index 00000000000..139cff4564f --- /dev/null +++ b/blocks/myoverview/templates/event-list-items.mustache @@ -0,0 +1,24 @@ +{{! + 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_myoverview/event-list-items + + This template renders a group of event list items for the myoverview block. +}} +{{#events}} + {{> block_myoverview/event-list-item }} +{{/events}} diff --git a/blocks/myoverview/templates/timeline-view-dates.mustache b/blocks/myoverview/templates/timeline-view-dates.mustache index 1304ac5dc0d..08c62761345 100644 --- a/blocks/myoverview/templates/timeline-view-dates.mustache +++ b/blocks/myoverview/templates/timeline-view-dates.mustache @@ -44,3 +44,8 @@ +{{#js}} +require(['jquery', 'block_myoverview/timeline_view_dates'], function($, js) { + js.registerEventListeners($('#timeline-view-dates-{{uniqid}}')); +}); +{{/js}} From 6a12232581dd05b324b5a35b4fc41e292948eb64 Mon Sep 17 00:00:00 2001 From: Cameron Ball Date: Mon, 2 Jan 2017 01:19:09 +0800 Subject: [PATCH 012/215] MDL-57445 block_myoverview: Add course view to timeline Part of MDL-55611 epic. --- .../templates/timeline-view-courses.mustache | 35 +++++++++++++++++++ .../templates/timeline-view.mustache | 1 + 2 files changed, 36 insertions(+) create mode 100644 blocks/myoverview/templates/timeline-view-courses.mustache diff --git a/blocks/myoverview/templates/timeline-view-courses.mustache b/blocks/myoverview/templates/timeline-view-courses.mustache new file mode 100644 index 00000000000..89539a26d42 --- /dev/null +++ b/blocks/myoverview/templates/timeline-view-courses.mustache @@ -0,0 +1,35 @@ +{{! + 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_myoverview/timeline-view-courses + + This template renders the timeline view by courses for the myoverview block. +}} +
    + {{#courses}} +
    +
    +
    + {{> block_myoverview/course-summary }} +
    +
    + {{> block_myoverview/view-dates }} +
    +
    +
    + {{/courses}} +
    diff --git a/blocks/myoverview/templates/timeline-view.mustache b/blocks/myoverview/templates/timeline-view.mustache index 3fb66335208..0f68ba3c24d 100644 --- a/blocks/myoverview/templates/timeline-view.mustache +++ b/blocks/myoverview/templates/timeline-view.mustache @@ -36,6 +36,7 @@ {{> block_myoverview/timeline-view-dates }}
    + {{> block_myoverview/timeline-view-courses }}
    From 992c63043a5434a7c3605d764e0e8a754a474cde Mon Sep 17 00:00:00 2001 From: Cameron Ball Date: Mon, 2 Jan 2017 01:22:10 +0800 Subject: [PATCH 013/215] MDL-57445 block_myoverview: Add courses view to myoverview block Part of MDL-55611 epic. --- .../build/calendar_events_repository.min.js | 1 + blocks/myoverview/amd/build/event_list.min.js | 1 + blocks/myoverview/amd/build/events.min.js | 1 + .../amd/build/timeline_view_dates.min.js | 1 + .../myoverview/lang/en/block_myoverview.php | 5 ++- .../templates/courses-view.mustache | 38 +++++++++++++++++++ 6 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 blocks/myoverview/amd/build/calendar_events_repository.min.js create mode 100644 blocks/myoverview/amd/build/event_list.min.js create mode 100644 blocks/myoverview/amd/build/events.min.js create mode 100644 blocks/myoverview/amd/build/timeline_view_dates.min.js create mode 100644 blocks/myoverview/templates/courses-view.mustache diff --git a/blocks/myoverview/amd/build/calendar_events_repository.min.js b/blocks/myoverview/amd/build/calendar_events_repository.min.js new file mode 100644 index 00000000000..cdc6b45220e --- /dev/null +++ b/blocks/myoverview/amd/build/calendar_events_repository.min.js @@ -0,0 +1 @@ +define(["jquery"],function(a){var b=[{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 1",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 2",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 3",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 4",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 5",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 6",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 7",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 8",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 9",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 10",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 11",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 12",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 13",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 14",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 15",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1},{actionname:"Submit assignment",actionurl:"https://www.google.com",enddate:"Nov 4th, 10am",contextname:"Assignment due 16",contexturl:"https://www.google.com",coursename:"Course 1",itemcount:1}],c=function(c,d,e,f){var g=a.Deferred();return setTimeout(function(){g.resolve(b.slice(f,f+e))},1e3),g.promise()};return{query_for_user_by_days:c}}); \ No newline at end of file diff --git a/blocks/myoverview/amd/build/event_list.min.js b/blocks/myoverview/amd/build/event_list.min.js new file mode 100644 index 00000000000..6624d85ff52 --- /dev/null +++ b/blocks/myoverview/amd/build/event_list.min.js @@ -0,0 +1 @@ +define(["jquery","core/notification","core/templates","block_myoverview/events","block_myoverview/calendar_events_repository"],function(a,b,c,d,e){return{load:function(f){f=a(f);var g=+f.attr("data-start-day"),h=+f.attr("data-end-day"),i=+f.attr("data-limit"),j=+f.attr("data-offset");return f.hasClass("loading")?a.Deferred().resolve():(f.addClass("loading"),f.trigger(d.LOADING_EVENTS),e.query_for_user_by_days(g,h,i,j).then(function(a){return f.trigger(d.LOADED_EVENTS,[{events:a}]),f.attr("data-offset",j+a.length),a}).then(function(a){return c.render("block_myoverview/event-list-items",{events:a}).done(function(a,b){c.appendNodeContents(f,a,b)})}).fail(b.exception).always(function(){f.removeClass("loading")}))}}}); \ No newline at end of file diff --git a/blocks/myoverview/amd/build/events.min.js b/blocks/myoverview/amd/build/events.min.js new file mode 100644 index 00000000000..4c6a92ea594 --- /dev/null +++ b/blocks/myoverview/amd/build/events.min.js @@ -0,0 +1 @@ +define([],function(){return{LOADING_EVENTS:"block_myoverview:events-loading",LOADED_EVENTS:"block_myoverview:events-loaded"}}); \ No newline at end of file diff --git a/blocks/myoverview/amd/build/timeline_view_dates.min.js b/blocks/myoverview/amd/build/timeline_view_dates.min.js new file mode 100644 index 00000000000..86fb5e6c44f --- /dev/null +++ b/blocks/myoverview/amd/build/timeline_view_dates.min.js @@ -0,0 +1 @@ +define(["core/custom_interaction_events","block_myoverview/event_list"],function(a,b){var c={VIEW_MORE_BUTTON:'[data-action="view-more"]',EVENT_LIST:'[data-region="event-list"]'},d=function(a){a.each(function(){b.load(this)})};return{registerEventListeners:function(b){var e=b.find(c.EVENT_LIST);d(e),a.define(b,[a.events.activate]),b.on(a.events.activate,c.VIEW_MORE_BUTTON,function(){d(e)})}}}); \ No newline at end of file diff --git a/blocks/myoverview/lang/en/block_myoverview.php b/blocks/myoverview/lang/en/block_myoverview.php index a9bba66546d..50e4d4eb9af 100644 --- a/blocks/myoverview/lang/en/block_myoverview.php +++ b/blocks/myoverview/lang/en/block_myoverview.php @@ -22,10 +22,13 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['future'] = 'Future'; +$string['inprogress'] = 'In progress'; $string['myoverview:addinstance'] = 'Add a new my overview block'; $string['myoverview:myaddinstance'] = 'Add a new my overview block to Dashboard'; -$string['next7days'] = 'Next 7 days'; $string['next30days'] = 'Next 30 days'; +$string['next7days'] = 'Next 7 days'; +$string['past'] = 'Past'; $string['pluginname'] = 'My overview'; $string['sortbycourses'] = 'Sort by courses'; $string['sortbydates'] = 'Sort by dates'; diff --git a/blocks/myoverview/templates/courses-view.mustache b/blocks/myoverview/templates/courses-view.mustache new file mode 100644 index 00000000000..261696e5975 --- /dev/null +++ b/blocks/myoverview/templates/courses-view.mustache @@ -0,0 +1,38 @@ +{{! + 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_myoverview/courses-view + + This template renders the courses view for the myoverview block. +}} +
    +
    +
    + + + +
    +
    +
    +
    +
    From e03d5d4790806b81450198350133490521c0f5dc Mon Sep 17 00:00:00 2001 From: Ryan Wyllie Date: Tue, 3 Jan 2017 04:59:58 +0000 Subject: [PATCH 014/215] MDL-57445 core: allow context variables in pix helper Allow the user of context variables in the id and component section of the pix helper. Part of MDL-55611 epic. --- blocks/myoverview/amd/build/event_list.min.js | 2 +- lib/amd/build/templates.min.js | 2 +- lib/amd/src/templates.js | 6 +++--- lib/classes/output/mustache_pix_helper.php | 7 +++---- lib/upgrade.txt | 3 +++ 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/blocks/myoverview/amd/build/event_list.min.js b/blocks/myoverview/amd/build/event_list.min.js index 6624d85ff52..34b7b54660a 100644 --- a/blocks/myoverview/amd/build/event_list.min.js +++ b/blocks/myoverview/amd/build/event_list.min.js @@ -1 +1 @@ -define(["jquery","core/notification","core/templates","block_myoverview/events","block_myoverview/calendar_events_repository"],function(a,b,c,d,e){return{load:function(f){f=a(f);var g=+f.attr("data-start-day"),h=+f.attr("data-end-day"),i=+f.attr("data-limit"),j=+f.attr("data-offset");return f.hasClass("loading")?a.Deferred().resolve():(f.addClass("loading"),f.trigger(d.LOADING_EVENTS),e.query_for_user_by_days(g,h,i,j).then(function(a){return f.trigger(d.LOADED_EVENTS,[{events:a}]),f.attr("data-offset",j+a.length),a}).then(function(a){return c.render("block_myoverview/event-list-items",{events:a}).done(function(a,b){c.appendNodeContents(f,a,b)})}).fail(b.exception).always(function(){f.removeClass("loading")}))}}}); \ No newline at end of file +define(["jquery","core/notification","core/templates","block_myoverview/calendar_events_repository"],function(a,b,c,d){return{load:function(e){e=a(e);var f=+e.attr("data-start-day"),g=+e.attr("data-end-day"),h=+e.attr("data-limit"),i=+e.attr("data-offset");return e.hasClass("loading")?a.Deferred().resolve():(e.addClass("loading"),d.query_for_user_by_days(f,g,h,i).then(function(a){if(e.attr("data-offset",i+a.length),a.length)return c.render("block_myoverview/event-list-items",{events:a}).done(function(a,b){c.appendNodeContents(e,a,b)})}).fail(b.exception).always(function(){e.removeClass("loading")}))}}}); \ No newline at end of file diff --git a/lib/amd/build/templates.min.js b/lib/amd/build/templates.min.js index 87d6ada6701..c465c9abf72 100644 --- a/lib/amd/build/templates.min.js +++ b/lib/amd/build/templates.min.js @@ -1 +1 @@ -define(["core/mustache","jquery","core/ajax","core/str","core/notification","core/url","core/config","core/localstorage","core/icon_system","core/event","core/yui","core/log","core/truncate","core/user_date"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){var o=0,p={},q={},r={},s=function(){this.requiredStrings=[],this.requiredJS=[],this.requiredDates=[],this.currentThemeName=""};s.prototype.requiredStrings=null,s.prototype.requiredDates=[],s.prototype.requiredJS=null,s.prototype.currentThemeName="",s.prototype.getTemplate=function(a){var d=a.split("/"),e=d.shift(),f=d.shift(),g=this.currentThemeName+"/"+a;if(g in q)return q[g];var i=h.get("core_template/"+g);if(i)return p[g]=i,q[g]=b.Deferred().resolve(i).promise(),q[g];var j=c.call([{methodname:"core_output_load_template",args:{component:e,template:f,themename:this.currentThemeName}}],!0,!1);return q[g]=j[0].then(function(a){return p[g]=a,h.set("core_template/"+g,a),a}),q[g]},s.prototype.partialHelper=function(a){var b=this.currentThemeName+"/"+a;return b in p||e.exception(new Error("Failed to pre-fetch the template: "+a)),p[b]},s.prototype.renderIcon=function(a,c,d){var e=g.iconsystemmodule,f=b.Deferred();return require([e],function(a){var b=new a;b instanceof i?(r=b,b.init().then(f.resolve)):f.reject("Invalid icon system specified"+g.iconsystemmodule)}),f.then(function(a){return this.getTemplate(a.getTemplateName())}.bind(this)).then(function(b){return r.renderIcon(a,c,d,b)})},s.prototype.pixHelper=function(a,b,c){var d=b.split(","),e="",f="",g="";d.length>0&&(e=c(d.shift().trim())),d.length>0&&(f=c(d.shift().trim())),d.length>0&&(g=c(d.join(",").trim()));var h=r.getTemplateName(),i=this.currentThemeName+"/"+h,j=p[i];return r.renderIcon(e,f,g,j)},s.prototype.jsHelper=function(a,b,c){return this.requiredJS.push(c(b,a)),""},s.prototype.stringHelper=function(a,b,c){var d=b.split(","),e="",f="",g="";d.length>0&&(e=d.shift().trim()),d.length>0&&(f=d.shift().trim()),d.length>0&&(g=d.join(",").trim()),""!==g&&(g=c(g,a)),0===g.indexOf("{")&&0!==g.indexOf("{{")&&(g=JSON.parse(g));var h=this.requiredStrings.length;return this.requiredStrings.push({key:e,component:f,param:g}),"[[_s"+h+"]]"},s.prototype.quoteHelper=function(a,b,c){var d=c(b.trim(),a);return d=d.replace('"','\\"').replace(/([\{\}]{2,3})/g,"{{=<% %>=}}$1<%={{ }}=%>"),'"'+d+'"'},s.prototype.shortenTextHelper=function(a,b,c){var d=/(.*?),(.*)/,e=b.match(d),f=e[1].trim(),g=e[2].trim(),h=c(g,a);return m.truncate(h,{length:f,words:!0,ellipsis:"..."})},s.prototype.userDateHelper=function(a,b,c){var d=/(.*?),(.*)/,e=b.match(d),f=c(e[1].trim(),a),g=c(e[2].trim(),a),h=this.requiredDates.length;return this.requiredDates.push({timestamp:f,format:g}),"[[_t_"+h+"]]"},s.prototype.addHelpers=function(a,b){this.currentThemeName=b,this.requiredStrings=[],this.requiredJS=[],a.uniqid=o++,a.str=function(){return this.stringHelper.bind(this,a)}.bind(this),a.pix=function(){return this.pixHelper.bind(this,a)}.bind(this),a.js=function(){return this.jsHelper.bind(this,a)}.bind(this),a.quote=function(){return this.quoteHelper.bind(this,a)}.bind(this),a.shortentext=function(){return this.shortenTextHelper.bind(this,a)}.bind(this),a.userdate=function(){return this.userDateHelper.bind(this,a)}.bind(this),a.globals={config:g},a.currentTheme=b},s.prototype.getJS=function(){var a="";return this.requiredJS.length>0&&(a=this.requiredJS.join(";\n")),a},s.prototype.treatStringsInContent=function(a,b){var c,d,e,f,g,h,i=/\[\[_s\d+\]\]/;do{for(c="",d=a.search(i);d>-1;){c+=a.substring(0,d),a=a.substr(d),e="",f=4,g=a.substr(f,1);do e+=g,f++,g=a.substr(f,1);while("]"!=g);h=b[parseInt(e,10)],"undefined"==typeof h&&(l.debug("Could not find string for pattern [[_s"+e+"]]."),h=""),c+=h,a=a.substr(6+e.length),d=a.search(i)}a=c+a,d=a.search(i)}while(d>-1);return a},s.prototype.treatDatesInContent=function(a,b){return b.forEach(function(b,c){var d="\\[\\[_t_"+c+"\\]\\]",e=new RegExp(d,"g");a=a.replace(e,b)}),a},s.prototype.doRender=function(c,e,f){this.currentThemeName=f;var g=r.getTemplateName();return this.getTemplate(g).then(function(){this.addHelpers(e,f);var d=a.render(c,e,this.partialHelper.bind(this));return b.Deferred().resolve(d.trim(),this.getJS()).promise()}.bind(this)).then(function(a,c){return this.requiredStrings.length>0?d.get_strings(this.requiredStrings).then(function(d){return this.requiredDates=this.requiredDates.map(function(a){return{timestamp:this.treatStringsInContent(a.timestamp,d),format:this.treatStringsInContent(a.format,d)}}.bind(this)),a=this.treatStringsInContent(a,d),c=this.treatStringsInContent(c,d),b.Deferred().resolve(a,c).promise()}.bind(this)):b.Deferred().resolve(a,c).promise()}.bind(this)).then(function(a,c){return this.requiredDates.length>0?n.get(this.requiredDates).then(function(d){return a=this.treatDatesInContent(a,d),c=this.treatDatesInContent(c,d),b.Deferred().resolve(a,c).promise()}.bind(this)):b.Deferred().resolve(a,c).promise()}.bind(this))};var t=function(a){if(""!==a.trim()){var c=b("