Merge branch 'MDL-65974-master-iteration03' of git://github.com/ferranrecio/moodle

This commit is contained in:
Adrian Greeve 2021-03-15 15:16:44 +08:00
commit 00cb88c352
60 changed files with 4986 additions and 1987 deletions

View File

@ -58,7 +58,7 @@ class core_backup_moodle2_course_format_testcase extends advanced_testcase {
'enablecompletion' => COMPLETION_ENABLED),
array('createsections' => true));
$courseobject = format_base::instance($course->id);
$courseobject = core_course\course_format::instance($course->id);
$section = $DB->get_record('course_sections',
array('course' => $course->id, 'section' => 1), '*', MUST_EXIST);
$data = array('id' => $section->id,
@ -91,7 +91,7 @@ class core_backup_moodle2_course_format_testcase extends advanced_testcase {
'enablecompletion' => COMPLETION_ENABLED),
array('createsections' => true));
$courseobject = format_base::instance($course->id);
$courseobject = core_course\course_format::instance($course->id);
$section = $DB->get_record('course_sections',
array('course' => $course->id, 'section' => 1), '*', MUST_EXIST);
$data = array('id' => $section->id,
@ -134,7 +134,7 @@ class core_backup_moodle2_course_format_testcase extends advanced_testcase {
array('createsections' => true));
// Set section 2 to have both options, and a name.
$courseobject = format_base::instance($course->id);
$courseobject = core_course\course_format::instance($course->id);
$section = $DB->get_record('course_sections',
array('course' => $course->id, 'section' => 2), '*', MUST_EXIST);
$data = array('id' => $section->id,
@ -151,7 +151,7 @@ class core_backup_moodle2_course_format_testcase extends advanced_testcase {
// Check that the section contains the options suitable for the new
// format and that even the one with the same name as from the old format
// has NOT been set.
$newcourseobject = format_base::instance($newcourse->id);
$newcourseobject = core_course\course_format::instance($newcourse->id);
$sectionoptions = $newcourseobject->get_format_options(2);
$this->assertArrayHasKey('numdaystocomplete', $sectionoptions);
$this->assertArrayNotHasKey('secondparameter', $sectionoptions);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,134 @@
<?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/>.
/**
* Contains the default activity list from a section.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output;
use core_course\course_format;
use section_info;
use completion_info;
use renderable;
use templatable;
use cm_info;
use stdClass;
/**
* Base class to render a course module inside a course format.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cm_format implements renderable, templatable {
/** @var course_format the course format */
protected $format;
/** @var section_info the section object */
private $section;
/** @var cm_info the course module instance */
protected $mod;
/** @var array optional display options */
protected $displayoptions;
/** @var completion_info the course completion */
protected $completioninfo;
/**
* Constructor.
*
* @param course_format $format the course format
* @param section_info $section the section info
* @param completion_info $completioninfo the course completion info
* @param cm_info $mod the course module ionfo
* @param array $displayoptions optional extra display options
*/
public function __construct(course_format $format, section_info $section, completion_info $completioninfo,
cm_info $mod, array $displayoptions = []) {
$this->format = $format;
$this->section = $section;
$this->completioninfo = $completioninfo;
$this->mod = $mod;
$this->displayoptions = $displayoptions;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return stdClass data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
$format = $this->format;
$course = $format->get_course();
$mod = $this->mod;
$displayoptions = $this->displayoptions;
$data = (object)[
'cmname' => $output->course_section_cm_name($mod, $displayoptions),
'afterlink' => $mod->afterlink,
'altcontent' => $output->course_section_cm_text($mod, $displayoptions),
'availability' => $output->course_section_cm_availability($mod, $displayoptions),
'url' => $mod->url,
'completion' => $output->course_section_cm_completion(
$course, $this->completioninfo, $mod, $displayoptions
),
];
if (!empty($mod->indent)) {
$data->indent = $mod->indent;
if ($mod->indent > 15) {
$data->hugeindent = true;
}
}
if (!empty($data->cmname)) {
$data->hasname = true;
}
if (!empty($data->url)) {
$data->hasurl = true;
}
$returnsection = $format->get_section_number();
$data->extras = [];
if ($format->show_editor()) {
// Edit actions.
$editactions = course_get_cm_edit_actions($mod, $mod->indent, $returnsection);
$data->extras[] = $output->course_section_cm_edit_actions($editactions, $mod, $displayoptions);
if (!empty($mod->afterediticons)) {
$data->extras[] = $mod->afterediticons;
}
// Move and select options.
$data->moveicon = course_get_cm_move($mod, $returnsection);
}
if (!empty($data->completion) || !empty($data->extras)) {
$data->hasextras = true;
}
return $data;
}
}

View File

@ -0,0 +1,185 @@
<?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/>.
/**
* Contains the main course format out class.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output;
use core_course\course_format as course_format_base;
use course_modinfo;
use renderable;
use templatable;
use stdClass;
/**
* Base class to render a course format.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class course_format implements renderable, templatable {
/** @var core_course\course_format the course format class */
protected $format;
/** @var string the section format class */
protected $sectionclass;
/** @var string the add section output class name */
protected $addsectionclass;
/** @var string section navigation class name */
protected $sectionnavigationclass;
/** @var string section selector class name */
protected $sectionselectorclass;
/**
* Constructor.
*
* @param course_format_base $format the coruse format
*/
public function __construct(course_format_base $format) {
$this->format = $format;
// Load output classes names from format.
$this->sectionclass = $format->get_output_classname('section_format');
$this->addsectionclass = $format->get_output_classname('course_format\\addsection');
$this->sectionnavigationclass = $format->get_output_classname('course_format\\sectionnavigation');
$this->sectionselectorclass = $format->get_output_classname('course_format\\sectionselector');
}
/**
* Export this data so it can be used as the context for a mustache template (core/inplace_editable).
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return stdClass data context for a mustache template
*/
public function export_for_template(\renderer_base $output) {
$format = $this->format;
$addsection = new $this->addsectionclass($format);
// Most formats uses section 0 as a separate section so we remove from the list.
$sections = $this->export_sections($output);
$initialsection = '';
if (!empty($sections)) {
$initialsection = array_shift($sections);
}
$data = (object)[
'title' => $format->page_title(), // This method should be in the course_format class.
'initialsection' => $initialsection,
'sections' => $sections,
'numsections' => $addsection->export_for_template($output),
'format' => $format->get_format(),
];
// The single section format has extra navigation.
$singlesection = $this->format->get_section_number();
if ($singlesection) {
$sectionnavigation = new $this->sectionnavigationclass($format, $singlesection);
$data->sectionnavigation = $sectionnavigation->export_for_template($output);
$sectionselector = new $this->sectionselectorclass($format, $sectionnavigation);
$data->sectionselector = $sectionselector->export_for_template($output);
$data->hasnavigation = true;
$data->singlesection = array_shift($data->sections);
}
return $data;
}
/**
* Export sections array data.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return array data context for a mustache template
*/
protected function export_sections(\renderer_base $output): array {
$format = $this->format;
$course = $format->get_course();
$modinfo = $this->format->get_modinfo();
// Generate section list.
$sections = [];
$stealthsections = [];
$numsections = $format->get_last_section_number();
foreach ($this->get_sections_to_display($modinfo) as $sectionnum => $thissection) {
// The course/view.php check the section existence but the output can be called
// from other parts so we need to check it.
if (!$thissection) {
print_error('unknowncoursesection', 'error', course_get_url($course), format_string($course->fullname));
}
$section = new $this->sectionclass($format, $thissection);
if ($sectionnum > $numsections) {
// Activities inside this section are 'orphaned', this section will be printed as 'stealth' below.
if (!empty($modinfo->sections[$sectionnum])) {
$stealthsections[] = $section->export_for_template($output);
}
continue;
}
// Show the section if the user is permitted to access it, OR if it's not available
// but there is some available info text which explains the reason & should display,
// OR it is hidden but the course has a setting to display hidden sections as unavilable.
$showsection = $thissection->uservisible ||
($thissection->visible && !$thissection->available && !empty($thissection->availableinfo)) ||
(!$thissection->visible && !$course->hiddensections);
if (!$showsection) {
continue;
}
$sections[] = $section->export_for_template($output);
}
if (!empty($stealthsections)) {
$sections = array_merge($sections, $stealthsections);
}
return $sections;
}
/**
* Return an array of sections to display.
*
* This method is used to differentiate between display a specific section
* or a list of them.
*
* @param course_modinfo $modinfo the current course modinfo object
* @return section_info[] an array of section_info to display
*/
private function get_sections_to_display(course_modinfo $modinfo): array {
$singlesection = $this->format->get_section_number();
if ($singlesection) {
return [
$modinfo->get_section_info(0),
$modinfo->get_section_info($singlesection),
];
}
return $modinfo->get_section_info_all();
}
}

View File

@ -0,0 +1,131 @@
<?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/>.
/**
* Contains the default section course format output class.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output\course_format;
use core_course\course_format;
use renderable;
use templatable;
use moodle_url;
use stdClass;
/**
* Base class to render a course add section buttons.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class addsection implements renderable, templatable {
/** @var course_format the course format class */
protected $format;
/**
* Constructor.
*
* @param course_format $format the course format
*/
public function __construct(course_format $format) {
$this->format = $format;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return stdClass data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
$format = $this->format;
$course = $format->get_course();
$options = $format->get_format_options();
$lastsection = $format->get_last_section_number();
$maxsections = $format->get_max_sections();
$data = new stdClass();
// If no editor must be displayed, just retun an empty structure.
if (!$format->show_editor()) {
return $data;
}
$supportsnumsections = array_key_exists('numsections', $options);
if ($supportsnumsections) {
// Current course format has 'numsections' option, which is very confusing and we suggest course format
// developers to get rid of it (see MDL-57769 on how to do it).
if ($lastsection < $maxsections) {
$data->increase = (object) [
'url' => new moodle_url(
'/course/changenumsections.php',
['courseid' => $course->id, 'increase' => true, 'sesskey' => sesskey()]
),
];
}
if ($course->numsections > 0) {
$data->decrease = (object) [
'url' => new moodle_url(
'/course/changenumsections.php',
['courseid' => $course->id, 'increase' => false, 'sesskey' => sesskey()]
),
];
}
} else if (course_get_format($course)->uses_sections() && $lastsection < $maxsections) {
// Current course format does not have 'numsections' option but it has multiple sections suppport.
// Display the "Add section" link that will insert a section in the end.
// Note to course format developers: inserting sections in the other positions should check both
// capabilities 'moodle/course:update' and 'moodle/course:movesections'.
if (get_string_manager()->string_exists('addsections', 'format_'.$course->format)) {
$addstring = get_string('addsections', 'format_'.$course->format);
} else {
$addstring = get_string('addsections');
}
$params = ['courseid' => $course->id, 'insertsection' => 0, 'sesskey' => sesskey()];
$singlesection = $this->format->get_section_number();
if ($singlesection) {
$params['sectionreturn'] = $singlesection;
}
$data->addsections = (object) [
'url' => new moodle_url('/course/changenumsections.php', $params),
'title' => $addstring,
'newsection' => $maxsections - $lastsection,
];
}
if (count((array)$data)) {
$data->showaddsection = true;
}
return $data;
}
}

View File

@ -0,0 +1,101 @@
<?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/>.
/**
* Contains the default frontpage section displayer.
*
* The frontpage has a different wat of rendering the main topic.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output\course_format;
use core_course\course_format;
use renderable;
use templatable;
use section_info;
use context_course;
use moodle_url;
use stdClass;
/**
* Represents the frontpage section 1.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class frontpagesection implements renderable, templatable {
/** @var course_format the course format class */
protected $format;
/** @var section_info the course section class */
protected $section;
/** @var string the section output class name */
protected $sectionclass;
/**
* Constructor.
*
* @param course_format $format the course format
* @param section_info $section the section info
*/
public function __construct(course_format $format, section_info $section) {
$this->format = $format;
$this->section = $section;
// Get the necessary classes.
$this->sectionclass = $format->get_output_classname('section_format');
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return stdClass data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
global $USER;
$format = $this->format;
$course = $format->get_course();
$context = context_course::instance($course->id);
$section = $this->section;
$sectionoutput = new $this->sectionclass($format, $section);
$sectionoutput->hide_controls();
if (trim($section->name) == '') {
$sectionoutput->hide_title();
}
$data = (object)[
'sections' => [$sectionoutput->export_for_template($output)],
];
if ($format->show_editor() && has_capability('moodle/course:update', $context)) {
$data->showsettings = true;
$data->settingsurl = new moodle_url('/course/editsection.php', ['id' => $section->id]);
}
return $data;
}
}

