mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 12:40:01 +01:00
MDL-82349 courseformat: add reactivity to main menu block
This commit is contained in:
parent
c5133ddc47
commit
2f13ffcfb1
@ -21,8 +21,7 @@
|
||||
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
class block_site_main_menu extends block_list {
|
||||
class block_site_main_menu extends block_base {
|
||||
function init() {
|
||||
$this->title = get_string('pluginname', 'block_site_main_menu');
|
||||
}
|
||||
@ -32,224 +31,37 @@ class block_site_main_menu extends block_list {
|
||||
}
|
||||
|
||||
function get_content() {
|
||||
global $USER, $CFG, $DB, $OUTPUT;
|
||||
|
||||
if ($this->content !== NULL) {
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
$this->content = new stdClass();
|
||||
$this->content->items = array();
|
||||
$this->content->icons = array();
|
||||
$this->content->text = '';
|
||||
$this->content->footer = '';
|
||||
|
||||
if (empty($this->instance)) {
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
require_once($CFG->dirroot . '/course/lib.php');
|
||||
|
||||
$course = get_site();
|
||||
$format = course_get_format($course);
|
||||
$courserenderer = $format->get_renderer($this->page);
|
||||
|
||||
$context = context_course::instance($course->id);
|
||||
$isediting = $this->page->user_is_editing() && has_capability('moodle/course:manageactivities', $context);
|
||||
|
||||
// Output classes.
|
||||
$cmnameclass = $format->get_output_classname('content\\cm\\cmname');
|
||||
$controlmenuclass = $format->get_output_classname('content\\cm\\controlmenu');
|
||||
|
||||
$badgeattributes = [
|
||||
'class' => 'badge rounded-pill bg-warning text-dark mt-2',
|
||||
'data-region' => 'visibility'
|
||||
];
|
||||
|
||||
// Extra fast view mode.
|
||||
if (!$isediting) {
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
if (!empty($modinfo->sections[0])) {
|
||||
foreach($modinfo->sections[0] as $cmid) {
|
||||
$cm = $modinfo->cms[$cmid];
|
||||
if (!$cm->uservisible || !$cm->is_visible_on_course_page()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($cm->indent > 0) {
|
||||
$indent = '<div class="mod-indent mod-indent-'.$cm->indent.'"></div>';
|
||||
} else {
|
||||
$indent = '';
|
||||
}
|
||||
|
||||
$badges = '';
|
||||
if (!$cm->visible) {
|
||||
$badges = html_writer::tag(
|
||||
'span',
|
||||
get_string('hiddenfromstudents'),
|
||||
$badgeattributes
|
||||
);
|
||||
}
|
||||
|
||||
if ($cm->is_stealth()) {
|
||||
$badges = html_writer::tag(
|
||||
'span',
|
||||
get_string('hiddenoncoursepage'),
|
||||
$badgeattributes
|
||||
);
|
||||
}
|
||||
|
||||
if (!$cm->url) {
|
||||
$activitybasis = html_writer::div(
|
||||
$indent . $cm->get_formatted_content(['overflowdiv' => true, 'noclean' => true]),
|
||||
'activity-basis d-flex align-items-center');
|
||||
$content = html_writer::div(
|
||||
$activitybasis . $badges,
|
||||
'contentwithoutlink activity-item activity',
|
||||
['data-activityname' => $cm->name]
|
||||
);
|
||||
} else {
|
||||
$cmname = new $cmnameclass($format, $cm->get_section_info(), $cm);
|
||||
$activitybasis = html_writer::div(
|
||||
$indent . $courserenderer->render($cmname),
|
||||
'activity-basis d-flex align-items-center');
|
||||
$content = html_writer::div(
|
||||
$activitybasis . $badges,
|
||||
'activity-item activity',
|
||||
['data-activityname' => $cm->name]
|
||||
);
|
||||
}
|
||||
|
||||
$this->content->items[] = html_writer::div($content, 'main-menu-content section');
|
||||
}
|
||||
}
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
// Slow & hacky editing mode.
|
||||
$ismoving = ismoving($course->id);
|
||||
course_create_sections_if_missing($course, 0);
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
$format = course_get_format($course);
|
||||
$modinfo = $format->get_modinfo();
|
||||
$section = $modinfo->get_section_info(0);
|
||||
|
||||
if ($ismoving) {
|
||||
$strmovefull = strip_tags(get_string('movefull', '', "'$USER->activitycopyname'"));
|
||||
$strcancel= get_string('cancel');
|
||||
} else {
|
||||
$strmove = get_string('move');
|
||||
}
|
||||
$courserenderer = $format->get_renderer($this->page);
|
||||
|
||||
if ($ismoving) {
|
||||
$this->content->icons[] = $OUTPUT->pix_icon('t/move', get_string('move'));
|
||||
$this->content->items[] = $USER->activitycopyname.' (<a href="'.$CFG->wwwroot.'/course/mod.php?cancelcopy=true&sesskey='.sesskey().'">'.$strcancel.'</a>)';
|
||||
}
|
||||
$output = new block_site_main_menu\output\mainsection($format, $section);
|
||||
|
||||
if (!empty($modinfo->sections[0])) {
|
||||
foreach ($modinfo->sections[0] as $modnumber) {
|
||||
$mod = $modinfo->cms[$modnumber];
|
||||
if (!$mod->uservisible || !$mod->is_visible_on_course_page()) {
|
||||
continue;
|
||||
}
|
||||
if (!$ismoving) {
|
||||
$this->content->text = $courserenderer->render($output);
|
||||
|
||||
$controlmenu = new $controlmenuclass(
|
||||
$format,
|
||||
$mod->get_section_info(),
|
||||
$mod
|
||||
);
|
||||
|
||||
$menu = $controlmenu->get_action_menu($OUTPUT);
|
||||
|
||||
$moveaction = html_writer::link(
|
||||
new moodle_url('/course/mod.php', ['sesskey' => sesskey(), 'copy' => $mod->id]),
|
||||
$OUTPUT->pix_icon('i/dragdrop', $strmove),
|
||||
['class' => 'editing_move_activity']
|
||||
);
|
||||
|
||||
$editbuttons = html_writer::tag(
|
||||
'div',
|
||||
$courserenderer->render($controlmenu),
|
||||
['class' => 'buttons activity-actions ms-auto']
|
||||
);
|
||||
} else {
|
||||
$editbuttons = '';
|
||||
$moveaction = '';
|
||||
}
|
||||
|
||||
if ($mod->visible || has_capability('moodle/course:viewhiddenactivities', $mod->context)) {
|
||||
if ($ismoving) {
|
||||
if ($mod->id == $USER->activitycopy) {
|
||||
continue;
|
||||
}
|
||||
$movingurl = new moodle_url('/course/mod.php', array('moveto' => $mod->id, 'sesskey' => sesskey()));
|
||||
$this->content->items[] = html_writer::link($movingurl, '', array('title' => $strmovefull,
|
||||
'class' => 'movehere'));
|
||||
$this->content->icons[] = '';
|
||||
}
|
||||
|
||||
if ($mod->indent > 0) {
|
||||
$indent = '<div class="mod-indent mod-indent-'.$mod->indent.'"></div>';
|
||||
} else {
|
||||
$indent = '';
|
||||
}
|
||||
|
||||
$badges = '';
|
||||
if (!$mod->visible) {
|
||||
$badges = html_writer::tag(
|
||||
'span',
|
||||
get_string('hiddenfromstudents'),
|
||||
$badgeattributes
|
||||
);
|
||||
}
|
||||
|
||||
if ($mod->is_stealth()) {
|
||||
$badges = html_writer::tag(
|
||||
'span',
|
||||
get_string('hiddenoncoursepage'),
|
||||
$badgeattributes
|
||||
);
|
||||
}
|
||||
|
||||
if (!$mod->url) {
|
||||
$activitybasis = html_writer::div(
|
||||
$moveaction .
|
||||
$indent .
|
||||
$mod->get_formatted_content(['overflowdiv' => true, 'noclean' => true]) .
|
||||
$editbuttons,
|
||||
'activity-basis d-flex align-items-center');
|
||||
$content = html_writer::div(
|
||||
$activitybasis . $badges,
|
||||
'contentwithoutlink activity-item activity',
|
||||
['data-activityname' => $mod->name]
|
||||
);
|
||||
} else {
|
||||
$cmname = new $cmnameclass($format, $mod->get_section_info(), $mod);
|
||||
$activitybasis = html_writer::div(
|
||||
$moveaction .
|
||||
$indent .
|
||||
$courserenderer->render($cmname) .
|
||||
$editbuttons,
|
||||
'activity-basis d-flex align-items-center');
|
||||
$content = html_writer::div(
|
||||
$activitybasis . $badges,
|
||||
'activity-item activity',
|
||||
['data-activityname' => $mod->name]
|
||||
);
|
||||
}
|
||||
$this->content->items[] = html_writer::div($content, 'main-menu-content');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($ismoving) {
|
||||
$movingurl = new moodle_url('/course/mod.php', array('movetosection' => $section->id, 'sesskey' => sesskey()));
|
||||
$this->content->items[] = html_writer::link($movingurl, '', array('title' => $strmovefull, 'class' => 'movehere'));
|
||||
$this->content->icons[] = '';
|
||||
}
|
||||
|
||||
if ($this->page->course->id === SITEID) {
|
||||
$this->content->footer = $courserenderer->course_section_add_cm_control($course,
|
||||
0, null, array('inblock' => true));
|
||||
}
|
||||
$this->content->footer = $courserenderer->course_section_add_cm_control(
|
||||
course: $course,
|
||||
section: 0,
|
||||
sectionreturn: null,
|
||||
displayoptions: ['inblock' => true],
|
||||
);
|
||||
return $this->content;
|
||||
}
|
||||
}
|
||||
|
72
blocks/site_main_menu/classes/output/mainsection.php
Normal file
72
blocks/site_main_menu/classes/output/mainsection.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?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 block_site_main_menu\output;
|
||||
|
||||
use core_courseformat\base as courseformat;
|
||||
use renderable;
|
||||
use section_info;
|
||||
use templatable;
|
||||
|
||||
/**
|
||||
* Class mainsection
|
||||
*
|
||||
* @package block_site_main_menu
|
||||
* @copyright 2024 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mainsection implements renderable, templatable {
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @param courseformat $format the course format instance
|
||||
* @param section_info $section the section to render
|
||||
*/
|
||||
public function __construct(
|
||||
/** @var courseformat $format the course format instance. */
|
||||
protected courseformat $format,
|
||||
/** @var section_info $section the section to render. */
|
||||
protected section_info $section,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Export for template.
|
||||
*
|
||||
* @param \renderer_base $output
|
||||
* @return array
|
||||
*/
|
||||
public function export_for_template(\renderer_base $output) {
|
||||
$format = $this->format;
|
||||
$course = $format->get_course();
|
||||
$section = $this->section;
|
||||
|
||||
$sectionoutputclass = $format->get_output_classname('content\\section\\cmlist');
|
||||
$sectionoutput = new $sectionoutputclass($format, $section);
|
||||
|
||||
$cmlist = $output->render($sectionoutput);
|
||||
|
||||
return [
|
||||
'siteid' => $course->id,
|
||||
'cmlist' => $cmlist,
|
||||
'sectionid' => $section->id,
|
||||
'sectionname' => $format->get_section_name($section),
|
||||
'sectionnum' => $section->sectionnum,
|
||||
'editing' => $format->show_editor(),
|
||||
];
|
||||
}
|
||||
}
|
@ -1,26 +1,34 @@
|
||||
.block_site_main_menu li {
|
||||
clear: both;
|
||||
/* Imitate mobile grid for activity card. */
|
||||
.block_site_main_menu .activity-item .activity-grid {
|
||||
grid-template-columns: min-content 1fr min-content min-content min-content;
|
||||
grid-template-rows: 1fr repeat(4, min-content);
|
||||
grid-template-areas:
|
||||
"icon name actions"
|
||||
"visibility visibility visibility"
|
||||
"dates dates dates"
|
||||
"completion completion completion"
|
||||
"altcontent altcontent altcontent"
|
||||
"afterlink afterlink afterlink"
|
||||
"availability availability availability";
|
||||
}
|
||||
|
||||
.block_site_main_menu.block .content > .unlist > li > .column {
|
||||
/* Made specific to win over .block.list_block .unlist > li > .column. */
|
||||
width: 100%;
|
||||
display: table;
|
||||
margin-bottom: 0.5rem;
|
||||
.block_site_main_menu .activity-item .activity-grid.noname-grid {
|
||||
grid-template-columns: 1fr min-content;
|
||||
grid-template-areas:
|
||||
"actions"
|
||||
"visibility"
|
||||
"altcontent"
|
||||
"groupmode"
|
||||
"afterlink"
|
||||
"completion"
|
||||
"availability";
|
||||
}
|
||||
|
||||
.block_site_main_menu li .buttons a img {
|
||||
vertical-align: text-bottom;
|
||||
.block_site_main_menu .activity-item .activity-grid.noname-grid .activity-actions {
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.block_site_main_menu .footer {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.block_site_main_menu .section_add_menus noscript div {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.block_site_main_menu .instancename {
|
||||
word-break: break-all;
|
||||
/* Hide extra edit elements in block space. */
|
||||
.block_site_main_menu .activity-groupmode-info {
|
||||
display: none;
|
||||
}
|
||||
|
85
blocks/site_main_menu/templates/mainsection.mustache
Normal file
85
blocks/site_main_menu/templates/mainsection.mustache
Normal file
@ -0,0 +1,85 @@
|
||||
{{!
|
||||
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 block_site_main_menu/mainsection
|
||||
|
||||
This mustache emulates a course single section structure inside a block.
|
||||
|
||||
It requires to include several divs to emulate the structure of a course format.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"cmlist": "Sample",
|
||||
"siteid": 1,
|
||||
"sectionid": 1,
|
||||
"sectionname": "Sample",
|
||||
"sectionnum": 1,
|
||||
"editing": true
|
||||
}
|
||||
}}
|
||||
<div
|
||||
id="block_site_main_menu_section"
|
||||
class="course-content"
|
||||
>
|
||||
{{! The section list is used by the content module to init the sections.}}
|
||||
<div
|
||||
data-for="course_sectionlist"
|
||||
>
|
||||
{{! The section need some bottom padding and margin for the dropzone.
|
||||
Otherwise the activities will cover the area. }}
|
||||
<div
|
||||
class="mainsection section pb-3"
|
||||
data-for="section"
|
||||
data-sectionid="{{sectionid}}"
|
||||
data-id="{{sectionid}}"
|
||||
data-number="{{sectionnum}}"
|
||||
data-sectionname="{{sectionname}}"
|
||||
>
|
||||
{{#editing}}
|
||||
{{! The section header is used as a dropzone when the section is empty.}}
|
||||
<div
|
||||
class="section-header"
|
||||
data-for="section_title"
|
||||
data-id="{{sectionid}}"
|
||||
data-number="{{sectionnum}}"
|
||||
> </div>
|
||||
{{/editing}}
|
||||
{{{cmlist}}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#js}}
|
||||
{{! The block should be fast to load, we only load the editor when needed.}}
|
||||
{{#editing}}
|
||||
require(
|
||||
[
|
||||
'core_courseformat/local/content',
|
||||
'core_courseformat/courseeditor'
|
||||
],
|
||||
function(
|
||||
Component,
|
||||
Courseeditor
|
||||
) {
|
||||
{{! The block could be included static in other courses so we use Courseeditor.getCourseEditor. }}
|
||||
new Component({
|
||||
element: document.getElementById('block_site_main_menu_section'),
|
||||
reactive: Courseeditor.getCourseEditor({{siteid}}),
|
||||
});
|
||||
}
|
||||
);
|
||||
{{/editing}}
|
||||
{{/js}}
|
Loading…
x
Reference in New Issue
Block a user