MDL-73462 course: Introduce course category tertiary navigation
Update the category management page.
This commit is contained in:
@@ -183,7 +183,10 @@ switch ($context->contextlevel) {
|
||||
break;
|
||||
}
|
||||
|
||||
$PAGE->set_navigation_overflow_state(false);
|
||||
// In a course category context we leverage overflow for the tertiary navigation
|
||||
if ($context->contextlevel != CONTEXT_COURSECAT) {
|
||||
$PAGE->set_navigation_overflow_state(false);
|
||||
}
|
||||
|
||||
// Within a course context we need to explicitly set active tab as there isn't a reference in the nav tree.
|
||||
if ($context->contextlevel == CONTEXT_COURSE) {
|
||||
|
||||
@@ -126,7 +126,11 @@ if (!is_null($reportuser)) {
|
||||
$rolenames = role_get_names($context);
|
||||
}
|
||||
|
||||
$PAGE->set_navigation_overflow_state(false);
|
||||
// In a course category context we leverage overflow for the tertiary navigation
|
||||
if ($context->contextlevel != CONTEXT_COURSECAT) {
|
||||
$PAGE->set_navigation_overflow_state(false);
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
if ($context->contextlevel == CONTEXT_COURSE || $context->contextlevel == CONTEXT_MODULE) {
|
||||
echo $OUTPUT->render_participants_tertiary_nav($course);
|
||||
|
||||
@@ -204,7 +204,11 @@ if ($capability && ($allowoverrides || ($allowsafeoverrides && is_safe_capabilit
|
||||
}
|
||||
}
|
||||
|
||||
$PAGE->set_navigation_overflow_state(false);
|
||||
// When we are within a category context we leave it to the overflow state to display additional nav nodes.
|
||||
if ($context->contextlevel != CONTEXT_COURSECAT) {
|
||||
$PAGE->set_navigation_overflow_state(false);
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
if ($context->contextlevel == CONTEXT_COURSE || $context->contextlevel == CONTEXT_MODULE) {
|
||||
echo $OUTPUT->render_participants_tertiary_nav($course);
|
||||
|
||||
@@ -2777,6 +2777,17 @@ class core_course_category implements renderable, cacheable_object, IteratorAggr
|
||||
return has_capability('moodle/category:manage', $this->get_context());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the category has access to content bank
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_contentbank() {
|
||||
$cb = new \core_contentbank\contentbank();
|
||||
return ($cb->is_context_allowed($this->get_context()) &&
|
||||
has_capability('moodle/contentbank:access', $this->get_context()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user has the manage capability on the parent category.
|
||||
* @return bool
|
||||
|
||||
@@ -173,6 +173,14 @@ class helper {
|
||||
$manageurl = new \moodle_url('/course/management.php', array('categoryid' => $category->id));
|
||||
$baseurl = new \moodle_url($manageurl, array('sesskey' => \sesskey()));
|
||||
$actions = array();
|
||||
|
||||
// View link.
|
||||
$actions['view'] = [
|
||||
'url' => new \moodle_url('/course/index.php', ['categoryid' => $category->id]),
|
||||
'icon' => null,
|
||||
'string' => get_string('view')
|
||||
];
|
||||
|
||||
// Edit.
|
||||
if ($category->can_edit()) {
|
||||
$actions['edit'] = array(
|
||||
@@ -252,36 +260,15 @@ class helper {
|
||||
);
|
||||
}
|
||||
|
||||
// Assign roles.
|
||||
if ($category->can_review_roles()) {
|
||||
$actions['assignroles'] = array(
|
||||
'url' => new \moodle_url('/admin/roles/assign.php', array('contextid' => $category->get_context()->id,
|
||||
'returnurl' => $manageurl->out_as_local_url(false))),
|
||||
'icon' => new \pix_icon('t/assignroles', new \lang_string('assignroles', 'role')),
|
||||
'string' => new \lang_string('assignroles', 'role')
|
||||
);
|
||||
}
|
||||
|
||||
// Permissions.
|
||||
if ($category->can_review_permissions()) {
|
||||
$actions['permissions'] = array(
|
||||
'url' => new \moodle_url('/admin/roles/permissions.php', array('contextid' => $category->get_context()->id,
|
||||
'returnurl' => $manageurl->out_as_local_url(false))),
|
||||
'url' => new \moodle_url('/admin/roles/permissions.php', ['contextid' => $category->get_context()->id]),
|
||||
'icon' => new \pix_icon('i/permissions', new \lang_string('permissions', 'role')),
|
||||
'string' => new \lang_string('permissions', 'role')
|
||||
);
|
||||
}
|
||||
|
||||
// Check permissions.
|
||||
if ($category->can_review_permissions()) {
|
||||
$actions['checkroles'] = array(
|
||||
'url' => new \moodle_url('/admin/roles/check.php', array('contextid' => $category->get_context()->id,
|
||||
'returnurl' => $manageurl->out_as_local_url(false))),
|
||||
'icon' => new \pix_icon('i/checkpermissions', new \lang_string('checkpermissions', 'role')),
|
||||
'string' => new \lang_string('checkpermissions', 'role')
|
||||
);
|
||||
}
|
||||
|
||||
// Context locking.
|
||||
if (!empty($CFG->contextlocking) && has_capability('moodle/site:managecontextlocks', $category->get_context())) {
|
||||
$parentcontext = $category->get_context()->get_parent_context();
|
||||
@@ -351,6 +338,16 @@ class helper {
|
||||
}
|
||||
}
|
||||
|
||||
// Content bank.
|
||||
if ($category->has_contentbank()) {
|
||||
$url = new \moodle_url('/contentbank/index.php', ['contextid' => $category->get_context()->id]);
|
||||
$actions['contentbank'] = [
|
||||
'url' => $url,
|
||||
'icon' => new \pix_icon('i/contentbank', ''),
|
||||
'string' => get_string('contentbank')
|
||||
];
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,12 +64,16 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* Displays a heading for the management pages.
|
||||
*
|
||||
* @deprecated since Moodle 4.0. This is now handled/replaced with the tertiary navigation
|
||||
* @todo Final deprecation MDL-73975
|
||||
* @param string $heading The heading to display
|
||||
* @param string|null $viewmode The current view mode if there are options.
|
||||
* @param int|null $categoryid The currently selected category if there is one.
|
||||
* @return string
|
||||
*/
|
||||
public function management_heading($heading, $viewmode = null, $categoryid = null) {
|
||||
debugging('management_heading() is deprecated. Use the class manage_categories_action_bar instead.', DEBUG_DEVELOPER);
|
||||
|
||||
$html = html_writer::start_div('coursecat-management-header clearfix');
|
||||
if (!empty($heading)) {
|
||||
$html .= $this->heading($heading);
|
||||
@@ -1294,11 +1298,13 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* Renders html to display a course search form
|
||||
*
|
||||
* @deprecated since Moodle 4.0. This is now handled within manage_categories_action_bar
|
||||
* @todo Final deprecation MDL-73975
|
||||
* @param string $value default value to populate the search field
|
||||
* @return string
|
||||
*/
|
||||
public function course_search_form($value = '') {
|
||||
|
||||
debugging('course_search_form() is deprecated. Use the class manage_categories_action_bar instead.', DEBUG_DEVELOPER);
|
||||
$data = [
|
||||
'action' => new moodle_url('/course/management.php'),
|
||||
'btnclass' => 'btn-primary',
|
||||
@@ -1337,4 +1343,13 @@ class core_course_management_renderer extends plugin_renderer_base {
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the tertiary nav for the manage categories page.
|
||||
*
|
||||
* @param \core_course\output\manage_categories_action_bar $actionbar
|
||||
* @return string The renderered template
|
||||
*/
|
||||
public function render_action_bar(\core_course\output\manage_categories_action_bar $actionbar): string {
|
||||
return $this->render_from_template('core_course/manage_category_actionbar', $actionbar->export_for_template($this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
<?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_course\output;
|
||||
|
||||
use context_coursecat;
|
||||
use core_course_category;
|
||||
use course_request;
|
||||
use moodle_page;
|
||||
use moodle_url;
|
||||
|
||||
/**
|
||||
* Class responsible for generating the action bar (tertiary nav) elements in an individual category page
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2021 Peter Dias
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class category_action_bar extends manage_categories_action_bar {
|
||||
/**
|
||||
* @var object The current category we are referring to.
|
||||
*/
|
||||
protected $category;
|
||||
/**
|
||||
* Constructor category_action_bar
|
||||
*
|
||||
* @param moodle_page $page The page object
|
||||
* @param object $category
|
||||
* @param object|null $course The course that we are generating the nav for
|
||||
* @param string|null $searchvalue
|
||||
*/
|
||||
public function __construct(moodle_page $page, object $category, ?object $course = null, ?string $searchvalue = null) {
|
||||
$this->category = $category;
|
||||
parent::__construct($page, 'courses', $course, $searchvalue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the url_select to be displayed in the participants page if available.
|
||||
*
|
||||
* @param \renderer_base $output
|
||||
* @return object|null The content required to render the url_select
|
||||
*/
|
||||
protected function get_category_select(\renderer_base $output): ?object {
|
||||
if (!$this->searchvalue && !core_course_category::is_simple_site()) {
|
||||
$categories = core_course_category::make_categories_list();
|
||||
if (count($categories) > 1) {
|
||||
foreach ($categories as $id => $cat) {
|
||||
$url = new moodle_url($this->page->url, ['categoryid' => $id]);
|
||||
$options[$url->out()] = $cat;
|
||||
}
|
||||
$currenturl = new moodle_url($this->page->url, ['categoryid' => $this->category->id]);
|
||||
$select = new \url_select($options, $currenturl, null);
|
||||
$select->set_label(get_string('categories'), ['class' => 'sr-only']);
|
||||
$select->class .= ' text-truncate w-100';
|
||||
return $select->export_for_template($output);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the additional options to be displayed within a 'More' dropdown in the tertiary navigation.
|
||||
* The predefined order defined by UX is:
|
||||
* - Add a course
|
||||
* - Add a sub cat
|
||||
* - Manage course
|
||||
* - Request a course
|
||||
* - Course pending approval
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_additional_category_options(): array {
|
||||
global $CFG, $DB;
|
||||
if ($this->category->is_uservisible()) {
|
||||
$context = get_category_or_system_context($this->category->id);
|
||||
if (has_capability('moodle/course:create', $context)) {
|
||||
$params = [
|
||||
'category' => $this->category->id ?: $CFG->defaultrequestcategory,
|
||||
'returnto' => $this->category->id ? 'category' : 'topcat'
|
||||
];
|
||||
|
||||
$options[0] = [
|
||||
'url' => new moodle_url('/course/edit.php', $params),
|
||||
'string' => get_string('addnewcourse')
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($CFG->enablecourserequests)) {
|
||||
// Display an option to request a new course.
|
||||
if (course_request::can_request($context)) {
|
||||
$params = [];
|
||||
if ($context instanceof context_coursecat) {
|
||||
$params['category'] = $context->instanceid;
|
||||
}
|
||||
|
||||
$options[3] = [
|
||||
'url' => new moodle_url('/course/request.php', $params),
|
||||
'string' => get_string('requestcourse')
|
||||
];
|
||||
}
|
||||
|
||||
// Display the manage pending requests option.
|
||||
if (has_capability('moodle/site:approvecourse', $context)) {
|
||||
$disabled = !$DB->record_exists('course_request', array());
|
||||
if (!$disabled) {
|
||||
$options[4] = [
|
||||
'url' => new moodle_url('/course/pending.php'),
|
||||
'string' => get_string('coursespending')
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->category->can_create_course() || $this->category->has_manage_capability()) {
|
||||
// Add 'Manage' button if user has permissions to edit this category.
|
||||
$options[2] = [
|
||||
'url' => new moodle_url('/course/management.php', ['categoryid' => $this->category->id]),
|
||||
'string' => get_string('managecourses')
|
||||
];
|
||||
|
||||
if ($this->category->has_manage_capability()) {
|
||||
$addsubcaturl = new moodle_url('/course/editcategory.php', array('parent' => $this->category->id));
|
||||
$options[1] = [
|
||||
'url' => $addsubcaturl,
|
||||
'string' => get_string('addsubcategory')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// We have stored the options in a predefined order. Sort it based on index and return.
|
||||
if (isset($options)) {
|
||||
sort($options);
|
||||
return ['options' => $options];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the content to be displayed on the category page.
|
||||
*
|
||||
* @param \renderer_base $output
|
||||
* @return array Consists of the following:
|
||||
* - categoryselect A list of available categories to be fed into a urlselect
|
||||
* - search The course search form
|
||||
* - additionaloptions Additional actions that can be performed in a category
|
||||
*/
|
||||
public function export_for_template(\renderer_base $output): array {
|
||||
return [
|
||||
'categoryselect' => $this->get_category_select($output),
|
||||
'search' => $this->get_search_form(),
|
||||
'additionaloptions' => $this->get_additional_category_options()
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
<?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_course\output;
|
||||
|
||||
use moodle_page;
|
||||
use moodle_url;
|
||||
|
||||
/**
|
||||
* Class responsible for generating the action bar (tertiary nav) elements in the category management page
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2021 Peter Dias
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class manage_categories_action_bar implements \renderable {
|
||||
/** @var object $course The course we are dealing with. */
|
||||
protected $course;
|
||||
/** @var moodle_page $page The current page. */
|
||||
protected $page;
|
||||
/** @var string|null $viewmode The viewmode of the underlying page - Course and categories, categories or courses */
|
||||
protected $viewmode;
|
||||
/** @var string|null $heading The heading to display */
|
||||
protected $heading;
|
||||
/** @var string|null $searchvalue The search value if any */
|
||||
protected $searchvalue;
|
||||
|
||||
/**
|
||||
* Constructor for the manage_categories_action_bar
|
||||
*
|
||||
* @param moodle_page $page The page object
|
||||
* @param string $viewmode The type of page we are viewing.
|
||||
* @param object|null $course The course that we are generating the nav for
|
||||
* @param string|null $searchvalue The search value if applicable
|
||||
*/
|
||||
public function __construct(moodle_page $page, string $viewmode, ?object $course, ?string $searchvalue) {
|
||||
$this->course = $course;
|
||||
$this->page = $page;
|
||||
$this->viewmode = $viewmode;
|
||||
$this->searchvalue = $searchvalue;
|
||||
if ($searchvalue) {
|
||||
$this->heading = get_string('searchresults');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the url_select to be displayed in the participants page if available.
|
||||
*
|
||||
* @param \renderer_base $output
|
||||
* @return object|null The content required to render the url_select
|
||||
*/
|
||||
protected function get_dropdown(\renderer_base $output): ?object {
|
||||
// If a search is being performed then no need to display the dropdown.
|
||||
if ($this->searchvalue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$modes = \core_course\management\helper::get_management_viewmodes();
|
||||
$activeurl = null;
|
||||
$content = [];
|
||||
foreach ($modes as $mode => $description) {
|
||||
$url = new moodle_url($this->page->url, ['view' => $mode]);
|
||||
$content[$url->out()] = $description;
|
||||
if ($this->viewmode == $mode) {
|
||||
$activeurl = $url->out();
|
||||
$this->heading = get_string("manage$mode");
|
||||
}
|
||||
}
|
||||
|
||||
// Default to the first option if asking for default. This is combined.
|
||||
if (!$activeurl && $this->viewmode === 'default') {
|
||||
$activeurl = array_key_first($content);
|
||||
$this->heading = get_string("managecombined");
|
||||
}
|
||||
|
||||
if ($content) {
|
||||
$urlselect = new \url_select($content, $activeurl, null);
|
||||
$urlselect->set_label(get_string('viewing'), ['class' => 'sr-only']);
|
||||
return $urlselect->export_for_template($output);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the url_select to be displayed in the participants page if available.
|
||||
*
|
||||
* @param \renderer_base $output
|
||||
* @return object|null The content required to render the url_select
|
||||
*/
|
||||
protected function get_category_select(\renderer_base $output): ?object {
|
||||
if (!$this->searchvalue && $this->viewmode === 'courses') {
|
||||
$categories = \core_course_category::make_categories_list(array('moodle/category:manage', 'moodle/course:create'));
|
||||
$currentcat = $this->page->url->param('categoryid');
|
||||
foreach ($categories as $id => $cat) {
|
||||
$url = new moodle_url($this->page->url, ['categoryid' => $id]);
|
||||
if ($id == $currentcat) {
|
||||
$currenturl = $url->out();
|
||||
}
|
||||
$options[$url->out()] = $cat;
|
||||
}
|
||||
|
||||
$select = new \url_select($options, $currenturl, null);
|
||||
$select->set_label(get_string('category'), ['class' => 'sr-only']);
|
||||
$select->class .= ' text-truncate w-100';
|
||||
return $select->export_for_template($output);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the search box
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_search_form(): array {
|
||||
return [
|
||||
'action' => new moodle_url('/course/management.php'),
|
||||
'btnclass' => 'btn-primary',
|
||||
'inputname' => 'search',
|
||||
'searchstring' => get_string('searchcourses'),
|
||||
'query' => $this->searchvalue
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the content to be displayed on the participants page.
|
||||
*
|
||||
* @param \renderer_base $output
|
||||
* @return array Consists of the following:
|
||||
* - urlselect A stdclass representing the standard navigation options to be fed into a urlselect
|
||||
* - renderedcontent Rendered content to be displayed in line with the tertiary nav
|
||||
*/
|
||||
public function export_for_template(\renderer_base $output): array {
|
||||
return [
|
||||
'urlselect' => $this->get_dropdown($output),
|
||||
'categoryselect' => $this->get_category_select($output),
|
||||
'search' => $this->get_search_form(),
|
||||
'heading' => $this->heading,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -112,6 +112,11 @@ if ($id) {
|
||||
$PAGE->set_context($catcontext);
|
||||
}
|
||||
|
||||
// We are adding a new course and have a category context.
|
||||
if (isset($catcontext)) {
|
||||
$PAGE->set_secondary_active_tab('categorymain');
|
||||
}
|
||||
|
||||
// Prepare course and the editor.
|
||||
$editoroptions = array('maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes'=>$CFG->maxbytes, 'trusttext'=>false, 'noclean'=>true);
|
||||
$overviewfilesoptions = course_overviewfiles_options($course);
|
||||
|
||||
@@ -650,9 +650,13 @@ function get_category_or_system_context($categoryid) {
|
||||
* Print the buttons relating to course requests.
|
||||
*
|
||||
* @param context $context current page context.
|
||||
* @deprecated since Moodle 4.0
|
||||
* @todo Final deprecation MDL-73976
|
||||
*/
|
||||
function print_course_request_buttons($context) {
|
||||
global $CFG, $DB, $OUTPUT;
|
||||
debugging("print_course_request_buttons() is deprecated. " .
|
||||
"This is replaced with the category_action_bar tertiary navigation.", DEBUG_DEVELOPER);
|
||||
if (empty($CFG->enablecourserequests)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ $PAGE->set_pagelayout('admin');
|
||||
$PAGE->set_title($strmanagement);
|
||||
$PAGE->set_heading($pageheading);
|
||||
$PAGE->requires->js_call_amd('core_course/copy_modal', 'init', array($context->id));
|
||||
$PAGE->set_secondary_active_tab('managecategory');
|
||||
$PAGE->set_secondary_active_tab('categorymain');
|
||||
|
||||
// This is a system level page that operates on other contexts.
|
||||
require_login();
|
||||
@@ -473,12 +473,8 @@ $displaycourselisting = ($viewmode === 'default' || $viewmode === 'combined' ||
|
||||
$displaycoursedetail = (isset($courseid));
|
||||
|
||||
echo $renderer->header();
|
||||
|
||||
if (!$issearching) {
|
||||
echo $renderer->management_heading($strmanagement, $viewmode, $categoryid);
|
||||
} else {
|
||||
echo $renderer->management_heading(new lang_string('searchresults'));
|
||||
}
|
||||
$actionbar = new \core_course\output\manage_categories_action_bar($PAGE, $viewmode, $course, $search);
|
||||
echo $renderer->render_action_bar($actionbar);
|
||||
|
||||
if (count($notificationspass) > 0) {
|
||||
echo $renderer->notification(join('<br />', $notificationspass), 'notifysuccess');
|
||||
@@ -489,8 +485,6 @@ if (count($notificationsfail) > 0) {
|
||||
|
||||
// Start the management form.
|
||||
|
||||
echo $renderer->course_search_form($search);
|
||||
|
||||
echo $renderer->management_form_start();
|
||||
|
||||
echo $renderer->accessible_skipto_links($displaycategorylisting, $displaycourselisting, $displaycoursedetail);
|
||||
|
||||
+2
-42
@@ -1667,14 +1667,8 @@ class core_course_renderer extends plugin_renderer_base {
|
||||
$coursecat = core_course_category::get(is_object($category) ? $category->id : $category);
|
||||
}
|
||||
$site = get_site();
|
||||
$output = '';
|
||||
|
||||
if ($coursecat->can_create_course() || $coursecat->has_manage_capability()) {
|
||||
// Add 'Manage' button if user has permissions to edit this category.
|
||||
$managebutton = $this->single_button(new moodle_url('/course/management.php',
|
||||
array('categoryid' => $coursecat->id)), get_string('managecourses'), 'get');
|
||||
$this->page->set_button($managebutton);
|
||||
}
|
||||
$actionbar = new \core_course\output\category_action_bar($this->page, $coursecat);
|
||||
$output = $this->render_from_template('core_course/category_actionbar', $actionbar->export_for_template($this));
|
||||
|
||||
if (core_course_category::is_simple_site()) {
|
||||
// There is only one category in the system, do not display link to it.
|
||||
@@ -1686,17 +1680,6 @@ class core_course_renderer extends plugin_renderer_base {
|
||||
} else {
|
||||
$strfulllistofcourses = get_string('fulllistofcourses');
|
||||
$this->page->set_title("$site->shortname: $strfulllistofcourses");
|
||||
|
||||
// Print the category selector
|
||||
$categorieslist = core_course_category::make_categories_list();
|
||||
if (count($categorieslist) > 1) {
|
||||
$output .= html_writer::start_tag('div', array('class' => 'categorypicker'));
|
||||
$select = new single_select(new moodle_url('/course/index.php'), 'categoryid',
|
||||
core_course_category::make_categories_list(), $coursecat->id, null, 'switchcategory');
|
||||
$select->set_label(get_string('categories').':', ['class' => 'sr-only']);
|
||||
$output .= $this->render($select);
|
||||
$output .= html_writer::end_tag('div'); // .categorypicker
|
||||
}
|
||||
}
|
||||
|
||||
// Print current category description
|
||||
@@ -1741,33 +1724,10 @@ class core_course_renderer extends plugin_renderer_base {
|
||||
$catdisplayoptions['viewmoreurl'] = new moodle_url($baseurl, array('browse' => 'categories', 'page' => 1));
|
||||
}
|
||||
$chelper->set_courses_display_options($coursedisplayoptions)->set_categories_display_options($catdisplayoptions);
|
||||
// Add course search form.
|
||||
$output .= $this->course_search_form();
|
||||
|
||||
// Display course category tree.
|
||||
$output .= $this->coursecat_tree($chelper, $coursecat);
|
||||
|
||||
// Add action buttons
|
||||
$output .= $this->container_start('buttons mt-3');
|
||||
if ($coursecat->is_uservisible()) {
|
||||
$context = get_category_or_system_context($coursecat->id);
|
||||
if (has_capability('moodle/course:create', $context)) {
|
||||
// Print link to create a new course, for the 1st available category.
|
||||
if ($coursecat->id) {
|
||||
$url = new moodle_url('/course/edit.php', array('category' => $coursecat->id, 'returnto' => 'category'));
|
||||
} else {
|
||||
$url = new moodle_url('/course/edit.php',
|
||||
array('category' => $CFG->defaultrequestcategory, 'returnto' => 'topcat'));
|
||||
}
|
||||
$output .= $this->single_button($url, get_string('addnewcourse'), 'get');
|
||||
}
|
||||
ob_start();
|
||||
print_course_request_buttons($context);
|
||||
$output .= ob_get_contents();
|
||||
ob_end_clean();
|
||||
}
|
||||
$output .= $this->container_end();
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_course/category_actionbar
|
||||
|
||||
Displays the tertiary nav for the category page
|
||||
|
||||
Context variables required for this template:
|
||||
* urlselect Object - The content to be rendered within the url_select
|
||||
* renderedcontent String - Any additional content/actions to be displayed inline with the select box
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"categoryselect" : {
|
||||
"formid": "url_select_f61834256d7754158",
|
||||
"classes": "urlselect",
|
||||
"label": "",
|
||||
"disabled": false,
|
||||
"title":null,
|
||||
"id":"url_select61834256d7754159",
|
||||
"sesskey":"LWILINyZMH",
|
||||
"action":"http:\/\/localhost\/stable_master\/course\/jumpto.php",
|
||||
"showbutton":null,
|
||||
"options": [
|
||||
{
|
||||
"name":"Category 1",
|
||||
"value":"\/course\/index.php\/?categoryid=279"
|
||||
},
|
||||
{
|
||||
"name":"Category 2",
|
||||
"value":"\/course\/index.php\/?categoryid=280"
|
||||
},
|
||||
{
|
||||
"name":"Category 3",
|
||||
"value":"\/course\/index.php\/?categoryid=281"
|
||||
}
|
||||
],
|
||||
"labelattributes":[],
|
||||
"helpicon":false,
|
||||
"attributes":[]
|
||||
},
|
||||
"search": {
|
||||
"action": "https://moodle.local/admin/search.php",
|
||||
"extraclasses": "my-2",
|
||||
"inputname": "search",
|
||||
"inform": false,
|
||||
"searchstring": "Search settings",
|
||||
"value": "policy",
|
||||
"btnclass": "primary",
|
||||
"query": "themedesigner",
|
||||
"hiddenfields": [
|
||||
{
|
||||
"name": "context",
|
||||
"value": "11"
|
||||
}
|
||||
]
|
||||
},
|
||||
"additionaloptions": {
|
||||
"options": [
|
||||
{
|
||||
"url": "\/course\/index.php\/?categoryid=281",
|
||||
"string": "Action 1"
|
||||
"attributes": [
|
||||
{
|
||||
"name": "data-id",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"name": "aria-role",
|
||||
"value": "test"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}}
|
||||
<div class="container-fluid tertiary-navigation" id="action_bar">
|
||||
<div class="row">
|
||||
{{#categoryselect}}
|
||||
<div class="navitem">
|
||||
{{> core/url_select }}
|
||||
</div>
|
||||
{{/categoryselect}}
|
||||
{{#search}}
|
||||
<div class="navitem">
|
||||
{{> core/search_input }}
|
||||
</div>
|
||||
{{/search}}
|
||||
{{#additionaloptions}}
|
||||
<div class="ml-auto d-flex">
|
||||
<div class="navitem dropdown">
|
||||
<button aria-label="{{#str}}moreactions{{/str}}" class="btn btn-secondary dropdown-toggle" id="dropdown-actions" data-toggle="dropdown" aria-haspopup="true" aria-controls="moreactionsmenu">
|
||||
{{#str}}moremenu{{/str}}
|
||||
</button>
|
||||
|
||||
<div id="moreactionsmenu" class="dropdown-menu" aria-labelledby="dropdown-actions" role="menu">
|
||||
{{#options}}
|
||||
<a role="menuitem" class="dropdown-item" {{#attributes}}{{name}}="{{value}}"{{/attributes}} href="{{url}}" tabindex="-1">{{string}}</a>
|
||||
{{/options}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/additionaloptions}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,119 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_course/manage_category_actionbar
|
||||
|
||||
Displays the tertiary nav for the category page
|
||||
|
||||
Context variables required for this template:
|
||||
* urlselect Object - The content to be rendered within the url_select
|
||||
* renderedcontent String - Any additional content/actions to be displayed inline with the select box
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"urlselect" : {
|
||||
"formid": "url_select_f61834256d7754158",
|
||||
"classes": "urlselect",
|
||||
"label": "",
|
||||
"disabled": false,
|
||||
"title":null,
|
||||
"id":"url_select61834256d7754159",
|
||||
"sesskey":"LWILINyZMH",
|
||||
"action":"http:\/\/localhost\/stable_master\/course\/jumpto.php",
|
||||
"showbutton":null,
|
||||
"options": [
|
||||
{
|
||||
"name":"Course and categories",
|
||||
"value":"\/course\/index.php\/?categoryid=279"
|
||||
},
|
||||
{
|
||||
"name":"Courses",
|
||||
"value":"\/course\/index.php\/?categoryid=280"
|
||||
},
|
||||
{
|
||||
"name":"Categories",
|
||||
"value":"\/course\/index.php\/?categoryid=281"
|
||||
}
|
||||
],
|
||||
"labelattributes":[],
|
||||
"helpicon":false,
|
||||
"attributes":[]
|
||||
},
|
||||
"categoryselect" : {
|
||||
"formid": "url_select_f61834256d7754158",
|
||||
"classes": "urlselect",
|
||||
"label": "",
|
||||
"disabled": false,
|
||||
"title":null,
|
||||
"id":"url_select61834256d7754159",
|
||||
"sesskey":"LWILINyZMH",
|
||||
"action":"http:\/\/localhost\/stable_master\/course\/jumpto.php",
|
||||
"showbutton":null,
|
||||
"options": [
|
||||
{
|
||||
"name":"Category 1",
|
||||
"value":"\/course\/index.php\/?categoryid=279"
|
||||
},
|
||||
{
|
||||
"name":"Category 2",
|
||||
"value":"\/course\/index.php\/?categoryid=280"
|
||||
},
|
||||
{
|
||||
"name":"Category 3",
|
||||
"value":"\/course\/index.php\/?categoryid=281"
|
||||
}
|
||||
],
|
||||
"labelattributes":[],
|
||||
"helpicon":false,
|
||||
"attributes":[]
|
||||
},
|
||||
"search": {
|
||||
"action": "https://moodle.local/admin/search.php",
|
||||
"extraclasses": "my-2",
|
||||
"inputname": "search",
|
||||
"inform": false,
|
||||
"searchstring": "Search settings",
|
||||
"value": "policy",
|
||||
"btnclass": "primary",
|
||||
"query": "themedesigner",
|
||||
"hiddenfields": [
|
||||
{
|
||||
"name": "context",
|
||||
"value": "11"
|
||||
}
|
||||
]
|
||||
},
|
||||
"heading": "Heading of page"
|
||||
}
|
||||
}}
|
||||
<div class="container-fluid tertiary-navigation" id="action_bar">
|
||||
<div class="row">
|
||||
{{#urlselect}}
|
||||
<div class="navitem">
|
||||
{{> core/url_select }}
|
||||
</div>
|
||||
{{/urlselect}}
|
||||
{{#categoryselect}}
|
||||
<div class="navitem">
|
||||
{{> core/url_select }}
|
||||
</div>
|
||||
{{/categoryselect}}
|
||||
{{#search}}
|
||||
<div class="navitem">
|
||||
{{> core/search_input }}
|
||||
</div>
|
||||
{{/search}}
|
||||
</div>
|
||||
</div>
|
||||
<h2>{{heading}}</h2>
|
||||
@@ -1118,7 +1118,6 @@ class core_course_management_helper_test extends advanced_testcase {
|
||||
$this->assertArrayHasKey('moveup', $actions);
|
||||
$this->assertArrayHasKey('movedown', $actions);
|
||||
$this->assertArrayHasKey('delete', $actions);
|
||||
$this->assertArrayHasKey('assignroles', $actions);
|
||||
$this->assertArrayHasKey('permissions', $actions);
|
||||
$this->assertArrayHasKey('cohorts', $actions);
|
||||
$this->assertArrayHasKey('filters', $actions);
|
||||
|
||||
@@ -1225,6 +1225,8 @@ $string['makeavailable'] = 'Make available';
|
||||
$string['makeeditable'] = 'If you make \'{$a}\' editable by the web server process (eg apache) then you could edit this file directly from this page';
|
||||
$string['makethismyhome'] = 'Make this my home page';
|
||||
$string['makeunavailable'] = 'Make unavailable';
|
||||
$string['managecombined'] = 'Manage course categories and courses';
|
||||
$string['managecategories'] = 'Manage course categories';
|
||||
$string['manageblocks'] = 'Blocks';
|
||||
$string['managecategorythis'] = 'Manage this category';
|
||||
$string['managecontentbanktypes'] = 'Manage content types';
|
||||
@@ -1374,6 +1376,7 @@ $string['movefull'] = 'Move {$a} to this location';
|
||||
$string['movehere'] = 'Move to here';
|
||||
$string['moveleft'] = 'Move left';
|
||||
$string['moremenu'] = 'More';
|
||||
$string['moreactions'] = 'More actions';
|
||||
$string['moveright'] = 'Move right';
|
||||
$string['movesection'] = 'Move section {$a}';
|
||||
$string['moveselectedcategoriesto'] = 'Move selected categories to';
|
||||
|
||||
@@ -586,7 +586,9 @@ class secondary extends view {
|
||||
// that are redirected to, be in the course context or module context depending on which callback was used.
|
||||
// Third part plugins were checked to see if any existing plugins had settings in a system context and none were found.
|
||||
// The request of third party developers is to keep their settings within the specified context.
|
||||
if ($this->page->context->contextlevel != CONTEXT_COURSE && $this->page->context->contextlevel != CONTEXT_MODULE) {
|
||||
if ($this->page->context->contextlevel != CONTEXT_COURSE
|
||||
&& $this->page->context->contextlevel != CONTEXT_MODULE
|
||||
&& $this->page->context->contextlevel != CONTEXT_COURSECAT) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -657,8 +659,12 @@ class secondary extends view {
|
||||
$settingsnav = $this->page->settingsnav;
|
||||
$mainnode = $settingsnav->find('categorysettings', self::TYPE_CONTAINER);
|
||||
$nodes = $this->get_default_category_mapping();
|
||||
$siteadmin = $settingsnav->find('root', self::TYPE_SITE_ADMIN);
|
||||
|
||||
if ($mainnode) {
|
||||
// If an admin is viewing a category context then load the site admin menu.
|
||||
if ($siteadmin) {
|
||||
$this->load_admin_navigation();
|
||||
} else if ($mainnode) {
|
||||
$url = new \moodle_url('/course/index.php', ['categoryid' => $this->context->instanceid]);
|
||||
$this->add($this->context->get_context_name(), $url, self::TYPE_CONTAINER, null, 'categorymain');
|
||||
|
||||
|
||||
@@ -5426,7 +5426,8 @@ class settings_navigation extends navigation_node {
|
||||
$categorynode->add(get_string('editcategorythis'), $editurl, self::TYPE_SETTING, null, 'edit', new pix_icon('i/edit', ''));
|
||||
|
||||
$addsubcaturl = new moodle_url('/course/editcategory.php', array('parent' => $catcontext->instanceid));
|
||||
$categorynode->add(get_string('addsubcategory'), $addsubcaturl, self::TYPE_SETTING, null, 'addsubcat', new pix_icon('i/withsubcat', ''));
|
||||
$categorynode->add(get_string('addsubcategory'), $addsubcaturl, self::TYPE_SETTING, null,
|
||||
'addsubcat', new pix_icon('i/withsubcat', ''))->set_show_in_secondary_navigation(false);
|
||||
}
|
||||
|
||||
// Assign local roles
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
@core @core_course
|
||||
Feature: Role assignments can be made at the category level
|
||||
In order to grant a user different capabilities
|
||||
As a user
|
||||
I can assign roles in categories
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| manager | Manager | Manager |
|
||||
And the following "categories" exist:
|
||||
| name | category | idnumber |
|
||||
| Cat 1 | 0 | CAT1 |
|
||||
And the following "role assigns" exist:
|
||||
| user | role | contextlevel | reference |
|
||||
| manager | manager | Category | CAT1 |
|
||||
And I log in as "admin"
|
||||
|
||||
@javascript
|
||||
Scenario: A user with a category role can assign roles
|
||||
Given I define the allowed role assignments for the "Manager" role as:
|
||||
| Teacher | Assignable |
|
||||
And I log out
|
||||
And I log in as "manager"
|
||||
And I am on course index
|
||||
When I follow "Cat 1"
|
||||
And I navigate to "Permissions" in current page administration
|
||||
Then I should see "Assign roles" in the "jump" "select"
|
||||
|
||||
@javascript
|
||||
Scenario: A user with a category role cannot assign roles if there are no roles to assign
|
||||
Given I define the allowed role assignments for the "Manager" role as:
|
||||
| Manager | Not assignable |
|
||||
| Course creator | Not assignable |
|
||||
| Teacher | Not assignable |
|
||||
| Non-editing teacher | Not assignable |
|
||||
| Student | Not assignable |
|
||||
And I change window size to "large"
|
||||
And I log out
|
||||
And I log in as "manager"
|
||||
And I am on course index
|
||||
When I follow "Cat 1"
|
||||
And I navigate to "Permissions" in current page administration
|
||||
Then I should not see "Assign roles" in the "jump" "select"
|
||||
Reference in New Issue
Block a user