View File

@ -0,0 +1,123 @@
<?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/>.
/**
* Contains the default section navigation output class.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output\course_format;
use core_course\course_format;
use renderable;
use templatable;
use context_course;
use stdClass;
/**
* Base class to render a course add section navigation.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class sectionnavigation implements renderable, templatable {
/** @var course_format the course format class */
protected $format;
/** @var int the course displayed section */
protected $sectionno;
/** @var stdClass the calculated data to prevent calculations when rendered several times */
private $data = null;
/**
* Constructor.
*
* @param course_format $format the course format
* @param int $sectionno the section number
*/
public function __construct(course_format $format, int $sectionno) {
$this->format = $format;
$this->sectionno = $sectionno;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return stdClass data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
global $USER;
if ($this->data !== null) {
return $this->data;
}
$format = $this->format;
$course = $format->get_course();
$context = context_course::instance($course->id);
$modinfo = $this->format->get_modinfo();
$sections = $modinfo->get_section_info_all();
// FIXME: This is really evil and should by using the navigation API.
$canviewhidden = has_capability('moodle/course:viewhiddensections', $context, $USER) || !$course->hiddensections;
$data = (object)[
'previousurl' => '',
'nexturl' => '',
'larrow' => $output->larrow(),
'rarrow' => $output->rarrow(),
'currentsection' => $this->sectionno,
];
$back = $this->sectionno - 1;
while ($back > 0 and empty($data->previousurl)) {
if ($canviewhidden || $sections[$back]->uservisible) {
if (!$sections[$back]->visible) {
$data->previoushidden = true;
}
$data->previousname = get_section_name($course, $sections[$back]);
$data->previousurl = course_get_url($course, $back);
$data->hasprevious = true;
}
$back--;
}
$forward = $this->sectionno + 1;
$numsections = course_get_format($course)->get_last_section_number();
while ($forward <= $numsections and empty($data->nexturl)) {
if ($canviewhidden || $sections[$forward]->uservisible) {
if (!$sections[$forward]->visible) {
$data->nexthidden = true;
}
$data->nextname = get_section_name($course, $sections[$forward]);
$data->nexturl = course_get_url($course, $forward);
$data->hasnext = true;
}
$forward++;
}
$this->data = $data;
return $data;
}
}

View File

@ -0,0 +1,100 @@
<?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/>.
/**
* Contains the default section selector.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output\course_format;
use core_course\course_format;
use renderable;
use templatable;
use url_select;
use stdClass;
/**
* Represents the section selector.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class sectionselector implements renderable, templatable {
/** @var course_format the course format class */
protected $format;
/** @var sectionnavigation the main section navigation class */
protected $navigation;
/**
* Constructor.
*
* In the current imeplementaiton the seciton selector is almost a variation of the section navigator
* but in the 4.0 this selector will be a kind of dropdown menu. When this happens the construct params
* will change.
*
* @param course_format $format the course format
* @param sectionnavigation $navigation the current section navigation
*/
public function __construct(course_format $format, sectionnavigation $navigation) {
$this->format = $format;
$this->navigation = $navigation;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return stdClass data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
$format = $this->format;
$course = $format->get_course();
$modinfo = $this->format->get_modinfo();
$data = $this->navigation->export_for_template($output);
// Add the section selector.
$sectionmenu = [];
$sectionmenu[course_get_url($course)->out(false)] = get_string('maincoursepage');
$section = 1;
$numsections = $format->get_last_section_number();
while ($section <= $numsections) {
$thissection = $modinfo->get_section_info($section);
$showsection = $thissection->uservisible || !$course->hiddensections;
$url = course_get_url($course, $section);
if ($showsection && $url && $section != $data->currentsection) {
$sectionmenu[$url->out(false)] = get_section_name($course, $section);
}
$section++;
}
$select = new url_select($sectionmenu, '', ['' => get_string('jumpto')]);
$select->class = 'jumpmenu';
$select->formid = 'sectionmenu';
$data->selector = $output->render($select);
return $data;
}
}

View File

@ -0,0 +1,211 @@
<?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/>.
/**
* Contains the default section course format output class.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output;
use core_course\course_format;
use completion_info;
use renderable;
use templatable;
use section_info;
use stdClass;
/**
* Base class to render a course section.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class section_format implements renderable, templatable {
/** @var course_format the course format */
protected $format;
/** @var section_info the section info */
protected $thissection;
/** @var section header output class */
protected $headerclass;
/** @var cm list output class */
protected $cmlistclass;
/** @var section summary output class */
protected $summaryclass;
/** @var activities summary output class */
protected $cmsummaryclass;
/** @var section control menu output class */
protected $controlclass;
/** @var section availability output class */
protected $availabilityclass;
/** @var optional move here output class */
protected $movehereclass;
/** @var bool if the title is hidden for some reason */
protected $hidetitle = false;
/** @var bool if the title is hidden for some reason */
protected $hidecontrols = false;
/**
* Constructor.
*
* @param course_format $format the course format
* @param section_info $thissection the section info
*/
public function __construct(course_format $format, section_info $thissection) {
$this->format = $format;
$this->thissection = $thissection;
// Load output classes names from format.
$this->headerclass = $format->get_output_classname('section_format\\header');
$this->cmlistclass = $format->get_output_classname('section_format\\cmlist');
$this->summaryclass = $format->get_output_classname('section_format\\summary');
$this->cmsummaryclass = $format->get_output_classname('section_format\\cmsummary');
$this->controlmenuclass = $format->get_output_classname('section_format\\controlmenu');
$this->availabilityclass = $format->get_output_classname('section_format\\availability');
$this->movehereclass = $format->get_output_classname('section_format\\movehere');
}
/**
* Hide the section title.
*
* This is used on blocks or in the home page where an isolated section is displayed.
*/
public function hide_title(): void {
$this->hidetitle = true;
}
/**
* Hide the section controls.
*
* This is used on blocks or in the home page where an isolated section is displayed.
*/
public function hide_controls(): void {
$this->hidecontrols = true;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return stdClass data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
$format = $this->format;
$course = $format->get_course();
$thissection = $this->thissection;
$singlesection = $format->get_section_number();
$summary = new $this->summaryclass($format, $thissection);
$availability = new $this->availabilityclass($format, $thissection);
$data = (object)[
'num' => $thissection->section ?? '0',
'id' => $thissection->id,
'sectionreturnid' => $singlesection,
'summary' => $summary->export_for_template($output),
'availability' => $availability->export_for_template($output),
];
// Check if it is a stealth sections (orphaned).
if ($thissection->section > $format->get_last_section_number()) {
$data->isstealth = true;
$data->ishidden = true;
}
if ($format->show_editor()) {
if (empty($this->hidecontrols)) {
$controlmenu = new $this->controlmenuclass($format, $thissection);
$data->controlmenu = $controlmenu->export_for_template($output);
}
if (empty($data->isstealth)) {
$data->cmcontrols = $output->course_section_add_cm_control($course, $thissection->section, 0);
}
}
if ($thissection->section == 0) {
// Section zero is always visible only as a cmlist.
$cmlist = new $this->cmlistclass($format, $thissection);
$data->cmlist = $cmlist->export_for_template($output);
// Section 0 could have a completion help icon.
$completioninfo = new completion_info($course);
$data->completioninfo = $completioninfo->display_help_icon();
return $data;
}
// When a section is displayed alone the title goes over the section, not inside it.
$header = new $this->headerclass($format, $thissection);
if ($thissection->section == $singlesection) {
if (empty($this->hidetitle)) {
$data->singleheader = $header->export_for_template($output);
}
} else {
if (empty($this->hidetitle)) {
$data->header = $header->export_for_template($output);
}
// Add activities summary if necessary.
if (!$format->show_editor() && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
$cmsummary = new $this->cmsummaryclass($format, $thissection);
$data->cmsummary = $cmsummary->export_for_template($output);
$data->onlysummary = true;
if (!$format->is_section_current($thissection)) {
// In multipage, only the current section (and the section zero) has elements.
return $data;
}
}
}
// Add the cm list.
if ($thissection->uservisible) {
$cmlist = new $this->cmlistclass($format, $thissection);
$data->cmlist = $cmlist->export_for_template($output);
}
if (!$thissection->visible) {
$data->ishidden = true;
}
if ($format->is_section_current($thissection)) {
$data->iscurrent = true;
$data->currentlink = get_accesshide(
get_string('currentsection', 'format_'.$format->get_format())
);
}
return $data;
}
}

View File

@ -0,0 +1,123 @@
<?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/>.
/**
* Contains the default section availability output class.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output\section_format;
use core_course\course_format;
use section_info;
use renderable;
use templatable;
use core_availability\info_section;
use core_availability\info;
use context_course;
use stdClass;
/**
* Base class to render section availability.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class availability implements renderable, templatable {
/** @var course_format the course format class */
protected $format;
/** @var section_info the section object */
protected $section;
/**
* Constructor.
*
* @param course_format $format the course format
* @param section_info $section the section info
*/
public function __construct(course_format $format, section_info $section) {
$this->format = $format;
$this->section = $section;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* If section is not visible, display the message about that ('Not available
* until...', that sort of thing). Otherwise, returns blank.
*
* For users with the ability to view hidden sections, it shows the
* information even though you can view the section and also may include
* slightly fuller information (so that teachers can tell when sections
* are going to be unavailable etc). This logic is the same as for
* activities.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return stdclass data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
global $CFG, $USER;
$format = $this->format;
$section = $this->section;
$course = $format->get_course();
$context = context_course::instance($section->course);
$canviewhidden = has_capability('moodle/course:viewhiddensections', $context, $USER);
$info = '';
if (!$section->visible) {
if ($canviewhidden) {
$info = $output->availability_info(get_string('hiddenfromstudents'), 'ishidden');
} else {
// We are here because of the setting "Hidden sections are shown in collapsed form".
// Student can not see the section contents but can see its name.
$info = $output->availability_info(get_string('notavailable'), 'ishidden');
}
} else if (!$section->uservisible) {
if ($section->availableinfo) {
// Note: We only get to this function if availableinfo is non-empty,
// so there is definitely something to print.
$formattedinfo = info::format_info($section->availableinfo, $section->course);
$info = $output->availability_info($formattedinfo, 'isrestricted');
}
} else if ($canviewhidden && !empty($CFG->enableavailability)) {
// Check if there is an availability restriction.
$ci = new info_section($section);
$fullinfo = $ci->get_full_information();
if ($fullinfo) {
$formattedinfo = info::format_info($fullinfo, $section->course);
$info = $output->availability_info($formattedinfo, 'isrestricted isfullinfo');
}
}
$data = (object)[
'info' => $info,
];
if (!empty($info)) {
$data->hasavailability = true;
}
return $data;
}
}

View File

@ -0,0 +1,101 @@
<?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/>.
/**
* Contains the default activity item from a section.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output\section_format;
use core_course\course_format;
use section_info;
use completion_info;
use renderable;
use templatable;
use cm_info;
use stdClass;
/**
* Base class to render a section activity in the activities list.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cmitem implements renderable, templatable {
/** @var course_format the course format class */
protected $format;
/** @var section_format the course section class */
protected $section;
/** @var cm_info the course module to display */
protected $mod;
/** @var array optional display options */
protected $displayoptions;
/** @var string the cm output class name */
protected $cmclass;
/**
* Constructor.
*
* @param course_format $format the course format
* @param section_info $section the section info
* @param cm_info $mod the course module ionfo
* @param array $displayoptions optional extra display options
*/
public function __construct(course_format $format, section_info $section, cm_info $mod, array $displayoptions = []) {
$this->format = $format;
$this->section = $section;
$this->mod = $mod;
$this->displayoptions = $displayoptions;
// Get the necessary classes.
$this->cmclass = $format->get_output_classname('cm_format');
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return array data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
$format = $this->format;
$course = $format->get_course();
$completioninfo = new completion_info($course);
$mod = $this->mod;
$data = new stdClass();
$data->cms = [];
$item = new $this->cmclass($format, $this->section, $completioninfo, $mod, $this->displayoptions);
return (object)[
'id' => $mod->id,
'module' => $mod->modname,
'extraclasses' => $mod->extraclasses,
'cmformat' => $item->export_for_template($output),
];
}
}

