Merge branch 'MDL-73645-master-1' of git://github.com/mihailges/moodle

This commit is contained in:
Jake Dallimore 2022-03-02 14:10:19 +08:00
commit c08caf57c5
18 changed files with 598 additions and 65 deletions

View File

@ -69,7 +69,9 @@ $PAGE->set_context($context);
// Set up navigation and breadcrumbs.
$strrecipients = get_string('recipients', 'badges');
$PAGE->navbar->add($badge->name, new moodle_url('overview.php', array('id' => $badge->id)))->add($strrecipients);
$PAGE->navbar->add($badge->name, new moodle_url('overview.php', array('id' => $badge->id)))
->add($strrecipients, new moodle_url('recipients.php', array('id' => $badge->id)))
->add(get_string('award', 'badges'));
$PAGE->set_title($strrecipients);
$PAGE->set_heading($heading);

View File

@ -73,7 +73,9 @@ $PAGE->set_context($context);
$PAGE->set_url('/badges/criteria_settings.php', $urlparams);
$PAGE->set_heading($heading);
$PAGE->set_title($badge->name);
$PAGE->navbar->add($badge->name, new moodle_url('overview.php', array('id' => $badge->id)))->add(get_string('criteria_' . $type, 'badges'));
$PAGE->navbar->add($badge->name, new moodle_url('overview.php', array('id' => $badge->id)))
->add(get_string('bcriteria', 'badges'), new moodle_url('criteria.php', ['id' => $badge->id]))
->add(get_string('criteria_' . $type, 'badges'));
$cparams = array('criteriatype' => $type, 'badgeid' => $badge->id);
if ($edit) {

View File

@ -88,6 +88,9 @@ if ($PAGE->course) {
$PAGE->set_url(new \moodle_url('/contentbank/edit.php', $values));
$PAGE->set_context($context);
if ($content) {
$PAGE->navbar->add($content->get_name(), new \moodle_url('/contentbank/view.php', ['id' => $id]));
}
$PAGE->navbar->add(get_string('edit'));
$PAGE->set_title($title);
$PAGE->set_pagelayout('incourse');

View File

@ -46,7 +46,6 @@ $strreset = get_string('reset');
$strresetcourse = get_string('resetcourse');
$strremove = get_string('remove');
$PAGE->navbar->add($strresetcourse);
$PAGE->set_title($course->fullname.': '.$strresetcourse);
$PAGE->set_heading($course->fullname.': '.$strresetcourse);

View File

@ -40,7 +40,8 @@ if (!$plugin) {
require_login($course);
require_capability('enrol/' . $type . ':config', $context);
$PAGE->set_url('/enrol/editinstance.php', array('courseid' => $course->id, 'id' => $instanceid, 'type' => $type));
$url = new moodle_url('/enrol/editinstance.php', ['courseid' => $course->id, 'id' => $instanceid, 'type' => $type]);
$PAGE->set_url($url);
$PAGE->set_pagelayout('admin');
$PAGE->set_docs_path('enrol/' . $type . '/edit');
@ -54,6 +55,11 @@ if (!enrol_is_enabled($type)) {
if ($instanceid) {
$instance = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => $type, 'id' => $instanceid), '*', MUST_EXIST);
if ($instance->status == ENROL_INSTANCE_DISABLED) { // The instance is currently disabled.
navigation_node::override_active_url(new moodle_url('/enrol/instances.php', ['id' => $course->id]));
$name = $instance->name ?: get_string('pluginname', 'enrol_' . $type);
$PAGE->navbar->add($name, $url);
}
} else {
require_capability('moodle/course:enrolconfig', $context);
@ -64,6 +70,7 @@ if ($instanceid) {
$instance->id = null;
$instance->courseid = $course->id;
$instance->status = ENROL_INSTANCE_ENABLED; // Do not use default for automatically created instances here.
$PAGE->navbar->add(get_string('pluginname', 'enrol_' . $type), $url);
}
$mform = new enrol_instance_edit_form(null, array($instance, $plugin, $context, $type, $return));

View File

@ -30,7 +30,7 @@ $contextid = optional_param('id', SYSCONTEXTID, PARAM_INT);
$action = optional_param('action', '', PARAM_ALPHA);
$edit = optional_param('edit', false, PARAM_BOOL); //are we editing?
$PAGE->set_url('/grade/edit/letter/index.php', array('id' => $contextid));
$url = new moodle_url('/grade/edit/letter/index.php', array('id' => $contextid));
list($context, $course, $cm) = get_context_info_array($contextid);
$contextid = null;//now we have a context object throw away the $contextid from the params
@ -42,7 +42,11 @@ if (!$edit) {
}
} else {//else we're editing
require_capability('moodle/grade:manageletters', $context);
navigation_node::override_active_url($url);
$url->param('edit', 1);
$PAGE->navbar->add(get_string('editgradeletters', 'grades'), $url);
}
$PAGE->set_url($url);
$returnurl = null;
$editparam = null;

View File

@ -79,7 +79,6 @@ if ($id) {
require_login($course);
$context = context_course::instance($course->id);
require_capability('moodle/grade:manage', $context);
navigation_node::override_active_url(new moodle_url('/grade/edit/outcome/course.php', array('id'=>$courseid)));
$outcome_rec = new stdClass();
$outcome_rec->standard = 0;
@ -98,6 +97,10 @@ if ($id) {
if (!$courseid) {
require_once $CFG->libdir.'/adminlib.php';
admin_externalpage_setup('outcomes');
} else {
navigation_node::override_active_url(new moodle_url('/grade/edit/outcome/course.php', ['id' => $courseid]));
$PAGE->navbar->add(get_string('manageoutcomes', 'grades'),
new moodle_url('/grade/edit/outcome/index.php', ['id' => $courseid]));
}
// default return url
@ -158,6 +161,8 @@ if ($mform->is_cancelled()) {
redirect($returnurl);
}
$PAGE->navbar->add($heading, $url);
print_grade_page_head($courseid ?: SITEID, 'outcome', 'edit', $heading, false, false, false);
if (!grade_scale::fetch_all_local($courseid) && !grade_scale::fetch_all_global()) {

View File

@ -32,7 +32,8 @@ $courseid = optional_param('courseid', 0, PARAM_INT);
$action = optional_param('action', '', PARAM_ALPHA);
$scope = optional_param('scope', 'custom', PARAM_ALPHA);
$PAGE->set_url('/grade/edit/outcome/import.php', array('courseid' => $courseid));
$url = new moodle_url('/grade/edit/outcome/import.php', array('courseid' => $courseid));
$PAGE->set_url($url);
$PAGE->set_pagelayout('admin');
/// Make sure they can even access this course
@ -46,6 +47,11 @@ if ($courseid) {
if (empty($CFG->enableoutcomes)) {
redirect('../../index.php?id='.$courseid);
}
navigation_node::override_active_url(new moodle_url('/grade/edit/outcome/course.php', ['id' => $courseid]));
$PAGE->navbar->add(get_string('manageoutcomes', 'grades'),
new moodle_url('/grade/edit/outcome/index.php', ['id' => $courseid]));
$PAGE->navbar->add(get_string('importoutcomes', 'grades'),
new moodle_url('/grade/edit/outcome/import.php', ['courseid' => $courseid]));
} else {
require_once $CFG->libdir.'/adminlib.php';
@ -55,8 +61,6 @@ if ($courseid) {
require_capability('moodle/grade:manageoutcomes', $context);
$navigation = grade_build_nav(__FILE__, get_string('outcomes', 'grades'), $courseid);
$upload_form = new import_outcomes_form();
if ($upload_form->is_cancelled()) {

View File

@ -29,7 +29,8 @@ require_once($CFG->libdir.'/gradelib.php');
$courseid = optional_param('id', 0, PARAM_INT);
$action = optional_param('action', '', PARAM_ALPHA);
$PAGE->set_url('/grade/edit/outcome/index.php', array('id' => $courseid));
$url = new moodle_url('/grade/edit/outcome/index.php', ['id' => $courseid]);
$PAGE->set_url($url);
$PAGE->set_pagelayout('admin');
/// Make sure they can even access this course
@ -44,6 +45,7 @@ if ($courseid) {
}
// This page doesn't exist on the navigation so map it to another
navigation_node::override_active_url(new moodle_url('/grade/edit/outcome/course.php', array('id'=>$courseid)));
$PAGE->navbar->add(get_string('manageoutcomes', 'grades'), $url);
} else {
if (empty($CFG->enableoutcomes)) {
redirect('../../../');
@ -90,6 +92,7 @@ switch ($action) {
if(!$deleteconfirmed){
$PAGE->set_title(get_string('outcomedelete', 'grades'));
$PAGE->navbar->add(get_string('outcomedelete', 'grades'));
echo $OUTPUT->header();
$confirmurl = new moodle_url('index.php', array(
'id' => $courseid, 'outcomeid' => $outcome->id,

View File

@ -144,6 +144,7 @@ if ($mform->is_cancelled()) {
}
$heading = $id ? get_string('editscale', 'grades') : get_string('addscale', 'grades');
$PAGE->navbar->add($heading);
print_grade_page_head($COURSE->id, 'scale', null, $heading, false, false, false);
$mform->display();

View File

@ -81,7 +81,11 @@ switch ($action) {
$deleteconfirmed = optional_param('deleteconfirmed', 0, PARAM_BOOL);
if (!$deleteconfirmed) {
$strdeletescale = get_string('delete'). ' '. get_string('scale');
if ($courseid) {
$PAGE->navbar->add(get_string('scales'), new moodle_url('/grade/edit/scale/index.php',
['id' => $courseid]));
}
$strdeletescale = get_string('deletescale', 'grades');
$PAGE->navbar->add($strdeletescale);
$PAGE->set_title($strdeletescale);
$PAGE->set_heading($COURSE->fullname);

View File

@ -76,11 +76,18 @@ if (!empty($key->userid) and $USER->id != $key->userid) {
$returnurl = $CFG->wwwroot.'/grade/export/keymanager.php?id='.$course->id;
$strkeys = get_string('keymanager', 'userkey');
$strexportgrades = get_string('export', 'grades');
$PAGE->navbar->add($strexportgrades, new moodle_url('/grade/export/index.php', ['id' => $courseid]));
$PAGE->navbar->add($strkeys, new moodle_url('/grade/export/keymanager.php', ['id' => $courseid]));
if ($id and $delete) {
if (!$confirm) {
$PAGE->set_title(get_string('deleteselectedkey'));
$PAGE->set_heading($course->fullname);
$PAGE->set_secondary_active_tab('grades');
$PAGE->navbar->add(get_string('deleteuserkey', 'userkey'));
echo $OUTPUT->header();
$optionsyes = array('id'=>$id, 'delete'=>1, 'courseid'=>$courseid, 'sesskey'=>sesskey(), 'confirm'=>1);
$optionsno = array('id'=>$courseid);
@ -118,17 +125,12 @@ if ($editform->is_cancelled()) {
redirect($returnurl);
}
$strkeys = get_string('userkeys', 'userkey');
$strgrades = get_string('grades');
if ($id) {
$strheading = get_string('edituserkey', 'userkey');
} else {
$strheading = get_string('createuserkey', 'userkey');
}
$PAGE->navbar->add($strgrades, new moodle_url('/grade/index.php', array('id'=>$courseid)));
$PAGE->navbar->add($strkeys, new moodle_url('/grade/export/keymanager.php', array('id'=>$courseid)));
$PAGE->navbar->add($strheading);
/// Print header

View File

@ -33,7 +33,8 @@ $id = optional_param('id', 0, PARAM_INT);
$delete = optional_param('delete', 0, PARAM_BOOL);
$confirm = optional_param('confirm', 0, PARAM_BOOL);
$PAGE->set_url('/grade/import/key.php', array('courseid' => $courseid, 'id' => $id));
$url = new moodle_url('/grade/import/key.php', ['courseid' => $courseid, 'id' => $id]);
$PAGE->set_url($url);
if ($id) {
if (!$key = $DB->get_record('user_private_key', array('id' => $id))) {
@ -76,11 +77,18 @@ if (!empty($key->userid) and $USER->id != $key->userid) {
$returnurl = $CFG->wwwroot.'/grade/import/keymanager.php?id='.$course->id;
$strkeys = get_string('keymanager', 'userkey');
$strimportgrades = get_string('import', 'grades');
$PAGE->navbar->add($strimportgrades, new moodle_url(new moodle_url('/grade/import/index.php', ['id' => $courseid])));
$PAGE->navbar->add($strkeys, new moodle_url('/grade/import/keymanager.php', ['id' => $courseid]));
if ($id and $delete) {
if (!$confirm) {
$PAGE->set_title(get_string('deleteselectedkey'));
$PAGE->set_heading($course->fullname);
$PAGE->set_secondary_active_tab('grades');
$PAGE->navbar->add(get_string('deleteuserkey', 'userkey'));
echo $OUTPUT->header();
$optionsyes = array('id'=>$id, 'delete'=>1, 'courseid'=>$courseid, 'sesskey'=>sesskey(), 'confirm'=>1);
$optionsno = array('id'=>$courseid);
@ -118,17 +126,12 @@ if ($editform->is_cancelled()) {
redirect($returnurl);
}
$strkeys = get_string('userkeys', 'userkey');
$strgrades = get_string('grades');
if ($id) {
$strheading = get_string('edituserkey', 'userkey');
} else {
$strheading = get_string('createuserkey', 'userkey');
}
$PAGE->navbar->add($strgrades, new moodle_url('/grade/index.php', array('id'=>$courseid)));
$PAGE->navbar->add($strkeys, new moodle_url('/grade/import/keymanager.php', array('id'=>$courseid)));
$PAGE->navbar->add($strheading);
/// Print header

View File

@ -132,7 +132,8 @@ navigation_node::override_active_url(new moodle_url('/group/index.php', array('i
$PAGE->set_pagelayout('admin');
$PAGE->navbar->add($strparticipants, new moodle_url('/user/index.php', array('id'=>$courseid)));
$PAGE->navbar->add($strgroups, new moodle_url('/group/index.php', array('id'=>$courseid)));
$PAGE->navbar->add(get_string('groupings', 'group'),
new moodle_url('/group/groupings.php', ['id' => $courseid]));
$PAGE->navbar->add($straddgroupstogroupings);
/// Print header

View File

@ -148,6 +148,7 @@ $string['decimalpoints_help'] = 'This setting determines the number of decimal p
$string['default'] = 'Default';
$string['defaultprev'] = 'Default ({$a})';
$string['deletecategory'] = 'Delete category';
$string['deletescale'] = 'Delete scale';
$string['disablegradehistory'] = 'Disable grade history';
$string['disablegradehistory_help'] = 'Disable history tracking of changes in grades related tables. This may speed up the server a little and conserve space in database.';
$string['displaylettergrade'] = 'Display letter grades';

View File

@ -26,6 +26,7 @@ $string['adduserkey'] = 'Add user key';
$string['createnewkey'] = 'Create a new user key';
$string['createuserkey'] = 'Create user key';
$string['deletekeyconfirm'] = 'Do you really want to delete this user key?';
$string['deleteuserkey'] = 'Delete user key';
$string['edituserkey'] = 'Edit user key';
$string['keyiprestriction'] = 'Key IP restriction';
$string['keyiprestriction_help'] = 'Enter a specific IP address, or a range of IP addresses that will be the only IP addresses allowed to access this data. Leave empty to disable IP restriction (not recommended).';

View File

@ -16,6 +16,12 @@
namespace theme_boost;
use core\navigation\views\view;
use navigation_node;
use moodle_url;
use action_link;
use lang_string;
/**
* Creates a navbar for boost that allows easy control of the navbar items.
*
@ -49,10 +55,36 @@ class boostnavbar implements \renderable {
protected function prepare_nodes_for_boost(): void {
global $PAGE;
// Don't show the navigation if we are in the course context.
// Defines whether section items with an action should be removed by default.
$removesections = true;
if ($this->page->context->contextlevel == CONTEXT_COURSE) {
$this->clear_items();
return;
// Remove any duplicate navbar nodes.
$this->remove_duplicate_items();
// Remove 'My courses' and 'Courses' if we are in the course context.
$this->remove('mycourses');
$this->remove('courses');
// Remove the course category breadcrumb node.
$this->remove($this->page->course->category);
// Remove the course breadcrumb node.
$this->remove($this->page->course->id);
// Remove the navbar nodes that already exist in the secondary navigation menu.
$this->remove_items_that_exist_in_navigation($PAGE->secondarynav);
switch ($this->page->pagetype) {
case 'group-groupings':
case 'group-grouping':
case 'group-overview':
case 'group-assign':
// Remove the 'Groups' navbar node in the Groupings, Grouping, group Overview and Assign pages.
$this->remove('groups');
case 'backup-backup':
case 'backup-restorefile':
case 'backup-copy':
case 'course-reset':
// Remove the 'Import' navbar node in the Backup, Restore, Copy course and Reset pages.
$this->remove('import');
}
}
$this->remove('myhome'); // Dashboard.
@ -61,18 +93,21 @@ class boostnavbar implements \renderable {
// Remove 'My courses' if we are in the module context.
if ($this->page->context->contextlevel == CONTEXT_MODULE) {
$this->remove('mycourses');
$this->remove('courses');
// Remove the course category breadcrumb node.
$this->remove($this->page->course->category);
$courseformat = course_get_format($this->page->course)->get_course();
// Section items can be only removed if a course layout (coursedisplay) is not explicitly set in the
// given course format or the set course layout is not 'One section per page'.
$removesections = !isset($courseformat->coursedisplay) ||
$courseformat->coursedisplay != COURSE_DISPLAY_MULTIPAGE;
}
if (!is_null($this->get_item('root'))) { // We are in site administration.
// Remove the 'Site administration' navbar node as it already exists in the primary navigation menu.
$this->remove('root');
// Loop through the remaining navbar nodes and remove the ones that already exist in the secondary
// navigation menu.
foreach ($this->items as $item) {
if ($PAGE->secondarynav->get($item->key)) {
$this->remove($item->key);
}
}
// Remove the navbar nodes that already exist in the secondary navigation menu.
$this->remove_items_that_exist_in_navigation($PAGE->secondarynav);
}
// Set the designated one path for courses.
@ -83,7 +118,7 @@ class boostnavbar implements \renderable {
$mycoursesnode->text = get_string('mycourses');
}
$this->remove_no_link_items();
$this->remove_no_link_items($removesections);
// Don't display the navbar if there is only one item. Apparently this is bad UX design.
if ($this->item_count() <= 1) {
@ -188,16 +223,94 @@ class boostnavbar implements \renderable {
}
/**
* Remove items that are categories or have no actions associated with them.
* Remove items that have no actions associated with them and optionally remove items that are sections.
*
* The only exception is the last item in the list which may not have a link but needs to be displayed.
*
* @param bool $removesections Whether section items should be also removed (only applies when they have an action)
*/
protected function remove_no_link_items(): void {
protected function remove_no_link_items(bool $removesections = true): void {
foreach ($this->items as $key => $value) {
if (!$value->is_last() && (!$value->has_action() || $value->type == \navigation_node::TYPE_SECTION)) {
if (!$value->is_last() &&
(!$value->has_action() || ($value->type == \navigation_node::TYPE_SECTION && $removesections))) {
unset($this->items[$key]);
}
}
$this->items = array_values($this->items);
}
/**
* Remove breadcrumb items that already exist in a given navigation view.
*
* This method removes the breadcrumb items that have a text => action match in a given navigation view
* (primary or secondary).
*
* @param view $navigationview The navigation view object.
*/
protected function remove_items_that_exist_in_navigation(view $navigationview): void {
// Loop through the navigation view items and create a 'text' => 'action' array which will be later used
// to compare whether any of the breadcrumb items matches these pairs.
$navigationviewitems = [];
foreach ($navigationview->children as $child) {
list($childtext, $childaction) = $this->get_node_text_and_action($child);
if ($childaction) {
$navigationviewitems[$childtext] = $childaction;
}
}
// Loop through the breadcrumb items and if the item's 'text' and 'action' values matches with any of the
// existing navigation view items, remove it from the breadcrumbs.
foreach ($this->items as $item) {
list($itemtext, $itemaction) = $this->get_node_text_and_action($item);
if ($itemaction) {
if (array_key_exists($itemtext, $navigationviewitems) &&
$navigationviewitems[$itemtext] === $itemaction) {
$this->remove($item->key);
}
}
}
}
/**
* Remove duplicate breadcrumb items.
*
* This method looks for breadcrumb items that have identical text and action values and removes the first item.
*/
protected function remove_duplicate_items(): void {
$taken = [];
// Reverse the order of the items before filtering so that the first occurrence is removed instead of the last.
$filtereditems = array_values(array_filter(array_reverse($this->items), function($item) use (&$taken) {
list($itemtext, $itemaction) = $this->get_node_text_and_action($item);
if ($itemaction) {
if (array_key_exists($itemtext, $taken) && $taken[$itemtext] === $itemaction) {
return false;
}
$taken[$itemtext] = $itemaction;
}
return true;
}));
// Reverse back the order.
$this->items = array_reverse($filtereditems);
}
/**
* Helper function that returns an array of the text and the outputted action url (if exists) for a given
* navigation node.
*
* @param navigation_node $node The navigation node object.
* @return array
*/
protected function get_node_text_and_action(navigation_node $node): array {
$text = $node->text instanceof lang_string ? $node->text->out() : $node->text;
$action = null;
if ($node->has_action()) {
if ($node->action instanceof moodle_url) {
$action = $node->action->out();
} else if ($node->action instanceof action_link) {
$action = $node->action->url->out();
} else {
$action = $node->action;
}
}
return [$text, $action];
}
}

View File

@ -20,6 +20,7 @@ namespace theme_boost;
* Test the boostnavbar file
*
* @package theme_boost
* @covers \theme_boost\boostnavbar
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@ -32,12 +33,13 @@ class boostnavbar_test extends \advanced_testcase {
*/
public function remove_no_link_items_provider(): array {
return [
'All nodes have links links including leaf node' => [
'All nodes have links links including leaf node. Set to remove section nodes.' => [
[
'node1' => true,
'node2' => true,
'node3' => true,
'node1' => ['hasaction' => true, 'issection' => false],
'node2' => ['hasaction' => true, 'issection' => false],
'node3' => ['hasaction' => true, 'issection' => false],
],
true,
[
'Home' => true,
'Courses' => true,
@ -47,12 +49,13 @@ class boostnavbar_test extends \advanced_testcase {
'node3' => true,
]
],
'Only some parent nodes have links. Leaf node has a link.' => [
'Only some parent nodes have links. Leaf node has a link. Set to remove section nodes.' => [
[
'node1' => false,
'node2' => true,
'node3' => true,
'node1' => ['hasaction' => false, 'issection' => false],
'node2' => ['hasaction' => true, 'issection' => false],
'node3' => ['hasaction' => true, 'issection' => false],
],
true,
[
'Home' => true,
'Courses' => true,
@ -61,12 +64,13 @@ class boostnavbar_test extends \advanced_testcase {
'node3' => true,
]
],
'All parent nodes do not have links. Leaf node has a link.' => [
'All parent nodes do not have links. Leaf node has a link. Set to remove section nodes.' => [
[
'node1' => false,
'node2' => false,
'node3' => true,
'node1' => ['hasaction' => false, 'issection' => false],
'node2' => ['hasaction' => false, 'issection' => false],
'node3' => ['hasaction' => true, 'issection' => false],
],
true,
[
'Home' => true,
'Courses' => true,
@ -74,12 +78,13 @@ class boostnavbar_test extends \advanced_testcase {
'node3' => true,
]
],
'All parent nodes have links. Leaf node does not has a link.' => [
'All parent nodes have links. Leaf node does not has a link. Set to remove section nodes.' => [
[
'node1' => true,
'node2' => true,
'node3' => false,
'node1' => ['hasaction' => true, 'issection' => false],
'node2' => ['hasaction' => true, 'issection' => false],
'node3' => ['hasaction' => false, 'issection' => false],
],
true,
[
'Home' => true,
'Courses' => true,
@ -89,12 +94,13 @@ class boostnavbar_test extends \advanced_testcase {
'node3' => false,
]
],
'All parent nodes do not have links. Leaf node does not has a link.' => [
'All parent nodes do not have links. Leaf node does not has a link. Set to remove section nodes.' => [
[
'node1' => false,
'node2' => false,
'node3' => false,
'node1' => ['hasaction' => false, 'issection' => false],
'node2' => ['hasaction' => false, 'issection' => false],
'node3' => ['hasaction' => false, 'issection' => false],
],
true,
[
'Home' => true,
'Courses' => true,
@ -102,12 +108,13 @@ class boostnavbar_test extends \advanced_testcase {
'node3' => false,
]
],
'Some parent nodes do not have links. Leaf node does not has a link.' => [
'Some parent nodes do not have links. Leaf node does not has a link. Set to remove section nodes.' => [
[
'node1' => true,
'node2' => false,
'node3' => false,
'node1' => ['hasaction' => true, 'issection' => false],
'node2' => ['hasaction' => false, 'issection' => false],
'node3' => ['hasaction' => false, 'issection' => false],
],
true,
[
'Home' => true,
'Courses' => true,
@ -115,6 +122,57 @@ class boostnavbar_test extends \advanced_testcase {
'node1' => true,
'node3' => false,
]
],
'All nodes have links links including leaf node and section nodes. Set to remove section nodes.' => [
[
'node1' => ['hasaction' => true, 'issection' => false],
'node2' => ['hasaction' => true, 'issection' => false],
'sectionnode1' => ['hasaction' => true, 'issection' => true],
'node3' => ['hasaction' => true, 'issection' => false],
],
true,
[
'Home' => true,
'Courses' => true,
'tc_1' => true,
'node1' => true,
'node2' => true,
'node3' => true,
]
],
'All nodes have links links including leaf node and section nodes. Set to not remove section nodes.' => [
[
'node1' => ['hasaction' => true, 'issection' => false],
'node2' => ['hasaction' => true, 'issection' => false],
'sectionnode1' => ['hasaction' => true, 'issection' => true],
'node3' => ['hasaction' => true, 'issection' => false],
],
false,
[
'Home' => true,
'Courses' => true,
'tc_1' => true,
'node1' => true,
'node2' => true,
'sectionnode1' => true,
'node3' => true,
]
],
'Only some parent nodes have links. Section node does not have a link. Set to not remove section nodes.' => [
[
'node1' => ['hasaction' => false, 'issection' => false],
'node2' => ['hasaction' => true, 'issection' => false],
'sectionnode1' => ['hasaction' => false, 'issection' => true],
'node3' => ['hasaction' => true, 'issection' => false],
],
true,
[
'Home' => true,
'Courses' => true,
'tc_1' => true,
'node2' => true,
'node3' => true,
]
]
];
}
@ -123,10 +181,11 @@ class boostnavbar_test extends \advanced_testcase {
*
* @dataProvider remove_no_link_items_provider
* @param array $setup
* @param bool $removesectionnodes Whether to remove the section nodes with an associated action.
* @param array $expected
* @throws \ReflectionException
*/
public function test_remove_no_link_items(array $setup, array $expected) {
public function test_remove_no_link_items(array $setup, bool $removesectionnodes, array $expected) {
global $PAGE;
$this->resetAfterTest();
@ -138,8 +197,9 @@ class boostnavbar_test extends \advanced_testcase {
$page->set_url(new \moodle_url('/course/view.php', array('id' => $course->id)));
// A dummy url to use. We don't care where it's pointing to.
$url = new \moodle_url('/');
foreach ($setup as $node => $hasaction) {
$page->navbar->add($node, $hasaction ? $url : null);
foreach ($setup as $key => $value) {
$page->navbar->add($key, $value['hasaction'] ? $url : null,
$value['issection'] ? \navigation_node::TYPE_SECTION : null);
}
$boostnavbar = $this->getMockBuilder(boostnavbar::class)
@ -155,7 +215,7 @@ class boostnavbar_test extends \advanced_testcase {
// Make the call to the function.
$rcm = $rc->getMethod('remove_no_link_items');
$rcm->setAccessible(true);
$rcm->invoke($boostnavbar);
$rcm->invoke($boostnavbar, $removesectionnodes);
// Get the value for the class variable that the function modifies.
$values = $rcp->getValue($boostnavbar);
@ -165,4 +225,322 @@ class boostnavbar_test extends \advanced_testcase {
}
$this->assertEquals($expected, $actual);
}
/**
* Provider for test_remove_duplicate_items.
*
* @return array
*/
public function remove_duplicate_items_provider(): array {
global $CFG;
return [
'Breadcrumb items with identical text and action url (actions of same type moodle_url).' => [
[
[
'text' => 'Node 1',
'action' => new \moodle_url('/page1.php')
],
[
'text' => 'Node 2',
'action' => new \moodle_url('/page2.php', ['id' => 1])
],
[
'text' => 'Node 4',
'action' => new \moodle_url('/page4.php', ['id' => 1])
],
[
'text' => 'Node 2',
'action' => new \moodle_url('/page2.php', ['id' => 1])
],
],
['Home', 'Node 1', 'Node 4', 'Node 2']
],
'Breadcrumb items with identical text and action url (actions of different type moodle_url/text).' => [
[
[
'text' => 'Node 1',
'action' => new \moodle_url('/page1.php')
],
[
'text' => 'Node 2',
'action' => new \moodle_url('/page2.php', ['id' => 1])
],
[
'text' => 'Node 4',
'action' => new \moodle_url('/page4.php', ['id' => 1])
],
[
'text' => 'Node 2',
'action' => "{$CFG->wwwroot}/page2.php?id=1"
],
],
['Home', 'Node 1', 'Node 4', 'Node 2']
],
'Breadcrumb items with identical text and action url (actions of different type moodle_url/action_link).' => [
[
[
'text' => 'Node 1',
'action' => new \moodle_url('/page1.php')
],
[
'text' => 'Node 2',
'action' => new \moodle_url('/page2.php', ['id' => 1])
],
[
'text' => 'Node 4',
'action' => new \moodle_url('/page4.php', ['id' => 1])
],
[
'text' => 'Node 2',
'action' => new \action_link(new \moodle_url('/page2.php', ['id' => 1]), 'Action link')
],
],
['Home', 'Node 1', 'Node 4', 'Node 2']
],
'Breadcrumbs items with identical text but not identical action url.' => [
[
[
'text' => 'Node 1',
'action' => new \moodle_url('/page1.php')
],
[
'text' => 'Node 2',
'action' => new \moodle_url('/page2.php', ['id' => 1])
],
[
'text' => 'Node 2',
'action' => new \moodle_url('/page2.php', ['id' => 2])
],
[
'text' => 'Node 4',
'action' => new \moodle_url('/page4.php', ['id' => 1])
],
],
['Home', 'Node 1', 'Node 2', 'Node 2', 'Node 4']
],
'Breadcrumb items with identical action url but not identical text.' => [
[
[
'text' => 'Node 1',
'action' => new \moodle_url('/page1.php')
],
[
'text' => 'Node 2',
'action' => new \moodle_url('/page2.php', ['id' => 1])
],
[
'text' => 'Node 3',
'action' => new \moodle_url('/page2.php', ['id' => 1])
],
[
'text' => 'Node 4',
'action' => new \moodle_url('/page4.php', ['id' => 1])
],
],
['Home', 'Node 1', 'Node 2', 'Node 3', 'Node 4']
],
'Breadcrumb items without any identical action url or text.' => [
[
[
'text' => 'Node 1',
'action' => new \moodle_url('/page1.php')
],
[
'text' => 'Node 2',
'action' => new \moodle_url('/page2.php', ['id' => 1])
],
[
'text' => 'Node 3',
'action' => new \moodle_url('/page3.php', ['id' => 1])
],
[
'text' => 'Node 4',
'action' => new \moodle_url('/page4.php', ['id' => 1])
],
],
['Home', 'Node 1', 'Node 2', 'Node 3', 'Node 4']
],
];
}
/**
* Test the remove_duplicate_items function.
*
* @dataProvider remove_duplicate_items_provider
* @param array $navbarnodes The array containing the text and action of the nodes to be added to the navbar
* @param array $expected The array containing the text of the expected navbar nodes
*/
public function test_remove_duplicate_items(array $navbarnodes, array $expected) {
$this->resetAfterTest();
$page = new \moodle_page();
$page->set_url('/');
// Add the navbar nodes.
foreach ($navbarnodes as $node) {
$page->navbar->add($node['text'], $node['action'], \navigation_node::TYPE_CUSTOM);
}
$boostnavbar = $this->getMockBuilder(boostnavbar::class)
->disableOriginalConstructor()
->onlyMethods([])
->getMock();
$rc = new \ReflectionClass(boostnavbar::class);
$rcp = $rc->getProperty('items');
$rcp->setAccessible(true);
$rcp->setValue($boostnavbar, $page->navbar->get_items());
// Make the call to the function.
$rcm = $rc->getMethod('remove_duplicate_items');
$rcm->setAccessible(true);
$rcm->invoke($boostnavbar);
// Get the value for the class variable that the function modifies.
$values = $rcp->getValue($boostnavbar);
$actual = [];
foreach ($values as $value) {
$actual[] = $value->text;
}
$this->assertEquals($expected, $actual);
}
/**
* Provider for test_remove_items_that_exist_in_navigation.
*
* @return array
*/
public function remove_items_that_exist_in_navigation_provider(): array {
global $CFG;
return [
'Item with identical action url and text exists in the primary navigation menu.' => [
'primary',
[
[
'text' => 'Node 1',
'action' => new \moodle_url('/page1.php')
],
],
[
'Node 1' => new \moodle_url('/page1.php'),
'Node 2' => new \moodle_url('/page2.php'),
'Node 3' => new \moodle_url('/page1.php'),
],
['Node 2', 'Node 3']
],
'Item with identical action url and text exists in the secondary navigation menu.' => [
'secondary',
[
[
'text' => 'Node 2',
'action' => new \moodle_url('/page2.php')
],
],
[
'Node 1' => new \moodle_url('/page1.php'),
'Node 2' => new \moodle_url('/page2.php'),
'Node 3' => new \moodle_url('/page1.php'),
],
['Home', 'Node 1', 'Node 3']
],
'Multiple items with identical action url and text exist in the secondary navigation menu.' => [
'secondary',
[
[
'text' => 'Node 2',
'action' => new \moodle_url('/page2.php')
],
[
'text' => 'Node 3',
'action' => new \moodle_url('/page3.php')
],
],
[
'Node 1' => new \moodle_url('/page1.php'),
'Node 2' => "{$CFG->wwwroot}/page2.php",
'Node 3' => new \action_link(new \moodle_url('/page3.php'), 'Action link'),
],
['Home', 'Node 1']
],
'No items with identical action url and text in the secondary navigation menu.' => [
'secondary',
[
[
'text' => 'Node 4',
'action' => new \moodle_url('/page4.php')
],
],
[
'Node 1' => new \moodle_url('/page1.php'),
'Node 2' => new \moodle_url('/page2.php'),
'Node 3' => new \moodle_url('/page1.php'),
],
['Home', 'Node 1', 'Node 2', 'Node 3']
],
];
}
/**
* Test the remove_items_that_exist_in_navigation function.
*
* @dataProvider remove_items_that_exist_in_navigation_provider
* @param string $navmenu The name of the navigation menu we would like to use (primary or secondary)
* @param array $navmenunodes The array containing the text and action of the nodes to be added to the navigation menu
* @param array $navbarnodes Array containing the text => action of the nodes to be added to the navbar
* @param array $expected Array containing the text of the expected navbar nodes after the filtering
*/
public function test_remove_items_that_exist_in_navigation(string $navmenu, array $navmenunodes, array $navbarnodes,
array $expected) {
global $PAGE;
// Unfortunate hack needed because people use global $PAGE around the place.
$PAGE->set_url('/');
$this->resetAfterTest();
$page = new \moodle_page();
$page->set_url('/');
switch ($navmenu) {
case 'primary':
$navigationmenu = new \core\navigation\views\primary($page);
break;
case 'secondary':
$navigationmenu = new \core\navigation\views\secondary($page);
}
$navigationmenu->initialise();
// Add the additional nodes to the navigation menu.
foreach ($navmenunodes as $navmenunode) {
$navigationmenu->add($navmenunode['text'], $navmenunode['action'], \navigation_node::TYPE_CUSTOM);
}
// Add the additional navbar nodes.
foreach ($navbarnodes as $text => $action) {
$page->navbar->add($text, $action, \navigation_node::TYPE_CUSTOM);
}
$boostnavbar = $this->getMockBuilder(boostnavbar::class)
->disableOriginalConstructor()
->onlyMethods([])
->getMock();
$rc = new \ReflectionClass(boostnavbar::class);
$rcp = $rc->getProperty('items');
$rcp->setAccessible(true);
$rcp->setValue($boostnavbar, $page->navbar->get_items());
// Make the call to the function.
$rcm = $rc->getMethod('remove_items_that_exist_in_navigation');
$rcm->setAccessible(true);
$rcm->invoke($boostnavbar, $navigationmenu);
// Get the value for the class variable that the function modifies.
$values = $rcp->getValue($boostnavbar);
$actual = [];
foreach ($values as $value) {
$actual[] = $value->text;
}
$this->assertEquals($expected, $actual);
}
}