From 8bded47e50eda8856091aba2d306d7f22974c255 Mon Sep 17 00:00:00 2001 From: ferran Date: Wed, 23 Oct 2024 16:38:06 +0200 Subject: [PATCH] MDL-83527 core_courseformat: refactor section action menu --- .../output/local/content/basecontrolmenu.php | 238 ++++++++++++++++++ .../local/content/cm/delegatedcontrolmenu.php | 82 +++++- .../local/content/section/controlmenu.php | 31 ++- 3 files changed, 349 insertions(+), 2 deletions(-) diff --git a/course/format/classes/output/local/content/basecontrolmenu.php b/course/format/classes/output/local/content/basecontrolmenu.php index 062edd12be02a..058b768052ffb 100644 --- a/course/format/classes/output/local/content/basecontrolmenu.php +++ b/course/format/classes/output/local/content/basecontrolmenu.php @@ -21,6 +21,7 @@ use core\output\named_templatable; use core_courseformat\base as course_format; use core_courseformat\output\local\courseformat_named_templatable; +use context_course; use moodle_url; use pix_icon; use renderable; @@ -48,12 +49,21 @@ abstract class basecontrolmenu implements named_templatable, renderable { /** @var cm_info the course module class */ protected $mod; + /** @var stdClass the course instance */ + protected stdClass $course; + + /** @var context_course the course context */ + protected $coursecontext; + /** @var string the menu ID */ protected $menuid; /** @var action_menu the action menu */ protected $menu; + /** @var moodle_url The base URL for the course or the section */ + protected moodle_url $baseurl; + /** * Constructor. * @@ -67,6 +77,9 @@ public function __construct(course_format $format, section_info $section, ?cm_in $this->section = $section; $this->mod = $mod; $this->menuid = $menuid; + $this->course = $format->get_course(); + $this->coursecontext = $format->get_context(); + $this->baseurl = $format->get_view_url($format->get_sectionnum(), ['navigation' => true]); } /** @@ -134,6 +147,10 @@ protected function format_controls(array $controls): ?action_menu { $menu->attributes['class'] .= ' section-actions'; $menu->attributes['data-sectionid'] = $this->section->id; foreach ($controls as $value) { + // Actions not available for the user can be null. + if ($value === null) { + continue; + } $url = empty($value['url']) ? '' : $value['url']; $icon = empty($value['icon']) ? '' : $value['icon']; $name = empty($value['name']) ? '' : $value['name']; @@ -160,4 +177,225 @@ protected function format_controls(array $controls): ?action_menu { public function section_control_items() { return []; } + + // Section items. + + /** + * Retrieves the view item for the section control menu. + * + * @return array|null The menu item array if applicable, otherwise null. + */ + protected function get_section_view_item(): ?array { + global $PAGE; + // Only show the view link if we are not already in the section view page. + if ($this->format->get_sectionid() == $this->section->id) { + return null; + } + return [ + 'url' => new moodle_url('/course/section.php', ['id' => $this->section->id]), + 'icon' => 'i/viewsection', + 'name' => get_string('view'), + 'pixattr' => ['class' => ''], + 'attr' => ['class' => 'icon view'], + ]; + } + + /** + * Retrieves the edit item for the section control menu. + * + * @return array|null The menu item array if applicable, otherwise null. + */ + protected function get_section_edit_item(): ?array { + if (!has_capability('moodle/course:update', $this->coursecontext)) { + return null; + } + $params = ['id' => $this->section->id]; + $params['sr'] = $this->section->section; + return [ + 'url' => new moodle_url('/course/editsection.php', $params), + 'icon' => 'i/settings', + 'name' => get_string('editsection'), + 'pixattr' => ['class' => ''], + 'attr' => ['class' => 'icon edit'], + ]; + } + + /** + * Retrieves the duplicate item for the section control menu. + * + * @return array|null The menu item array if applicable, otherwise null. + */ + protected function get_section_duplicate_item(): ?array { + if ( + $this->section->sectionnum == 0 + || !has_capability('moodle/course:update', $this->coursecontext) + ) { + return null; + } + $url = clone($this->baseurl); + $url->param('sectionid', $this->section->id); + $url->param('duplicatesection', 1); + return [ + 'url' => $url, + 'icon' => 't/copy', + 'name' => get_string('duplicate'), + 'pixattr' => ['class' => ''], + 'attr' => ['class' => 'icon duplicate'], + ]; + } + + /** + * Retrieves the get_section_visibility_menu_item item for the section control menu. + * + * @return array|null The menu item array if applicable, otherwise null. + */ + protected function get_section_visibility_item(): ?array { + if ( + $this->section->sectionnum == 0 + || !has_capability('moodle/course:sectionvisibility', $this->coursecontext) + ) { + return null; + } + $sectionreturn = $this->format->get_sectionnum(); + + $url = clone($this->baseurl); + + $strhide = get_string('hide'); + $strshow = get_string('show'); + + if ($this->section->visible) { + $url->param('hide', $this->section->sectionnum); + return [ + 'url' => $url, + 'icon' => 'i/show', + 'name' => $strhide, + 'pixattr' => ['class' => ''], + 'attr' => [ + 'class' => 'icon editing_showhide', + 'data-sectionreturn' => $sectionreturn, + 'data-action' => 'sectionHide', + 'data-id' => $this->section->id, + 'data-icon' => 'i/show', + 'data-swapname' => $strshow, + 'data-swapicon' => 'i/hide', + ], + ]; + } else { + $url->param('show', $this->section->sectionnum); + return [ + 'url' => $url, + 'icon' => 'i/hide', + 'name' => $strshow, + 'pixattr' => ['class' => ''], + 'attr' => [ + 'class' => 'icon editing_showhide', + 'data-sectionreturn' => $sectionreturn, + 'data-action' => 'sectionShow', + 'data-id' => $this->section->id, + 'data-icon' => 'i/hide', + 'data-swapname' => $strhide, + 'data-swapicon' => 'i/show', + ], + ]; + } + } + + /** + * Retrieves the move item for the section control menu. + * + * @return array|null The menu item array if applicable, otherwise null. + */ + protected function get_section_movesection_item(): ?array { + if ( + $this->section->sectionnum == 0 + || $this->format->get_sectionid() + || !has_capability('moodle/course:movesections', $this->coursecontext) + ) { + return null; + } + + $url = clone ($this->baseurl); + $url->param('movesection', $this->section->sectionnum); + $url->param('section', $this->section->sectionnum); + return [ + 'url' => $url, + 'icon' => 'i/dragdrop', + 'name' => get_string('move'), + 'pixattr' => ['class' => ''], + 'attr' => [ + // This tool requires ajax and will appear only when the frontend state is ready. + 'class' => 'icon move waitstate', + 'data-action' => 'moveSection', + 'data-id' => $this->section->id, + ], + ]; + } + + /** + * Retrieves the permalink item for the section control menu. + * + * @return array|null The menu item array if applicable, otherwise null. + */ + protected function get_section_permalink_item(): ?array { + if (!has_any_capability( + [ + 'moodle/course:movesections', + 'moodle/course:update', + 'moodle/course:sectionvisibility', + ], + $this->coursecontext + ) + ) { + return null; + } + + $url = new moodle_url( + '/course/section.php', + ['id' => $this->section->id] + ); + return [ + 'url' => $url, + 'icon' => 'i/link', + 'name' => get_string('sectionlink', 'course'), + 'pixattr' => ['class' => ''], + 'attr' => [ + 'class' => 'icon', + 'data-action' => 'permalink', + ], + ]; + } + + /** + * Retrieves the delete item for the section control menu. + * + * @return array|null The menu item array if applicable, otherwise null. + */ + protected function get_section_delete_item(): ?array { + if (!course_can_delete_section($this->format->get_course(), $this->section)) { + return null; + } + + $params = [ + 'id' => $this->section->id, + 'delete' => 1, + 'sesskey' => sesskey(), + ]; + $params['sr'] ??= $this->format->get_sectionnum(); + + $url = new moodle_url( + '/course/editsection.php', + $params, + ); + return [ + 'url' => $url, + 'icon' => 'i/delete', + 'name' => get_string('delete'), + 'pixattr' => ['class' => ''], + 'attr' => [ + 'class' => 'icon editing_delete text-danger', + 'data-action' => 'deleteSection', + 'data-id' => $this->section->id, + ], + ]; + } } diff --git a/course/format/classes/output/local/content/cm/delegatedcontrolmenu.php b/course/format/classes/output/local/content/cm/delegatedcontrolmenu.php index bcf07fcf697ce..b9caf646f2dac 100644 --- a/course/format/classes/output/local/content/cm/delegatedcontrolmenu.php +++ b/course/format/classes/output/local/content/cm/delegatedcontrolmenu.php @@ -57,6 +57,85 @@ public function get_default_action_menu(\renderer_base $output): ?action_menu { return $this->format_controls($controls); } + /** + * Generate the edit control items of a section. + * + * @return array of edit control items + */ + public function delegated_control_items() { + // TODO remove this if as part of MDL-83530. + if (!$this->format->supports_components()) { + return $this->delegated_control_items_legacy(); + } + + $controls = []; + $controls['view'] = $this->get_section_view_item(); + $controls['edit'] = $this->get_section_edit_item(); + $controls['visibility'] = $this->get_section_visibility_item(); + $controls['movesection'] = $this->get_cm_move_item(); + $controls['permalink'] = $this->get_section_permalink_item(); + $controls['delete'] = $this->get_cm_delete_menu_item(); + + return $controls; + } + + /** + * Generates the delete item for a course module. + * + * @return array|null The menu item array if applicable, otherwise null. + */ + protected function get_cm_delete_menu_item(): ?array { + // Delete deletes the module. + if (!has_capability('moodle/course:manageactivities', $this->coursecontext)) { + return null; + } + + $url = new moodle_url('/course/mod.php'); + $url->param('sesskey', sesskey()); + $url->param('delete', $this->mod->id); + $url->param('sr', $this->mod->sectionnum); + + return [ + 'url' => $url, + 'icon' => 't/delete', + 'name' => get_string('delete'), + 'pixattr' => ['class' => ''], + 'attr' => [ + 'class' => 'editing_delete text-danger', + 'data-action' => 'cmDelete', + 'data-sectionreturn' => $this->format->get_sectionnum(), + 'data-id' => $this->mod->id, + ], + ]; + } + + /** + * Generates the move item for a course module. + * + * @return array|null The menu item array if applicable, otherwise null. + */ + protected function get_cm_move_item(): ?array { + // Only show the move link if we are not already in the section view page. + if ( + $this->format->get_sectionid() == $this->section->id + || !has_capability('moodle/course:manageactivities', $this->coursecontext) + ) { + return null; + } + return [ + 'url' => $this->baseurl, + 'icon' => 'i/dragdrop', + 'name' => get_string('move'), + 'pixattr' => ['class' => ''], + 'attr' => [ + // This tool requires ajax and will appear only when the frontend state is ready. + 'class' => 'editing_movecm waitstate', + 'data-action' => 'moveCm', + 'data-id' => $this->mod->id, + ], + ]; + } + /** * Generate the edit control items of a section. * @@ -65,9 +144,10 @@ public function get_default_action_menu(\renderer_base $output): ?action_menu { * * This method must remain public until the final deprecation of section_edit_control_items. * + * @todo Remove this method in Moodle 6.0 (MDL-83530). * @return array of edit control items */ - public function delegated_control_items() { + protected function delegated_control_items_legacy(): array { global $USER; $format = $this->format; diff --git a/course/format/classes/output/local/content/section/controlmenu.php b/course/format/classes/output/local/content/section/controlmenu.php index ba0c5b07f1c3b..ee058c115855d 100644 --- a/course/format/classes/output/local/content/section/controlmenu.php +++ b/course/format/classes/output/local/content/section/controlmenu.php @@ -76,6 +76,34 @@ public function get_default_action_menu(\renderer_base $output): ?action_menu { return $this->format_controls($controls); } + /** + * Generate the edit control items of a section. + * + * @return array of edit control items + */ + public function section_control_items() { + // TODO remove this if as part of MDL-83530. + if (!$this->format->supports_components()) { + return $this->section_control_items_legacy(); + } + + $controls = []; + + $controls['view'] = $this->get_section_view_item(); + + if (!$this->section->is_orphan()) { + $controls['edit'] = $this->get_section_edit_item(); + $controls['duplicate'] = $this->get_section_duplicate_item(); + $controls['visibility'] = $this->get_section_visibility_item(); + $controls['movesection'] = $this->get_section_movesection_item(); + $controls['permalink'] = $this->get_section_permalink_item(); + } + + $controls['delete'] = $this->get_section_delete_item(); + + return $controls; + } + /** * Generate the edit control items of a section. * @@ -84,9 +112,10 @@ public function get_default_action_menu(\renderer_base $output): ?action_menu { * * This method must remain public until the final deprecation of section_edit_control_items. * + * @todo Remove this method in Moodle 6.0 (MDL-83530). * @return array of edit control items */ - public function section_control_items() { + protected function section_control_items_legacy(): array { global $USER, $PAGE; $format = $this->format;