View File

@ -0,0 +1,132 @@
<?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/>.
/**
* Contains the default activity list from a section.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output\section_format;
use core_course\course_format;
use section_info;
use renderable;
use templatable;
use moodle_url;
use stdClass;
/**
* Base class to render a section activity list.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cmlist implements renderable, templatable {
/** @var course_format the course format class */
protected $format;
/** @var section_format the course section class */
protected $section;
/** @var array optional display options */
protected $displayoptions;
/** @var string the item output class name */
protected $itemclass;
/** @var optional move here output class */
protected $movehereclass;
/**
* Constructor.
*
* @param course_format $format the course format
* @param section_info $section the section info
* @param array $displayoptions optional extra display options
*/
public function __construct(course_format $format, section_info $section, array $displayoptions = []) {
$this->format = $format;
$this->section = $section;
$this->displayoptions = $displayoptions;
// Get the necessary classes.
$this->itemclass = $format->get_output_classname('section_format\cmitem');
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return array data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
global $USER;
$format = $this->format;
$section = $this->section;
$course = $format->get_course();
$modinfo = $format->get_modinfo();
$user = $USER;
$data = new stdClass();
$data->cms = [];
// By default, non-ajax controls are disabled but in some places like the frontpage
// it is necessary to display them. This is a temporal solution while JS is still
// optional for course editing.
$showmovehere = ismoving($course->id);
if ($showmovehere) {
$data->hascms = true;
$data->showmovehere = true;
$data->strmovefull = strip_tags(get_string("movefull", "", "'$user->activitycopyname'"));
$data->movetosectionurl = new moodle_url('/course/mod.php', ['movetosection' => $section->id, 'sesskey' => sesskey()]);
$data->movingstr = strip_tags(get_string('activityclipboard', '', $user->activitycopyname));
$data->cancelcopyurl = new moodle_url('/course/mod.php', ['cancelcopy' => 'true', 'sesskey' => sesskey()]);
}
if (empty($modinfo->sections[$section->section])) {
return $data;
}
foreach ($modinfo->sections[$section->section] as $modnumber) {
$mod = $modinfo->cms[$modnumber];
// If the old non-ajax move is necessary, we do not print the selected cm.
if ($showmovehere && $USER->activitycopy == $mod->id) {
continue;
}
if ($mod->is_visible_on_course_page()) {
$item = new $this->itemclass($format, $section, $mod, $this->displayoptions);
$data->cms[] = (object)[
'cmitem' => $item->export_for_template($output),
'moveurl' => new moodle_url('/course/mod.php', array('moveto' => $modnumber, 'sesskey' => sesskey())),
];
}
}
if (!empty($data->cms)) {
$data->hascms = true;
}
return $data;
}
}

View File

@ -0,0 +1,128 @@
<?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/>.
/**
* Contains the default activities summary (used for singlesection format).
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output\section_format;
use core_course\course_format;
use section_info;
use completion_info;
use renderable;
use templatable;
use stdClass;
/**
* Base class to render a course section summary.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cmsummary implements renderable, templatable {
/** @var course_format the course format class */
protected $format;
/** @var section_info the course section class */
protected $section;
/**
* Constructor.
*
* @param course_format $format the course format
* @param section_info $section the section info
*/
public function __construct(course_format $format, section_info $section) {
$this->format = $format;
$this->section = $section;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return array data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
list($mods, $complete, $total) = $this->calculate_section_stats();
if (empty($mods)) {
return new stdClass();
}
$data = (object)[
'total' => $total,
'complete' => $complete,
'mods' => array_values($mods),
];
$data->modprogress = get_string('progresstotal', 'completion', $data);
return $data;
}
/**
* Calculate the activities count of the current section.
*
* @return array with [[count by activity type], completed activities, total of activitites]
*/
private function calculate_section_stats(): array {
$format = $this->format;
$course = $format->get_course();
$section = $this->section;
$modinfo = $format->get_modinfo();
$completioninfo = new completion_info($course);
$mods = [];
$total = 0;
$complete = 0;
$cmids = $modinfo->sections[$section->section] ?? [];
$cancomplete = isloggedin() && !isguestuser();
foreach ($cmids as $cmid) {
$thismod = $modinfo->cms[$cmid];
if ($thismod->uservisible) {
if (isset($mods[$thismod->modname])) {
$mods[$thismod->modname]['name'] = $thismod->modplural;
$mods[$thismod->modname]['count']++;
} else {
$mods[$thismod->modname]['name'] = $thismod->modfullname;
$mods[$thismod->modname]['count'] = 1;
}
if ($cancomplete && $completioninfo->is_enabled($thismod) != COMPLETION_TRACKING_NONE) {
$total++;
$completiondata = $completioninfo->get_data($thismod, true);
if ($completiondata->completionstate == COMPLETION_COMPLETE ||
$completiondata->completionstate == COMPLETION_COMPLETE_PASS) {
$complete++;
}
}
}
}
return [$mods, $complete, $total];
}
}

View File

@ -0,0 +1,232 @@
<?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/>.
/**
* Contains the default section controls output class.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output\section_format;
use core_course\course_format;
use section_info;
use renderable;
use templatable;
use context_course;
use moodle_url;
use pix_icon;
use action_menu_link_secondary;
use action_menu;
use stdClass;
/**
* Base class to render section controls.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class controlmenu implements renderable, templatable {
/** @var course_format the course format class */
protected $format;
/** @var section_info the course section class */
protected $section;
/**
* Constructor.
*
* @param course_format $format the course format
* @param section_info $section the section info
*/
public function __construct(course_format $format, section_info $section) {
$this->format = $format;
$this->section = $section;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return array data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
$section = $this->section;
$controls = $this->section_control_items();
if (empty($controls)) {
return new stdClass();
}
// Convert control array into an action_menu.
$menu = new action_menu();
$menu->set_menu_trigger(get_string('edit'));
$menu->attributes['class'] .= ' section-actions';
foreach ($controls as $value) {
$url = empty($value['url']) ? '' : $value['url'];
$icon = empty($value['icon']) ? '' : $value['icon'];
$name = empty($value['name']) ? '' : $value['name'];
$attr = empty($value['attr']) ? array() : $value['attr'];
$class = empty($value['pixattr']['class']) ? '' : $value['pixattr']['class'];
$al = new action_menu_link_secondary(
new moodle_url($url),
new pix_icon($icon, '', null, array('class' => "smallicon " . $class)),
$name,
$attr
);
$menu->add($al);
}
$data = (object)[
'menu' => $output->render($menu),
'hasmenu' => true,
'id' => $section->id,
];
return $data;
}
/**
* Generate the edit control items of a section.
*
* It is not clear this kind of controls are still available in 4.0 so, for now, this
* method is almost a clone of the previous section_control_items from the course/renderer.php.
*
* This method must remain public until the final deprecation of section_edit_control_items.
*
* @return array of edit control items
*/
public function section_control_items() {
global $USER;
$format = $this->format;
$section = $this->section;
$course = $format->get_course();
$sectionreturn = $format->get_section_number();
$user = $USER;
$coursecontext = context_course::instance($course->id);
$numsections = $format->get_last_section_number();
$isstealth = $section->section > $numsections;
$baseurl = course_get_url($course, $sectionreturn);
$baseurl->param('sesskey', sesskey());
$controls = [];
if (!$isstealth && has_capability('moodle/course:update', $coursecontext, $user)) {
if ($section->section > 0
&& get_string_manager()->string_exists('editsection', 'format_'.$format->get_format())) {
$streditsection = get_string('editsection', 'format_'.$format->get_format());
} else {
$streditsection = get_string('editsection');
}
$controls['edit'] = array(
'url' => new moodle_url('/course/editsection.php', array('id' => $section->id, 'sr' => $sectionreturn)),
'icon' => 'i/settings',
'name' => $streditsection,
'pixattr' => array('class' => ''),
'attr' => array('class' => 'icon edit'));
}
if ($section->section) {
$url = clone($baseurl);
if (!$isstealth) {
if (has_capability('moodle/course:sectionvisibility', $coursecontext, $user)) {
if ($section->visible) { // Show the hide/show eye.
$strhidefromothers = get_string('hidefromothers', 'format_'.$course->format);
$url->param('hide', $section->section);
$controls['visiblity'] = array(
'url' => $url,
'icon' => 'i/hide',
'name' => $strhidefromothers,
'pixattr' => array('class' => ''),
'attr' => array('class' => 'icon editing_showhide',
'data-sectionreturn' => $sectionreturn, 'data-action' => 'hide'));
} else {
$strshowfromothers = get_string('showfromothers', 'format_'.$course->format);
$url->param('show', $section->section);
$controls['visiblity'] = array(
'url' => $url,
'icon' => 'i/show',
'name' => $strshowfromothers,
'pixattr' => array('class' => ''),
'attr' => array('class' => 'icon editing_showhide',
'data-sectionreturn' => $sectionreturn, 'data-action' => 'show'));
}
}
if (!$sectionreturn) {
if (has_capability('moodle/course:movesections', $coursecontext, $user)) {
$url = clone($baseurl);
if ($section->section > 1) { // Add a arrow to move section up.
$url->param('section', $section->section);
$url->param('move', -1);
$strmoveup = get_string('moveup');
$controls['moveup'] = array(
'url' => $url,
'icon' => 'i/up',
'name' => $strmoveup,
'pixattr' => array('class' => ''),
'attr' => array('class' => 'icon moveup'));
}
$url = clone($baseurl);
if ($section->section < $numsections) { // Add a arrow to move section down.
$url->param('section', $section->section);
$url->param('move', 1);
$strmovedown = get_string('movedown');
$controls['movedown'] = array(
'url' => $url,
'icon' => 'i/down',
'name' => $strmovedown,
'pixattr' => array('class' => ''),
'attr' => array('class' => 'icon movedown'));
}
}
}
}
if (course_can_delete_section($course, $section)) {
if (get_string_manager()->string_exists('deletesection', 'format_'.$course->format)) {
$strdelete = get_string('deletesection', 'format_'.$course->format);
} else {
$strdelete = get_string('deletesection');
}
$url = new moodle_url('/course/editsection.php', array(
'id' => $section->id,
'sr' => $sectionreturn,
'delete' => 1,
'sesskey' => sesskey()));
$controls['delete'] = array(
'url' => $url,
'icon' => 'i/delete',
'name' => $strdelete,
'pixattr' => array('class' => ''),
'attr' => array('class' => 'icon editing_delete'));
}
}
return $controls;
}
}

View File

@ -0,0 +1,99 @@
<?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/>.
/**
* Contains the default section header format output class.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output\section_format;
use core_course\course_format;
use section_info;
use renderable;
use templatable;
use stdClass;
/**
* Base class to render a section header.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class header implements renderable, templatable {
/** @var course_format the course format class */
protected $format;
/** @var section_info the course section class */
protected $section;
/**
* Constructor.
*
* @param course_format $format the course format
* @param section_info $section the section info
*/
public function __construct(course_format $format, section_info $section) {
$this->format = $format;
$this->section = $section;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return array data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
$format = $this->format;
$section = $this->section;
$course = $format->get_course();
$data = (object)[
'num' => $section->section,
'id' => $section->id,
];
if ($section->section > $format->get_last_section_number()) {
// Stealth sections (orphaned) has special title.
$data->title = get_string('orphanedactivitiesinsectionno', '', $section->section);
} else if ($section->section == $format->get_section_number()) {
// Regular section title.
$data->title = $output->section_title_without_link($section, $course);
$data->issinglesection = true;
} else {
// Regular section title.
$data->title = $output->section_title($section, $course);
}
if (!$section->visible) {
$data->ishidden = true;
}
if (!$format->show_editor() && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE && empty($data->issinglesection)) {
$data->url = course_get_url($course, $section->section);
$data->name = get_section_name($course, $section);
}
return $data;
}
}

