Merge branch 'MDL-80248-main' of https://github.com/sarjona/moodle

This commit is contained in:
Jun Pataleta 2024-01-22 15:24:12 +08:00
commit e7a947846d
No known key found for this signature in database
GPG Key ID: F83510526D99E2C7
55 changed files with 534 additions and 240 deletions

View File

@ -108,7 +108,7 @@ abstract class base extends area_base {
*/
public static function get_edit_url(\stdClass $componentinfo): \moodle_url {
if ($componentinfo->tablename == 'course_sections') {
return new \moodle_url('/course/editsection.php', ['id' => $componentinfo->itemid, 'sr' => '']);
return new \moodle_url('/course/editsection.php', ['id' => $componentinfo->itemid]);
} else if ($componentinfo->tablename == 'course_categories') {
return new \moodle_url('/course/editcategory.php', ['id' => $componentinfo->itemid]);
} else {

View File

@ -108,6 +108,6 @@ abstract class module_area_base extends area_base {
* @return \moodle_url
*/
public static function get_edit_url(\stdClass $componentinfo): \moodle_url {
return new \moodle_url('/course/mod.php', ['update' => $componentinfo->cmid, 'sr' => 0, 'sesskey' => sesskey()]);
return new \moodle_url('/course/mod.php', ['update' => $componentinfo->cmid, 'sr' => null, 'sesskey' => sesskey()]);
}
}

View File

@ -121,7 +121,7 @@ Feature: Confirm that availability_completion works with previous activity setti
Then I should see "Not available unless: The activity Page2 is marked complete" in the "region-main" "region"
# Remove Page 2 and check Section 4 depends now on Page1.
When I turn editing mode on
When I am on "Course 1" course homepage with editing mode on
And I change window size to "large"
And I delete "Page2" activity
And I turn editing mode off
@ -175,11 +175,11 @@ Feature: Confirm that availability_completion works with previous activity setti
And I press "Save changes"
Then I should see "Not available unless: The previous activity with completion" in the "region-main" "region"
When I turn editing mode off
Then I should see "Not available unless: The activity Page1 is marked complete" in the "region-main" "region"
And I turn editing mode off
And I should see "Not available unless: The activity Page1 is marked complete" in the "region-main" "region"
# Set section 5 restriction to Previous Activity with completion.
When I turn editing mode on
And I am on "Course 1" course homepage with editing mode on
And I edit the section "5"
And I expand all fieldsets
And I click on "Add restriction..." "button"
@ -187,18 +187,18 @@ Feature: Confirm that availability_completion works with previous activity setti
And I click on "Displayed if student doesn't meet this condition Click to hide" "link"
And I set the field "Activity or resource" to "Previous activity with completion"
And I press "Save changes"
Then I should see "Not available unless: The previous activity with completion" in the "region-main" "region"
And I should see "Not available unless: The previous activity with completion" in the "region-main" "region"
When I turn editing mode off
And I turn editing mode off
Then I should see "Not available unless: The activity Page3 is marked complete" in the "region-main" "region"
# Test if I disable completion tracking on Page3 section 5 depends on Page2.
When I turn editing mode on
And I am on "Course 1" course homepage with editing mode on
And I open "Page3" actions menu
And I click on "Edit settings" "link" in the "Page3" activity
And I set the following fields to these values:
| None | 1 |
And I press "Save and return to course"
When I turn editing mode off
Then I should see "Not available unless: The activity Page2 is marked complete" in the "region-main" "region"
And I turn editing mode off
And I should see "Not available unless: The activity Page2 is marked complete" in the "region-main" "region"

View File

@ -126,7 +126,8 @@ Feature: display_availability
And I press "Save changes"
# Section 2 is the same but hidden from students
When I edit the section "2"
And I am on "Course 1" course homepage
And I edit the section "2"
And I expand all fieldsets
And I press "Add restriction..."
And I click on "Date" "button" in the "Add restriction..." "dialogue"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -335,7 +335,7 @@ define(
methodname: 'core_course_edit_module',
args: {id: cmid,
action: action,
sectionreturn: target.attr('data-sectionreturn') ? target.attr('data-sectionreturn') : 0
sectionreturn: target.attr('data-sectionreturn') ? target.attr('data-sectionreturn') : null
}
}], true);
@ -694,7 +694,7 @@ define(
*/
var editSection = function(sectionElement, sectionid, target, courseformat) {
var action = target.attr('data-action'),
sectionreturn = target.attr('data-sectionreturn') ? target.attr('data-sectionreturn') : 0;
sectionreturn = target.attr('data-sectionreturn') ? target.attr('data-sectionreturn') : null;
// Filter direct component handled actions.
if (courseeditor.supportComponents && componentActions.includes(action)) {

View File

@ -197,7 +197,10 @@ const sectionIdMapper = (webServiceData, id, sectionreturnid, beforemod) => {
// We need to take a fresh deep copy of the original data as an object is a reference type.
const newData = JSON.parse(JSON.stringify(webServiceData));
newData.content_items.forEach((module) => {
module.link += '&section=' + id + '&sr=' + (sectionreturnid ?? 0) + '&beforemod=' + (beforemod ?? 0);
module.link += '&section=' + id + '&beforemod=' + (beforemod ?? 0);
if (sectionreturnid) {
module.link += '&sr=' + sectionreturnid;
}
});
return newData.content_items;
};

View File

@ -28,11 +28,16 @@ require_once("lib.php");
require_once($CFG->libdir . '/formslib.php');
$id = required_param('id', PARAM_INT); // course_sections.id
$sectionreturn = optional_param('sr', 0, PARAM_INT);
$sectionreturn = optional_param('sr', null, PARAM_INT);
$deletesection = optional_param('delete', 0, PARAM_BOOL);
$showonly = optional_param('showonly', 0, PARAM_TAGLIST);
$params = ['id' => $id, 'sr' => $sectionreturn];
$returnparams = [];
$params = ['id' => $id];
if (!is_null($sectionreturn)) {
$params['sr'] = $sectionreturn;
$returnparams['sr'] = $sectionreturn;
}
if (!empty($showonly)) {
$params['showonly'] = $showonly;
}
@ -51,7 +56,7 @@ $sectioninfo = get_fast_modinfo($course)->get_section_info($sectionnum);
// Deleting the section.
if ($deletesection) {
$cancelurl = course_get_url($course, $sectioninfo, array('sr' => $sectionreturn));
$cancelurl = course_get_url($course, $sectioninfo, $returnparams);
if (course_can_delete_section($course, $sectioninfo)) {
$confirm = optional_param('confirm', false, PARAM_BOOL) && confirm_sesskey();
if (!$confirm && optional_param('sesskey', null, PARAM_RAW) !== null &&
@ -61,7 +66,7 @@ if ($deletesection) {
}
if ($confirm) {
course_delete_section($course, $sectioninfo, true, true);
$courseurl = course_get_url($course, $sectioninfo->section - 1, array('sr' => $sectionreturn));
$courseurl = course_get_url($course, $sectioninfo->section - 1, $returnparams);
redirect($courseurl);
} else {
if (get_string_manager()->string_exists('deletesection', 'format_' . $course->format)) {
@ -123,7 +128,7 @@ if (!empty($showonly)) {
if ($mform->is_cancelled()){
// Form cancelled, return to course.
redirect(course_get_url($course, $section, array('sr' => $sectionreturn)));
redirect(course_get_url($course, $section, $returnparams));
} else if ($data = $mform->get_data()) {
// Data submitted and validated, update and return to course.
@ -139,7 +144,7 @@ if ($mform->is_cancelled()){
course_update_section($course, $section, $data);
$PAGE->navigation->clear_cache();
redirect(course_get_url($course, $section, array('sr' => $sectionreturn)));
redirect(course_get_url($course, $section, $returnparams));
}
// The edit form is displayed for the first time or if there was validation error on the previous step.

View File

@ -3639,8 +3639,8 @@ class core_course_external extends external_api {
$coursecontext = context_course::instance($course->id);
self::validate_context($modcontext);
$format = course_get_format($course);
if ($sectionreturn) {
$format->set_section_number($sectionreturn);
if (!is_null($sectionreturn)) {
$format->set_sectionnum($sectionreturn);
}
$renderer = $format->get_renderer($PAGE);
@ -3767,8 +3767,8 @@ class core_course_external extends external_api {
self::validate_context(context_course::instance($course->id));
$format = course_get_format($course);
if ($sectionreturn) {
$format->set_section_number($sectionreturn);
if (!is_null($sectionreturn)) {
$format->set_sectionnum($sectionreturn);
}
$renderer = $format->get_renderer($PAGE);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6,6 +6,6 @@ define("core_courseformat/local/content/section",["exports","core_courseformat/l
* @class core_courseformat/local/content/section
* @copyright 2021 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_header=_interopRequireDefault(_header),_dndsection=_interopRequireDefault(_dndsection),_templates=_interopRequireDefault(_templates);class _default extends _dndsection.default{create(){this.name="content_section",this.selectors={SECTION_ITEM:"[data-for='section_title']",CM:'[data-for="cmitem"]',SECTIONINFO:'[data-for="sectioninfo"]',SECTIONBADGES:'[data-region="sectionbadges"]',SHOWSECTION:'[data-action="sectionShow"]',HIDESECTION:'[data-action="sectionHide"]',ACTIONTEXT:".menu-action-text",ICON:".icon"},this.classes={LOCKED:"editinprogress",HASDESCRIPTION:"description",HIDE:"d-none",HIDDEN:"hidden",CURRENT:"current"},this.id=this.element.dataset.id}stateReady(state){if(this.configState(state),this.reactive.isEditing&&this.reactive.supportComponents){const sectionItem=this.getElement(this.selectors.SECTION_ITEM);if(sectionItem){const headerComponent=new _header.default({...this,element:sectionItem,fullregion:this.element});this.configDragDrop(headerComponent)}}}getWatchers(){return[{watch:"section[".concat(this.id,"]:updated"),handler:this._refreshSection}]}validateDropData(dropdata){return("section"!==(null==dropdata?void 0:dropdata.type)||0==this.reactive.sectionReturn)&&super.validateDropData(dropdata)}getLastCm(){const cms=this.getElements(this.selectors.CM);return cms&&0!==cms.length?cms[cms.length-1]:null}_refreshSection(_ref){var _element$dragging,_element$locked,_element$visible,_element$current;let{element:element}=_ref;this.element.classList.toggle(this.classes.DRAGGING,null!==(_element$dragging=element.dragging)&&void 0!==_element$dragging&&_element$dragging),this.element.classList.toggle(this.classes.LOCKED,null!==(_element$locked=element.locked)&&void 0!==_element$locked&&_element$locked),this.element.classList.toggle(this.classes.HIDDEN,null!==(_element$visible=!element.visible)&&void 0!==_element$visible&&_element$visible),this.element.classList.toggle(this.classes.CURRENT,null!==(_element$current=element.current)&&void 0!==_element$current&&_element$current),this.locked=element.locked;const sectioninfo=this.getElement(this.selectors.SECTIONINFO);sectioninfo&&sectioninfo.classList.toggle(this.classes.HASDESCRIPTION,element.hasrestrictions),this._updateBadges(element),this._updateActionsMenu(element)}_updateBadges(section){const current=this.getElement("".concat(this.selectors.SECTIONBADGES," [data-type='iscurrent']"));null==current||current.classList.toggle(this.classes.HIDE,!section.current);const hiddenFromStudents=this.getElement("".concat(this.selectors.SECTIONBADGES," [data-type='hiddenfromstudents']"));null==hiddenFromStudents||hiddenFromStudents.classList.toggle(this.classes.HIDE,section.visible)}async _updateActionsMenu(section){var _affectedAction$datas,_affectedAction$datas2;let selector,newAction;section.visible?(selector=this.selectors.SHOWSECTION,newAction="sectionHide"):(selector=this.selectors.HIDESECTION,newAction="sectionShow");const affectedAction=this.getElement(selector);if(!affectedAction)return;affectedAction.dataset.action=newAction;const actionText=affectedAction.querySelector(this.selectors.ACTIONTEXT);if(null!==(_affectedAction$datas=affectedAction.dataset)&&void 0!==_affectedAction$datas&&_affectedAction$datas.swapname&&actionText){const oldText=null==actionText?void 0:actionText.innerText;actionText.innerText=affectedAction.dataset.swapname,affectedAction.dataset.swapname=oldText}const icon=affectedAction.querySelector(this.selectors.ICON);if(null!==(_affectedAction$datas2=affectedAction.dataset)&&void 0!==_affectedAction$datas2&&_affectedAction$datas2.swapicon&&icon){const newIcon=affectedAction.dataset.swapicon;if(newIcon){const pixHtml=await _templates.default.renderPix(newIcon,"core");_templates.default.replaceNode(icon,pixHtml,"")}}}}return _exports.default=_default,_exports.default}));
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_header=_interopRequireDefault(_header),_dndsection=_interopRequireDefault(_dndsection),_templates=_interopRequireDefault(_templates);class _default extends _dndsection.default{create(){this.name="content_section",this.selectors={SECTION_ITEM:"[data-for='section_title']",CM:'[data-for="cmitem"]',SECTIONINFO:'[data-for="sectioninfo"]',SECTIONBADGES:'[data-region="sectionbadges"]',SHOWSECTION:'[data-action="sectionShow"]',HIDESECTION:'[data-action="sectionHide"]',ACTIONTEXT:".menu-action-text",ICON:".icon"},this.classes={LOCKED:"editinprogress",HASDESCRIPTION:"description",HIDE:"d-none",HIDDEN:"hidden",CURRENT:"current"},this.id=this.element.dataset.id}stateReady(state){if(this.configState(state),this.reactive.isEditing&&this.reactive.supportComponents){const sectionItem=this.getElement(this.selectors.SECTION_ITEM);if(sectionItem){const headerComponent=new _header.default({...this,element:sectionItem,fullregion:this.element});this.configDragDrop(headerComponent)}}}getWatchers(){return[{watch:"section[".concat(this.id,"]:updated"),handler:this._refreshSection}]}validateDropData(dropdata){return("section"!==(null==dropdata?void 0:dropdata.type)||null===this.reactive.sectionReturn)&&super.validateDropData(dropdata)}getLastCm(){const cms=this.getElements(this.selectors.CM);return cms&&0!==cms.length?cms[cms.length-1]:null}_refreshSection(_ref){var _element$dragging,_element$locked,_element$visible,_element$current;let{element:element}=_ref;this.element.classList.toggle(this.classes.DRAGGING,null!==(_element$dragging=element.dragging)&&void 0!==_element$dragging&&_element$dragging),this.element.classList.toggle(this.classes.LOCKED,null!==(_element$locked=element.locked)&&void 0!==_element$locked&&_element$locked),this.element.classList.toggle(this.classes.HIDDEN,null!==(_element$visible=!element.visible)&&void 0!==_element$visible&&_element$visible),this.element.classList.toggle(this.classes.CURRENT,null!==(_element$current=element.current)&&void 0!==_element$current&&_element$current),this.locked=element.locked;const sectioninfo=this.getElement(this.selectors.SECTIONINFO);sectioninfo&&sectioninfo.classList.toggle(this.classes.HASDESCRIPTION,element.hasrestrictions),this._updateBadges(element),this._updateActionsMenu(element)}_updateBadges(section){const current=this.getElement("".concat(this.selectors.SECTIONBADGES," [data-type='iscurrent']"));null==current||current.classList.toggle(this.classes.HIDE,!section.current);const hiddenFromStudents=this.getElement("".concat(this.selectors.SECTIONBADGES," [data-type='hiddenfromstudents']"));null==hiddenFromStudents||hiddenFromStudents.classList.toggle(this.classes.HIDE,section.visible)}async _updateActionsMenu(section){var _affectedAction$datas,_affectedAction$datas2;let selector,newAction;section.visible?(selector=this.selectors.SHOWSECTION,newAction="sectionHide"):(selector=this.selectors.HIDESECTION,newAction="sectionShow");const affectedAction=this.getElement(selector);if(!affectedAction)return;affectedAction.dataset.action=newAction;const actionText=affectedAction.querySelector(this.selectors.ACTIONTEXT);if(null!==(_affectedAction$datas=affectedAction.dataset)&&void 0!==_affectedAction$datas&&_affectedAction$datas.swapname&&actionText){const oldText=null==actionText?void 0:actionText.innerText;actionText.innerText=affectedAction.dataset.swapname,affectedAction.dataset.swapname=oldText}const icon=affectedAction.querySelector(this.selectors.ICON);if(null!==(_affectedAction$datas2=affectedAction.dataset)&&void 0!==_affectedAction$datas2&&_affectedAction$datas2.swapicon&&icon){const newIcon=affectedAction.dataset.swapicon;if(newIcon){const pixHtml=await _templates.default.renderPix(newIcon,"core");_templates.default.replaceNode(icon,pixHtml,"")}}}}return _exports.default=_default,_exports.default}));
//# sourceMappingURL=section.min.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -76,7 +76,7 @@ export default class Component extends BaseComponent {
this.sections = {};
this.cms = {};
// The page section return.
this.sectionReturn = descriptor.sectionReturn ?? 0;
this.sectionReturn = descriptor.sectionReturn ?? null;
this.debouncedReloads = new Map();
}
@ -433,7 +433,7 @@ export default class Component extends BaseComponent {
*/
_refreshCourseSectionlist({element}) {
// If we have a section return means we only show a single section so no need to fix order.
if (this.reactive.sectionReturn != 0) {
if (this.reactive.sectionReturn !== null) {
return;
}
const sectionlist = element.sectionlist ?? [];
@ -541,7 +541,7 @@ export default class Component extends BaseComponent {
{
id: cmId,
courseid: Config.courseId,
sr: this.reactive.sectionReturn ?? 0,
sr: this.reactive.sectionReturn ?? null,
}
);
promise.then((html, js) => {
@ -608,7 +608,7 @@ export default class Component extends BaseComponent {
{
id: element.id,
courseid: Config.courseId,
sr: this.reactive.sectionReturn ?? 0,
sr: this.reactive.sectionReturn ?? null,
}
);
promise.then((html, js) => {

View File

@ -100,7 +100,7 @@ export default class extends DndSection {
*/
validateDropData(dropdata) {
// If the format uses one section per page sections dropping in the content is ignored.
if (dropdata?.type === 'section' && this.reactive.sectionReturn != 0) {
if (dropdata?.type === 'section' && this.reactive.sectionReturn !== null) {
return false;
}
return super.validateDropData(dropdata);

View File

@ -52,9 +52,9 @@ export default class extends Reactive {
* The current page section return
* @attribute sectionReturn
* @type number
* @default 0
* @default null
*/
sectionReturn = 0;
sectionReturn = null;
/**
* Set up the course editor when the page is ready.

View File

@ -37,7 +37,6 @@ use moodle_exception;
use coding_exception;
use moodle_url;
use lang_string;
use completion_info;
use core_external\external_api;
use stdClass;
use cache;
@ -78,8 +77,10 @@ abstract class base {
protected $course = false;
/** @var array caches format options, please use course_format::get_format_options() */
protected $formatoptions = array();
/** @var int the section number in single section format, zero for multiple section formats. */
protected $singlesection = 0;
/** @var int|null the section number in single section format, null for multiple section formats. */
protected $singlesection = null;
/** @var int|null the sectionid when a single section is selected, null when multiple sections are displayed. */
protected $singlesectionid = null;
/** @var course_modinfo the current course modinfo, please use course_format::get_modinfo() */
private $modinfo = null;
/** @var array cached instances */
@ -560,15 +561,99 @@ abstract class base {
return get_string('highlighted');
}
/**
* Set if the current format instance will show multiple sections or an individual one.
*
* Some formats has the hability to swith from one section to multiple sections per page.
*
* @param int|null $sectionid null for all sections or a sectionid.
*/
public function set_sectionid(?int $sectionid): void {
if ($sectionid === null) {
$this->singlesection = null;
$this->singlesectionid = null;
return;
}
$modinfo = get_fast_modinfo($this->courseid);
$sectioninfo = $modinfo->get_section_info_by_id($sectionid);
if ($sectioninfo === null) {
throw new coding_exception('Invalid sectionid: '. $sectionid);
}
$this->singlesection = $sectioninfo->section;
$this->singlesectionid = $sectionid;
}
/**
* Get if the current format instance will show multiple sections or an individual one.
*
* Some formats has the hability to swith from one section to multiple sections per page,
* output components will use this method to know if the current display is a single or
* multiple sections.
*
* @return int|null null for all sections or the sectionid.
*/
public function get_sectionid(): ?int {
return $this->singlesectionid;
}
/**
* Set if the current format instance will show multiple sections or an individual one.
*
* Some formats has the hability to swith from one section to multiple sections per page.
*
* @param int $singlesection zero for all sections or a section number
* @deprecated Since 4.4. Use set_sectionnum instead.
* @todo MDL-80116 This will be deleted in Moodle 4.8.
*/
public function set_section_number(int $singlesection): void {
$this->singlesection = $singlesection;
debugging(
'The method core_courseformat\base::set_section_number() has been deprecated, please use set_sectionnum() instead.',
DEBUG_DEVELOPER
);
if ($singlesection === 0) {
// Convert zero to null, to guarantee all the sections are displayed.
$singlesection = null;
}
$this->set_sectionnum($singlesection);
}
/**
* Set the current section number to display.
* Some formats has the hability to swith from one section to multiple sections per page.
*
* @since Moodle 4.4
* @param int|null $sectionnum null for all sections or a sectionid.
*/
public function set_sectionnum(?int $sectionnum): void {
if ($sectionnum === null) {
$this->singlesection = null;
$this->singlesectionid = null;
return;
}
$modinfo = get_fast_modinfo($this->courseid);
$sectioninfo = $modinfo->get_section_info($sectionnum);
if ($sectioninfo === null) {
throw new coding_exception('Invalid sectionnum: '. $sectionnum);
}
$this->singlesection = $sectionnum;
$this->singlesectionid = $sectioninfo->id;
}
/**
* Get the current section number to display.
* Some formats has the hability to swith from one section to multiple sections per page.
*
* @since Moodle 4.4
* @return int|null the current section number or null when there is no single section.
*/
public function get_sectionnum(): ?int {
return $this->singlesection;
}
/**
@ -579,8 +664,21 @@ abstract class base {
* multiple sections.
*
* @return int zero for all sections or the sectin number
* @deprecated Since 4.4. Use get_sectionnum instead.
* @todo MDL-80116 This will be deleted in Moodle 4.8.
*/
public function get_section_number(): int {
debugging(
'The method core_courseformat\base::get_section_number() has been deprecated, please use get_sectionnum() instead.',
DEBUG_DEVELOPER
);
if ($this->singlesection === null) {
// Convert null to zero, to guarantee all the sections are displayed.
return 0;
}
return $this->singlesection;
}
@ -773,7 +871,9 @@ abstract class base {
'/course/mod.php',
['sesskey' => sesskey(), $nonajaxaction => $cm->id]
);
$nonajaxurl->param('sr', $this->get_section_number());
if (!is_null($this->get_sectionid())) {
$nonajaxurl->param('sr', $this->get_sectionnum());
}
return $nonajaxurl;
}
@ -1807,8 +1907,8 @@ abstract class base {
$section = $modinfo->get_section_info($section->section);
}
if ($sr) {
$this->set_section_number($sr);
if (!is_null($sr)) {
$this->set_sectionnum($sr);
}
switch($action) {

View File

@ -94,14 +94,14 @@ class content implements named_templatable, renderable {
'initialsection' => $initialsection,
'sections' => $sections,
'format' => $format->get_format(),
'sectionreturn' => 0,
'sectionreturn' => null,
];
// The single section format has extra navigation.
$singlesection = $this->format->get_section_number();
if ($singlesection) {
if ($this->format->get_sectionid()) {
$singlesectionnum = $this->format->get_sectionnum();
if (!$PAGE->theme->usescourseindex) {
$sectionnavigation = new $this->sectionnavigationclass($format, $singlesection);
$sectionnavigation = new $this->sectionnavigationclass($format, $singlesectionnum);
$data->sectionnavigation = $sectionnavigation->export_for_template($output);
$sectionselector = new $this->sectionselectorclass($format, $sectionnavigation);
@ -109,7 +109,7 @@ class content implements named_templatable, renderable {
}
$data->hasnavigation = true;
$data->singlesection = array_shift($data->sections);
$data->sectionreturn = $singlesection;
$data->sectionreturn = $singlesectionnum;
}
if ($this->hasaddsection) {
@ -181,10 +181,10 @@ class content implements named_templatable, renderable {
* @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) {
$singlesectionid = $this->format->get_sectionid();
if ($singlesectionid) {
return [
$modinfo->get_section_info($singlesection),
$modinfo->get_section_info_by_id($singlesectionid),
];
}

View File

@ -153,7 +153,7 @@ class addsection implements named_templatable, renderable {
$params = ['courseid' => $course->id, 'insertsection' => 0, 'sesskey' => sesskey()];
$singlesection = $this->format->get_section_number();
$singlesection = $this->format->get_sectionnum();
if ($singlesection) {
$params['sectionreturn'] = $singlesection;
}

View File

@ -159,7 +159,7 @@ class bulkedittools implements named_templatable, renderable {
global $USER;
$format = $this->format;
$context = $format->get_context();
$sectionreturn = $format->get_section_number();
$sectionreturn = $format->get_sectionnum();
$user = $USER;
$controls = [];

View File

@ -310,7 +310,7 @@ class cm implements named_templatable, renderable {
if (!$this->format->show_editor($editcaps)) {
return false;
}
$returnsection = $this->format->get_section_number();
$returnsection = $this->format->get_sectionnum();
// Edit actions.
$controlmenu = new $this->controlmenuclass(
$this->format,

View File

@ -161,7 +161,7 @@ class controlmenu implements named_templatable, renderable {
protected function cm_control_items() {
$format = $this->format;
$mod = $this->mod;
$sectionreturn = $format->get_section_number();
$sectionreturn = $format->get_sectionnum();
if (!empty($this->displayoptions['disableindentation']) || !$format->uses_indentation()) {
$indent = -1;
} else {

View File

@ -142,13 +142,13 @@ class section implements named_templatable, renderable {
$data = (object)[
'num' => $section->section ?? '0',
'id' => $section->id,
'sectionreturnid' => $format->get_section_number(),
'sectionreturnid' => $format->get_sectionnum(),
'insertafter' => false,
'summary' => $summary->export_for_template($output),
'highlightedlabel' => $format->get_section_highlighted_name(),
'sitehome' => $course->id == SITEID,
'editing' => $PAGE->user_is_editing(),
'displayonesection' => ($course->id != SITEID && $format->get_section_number() !== 0),
'displayonesection' => ($course->id != SITEID && !is_null($format->get_sectionid())),
];
$haspartials = [];
@ -181,7 +181,7 @@ class section implements named_templatable, renderable {
$headerdata = $header->export_for_template($output);
// When a section is displayed alone the title goes over the section, not inside it.
if ($section->section != 0 && $section->section == $format->get_section_number()) {
if ($section->section != 0 && $section->section == $format->get_sectionnum()) {
$data->singleheader = $headerdata;
} else {
$data->header = $headerdata;
@ -203,7 +203,7 @@ class section implements named_templatable, renderable {
$format = $this->format;
$showsummary = ($section->section != 0 &&
$section->section != $format->get_section_number() &&
$section->section != $format->get_sectionnum() &&
$format->get_course_display() == COURSE_DISPLAY_MULTIPAGE &&
!$format->show_editor()
);
@ -302,7 +302,7 @@ class section implements named_templatable, renderable {
$data->cmcontrols = $output->course_section_add_cm_control(
$course,
$this->section->section,
$this->format->get_section_number()
$this->format->get_sectionnum()
);
}
return true;

View File

@ -124,7 +124,7 @@ class controlmenu implements named_templatable, renderable {
$format = $this->format;
$section = $this->section;
$course = $format->get_course();
$sectionreturn = $format->get_section_number();
$sectionreturn = !is_null($format->get_sectionid()) ? $format->get_sectionnum() : null;
$user = $USER;
$usecomponents = $format->supports_components();
@ -144,15 +144,16 @@ class controlmenu implements named_templatable, renderable {
];
if (!$isstealth && has_capability('moodle/course:update', $coursecontext, $user)) {
if ($section->section > 0
&& get_string_manager()->string_exists('editsection', 'format_'.$format->get_format())) {
$params = ['id' => $section->id];
$params['sr'] = $section->section;
if (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'] = [
'url' => new moodle_url('/course/editsection.php', ['id' => $section->id, 'sr' => $sectionreturn]),
'url' => new moodle_url('/course/editsection.php', $params),
'icon' => 'i/settings',
'name' => $streditsection,
'pixattr' => ['class' => ''],
@ -162,6 +163,9 @@ class controlmenu implements named_templatable, renderable {
$duplicatesectionurl = clone($baseurl);
$duplicatesectionurl->param('section', $section->section);
$duplicatesectionurl->param('duplicatesection', $section->section);
if (!is_null($sectionreturn)) {
$duplicatesectionurl->param('sr', $sectionreturn);
}
$controls['duplicate'] = [
'url' => $duplicatesectionurl,
'icon' => 't/copy',
@ -267,14 +271,17 @@ class controlmenu implements named_templatable, renderable {
} else {
$strdelete = get_string('deletesection');
}
$params = [
'id' => $section->id,
'delete' => 1,
'sesskey' => sesskey(),
];
if (!is_null($sectionreturn)) {
$params['sr'] = $sectionreturn;
}
$url = new moodle_url(
'/course/editsection.php',
[
'id' => $section->id,
'sr' => $sectionreturn,
'delete' => 1,
'sesskey' => sesskey(),
]
$params,
);
$controls['delete'] = [
'url' => $url,

View File

@ -82,7 +82,7 @@ class header implements named_templatable, renderable {
$data->title = $output->section_title_without_link($section, $course);
$data->sitehome = true;
} else {
if ($format->get_section_number() === 0) {
if (is_null($format->get_sectionid())) {
// All sections are displayed.
if (!$data->editing) {
$data->title = $output->section_title($section, $course);
@ -114,7 +114,7 @@ class header implements named_templatable, renderable {
$data->name = get_section_name($course, $section);
$data->selecttext = $format->get_format_string('selectsection', $data->name);
if (!$format->get_section_number()) {
if (!$format->get_sectionnum()) {
$data->sectionbulk = true;
}

View File

@ -94,7 +94,7 @@ class sectionnavigation implements named_templatable, renderable {
];
$back = $this->sectionno - 1;
while ($back > 0 and empty($data->previousurl)) {
while ($back >= 0 && empty($data->previousurl)) {
if ($canviewhidden || $sections[$back]->uservisible) {
if (!$sections[$back]->visible) {
$data->previoushidden = true;

View File

@ -131,7 +131,7 @@ class format_site extends course_format {
*
* @return int
*/
public function get_section_number(): int {
public function get_sectionnum(): int {
return 1;
}
}
@ -219,8 +219,8 @@ function core_courseformat_output_fragment_cmitem($args): string {
}
$format = course_get_format($course);
if (!empty($args['sr'])) {
$format->set_section_number($args['sr']);
if (!is_null($args['sr'])) {
$format->set_sectionnum($args['sr']);
}
$renderer = $format->get_renderer($PAGE);
$section = $cm->get_section_info();
@ -246,8 +246,8 @@ function core_courseformat_output_fragment_section($args): string {
}
$format = course_get_format($course);
if (!empty($args['sr'])) {
$format->set_section_number($args['sr']);
if (!is_null($args['sr'])) {
$format->set_sectionnum($args['sr']);
}
$modinfo = $format->get_modinfo();

View File

@ -106,19 +106,21 @@
{{/ core_courseformat/local/content/section/badges }}
</div>
{{#collapsemenu}}
<div class="flex-fill d-flex justify-content-end mr-2 align-self-start mt-2">
<a
id="collapsesections"
class="section-collapsemenu"
href="#"
aria-expanded="true"
role="button"
data-toggle="toggleall"
>
<span class="collapseall text-nowrap">{{#str}}collapseall{{/str}}</span>
<span class="expandall text-nowrap">{{#str}}expandall{{/str}}</span>
</a>
{{^displayonesection}}
<div class="flex-fill d-flex justify-content-end mr-2 align-self-start mt-2">
<a
id="collapsesections"
class="section-collapsemenu"
href="#"
aria-expanded="true"
role="button"
data-toggle="toggleall"
>
<span class="collapseall text-nowrap">{{#str}}collapseall{{/str}}</span>
<span class="expandall text-nowrap">{{#str}}expandall{{/str}}</span>
</a>
</div>
{{/displayonesection}}
{{/collapsemenu}}
{{#controlmenu}}
{{$ core_courseformat/local/content/section/controlmenu }}

View File

@ -770,6 +770,109 @@ class base_test extends advanced_testcase {
$format = course_get_format($course);
$this->assertEmpty($format->get_required_jsfiles());
}
/**
* Test set_sectionid().
*
* @covers ::set_sectionid
* @covers ::get_sectionid
* @covers ::get_sectionnum
*/
public function test_set_sectionid(): void {
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$course = $generator->create_course(['numsections' => 2]);
$format = course_get_format($course);
// No section.
$this->assertNull($format->get_sectionid());
$this->assertNull($format->get_sectionnum());
// Valid section.
$sectionnum = 1;
$modinfo = get_fast_modinfo($course);
$sectioninfo = $modinfo->get_section_info($sectionnum);
$sectionid = $sectioninfo->id;
$format->set_sectionid($sectionid);
$this->assertEquals($sectionid, $format->get_sectionid());
$this->assertEquals($sectionnum, $format->get_sectionnum());
// Null section.
$format->set_sectionid(null);
$this->assertNull($format->get_sectionid());
$this->assertNull($format->get_sectionnum());
// Invalid section.
$this->expectException(\coding_exception::class);
$format->set_sectionid(-1);
}
/**
* Test set_sectionnum().
*
* @dataProvider set_sectionnum_provider
* @covers ::set_sectionnum
* @param int|null $sectionnum The section number
* @param bool $nullexpected If null is expected
* @param bool $exceptionexpected If an exception is expected
*/
public function test_set_sectionnum(?int $sectionnum, bool $nullexpected = false, bool $exceptionexpected = false): void {
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$course = $generator->create_course(['numsections' => 2]);
$format = course_get_format($course);
if ($exceptionexpected) {
$this->expectException(\coding_exception::class);
}
$format->set_sectionnum($sectionnum);
if ($nullexpected) {
$this->assertNull($format->get_sectionid());
$this->assertNull($format->get_sectionnum());
} else {
$this->assertNotNull($format->get_sectionid());
$this->assertNotNull($format->get_sectionnum());
}
}
/**
* Data provider for test_set_sectionnum.
*
* @return array The testing scenarios
*/
public static function set_sectionnum_provider(): array {
return [
'General sectionnumber' => [
'sectionnum' => 0,
'nullexpected' => false,
],
'Existing sectionnumber' => [
'sectionnum' => 1,
'nullexpected' => false,
],
'Another existing sectionnumber' => [
'sectionnum' => 2,
'nullexpected' => false,
],
'Null sectionnumber' => [
'sectionnum' => null,
'nullexpected' => true,
],
'Invalid sectionnumber' => [
'sectionnum' => 3,
'nullexpected' => true,
'exceptionexpected' => true,
],
'Another invalid sectionnumber' => [
'sectionnum' => -1,
'nullexpected' => true,
'exceptionexpected' => true,
],
];
}
}
/**

View File

@ -39,7 +39,7 @@ Feature: Single section course page
Scenario: General section is not displayed in the single section page
When I click on "Topic 1" "link" in the "region-main" "region"
Then I should not see "General" in the "region-main" "region"
Then I should not see "General" in the "#section-1" "css_element"
And I should not see "Activity sample 0.1" in the "region-main" "region"
And I should see "Activity sample 1.1"
And I should see "Activity sample 1.2"
@ -52,7 +52,7 @@ Feature: Single section course page
Given I turn editing mode on
And I open section "1" edit menu
When I click on "View" "link" in the "Topic 1" "section"
Then I should not see "General" in the "region-main" "region"
Then I should not see "General" in the "#section-1" "css_element"
And I should not see "Activity sample 0.1" in the "region-main" "region"
And I should see "Activity sample 1.1"
And I should see "Activity sample 1.2"
@ -62,21 +62,21 @@ Feature: Single section course page
And I am on "Course 1" course homepage
And I open section "2" edit menu
And I click on "View" "link" in the "Topic 2" "section"
And I should not see "General" in the "region-main" "region"
And I should not see "General" in the "#section-2" "css_element"
And I should not see "Activity sample 0.1" in the "region-main" "region"
And I should not see "Activity sample 1.1"
And I should not see "Activity sample 1.2"
And I should not see "Activity sample 1.3"
And I should see "Activity sample 2.1" in the "region-main" "region"
And I should see "Activity sample 2.1" in the "region-main" "region"
# The following steps will need to be changed in MDL-80248, when the General section will be displayed in isolation.
# The General section is also displayed in isolation.
But I am on "Course 1" course homepage
And I open section "0" edit menu
And I click on "View" "link" in the "General" "section"
And I should see "General" in the "region-main" "region"
And I should see "Activity sample 0.1" in the "region-main" "region"
And I should see "Activity sample 1.1"
And I should see "Activity sample 1.2"
And I should see "Activity sample 1.3"
And I should see "Activity sample 2.1" in the "region-main" "region"
And I should see "Activity sample 2.1" in the "region-main" "region"
And I should not see "Activity sample 1.1" in the "region-main" "region"
And I should not see "Activity sample 1.2" in the "region-main" "region"
And I should not see "Activity sample 1.3" in the "region-main" "region"
And I should not see "Activity sample 2.1" in the "region-main" "region"
And I should not see "Activity sample 2.1" in the "region-main" "region"

View File

@ -45,7 +45,7 @@ class section extends section_base {
$data = parent::export_for_template($output);
if (!$this->format->get_section_number()) {
if (!$this->format->get_sectionnum()) {
$addsectionclass = $format->get_output_classname('content\\addsection');
$addsection = new $addsectionclass($format);
$data->numsections = $addsection->export_for_template($output);

View File

@ -90,7 +90,7 @@ class controlmenu extends controlmenu_base {
$format = $this->format;
$section = $this->section;
$course = $format->get_course();
$sectionreturn = $format->get_section_number();
$sectionreturn = $format->get_sectionnum();
if ($sectionreturn) {
$url = course_get_url($course, $section->section);

View File

@ -52,8 +52,8 @@ course_create_sections_if_missing($course, 0);
$renderer = $PAGE->get_renderer('format_topics');
if (!empty($displaysection)) {
$format->set_section_number($displaysection);
if (!is_null($displaysection)) {
$format->set_sectionnum($displaysection);
}
$outputclass = $format->get_output_classname('content');
$widget = new $outputclass($format);

View File

@ -114,7 +114,7 @@ class format_topics extends core_courseformat\base {
*/
public function get_view_url($section, $options = []) {
$course = $this->get_course();
if (array_key_exists('sr', $options)) {
if (array_key_exists('sr', $options) && !is_null($options['sr'])) {
$sectionno = $options['sr'];
} else if (is_object($section)) {
$sectionno = $section->section;

View File

@ -47,6 +47,9 @@ always linked because a new page, section.php, has been created to display any s
- course/format/topics/renderer.php
- course/format/weeks/renderer.php
* New core_courseformat\sectiondelegate class. The class can be extended by plugins to take control of a course section.
* The methods core_courseformat\base::set_section_number() and core_courseformat\base:: get_section_number() have been deprecated
and replaced by core_courseformat\base::set_sectionnum() and core_courseformat\base::get_sectionnum(). The new methods use the null
value when all the sections must be displayed (instead of 0). That way, section 0 (General), can be displayed on a single page too.
=== 4.3 ===
* New core_courseformat\output\activitybadge class that can be extended by any module to display content near the activity name.

View File

@ -44,8 +44,8 @@ course_create_sections_if_missing($format->get_course(), 0);
$renderer = $PAGE->get_renderer('format_weeks');
if (!empty($displaysection)) {
$format->set_section_number($displaysection);
if (!is_null($displaysection)) {
$format->set_sectionnum($displaysection);
}
$outputclass = $format->get_output_classname('content');

View File

@ -124,7 +124,7 @@ class format_weeks extends core_courseformat\base {
*/
public function get_view_url($section, $options = array()) {
$course = $this->get_course();
if (array_key_exists('sr', $options)) {
if (array_key_exists('sr', $options) && !is_null($options['sr'])) {
$sectionno = $options['sr'];
} else if (is_object($section)) {
$sectionno = $section->section;

View File

@ -51,7 +51,15 @@ foreach (compact('indent','update','hide','show','copy','moveto','movetosection'
$url->param($key, $value);
}
}
$url->param('sr', $sectionreturn);
// Force it to be null if it's not a valid section number.
if ($sectionreturn < 0) {
$sectionreturn = null;
}
$urloptions = [];
if (!is_null($sectionreturn)) {
$url->param('sr', $sectionreturn);
$urloptions['sr'] = $sectionreturn;
}
if ($add !== '') {
$url->param('add', $add);
}
@ -73,26 +81,42 @@ if (!empty($add)) {
$returntomod = optional_param('return', 0, PARAM_BOOL);
$beforemod = optional_param('beforemod', 0, PARAM_INT);
$params = [
'add' => $add,
'type' => $type,
'course' => $id,
'section' => $section,
'return' => $returntomod,
'beforemod' => $beforemod,
];
if (!is_null($sectionreturn)) {
$params['sr'] = $sectionreturn;
}
redirect(
new moodle_url(
'/course/modedit.php',
[
'add' => $add,
'type' => $type,
'course' => $id,
'section' => $section,
'return' => $returntomod,
'sr' => $sectionreturn,
'beforemod' => $beforemod,
]
$params,
)
);
} else if (!empty($update)) {
$cm = get_coursemodule_from_id('', $update, 0, true, MUST_EXIST);
$returntomod = optional_param('return', 0, PARAM_BOOL);
redirect("$CFG->wwwroot/course/modedit.php?update=$update&return=$returntomod&sr=$sectionreturn");
$params = [
'update' => $update,
'return' => $returntomod,
];
if (!is_null($sectionreturn)) {
$params['sr'] = $sectionreturn;
}
redirect(
new moodle_url(
'/course/modedit.php',
$params,
)
);
} else if (!empty($duplicate) and confirm_sesskey()) {
$cm = get_coursemodule_from_id('', $duplicate, 0, true, MUST_EXIST);
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
@ -101,9 +125,9 @@ if (!empty($add)) {
$modcontext = context_module::instance($cm->id);
require_capability('moodle/course:manageactivities', $modcontext);
// Duplicate the module.
$newcm = duplicate_module($course, $cm);
redirect(course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)));
// Duplicate the module.
$newcm = duplicate_module($course, $cm);
redirect(course_get_url($course, $cm->sectionnum, $urloptions));
} else if (!empty($delete)) {
$cm = get_coursemodule_from_id('', $delete, 0, true, MUST_EXIST);
@ -113,13 +137,19 @@ if (!empty($add)) {
$modcontext = context_module::instance($cm->id);
require_capability('moodle/course:manageactivities', $modcontext);
$return = course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn));
$return = course_get_url($course, $cm->sectionnum, $urloptions);
if (!$confirm or !confirm_sesskey()) {
$fullmodulename = get_string('modulename', $cm->modname);
$optionsyes = array('confirm'=>1, 'delete'=>$cm->id, 'sesskey'=>sesskey(), 'sr' => $sectionreturn);
$optionsyes = [
'confirm' => 1,
'delete' => $cm->id,
'sesskey' => sesskey(),
];
if (!is_null($sectionreturn)) {
$optionsyes['sr'] = $sectionreturn;
}
$strdeletecheck = get_string('deletecheck', '', $fullmodulename);
$strparams = (object)array('type' => $fullmodulename, 'name' => $cm->name);
$strdeletechecktypename = get_string('deletechecktypename', '', $strparams);
@ -183,7 +213,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
unset($USER->activitycopyname);
unset($USER->activitycopysectionreturn);
redirect(course_get_url($course, $section->section, array('sr' => $sectionreturn)));
redirect(course_get_url($course, $section->section, $urloptions));
} else if (!empty($indent) and confirm_sesskey()) {
$id = required_param('id', PARAM_INT);
@ -208,7 +238,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
// Rebuild invalidated module cache.
rebuild_course_cache($cm->course, false, true);
redirect(course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)));
redirect(course_get_url($course, $cm->sectionnum, $urloptions));
} else if (!empty($hide) and confirm_sesskey()) {
$cm = get_coursemodule_from_id('', $hide, 0, true, MUST_EXIST);
@ -222,7 +252,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
if (set_coursemodule_visible($cm->id, 0)) {
\core\event\course_module_updated::create_from_cm($cm, $modcontext)->trigger();
}
redirect(course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)));
redirect(course_get_url($course, $cm->sectionnum, $urloptions));
} else if (!empty($stealth) and confirm_sesskey()) {
list($course, $cm) = get_course_and_cm_from_cmid($stealth);
@ -243,7 +273,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
if (set_coursemodule_visible($cm->id, 1)) {
\core\event\course_module_updated::create_from_cm($cm)->trigger();
}
redirect(course_get_url($course, $section->section, array('sr' => $sectionreturn)));
redirect(course_get_url($course, $section->section, $urloptions));
} else if ($groupmode > -1 and confirm_sesskey()) {
$id = required_param('id', PARAM_INT);
@ -258,7 +288,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
set_coursemodule_groupmode($cm->id, $groupmode);
\core\event\course_module_updated::create_from_cm($cm, $modcontext)->trigger();
redirect(course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)));
redirect(course_get_url($course, $cm->sectionnum, $urloptions));
} else if (!empty($copy) and confirm_sesskey()) { // value = course module
$cm = get_coursemodule_from_id('', $copy, 0, true, MUST_EXIST);
@ -276,7 +306,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
$USER->activitycopyname = $cm->name;
$USER->activitycopysectionreturn = $sectionreturn;
redirect(course_get_url($course, $section->section, array('sr' => $sectionreturn)));
redirect(course_get_url($course, $section->section, $urloptions));
} else if (!empty($cancelcopy) and confirm_sesskey()) { // value = course module
@ -289,7 +319,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
unset($USER->activitycopycourse);
unset($USER->activitycopyname);
unset($USER->activitycopysectionreturn);
redirect(course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)));
redirect(course_get_url($course, $cm->sectionnum, $urloptions));
} else {
throw new \moodle_exception('unknowaction');
}

View File

@ -39,8 +39,15 @@ $sectionreturn = optional_param('sr', null, PARAM_INT);
$beforemod = optional_param('beforemod', 0, PARAM_INT);
$showonly = optional_param('showonly', '', PARAM_TAGLIST); // Settings group to show expanded and hide the rest.
// Force it to be null if it's not a valid section number.
if ($sectionreturn < 0) {
$sectionreturn = null;
}
$url = new moodle_url('/course/modedit.php');
$url->param('sr', $sectionreturn);
if (!is_null($sectionreturn)) {
$url->param('sr', $sectionreturn);
}
if (!empty($return)) {
$url->param('return', $return);
}
@ -76,7 +83,9 @@ if (!empty($add)) {
list($module, $context, $cw, $cm, $data) = prepare_new_moduleinfo_data($course, $add, $section);
$data->return = 0;
$data->sr = $sectionreturn;
if (!is_null($sectionreturn)) {
$data->sr = $sectionreturn;
}
$data->add = $add;
$data->beforemod = $beforemod;
if (!empty($type)) { //TODO: hopefully will be removed in 2.0
@ -115,7 +124,9 @@ if (!empty($add)) {
list($cm, $context, $module, $data, $cw) = get_moduleinfo_data($cm, $course);
$data->return = $return;
$data->sr = $sectionreturn;
if (!is_null($sectionreturn)) {
$data->sr = $sectionreturn;
}
$data->update = $update;
if (!empty($showonly)) {
$data->showonly = $showonly;
@ -173,7 +184,11 @@ if ($mform->is_cancelled()) {
$activityurl = new moodle_url("/mod/$module->name/view.php", $urlparams);
redirect($activityurl);
} else {
redirect(course_get_url($course, $cw->section, array('sr' => $sectionreturn)));
$options = [];
if (!is_null($sectionreturn)) {
$options['sr'] = $sectionreturn;
}
redirect(course_get_url($course, $cw->section, $options));
}
} else if ($fromform = $mform->get_data()) {
// Mark that this is happening in the front-end UI. This is used to indicate that we are able to
@ -193,7 +208,11 @@ if ($mform->is_cancelled()) {
$url = $fromform->gradingman->get_management_url($url);
}
} else {
$url = course_get_url($course, $cw->section, array('sr' => $sectionreturn));
$options = [];
if (!is_null($sectionreturn)) {
$options['sr'] = $sectionreturn;
}
$url = course_get_url($course, $cw->section, $options);
}
// If we need to regrade the course with a progress bar as a result of updating this module,

View File

@ -868,7 +868,9 @@ abstract class moodleform_mod extends moodleform {
$mform->addElement('hidden', 'return', 0);
$mform->setType('return', PARAM_BOOL);
$mform->addElement('hidden', 'sr', 0);
// The section number where to return: -1 means no section (0 can't be used because it is a valid section number and
// null can't be used because it's converted to 0).
$mform->addElement('hidden', 'sr', -1);
$mform->setType('sr', PARAM_INT);
$mform->addElement('hidden', 'beforemod', 0);

View File

@ -168,7 +168,7 @@ echo $renderer->container_start('course-content');
// Include course AJAX.
include_course_ajax($course, $modinfo->get_used_module_names());
$format->set_section_number($section->section);
$format->set_sectionid($section->id);
$outputclass = $format->get_output_classname('content');
$widget = new $outputclass($format);
echo $renderer->render($widget);

View File

@ -30,7 +30,9 @@
}
}}
<button class="btn btn-link text-decoration-none section-modchooser section-modchooser-link activity-add bulk-hidden d-flex align-items-center p-3 mb-5"
data-action="open-chooser" data-sectionid="{{sectionid}}" data-sectionreturnid="{{sectionreturn}}">
data-action="open-chooser"
data-sectionid="{{sectionid}}"
{{#sectionreturn}}data-sectionreturnid="{{.}}"{{/sectionreturn}}>
<span class="pluscontainer icon-no-margin icon-size-3 d-flex p-2 mr-2">
{{#pix}} t/add, core {{/pix}}
</span>

View File

@ -32,6 +32,11 @@
}
}}
<button class="btn btn-link text-decoration-none section-modchooser section-modchooser-link activity-add d-flex align-items-center activitychooser-button"
data-action="open-chooser" data-sectionid="{{num}}" data-sectionreturnid="{{sectionreturn}}" data-beforemod="{{id}}" aria-label="{{#str}}insertresourceoractivitybefore, core, { "activityname": {{#quote}} {{activityname}} {{/quote}} } {{/str}}" tabindex="0">
data-action="open-chooser"
data-sectionid="{{num}}"
{{#sectionreturn}}data-sectionreturnid="{{.}}"{{/sectionreturn}}
data-beforemod="{{id}}"
aria-label="{{#str}}insertresourceoractivitybefore, core, { "activityname": {{#quote}} {{activityname}} {{/quote}} } {{/str}}"
tabindex="0">
{{#pix}} t/add, core {{/pix}}
</button>

View File

@ -52,6 +52,7 @@ Feature: Activity navigation
# Hidden activity.
And I click on "Hide" "link" in the "Glossary 1" activity
# Hidden section.
And I am on "Course 1" course homepage
And I hide section "5"
# Set up book.
And I follow "Book 1"

View File

@ -400,7 +400,7 @@ class behat_course extends behat_base {
// We need to know the course format as the text strings depends on them.
$courseformat = $this->get_course_format();
if ($sectionnumber > 0 && get_string_manager()->string_exists('editsection', $courseformat)) {
if (get_string_manager()->string_exists('editsection', $courseformat)) {
$stredit = get_string('editsection', $courseformat);
} else {
$stredit = get_string('editsection');

View File

@ -32,18 +32,18 @@ Feature: Collapse course sections
| teacher1 | C1 | editingteacher |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
When I edit the section "4"
And I hide section "5"
And I edit the section "4"
And I expand all fieldsets
And I press "Add restriction..."
And I click on "Date" "button" in the "Add restriction..." "dialogue"
And I set the field "direction" to "until"
And I set the field "x[year]" to "2013"
And I press "Save changes"
And I hide section "5"
@javascript
Scenario: No chevron on site home
Given the following activity" exists:
Given the following "activity" exists:
| activity | forum |
| course | Acceptance test site |
| section | 1 |

View File

@ -18,18 +18,19 @@ Feature: Course activity controls works as expected
@javascript @_cross_browser
Scenario Outline: Check activities using topics and weeks formats, and paged mode and not paged mode
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | format | coursedisplay | numsections | startdate |
| Course 1 | C1 | <courseformat> | <coursedisplay> | 5 | 0 |
| fullname | shortname | format | coursedisplay | numsections | startdate |
| Course 1 | C1 | <courseformat> | <coursedisplay> | 5 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | course | section | name |
| forum | C1 | 1 | Test forum name 1 |
| forum | C1 | 1 | Test forum name 2 |
| activity | course | section | name |
| forum | C1 | <targetsectionnum> | Test forum name 1 |
| forum | C1 | <targetsectionnum> | Test forum name 2 |
| forum | C1 | 1 | Test forum name 3 |
And I am on the "Course 1" course page logged in as "teacher1"
When I click on <targetpage> "link" in the "region-main" "region"
And I turn editing mode on
@ -37,67 +38,72 @@ Feature: Course activity controls works as expected
And I open the action menu in "Recent activity" "block"
And I click on "Delete Recent activity block" "link"
And I click on "Delete" "button" in the "Delete block?" "dialogue"
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And I open "Test forum name 1" actions menu
And I click on "Edit settings" "link" in the "Test forum name 1" activity
And I should see "Updating Forum"
And I should see "Updating"
And I should see "Display description on course page"
And I set the following fields to these values:
| Forum name | Just to check that I can edit the name |
| Description | Just to check that I can edit the description |
| Display description on course page | 1 |
And I click on "Cancel" "button"
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And I open "Test forum name 1" actions menu
And I choose "Availability > Hide on course page" in the open action menu
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And I delete "Test forum name 1" activity
And I should not see "Test forum name 1" in the "region-main" "region"
And I duplicate "Test forum name 2" activity editing the new copy with:
| Forum name | Edited test forum name 2 |
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And I should see "Test forum name 2"
And I should see "Edited test forum name 2"
# General section can't be hidden. Check this part using always the first section.
And I am on the "Course 1" course page
And I open section "1" edit menu
And I click on "View" "link" in the <firstsection> "section"
And I hide section "1"
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And section "1" should be hidden
And all activities in section "1" should be hidden
And I show section "1"
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And section "1" should be visible
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Section links" block
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And I should see "1 2 3 4 5" in the "Section links" "block"
And I click on "2" "link" in the "Section links" "block"
And I <should_see_other_sections_following_block_sections_links> see "Test forum name 2"
And I should not see "Test forum name 2"
Examples:
| courseformat | coursedisplay | targetpage | should_see_other_sections | should_see_other_sections_following_block_sections_links | belowpage |
| topics | 0 | "General" | should | should not | "Topic 2" |
| topics | 1 | "General" | should | should not | "Topic 2" |
| topics | 0 | "Topic 1" | should not | should not | "Topic 2" |
| topics | 1 | "Topic 1" | should not | should not | "Topic 2" |
| weeks | 0 | "General" | should | should not | "8 January - 14 January" |
| weeks | 1 | "General" | should | should not | "8 January - 14 January" |
| weeks | 0 | "1 January - 7 January" | should not | should not | "8 January - 14 January" |
| weeks | 1 | "1 January - 7 January" | should not | should not | "8 January - 14 January" |
| courseformat | coursedisplay | targetsectionnum | targetpage | belowpage | firstsection |
| topics | 0 | 0 | "General" | "Topic 2" | "Topic 1" |
| topics | 1 | 0 | "General" | "Topic 2" | "Topic 1" |
| topics | 0 | 1 | "Topic 1" | "Topic 2" | "Topic 1" |
| topics | 1 | 1 | "Topic 1" | "Topic 2" | "Topic 1" |
| weeks | 0 | 0 | "General" | "8 January - 14 January" | "1 January - 7 January" |
| weeks | 1 | 0 | "General" | "8 January - 14 January" | "1 January - 7 January" |
| weeks | 0 | 1 | "1 January - 7 January" | "8 January - 14 January" | "1 January - 7 January" |
| weeks | 1 | 1 | "1 January - 7 January" | "8 January - 14 January" | "1 January - 7 January" |
Scenario Outline: Check, without javascript, activities using topics and weeks formats, and paged mode and not paged mode
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | format | coursedisplay | numsections | startdate |
| Course 1 | C1 | <courseformat> | <coursedisplay> | 5 | 0 |
| fullname | shortname | format | coursedisplay | numsections | startdate |
| Course 1 | C1 | <courseformat> | <coursedisplay> | 5 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber | section |
| forum | Test forum name 1 | C1 | 0001 | 1 |
| forum | Test forum name 2 | C1 | 0002 | 1 |
| activity | course | section | name | idnumber |
| forum | C1 | <targetsectionnum> | Test forum name 1 | 00001 |
| forum | C1 | <targetsectionnum> | Test forum name 2 | 00002 |
| forum | C1 | 1 | Test forum name 3 | 00003 |
And I am on the "Course 1" course page logged in as "teacher1"
When I click on <targetpage> "link" in the "region-main" "region"
And I turn editing mode on
@ -105,22 +111,27 @@ Feature: Course activity controls works as expected
And I open the action menu in "Recent activity" "block"
And I click on "Delete Recent activity block" "link"
And I press "Yes"
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And I click on "Edit settings" "link" in the "Test forum name 1" activity
And I should see "Updating Forum"
And I should see "Updating"
And I should see "Display description on course page"
And I press "Save and return to course"
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And I click on "Hide on course page" "link" in the "Test forum name 1" activity
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And I delete "Test forum name 1" activity
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And I should not see "Test forum name 1" in the "region-main" "region"
And I duplicate "Test forum name 2" activity editing the new copy with:
| Forum name | Edited test forum name 2 |
And <belowpage> "section" <should_see_other_sections> exist
And <belowpage> "section" should not exist
And I should see "Test forum name 2"
And I should see "Edited test forum name 2"
# General section can't be hidden. Check this part using always the first section.
And I am on the "Course 1" course page
And I turn editing mode off
And I click on <firstsection> "link" in the "region-main" "region"
And I turn editing mode on
And I hide section "1"
And section "1" should be hidden
And all activities in section "1" should be hidden
@ -131,18 +142,18 @@ Feature: Course activity controls works as expected
And I add the "Section links" block
And I should see "1 2 3 4 5" in the "Section links" "block"
And I click on "2" "link" in the "Section links" "block"
And I <should_see_other_sections_following_block_sections_links> see "Test forum name 2"
And I should not see "Test forum name 2"
Examples:
| courseformat | coursedisplay | targetpage | should_see_other_sections | should_see_other_sections_following_block_sections_links | belowpage |
| topics | 0 | "General" | should | should not | "Topic 2" |
| topics | 1 | "General" | should | should not | "Topic 2" |
| topics | 0 | "Topic 1" | should not | should not | "Topic 2" |
| topics | 1 | "Topic 1" | should not | should not | "Topic 2" |
| weeks | 0 | "General" | should | should not | "8 January - 14 January" |
| weeks | 1 | "General" | should | should not | "8 January - 14 January" |
| weeks | 0 | "1 January - 7 January" | should not | should not | "8 January - 14 January" |
| weeks | 1 | "1 January - 7 January" | should not | should not | "8 January - 14 January" |
| courseformat | coursedisplay | targetsectionnum | targetpage | belowpage | firstsection |
| topics | 0 | 0 | "General" | "Topic 2" | "Topic 1" |
| topics | 1 | 0 | "General" | "Topic 2" | "Topic 1" |
| topics | 0 | 1 | "Topic 1" | "Topic 2" | "Topic 1" |
| topics | 1 | 1 | "Topic 1" | "Topic 2" | "Topic 1" |
| weeks | 0 | 0 | "General" | "8 January - 14 January" | "1 January - 7 January" |
| weeks | 1 | 0 | "General" | "8 January - 14 January" | "1 January - 7 January" |
| weeks | 0 | 1 | "1 January - 7 January" | "8 January - 14 January" | "1 January - 7 January" |
| weeks | 1 | 1 | "1 January - 7 January" | "8 January - 14 January" | "1 January - 7 January" |
@javascript
Scenario Outline: Indentation should allow one level only

View File

@ -7,36 +7,32 @@ Feature: Course paged mode
@javascript @_cross_browser
Scenario Outline: Weekly and topics course formats with Javascript enabled
Given the following "courses" exist:
| fullname | shortname | category | format | coursedisplay | numsections | startdate |
| Course 1 | C1 | 0 | <courseformat> | 1 | 3 | 0 |
| fullname | shortname | category | format | coursedisplay | numsections | startdate |
| Course 1 | C1 | 0 | <courseformat> | 1 | 2 | 0 |
And I log in as "admin"
And I am on "Course 1" course homepage
Then I click on <section2> "link" in the <section2> "section"
And I am on "Course 1" course homepage
And I click on <section3> "link" in the <section3> "section"
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 div.nextsection" "css_element"
And I am on "Course 1" course homepage
And I click on <section2> "link" in the <section2> "section"
And I am on "Course 1" course homepage
When I click on <general> "link" in the <general> "section"
Then I should see <general> in the "div.single-section" "css_element"
And I should see <section1> 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 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 should see <general> in the ".single-section div.prevsection" "css_element"
And I should see <section2> in the ".single-section div.nextsection" "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 div.prevsection" "css_element"
And I should not see <section1> in the ".single-section .section-navigation" "css_element"
And I should see <section2> in the "div.single-section" "css_element"
And I should not see <general> 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"
Examples:
| courseformat | section1 | section2 | section3 | prevunexistingsection | nextunexistingsection |
| topics | "Topic 1" | "Topic 2" | "Topic 3" | "Topic 0" | "Topic 4" |
| weeks | "1 January - 7 January" | "8 January - 14 January" | "15 January - 21 January" | "25 December - 31 December" | "22 January - 28 January" |
| courseformat | general | section1 | section2 | prevunexistingsection | nextunexistingsection |
| topics | "General" | "Topic 1" | "Topic 2" | "Topic 0" | "Topic 3" |
| weeks | "General" | "1 January - 7 January" | "8 January - 14 January" | "25 December - 31 December" | "15 January - 21 January" |
@javascript
Scenario Outline: Paged section redirect after creating an activity
@ -64,33 +60,29 @@ Feature: Course paged mode
Scenario Outline: Weekly and topics course formats with Javascript disabled
Given the following "courses" exist:
| fullname | shortname | category | format | coursedisplay | numsections | startdate |
| Course 1 | C1 | 0 | <courseformat> | 1 | 3 | 0 |
| fullname | shortname | category | format | coursedisplay | numsections | startdate |
| Course 1 | C1 | 0 | <courseformat> | 1 | 2 | 0 |
And I log in as "admin"
And I am on "Course 1" course homepage
Then I click on <section2> "link" in the <section2> "section"
Then I click on <section1> "link" in the <section1> "section"
And I am on "Course 1" course homepage
And I click on <section3> "link" in the <section3> "section"
And I click on <section2> "link" in the <section2> "section"
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 div.nextsection" "css_element"
And I click on <general> "link" in the <general> "section"
And I should see <general> in the "div.single-section" "css_element"
And I should see <section1> 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 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 should see <general> in the ".single-section div.prevsection" "css_element"
And I should see <section2> in the ".single-section div.nextsection" "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 div.prevsection" "css_element"
And I should not see <section1> in the ".single-section .section-navigation" "css_element"
And I should see <section2> in the "div.single-section" "css_element"
And I should not see <general> 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"
Examples:
| courseformat | section1 | section2 | section3 | prevunexistingsection | nextunexistingsection |
| topics | "Topic 1" | "Topic 2" | "Topic 3" | "Topic 0" | "Topic 4" |
| weeks | "1 January - 7 January" | "8 January - 14 January" | "15 January - 21 January" | "25 December - 31 December" | "22 January - 28 January" |
| courseformat | general | section1 | section2 | prevunexistingsection | nextunexistingsection |
| topics | "General" | "Topic 1" | "Topic 2" | "Topic 0" | "Topic 3" |
| weeks | "General" | "1 January - 7 January" | "8 January - 14 January" | "25 December - 31 December" | "15 January - 21 January" |

View File

@ -36,7 +36,7 @@ $show = optional_param('show', 0, PARAM_INT);
$duplicatesection = optional_param('duplicatesection', 0, PARAM_INT);
$idnumber = optional_param('idnumber', '', PARAM_RAW);
$sectionid = optional_param('sectionid', 0, PARAM_INT);
$section = optional_param('section', 0, PARAM_INT);
$section = optional_param('section', null, PARAM_INT);
$expandsection = optional_param('expandsection', -1, PARAM_INT);
$move = optional_param('move', 0, PARAM_INT);
$marker = optional_param('marker', -1 , PARAM_INT);
@ -62,7 +62,7 @@ $urlparams = ['id' => $course->id];
if ($sectionid) {
$section = $DB->get_field('course_sections', 'section', ['id' => $sectionid, 'course' => $course->id], MUST_EXIST);
}
if ($section) {
if (!is_null($section)) {
$urlparams['section'] = $section;
}
if ($expandsection !== -1) {

View File

@ -2379,8 +2379,16 @@ function lti_get_configured_types($courseid, $sectionreturn = 0) {
}
$type->icon = html_writer::empty_tag('img', ['src' => $iconurl, 'alt' => '', 'class' => "icon $iconclass"]);
$type->link = new moodle_url('/course/modedit.php', array('add' => 'lti', 'return' => 0, 'course' => $courseid,
'sr' => $sectionreturn, 'typeid' => $ltitype->id));
$params = [
'add' => 'lti',
'return' => 0,
'course' => $courseid,
'typeid' => $ltitype->id,
];
if (!is_null($sectionreturn)) {
$params['sr'] = $sectionreturn;
}
$type->link = new moodle_url('/course/modedit.php', $params);
$types[] = $type;
}
return $types;