Commit 830c3eb9 authored by Ferran Recio Calderó's avatar Ferran Recio Calderó Committed by Amaia
Browse files

MDL-71209 courseformat: add course index modules

The course index is the first UI component that implements the new
drawers and the reactive components. The course index uses the course
state to present the current course structure and changes whenever
that structure change.
parent 804e138c
......@@ -46,6 +46,10 @@ class format_topics extends core_courseformat\base {
return true;
}
public function uses_course_index() {
return true;
}
/**
* Returns the display name of the given section that the course prefers.
*
......
......@@ -2,6 +2,9 @@ This files describes API changes for course formats
Overview of this plugin type at http://docs.moodle.org/dev/Course_formats
=== 4.0 ===
* New core_courseformat\uses_course_index() to define whether the course format uses course index or not.
=== 3.10 ===
* Added the missing callback supports_ajax() to format_social.
......
......@@ -45,6 +45,10 @@ class format_weeks extends core_courseformat\base {
return true;
}
public function uses_course_index() {
return true;
}
/**
* Generate the title for this section page
* @return string the page title
......
......@@ -24,6 +24,8 @@
defined('MOODLE_INTERNAL') || die;
use core_courseformat\base as course_format;
require_once($CFG->libdir.'/completionlib.php');
require_once($CFG->libdir.'/filelib.php');
require_once($CFG->libdir.'/datalib.php');
......@@ -3197,13 +3199,6 @@ function course_ajax_enabled($course) {
function include_course_ajax($course, $usedmodules = array(), $enabledmodules = null, $config = null) {
global $CFG, $PAGE, $SITE;
// All the new editor elements will be loaded after the course is presented and
// the initial course state will be generated using core_courseformat_get_state webservice.
if ($SITE->id !== $course->id) {
$PAGE->requires->js_call_amd('core_courseformat/courseeditor', 'getCourseEditor', [$course->id]);
}
// TODO: as part of MDL-70907, add a way to indicate the plugin needs the legacy libraries (and get a deprecation message).
// Ensure that ajax should be included
if (!course_ajax_enabled($course)) {
return false;
......@@ -3295,6 +3290,29 @@ function include_course_ajax($course, $usedmodules = array(), $enabledmodules =
return true;
}
/**
* Include and configure the course editor modules.
*
* @param course_format $format the course format instance.
*/
function include_course_editor(course_format $format) {
global $PAGE, $SITE;
$course = $format->get_course();
if ($SITE->id === $course->id) {
return;
}
// Edition mode and some format specs must be passed to the init method.
$setup = (object)[
'editing' => $format->show_editor(),
];
// All the new editor elements will be loaded after the course is presented and
// the initial course state will be generated using core_course_get_state webservice.
$PAGE->requires->js_call_amd('core_courseformat/courseeditor', 'setViewFormat', [$course->id, $setup]);
}
/**
* Returns the sorted list of available course formats, filtered by enabled if necessary
*
......@@ -3835,6 +3853,24 @@ function core_course_core_calendar_get_valid_event_timestart_range(\calendar_eve
return [$mindate, $maxdate];
}
/**
* Render the main course drawer to be included in the left part of the page.
*
* @return string HTML
*/
function core_course_drawer(): string {
global $PAGE;
// Only course and mod pages are able to render course index.
if (!preg_match('/^(mod|course).*/', $PAGE->pagetype)) {
return '';
}
$format = course_get_format($PAGE->course);
$renderer = $format->get_renderer($PAGE);
$placeholder = $renderer->course_index_drawer($format);
return $placeholder;
}
/**
* Returns course modules tagged with a specified tag ready for output on tag/index.php page
*
......
......@@ -560,12 +560,10 @@ class core_course_renderer extends plugin_renderer_base {
* Checks if course module has any conditions that may make it unavailable for
* all or some of the students
*
* This function is internal and is only used to create CSS classes for the module name/text
*
* @param cm_info $mod
* @return bool
*/
protected function is_cm_conditionally_hidden(cm_info $mod) {
public function is_cm_conditionally_hidden(cm_info $mod) {
global $CFG;
$conditionalhidden = false;
if (!empty($CFG->enableavailability)) {
......
......@@ -52,6 +52,8 @@ course formats don't have their own renderer.
* New external function core_course_update_course runs given action to edit course status.
* The `\core\event\course_category_deleted` event is now created with a snapshot of the category record being deleted,
available inside event observers via `$event->get_record_snapshot`
* New include_course_editor() function to include and configure course editor modules.
* New core_course_drawer() function to render the message drawer in the top of the body of each page.
=== 3.11 ===
* A new callback xxx_coursemodule_definition_after_data that allows plugins to extend activity forms after the data is set.
......
......@@ -22,4 +22,5 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['courseindex'] = 'Course index';
$string['privacy:metadata'] = 'The course format subsystem does not store any personal data.';
......@@ -356,7 +356,6 @@ $string['coursehelpnewsitemsnumber'] = 'Number of recent announcements appearing
$string['coursehelpnumberweeks'] = 'Number of sections in the course (applies to certain course formats only).';
$string['coursehelpshowgrades'] = 'Enable the display of the gradebook. It does not prevent grades from being displayed within the individual activities.';
$string['coursehidden'] = 'This course is currently unavailable to students';
$string['courseindex'] = 'Course index';
$string['courseoverviewfiles'] = 'Course image';
$string['courseoverviewfilesext'] = 'Course image file extensions';
$string['courseoverviewfileslimit'] = 'Course image files limit';
......
......@@ -25,6 +25,7 @@
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/behat/lib.php');
require_once($CFG->dirroot . '/course/lib.php');
user_preference_allow_ajax_update('drawer-open-nav', PARAM_ALPHA);
user_preference_allow_ajax_update('drawer-open-index', PARAM_BOOL);
......@@ -57,7 +58,7 @@ $hasblocks = strpos($blockshtml, 'data-block=') !== false;
if (!$hasblocks) {
$blockdraweropen = false;
}
$courseindex = false;
$courseindex = core_course_drawer();
if (!$courseindex) {
$courseindexopen = false;
}
......
......@@ -44,3 +44,4 @@ $breadcrumb-divider-rtl: "◀" !default;
@import "moodle/toasts";
@import "moodle/navbar";
@import "moodle/reportbuilder";
@import "moodle/courseindex";
$courseindex-link-color: $list-group-action-color !default;
$courseindex-link-hover-color: $list-group-action-hover-color !default;
$courseindex-item-hover-bg: theme-color-level('info', -11) !default;
$courseindex-item-hover-border: theme-color-level('info', -9) !default;
$courseindex-item-active-border: $gray-300 !default;
$courseindex-item-active-bg: $gray-100 !default;
$courseindex-item-padding-y: 0.5rem;
$courseindex-item-padding-x: 1rem;
$courseindex-item-radius: $border-radius !default;
$courseindex-item-current: $primary !default;
.courseindex {
.courseindex-heading {
padding: $courseindex-item-padding-y $courseindex-item-padding-x;
}
.courseindex-item {
padding: $courseindex-item-padding-y $courseindex-item-padding-x;
border: $border-width solid transparent;
@include border-radius($courseindex-item-radius);
.courseindex-link {
color: $courseindex-link-color;
@include hover-focus() {
color: $courseindex-link-hover-color;
text-decoration: none;
}
}
.courseindex-name {
font-style: italic;
}
@include hover-focus() {
background-color: $courseindex-item-hover-bg;
border-color: $courseindex-item-hover-border;
}
&.active {
background-color: $courseindex-item-active-bg;
border-color: $courseindex-item-active-border;
@include hover-focus() {
background-color: $courseindex-item-hover-bg;
border-color: $courseindex-item-hover-border;
}
}
&.dimmed {
opacity: .7;
font-style: italic;
}
}
.courseindex-sectioncontent {
.courseindex-item {
padding-left: calc(#{$courseindex-item-padding-x} * 2 + 0.5rem);
}
}
.courseindex-section.current {
border-left: solid 3px $courseindex-item-current;
}
.d-flex-noedit {
display: none;
}
&.editing {
.d-flex-noedit {
display: flex;
}
}
.media-list {
.rounded-circle {
height: 1rem;
width: 1rem;
}
.w-100 {
height: 1rem;
margin: 0.5rem 0;
}
}
}
......@@ -20036,6 +20036,52 @@ div.editor_atto_toolbar button .icon {
text-overflow: clip;
word-break: break-all; }
.courseindex .courseindex-heading {
padding: 0.5rem 1rem; }
.courseindex .courseindex-item {
padding: 0.5rem 1rem;
border: 1px solid transparent; }
.courseindex .courseindex-item .courseindex-link {
color: #495057; }
.courseindex .courseindex-item .courseindex-link:hover, .courseindex .courseindex-item .courseindex-link:focus {
color: #495057;
text-decoration: none; }
.courseindex .courseindex-item .courseindex-name {
font-style: italic; }
.courseindex .courseindex-item:hover, .courseindex .courseindex-item:focus {
background-color: #e0f0f2;
border-color: #b8dce2; }
.courseindex .courseindex-item.active {
background-color: #f8f9fa;
border-color: #dee2e6; }
.courseindex .courseindex-item.active:hover, .courseindex .courseindex-item.active:focus {
background-color: #e0f0f2;
border-color: #b8dce2; }
.courseindex .courseindex-item.dimmed {
opacity: .7;
font-style: italic; }
.courseindex .courseindex-sectioncontent .courseindex-item {
padding-left: calc(1rem * 2 + 0.5rem); }
.courseindex .courseindex-section.current {
border-left: solid 3px #0f6fc5; }
.courseindex .d-flex-noedit {
display: none; }
.courseindex.editing .d-flex-noedit {
display: flex; }
.courseindex .media-list .rounded-circle {
height: 1rem;
width: 1rem; }
.courseindex .media-list .w-100 {
height: 1rem;
margin: 0.5rem 0; }
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; }
......
......@@ -63,7 +63,7 @@
{{$id}}theme_boost-drawers-courseindex{{/id}}
{{$drawerclasses}}drawer drawer-left {{#courseindexopen}}show{{/courseindexopen}}{{/drawerclasses}}
{{$drawerheading}}
{{#str}} courseindex {{/str}}
{{#str}}courseindex, core_courseformat{{/str}}
{{/drawerheading}}
{{$drawercontent}}
{{{courseindex}}}
......
......@@ -20227,6 +20227,53 @@ div.editor_atto_toolbar button .icon {
text-overflow: clip;
word-break: break-all; }
 
.courseindex .courseindex-heading {
padding: 0.5rem 1rem; }
.courseindex .courseindex-item {
padding: 0.5rem 1rem;
border: 1px solid transparent;
border-radius: 0.25rem; }
.courseindex .courseindex-item .courseindex-link {
color: #495057; }
.courseindex .courseindex-item .courseindex-link:hover, .courseindex .courseindex-item .courseindex-link:focus {
color: #495057;
text-decoration: none; }
.courseindex .courseindex-item .courseindex-name {
font-style: italic; }
.courseindex .courseindex-item:hover, .courseindex .courseindex-item:focus {
background-color: #e0f0f2;
border-color: #b8dce2; }
.courseindex .courseindex-item.active {
background-color: #f8f9fa;
border-color: #dee2e6; }
.courseindex .courseindex-item.active:hover, .courseindex .courseindex-item.active:focus {
background-color: #e0f0f2;
border-color: #b8dce2; }
.courseindex .courseindex-item.dimmed {
opacity: .7;
font-style: italic; }
.courseindex .courseindex-sectioncontent .courseindex-item {
padding-left: calc(1rem * 2 + 0.5rem); }
.courseindex .courseindex-section.current {
border-left: solid 3px #0f6fc5; }
.courseindex .d-flex-noedit {
display: none; }
.courseindex.editing .d-flex-noedit {
display: flex; }
.courseindex .media-list .rounded-circle {
height: 1rem;
width: 1rem; }
.courseindex .media-list .w-100 {
height: 1rem;
margin: 0.5rem 0; }
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment