From 41b46256934af94a61671b345ced4e85564496f1 Mon Sep 17 00:00:00 2001 From: Ferran Recio Date: Wed, 15 Sep 2021 15:35:15 +0200 Subject: [PATCH] MDL-72578 course: activity render to output classes --- availability/classes/info.php | 3 +- .../site_main_menu/block_site_main_menu.php | 63 +++++-- .../block_social_activities.php | 55 ++++-- course/classes/output/course_module_name.php | 5 + course/format/classes/base.php | 2 +- .../output/local/content/{section => }/cm.php | 135 +++++++++++-- .../output/local/content/cm/availability.php | 161 ++++++++++++++++ .../output/local/content/cm/cmname.php | 159 ++++++++++++++++ .../output/local/content/cm/controlmenu.php | 174 +++++++++++++++++ .../classes/output/local/content/cm/title.php | 127 +++++++++++++ .../local/content/section/availability.php | 65 +++++-- .../output/local/content/section/cmitem.php | 2 +- .../format/classes/output/local/state/cm.php | 5 +- .../templates/local/content/cm.mustache | 27 ++- .../local/content/cm/availability.mustache | 48 +++++ .../local/content/cm/cmname.mustache | 38 ++++ .../local/content/cm/controlmenu.mustache | 35 ++++ .../templates/local/content/cm/title.mustache | 51 +++++ .../content/section/availability.mustache | 22 ++- course/lib.php | 2 +- course/renderer.php | 177 ++++++++++-------- course/upgrade.txt | 8 + lib/templates/availability_info.mustache | 2 + 23 files changed, 1207 insertions(+), 159 deletions(-) rename course/format/classes/output/local/content/{section => }/cm.php (53%) create mode 100644 course/format/classes/output/local/content/cm/availability.php create mode 100644 course/format/classes/output/local/content/cm/cmname.php create mode 100644 course/format/classes/output/local/content/cm/controlmenu.php create mode 100644 course/format/classes/output/local/content/cm/title.php create mode 100644 course/format/templates/local/content/cm/availability.mustache create mode 100644 course/format/templates/local/content/cm/cmname.mustache create mode 100644 course/format/templates/local/content/cm/controlmenu.mustache create mode 100644 course/format/templates/local/content/cm/title.mustache diff --git a/availability/classes/info.php b/availability/classes/info.php index 25fb076a2a2..fc00fae5b07 100644 --- a/availability/classes/info.php +++ b/availability/classes/info.php @@ -232,7 +232,8 @@ abstract class info { * @return bool True if activity is available for all */ public function is_available_for_all() { - if (is_null($this->availability)) { + global $CFG; + if (is_null($this->availability) || !empty($CFG->enableavailability)) { return true; } else { try { diff --git a/blocks/site_main_menu/block_site_main_menu.php b/blocks/site_main_menu/block_site_main_menu.php index a0de2d1a755..299bb29cc86 100644 --- a/blocks/site_main_menu/block_site_main_menu.php +++ b/blocks/site_main_menu/block_site_main_menu.php @@ -48,12 +48,19 @@ class block_site_main_menu extends block_list { } $course = get_site(); + $format = course_get_format($course); + $courserenderer = $format->get_renderer($this->page); + require_once($CFG->dirroot.'/course/lib.php'); + $context = context_course::instance($course->id); $isediting = $this->page->user_is_editing() && has_capability('moodle/course:manageactivities', $context); - $courserenderer = $this->page->get_renderer('core', 'course'); -/// extra fast view mode + // Output classes. + $cmnameclass = $format->get_output_classname('content\\cm\\cmname'); + $controlmenuclass = $format->get_output_classname('content\\cm\\controlmenu'); + + // Extra fast view mode. if (!$isediting) { $modinfo = get_fast_modinfo($course); if (!empty($modinfo->sections[0])) { @@ -69,13 +76,17 @@ class block_site_main_menu extends block_list { $indent = ''; } - if (!empty($cm->url)) { - $content = html_writer::div($courserenderer->course_section_cm_name($cm), 'activity'); + if (empty($cm->url)) { + $content = html_writer::div( + $cm->get_formatted_content(['overflowdiv' => true, 'noclean' => true]), + 'contentwithoutlink' + ); } else { - $content = $courserenderer->course_section_cm_text($cm); + $cmname = new $cmnameclass($format, $cm->get_section_info(), $cm, $isediting); + $content = $courserenderer->render($cmname); } - $this->content->items[] = $indent . html_writer::div($content, 'main-menu-content'); + $this->content->items[] = $indent . html_writer::div($content, 'main-menu-content activity'); } } return $this->content; @@ -106,18 +117,28 @@ class block_site_main_menu extends block_list { continue; } if (!$ismoving) { - $actions = course_get_cm_edit_actions($mod, $mod->indent); - // Prepend list of actions with the 'move' action. - $actions = array('move' => new action_menu_link_primary( - new moodle_url('/course/mod.php', array('sesskey' => sesskey(), 'copy' => $mod->id)), - new pix_icon('t/move', $strmove, 'moodle', array('class' => 'iconsmall', 'title' => '')), - $strmove - )) + $actions; + $controlmenu = new $controlmenuclass( + $format, + $mod->get_section_info(), + $mod + ); - $editbuttons = html_writer::tag('div', - $courserenderer->course_section_cm_edit_actions($actions, $mod, array('donotenhance' => true)), - array('class' => 'buttons') + $menu = $controlmenu->get_action_menu(); + + // Add a move primary action. + $menu->add( + new action_menu_link_primary( + new moodle_url('/course/mod.php', ['sesskey' => sesskey(), 'copy' => $mod->id]), + new pix_icon('t/move', $strmove, 'moodle', ['class' => 'iconsmall', 'title' => '']), + $strmove + ) + ); + + $editbuttons = html_writer::tag( + 'div', + $courserenderer->render($controlmenu), + ['class' => 'buttons'] ); } else { $editbuttons = ''; @@ -138,9 +159,13 @@ class block_site_main_menu extends block_list { $indent = ''; } if (!$mod->url) { - $content = $courserenderer->course_section_cm_text($mod); + $content = html_writer::div( + $mod->get_formatted_content(['overflowdiv' => true, 'noclean' => true]), + 'contentwithoutlink' + ); } else { - $content = html_writer::div($courserenderer->course_section_cm_name($mod), ' activity'); + $cmname = new $cmnameclass($format, $mod->get_section_info(), $mod, $isediting); + $content = html_writer::div($courserenderer->render($cmname), 'activity'); } $this->content->items[] = $indent . html_writer::div($content . $editbuttons, 'main-menu-content'); } @@ -159,5 +184,3 @@ class block_site_main_menu extends block_list { return $this->content; } } - - diff --git a/blocks/social_activities/block_social_activities.php b/blocks/social_activities/block_social_activities.php index 35c651b94fe..4f5a085a1fb 100644 --- a/blocks/social_activities/block_social_activities.php +++ b/blocks/social_activities/block_social_activities.php @@ -48,7 +48,8 @@ class block_social_activities extends block_list { } $course = $this->page->course; - $courserenderer = $this->page->get_renderer('core', 'course'); + $format = course_get_format($course); + $courserenderer = $format->get_renderer($this->page); require_once($CFG->dirroot.'/course/lib.php'); @@ -56,7 +57,11 @@ class block_social_activities extends block_list { $isediting = $this->page->user_is_editing() && has_capability('moodle/course:manageactivities', $context); $modinfo = get_fast_modinfo($course); -/// extra fast view mode + // Output classes. + $cmnameclass = $format->get_output_classname('content\\cm\\cmname'); + $controlmenuclass = $format->get_output_classname('content\\cm\\controlmenu'); + + // Extra fast view mode. if (!$isediting) { if (!empty($modinfo->sections[0])) { foreach($modinfo->sections[0] as $cmid) { @@ -66,18 +71,21 @@ class block_social_activities extends block_list { } if (!$cm->url) { - $content = $courserenderer->course_section_cm_text($cm); + $content = html_writer::div( + $cm->get_formatted_content(['overflowdiv' => true, 'noclean' => true]), + 'contentwithoutlink' + ); $this->content->items[] = $content; $this->content->icons[] = ''; } else { - $this->content->items[] = html_writer::div($courserenderer->course_section_cm_name($cm), 'activity'); + $cmname = new $cmnameclass($format, $cm->get_section_info(), $cm, $isediting); + $this->content->items[] = html_writer::div($courserenderer->render($cmname), 'activity'); } } } return $this->content; } - // Slow & hacky editing mode. $ismoving = ismoving($course->id); $section = $modinfo->get_section_info(0); @@ -102,18 +110,28 @@ class block_social_activities extends block_list { continue; } if (!$ismoving) { - $actions = course_get_cm_edit_actions($mod, -1); - // Prepend list of actions with the 'move' action. - $actions = array('move' => new action_menu_link_primary( - new moodle_url('/course/mod.php', array('sesskey' => sesskey(), 'copy' => $mod->id)), - new pix_icon('t/move', $strmove, 'moodle', array('class' => 'iconsmall', 'title' => '')), - $strmove - )) + $actions; + $controlmenu = new $controlmenuclass( + $format, + $mod->get_section_info(), + $mod, + ['disableindentation' => true] + ); + + $menu = $controlmenu->get_action_menu(); + + // Add a move primary action. + $menu->add( + new action_menu_link_primary( + new moodle_url('/course/mod.php', ['sesskey' => sesskey(), 'copy' => $mod->id]), + new pix_icon('t/move', $strmove, 'moodle', ['class' => 'iconsmall', 'title' => '']), + $strmove + ) + ); $editbuttons = html_writer::tag('div', - $courserenderer->course_section_cm_edit_actions($actions, $mod, array('donotenhance' => true)), - array('class' => 'buttons') + $courserenderer->render($controlmenu), + ['class' => 'buttons'] ); } else { $editbuttons = ''; @@ -129,12 +147,15 @@ class block_social_activities extends block_list { $this->content->icons[] = ''; } if (!$mod->url) { - $content = $courserenderer->course_section_cm_text($mod); + $content = html_writer::div( + $mod->get_formatted_content(['overflowdiv' => true, 'noclean' => true]), + 'contentwithoutlink' + ); $this->content->items[] = $content . $editbuttons; $this->content->icons[] = ''; } else { - $this->content->items[] = html_writer::div($courserenderer->course_section_cm_name($mod), 'activity') . - $editbuttons; + $cmname = new $cmnameclass($format, $mod->get_section_info(), $mod, $isediting); + $this->content->items[] = html_writer::div($courserenderer->render($cmname), 'activity') . $editbuttons; } } } diff --git a/course/classes/output/course_module_name.php b/course/classes/output/course_module_name.php index 709846c4e71..57a45c2c903 100644 --- a/course/classes/output/course_module_name.php +++ b/course/classes/output/course_module_name.php @@ -31,6 +31,7 @@ use cm_info; /** * Class to prepare a course module name for display and in-place editing * + * @deprecated since Moodle 4.0 * @package core_course * @copyright 2016 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later @@ -51,6 +52,10 @@ class course_module_name extends \core\output\inplace_editable { * @param array $displayoptions */ public function __construct(cm_info $cm, $editable, $displayoptions = array()) { + debugging( + 'course_section_cm_list is deprecated. Use core_courseformat\\output\\local\\cm\\cmname instead', + DEBUG_DEVELOPER + ); $this->cm = $cm; $this->displayoptions = $displayoptions; $value = $cm->name; diff --git a/course/format/classes/base.php b/course/format/classes/base.php index 63a05e13c01..f82495e8574 100644 --- a/course/format/classes/base.php +++ b/course/format/classes/base.php @@ -1109,7 +1109,7 @@ abstract class base { } /** - * Returns instance of output compornent used by this plugin + * Returns instance of output component used by this plugin * * @throws coding_exception if the format class does not extends the original core one. * @param string $outputname the element to render (section, activity...) diff --git a/course/format/classes/output/local/content/section/cm.php b/course/format/classes/output/local/content/cm.php similarity index 53% rename from course/format/classes/output/local/content/section/cm.php rename to course/format/classes/output/local/content/cm.php index c17d30fe25a..fe6d71b0da1 100644 --- a/course/format/classes/output/local/content/section/cm.php +++ b/course/format/classes/output/local/content/cm.php @@ -22,7 +22,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -namespace core_courseformat\output\local\content\section; +namespace core_courseformat\output\local\content; use cm_info; use core\activity_dates; @@ -33,6 +33,7 @@ use renderable; use section_info; use stdClass; use templatable; +use \core_availability\info_module; /** * Base class to render a course module inside a course format. @@ -55,6 +56,21 @@ class cm implements renderable, templatable { /** @var array optional display options */ protected $displayoptions; + /** @var string activity link css classes */ + protected $linkclasses = null; + + /** @var string text css classes */ + protected $textclasses = null; + + /** @var string the activity name output class name */ + protected $cmnameclass; + + /** @var string the activity control menu class name */ + protected $controlmenuclass; + + /** @var string the activity availability class name */ + protected $availabilityclass; + /** * Constructor. * @@ -68,6 +84,13 @@ class cm implements renderable, templatable { $this->section = $section; $this->mod = $mod; $this->displayoptions = $displayoptions; + + $this->load_classes(); + + // Get the necessary classes. + $this->cmnameclass = $format->get_output_classname('content\\cm\\cmname'); + $this->controlmenuclass = $format->get_output_classname('content\\cm\\controlmenu'); + $this->availabilityclass = $format->get_output_classname('content\\cm\\availability'); } /** @@ -80,6 +103,7 @@ class cm implements renderable, templatable { global $USER; $format = $this->format; + $section = $this->section; $mod = $this->mod; $displayoptions = $this->displayoptions; $course = $mod->get_course(); @@ -94,6 +118,12 @@ class cm implements renderable, templatable { $activitydates = activity_dates::get_dates_for_module($mod, $USER->id); } + $displayoptions['linkclasses'] = $this->get_link_classes(); + $displayoptions['textclasses'] = $this->get_text_classes(); + + // Grouping activity. + $groupinglabel = $mod->get_grouping_label($displayoptions['textclasses']); + $activityinfodata = null; // - There are activity dates to be shown; or // - Completion info needs to be displayed @@ -107,13 +137,32 @@ class cm implements renderable, templatable { $activityinfodata = $activityinfo->export_for_template($output); } + // Mod inplace name editable. + $cmname = new $this->cmnameclass( + $format, + $this->section, + $mod, + $format->show_editor(), + $this->displayoptions + ); + + // Mod availability. + $availability = new $this->availabilityclass( + $format, + $this->section, + $mod, + $this->displayoptions + ); + $data = (object)[ - 'cmname' => $output->course_section_cm_name($mod, $displayoptions), + 'cmname' => $cmname->export_for_template($output), + 'grouping' => $groupinglabel, 'afterlink' => $mod->afterlink, - 'altcontent' => $output->course_section_cm_text($mod, $displayoptions), - 'availability' => $output->course_section_cm_availability($mod, $displayoptions), + 'altcontent' => $mod->get_formatted_content(['overflowdiv' => true, 'noclean' => true]), + 'modavailability' => $availability->export_for_template($output), 'url' => $mod->url, 'activityinfo' => $activityinfodata, + 'textclasses' => $displayoptions['textclasses'], ]; if (!empty($mod->indent)) { @@ -131,22 +180,80 @@ class cm implements renderable, templatable { } $returnsection = $format->get_section_number(); - $data->extras = []; + if ($format->show_editor()) { // Edit actions. - $editactions = course_get_cm_edit_actions($mod, $mod->indent, $returnsection); - $data->extras[] = $output->course_section_cm_edit_actions($editactions, $mod, $displayoptions); - if (!empty($mod->afterediticons)) { - $data->extras[] = $mod->afterediticons; - } + $controlmenu = new $this->controlmenuclass( + $format, + $this->section, + $mod, + $this->displayoptions + ); + $data->controlmenu = $controlmenu->export_for_template($output); + // Move and select options. $data->moveicon = course_get_cm_move($mod, $returnsection); } - if (!empty($data->extras)) { - $data->hasextras = true; - } - return $data; } + + /** + * Returns the CSS classes for the activity name/content + * + * For items which are hidden, unavailable or stealth but should be displayed + * to current user ($mod->is_visible_on_course_page()), we show those as dimmed. + * Students will also see as dimmed activities names that are not yet available + * but should still be displayed (without link) with availability info. + */ + protected function load_classes() { + + $mod = $this->mod; + + $linkclasses = ''; + $textclasses = ''; + if ($mod->uservisible) { + $info = new info_module($mod); + $conditionalhidden = !$info->is_available_for_all(); + $accessiblebutdim = (!$mod->visible || $conditionalhidden) && + has_capability('moodle/course:viewhiddenactivities', $mod->context); + if ($accessiblebutdim) { + $linkclasses .= ' dimmed'; + $textclasses .= ' dimmed_text'; + if ($conditionalhidden) { + $linkclasses .= ' conditionalhidden'; + $textclasses .= ' conditionalhidden'; + } + } + if ($mod->is_stealth()) { + // Stealth activity is the one that is not visible on course page. + // It still may be displayed to the users who can manage it. + $linkclasses .= ' stealth'; + $textclasses .= ' stealth'; + } + } else { + $linkclasses .= ' dimmed'; + $textclasses .= ' dimmed dimmed_text'; + } + $this->linkclasses = $linkclasses; + $this->textclasses = $textclasses; + } + + /** + * Get the activity link classes. + * + * @return string the activity link classes. + */ + public function get_link_classes(): string { + return $this->linkclasses; + } + + /** + * Get the activity text/description classes. + * + * @return string the activity text classes. + */ + public function get_text_classes(): string { + return $this->textclasses; + } } diff --git a/course/format/classes/output/local/content/cm/availability.php b/course/format/classes/output/local/content/cm/availability.php new file mode 100644 index 00000000000..06dc765fa34 --- /dev/null +++ b/course/format/classes/output/local/content/cm/availability.php @@ -0,0 +1,161 @@ +. + +/** + * Contains the default activity availability information. + * + * @package core_courseformat + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_courseformat\output\local\content\cm; + +use core_courseformat\output\local\content\section\availability as section_avalability; +use cm_info; +use core_courseformat\base as course_format; +use section_info; +use stdClass; +use core_availability\info_module; +use core_availability\info; + +/** + * Base class to render a course module availability inside a course format. + * + * @package core_courseformat + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class availability extends section_avalability { + + /** @var course_format the course format */ + protected $format; + + /** @var section_info the section object */ + protected $section; + + /** @var cm_info the course module instance */ + protected $mod; + + /** @var array optional display options */ + protected $displayoptions; + + /** + * Constructor. + * + * @param course_format $format the course format + * @param section_info $section the section info + * @param cm_info $mod the course module ionfo + * @param array $displayoptions optional extra display options + */ + public function __construct(course_format $format, section_info $section, cm_info $mod, array $displayoptions = []) { + $this->format = $format; + $this->section = $section; + $this->mod = $mod; + $this->displayoptions = $displayoptions; + } + + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param \renderer_base $output typically, the renderer that's calling this function + * @return stdClass data context for a mustache template + */ + public function export_for_template(\renderer_base $output): stdClass { + + $data = (object)[ + 'info' => $this->get_info($output), + ]; + + if (!empty($data->info)) { + $data->hasmodavailability = true; + } + + return $data; + } + + /** + * Get the availability HTML form the course renderer. + * + * @param \renderer_base $output typically, the renderer that's calling this function + * @return string the availability HTML + */ + protected function get_info(\renderer_base $output): array { + global $CFG; + + $format = $this->format; + $mod = $this->mod; + $section = $this->section; + + $info = []; + + if (!$mod->is_visible_on_course_page()) { + // Nothing to be displayed to the user. + return $info; + } + + if (!$mod->uservisible) { + // This is a student who is not allowed to see the module but might be allowed + // to see availability info (i.e. "Available from ..."). + if (!empty($mod->availableinfo)) { + $formattedinfo = \core_availability\info::format_info( + $mod->availableinfo, + $mod->get_course() + ); + $info[] = $this->availability_info($formattedinfo, 'isrestricted'); + } + return $info; + } + + // This is a teacher who is allowed to see module but still should see the + // information that module is not available to all/some students. + $modcontext = $mod->context; + $canviewhidden = has_capability('moodle/course:viewhiddenactivities', $modcontext); + if ($canviewhidden && !$mod->visible) { + // This module is hidden but current user has capability to see it. + // Do not display the availability info if the whole section is hidden. + if ($section->visible) { + $info[] = $this->availability_info(get_string('hiddenfromstudents'), 'ishidden'); + } + } else if ($mod->is_stealth()) { + // This module is available but is normally not displayed on the course page + // (this user can see it because they can manage it). + $info[] = $this->availability_info(get_string('hiddenoncoursepage'), 'isstealth'); + } + + if ($canviewhidden && !empty($CFG->enableavailability)) { + // Display information about conditional availability. + // Don't add availability information if user is not editing and activity is hidden. + if ($mod->visible || $format->show_editor()) { + $hidinfoclass = 'isrestricted isfullinfo'; + if (!$mod->visible) { + $hidinfoclass .= ' hide'; + } + $ci = new info_module($mod); + $fullinfo = $ci->get_full_information(); + if ($fullinfo) { + $formattedinfo = info::format_info( + $fullinfo, + $mod->get_course() + ); + $info[] = $this->availability_info($formattedinfo, $hidinfoclass); + } + } + } + + return $info; + } +} diff --git a/course/format/classes/output/local/content/cm/cmname.php b/course/format/classes/output/local/content/cm/cmname.php new file mode 100644 index 00000000000..7ab70dce111 --- /dev/null +++ b/course/format/classes/output/local/content/cm/cmname.php @@ -0,0 +1,159 @@ +. + +/** + * Contains the default activity name inplace editable. + * + * @package core_courseformat + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_courseformat\output\local\content\cm; + +use cm_info; +use core_courseformat\base as course_format; +use section_info; +use stdClass; +use context_module; +use lang_string; +use external_api; +use core\output\inplace_editable; + +/** + * Base class to render a course module inplace editable header. + * + * @package core_courseformat + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class cmname extends inplace_editable { + + /** @var course_format the course format */ + protected $format; + + /** @var section_info the section object */ + private $section; + + /** @var cm_info the course module instance */ + protected $mod; + + /** @var editable if the title is editable */ + protected $editable; + + /** @var array optional display options */ + protected $displayoptions; + + /** @var string the activity title output class name */ + protected $titleclass; + + /** + * Constructor. + * + * @param course_format $format the course format + * @param section_info $section the section info + * @param cm_info $mod the course module ionfo + * @param bool $editable if it is editable + * @param array $displayoptions optional extra display options + */ + public function __construct( + course_format $format, + section_info $section, + cm_info $mod, + bool $editable, + array $displayoptions = [] + ) { + $this->format = $format; + $this->section = $section; + $this->mod = $mod; + $this->displayoptions = $displayoptions; + + $this->editable = $editable && has_capability( + 'moodle/course:manageactivities', + $mod->context + ); + + // Get the necessary classes. + $this->titleclass = $format->get_output_classname('content\\cm\\title'); + + // Setup inplace editable. + parent::__construct( + 'core_course', + 'activityname', + $mod->id, + $this->editable, + $mod->name, + $mod->name, + new lang_string('edittitle'), + new lang_string('newactivityname', '', $mod->get_formatted_name()) + ); + } + + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param \renderer_base $output typically, the renderer that's calling this function + * @return stdClass data context for a mustache template + */ + public function export_for_template(\renderer_base $output): array { + global $PAGE; + + // Inplace editable uses core renderer by default. However, course elements require + // the format specific renderer. + $courseoutput = $this->format->get_renderer($PAGE); + + // Inplace editable uses pre-rendered elements and does not allow line beaks in the UI value. + $title = new $this->titleclass( + $this->format, + $this->section, + $this->mod, + $this->displayoptions + ); + $this->displayvalue = str_replace("\n", "", $courseoutput->render($title)); + + if (trim($this->displayvalue) == '') { + $this->editable = false; + } + $data = parent::export_for_template($output); + + return $data; + } + + /** + * Updates course module name + * + * @param int $itemid course module id + * @param string $newvalue new name + * @return static + */ + public static function update($itemid, $newvalue) { + $context = context_module::instance($itemid); + // Check access. + external_api::validate_context($context); + require_capability('moodle/course:manageactivities', $context); + + // Trim module name and Update value. + set_coursemodule_name($itemid, trim($newvalue)); + $coursemodulerecord = get_coursemodule_from_id('', $itemid, 0, false, MUST_EXIST); + // Return instance. + $modinfo = get_fast_modinfo($coursemodulerecord->course); + $cm = $modinfo->get_cm($itemid); + $section = $modinfo->get_section_info($cm->sectionnum); + + $format = course_get_format($cm->course); + return new static($format, $section, $cm, true); + } +} diff --git a/course/format/classes/output/local/content/cm/controlmenu.php b/course/format/classes/output/local/content/cm/controlmenu.php new file mode 100644 index 00000000000..35720d7712a --- /dev/null +++ b/course/format/classes/output/local/content/cm/controlmenu.php @@ -0,0 +1,174 @@ +. + +/** + * Contains the default activity control menu. + * + * @package core_courseformat + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_courseformat\output\local\content\cm; + +use cm_info; +use core_courseformat\base as course_format; +use renderable; +use section_info; +use stdClass; +use templatable; +use action_menu; +use action_menu_link; + +/** + * Base class to render a course module menu inside a course format. + * + * @package core_courseformat + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class controlmenu implements renderable, templatable { + + /** @var course_format the course format */ + protected $format; + + /** @var section_info the section object */ + private $section; + + /** @var action_menu the activity aciton menu */ + protected $menu; + + /** @var cm_info the course module instance */ + protected $mod; + + /** @var array optional display options */ + protected $displayoptions; + + /** + * Constructor. + * + * @param course_format $format the course format + * @param section_info $section the section info + * @param cm_info $mod the course module ionfo + * @param array $displayoptions optional extra display options + */ + public function __construct(course_format $format, section_info $section, cm_info $mod, array $displayoptions = []) { + $this->format = $format; + $this->section = $section; + $this->mod = $mod; + $this->displayoptions = $displayoptions; + } + + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param \renderer_base $output typically, the renderer that's calling this function + * @return stdClass data context for a mustache template + */ + public function export_for_template(\renderer_base $output): stdClass { + + $mod = $this->mod; + + $menu = $this->get_action_menu(); + + if (empty($menu)) { + return new stdClass(); + } + + $data = (object)[ + 'menu' => $menu->export_for_template($output), + 'hasmenu' => true, + 'id' => $mod->id, + ]; + + // After icons. + if (!empty($mod->afterediticons)) { + $data->afterediticons = $mod->afterediticons; + } + + return $data; + } + + /** + * Generate the aciton menu element. + * + * This method is public in case some block needs to modify the menu before output it. + * + * @return aciton_menu the activity action menu + */ + public function get_action_menu(): ?action_menu { + + if (!empty($this->menu)) { + return $this->menu; + } + + $mod = $this->mod; + + $controls = $this->cm_control_items(); + + if (empty($controls)) { + return null; + } + + // Convert control array into an action_menu. + $menu = new action_menu(); + $menu->set_alignment(action_menu::TR, action_menu::BR); + $menu->set_menu_trigger(get_string('edit')); + + $menu->attributes['class'] .= ' section-cm-edit-actions commands'; + + // Prioritise the menu ahead of all other actions. + $menu->prioritise = true; + + $ownerselector = $displayoptions['ownerselector'] ?? '#module-' . $mod->id; + $menu->set_owner_selector($ownerselector); + + $constraint = $displayoptions['constraintselector'] ?? '.course-content'; + $menu->set_constraint($constraint); + + foreach ($controls as $control) { + if ($control instanceof action_menu_link) { + $control->add_class('cm-edit-action'); + } + $menu->add($control); + } + + $this->menu = $menu; + + return $menu; + } + + /** + * Generate the edit control items of a course module. + * + * This method uses course_get_cm_edit_actions function to get the cm actions. + * However, format plugins can override the method to add or remove elements + * from the menu. + * + * @return array of edit control items + */ + protected function cm_control_items() { + $format = $this->format; + $mod = $this->mod; + $sectionreturn = $format->get_section_number(); + if (!empty($this->displayoptions['disableindentation'])) { + $indent = -1; + } else { + $indent = $mod->indent; + } + return course_get_cm_edit_actions($mod, $indent, $sectionreturn); + } +} diff --git a/course/format/classes/output/local/content/cm/title.php b/course/format/classes/output/local/content/cm/title.php new file mode 100644 index 00000000000..8b98b778263 --- /dev/null +++ b/course/format/classes/output/local/content/cm/title.php @@ -0,0 +1,127 @@ +. + +/** + * Contains the default activity title. + * + * This class is usually rendered inside the cmname inplace editable. + * + * @package core_courseformat + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_courseformat\output\local\content\cm; + +use cm_info; +use core_courseformat\base as course_format; +use renderable; +use section_info; +use stdClass; +use templatable; +use core_text; + +/** + * Base class to render a course module title inside a course format. + * + * @package core_courseformat + * @copyright 2020 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class title implements renderable, templatable { + + /** @var course_format the course format */ + protected $format; + + /** @var section_info the section object */ + private $section; + + /** @var cm_info the course module instance */ + protected $mod; + + /** @var array optional display options */ + protected $displayoptions; + + /** + * Constructor. + * + * @param course_format $format the course format + * @param section_info $section the section info + * @param cm_info $mod the course module ionfo + * @param array $displayoptions optional extra display options + */ + public function __construct(course_format $format, section_info $section, cm_info $mod, array $displayoptions = []) { + $this->format = $format; + $this->section = $section; + $this->mod = $mod; + $this->displayoptions = $displayoptions; + } + + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param \renderer_base $output typically, the renderer that's calling this function + * @return stdClass data context for a mustache template + */ + public function export_for_template(\renderer_base $output): stdClass { + + $format = $this->format; + $mod = $this->mod; + $displayoptions = $this->displayoptions; + + if (!$mod->is_visible_on_course_page() || !$mod->url) { + // Nothing to be displayed to the user. + return new stdClass(); + } + + // Usually classes are loaded in the main cm output. However when the user uses the inplace editor + // the cmname output does not calculate the css classes. + if (!isset($displayoptions['linkclasses']) || !isset($displayoptions['textclasses'])) { + $cmclass = $format->get_output_classname('content\\cm'); + $cmoutput = new $cmclass( + $format, + $this->section, + $mod, + $displayoptions + ); + $displayoptions['linkclasses'] = $cmoutput->get_link_classes(); + $displayoptions['textclasses'] = $cmoutput->get_text_classes(); + } + + $data = (object)[ + 'url' => $mod->url, + 'instancename' => $mod->get_formatted_name(), + 'uservisible' => $mod->uservisible, + 'icon' => $mod->get_icon_url(), + 'linkclasses' => $displayoptions['linkclasses'], + 'textclasses' => $displayoptions['textclasses'], + ]; + + // File type after name, for alphabetic lists (screen reader). + if (strpos( + core_text::strtolower($data->instancename), + core_text::strtolower($mod->modfullname) + ) === false) { + $data->altname = get_accesshide(' ' . $mod->modfullname); + } + + // Get on-click attribute value if specified and decode the onclick - it + // has already been encoded for display (puke). + $data->onclick = htmlspecialchars_decode($mod->onclick, ENT_QUOTES); + + return $data; + } +} diff --git a/course/format/classes/output/local/content/section/availability.php b/course/format/classes/output/local/content/section/availability.php index f806680b90e..6b96aee582f 100644 --- a/course/format/classes/output/local/content/section/availability.php +++ b/course/format/classes/output/local/content/section/availability.php @@ -59,6 +59,25 @@ class availability implements renderable, templatable { $this->section = $section; } + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param \renderer_base $output typically, the renderer that's calling this function + * @return stdClass data context for a mustache template + */ + public function export_for_template(\renderer_base $output): stdClass { + + $data = (object)[ + 'info' => $this->get_info($output), + ]; + + if (!empty($data->info)) { + $data->hasavailability = true; + } + + return $data; + } + /** * Export this data so it can be used as the context for a mustache template. * @@ -74,31 +93,29 @@ class availability implements renderable, templatable { * @param renderer_base $output typically, the renderer that's calling this function * @return stdclass data context for a mustache template */ - public function export_for_template(\renderer_base $output): stdClass { + protected function get_info(\renderer_base $output): array { global $CFG, $USER; - $format = $this->format; $section = $this->section; - $course = $format->get_course(); $context = context_course::instance($section->course); $canviewhidden = has_capability('moodle/course:viewhiddensections', $context, $USER); - $info = ''; + $info = []; if (!$section->visible) { if ($canviewhidden) { - $info = $output->availability_info(get_string('hiddenfromstudents'), 'ishidden'); + $info[] = $this->availability_info(get_string('hiddenfromstudents'), 'ishidden'); } else { // We are here because of the setting "Hidden sections are shown in collapsed form". // Student can not see the section contents but can see its name. - $info = $output->availability_info(get_string('notavailable'), 'ishidden'); + $info[] = $this->availability_info(get_string('notavailable'), 'ishidden'); } } else if (!$section->uservisible) { if ($section->availableinfo) { // Note: We only get to this function if availableinfo is non-empty, // so there is definitely something to print. $formattedinfo = info::format_info($section->availableinfo, $section->course); - $info = $output->availability_info($formattedinfo, 'isrestricted'); + $info[] = $this->availability_info($formattedinfo, 'isrestricted'); } } else if ($canviewhidden && !empty($CFG->enableavailability)) { // Check if there is an availability restriction. @@ -106,16 +123,38 @@ class availability implements renderable, templatable { $fullinfo = $ci->get_full_information(); if ($fullinfo) { $formattedinfo = info::format_info($fullinfo, $section->course); - $info = $output->availability_info($formattedinfo, 'isrestricted isfullinfo'); + $info[] = $this->availability_info($formattedinfo, 'isrestricted isfullinfo'); } } - $data = (object)[ - 'info' => $info, - ]; + return $info; + } - if (!empty($info)) { - $data->hasavailability = true; + /** + * Generate the basic availability information data. + * + * @param string $text the formatted avalability text + * @param string $additionalclasses additional css classes + * @return stdClass the availability information data + */ + protected function availability_info($text, $additionalclasses = ''): stdClass { + + $data = (object)[ + 'text' => $text, + 'classes' => $additionalclasses + ]; + $additionalclasses = array_filter(explode(' ', $additionalclasses)); + + if (in_array('ishidden', $additionalclasses)) { + $data->ishidden = 1; + } else if (in_array('isstealth', $additionalclasses)) { + $data->isstealth = 1; + } else if (in_array('isrestricted', $additionalclasses)) { + $data->isrestricted = 1; + + if (in_array('isfullinfo', $additionalclasses)) { + $data->isfullinfo = 1; + } } return $data; diff --git a/course/format/classes/output/local/content/section/cmitem.php b/course/format/classes/output/local/content/section/cmitem.php index 2547f89a9c6..16e7c1223c1 100644 --- a/course/format/classes/output/local/content/section/cmitem.php +++ b/course/format/classes/output/local/content/section/cmitem.php @@ -72,7 +72,7 @@ class cmitem implements renderable, templatable { $this->displayoptions = $displayoptions; // Get the necessary classes. - $this->cmclass = $format->get_output_classname('content\\section\\cm'); + $this->cmclass = $format->get_output_classname('content\\cm'); } /** diff --git a/course/format/classes/output/local/state/cm.php b/course/format/classes/output/local/state/cm.php index d899acb1f26..aa4c3dd9e1b 100644 --- a/course/format/classes/output/local/state/cm.php +++ b/course/format/classes/output/local/state/cm.php @@ -21,6 +21,7 @@ use section_info; use cm_info; use renderable; use stdClass; +use core_availability\info_module; /** * Contains the ajax update course module structure. @@ -80,8 +81,8 @@ class cm implements renderable { ]; // Check the user access type to this cm. - $conditionalhidden = $output->is_cm_conditionally_hidden($cm); - $data->accessvisible = ($data->visible && !$conditionalhidden); + $info = new info_module($cm); + $data->accessvisible = ($data->visible && $info->is_available_for_all()); // Add url if the activity is compatible. $url = $cm->url; diff --git a/course/format/templates/local/content/cm.mustache b/course/format/templates/local/content/cm.mustache index 115089b454f..748e76e5853 100644 --- a/course/format/templates/local/content/cm.mustache +++ b/course/format/templates/local/content/cm.mustache @@ -51,7 +51,9 @@ {{! Display the link to the module (or do nothing if module has no url). }} {{#hasname}}
- {{{cmname}}} {{{afterlink}}} + {{#cmname}} {{> core/inplace_editable }} {{/cmname}} + {{{grouping}}} + {{{afterlink}}}
{{/hasname}} {{! If there is content but NO link (eg label), then display the @@ -60,20 +62,27 @@ and for accessibility reasons, e.g. if you have a one-line label it should work similarly (at least in terms of ordering) to an activity. }} - {{^hasurl}} {{{altcontent}}} {{/hasurl}} + {{^hasurl}} + + {{/hasurl}} - {{#hasextras}} -
- {{#extras}} {{{.}}} {{/extras}} -
- {{/hasextras}} + {{#controlmenu}} + {{> core_courseformat/local/content/cm/controlmenu }} + {{/controlmenu}} {{#activityinfo}} {{> core_course/activity_info}} {{/activityinfo}} - {{{availability}}} + {{#modavailability}} + {{> core_courseformat/local/content/cm/availability }} + {{/modavailability}} - {{#hasurl}} {{{altcontent}}} {{/hasurl}} + {{#hasurl}} + + {{/hasurl}} diff --git a/course/format/templates/local/content/cm/availability.mustache b/course/format/templates/local/content/cm/availability.mustache new file mode 100644 index 00000000000..acb17f2c4be --- /dev/null +++ b/course/format/templates/local/content/cm/availability.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 core_courseformat/local/content/cm/availability + + Displays a activity availability. + + Example context (json): + { + "info": [ + { + "classes": "", + "text": "Not available unless:
  • It is on or after 8 June 2012
", + "ishidden": 0, + "isstealth": 0, + "isrestricted": 1, + "isfullinfo": 1 + } + ], + "hasmodavailability": true + } +}} +{{#hasmodavailability}} + {{#info}} +
+ {{^isrestricted}} + {{{text}}} + {{/isrestricted}} + {{#isrestricted}} + {{#str}}restricted, core{{/str}} {{{text}}} + {{/isrestricted}} +
+ {{/info}} +{{/hasmodavailability}} diff --git a/course/format/templates/local/content/cm/cmname.mustache b/course/format/templates/local/content/cm/cmname.mustache new file mode 100644 index 00000000000..2699bd452f8 --- /dev/null +++ b/course/format/templates/local/content/cm/cmname.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 core_courseformat/local/content/cm/cmname + + Convenience mustache to displays a course module inplcae editable from the format renderer. + + Format plugins are free to implement an alternative inplace editable for activities. + + Example context (json): + { + "displayvalue" : "Moodle", + "value" : "Moodle", + "itemid" : "1", + "component" : "core_unknown", + "itemtype" : "unknown", + "edithint" : "Edit this", + "editlabel" : "New name for this", + "type" : "text", + "options" : "", + "linkeverything": 0 + } +}} +{{> core/inplace_editable }} diff --git a/course/format/templates/local/content/cm/controlmenu.mustache b/course/format/templates/local/content/cm/controlmenu.mustache new file mode 100644 index 00000000000..fd750b581ea --- /dev/null +++ b/course/format/templates/local/content/cm/controlmenu.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 core_courseformat/local/content/cm/controlmenu + + Displays an activity control menu (dropdown menu). + + Example context (json): + { + "menu": "Edit", + "hasmenu": true + } +}} +{{#hasmenu}} +
+ {{#menu}} + {{> core/action_menu }} + {{/menu}} + {{#afterediticons}} {{{.}}} {{/afterediticons}} +
+{{/hasmenu}} diff --git a/course/format/templates/local/content/cm/title.mustache b/course/format/templates/local/content/cm/title.mustache new file mode 100644 index 00000000000..b345a04dabe --- /dev/null +++ b/course/format/templates/local/content/cm/title.mustache @@ -0,0 +1,51 @@ +{{! + 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 core_courseformat/local/content/cm/title + + Displays a course module instance inside a course section. + + Example context (json): + { + "url": "#", + "instancename": "Activity name", + "uservisible": true, + "icon": "../../../pix/help.svg", + "onclick": "alert('ok')", + "altname": "PDF file", + "linkclasses": "", + "textclasses": "" + } +}} +{{#url}} + {{#uservisible}} + + + + {{instancename}} {{{altname}}} + + + {{/uservisible}} + {{^uservisible}} +
+ + + {{instancename}} {{{altname}}} + +
+ {{/uservisible}} +{{/url}} diff --git a/course/format/templates/local/content/section/availability.mustache b/course/format/templates/local/content/section/availability.mustache index 4875c73baeb..8c68eb3744a 100644 --- a/course/format/templates/local/content/section/availability.mustache +++ b/course/format/templates/local/content/section/availability.mustache @@ -23,12 +23,30 @@ Example context (json): { - "info": "Hidden from students", + "info": [ + { + "classes": "", + "text": "Not available unless:
  • It is on or after 8 June 2012
", + "ishidden": 0, + "isstealth": 0, + "isrestricted": 1, + "isfullinfo": 1 + } + ], "hasavailability": true } }}
{{#hasavailability}} - {{{info}}} + {{#info}} +
+ {{^isrestricted}} + {{{text}}} + {{/isrestricted}} + {{#isrestricted}} + {{#str}}restricted, core{{/str}} {{{text}}} + {{/isrestricted}} +
+ {{/info}} {{/hasavailability}}
diff --git a/course/lib.php b/course/lib.php index b776c3af93c..8c469af3f5b 100644 --- a/course/lib.php +++ b/course/lib.php @@ -3821,7 +3821,7 @@ function course_get_tagged_courses($tag, $exclusivemode = false, $fromctx = 0, $ */ function core_course_inplace_editable($itemtype, $itemid, $newvalue) { if ($itemtype === 'activityname') { - return \core_course\output\course_module_name::update($itemid, $newvalue); + return \core_courseformat\output\local\content\cm\cmname::update($itemid, $newvalue); } } diff --git a/course/renderer.php b/course/renderer.php index 3d8d78e805a..80d4ee54aa1 100644 --- a/course/renderer.php +++ b/course/renderer.php @@ -206,6 +206,8 @@ class core_course_renderer extends plugin_renderer_base { /** * Renders HTML for displaying the sequence of course module editing buttons * + * @deprecated since 4.0 + * * @see course_get_cm_edit_actions() * * @param action_link[] $actions Array of action_link objects @@ -222,6 +224,11 @@ class core_course_renderer extends plugin_renderer_base { public function course_section_cm_edit_actions($actions, cm_info $mod = null, $displayoptions = array()) { global $CFG; + debugging( + 'course_section_cm_edit_actions is deprecated. Use core_courseformat\\output\\local\\content\\cm\\controlmenu instead.', + DEBUG_DEVELOPER + ); + if (empty($actions)) { return ''; } @@ -560,11 +567,19 @@ class core_course_renderer extends plugin_renderer_base { * Checks if course module has any conditions that may make it unavailable for * all or some of the students * + * @deprecated since Moodle 4.0 + * * @param cm_info $mod * @return bool */ public function is_cm_conditionally_hidden(cm_info $mod) { global $CFG; + + debugging( + 'is_cm_conditionally_hidden is deprecated. Use \core_availability\info_module::is_available_for_all instead', + DEBUG_DEVELOPER + ); + $conditionalhidden = false; if (!empty($CFG->enableavailability)) { $info = new \core_availability\info_module($mod); @@ -582,11 +597,18 @@ class core_course_renderer extends plugin_renderer_base { * Note, that for course modules that never have separate pages (i.e. labels) * this function return an empty string * + * @deprecated since 4.0 + * * @param cm_info $mod * @param array $displayoptions * @return string */ public function course_section_cm_name(cm_info $mod, $displayoptions = array()) { + debugging( + 'course_section_cm_name is deprecated. Use core_courseformat\output\local\content\cm\\cmname class instead.', + DEBUG_DEVELOPER + ); + if (!$mod->is_visible_on_course_page() || !$mod->url) { // Nothing to be displayed to the user. return ''; @@ -595,16 +617,29 @@ class core_course_renderer extends plugin_renderer_base { list($linkclasses, $textclasses) = $this->course_section_cm_classes($mod); $groupinglabel = $mod->get_grouping_label($textclasses); - // Render element that allows to edit activity name inline. It calls {@link course_section_cm_name_title()} - // to get the display title of the activity. - $tmpl = new \core_course\output\course_module_name($mod, $this->page->user_is_editing(), $displayoptions); - return $this->output->render_from_template('core/inplace_editable', $tmpl->export_for_template($this->output)) . + // Render element that allows to edit activity name inline. + $format = course_get_format($mod->course); + $cmnameclass = $format->get_output_classname('content\\cm\\cmname'); + // Mod inplace name editable. + $cmname = new $cmnameclass( + $format, + $mod->get_section_info(), + $mod, + $this->page->user_is_editing(), + $displayoptions + ); + + $data = $cmname->export_for_template($this->output); + + return $this->output->render_from_template('core/inplace_editable', $data) . $groupinglabel; } /** * Returns the CSS classes for the activity name/content * + * @deprecated since Moodle 4.0 + * * For items which are hidden, unavailable or stealth but should be displayed * to current user ($mod->is_visible_on_course_page()), we show those as dimmed. * Students will also see as dimmed activities names that are not yet available @@ -614,31 +649,24 @@ class core_course_renderer extends plugin_renderer_base { * @return array array of two elements ($linkclasses, $textclasses) */ protected function course_section_cm_classes(cm_info $mod) { - $linkclasses = ''; - $textclasses = ''; - if ($mod->uservisible) { - $conditionalhidden = $this->is_cm_conditionally_hidden($mod); - $accessiblebutdim = (!$mod->visible || $conditionalhidden) && - has_capability('moodle/course:viewhiddenactivities', $mod->context); - if ($accessiblebutdim) { - $linkclasses .= ' dimmed'; - $textclasses .= ' dimmed_text'; - if ($conditionalhidden) { - $linkclasses .= ' conditionalhidden'; - $textclasses .= ' conditionalhidden'; - } - } - if ($mod->is_stealth()) { - // Stealth activity is the one that is not visible on course page. - // It still may be displayed to the users who can manage it. - $linkclasses .= ' stealth'; - $textclasses .= ' stealth'; - } - } else { - $linkclasses .= ' dimmed'; - $textclasses .= ' dimmed dimmed_text'; - } - return array($linkclasses, $textclasses); + + debugging( + 'course_section_cm_classes is deprecated. Now it is part of core_courseformat\\output\\local\\content\\cm ', + DEBUG_DEVELOPER + ); + + $format = course_get_format($mod->course); + + $cmclass = $format->get_output_classname('content\\cm'); + $cmoutput = new $cmclass( + $format, + $mod->get_section_info(), + $mod, + ); + return [ + $cmoutput->get_link_classes(), + $cmoutput->get_text_classes(), + ]; } /** @@ -650,11 +678,19 @@ class core_course_renderer extends plugin_renderer_base { * Note, that for course modules that never have separate pages (i.e. labels) * this function return an empty string * + * @deprecated since Moodle 4.0 + * * @param cm_info $mod * @param array $displayoptions * @return string */ public function course_section_cm_name_title(cm_info $mod, $displayoptions = array()) { + + debugging( + 'course_section_cm_name_title is deprecated. Use core_courseformat\\output\\local\\cm\\title classes instead.', + DEBUG_DEVELOPER + ); + $output = ''; $url = $mod->url; if (!$mod->is_visible_on_course_page() || !$url) { @@ -700,11 +736,19 @@ class core_course_renderer extends plugin_renderer_base { /** * Renders html to display the module content on the course page (i.e. text of the labels) * + * @deprecated since 4.0 + * * @param cm_info $mod * @param array $displayoptions * @return string */ public function course_section_cm_text(cm_info $mod, $displayoptions = array()) { + + debugging( + 'course_section_cm_text is deprecated. Now it is part of core_courseformat\\output\\local\\content\\cm ', + DEBUG_DEVELOPER + ); + $output = ''; if (!$mod->is_visible_on_course_page()) { // nothing to be displayed to the user @@ -731,12 +775,18 @@ class core_course_renderer extends plugin_renderer_base { /** * Displays availability info for a course section or course module * + * @deprecated since Moodle 4.0 MDL-72656 - please do not use this function any more. * @param string $text * @param string $additionalclasses * @return string */ public function availability_info($text, $additionalclasses = '') { + debugging( + 'availability_info is deprecated. Use core_courseformat\\output\\local\\content\\section\\availability instead', + DEBUG_DEVELOPER + ); + $data = ['text' => $text, 'classes' => $additionalclasses]; $additionalclasses = array_filter(explode(' ', $additionalclasses)); @@ -761,59 +811,30 @@ class core_course_renderer extends plugin_renderer_base { * Renders HTML to show course module availability information (for someone who isn't allowed * to see the activity itself, or for staff) * + * @deprecated since Moodle 4.0 * @param cm_info $mod * @param array $displayoptions * @return string */ public function course_section_cm_availability(cm_info $mod, $displayoptions = array()) { - global $CFG; - $output = ''; - if (!$mod->is_visible_on_course_page()) { - return $output; - } - if (!$mod->uservisible) { - // this is a student who is not allowed to see the module but might be allowed - // to see availability info (i.e. "Available from ...") - if (!empty($mod->availableinfo)) { - $formattedinfo = \core_availability\info::format_info( - $mod->availableinfo, $mod->get_course()); - $output = $this->availability_info($formattedinfo, 'isrestricted'); - } - return $output; - } - // this is a teacher who is allowed to see module but still should see the - // information that module is not available to all/some students - $modcontext = context_module::instance($mod->id); - $canviewhidden = has_capability('moodle/course:viewhiddenactivities', $modcontext); - if ($canviewhidden && !$mod->visible) { - // This module is hidden but current user has capability to see it. - // Do not display the availability info if the whole section is hidden. - if ($mod->get_section_info()->visible) { - $output .= $this->availability_info(get_string('hiddenfromstudents'), 'ishidden'); - } - } else if ($mod->is_stealth()) { - // This module is available but is normally not displayed on the course page - // (this user can see it because they can manage it). - $output .= $this->availability_info(get_string('hiddenoncoursepage'), 'isstealth'); - } - if ($canviewhidden && !empty($CFG->enableavailability)) { - // Display information about conditional availability. - // Don't add availability information if user is not editing and activity is hidden. - if ($mod->visible || $this->page->user_is_editing()) { - $hidinfoclass = 'isrestricted isfullinfo'; - if (!$mod->visible) { - $hidinfoclass .= ' hide'; - } - $ci = new \core_availability\info_module($mod); - $fullinfo = $ci->get_full_information(); - if ($fullinfo) { - $formattedinfo = \core_availability\info::format_info( - $fullinfo, $mod->get_course()); - $output .= $this->availability_info($formattedinfo, $hidinfoclass); - } - } - } - return $output; + + debugging( + 'course_section_cm_availability is deprecated. Use core_courseformat\\output\\local\\content\\cm\\availability instead', + DEBUG_DEVELOPER + ); + + $format = course_get_format($mod->course); + + $availabilityclass = $format->get_output_classname('content\\cm\\availability'); + $availability = new $availabilityclass( + $format, + $mod->get_section_info(), + $mod, + ); + + $renderer = $format->get_renderer($this->page); + $data = $availability->export_for_template($renderer); + return $data->info ?? ''; } /** @@ -880,7 +901,7 @@ class core_course_renderer extends plugin_renderer_base { } $section = $modinfo->get_section_info($format->get_section_number()); - $cmclass = $format->get_output_classname('content\\section\\cm'); + $cmclass = $format->get_output_classname('content\\cm'); $cm = new $cmclass($format, $section, $mod, $displayoptions); // The course outputs works with format renderers, not with course renderers. $renderer = $format->get_renderer($this->page); diff --git a/course/upgrade.txt b/course/upgrade.txt index 8dacee9845c..05c6692a4e9 100644 --- a/course/upgrade.txt +++ b/course/upgrade.txt @@ -39,6 +39,13 @@ renderer and course format renderer: - stealth_section_header (replaced by output\section_format\header) - stealth_section_footer (integrated in by output\section_format) - section_nav_selection (replaced by output\course_format\sectionselector) + - course_section_cm_edit_actions (replaced by core_courseformat\output\local\content\cm\\controlmenu) + - is_cm_conditionally_hidden (incorporated in core_availability\info_module::is_available_for_all) + - course_section_cm_name (replaced by core_courseformat\output\local\content\cm\\cmname) + - course_section_cm_classes (integrated in core_courseformat\output\local\content\cm) + - course_section_cm_name_title (replaced by core_courseformat\\output\\local\\cm\\title) + - course_section_cm_text (integrated in core_courseformat\\output\\local\\content\\cm) + - course_section_cm_availability (replaced by core_courseformat\\output\\local\\content\\cm\\availability)) * The following abstract methods are deleted: - start_section_list (integrated in output\course_format) - end_section_list (integrated in output\course_format) @@ -56,6 +63,7 @@ course formats don't have their own renderer. * New core_course_drawer() function to render the message drawer in the top of the body of each page. * New course_get_enrolled_courses_for_logged_in_user_from_search which hooks in with external\get_enrolled_courses_by_timeline_classification given COURSE_TIMELINE_SEARCH is set then get_enrolled_courses_by_timeline_classification will deviate to use a string search of enrolled courses. +* Class core_course\output\course_module_name is deprecated. Now core_courseformat\output\local\cm\cmname controls inline edit. === 3.11 === * A new callback xxx_coursemodule_definition_after_data that allows plugins to extend activity forms after the data is set. diff --git a/lib/templates/availability_info.mustache b/lib/templates/availability_info.mustache index 53b9bf2b910..b1c15231724 100644 --- a/lib/templates/availability_info.mustache +++ b/lib/templates/availability_info.mustache @@ -17,6 +17,8 @@ {{! @template core/availability_info + @deprecated since Moodle 3.9 MDL-68612 - Use core_courseformat\\output\\local\\content\\section\\availability instead + Renders the availability info on the course outline page. Availability info can be displayed for activity modules or whole course