mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 12:40:01 +01:00
Merge branch 'MDL-83527-main-v02' of https://github.com/ferranrecio/moodle
This commit is contained in:
commit
1627aa8e71
10
.upgradenotes/MDL-83527-2024121902405772.yml
Normal file
10
.upgradenotes/MDL-83527-2024121902405772.yml
Normal file
@ -0,0 +1,10 @@
|
||||
issueNumber: MDL-83527
|
||||
notes:
|
||||
core_courseformat:
|
||||
- message: >-
|
||||
Using arrays to define course menu items is deprecated. All course
|
||||
formats that extend the section or activity control menus
|
||||
(format_NAME\output\courseformat\content\section\controlmenu or
|
||||
format_NAME\output\courseformat\cm\section\controlmenu) should return
|
||||
standard action_menu_link objects instead.
|
||||
type: deprecated
|
7
.upgradenotes/MDL-83527-2024122305195264.yml
Normal file
7
.upgradenotes/MDL-83527-2024122305195264.yml
Normal file
@ -0,0 +1,7 @@
|
||||
issueNumber: MDL-83527
|
||||
notes:
|
||||
format_topics:
|
||||
- message: >-
|
||||
The get_highlight_control in the section controlmenu class is now
|
||||
deprecated. Use get_section_highlight_item instead
|
||||
type: deprecated
|
7
.upgradenotes/MDL-83527-2024122305271479.yml
Normal file
7
.upgradenotes/MDL-83527-2024122305271479.yml
Normal file
@ -0,0 +1,7 @@
|
||||
issueNumber: MDL-83527
|
||||
notes:
|
||||
core_course:
|
||||
- message: >-
|
||||
course_get_cm_edit_actions is now deprecated. Formats should extend
|
||||
core_courseformat\output\local\content\cm\controlmenu instead.
|
||||
type: deprecated
|
@ -16,14 +16,16 @@
|
||||
|
||||
namespace core_courseformat\output\local\content;
|
||||
|
||||
use action_menu;
|
||||
use action_menu_link_secondary;
|
||||
use core\context\course as context_course;
|
||||
use core\output\action_menu;
|
||||
use core\output\action_menu\link_secondary;
|
||||
use core\output\named_templatable;
|
||||
use core\output\pix_icon;
|
||||
use core\output\renderable;
|
||||
use core\output\renderer_base;
|
||||
use core_courseformat\base as course_format;
|
||||
use core_courseformat\output\local\courseformat_named_templatable;
|
||||
use moodle_url;
|
||||
use pix_icon;
|
||||
use renderable;
|
||||
use core\url;
|
||||
use section_info;
|
||||
use cm_info;
|
||||
use stdClass;
|
||||
@ -48,12 +50,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 url The base URL for the course or the section */
|
||||
protected url $baseurl;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@ -67,15 +78,18 @@ abstract class basecontrolmenu implements named_templatable, renderable {
|
||||
$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]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param renderer_base $output typically, the renderer that's calling this function
|
||||
* @return null|array data context for a mustache template
|
||||
*/
|
||||
public function export_for_template(\renderer_base $output): ?stdClass {
|
||||
public function export_for_template(renderer_base $output): ?stdClass {
|
||||
$menu = $this->get_action_menu($output);
|
||||
if (empty($menu)) {
|
||||
return new stdClass();
|
||||
@ -93,10 +107,10 @@ abstract class basecontrolmenu implements named_templatable, renderable {
|
||||
/**
|
||||
* Generate the action menu element.
|
||||
*
|
||||
* @param \renderer_base $output typically, the renderer that's calling this function
|
||||
* @param renderer_base $output typically, the renderer that's calling this function
|
||||
* @return action_menu|null the action menu or null if no action menu is available
|
||||
*/
|
||||
public function get_action_menu(\renderer_base $output): ?action_menu {
|
||||
public function get_action_menu(renderer_base $output): ?action_menu {
|
||||
|
||||
if (!empty($this->menu)) {
|
||||
return $this->menu;
|
||||
@ -111,10 +125,10 @@ abstract class basecontrolmenu implements named_templatable, renderable {
|
||||
*
|
||||
* This method is public in case some block needs to modify the menu before output it.
|
||||
*
|
||||
* @param \renderer_base $output typically, the renderer that's calling this function
|
||||
* @param renderer_base $output typically, the renderer that's calling this function
|
||||
* @return action_menu|null the action menu
|
||||
*/
|
||||
public function get_default_action_menu(\renderer_base $output): ?action_menu {
|
||||
public function get_default_action_menu(renderer_base $output): ?action_menu {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -133,23 +147,57 @@ abstract class basecontrolmenu implements named_templatable, renderable {
|
||||
$menu->set_kebab_trigger(get_string('edit'));
|
||||
$menu->attributes['class'] .= ' section-actions';
|
||||
$menu->attributes['data-sectionid'] = $this->section->id;
|
||||
foreach ($controls as $value) {
|
||||
$url = empty($value['url']) ? '' : $value['url'];
|
||||
$icon = empty($value['icon']) ? '' : $value['icon'];
|
||||
$name = empty($value['name']) ? '' : $value['name'];
|
||||
$attr = empty($value['attr']) ? [] : $value['attr'];
|
||||
$class = empty($value['pixattr']['class']) ? '' : $value['pixattr']['class'];
|
||||
$al = new action_menu_link_secondary(
|
||||
new moodle_url($url),
|
||||
new pix_icon($icon, '', null, ['class' => "smallicon " . $class]),
|
||||
$name,
|
||||
$attr
|
||||
);
|
||||
$menu->add($al);
|
||||
foreach ($controls as $item) {
|
||||
// Actions not available for the user can be null.
|
||||
if ($item === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO remove this if as part of MDL-83530.
|
||||
if (is_array($item)) {
|
||||
// Some third party formats from 4.5 and older can use array to define the action menu items.
|
||||
$item = $this->normalize_action_menu_link($item);
|
||||
}
|
||||
|
||||
$menu->add($item);
|
||||
}
|
||||
return $menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nromalize the action menu item, or return null if it is not possible.
|
||||
*
|
||||
* Traditionally, this class uses array to define the action menu items,
|
||||
* for backward compatibility, this method will normalize the array into
|
||||
* the correct action_menu_link object.
|
||||
*
|
||||
* @todo Remove this method in Moodle 6.0 (MDL-83530).
|
||||
* @param array|null $itemdata the item data
|
||||
* @return void
|
||||
*/
|
||||
private function normalize_action_menu_link(
|
||||
array|null $itemdata
|
||||
): ?link_secondary {
|
||||
debugging(
|
||||
"Using arrays as action menu items is deprecated, use a compatible menu item instead.",
|
||||
DEBUG_DEVELOPER
|
||||
);
|
||||
if (empty($itemdata)) {
|
||||
return null;
|
||||
}
|
||||
$url = empty($itemdata['url']) ? '' : $itemdata['url'];
|
||||
$icon = empty($itemdata['icon']) ? '' : $itemdata['icon'];
|
||||
$name = empty($itemdata['name']) ? '' : $itemdata['name'];
|
||||
$attr = empty($itemdata['attr']) ? [] : $itemdata['attr'];
|
||||
$class = empty($itemdata['pixattr']['class']) ? '' : $itemdata['pixattr']['class'];
|
||||
return new link_secondary(
|
||||
url: new url($url),
|
||||
icon: new pix_icon($icon, '', null, ['class' => "smallicon " . $class]),
|
||||
text: $name,
|
||||
attributes: $attr,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the edit control items of a section.
|
||||
*
|
||||
@ -160,4 +208,33 @@ abstract class basecontrolmenu implements named_templatable, renderable {
|
||||
public function section_control_items() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new control item after a given control item.
|
||||
*
|
||||
* If the control item is not found, the new control item is added at the beginning.
|
||||
*
|
||||
* @param array $controls array of edit control items
|
||||
* @param string $aftername name of the control item after which the new control item will be added
|
||||
* @param string $newkey key of the new control item
|
||||
* @param mixed $newcontrol new control item to be added (anything compatible with an action menu or null)
|
||||
*/
|
||||
protected function add_control_after(array $controls, string $aftername, string $newkey, mixed $newcontrol): array {
|
||||
if (!array_key_exists($aftername, $controls)) {
|
||||
return array_merge([$newkey => $newcontrol], $controls);
|
||||
}
|
||||
$newcontrols = [];
|
||||
$found = false;
|
||||
foreach ($controls as $keyname => $control) {
|
||||
$newcontrols[$keyname] = $control;
|
||||
if ($keyname === $aftername) {
|
||||
$newcontrols[$newkey] = $newcontrol;
|
||||
$found = true;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
$newcontrols[$newkey] = $newcontrol;
|
||||
}
|
||||
return $newcontrols;
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,18 @@
|
||||
|
||||
namespace core_courseformat\output\local\content\cm;
|
||||
|
||||
use action_menu;
|
||||
use action_menu_link;
|
||||
use cm_info;
|
||||
use core\context\module as context_module;
|
||||
use core\output\action_menu;
|
||||
use core\output\action_menu\link;
|
||||
use core\output\action_menu\link_secondary;
|
||||
use core\output\action_menu\subpanel;
|
||||
use core\output\pix_icon;
|
||||
use core\output\renderer_base;
|
||||
use core_courseformat\base as course_format;
|
||||
use core_courseformat\output\local\content\basecontrolmenu;
|
||||
use core_courseformat\output\local\courseformat_named_templatable;
|
||||
use core_courseformat\sectiondelegate;
|
||||
use core\url;
|
||||
use section_info;
|
||||
use stdClass;
|
||||
|
||||
@ -45,6 +51,15 @@ class controlmenu extends basecontrolmenu {
|
||||
/** @var array optional display options */
|
||||
protected $displayoptions;
|
||||
|
||||
/** @var context_module|null modcontext the module context if any */
|
||||
protected ?context_module $modcontext = null;
|
||||
|
||||
/** @var bool $canmanageactivities Optimization to know if the user can manage activities */
|
||||
protected bool $canmanageactivities;
|
||||
|
||||
/** @var url $basemodurl the base mod.php url */
|
||||
protected url $basemodurl;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@ -56,15 +71,24 @@ class controlmenu extends basecontrolmenu {
|
||||
public function __construct(course_format $format, section_info $section, cm_info $mod, array $displayoptions = []) {
|
||||
parent::__construct($format, $section, $mod, $mod->id);
|
||||
$this->displayoptions = $displayoptions;
|
||||
|
||||
$this->modcontext = context_module::instance($mod->id);
|
||||
$this->canmanageactivities = has_capability('moodle/course:manageactivities', $this->modcontext);
|
||||
|
||||
$this->basemodurl = new url('/course/mod.php', ['sesskey' => sesskey()]);
|
||||
$sectionnumreturn = $format->get_sectionnum();
|
||||
if ($sectionnumreturn !== null) {
|
||||
$this->basemodurl->param('sr', $sectionnumreturn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param renderer_base $output typically, the renderer that's calling this function
|
||||
* @return stdClass|null data context for a mustache template
|
||||
*/
|
||||
public function export_for_template(\renderer_base $output): ?stdClass {
|
||||
public function export_for_template(renderer_base $output): ?stdClass {
|
||||
|
||||
$mod = $this->mod;
|
||||
|
||||
@ -96,25 +120,305 @@ class controlmenu extends basecontrolmenu {
|
||||
* Generate the action menu element.
|
||||
*
|
||||
* This method is public in case some block needs to modify the menu before output it.
|
||||
* @param \renderer_base $output typically, the renderer that's calling this function
|
||||
* @param renderer_base $output typically, the renderer that's calling this function
|
||||
* @return action_menu|null the activity action menu
|
||||
*/
|
||||
public function get_action_menu(\renderer_base $output): ?action_menu {
|
||||
public function get_action_menu(renderer_base $output): ?action_menu {
|
||||
|
||||
if (!empty($this->menu)) {
|
||||
return $this->menu;
|
||||
}
|
||||
|
||||
$mod = $this->mod;
|
||||
|
||||
// In case module is delegating a section, we should return delegated section action menu.
|
||||
if ($delegated = $mod->get_delegated_section_info()) {
|
||||
if ($delegated = $this->mod->get_delegated_section_info()) {
|
||||
$controlmenuclass = $this->format->get_output_classname('content\\cm\\delegatedcontrolmenu');
|
||||
$controlmenu = new $controlmenuclass($this->format, $delegated, $mod);
|
||||
|
||||
$controlmenu = new $controlmenuclass($this->format, $delegated, $this->mod);
|
||||
return $controlmenu->get_action_menu($output);
|
||||
}
|
||||
|
||||
// TODO remove this if as part of MDL-83530.
|
||||
if (!$this->format->supports_components()) {
|
||||
$this->menu = $this->get_action_menu_legacy($output);
|
||||
return $this->menu;
|
||||
}
|
||||
|
||||
$controls = $this->get_cm_control_items();
|
||||
return $this->format_controls($controls);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function get_cm_control_items(): ?array {
|
||||
$controls = [];
|
||||
|
||||
$controls['update'] = $this->get_cm_edit_item();
|
||||
$controls['move'] = $this->get_cm_move_item();
|
||||
$controls['moveright'] = $this->get_cm_moveend_item();
|
||||
$controls['moveleft'] = $this->get_cm_movestart_item();
|
||||
$controls['availability'] = $this->get_cm_visibility_item();
|
||||
$controls['duplicate'] = $this->get_cm_duplicate_item();
|
||||
$controls['assign'] = $this->get_cm_assign_item();
|
||||
$controls['groupmode'] = $this->get_cm_groupmode_item();
|
||||
$controls['delete'] = $this->get_cm_delete_item();
|
||||
|
||||
return $controls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the edit settings item for a course module.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_cm_edit_item(): ?link {
|
||||
if (!$this->canmanageactivities) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url($this->basemodurl, ['update' => $this->mod->id]);
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('i/settings', ''),
|
||||
text: get_string('editsettings'),
|
||||
attributes: [
|
||||
'class' => 'editing_update',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the move item for a course module.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_cm_move_item(): ?link {
|
||||
// Only show the move link if we are not already in the section view page.
|
||||
if (!$this->canmanageactivities) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url($this->basemodurl, ['copy' => $this->mod->id]);
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('i/dragdrop', ''),
|
||||
text: get_string('move'),
|
||||
attributes: [
|
||||
// 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,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the course module can be indented.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function can_indent_cm(): bool {
|
||||
return $this->canmanageactivities
|
||||
&& !sectiondelegate::has_delegate_class('mod_'.$this->mod->modname)
|
||||
&& empty($this->displayoptions['disableindentation'])
|
||||
&& $this->format->uses_indentation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the move right item for a course module.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_cm_moveend_item(): ?link {
|
||||
if (!$this->can_indent_cm() || $this->mod->indent > 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url($this->basemodurl, ['id' => $this->mod->id, 'indent' => 1]);
|
||||
|
||||
$icon = (right_to_left()) ? 't/left' : 't/right';
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon($icon, ''),
|
||||
text: get_string('moveright'),
|
||||
attributes: [
|
||||
'class' => 'editing_moveright',
|
||||
'data-action' => 'cmMoveRight',
|
||||
'data-keepopen' => true,
|
||||
'data-sectionreturn' => $this->format->get_sectionnum(),
|
||||
'data-id' => $this->mod->id,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the move left item for a course module.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_cm_movestart_item(): ?link {
|
||||
if (!$this->can_indent_cm() || $this->mod->indent <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url($this->basemodurl, ['id' => $this->mod->id, 'indent' => -1]);
|
||||
|
||||
$icon = (right_to_left()) ? 't/right' : 't/left';
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon($icon, ''),
|
||||
text: get_string('moveleft'),
|
||||
attributes: [
|
||||
'class' => 'editing_moveleft',
|
||||
'data-action' => 'cmMoveLeft',
|
||||
'data-keepopen' => true,
|
||||
'data-sectionreturn' => $this->format->get_sectionnum(),
|
||||
'data-id' => $this->mod->id,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the visibility item for a course module.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_cm_visibility_item(): link_secondary|subpanel|null {
|
||||
if (!has_capability('moodle/course:activityvisibility', $this->modcontext)) {
|
||||
return null;
|
||||
}
|
||||
$outputclass = $this->format->get_output_classname('content\\cm\\visibility');
|
||||
/** @var \core_courseformat\output\local\content\cm\visibility $output */
|
||||
$output = new $outputclass($this->format, $this->section, $this->mod);
|
||||
return $output->get_menu_item();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the duplicate item for a course module.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_cm_duplicate_item(): ?link {
|
||||
if (
|
||||
!has_all_capabilities(
|
||||
['moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport'],
|
||||
$this->coursecontext
|
||||
)
|
||||
|| !plugin_supports('mod', $this->mod->modname, FEATURE_BACKUP_MOODLE2)
|
||||
|| !course_allowed_module($this->mod->get_course(), $this->mod->modname)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url($this->basemodurl, ['duplicate' => $this->mod->id]);
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('t/copy', ''),
|
||||
text: get_string('duplicate'),
|
||||
attributes: [
|
||||
'class' => 'editing_duplicate',
|
||||
'data-action' => 'cmDuplicate',
|
||||
'data-sectionreturn' => $this->format->get_sectionnum(),
|
||||
'data-id' => $this->mod->id,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the assign roles item for a course module.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_cm_assign_item(): ?link {
|
||||
if (
|
||||
!has_capability('moodle/role:assign', $this->modcontext)
|
||||
|| sectiondelegate::has_delegate_class('mod_'.$this->mod->modname)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new link_secondary(
|
||||
url: new url('/admin/roles/assign.php', ['contextid' => $this->modcontext->id]),
|
||||
icon: new pix_icon('t/assignroles', ''),
|
||||
text: get_string('assignroles', 'role'),
|
||||
attributes: [
|
||||
'class' => 'editing_assign',
|
||||
'data-sectionreturn' => $this->format->get_sectionnum(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the group mode item for a course module.
|
||||
*
|
||||
* @return subpanel|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_cm_groupmode_item(): ?subpanel {
|
||||
if (
|
||||
!$this->format->show_groupmode($this->mod)
|
||||
|| $this->mod->coursegroupmodeforce
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$groupmodeclass = $this->format->get_output_classname('content\\cm\\groupmode');
|
||||
/** @var \core_courseformat\output\local\content\cm\groupmode $groupmode */
|
||||
$groupmode = new $groupmodeclass($this->format, $this->section, $this->mod);
|
||||
return new subpanel(
|
||||
text: get_string('groupmode', 'group'),
|
||||
subpanel: $groupmode->get_choice_list(),
|
||||
attributes: ['class' => 'editing_groupmode'],
|
||||
icon: new pix_icon('t/groupv', '', 'moodle', ['class' => 'iconsmall']),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the delete item for a course module.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_cm_delete_item(): ?link {
|
||||
if (!$this->canmanageactivities) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url($this->basemodurl, ['delete' => $this->mod->id]);
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('t/delete', ''),
|
||||
text: get_string('delete'),
|
||||
attributes: [
|
||||
'class' => 'editing_delete text-danger',
|
||||
'data-action' => 'cmDelete',
|
||||
'data-sectionreturn' => $this->format->get_sectionnum(),
|
||||
'data-id' => $this->mod->id,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the action menu element for old course formats.
|
||||
*
|
||||
* This method is public in case some block needs to modify the menu before output it.
|
||||
*
|
||||
* @todo Remove this method in Moodle 6.0 (MDL-83530).
|
||||
* @param \renderer_base $output typically, the renderer that's calling this function
|
||||
* @return action_menu|null the activity action menu
|
||||
*/
|
||||
private function get_action_menu_legacy(\renderer_base $output): ?action_menu {
|
||||
$mod = $this->mod;
|
||||
|
||||
$controls = $this->cm_control_items();
|
||||
|
||||
if (empty($controls)) {
|
||||
@ -133,7 +437,7 @@ class controlmenu extends basecontrolmenu {
|
||||
$menu->set_owner_selector($ownerselector);
|
||||
|
||||
foreach ($controls as $control) {
|
||||
if ($control instanceof action_menu_link) {
|
||||
if ($control instanceof link) {
|
||||
$control->add_class('cm-edit-action');
|
||||
}
|
||||
$menu->add($control);
|
||||
@ -151,9 +455,17 @@ class controlmenu extends basecontrolmenu {
|
||||
* However, format plugins can override the method to add or remove elements
|
||||
* from the menu.
|
||||
*
|
||||
* @deprecated since Moodle 5.0
|
||||
* @todo Remove this method in Moodle 6.0 (MDL-83530).
|
||||
* @return array of edit control items
|
||||
*/
|
||||
#[\core\attribute\deprecated(
|
||||
replacement: 'get_cm_control_items',
|
||||
since: '5.0',
|
||||
mdl: 'MDL-83527',
|
||||
)]
|
||||
protected function cm_control_items() {
|
||||
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
|
||||
$format = $this->format;
|
||||
$mod = $this->mod;
|
||||
$sectionreturn = $format->get_sectionnum();
|
||||
|
@ -16,13 +16,18 @@
|
||||
|
||||
namespace core_courseformat\output\local\content\cm;
|
||||
|
||||
use action_menu;
|
||||
use context_course;
|
||||
use cm_info;
|
||||
use core\context\course as context_course;
|
||||
use core\context\module as context_module;
|
||||
use core\output\action_menu;
|
||||
use core\output\action_menu\link;
|
||||
use core\output\action_menu\link_secondary;
|
||||
use core\output\renderer_base;
|
||||
use core_courseformat\base as course_format;
|
||||
use core_courseformat\output\local\content\basecontrolmenu;
|
||||
use moodle_url;
|
||||
use core\output\pix_icon;
|
||||
use core\url;
|
||||
use section_info;
|
||||
use cm_info;
|
||||
|
||||
/**
|
||||
* Base class to render delegated section controls.
|
||||
@ -32,6 +37,11 @@ use cm_info;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class delegatedcontrolmenu extends basecontrolmenu {
|
||||
/** @var context_module|null modcontext the module context if any */
|
||||
protected ?context_module $modcontext = null;
|
||||
|
||||
/** @var bool $canmanageactivities Optimization to know if the user can manage activities */
|
||||
protected bool $canmanageactivities;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -42,6 +52,9 @@ class delegatedcontrolmenu extends basecontrolmenu {
|
||||
*/
|
||||
public function __construct(course_format $format, section_info $section, cm_info $mod) {
|
||||
parent::__construct($format, $section, $mod, $section->id);
|
||||
|
||||
$this->modcontext = context_module::instance($mod->id);
|
||||
$this->canmanageactivities = has_capability('moodle/course:manageactivities', $this->modcontext);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,26 +62,267 @@ class delegatedcontrolmenu extends basecontrolmenu {
|
||||
*
|
||||
* This method is public in case some block needs to modify the menu before output it.
|
||||
*
|
||||
* @param \renderer_base $output typically, the renderer that's calling this function
|
||||
* @param renderer_base $output typically, the renderer that's calling this function
|
||||
* @return action_menu|null the action menu
|
||||
*/
|
||||
public function get_default_action_menu(\renderer_base $output): ?action_menu {
|
||||
public function get_default_action_menu(renderer_base $output): ?action_menu {
|
||||
$controls = $this->delegated_control_items();
|
||||
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_item();
|
||||
|
||||
return $controls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the view item for the section control menu.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_view_item(): ?link {
|
||||
// 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 new link_secondary(
|
||||
url: new url('/course/section.php', ['id' => $this->section->id]),
|
||||
icon: new pix_icon('i/viewsection', ''),
|
||||
text: get_string('view'),
|
||||
attributes: ['class' => 'view'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the edit item for the section control menu.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_edit_item(): ?link {
|
||||
if (!has_capability('moodle/course:update', $this->coursecontext)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url(
|
||||
'/course/editsection.php',
|
||||
[
|
||||
'id' => $this->section->id,
|
||||
'sr' => $this->section->sectionnum,
|
||||
]
|
||||
);
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('i/settings', ''),
|
||||
text: get_string('editsection'),
|
||||
attributes: ['class' => 'edit'],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates the move item for a course module.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_cm_move_item(): ?link {
|
||||
// Only show the move link if we are not already in the section view page.
|
||||
if (
|
||||
!$this->canmanageactivities
|
||||
|| $this->format->get_sectionid() == $this->section->id
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The move action uses visual elements on the course page.
|
||||
$url = new url(
|
||||
'/course/mod.php',
|
||||
[
|
||||
'sesskey' => sesskey(),
|
||||
'copy' => $this->mod->id,
|
||||
]
|
||||
);
|
||||
|
||||
$sectionnumreturn = $this->format->get_sectionnum();
|
||||
if ($sectionnumreturn !== null) {
|
||||
$url->param('sr', $sectionnumreturn);
|
||||
}
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('i/dragdrop', ''),
|
||||
text: get_string('move'),
|
||||
attributes: [
|
||||
// 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,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the get_section_visibility_menu_item item for the section control menu.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_visibility_item(): ?link {
|
||||
// To avoid exponential complexity, we only allow subsection visibility actions
|
||||
// when the parent section is visible.
|
||||
$parentsection = $this->mod->get_section_info();
|
||||
if (
|
||||
$this->section->sectionnum == 0
|
||||
|| !$parentsection->visible
|
||||
|| !has_capability('moodle/course:sectionvisibility', $this->coursecontext)
|
||||
|| !has_capability('moodle/course:activityvisibility', $this->modcontext)
|
||||
) {
|
||||
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);
|
||||
$icon = 'i/show';
|
||||
$name = $strhide;
|
||||
$attributes = [
|
||||
'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);
|
||||
$icon = 'i/hide';
|
||||
$name = $strshow;
|
||||
$attributes = [
|
||||
'class' => 'editing_showhide',
|
||||
'data-sectionreturn' => $sectionreturn,
|
||||
'data-action' => 'sectionShow',
|
||||
'data-id' => $this->section->id,
|
||||
'data-icon' => 'i/hide',
|
||||
'data-swapname' => $strhide,
|
||||
'data-swapicon' => 'i/show',
|
||||
];
|
||||
}
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon($icon, ''),
|
||||
text: $name,
|
||||
attributes: $attributes,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the permalink item for the section control menu.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_permalink_item(): ?link {
|
||||
if (!has_any_capability(
|
||||
[
|
||||
'moodle/course:movesections',
|
||||
'moodle/course:update',
|
||||
'moodle/course:sectionvisibility',
|
||||
],
|
||||
$this->coursecontext
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url(
|
||||
'/course/section.php',
|
||||
['id' => $this->section->id]
|
||||
);
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('i/link', ''),
|
||||
text: get_string('sectionlink', 'course'),
|
||||
attributes: [
|
||||
'class' => 'permalink',
|
||||
'data-action' => 'permalink',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the delete item for a course module.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_cm_delete_item(): ?link {
|
||||
if (!$this->canmanageactivities) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Removing a delegated section without ajax returns to the parent section.
|
||||
$url = new url(
|
||||
'/course/mod.php',
|
||||
[
|
||||
'sesskey' => sesskey(),
|
||||
'delete' => $this->mod->id,
|
||||
'sr' => $this->mod->sectionnum,
|
||||
],
|
||||
);
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('t/delete', ''),
|
||||
text: get_string('delete'),
|
||||
attributes: [
|
||||
'class' => 'editing_delete text-danger',
|
||||
'data-action' => 'cmDelete',
|
||||
'data-sectionreturn' => $this->format->get_sectionnum(),
|
||||
'data-id' => $this->mod->id,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the edit control items of a section.
|
||||
*
|
||||
* It is not clear this kind of controls are still available in 4.0 so, for now, this
|
||||
* method is almost a clone of the previous section_control_items from the course/renderer.php.
|
||||
*
|
||||
* This method must remain public until the final deprecation of section_edit_control_items.
|
||||
*
|
||||
* @deprecated since Moodle 5.0
|
||||
* @todo Remove this method in Moodle 6.0 (MDL-83530).
|
||||
* @return array of edit control items
|
||||
*/
|
||||
public function delegated_control_items() {
|
||||
#[\core\attribute\deprecated(
|
||||
replacement: 'delegated_control_items',
|
||||
since: '5.0',
|
||||
mdl: 'MDL-83527',
|
||||
)]
|
||||
protected function delegated_control_items_legacy(): array {
|
||||
global $USER;
|
||||
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
|
||||
|
||||
$format = $this->format;
|
||||
$section = $this->section;
|
||||
@ -83,7 +337,7 @@ class delegatedcontrolmenu extends basecontrolmenu {
|
||||
$baseurl = course_get_url($course, $sectionreturn);
|
||||
$baseurl->param('sesskey', sesskey());
|
||||
|
||||
$cmbaseurl = new moodle_url('/course/mod.php');
|
||||
$cmbaseurl = new url('/course/mod.php');
|
||||
$cmbaseurl->param('sesskey', sesskey());
|
||||
|
||||
$hasmanageactivities = has_capability('moodle/course:manageactivities', $coursecontext);
|
||||
@ -94,7 +348,7 @@ class delegatedcontrolmenu extends basecontrolmenu {
|
||||
// Only show the view link if we are not already in the section view page.
|
||||
if (!$isheadersection) {
|
||||
$controls['view'] = [
|
||||
'url' => new moodle_url('/course/section.php', ['id' => $section->id]),
|
||||
'url' => new url('/course/section.php', ['id' => $section->id]),
|
||||
'icon' => 'i/viewsection',
|
||||
'name' => get_string('view'),
|
||||
'pixattr' => ['class' => ''],
|
||||
@ -113,7 +367,7 @@ class delegatedcontrolmenu extends basecontrolmenu {
|
||||
|
||||
// Edit settings goes to section settings form.
|
||||
$controls['edit'] = [
|
||||
'url' => new moodle_url('/course/editsection.php', $params),
|
||||
'url' => new url('/course/editsection.php', $params),
|
||||
'icon' => 'i/settings',
|
||||
'name' => $streditsection,
|
||||
'pixattr' => ['class' => ''],
|
||||
@ -171,7 +425,7 @@ class delegatedcontrolmenu extends basecontrolmenu {
|
||||
// Move (only for component compatible formats).
|
||||
if (!$isheadersection && $hasmanageactivities && $usecomponents) {
|
||||
$controls['move'] = [
|
||||
'url' => new moodle_url('/course/mod.php', ['copy' => $cm->id]),
|
||||
'url' => new url('/course/mod.php', ['copy' => $cm->id]),
|
||||
'icon' => 'i/dragdrop',
|
||||
'name' => get_string('move'),
|
||||
'pixattr' => ['class' => ''],
|
||||
@ -211,7 +465,7 @@ class delegatedcontrolmenu extends basecontrolmenu {
|
||||
'moodle/course:sectionvisibility',
|
||||
], $coursecontext)
|
||||
) {
|
||||
$sectionlink = new moodle_url(
|
||||
$sectionlink = new url(
|
||||
'/course/section.php',
|
||||
['id' => $section->id]
|
||||
);
|
||||
|
@ -16,11 +16,15 @@
|
||||
|
||||
namespace core_courseformat\output\local\content\section;
|
||||
|
||||
use action_menu;
|
||||
use context_course;
|
||||
use core\context\course as context_course;
|
||||
use core\output\action_menu;
|
||||
use core\output\action_menu\link;
|
||||
use core\output\action_menu\link_secondary;
|
||||
use core\output\pix_icon;
|
||||
use core\output\renderer_base;
|
||||
use core_courseformat\base as course_format;
|
||||
use core_courseformat\output\local\content\basecontrolmenu;
|
||||
use moodle_url;
|
||||
use core\url;
|
||||
use section_info;
|
||||
|
||||
/**
|
||||
@ -47,10 +51,10 @@ class controlmenu extends basecontrolmenu {
|
||||
*
|
||||
* Sections controlled by a plugin will delegate the control menu to the delegated section class.
|
||||
*
|
||||
* @param \renderer_base $output typically, the renderer that's calling this function
|
||||
* @param renderer_base $output typically, the renderer that's calling this function
|
||||
* @return action_menu|null the section action menu or null if no action menu is available
|
||||
*/
|
||||
public function get_action_menu(\renderer_base $output): ?action_menu {
|
||||
public function get_action_menu(renderer_base $output): ?action_menu {
|
||||
|
||||
if (!empty($this->menu)) {
|
||||
return $this->menu;
|
||||
@ -68,14 +72,357 @@ class controlmenu extends basecontrolmenu {
|
||||
*
|
||||
* This method is public in case some block needs to modify the menu before output it.
|
||||
*
|
||||
* @param \renderer_base $output typically, the renderer that's calling this function
|
||||
* @param renderer_base $output typically, the renderer that's calling this function
|
||||
* @return action_menu|null the section action menu
|
||||
*/
|
||||
public function get_default_action_menu(\renderer_base $output): ?action_menu {
|
||||
public function get_default_action_menu(renderer_base $output): ?action_menu {
|
||||
$controls = $this->section_control_items();
|
||||
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['moveup'] = $this->get_section_moveup_item();
|
||||
$controls['movedown'] = $this->get_section_movedown_item();
|
||||
$controls['permalink'] = $this->get_section_permalink_item();
|
||||
}
|
||||
|
||||
$controls['delete'] = $this->get_section_delete_item();
|
||||
|
||||
return $controls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the view item for the section control menu.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_view_item(): ?link {
|
||||
// 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 new link_secondary(
|
||||
url: new url('/course/section.php', ['id' => $this->section->id]),
|
||||
icon: new pix_icon('i/viewsection', ''),
|
||||
text: get_string('view'),
|
||||
attributes: ['class' => 'view'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the edit item for the section control menu.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_edit_item(): ?link {
|
||||
if (!has_capability('moodle/course:update', $this->coursecontext)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url(
|
||||
'/course/editsection.php',
|
||||
[
|
||||
'id' => $this->section->id,
|
||||
'sr' => $this->section->sectionnum,
|
||||
]
|
||||
);
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('i/settings', ''),
|
||||
text: get_string('editsection'),
|
||||
attributes: ['class' => 'edit'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the duplicate item for the section control menu.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_duplicate_item(): ?link {
|
||||
if (
|
||||
$this->section->sectionnum == 0
|
||||
|| !has_capability('moodle/course:update', $this->coursecontext)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url(
|
||||
$this->baseurl,
|
||||
[
|
||||
'sectionid' => $this->section->id,
|
||||
'duplicatesection' => 1,
|
||||
'sesskey' => sesskey(),
|
||||
]
|
||||
);
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('t/copy', ''),
|
||||
text: get_string('duplicate'),
|
||||
attributes: ['class' => 'duplicate'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the get_section_visibility_menu_item item for the section control menu.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_visibility_item(): ?link {
|
||||
if (
|
||||
$this->section->sectionnum == 0
|
||||
|| !has_capability('moodle/course:sectionvisibility', $this->coursecontext)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
$sectionreturn = $this->format->get_sectionnum();
|
||||
|
||||
$url = new url($this->baseurl, ['sesskey' => sesskey()]);
|
||||
|
||||
$strhide = get_string('hide');
|
||||
$strshow = get_string('show');
|
||||
|
||||
if ($this->section->visible) {
|
||||
$url->param('hide', $this->section->sectionnum);
|
||||
$icon = 'i/show';
|
||||
$name = $strhide;
|
||||
$attributes = [
|
||||
'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);
|
||||
$icon = 'i/hide';
|
||||
$name = $strshow;
|
||||
$attributes = [
|
||||
'class' => 'editing_showhide',
|
||||
'data-sectionreturn' => $sectionreturn,
|
||||
'data-action' => 'sectionShow',
|
||||
'data-id' => $this->section->id,
|
||||
'data-icon' => 'i/hide',
|
||||
'data-swapname' => $strhide,
|
||||
'data-swapicon' => 'i/show',
|
||||
];
|
||||
}
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon($icon, ''),
|
||||
text: $name,
|
||||
attributes: $attributes,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the move item for the section control menu.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_movesection_item(): ?link {
|
||||
if (
|
||||
$this->section->sectionnum == 0
|
||||
|| $this->format->get_sectionid()
|
||||
|| !has_capability('moodle/course:movesections', $this->coursecontext)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url(
|
||||
$this->baseurl,
|
||||
[
|
||||
'movesection' => $this->section->sectionnum,
|
||||
'section' => $this->section->sectionnum,
|
||||
]
|
||||
);
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('i/dragdrop', ''),
|
||||
text: get_string('move'),
|
||||
attributes: [
|
||||
// This tool requires ajax and will appear only when the frontend state is ready.
|
||||
'class' => 'move waitstate',
|
||||
'data-action' => 'moveSection',
|
||||
'data-id' => $this->section->id,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the move up for the section control menu.
|
||||
*
|
||||
* This actions only apply to non-component-based formats
|
||||
* or when javascript is not available.
|
||||
*
|
||||
* Note: this action will be removed, do not depend on it for your
|
||||
* custom formats. For more information, see MDL-83562.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_moveup_item(): ?link {
|
||||
if (
|
||||
$this->section->sectionnum <= 1
|
||||
|| $this->format->get_sectionid()
|
||||
|| !has_capability('moodle/course:movesections', $this->coursecontext)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url(
|
||||
$this->baseurl,
|
||||
[
|
||||
'section' => $this->section->sectionnum,
|
||||
'move' => -1,
|
||||
'sesskey' => sesskey(),
|
||||
]
|
||||
);
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('i/up', ''),
|
||||
text: get_string('moveup'),
|
||||
attributes: [
|
||||
// This tool disappears when the state is ready whilenostate.
|
||||
'class' => 'moveup whilenostate',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the move down for the section control menu.
|
||||
*
|
||||
* This actions only apply to non-component-based formats
|
||||
* or when javascript is not available.
|
||||
*
|
||||
* Note: this action will be removed, do not depend on it for your
|
||||
* custom formats. For more information, see MDL-83562.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_movedown_item(): ?link {
|
||||
$numsections = $this->format->get_last_section_number();
|
||||
|
||||
if (
|
||||
$this->section->sectionnum == 0
|
||||
|| $this->section->sectionnum >= $numsections
|
||||
|| $this->format->get_sectionid()
|
||||
|| !has_capability('moodle/course:movesections', $this->coursecontext)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url(
|
||||
$this->baseurl,
|
||||
[
|
||||
'section' => $this->section->sectionnum,
|
||||
'move' => 1,
|
||||
'sesskey' => sesskey(),
|
||||
]
|
||||
);
|
||||
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('i/down', ''),
|
||||
text: get_string('movedown'),
|
||||
attributes: [
|
||||
// This tool disappears when the state is ready.
|
||||
'class' => 'movedown whilenostate',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the permalink item for the section control menu.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_permalink_item(): ?link {
|
||||
if (!has_any_capability(
|
||||
[
|
||||
'moodle/course:movesections',
|
||||
'moodle/course:update',
|
||||
'moodle/course:sectionvisibility',
|
||||
],
|
||||
$this->coursecontext
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = new url(
|
||||
'/course/section.php',
|
||||
['id' => $this->section->id]
|
||||
);
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('i/link', ''),
|
||||
text: get_string('sectionlink', 'course'),
|
||||
attributes: [
|
||||
'class' => 'permalink',
|
||||
'data-action' => 'permalink',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the delete item for the section control menu.
|
||||
*
|
||||
* @return link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_delete_item(): ?link {
|
||||
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 url(
|
||||
'/course/editsection.php',
|
||||
$params,
|
||||
);
|
||||
return new link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon('i/delete', ''),
|
||||
text: get_string('delete'),
|
||||
attributes: [
|
||||
'class' => 'editing_delete text-danger',
|
||||
'data-action' => 'deleteSection',
|
||||
'data-id' => $this->section->id,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the edit control items of a section.
|
||||
*
|
||||
@ -84,10 +431,18 @@ class controlmenu extends basecontrolmenu {
|
||||
*
|
||||
* This method must remain public until the final deprecation of section_edit_control_items.
|
||||
*
|
||||
* @deprecated since Moodle 5.0
|
||||
* @todo Remove this method in Moodle 6.0 (MDL-83530).
|
||||
* @return array of edit control items
|
||||
*/
|
||||
public function section_control_items() {
|
||||
#[\core\attribute\deprecated(
|
||||
replacement: 'section_control_items',
|
||||
since: '5.0',
|
||||
mdl: 'MDL-83527',
|
||||
)]
|
||||
protected function section_control_items_legacy(): array {
|
||||
global $USER, $PAGE;
|
||||
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
|
||||
|
||||
$format = $this->format;
|
||||
$section = $this->section;
|
||||
@ -108,7 +463,7 @@ class controlmenu extends basecontrolmenu {
|
||||
// Only show the view link if we are not already in the section view page.
|
||||
if ($PAGE->pagetype !== 'course-view-section-' . $course->format) {
|
||||
$controls['view'] = [
|
||||
'url' => new moodle_url('/course/section.php', ['id' => $section->id]),
|
||||
'url' => new url('/course/section.php', ['id' => $section->id]),
|
||||
'icon' => 'i/viewsection',
|
||||
'name' => get_string('view'),
|
||||
'pixattr' => ['class' => ''],
|
||||
@ -126,7 +481,7 @@ class controlmenu extends basecontrolmenu {
|
||||
}
|
||||
|
||||
$controls['edit'] = [
|
||||
'url' => new moodle_url('/course/editsection.php', $params),
|
||||
'url' => new url('/course/editsection.php', $params),
|
||||
'icon' => 'i/settings',
|
||||
'name' => $streditsection,
|
||||
'pixattr' => ['class' => ''],
|
||||
@ -259,7 +614,7 @@ class controlmenu extends basecontrolmenu {
|
||||
if (!is_null($sectionreturn)) {
|
||||
$params['sr'] = $sectionreturn;
|
||||
}
|
||||
$url = new moodle_url(
|
||||
$url = new url(
|
||||
'/course/editsection.php',
|
||||
$params,
|
||||
);
|
||||
@ -284,7 +639,7 @@ class controlmenu extends basecontrolmenu {
|
||||
'moodle/course:sectionvisibility',
|
||||
], $coursecontext)
|
||||
) {
|
||||
$sectionlink = new moodle_url(
|
||||
$sectionlink = new url(
|
||||
'/course/section.php',
|
||||
['id' => $section->id]
|
||||
);
|
||||
|
@ -24,8 +24,11 @@
|
||||
|
||||
namespace format_topics\output\courseformat\content\section;
|
||||
|
||||
use core\output\action_menu\link as action_menu_link;
|
||||
use core\output\action_menu\link_secondary as action_menu_link_secondary;
|
||||
use core\output\pix_icon;
|
||||
use core_courseformat\output\local\content\section\controlmenu as controlmenu_base;
|
||||
use moodle_url;
|
||||
use core\url;
|
||||
|
||||
/**
|
||||
* Base class to render a course section menu.
|
||||
@ -50,54 +53,33 @@ class controlmenu extends controlmenu_base {
|
||||
* @return array of edit control items
|
||||
*/
|
||||
public function section_control_items() {
|
||||
|
||||
$format = $this->format;
|
||||
$section = $this->section;
|
||||
$coursecontext = $format->get_context();
|
||||
|
||||
$parentcontrols = parent::section_control_items();
|
||||
|
||||
if ($section->is_orphan() || !$section->section) {
|
||||
if ($section->is_orphan() || !$section->sectionnum) {
|
||||
return $parentcontrols;
|
||||
}
|
||||
|
||||
$controls = [];
|
||||
if (has_capability('moodle/course:setcurrentsection', $coursecontext)) {
|
||||
$controls['highlight'] = $this->get_highlight_control();
|
||||
if (!has_capability('moodle/course:setcurrentsection', $this->coursecontext)) {
|
||||
return $parentcontrols;
|
||||
}
|
||||
|
||||
// If the edit key exists, we are going to insert our controls after it.
|
||||
if (array_key_exists("edit", $parentcontrols)) {
|
||||
$merged = [];
|
||||
// We can't use splice because we are using associative arrays.
|
||||
// Step through the array and merge the arrays.
|
||||
foreach ($parentcontrols as $key => $action) {
|
||||
$merged[$key] = $action;
|
||||
if ($key == "edit") {
|
||||
// If we have come to the edit key, merge these controls here.
|
||||
$merged = array_merge($merged, $controls);
|
||||
}
|
||||
}
|
||||
|
||||
return $merged;
|
||||
} else {
|
||||
return array_merge($controls, $parentcontrols);
|
||||
}
|
||||
return $this->add_control_after($parentcontrols, 'edit', 'highlight', $this->get_section_highlight_item());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the course url.
|
||||
*
|
||||
* @return moodle_url
|
||||
* @return url
|
||||
*/
|
||||
protected function get_course_url(): moodle_url {
|
||||
protected function get_course_url(): url {
|
||||
$format = $this->format;
|
||||
$section = $this->section;
|
||||
$course = $format->get_course();
|
||||
$sectionreturn = $format->get_sectionnum();
|
||||
|
||||
if ($sectionreturn) {
|
||||
$url = course_get_url($course, $section->section);
|
||||
$url = course_get_url($course, $section->sectionnum);
|
||||
} else {
|
||||
$url = course_get_url($course);
|
||||
}
|
||||
@ -105,12 +87,77 @@ class controlmenu extends controlmenu_base {
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the view item for the section control menu.
|
||||
*
|
||||
* @return action_menu_link|null The menu item if applicable, otherwise null.
|
||||
*/
|
||||
protected function get_section_highlight_item(): action_menu_link_secondary {
|
||||
$format = $this->format;
|
||||
$section = $this->section;
|
||||
$course = $format->get_course();
|
||||
$sectionreturn = $format->get_sectionnum();
|
||||
$url = $this->get_course_url();
|
||||
if (!is_null($sectionreturn)) {
|
||||
$url->param('sectionid', $format->get_sectionid());
|
||||
}
|
||||
|
||||
$highlightoff = get_string('highlightoff');
|
||||
$highlightofficon = 'i/marked';
|
||||
|
||||
$highlighton = get_string('highlight');
|
||||
$highlightonicon = 'i/marker';
|
||||
|
||||
if ($course->marker == $section->sectionnum) { // Show the "light globe" on/off.
|
||||
$url->param('marker', 0);
|
||||
$icon = $highlightofficon;
|
||||
$name = $highlightoff;
|
||||
$attributes = [
|
||||
'class' => 'editing_highlight',
|
||||
'data-action' => 'sectionUnhighlight',
|
||||
'data-sectionreturn' => $sectionreturn,
|
||||
'data-id' => $section->id,
|
||||
'data-icon' => $highlightofficon,
|
||||
'data-swapname' => $highlighton,
|
||||
'data-swapicon' => $highlightonicon,
|
||||
];
|
||||
} else {
|
||||
$url->param('marker', $section->section);
|
||||
$icon = $highlightonicon;
|
||||
$name = $highlighton;
|
||||
$attributes = [
|
||||
'class' => 'editing_highlight',
|
||||
'data-action' => 'sectionHighlight',
|
||||
'data-sectionreturn' => $sectionreturn,
|
||||
'data-id' => $section->id,
|
||||
'data-icon' => $highlightonicon,
|
||||
'data-swapname' => $highlightoff,
|
||||
'data-swapicon' => $highlightofficon,
|
||||
];
|
||||
}
|
||||
return new action_menu_link_secondary(
|
||||
url: $url,
|
||||
icon: new pix_icon($icon, ''),
|
||||
text: $name,
|
||||
attributes: $attributes,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specific section highlight action.
|
||||
*
|
||||
* @deprecated since Moodle 5.0
|
||||
* @todo Remove this method in Moodle 6.0 (MDL-83530).
|
||||
* @return array the action element.
|
||||
*/
|
||||
#[\core\attribute\deprecated(
|
||||
replacement: 'get_section_highlight_item',
|
||||
since: '5.0',
|
||||
mdl: 'MDL-83527',
|
||||
reason: 'Wrong return type',
|
||||
)]
|
||||
protected function get_highlight_control(): array {
|
||||
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
|
||||
$format = $this->format;
|
||||
$section = $this->section;
|
||||
$course = $format->get_course();
|
||||
|
@ -1353,14 +1353,25 @@ function moveto_module($mod, $section, $beforemod=NULL) {
|
||||
/**
|
||||
* Returns the list of all editing actions that current user can perform on the module
|
||||
*
|
||||
* @deprecated since Moodle 5.0
|
||||
* @todo Remove this method in Moodle 6.0 (MDL-83530).
|
||||
*
|
||||
* @param cm_info $mod The module to produce editing buttons for
|
||||
* @param int $indent The current indenting (default -1 means no move left-right actions)
|
||||
* @param int $sr The section to link back to (used for creating the links)
|
||||
* @return array array of action_link or pix_icon objects
|
||||
*/
|
||||
#[\core\attribute\deprecated(
|
||||
replacement: 'core_courseformat\output\local\content\cm\controlmenu',
|
||||
since: '5.0',
|
||||
mdl: 'MDL-83527',
|
||||
reason: 'Replaced by an output class equivalent.',
|
||||
)]
|
||||
function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
|
||||
global $COURSE, $SITE, $CFG;
|
||||
|
||||
\core\deprecation::emit_deprecation_if_present(__FUNCTION__);
|
||||
|
||||
static $str;
|
||||
|
||||
$coursecontext = context_course::instance($mod->course);
|
||||
|
@ -18,6 +18,7 @@ namespace core_question\output;
|
||||
|
||||
use action_link;
|
||||
use renderer_base;
|
||||
use core_courseformat\output\local\content\cm\controlmenu;
|
||||
|
||||
/**
|
||||
* Create a list of question bank type links to manage their respective instances.
|
||||
@ -51,7 +52,9 @@ class question_bank_list implements \renderable, \templatable {
|
||||
$banks = [];
|
||||
foreach ($this->bankinstances as $instance) {
|
||||
if (plugin_supports('mod', $instance->cminfo->modname, FEATURE_PUBLISHES_QUESTIONS)) {
|
||||
$actions = course_get_cm_edit_actions($instance->cminfo);
|
||||
$format = course_get_format($instance->cminfo->course);
|
||||
$controlmenu = new controlmenu($format, $instance->cminfo->get_section_info(), $instance->cminfo);
|
||||
$actions = $controlmenu->get_cm_control_items();
|
||||
$actionmenu = new \action_menu();
|
||||
$actionmenu->set_kebab_trigger(get_string('edit'));
|
||||
$actionmenu->add_secondary_action($actions['update']);
|
||||
|
Loading…
x
Reference in New Issue
Block a user