View File

@ -0,0 +1,94 @@
<?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/>.
/**
* Contains the default section summary (used for multipage format).
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_course\output\section_format;
use core_course\course_format;
use section_info;
use renderable;
use templatable;
use context_course;
use stdClass;
/**
* Base class to render a course section summary.
*
* @package core_course
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class summary implements renderable, templatable {
/** @var course_format the course format class */
protected $format;
/** @var section_info the course section class */
private $section;
/**
* Constructor.
*
* @param course_format $format the course format
* @param section_info $section the section info
*/
public function __construct(course_format $format, section_info $section) {
$this->format = $format;
$this->section = $section;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output typically, the renderer that's calling this function
* @return array data context for a mustache template
*/
public function export_for_template(\renderer_base $output): stdClass {
$section = $this->section;
$data = new stdClass();
if ($section->uservisible || $section->visible) {
$data->summarytext = $this->format_summary_text();
}
return $data;
}
/**
* Generate html for a section summary text
*
* @return string HTML to output.
*/
public function format_summary_text(): string {
$section = $this->section;
$context = context_course::instance($section->course);
$summarytext = file_rewrite_pluginfile_urls($section->summary, 'pluginfile.php',
$context->id, 'course', 'section', $section->id);
$options = new stdClass();
$options->noclean = true;
$options->overflowdiv = true;
return format_text($summarytext, $section->summaryformat, $options);
}
}

View File

