Rev 11 | AutorÃa | Comparar con el anterior | Ultima modificación | Ver Log |
<?php
// 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 <http://www.gnu.org/licenses/>.
namespace core_courseformat\output\local\content\section;
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 core\url;
use section_info;
/**
* Base class to render section controls.
*
* @package core_courseformat
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class controlmenu extends basecontrolmenu {
/**
* Constructor.
*
* @param course_format $format the course format
* @param section_info $section the section info
*/
public function __construct(course_format $format, section_info $section) {
parent::__construct($format, $section, null, $section->id);
}
/**
* Generate the action menu element depending on the section.
*
* 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
* @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 {
if (!empty($this->menu)) {
return $this->menu;
}
$sectiondelegate = $this->section->get_component_instance();
if ($sectiondelegate) {
return $sectiondelegate->get_section_action_menu($this->format, $this, $output);
}
return $this->get_default_action_menu($output);
}
/**
* Generate the default section action menu.
*
* 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
* @return action_menu|null the section 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['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();
$strhide = get_string('hide');
$strshow = get_string('show');
if ($this->section->visible) {
$stateaction = 'section_hide';
$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 {
$stateaction = 'section_show';
$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',
];
}
$url = $this->format->get_update_url(
action: $stateaction,
ids: [$this->section->id],
returnurl: $this->baseurl,
);
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. Use this method
* only if your format is not compatible with the move section modal
* and you are still migrating to components.
*
* @deprecated since Moodle 5.0
* @todo Remove this method in Moodle 6.0 (MDL-83530).
* @return link|null The menu item if applicable, otherwise null.
*/
#[\core\attribute\deprecated(
replacement: 'core_courseformat\output\local\content\section::get_section_movesection_item',
since: '5.0',
reason: 'Non-ajax section move is deprecated.',
mdl: 'MDL-83562',
)]
protected function get_section_moveup_item(): ?link {
\core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
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.
*
* @deprecated since Moodle 5.0
* @todo Remove this method in Moodle 6.0 (MDL-83530).
* @return link|null The menu item if applicable, otherwise null.
*/
#[\core\attribute\deprecated(
replacement: 'core_courseformat\output\local\content\section::get_section_movesection_item',
since: '5.0',
reason: 'Non-ajax section move is deprecated.',
mdl: 'MDL-83562',
)]
protected function get_section_movedown_item(): ?link {
\core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
$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;
}
$url = $this->format->get_update_url(
action: 'section_delete',
ids: [$this->section->id],
returnurl: $this->baseurl,
);
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.
*
* 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
*/
#[\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([self::class, __FUNCTION__]);
$format = $this->format;
$section = $this->section;
$course = $format->get_course();
$sectionreturn = !is_null($format->get_sectionid()) ? $format->get_sectionnum() : null;
$user = $USER;
$usecomponents = $format->supports_components();
$coursecontext = context_course::instance($course->id);
$numsections = $format->get_last_section_number();
$isstealth = $section->is_orphan();
$baseurl = course_get_url($course, $sectionreturn);
$baseurl->param('sesskey', sesskey());
$controls = [];
// 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 url('/course/section.php', ['id' => $section->id]),
'icon' => 'i/viewsection',
'name' => get_string('view'),
'pixattr' => ['class' => ''],
'attr' => ['class' => 'icon view'],
];
}
if (!$isstealth && has_capability('moodle/course:update', $coursecontext, $user)) {
$params = ['id' => $section->id];
$params['sr'] = $section->section;
if (get_string_manager()->string_exists('editsection', 'format_'.$format->get_format())) {
$streditsection = get_string('editsection', 'format_'.$format->get_format());
} else {
$streditsection = get_string('editsection');
}
$controls['edit'] = [
'url' => new url('/course/editsection.php', $params),
'icon' => 'i/settings',
'name' => $streditsection,
'pixattr' => ['class' => ''],
'attr' => ['class' => 'icon edit'],
];
if ($section->section) {
$duplicatesectionurl = clone($baseurl);
$duplicatesectionurl->param('sectionid', $section->id);
$duplicatesectionurl->param('duplicatesection', 1);
if (!is_null($sectionreturn)) {
$duplicatesectionurl->param('sr', $sectionreturn);
}
$controls['duplicate'] = [
'url' => $duplicatesectionurl,
'icon' => 't/copy',
'name' => get_string('duplicate'),
'pixattr' => ['class' => ''],
'attr' => ['class' => 'icon duplicate'],
];
}
}
if ($section->section) {
$url = clone($baseurl);
if (!is_null($sectionreturn)) {
$url->param('sectionid', $format->get_sectionid());
}
if (!$isstealth) {
if (has_capability('moodle/course:sectionvisibility', $coursecontext, $user)) {
$strhidefromothers = get_string('hidefromothers', 'format_' . $course->format);
$strshowfromothers = get_string('showfromothers', 'format_' . $course->format);
if ($section->visible) { // Show the hide/show eye.
$url->param('hide', $section->section);
$controls['visibility'] = [
'url' => $url,
'icon' => 'i/show',
'name' => $strhidefromothers,
'pixattr' => ['class' => ''],
'attr' => [
'class' => 'icon editing_showhide',
'data-sectionreturn' => $sectionreturn,
'data-action' => ($usecomponents) ? 'sectionHide' : 'hide',
'data-id' => $section->id,
'data-icon' => 'i/show',
'data-swapname' => $strshowfromothers,
'data-swapicon' => 'i/hide',
],
];
} else {
$url->param('show', $section->section);
$controls['visibility'] = [
'url' => $url,
'icon' => 'i/hide',
'name' => $strshowfromothers,
'pixattr' => ['class' => ''],
'attr' => [
'class' => 'icon editing_showhide',
'data-sectionreturn' => $sectionreturn,
'data-action' => ($usecomponents) ? 'sectionShow' : 'show',
'data-id' => $section->id,
'data-icon' => 'i/hide',
'data-swapname' => $strhidefromothers,
'data-swapicon' => 'i/show',
],
];
}
}
if (!$sectionreturn && has_capability('moodle/course:movesections', $coursecontext, $user)) {
if ($usecomponents) {
// This tool will appear only when the state is ready.
$url = clone ($baseurl);
$url->param('movesection', $section->section);
$url->param('section', $section->section);
$controls['movesection'] = [
'url' => $url,
'icon' => 'i/dragdrop',
'name' => get_string('move', 'moodle'),
'pixattr' => ['class' => ''],
'attr' => [
'class' => 'icon move waitstate',
'data-action' => 'moveSection',
'data-id' => $section->id,
],
];
}
// Legacy move up and down links for non component-based formats.
$url = clone($baseurl);
if ($section->section > 1) { // Add a arrow to move section up.
$url->param('section', $section->section);
$url->param('move', -1);
$strmoveup = get_string('moveup');
$controls['moveup'] = [
'url' => $url,
'icon' => 'i/up',
'name' => $strmoveup,
'pixattr' => ['class' => ''],
'attr' => ['class' => 'icon moveup whilenostate'],
];
}
$url = clone($baseurl);
if ($section->section < $numsections) { // Add a arrow to move section down.
$url->param('section', $section->section);
$url->param('move', 1);
$strmovedown = get_string('movedown');
$controls['movedown'] = [
'url' => $url,
'icon' => 'i/down',
'name' => $strmovedown,
'pixattr' => ['class' => ''],
'attr' => ['class' => 'icon movedown whilenostate'],
];
}
}
}
if (course_can_delete_section($course, $section)) {
if (get_string_manager()->string_exists('deletesection', 'format_'.$course->format)) {
$strdelete = get_string('deletesection', 'format_'.$course->format);
} else {
$strdelete = get_string('deletesection');
}
$params = [
'id' => $section->id,
'delete' => 1,
'sesskey' => sesskey(),
];
if (!is_null($sectionreturn)) {
$params['sr'] = $sectionreturn;
}
$url = new url(
'/course/editsection.php',
$params,
);
$controls['delete'] = [
'url' => $url,
'icon' => 'i/delete',
'name' => $strdelete,
'pixattr' => ['class' => ''],
'attr' => [
'class' => 'icon editing_delete text-danger',
'data-action' => 'deleteSection',
'data-id' => $section->id,
],
];
}
}
if (
!$isstealth &&
has_any_capability([
'moodle/course:movesections',
'moodle/course:update',
'moodle/course:sectionvisibility',
], $coursecontext)
) {
$sectionlink = new url(
'/course/section.php',
['id' => $section->id]
);
$controls['permalink'] = [
'url' => $sectionlink,
'icon' => 'i/link',
'name' => get_string('sectionlink', 'course'),
'pixattr' => ['class' => ''],
'attr' => [
'class' => 'icon',
'data-action' => 'permalink',
],
];
}
return $controls;
}
}