@ -652,13 +652,13 @@ class dndupload_ajax_processor {
$resp->error = self::ERROR_OK;
$resp->elementid = 'module-' . $mod->id;
$courserenderer = $PAGE->get_renderer('core', 'course');
$completioninfo = new completion_info($this->course);
$info = get_fast_modinfo($this->course);
$sr = null;
$modulehtml = $courserenderer->course_section_cm($this->course, $completioninfo,
$mod, null, array());
$resp->fullcontent = $courserenderer->course_section_cm_list_item($this->course, $completioninfo, $mod, $sr);
$format = course_get_format($this->course);
$renderer = $format->get_renderer($PAGE);
$modinfo = $format->get_modinfo();
$section = $modinfo->get_section_info($mod->sectionnum);
// Get the new element html content.
$resp->fullcontent = $renderer->course_section_updated_cm_item($format, $section, $mod);
echo $OUTPUT->header();
echo json_encode($resp);

View File

@ -3521,8 +3521,11 @@ class core_course_external extends external_api {
$modcontext = context_module::instance($cm->id);
$coursecontext = context_course::instance($course->id);
self::validate_context($modcontext);
$courserenderer = $PAGE->get_renderer('core', 'course');
$completioninfo = new completion_info($course);
$format = course_get_format($course);
if ($sectionreturn) {
$format->set_section_number($sectionreturn);
}
$renderer = $format->get_renderer($PAGE);
switch($action) {
case 'hide':
@ -3542,10 +3545,15 @@ class core_course_external extends external_api {
throw new moodle_exception('No permission to create that activity');
}
if ($newcm = duplicate_module($course, $cm)) {
$cm = get_fast_modinfo($course)->get_cm($id);
$newcm = get_fast_modinfo($course)->get_cm($newcm->id);
return $courserenderer->course_section_cm_list_item($course, $completioninfo, $cm, $sectionreturn) .
$courserenderer->course_section_cm_list_item($course, $completioninfo, $newcm, $sectionreturn);
$modinfo = $format->get_modinfo();
$section = $modinfo->get_section_info($newcm->sectionnum);
$cm = $modinfo->get_cm($id);
// Get both original and new element html.
$result = $renderer->course_section_updated_cm_item($format, $section, $cm);
$result .= $renderer->course_section_updated_cm_item($format, $section, $newcm);
return $result;
}
break;
case 'groupsseparate':
@ -3580,8 +3588,10 @@ class core_course_external extends external_api {
throw new coding_exception('Unrecognised action');
}
$cm = get_fast_modinfo($course)->get_cm($id);
return $courserenderer->course_section_cm_list_item($course, $completioninfo, $cm, $sectionreturn);
$modinfo = $format->get_modinfo();
$section = $modinfo->get_section_info($cm->sectionnum);
$cm = $modinfo->get_cm($id);
return $renderer->course_section_updated_cm_item($format, $section, $cm);
}
/**
@ -3639,9 +3649,15 @@ class core_course_external extends external_api {
list($course, $cm) = get_course_and_cm_from_cmid($id);
self::validate_context(context_course::instance($course->id));
$courserenderer = $PAGE->get_renderer('core', 'course');
$completioninfo = new completion_info($course);
return $courserenderer->course_section_cm_list_item($course, $completioninfo, $cm, $sectionreturn);
$format = course_get_format($course);
if ($sectionreturn) {
$format->set_section_number($sectionreturn);
}
$renderer = $format->get_renderer($PAGE);
$modinfo = $format->get_modinfo();
$section = $modinfo->get_section_info($cm->sectionnum);
return $renderer->course_section_updated_cm_item($format, $section, $cm);
}
/**

View File

@ -9,6 +9,10 @@ below.
If you want to store information in the database for your format, or control
access to features of your format, you need some of the optional files too.
If you want to override some standard course output component (located in
coure/classes/output/{course|section|cm}_format/*) you need to create an
extend class inside your course/format/yourformat/classes/output.
All names below assume that your format is called 'yourformat'.
@ -139,3 +143,31 @@ Optional file (styles)
If this file exists it will be included in the CSS Moodle generates.
Optional files (outputs)
----------------------
By default, the format renderer will use those output classes:
* core_course\output\course_format: for the general course structure
* core_course\output\course_format\*: to render specific course structure parts
* core_course\output\section_format: for the complete section output
* core_course\output\section_format\*: to render specific section parts
* core_course\output\cm_format: for output an activity inside a section
* core_course\output\cm_format\*: for speficis parts of the cm output
Your format can override any of this output classes just by creating class
inside your format_yourformat\output\ classes. We recommend to extend the
original class to ensure all element will work as expected.
For example: if you want to change the section header, you should create
format_yourformat\output\section_format\header, which will extend the original
core_course\output\section_format\header class.
By default, only two format renderer methods are needed to render a course:
- render_course_format to render a full course
- course_section_updated_cm_item used by the course editor to refresh a specific cm item
Formats can override those two methods to use different templates to render a course.

View File

@ -31,7 +31,7 @@ defined('MOODLE_INTERNAL') || die;
* @copyright 2012 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_legacy extends format_base {
class format_legacy extends core_course\course_format {
/**
* Returns true if this course format uses sections

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,7 @@ require_once($CFG->dirroot. '/course/format/lib.php');
* @copyright 2012 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_singleactivity extends format_base {
class format_singleactivity extends core_course\course_format {
/** @var cm_info the current activity. Use get_activity() to retrieve it. */
private $activity = false;

View File

@ -23,6 +23,7 @@
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot.'/course/format/renderer.php');
/**
* Basic renderer for singleactivity format.
@ -31,7 +32,7 @@ defined('MOODLE_INTERNAL') || die();
* @copyright 2013 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_singleactivity_renderer extends plugin_renderer_base {
class format_singleactivity_renderer extends format_section_renderer_base {
/**
* Displays the activities list in cases when course view page is not
@ -42,20 +43,28 @@ class format_singleactivity_renderer extends plugin_renderer_base {
* if true displays all other activities
*/
public function display($course, $orphaned) {
$courserenderer = $this->page->get_renderer('core', 'course');
$format = course_get_format($course);
$modinfo = $format->get_modinfo();
$cmlistclass = $format->get_output_classname('section_format\\cmlist');
$output = '';
$modinfo = get_fast_modinfo($course);
if ($orphaned) {
if (!empty($modinfo->sections[1])) {
$output .= $this->output->heading(get_string('orphaned', 'format_singleactivity'), 3, 'sectionname');
$output .= $this->output->box(get_string('orphanedwarning', 'format_singleactivity'));
$output .= $courserenderer->course_section_cm_list($course, 1, 1);
$section = $modinfo->get_section_info(1);
$output .= $this->render(new $cmlistclass($format, $section));
}
} else {
$output .= $courserenderer->course_section_cm_list($course, 0, 0);
$section = $modinfo->get_section_info(0);
$output .= $this->render(new $cmlistclass($format, $section));
if (empty($modinfo->sections[0]) && course_get_format($course)->activity_has_subtypes()) {
// Course format was unable to automatically redirect to add module page.
$output .= $courserenderer->course_section_add_cm_control($course, 0, 0);
$output .= $this->course_section_add_cm_control($course, 0, 0);
}
}
return $output;

View File

@ -33,7 +33,7 @@ require_once($CFG->dirroot. '/course/format/lib.php');
* @copyright 2012 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_social extends format_base {
class format_social extends core_course\course_format {
/**
* The URL to use for the specified course

View File

@ -0,0 +1,118 @@
<?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/>.
/**
* Contains the default section controls output class.
*
* @package format_topics
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace format_topics\output\section_format;
use context_course;
/**
* Base class to render a course section menu.
*
* @package format_topics
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class controlmenu extends \core_course\output\section_format\controlmenu {
/** @var course_format the course format class */
protected $format;
/** @var section_info the course section class */
protected $section;
/**
* Generate the edit control items of a section.
*
* This method must remain public until the final deprecation of section_edit_control_items.
*
* @return array of edit control items
*/
public function section_control_items() {
$format = $this->format;
$section = $this->section;
$course = $format->get_course();
$sectionreturn = $format->get_section_number();
$coursecontext = context_course::instance($course->id);
if ($sectionreturn) {
$url = course_get_url($course, $section->section);
} else {
$url = course_get_url($course);
}
$url->param('sesskey', sesskey());
$controls = [];
if ($section->section && has_capability('moodle/course:setcurrentsection', $coursecontext)) {
if ($course->marker == $section->section) { // Show the "light globe" on/off.
$url->param('marker', 0);
$highlightoff = get_string('highlightoff');
$controls['highlight'] = [
'url' => $url,
'icon' => 'i/marked',
'name' => $highlightoff,
'pixattr' => ['class' => ''],
'attr' => [
'class' => 'editing_highlight',
'data-action' => 'removemarker'
],
];
} else {
$url->param('marker', $section->section);
$highlight = get_string('highlight');
$controls['highlight'] = [
'url' => $url,
'icon' => 'i/marker',
'name' => $highlight,
'pixattr' => ['class' => ''],
'attr' => [
'class' => 'editing_highlight',
'data-action' => 'setmarker'
],
];
}
}
$parentcontrols = parent::section_control_items();
// If the edit key exists, we are going to insert our controls after it.
if (array_key_exists("edit", $parentcontrols)) {
$merged = [];
// We can't use splice because we are using associative arrays.
// Step through the array and merge the arrays.
foreach ($parentcontrols as $key => $action) {
$merged[$key] = $action;
if ($key == "edit") {
// If we have come to the edit key, merge these controls here.
$merged = array_merge($merged, $controls);
}
}
return $merged;
} else {
return array_merge($controls, $parentcontrols);
}
}
}

View File

@ -37,9 +37,10 @@ if ($topic = optional_param('topic', 0, PARAM_INT)) {
}
// End backwards-compatible aliasing.
$context = context_course::instance($course->id);
// Retrieve course format option fields and add them to the $course object.
$course = course_get_format($course)->get_course();
$format = course_get_format($course);
$course = $format->get_course();
$context = context_course::instance($course->id);
if (($marker >= 0) && has_capability('moodle/course:setcurrentsection', $context) && confirm_sesskey()) {
$course->marker = $marker;
@ -52,10 +53,11 @@ course_create_sections_if_missing($course, 0);
$renderer = $PAGE->get_renderer('format_topics');
if (!empty($displaysection)) {
$renderer->print_single_section_page($course, null, null, null, null, $displaysection);
} else {
$renderer->print_multiple_section_page($course, null, null, null, null);
$format->set_section_number($displaysection);
}
$outputclass = $format->get_output_classname('course_format');
$widget = new $outputclass($format);
echo $renderer->render($widget);
// Include course format js module.
$PAGE->requires->js('/course/format/topics/format.js');

View File

@ -35,7 +35,7 @@ use core\output\inplace_editable;
* @copyright 2012 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_topics extends format_base {
class format_topics extends core_course\course_format {
/**
* Returns true if this course format uses sections.
@ -68,7 +68,7 @@ class format_topics extends format_base {
* Returns the default section name for the topics course format.
*
* If the section number is 0, it will use the string with key = section0name from the course format's lang file.
* If the section number is not 0, the base implementation of format_base::get_default_section_name which uses
* If the section number is not 0, the base implementation of course_format::get_default_section_name which uses
* the string with the key = 'sectionname' from the course format's lang file + the section number will be used.
*
* @param stdClass $section Section object from database or just field course_sections section
@ -79,12 +79,21 @@ class format_topics extends format_base {
// Return the general section.
return get_string('section0name', 'format_topics');
} else {
// Use format_base::get_default_section_name implementation which
// Use course_format::get_default_section_name implementation which
// will display the section name in "Topic n" format.
return parent::get_default_section_name($section);
}
}
/**
* Generate the title for this section page.
*
* @return string the page title
*/
public function page_title(): string {
return get_string('topicoutline');
}
/**
* The URL to use for the specified course (with section).
*
@ -412,7 +421,15 @@ class format_topics extends format_base {
// For show/hide actions call the parent method and return the new content for .section_availability element.
$rv = parent::section_action($section, $action, $sr);
$renderer = $PAGE->get_renderer('format_topics');
$rv['section_availability'] = $renderer->section_availability($this->get_section($section));
if (!($section instanceof section_info)) {
$modinfo = $this->get_modinfo();
$section = $modinfo->get_section_info($section->section);
}
$elementclass = $this->get_output_classname('section_format\\availability');
$availability = new $elementclass($this, $section);
$rv['section_availability'] = $renderer->render($availability);
return $rv;
}

View File

@ -49,33 +49,6 @@ class format_topics_renderer extends format_section_renderer_base {
$page->set_other_editing_capability('moodle/course:setcurrentsection');
}
/**
* Generate the starting container html for a list of sections.
*
* @return string HTML to output.
*/
protected function start_section_list() {
return html_writer::start_tag('ul', ['class' => 'topics']);
}
/**
* Generate the closing container html for a list of sections.
*
* @return string HTML to output.
*/
protected function end_section_list() {
return html_writer::end_tag('ul');
}
/**
* Generate the title for this section page.
*
* @return string the page title
*/
protected function page_title() {
return get_string('topicoutline');
}
/**
* Generate the section title, wraps it in a link to the section page if page is to be displayed on a separate page.
*
@ -98,77 +71,4 @@ class format_topics_renderer extends format_section_renderer_base {
return $this->render(course_get_format($course)->inplace_editable_render_section_name($section, false));
}
/**
* Generate the edit control items of a section.
*
* @param int|stdClass $course The course entry from DB
* @param section_info|stdClass $section The course_section entry from DB
* @param bool $onsectionpage true if being printed on a section page
* @return array of edit control items
*/
protected function section_edit_control_items($course, $section, $onsectionpage = false) {
if (!$this->page->user_is_editing()) {
return [];
}
$coursecontext = context_course::instance($course->id);
if ($onsectionpage) {
$url = course_get_url($course, $section->section);
} else {
$url = course_get_url($course);
}
$url->param('sesskey', sesskey());
$controls = [];
if ($section->section && has_capability('moodle/course:setcurrentsection', $coursecontext)) {
if ($course->marker == $section->section) { // Show the "light globe" on/off.
$url->param('marker', 0);
$highlightoff = get_string('highlightoff');
$controls['highlight'] = [
'url' => $url,
'icon' => 'i/marked',
'name' => $highlightoff,
'pixattr' => ['class' => ''],
'attr' => [
'class' => 'editing_highlight',
'data-action' => 'removemarker'
],
];
} else {
$url->param('marker', $section->section);
$highlight = get_string('highlight');
$controls['highlight'] = [
'url' => $url,
'icon' => 'i/marker',
'name' => $highlight,
'pixattr' => ['class' => ''],
'attr' => [
'class' => 'editing_highlight',
'data-action' => 'setmarker'
],
];
}
}
$parentcontrols = parent::section_edit_control_items($course, $section, $onsectionpage);
// If the edit key exists, we are going to insert our controls after it.
if (array_key_exists("edit", $parentcontrols)) {
$merged = [];
// We can't use splice because we are using associative arrays.
// Step through the array and merge the arrays.
foreach ($parentcontrols as $key => $action) {
$merged[$key] = $action;
if ($key == "edit") {
// If we have come to the edit key, merge these controls here.
$merged = array_merge($merged, $controls);
}
}
return $merged;
} else {
return array_merge($controls, $parentcontrols);
}
}
}

View File

@ -37,16 +37,19 @@ if ($week = optional_param('week', 0, PARAM_INT)) {
}
// End backwards-compatible aliasing..
$format = course_get_format($course);
// Make sure section 0 is created.
$course = course_get_format($course)->get_course();
course_create_sections_if_missing($course, 0);
course_create_sections_if_missing($format->get_course(), 0);
$renderer = $PAGE->get_renderer('format_weeks');
if (!empty($displaysection)) {
$renderer->print_single_section_page($course, null, null, null, null, $displaysection);
} else {
$renderer->print_multiple_section_page($course, null, null, null, null);
$format->set_section_number($displaysection);
}
$outputclass = $format->get_output_classname('course_format');
$output = new $outputclass($format);
echo $renderer->render($output);
$PAGE->requires->js('/course/format/weeks/format.js');

View File

@ -34,7 +34,7 @@ require_once($CFG->dirroot. '/course/lib.php');
* @copyright 2012 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_weeks extends format_base {
class format_weeks extends core_course\course_format {
/**
* Returns true if this course format uses sections
@ -45,6 +45,14 @@ class format_weeks extends format_base {
return true;
}
/**
* Generate the title for this section page
* @return string the page title
*/
public function page_title(): string {
return get_string('weeklyoutline');
}
/**
* Returns the display name of the given section that the course prefers.
*
@ -505,7 +513,16 @@ class format_weeks extends format_base {
// Call the parent method and return the new content for .section_availability element.
$rv = parent::section_action($section, $action, $sr);
$renderer = $PAGE->get_renderer('format_weeks');
$rv['section_availability'] = $renderer->section_availability($this->get_section($section));
if (!($section instanceof section_info)) {
$modinfo = $this->get_modinfo();
$section = $modinfo->get_section_info($section->section);
}
$elementclass = $this->get_output_classname('section_format\\availability');
$availability = new $elementclass($this, $section);
$rv['section_availability'] = $renderer->render($availability);
return $rv;
}

View File

@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot.'/course/format/renderer.php');
require_once($CFG->dirroot.'/course/format/weeks/lib.php');
use core_course\output\section_format\availability;
/**
* Basic renderer for weeks format.
@ -36,29 +37,6 @@ require_once($CFG->dirroot.'/course/format/weeks/lib.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_weeks_renderer extends format_section_renderer_base {
/**
* Generate the starting container html for a list of sections
* @return string HTML to output.
*/
protected function start_section_list() {
return html_writer::start_tag('ul', array('class' => 'weeks'));
}
/**
* Generate the closing container html for a list of sections
* @return string HTML to output.
*/
protected function end_section_list() {
return html_writer::end_tag('ul');
}
/**
* Generate the title for this section page
* @return string the page title
*/
protected function page_title() {
return get_string('weeklyoutline');
}
/**
* Generate the section title, wraps it in a link to the section page if page is to be displayed on a separate page

View File

@ -592,9 +592,7 @@ function course_set_marker($courseid, $marker) {
if ($COURSE && $COURSE->id == $courseid) {
$COURSE->marker = $marker;
}
if (class_exists('format_base')) {
format_base::reset_course_cache($courseid);
}
core_course\course_format::reset_course_cache($courseid);
course_modinfo::clear_instance_cache($courseid);
}
@ -2149,7 +2147,7 @@ function move_courses($courseids, $categoryid) {
* Returns the display name of the given section that the course prefers
*
* Implementation of this function is provided by course format
* @see format_base::get_section_name()
* @see core_course\course_format::get_section_name()
*
* @param int|stdClass $courseorid The course to get the section name for (object or just course id)
* @param int|stdClass $section Section object from database or just field course_sections.section
@ -3422,12 +3420,15 @@ function mod_duplicate_activity($course, $cm, $sr = null) {
$resp = new stdClass();
if ($newcm) {
$courserenderer = $PAGE->get_renderer('core', 'course');
$completioninfo = new completion_info($course);
$modulehtml = $courserenderer->course_section_cm($course, $completioninfo,
$newcm, null, array());
$resp->fullcontent = $courserenderer->course_section_cm_list_item($course, $completioninfo, $newcm, $sr);
$format = course_get_format($course);
$renderer = $format->get_renderer($PAGE);
$modinfo = $format->get_modinfo();
$section = $modinfo->get_section_info($newcm->sectionnum);
// Get the new element html content.
$resp->fullcontent = $renderer->course_section_updated_cm_item($format, $section, $newcm);
$resp->cmid = $newcm->id;
} else {
// Trigger a redirect.

View File

@ -815,6 +815,8 @@ class core_course_renderer extends plugin_renderer_base {
/**
* Renders HTML to display one course module for display within a section.
*
* @deprecated since 4.0 - use core_course output components or course_format::course_section_updated_cm_item instead.
*
* This function calls:
* {@link core_course_renderer::course_section_cm()}
*
@ -825,7 +827,11 @@ class core_course_renderer extends plugin_renderer_base {
* @param array $displayoptions
* @return String
*/
public function course_section_cm_list_item($course, &$completioninfo, cm_info $mod, $sectionreturn, $displayoptions = array()) {
public function course_section_cm_list_item($course, &$completioninfo, cm_info $mod, $sectionreturn, $displayoptions = []) {
debugging('course_section_cm_list_item is deprecated. Use course_format::course_section_updated_cm_item instead',
DEBUG_DEVELOPER);
$output = '';
if ($modulehtml = $this->course_section_cm($course, $completioninfo, $mod, $sectionreturn, $displayoptions)) {
$modclasses = 'activity ' . $mod->modname . ' modtype_' . $mod->modname . ' ' . $mod->extraclasses;
@ -840,6 +846,8 @@ class core_course_renderer extends plugin_renderer_base {
* This includes link, content, availability, completion info and additional information
* that module type wants to display (i.e. number of unread forum posts)
*
* @deprecated since 4.0 - use core_course output components instead.
*
* This function calls:
* {@link core_course_renderer::course_section_cm_name()}
* {@link core_course_renderer::course_section_cm_text()}
@ -855,98 +863,27 @@ class core_course_renderer extends plugin_renderer_base {
* @param array $displayoptions
* @return string
*/
public function course_section_cm($course, &$completioninfo, cm_info $mod, $sectionreturn, $displayoptions = array()) {
$output = '';
// We return empty string (because course module will not be displayed at all)
// if:
// 1) The activity is not visible to users
// and
// 2) The 'availableinfo' is empty, i.e. the activity was
// hidden in a way that leaves no info, such as using the
// eye icon.
public function course_section_cm($course, &$completioninfo, cm_info $mod, $sectionreturn, $displayoptions = []) {
debugging('course_section_cm is deprecated. Use core_course\output\cm_format output classes instead.', DEBUG_DEVELOPER);
if (!$mod->is_visible_on_course_page()) {
return $output;
return '';
}
$indentclasses = 'mod-indent';
if (!empty($mod->indent)) {
$indentclasses .= ' mod-indent-'.$mod->indent;
if ($mod->indent > 15) {
$indentclasses .= ' mod-indent-huge';
}
$format = course_get_format($course);
$modinfo = $format->get_modinfo();
// Output renderers works only with real section_info objects.
if ($sectionreturn) {
$format->set_section_number($sectionreturn);
}
$section = $modinfo->get_section_info($format->get_section_number());
$output .= html_writer::start_tag('div');
if ($this->page->user_is_editing()) {
$output .= course_get_cm_move($mod, $sectionreturn);
}
$output .= html_writer::start_tag('div', array('class' => 'mod-indent-outer w-100'));
// This div is used to indent the content.
$output .= html_writer::div('', $indentclasses);
// Start a wrapper for the actual content to keep the indentation consistent
$output .= html_writer::start_tag('div');
// Display the link to the module (or do nothing if module has no url)
$cmname = $this->course_section_cm_name($mod, $displayoptions);
if (!empty($cmname)) {
// Start the div for the activity title, excluding the edit icons.
$output .= html_writer::start_tag('div', array('class' => 'activityinstance'));
$output .= $cmname;
// Module can put text after the link (e.g. forum unread)
$output .= $mod->afterlink;
// Closing the tag which contains everything but edit icons. Content part of the module should not be part of this.
$output .= html_writer::end_tag('div'); // .activityinstance
}
// If there is content but NO link (eg label), then display the
// content here (BEFORE any icons). In this case cons must be
// displayed after the content so that it makes more sense visually
// and for accessibility reasons, e.g. if you have a one-line label
// it should work similarly (at least in terms of ordering) to an
// activity.
$contentpart = $this->course_section_cm_text($mod, $displayoptions);
$url = $mod->url;
if (empty($url)) {
$output .= $contentpart;
}
$modicons = '';
if ($this->page->user_is_editing()) {
$editactions = course_get_cm_edit_actions($mod, $mod->indent, $sectionreturn);
$modicons .= ' '. $this->course_section_cm_edit_actions($editactions, $mod, $displayoptions);
$modicons .= $mod->afterediticons;
}
$modicons .= $this->course_section_cm_completion($course, $completioninfo, $mod, $displayoptions);
if (!empty($modicons)) {
$output .= html_writer::div($modicons, 'actions');
}
// Show availability info (if module is not available).
$output .= $this->course_section_cm_availability($mod, $displayoptions);
// If there is content AND a link, then display the content here
// (AFTER any icons). Otherwise it was displayed before
if (!empty($url)) {
$output .= $contentpart;
}
$output .= html_writer::end_tag('div'); // $indentclasses
// End of indentation div.
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('div');
return $output;
$cmclass = $format->get_output_classname('cm_format');
$cm = new $cmclass($format, $section, $completioninfo, $mod, $displayoptions);
// The course outputs works with format renderers, not with course renderers.
$renderer = $format->get_renderer($this->page);
return $renderer->render($cm);
}
/**
@ -979,7 +916,9 @@ class core_course_renderer extends plugin_renderer_base {
/**
* Renders HTML to display a list of course modules in a course section
* Also displays "move here" controls in Javascript-disabled mode
* Also displays "move here" controls in Javascript-disabled mode.
*
* @deprecated since 4.0 - use core_course output components instead.
*
* This function calls {@link core_course_renderer::course_section_cm()}
*
@ -989,11 +928,17 @@ class core_course_renderer extends plugin_renderer_base {
* @param int $displayoptions
* @return void
*/
public function course_section_cm_list($course, $section, $sectionreturn = null, $displayoptions = array()) {
public function course_section_cm_list($course, $section, $sectionreturn = null, $displayoptions = []) {
global $USER;
debugging('course_section_cm_list is deprecated. Use core_course\\output\\section_format\\cmlist '.
'classes instead.', DEBUG_DEVELOPER);
$output = '';
$modinfo = get_fast_modinfo($course);
$format = course_get_format($course);
$modinfo = $format->get_modinfo();
if (is_object($section)) {
$section = $modinfo->get_section_info($section->section);
} else {
@ -1002,13 +947,14 @@ class core_course_renderer extends plugin_renderer_base {
$completioninfo = new completion_info($course);
// check if we are currently in the process of moving a module with JavaScript disabled
$ismoving = $this->page->user_is_editing() && ismoving($course->id);
$ismoving = $format->show_editor() && ismoving($course->id);
if ($ismoving) {
$strmovefull = strip_tags(get_string("movefull", "", "'$USER->activitycopyname'"));
}
// Get the list of modules visible to user (excluding the module being moved if there is one)
$moduleshtml = array();
$moduleshtml = [];
if (!empty($modinfo->sections[$section->section])) {
foreach ($modinfo->sections[$section->section] as $modnumber) {
$mod = $modinfo->cms[$modnumber];
@ -1031,8 +977,8 @@ class core_course_renderer extends plugin_renderer_base {
if ($ismoving) {
$movingurl = new moodle_url('/course/mod.php', array('moveto' => $modnumber, 'sesskey' => sesskey()));
$sectionoutput .= html_writer::tag('li',
html_writer::link($movingurl, '', array('title' => $strmovefull, 'class' => 'movehere')),
array('class' => 'movehere'));
html_writer::link($movingurl, '', array('title' => $strmovefull, 'class' => 'movehere')),
array('class' => 'movehere'));
}
$sectionoutput .= $modulehtml;
@ -1041,8 +987,8 @@ class core_course_renderer extends plugin_renderer_base {
if ($ismoving) {
$movingurl = new moodle_url('/course/mod.php', array('movetosection' => $section->id, 'sesskey' => sesskey()));
$sectionoutput .= html_writer::tag('li',
html_writer::link($movingurl, '', array('title' => $strmovefull, 'class' => 'movehere')),
array('class' => 'movehere'));
html_writer::link($movingurl, '', array('title' => $strmovefull, 'class' => 'movehere')),
array('class' => 'movehere'));
}
}
@ -2256,53 +2202,17 @@ class core_course_renderer extends plugin_renderer_base {
$modinfo = get_fast_modinfo($SITE);
$section = $modinfo->get_section_info(1);
if (($section && (!empty($modinfo->sections[1]) or !empty($section->summary))) or $editing) {
$output .= $this->box_start('generalbox sitetopic');
// If currently moving a file then show the current clipboard.
if (ismoving($SITE->id)) {
$stractivityclipboard = strip_tags(get_string('activityclipboard', '', $USER->activitycopyname));
$output .= '<p><font size="2">';
$cancelcopyurl = new moodle_url('/course/mod.php', ['cancelcopy' => 'true', 'sesskey' => sesskey()]);
$output .= "$stractivityclipboard&nbsp;&nbsp;(" . html_writer::link($cancelcopyurl, get_string('cancel')) .')';
$output .= '</font></p>';
}
$format = course_get_format($SITE);
$frontpageclass = $format->get_output_classname('course_format\\frontpagesection');
$frontpagesection = new $frontpageclass($format, $section);
$context = context_course::instance(SITEID);
// If the section name is set we show it.
if (trim($section->name) !== '') {
$output .= $this->heading(
format_string($section->name, true, array('context' => $context)),
2,
'sectionname'
);
}
$summarytext = file_rewrite_pluginfile_urls($section->summary,
'pluginfile.php',
$context->id,
'course',
'section',
$section->id);
$summaryformatoptions = new stdClass();
$summaryformatoptions->noclean = true;
$summaryformatoptions->overflowdiv = true;
$output .= format_text($summarytext, $section->summaryformat, $summaryformatoptions);
if ($editing && has_capability('moodle/course:update', $context)) {
$streditsummary = get_string('editsummary');
$editsectionurl = new moodle_url('/course/editsection.php', ['id' => $section->id]);
$attributes = ['title' => $streditsummary, 'aria-label' => $streditsummary];
$output .= html_writer::link($editsectionurl, $this->pix_icon('t/edit', ''), $attributes) .
"<br /><br />";
}
$output .= $this->course_section_cm_list($SITE, $section);
$output .= $this->course_section_add_cm_control($SITE, $section->section);
$output .= $this->box_end();
// The course outputs works with format renderers, not with course renderers.
$renderer = $format->get_renderer($this->page);
$output .= $renderer->render($frontpagesection);
}
return $output;

View File

@ -0,0 +1,69 @@
{{!
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/local/cm_format
Displays a course module instance inside a course section.
Example context (json):
{
"cmname": "<a class=\"aalink\" href=\"#\"><span class=\"instancename\">Activity example</span></a>",
"hasname": "true",
"moveicon": "<i>[Move]</i>",
"indent": 2,
"afterlink": "<span class=\"badge badge-primary\">30 unread messages</span>",
"hasextras": true,
"extras": ["<span class=\"badge badge-secondary\">[extras]</span>"],
"completion": "<span class=\"badge badge-success\">Completed!</span>",
"availability": "<div><span class=\"badge badge-info\">Restricted</span> Available from <strong>3 Dec 2029</strong></div>"
}
}}
<div>
<div class="mod-indent-outer w-100">
{{#moveicon}} {{{moveicon}}} {{/moveicon}}
{{! This div is used to indent the content. }}
<div class="mod-indent {{#indent}}mod-indent-{{indent}}{{/indent}} {{#hugeindent}}mod-indent-huge{{/hugeindent}}"></div>
{{! Start a wrapper for the actual content to keep the indentation consistent. }}
<div>
{{! Display the link to the module (or do nothing if module has no url). }}
{{#hasname}}
<div class="activityinstance">
{{{cmname}}} {{{afterlink}}}
</div>
{{/hasname}}
{{! If there is content but NO link (eg label), then display the
content here (BEFORE any icons). In this case cons must be
displayed after the content so that it makes more sense visually
and for accessibility reasons, e.g. if you have a one-line label
it should work similarly (at least in terms of ordering) to an
activity. }}
{{^hasurl}} {{{altcontent}}} {{/hasurl}}
{{#hasextras}}
<div class="actions">
{{#extras}} {{{.}}} {{/extras}}
{{{completion}}}
</div>
{{/hasextras}}
{{{availability}}}
{{#hasurl}} {{{altcontent}}} {{/hasurl}}
</div>
</div>
</div>

View File

@ -0,0 +1,181 @@
{{!
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/local/course_format
Displays the complete course format.
Example context (json):
{
"initialsection": {
"num": 0,
"id": 34,
"cmlist": {
"cms": [
{
"cmitem": {
"cmformat": {
"cmname": "<a class=\"aalink\" href=\"#\"><span class=\"instancename\">Forum example</span></a>",
"hasname": "true"
},
"id": 3,
"module": "forum",
"extraclasses": "newmessages"
}
}
],
"hascms": true
},
"iscurrent": true,
"summary": {
"summarytext": "Summary text!"
}
},
"sections": [
{
"num": 1,
"id": 35,
"header": {
"name": "Section title",
"url": "#"
},
"cmlist": {
"cms": [
{
"cmitem": {
"cmformat": {
"cmname": "<a class=\"aalink\" href=\"#\"><span class=\"instancename\">Another forum</span></a>",
"hasname": "true"
},
"id": 3,
"module": "forum",
"extraclasses": "newmessages"
}
}
],
"hascms": true
},
"iscurrent": true,
"summary": {
"summarytext": "Summary text!"
}
},
{
"num": 4,
"id": 36,
"header": {
"name": "Section 2 title",
"url": "#"
},
"cmlist": {
"cms": [
{
"cmitem": {
"cmformat": {
"cmname": "<a class=\"aalink\" href=\"#\"><span class=\"instancename\">Forum example</span></a>",
"hasname": "true"
},
"id": 5,
"module": "forum",
"extraclasses": "newmessages"
}
}
],
"hascms": true
},
"iscurrent": true,
"summary": {
"summarytext": "Summary text!"
}
}
],
"format": "topics",
"title": "Course title example",
"hasnavigation": true,
"sectionnavigation": {
"hasprevious": true,
"previousurl": "#",
"larrow": "&#x25C4;",
"previousname": "Section 3",
"hasnext": true,
"rarrow": "&#x25BA;",
"nexturl": "#",
"nextname": "Section 5"
},
"sectionselector": {
"hasprevious": true,
"previousurl": "#",
"larrow": "&#x25C4;",
"previousname": "Section 3",
"hasnext": true,
"rarrow": "&#x25BA;",
"nexturl": "#",
"nextname": "Section 5",
"selector": "<select><option>Section 4</option></select>"
},
"singlesection": {
"num": 1,
"id": 35,
"header": {
"name": "Single Section Example",
"url": "#"
},
"cmlist": {
"cms": [
{
"cmitem": {
"cmformat": {
"cmname": "<a class=\"aalink\" href=\"#\"><span class=\"instancename\">Assign example</span></a>",
"hasname": "true"
},
"id": 4,
"module": "assign",
"extraclasses": ""
}
}
],
"hascms": true
},
"iscurrent": true,
"summary": {
"summarytext": "Summary text!"
}
}
}
}}
<h2 class="accesshide">{{{title}}}</h2>
{{{completionhelp}}}
<ul class="{{format}}">
{{#initialsection}}
{{> core_course/local/section_format }}
{{/initialsection}}
{{#sections}}
{{> core_course/local/section_format }}
{{/sections}}
</ul>
{{#hasnavigation}}
<div class="single-section">
{{#sectionnavigation}} {{> core_course/local/course_format/sectionnavigation }} {{/sectionnavigation}}
<ul class="{{format}}">
{{#singlesection}}
{{> core_course/local/section_format }}
{{/singlesection}}
</ul>
{{#sectionselector}} {{> core_course/local/course_format/sectionselector }} {{/sectionselector}}
</div>
{{/hasnavigation}}
{{#numsections}} {{> core_course/local/course_format/addsection}} {{/numsections}}

View File

@ -0,0 +1,56 @@
{{!
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/local/course_format/addsection
Displays the add section button inside a course.
Example context (json):
{
"showaddsection": true,
"increase": {
"url": "#"
},
"decrease": {
"url": "#"
},
"addsections": {
"url": "#",
"title": "Add section",
"newsection": 3
}
}
}}
{{#showaddsection}}
<div id="changenumsections" class="mdl-right">
{{#increase}}
<a href="{{{url}}}" class="increase-sections">
{{#pix}}t/switch_plus, moodle, {{#str}} increasesections, moodle {{/str}}{{/pix}}
</a>
{{/increase}}
{{#decrease}}
<a href="{{{url}}}" class="reduce-sections">
{{#pix}}t/switch_minus, moodle, {{#str}} reducesections, moodle {{/str}}{{/pix}}
</a>
{{/decrease}}
{{#addsections}}
<a href="{{{url}}}" class="add-sections" data-add-sections="{{title}}" data-new-sections="{{newsection}}">
{{#pix}} t/add, moodle {{/pix}} {{title}}
</a>
{{/addsections}}
</div>
{{/showaddsection}}

View File

@ -0,0 +1,46 @@
{{!
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/local/course_format/frontpagesection
Displays the frontpage section 1 (site home).
Example context (json):
{
"sections": [
"<li>This is the section content</li>"
],
"showsettings": true,
"settingsurl": "#"
}
}}
<div class="course-content">
{{#showsettings}}
<div class="mb-2">
<a href="{{{settingsurl}}}" title="{{#str}} editsummary {{/str}}" aria-label="{{#str}} editsummary {{/str}}">
{{#pix}} t/edit, moodle {{/pix}}
</a>
</div>
{{/showsettings}}
<div class="sitetopic">
<ul class="topics frontpage">
{{#sections}}
{{> core_course/local/section_format }}
{{/sections}}
</ul>
</div>
</div>

View File

@ -0,0 +1,49 @@
{{!
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/local/course_format/sectionnavigation
Displays the course section navigation.
Example context (json):
{
"hasprevious": true,
"previousurl": "#",
"larrow": "&#x25C4;",
"previousname": "Section 3",
"hasnext": true,
"rarrow": "&#x25BA;",
"nexturl": "#",
"nextname": "Section 5"
}
}}
<div class="section-navigation navigationtitle d-flex justify-content-between">
<div class="prevsection">
{{#hasprevious}}
<a href="{{{previousurl}}}" class="{{#previoushidden}} dimmed_text {{/previoushidden}}">
<span class="larrow">{{{larrow}}}</span>{{{previousname}}}
</a>
{{/hasprevious}}
</div>
<div class="nextsection">
{{#hasnext}}
<a href="{{{nexturl}}}" class="{{#nexthidden}} dimmed_text {{/nexthidden}}">
<span class="rarrow">{{{rarrow}}}</span>{{{nextname}}}
</a>
{{/hasnext}}
</div>
</div>

View File

@ -0,0 +1,53 @@
{{!
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/local/course_format/sectionselector
Displays the course section navigation.
Example context (json):
{
"hasprevious": true,
"previousurl": "#",
"larrow": "&#x25C4;",
"previousname": "Section 3",
"hasnext": true,
"rarrow": "&#x25BA;",
"nexturl": "#",
"nextname": "Section 5",
"selector": "<select><option>Section 4</option></select>"
}
}}
<div class="section-navigation mdl-bottom d-flex justify-content-between">
<div class="prevsection">
{{#hasprevious}}
<a href="{{{previousurl}}}" class="{{#previoushidden}} dimmed_text {{/previoushidden}}">
<span class="larrow">{{{larrow}}}</span>{{{previousname}}}
</a>
{{/hasprevious}}
</div>
<div>
{{{selector}}}
</div>
<div class="nextsection">
{{#hasnext}}
<a href="{{{nexturl}}}" class="{{#nexthidden}} dimmed_text {{/nexthidden}}">
<span class="rarrow">{{{rarrow}}}</span>{{{nextname}}}
</a>
{{/hasnext}}
</div>
</div>

View File

@ -0,0 +1,107 @@
{{!
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/local/section_format
Displays a course section.
Example context (json):
{
"num": 3,
"id": 35,
"controlmenu": "[tools menu]",
"header": {
"name": "Section title",
"url": "#",
"ishidden": true
},
"cmlist": {
"cms": [
{
"cmitem": {
"cmformat": {
"cmname": "<a class=\"aalink\" href=\"#\"><span class=\"instancename\">Forum example</span></a>",
"hasname": "true"
},
"id": 3,
"module": "forum",
"extraclasses": "newmessages"
}
},
{
"cmitem": {
"cmformat": {
"cmname": "<a class=\"aalink\" href=\"#\"><span class=\"instancename\">Assign example</span></a>",
"hasname": "true"
},
"id": 4,
"module": "assign",
"extraclasses": ""
}
}
],
"hascms": true
},
"ishidden": false,
"iscurrent": true,
"currentlink": "<span class=\"accesshide\">This topic</span>",
"completioninfo": "<span class=\"badge badge-primary\">Completion Info</span>",
"availability": {
"info": "<span class=\"badge badge-info\">Hidden from students</span>",
"hasavailability": true
},
"summary": {
"summarytext": "Summary text!"
},
"controlmenu": {
"menu": "<a href=\"#\" class=\"d-inline-block dropdown-toggle icon-no-margin\">Edit<b class=\"caret\"></b></a>",
"hasmenu": true
},
"cmcontrols": "[Add an activity or resource]"
}
}}
<li id="section-{{num}}"
class="section main {{#onlysummary}} section-summary {{/onlysummary}} clearfix
{{#ishidden}} hidden {{/ishidden}} {{#iscurrent}} current {{/iscurrent}}
{{#isstealth}} orphaned {{/isstealth}}"
role="region"
aria-labelledby="sectionid-{{id}}-title"
data-sectionid="{{num}}"
data-sectionreturnid="{{sectionreturnid}}">
{{#singleheader}} {{> core_course/local/section_format/header }} {{/singleheader}}
<div class="left side">{{#iscurrent}} {{{currentlink}}} {{/iscurrent}}</div>
<div class="right side">
{{#controlmenu}}
{{> core_course/local/section_format/controlmenu }}
{{/controlmenu}}
</div>
<div class="content">
{{#header}} {{> core_course/local/section_format/header }} {{/header}}
{{{completioninfo}}}
{{#availability}}
{{> core_course/local/section_format/availability }}
{{/availability}}
<div class="summary">
{{#summary}}
{{> core_course/local/section_format/summary }}
{{/summary}}
</div>
{{#cmsummary}} {{> core_course/local/section_format/cmsummary }} {{/cmsummary}}
{{#cmlist}} {{> core_course/local/section_format/cmlist }} {{/cmlist}}
{{{cmcontrols}}}
</div>
</li>

View File

@ -0,0 +1,34 @@
{{!
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/local/section_format/availability
Displays a section availability.
The 3.x version course edition requires an existing section_availability div.
Example context (json):
{
"info": "<span class=\"badge badge-info\">Hidden from students</span>",
"hasavailability": true
}
}}
<div class="section_availability">
{{#hasavailability}}
{{{info}}}
{{/hasavailability}}
</div>

View File

@ -0,0 +1,43 @@
{{!
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/local/section_format/cmitem
Displays the course module list inside a course section.
Example context (json):
{
"cmformat": {
"cmname": "<a class=\"aalink\" href=\"#\"><span class=\"instancename\">Activity example</span></a>",
"hasname": "true",
"moveicon": "<i>[Move]</i>",
"indent": 2,
"afterlink": "<span class=\"badge badge-primary\">30 unread messages</span>",
"hasextras": true,
"extras": ["<span class=\"badge badge-secondary\">[extras]</span>"],
"completion": "<span class=\"badge badge-success\">Completed!</span>"
},
"id": 3,
"module": "forum",
"extraclasses": "newmessages"
}
}}
<li class="activity {{module}} modtype_{{module}} {{extraclasses}}" id="module-{{id}}">
{{#cmformat}}
{{> core_course/local/cm_format}}
{{/cmformat}}
</li>

View File

@ -0,0 +1,77 @@
{{!
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/local/section_format/cmlist
Displays the course module list inside a course section.
Example context (json):
{
"cms": [
{
"cmitem": {
"cmformat": {
"cmname": "<a class=\"aalink\" href=\"#\"><span class=\"instancename\">Forum example</span></a>",
"hasname": "true"
},
"id": 3,
"module": "forum",
"extraclasses": "newmessages"
}
},
{
"cmitem": {
"cmformat": {
"cmname": "<a class=\"aalink\" href=\"#\"><span class=\"instancename\">Assign example</span></a>",
"hasname": "true"
},
"id": 3,
"module": "assign",
"extraclasses": ""
}
}
],
"hascms": true,
"showmovehere": true,
"movingstr": "Moving this activity: folder example",
"cancelcopyurl": "#",
"movetosectionurl": "#",
"strmovefull": "Move 'folder example' to this location"
}
}}
{{#showmovehere}}
<p>{{movingstr}} (<a href="{{{cancelcopyurl}}}">{{#str}} cancel {{/str}}</a>)</p>
{{/showmovehere}}
{{#hascms}}
<ul class="section img-text">
{{#cms}}
{{#showmovehere}}
<li class="movehere">
<a href="{{{moveurl}}}" title="{{strmovefull}}" class="movehere"></a>
</li>
{{/showmovehere}}
{{#cmitem}}
{{> core_course/local/section_format/cmitem}}
{{/cmitem}}
{{/cms}}
{{#showmovehere}}
<li class="movehere">
<a href="{{{movetosectionurl}}}" title="{{strmovefull}}" class="movehere"></a>
</li>
{{/showmovehere}}
</ul>
{{/hascms}}

View File

@ -0,0 +1,44 @@
{{!
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/local/section_format/cmsummary
Displays the activities summary of a section.
Example context (json):
{
"mods": [
{
"name": "Forums",
"count": "3"
},
{
"name": "Books",
"count": "2"
}
],
"modprogress": "Total 5"
}
}}
<div class="section-summary-activities pr-2 mdl-right">
{{#mods}}
<span class="activity-count">{{name}}: {{count}}</span>
{{/mods}}
</div>
<div class="section-summary-activities pr-2 mdl-right">
<span class="activity-count">{{modprogress}}</span>
</div>

View File

@ -0,0 +1,32 @@
{{!
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/local/section_format/controlmenu
Displays a section control menu (dropdown menu).
Example context (json):
{
"menu": "<a href=\"#\" class=\"d-inline-block dropdown-toggle icon-no-margin\">Edit<b class=\"caret\"></b></a>",
"hasmenu": true
}
}}
{{#hasmenu}}
<div class="section_action_menu" data-sectionid="{{id}}">
{{{menu}}}
</div>
{{/hasmenu}}

View File

@ -0,0 +1,37 @@
{{!
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/local/section_format/header
Displays a course section header.
Example context (json):
{
"name": "Section title",
"url": "#",
"ishidden": true
}
}}
<h3 class="sectionid-{{id}}-title sectionname">
{{#url}}
<a href="{{{url}}}" class="{{#ishidden}} dimmed_text {{/ishidden}}">{{name}}</a>
{{/url}}
{{^url}}
<span>{{{title}}}</span>
{{/url}}
</h3>

View File

@ -0,0 +1,31 @@
{{!
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/local/section_format/summary
Displays the course section summary.
Example context (json):
{
"summarytext": "Summary text!"
}
}}
{{#summarytext}}
<div class="summarytext">
{{{summarytext}}}
</div>
{{/summarytext}}

View File

@ -17,18 +17,18 @@ Feature: Course paged mode
And I am on "Course 1" course homepage
And I click on <section1> "link" in the <section1> "section"
And I should see <section1> in the "div.single-section" "css_element"
And I should see <section2> in the ".single-section span.mdl-right" "css_element"
And I should see <section2> in the ".single-section div.nextsection" "css_element"
And I should not see <prevunexistingsection> in the ".single-section" "css_element"
And I click on <section2> "link" in the ".single-section" "css_element"
And I should see <section2> in the "div.single-section" "css_element"
And I should see <section1> in the ".single-section span.mdl-left" "css_element"
And I should see <section3> in the ".single-section span.mdl-right" "css_element"
And I should see <section1> in the ".single-section div.prevsection" "css_element"
And I should see <section3> in the ".single-section div.nextsection" "css_element"
And I click on <section1> "link" in the ".single-section" "css_element"
And I should see <section1> in the "div.single-section" "css_element"
And I click on <section2> "link" in the ".single-section" "css_element"
And I click on <section3> "link" in the ".single-section" "css_element"
And I should see <section3> in the "div.single-section" "css_element"
And I should see <section2> in the ".single-section span.mdl-left" "css_element"
And I should see <section2> in the ".single-section div.prevsection" "css_element"
And I should not see <section1> in the ".single-section .section-navigation" "css_element"
And I should not see <prevunexistingsection> in the ".single-section" "css_element"
And I should not see <nextunexistingsection> in the ".single-section" "css_element"
@ -47,13 +47,13 @@ Feature: Course paged mode
And I am on "Course 1" course homepage with editing mode on
And I click on <section1> "link" in the <section1> "section"
And I should see <section1> in the "div.single-section" "css_element"
And I should see <section2> in the ".single-section span.mdl-right" "css_element"
And I should see <section2> in the ".single-section div.nextsection" "css_element"
And I should not see <prevunexistingsection> in the ".single-section" "css_element"
When I add a "Chat" to section "1" and I fill the form with:
| Name of this chat room | Chat room |
| Description | Chat description |
Then I should see <section1> in the "div.single-section" "css_element"
And I should see <section2> in the ".single-section span.mdl-right" "css_element"
And I should see <section2> in the ".single-section div.nextsection" "css_element"
And I should not see <prevunexistingsection> in the ".single-section" "css_element"
Examples:
@ -73,18 +73,18 @@ Feature: Course paged mode
And I am on "Course 1" course homepage
And I click on <section1> "link" in the <section1> "section"
And I should see <section1> in the "div.single-section" "css_element"
And I should see <section2> in the ".single-section span.mdl-right" "css_element"
And I should see <section2> in the ".single-section div.nextsection" "css_element"
And I should not see <prevunexistingsection> in the ".single-section" "css_element"
And I click on <section2> "link" in the ".single-section" "css_element"
And I should see <section2> in the "div.single-section" "css_element"
And I should see <section1> in the ".single-section span.mdl-left" "css_element"
And I should see <section3> in the ".single-section span.mdl-right" "css_element"
And I should see <section1> in the ".single-section div.prevsection" "css_element"
And I should see <section3> in the ".single-section div.nextsection" "css_element"
And I click on <section1> "link" in the ".single-section" "css_element"
And I should see <section1> in the "div.single-section" "css_element"
And I click on <section2> "link" in the ".single-section" "css_element"
And I click on <section3> "link" in the ".single-section" "css_element"
And I should see <section3> in the "div.single-section" "css_element"
And I should see <section2> in the ".single-section span.mdl-left" "css_element"
And I should see <section2> in the ".single-section div.prevsection" "css_element"
And I should not see <section1> in the ".single-section .section-navigation" "css_element"
And I should not see <prevunexistingsection> in the ".single-section" "css_element"
And I should not see <nextunexistingsection> in the ".single-section" "css_element"

View File

@ -210,7 +210,7 @@ class core_course_courseformat_testcase extends advanced_testcase {
* @copyright 2016 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_testformat extends format_base {
class format_testformat extends core_course\course_format {
/**
* Returns the list of blocks to be automatically added for the newly created course.
*
@ -232,7 +232,7 @@ class format_testformat extends format_base {
* @copyright 2016 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_testlegacy extends format_base {
class format_testlegacy extends core_course\course_format {
/**
* Returns the list of blocks to be automatically added for the newly created course.
*

View File

@ -14,10 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/course/format/lib.php');
/**
* Fixture for fake course format testing course format API.
*
@ -25,7 +21,7 @@ require_once($CFG->dirroot . '/course/format/lib.php');
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_theunittest extends format_base {
class format_theunittest extends core_course\course_format {
/**
* Definitions of the additional options that format uses

View File

@ -1,6 +1,49 @@
This files describes API changes in /course/*,
information provided here is intended especially for developers.
=== 4.0 ===
* The format_base is now deprecated. Use core_course\course_format instead.
* The new course output components deprecate many renderer methods from course
renderer and course format renderer:
- output\course_format: to render the general course structure
- output\section_format: to render a section
- output\cm_format: to render an activity card inside a section
- output\course_format\*: to render parts of the course structure
- output\section_format\*: to render parts of the course section
* The previous format renderer page_title method has been moved to course_format::page_title
* New format renderer methods to interact with the new output components:
- render: override the default templatable mustache location for the new course components.
- course_section_updated_cm_item: used when the course editor needs to update a cm item HTML.
- render_course_format: contrib formats should override this method to change the default template.
* The following methods are adapted to use outputs but with a deprecation warning and should not be used anymore:
- print_single_section_page (replaced by output\course_format)
- print_multiple_section_page (replaced by output\course_format)
- course_activity_clipboard (integrated in replaced by output\course_format)
- format_summary_text (replaced by output\section_format\summay)
- change_number_sections (replaced by output\course_format\addsection)
- course_section_cm_list_item (replaced by output\section_format\cmitem)
- course_section_cm (replaced by output\cm_format)
- course_section_cm_list (replaced by output\section_format\cmlist)
- section_edit_control_menu (replaced by output\section_format\controlmenu)
- section_right_content (integrated in output\section_format)
- section_left_content (integrated in output\section_format)
- section_header (replaced by output\section_format\header)
- section_footer (integrated in output\section_format)
- section_edit_control_items (replaced by output\section_format\controlmenu)
- section_summary (replaced by output\section_format\summary)
- section_activity_summary (replaced by output\section_format\cmsummary)
- section_availability_message (integrated in output\section_format\availability)
- section_availability (replaced by output\section_format\availability)
- get_nav_links (replaced by output\course_format\sectionnavigation)
- stealth_section_header (replaced by output\section_format\header)
- stealth_section_footer (integrated in by output\section_format)
- section_nav_selection (replaced by output\course_format\sectionselector)
* The following abstract methods are deleted:
- start_section_list (integrated in output\course_format)
- end_section_list (integrated in output\course_format)
- page_title (moved to output\course_format)
=== 3.11 ===
* A new callback xxx_coursemodule_definition_after_data that allows plugins to extend activity forms after the data is set.

View File

@ -4492,7 +4492,7 @@ class admin_setting_sitesetselect extends admin_setting_configselect {
if ($SITE->id == $COURSE->id) {
$COURSE = $SITE;
}
format_base::reset_course_cache($SITE->id);
core_course\course_format::reset_course_cache($SITE->id);
return '';
@ -4703,7 +4703,7 @@ class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
if ($SITE->id == $COURSE->id) {
$COURSE = $SITE;
}
format_base::reset_course_cache($SITE->id);
core_course\course_format::reset_course_cache($SITE->id);
return '';
}
@ -4785,7 +4785,7 @@ class admin_setting_sitesettext extends admin_setting_configtext {
if ($SITE->id == $COURSE->id) {
$COURSE = $SITE;
}
format_base::reset_course_cache($SITE->id);
core_course\course_format::reset_course_cache($SITE->id);
return '';
}
@ -4837,7 +4837,7 @@ class admin_setting_special_frontpagedesc extends admin_setting_confightmleditor
if ($SITE->id == $COURSE->id) {
$COURSE = $SITE;
}
format_base::reset_course_cache($SITE->id);
core_course\course_format::reset_course_cache($SITE->id);
return '';
}

View File

@ -411,10 +411,7 @@ class behat_util extends testing_util {
filter_manager::reset_caches();
// Reset course and module caches.
if (class_exists('format_base')) {
// If file containing class is not loaded, there is no cache there anyway.
format_base::reset_course_cache(0);
}
core_course\course_format::reset_course_cache(0);
get_fast_modinfo(0, 0, true);
// Inform data generator.

View File

@ -42,4 +42,5 @@ $renamedclasses = array(
'core\\analytics\\target\\course_completion' => 'core_course\\analytics\\target\\course_completion',
'core\\analytics\\target\\course_gradetopass' => 'core_course\\analytics\\target\\course_gradetopass',
'core\\analytics\\target\\no_teaching' => 'core_course\\analytics\\target\\no_teaching',
'format_base' => 'core_course\\course_format',
);

View File

@ -918,7 +918,8 @@ function textlib_get_instance() {
* @deprecated since 2.4
*/
function get_generic_section_name() {
throw new coding_exception('get_generic_section_name() is deprecated. Please use appropriate functionality from class format_base');
throw new coding_exception('get_generic_section_name() is deprecated. Please use appropriate functionality '
.'from class core_course\\course_format');
}
/**
@ -988,8 +989,8 @@ function make_editing_buttons() {
* @deprecated since 2.5
*/
function print_section() {
throw new coding_exception('Function print_section() is removed. Please use course renderer function '.
'course_section_cm_list() instead.');
throw new coding_exception('Function print_section() is removed. Please use core_course\output\section_format '.
' to render a course section instead.');
}
/**

View File

@ -2357,10 +2357,7 @@ function rebuild_course_cache($courseid=0, $clearonly=false) {
// Destroy navigation caches
navigation_cache::destroy_volatile_caches();
if (class_exists('format_base')) {
// if file containing class is not loaded, there is no cache there anyway
format_base::reset_course_cache($courseid);
}
core_course\course_format::reset_course_cache($courseid);
$cachecoursemodinfo = cache::make('core', 'coursemodinfo');
if (empty($courseid)) {

View File

@ -5011,9 +5011,7 @@ function delete_course($courseorid, $showfeedback = true) {
$DB->delete_records("course_format_options", array("courseid" => $courseid));
// Reset all course related caches here.
if (class_exists('format_base', false)) {
format_base::reset_course_cache($courseid);
}
core_course\course_format::reset_course_cache($courseid);
// Tell search that we have deleted the course so it can delete course data from the index.
\core_search\manager::course_deleting_finish($courseid);

View File

@ -2005,11 +2005,11 @@ class global_navigation extends navigation_node {
* Loads all of the courses section into the navigation.
*
* This function calls method from current course format, see
* {@link format_base::extend_course_navigation()}
* core_course\course_format::extend_course_navigation()
* If course module ($cm) is specified but course format failed to create the node,
* the activity node is created anyway.
*
* By default course formats call the method {@link global_navigation::load_generic_course_sections()}
* By default course formats call the method global_navigation::load_generic_course_sections()
*
* @param stdClass $course Database record for the course
* @param navigation_node $coursenode The course node within the navigation

View File

@ -240,10 +240,7 @@ class phpunit_util extends testing_util {
//TODO MDL-25290: add more resets here and probably refactor them to new core function
// Reset course and module caches.
if (class_exists('format_base')) {
// If file containing class is not loaded, there is no cache there anyway.
format_base::reset_course_cache(0);
}
core_course\course_format::reset_course_cache(0);
get_fast_modinfo(0, 0, true);
// Reset other singletons.