MDL-76993 core_course: Recover move right/left functionality

This is a backport of MDL-76990
This commit is contained in:
Amaia Anabitarte 2023-02-08 17:04:04 +01:00
parent f8e2445513
commit 3a38791d62
27 changed files with 245 additions and 37 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -60,7 +60,7 @@ define(
// Meanwhile, we filter the migrated actions.
const componentActions = [
'moveSection', 'moveCm', 'addSection', 'deleteSection', 'sectionHide', 'sectionShow',
'cmHide', 'cmShow', 'cmStealth',
'cmHide', 'cmShow', 'cmStealth', 'cmMoveRight', 'cmMoveLeft',
];
// The course reactive instance.

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -221,6 +221,7 @@ export default class Component extends BaseComponent {
// State changes that require to reload some course modules.
{watch: `cm.visible:updated`, handler: this._reloadCm},
{watch: `cm.stealth:updated`, handler: this._reloadCm},
{watch: `cm.indent:updated`, handler: this._reloadCm},
// Update section number and title.
{watch: `section.number:updated`, handler: this._refreshSectionNumber},
// Collapse and expand sections.

View File

@ -50,6 +50,8 @@ const directMutations = {
cmHide: 'cmHide',
cmShow: 'cmShow',
cmStealth: 'cmStealth',
cmMoveRight: 'cmMoveRight',
cmMoveLeft: 'cmMoveLeft',
};
export default class extends BaseComponent {

View File

@ -282,6 +282,24 @@ export default class {
this._setElementsValue(stateManager, 'cm', cmIds, 'completionstate', newValue);
}
/**
* Move cms to the right: indent = 1.
* @param {StateManager} stateManager the current state manager
* @param {array} cmIds the list of cm ids
*/
async cmMoveRight(stateManager, cmIds) {
await this._cmBasicAction(stateManager, 'cm_moveright', cmIds);
}
/**
* Move cms to the left: indent = 0.
* @param {StateManager} stateManager the current state manager
* @param {array} cmIds the list of cm ids
*/
async cmMoveLeft(stateManager, cmIds) {
await this._cmBasicAction(stateManager, 'cm_moveleft', cmIds);
}
/**
* Lock or unlock course modules.
*

View File

@ -456,14 +456,6 @@ abstract class base {
/**
* Returns true if this course format uses activity indentation.
*
* Indentation is not supported by core formats anymore and may be deprecated in the future.
* This method will keep a default return "true" for legacy reasons but new formats should override
* it with a return false to prevent future deprecations.
*
* A message in a bottle: if indentation is finally deprecated, both behat steps i_indent_right_activity
* and i_indent_left_activity should be removed as well. Right now no core behat uses them but indentation
* is not officially deprecated so they are still available for the contrib formats.
*
* @return bool if the course format uses indentation.
*/
public function uses_indentation(): bool {

View File

@ -106,6 +106,7 @@ class cmitem implements named_templatable, renderable {
'extraclasses' => $mod->extraclasses,
'cmformat' => $item->export_for_template($output),
'hasinfo' => $hasinfo,
'indent' => $mod->indent,
];
}
}

View File

@ -90,6 +90,7 @@ class cm implements renderable {
'sectionnumber' => $section->section,
'uservisible' => $cm->uservisible,
'hascmrestrictions' => $this->get_has_restrictions(),
'indent' => $cm->indent,
];
// Check the user access type to this cm.

View File

@ -422,6 +422,79 @@ class stateactions {
}
}
/**
* Move course cms to the right. Indent = 1.
*
* @param stateupdates $updates the affected course elements track
* @param stdClass $course the course object
* @param int[] $ids cm ids
* @param int $targetsectionid not used
* @param int $targetcmid not used
*/
public function cm_moveright(
stateupdates $updates,
stdClass $course,
array $ids = [],
?int $targetsectionid = null,
?int $targetcmid = null
): void {
$this->set_cm_indentation($updates, $course, $ids, 1);
}
/**
* Move course cms to the left. Indent = 0.
*
* @param stateupdates $updates the affected course elements track
* @param stdClass $course the course object
* @param int[] $ids cm ids
* @param int $targetsectionid not used
* @param int $targetcmid not used
*/
public function cm_moveleft(
stateupdates $updates,
stdClass $course,
array $ids = [],
?int $targetsectionid = null,
?int $targetcmid = null
): void {
$this->set_cm_indentation($updates, $course, $ids, 0);
}
/**
* Internal method to define the cm indentation level.
*
* @param stateupdates $updates the affected course elements track
* @param stdClass $course the course object
* @param int[] $ids cm ids
* @param int $indent new value for indentation
*/
protected function set_cm_indentation(
stateupdates $updates,
stdClass $course,
array $ids,
int $indent
): void {
global $DB;
$this->validate_cms($course, $ids, __FUNCTION__);
// Check capabilities on every activity context.
foreach ($ids as $cmid) {
$modcontext = context_module::instance($cmid);
require_capability('moodle/course:manageactivities', $modcontext);
}
$modinfo = get_fast_modinfo($course);
$cms = $this->get_cm_info($modinfo, $ids);
list($insql, $inparams) = $DB->get_in_or_equal(array_keys($cms), SQL_PARAMS_NAMED);
$DB->set_field_select('course_modules', 'indent', $indent, "id $insql", $inparams);
rebuild_course_cache($course->id, false, true);
foreach ($cms as $cm) {
$modcontext = context_module::instance($cm->id);
course_module_updated::create_from_cm($cm, $modcontext)->trigger();
$updates->add_cm_put($cm->id);
}
}
/**
* Extract several cm_info from the course_modinfo.
*

View File

@ -53,7 +53,8 @@
}
]
},
"modstealth": true
"modstealth": true,
"indent": 1
}
}}
<div class="activity-item {{#modstealth}}hiddenactivity{{/modstealth}}{{!

View File

@ -34,11 +34,12 @@
"id": 3,
"anchor": "module-3",
"module": "forum",
"extraclasses": "newmessages"
"extraclasses": "newmessages",
"indent": 0
}
}}
<li
class="activity activity-wrapper {{module}} modtype_{{module}} {{extraclasses}} {{#hasinfo}}hasinfo{{/hasinfo}}"
class="activity activity-wrapper {{module}} modtype_{{module}} {{extraclasses}} {{#hasinfo}}hasinfo{{/hasinfo}} {{#indent}}indented{{/indent}}"
id="{{anchor}}"
data-for="cmitem"
data-id="{{id}}"

View File

@ -870,4 +870,58 @@ class stateactions_test extends \advanced_testcase {
],
];
}
/**
* Test for cm_moveright
*
* @covers ::cm_moveright
* @dataProvider basic_role_provider
* @param string $role the user role
* @param bool $expectedexception if it will expect an exception.
*/
public function test_cm_moveright(
string $role = 'editingteacher',
bool $expectedexception = false
): void {
$this->basic_state_text(
'cm_moveright',
$role,
['cm0', 'cm1', 'cm2', 'cm3'],
$expectedexception,
4,
null,
null,
null,
null,
'indent',
1
);
}
/**
* Test for cm_moveleft
*
* @covers ::cm_moveleft
* @dataProvider basic_role_provider
* @param string $role the user role
* @param bool $expectedexception if it will expect an exception.
*/
public function test_cm_moveleft(
string $role = 'editingteacher',
bool $expectedexception = false
): void {
$this->basic_state_text(
'cm_moveleft',
$role,
['cm0', 'cm1', 'cm2', 'cm3'],
$expectedexception,
4,
null,
null,
null,
null,
'indent',
0
);
}
}

View File

@ -50,10 +50,6 @@ class format_topics extends core_courseformat\base {
return true;
}
public function uses_indentation(): bool {
return false;
}
/**
* Returns the display name of the given section that the course prefers.
*

View File

@ -49,10 +49,6 @@ class format_weeks extends core_courseformat\base {
return true;
}
public function uses_indentation(): bool {
return false;
}
/**
* Generate the title for this section page
* @return string the page title

View File

@ -1702,7 +1702,9 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
if ($hasmanageactivities && $indent >= 0) {
$indentlimits = new stdClass();
$indentlimits->min = 0;
$indentlimits->max = 16;
// Legacy indentation could continue using a limit of 16,
// but components based formats will be forced to use one level indentation only.
$indentlimits->max = ($usecomponents) ? 1 : 16;
if (right_to_left()) { // Exchange arrows on RTL
$rightarrow = 't/left';
$leftarrow = 't/right';
@ -1717,11 +1719,16 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
$enabledclass = '';
}
$actions['moveright'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '1')),
new pix_icon($rightarrow, '', 'moodle', array('class' => 'iconsmall')),
new moodle_url($baseurl, ['id' => $mod->id, 'indent' => '1']),
new pix_icon($rightarrow, '', 'moodle', ['class' => 'iconsmall']),
$str->moveright,
array('class' => 'editing_moveright ' . $enabledclass, 'data-action' => 'moveright',
'data-keepopen' => true, 'data-sectionreturn' => $sr)
[
'class' => 'editing_moveright ' . $enabledclass,
'data-action' => ($usecomponents) ? 'cmMoveRight' : 'moveright',
'data-keepopen' => true,
'data-sectionreturn' => $sr,
'data-id' => $mod->id,
]
);
if ($indent <= $indentlimits->min) {
@ -1730,11 +1737,16 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
$enabledclass = '';
}
$actions['moveleft'] = new action_menu_link_secondary(
new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '-1')),
new pix_icon($leftarrow, '', 'moodle', array('class' => 'iconsmall')),
new moodle_url($baseurl, ['id' => $mod->id, 'indent' => '0']),
new pix_icon($leftarrow, '', 'moodle', ['class' => 'iconsmall']),
$str->moveleft,
array('class' => 'editing_moveleft ' . $enabledclass, 'data-action' => 'moveleft',
'data-keepopen' => true, 'data-sectionreturn' => $sr)
[
'class' => 'editing_moveleft ' . $enabledclass,
'data-action' => ($usecomponents) ? 'cmMoveLeft' : 'moveleft',
'data-keepopen' => true,
'data-sectionreturn' => $sr,
'data-id' => $mod->id,
]
);
}

View File

@ -145,3 +145,36 @@ Feature: Course activity controls works as expected
| weeks | 0 | "General" | should | should | "8 January - 14 January" |
| weeks | 1 | "1 January - 7 January" | should not | should not | "8 January - 14 January" |
| weeks | 1 | "General" | should | should not | "8 January - 14 January" |
@javascript
Scenario Outline: Indentation should allow one level only
Given the following "users" exist:
| 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 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| forum | Test forum name | Test forum description | C1 | forum1 |
When I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I open "Test forum name" actions menu
Then "Move right" "link" should be visible
And "Move left" "link" should not be visible
And I click on "Move right" "link" in the "Test forum name" activity
And I open "Test forum name" actions menu
And "Move right" "link" should not be visible
And "Move left" "link" should be visible
And I click on "Move left" "link" in the "Test forum name" activity
And I open "Test forum name" actions menu
And "Move right" "link" should be visible
And "Move left" "link" should not be visible
Examples:
| courseformat |
| topics |
| weeks |

View File

@ -16,6 +16,8 @@ information provided here is intended especially for developers.
parameter. This information can be used by the plugins when enclosing the icons in `.activityiconcontainer .icon` or
`.activityiconcontainer .activityicon` containers to determine whether CSS filtering should be applied to the icon. If the icon
needs to be rendered as is and not whitened out, the `.nofilter` CSS class needs to be applied to the icon.
* Course module indentation has been recovered for course format using components via Move right/left feature.
Course formats using components will be allowed to use one level indentation only.
=== 4.1.2 ===

View File

@ -109,6 +109,19 @@ body:not(.editing) .sitetopic ul.section {
a.stealth:hover {
color: lighten($link-color, 25%) !important; /* stylelint-disable-line declaration-no-important */
}
&.indented {
.activity-item {
border: 0;
margin-left: map-get($spacers, 3);
}
}
&.indented + .indented {
.activity-item {
border-top: $border-width solid $border-color;
border-radius: unset;
}
}
}
.label {

View File

@ -13994,6 +13994,12 @@ body:not(.editing) .sitetopic ul.section {
.section .activity a.stealth:hover {
color: #5babf2 !important;
/* stylelint-disable-line declaration-no-important */ }
.section .activity.indented .activity-item {
border: 0;
margin-left: 1rem; }
.section .activity.indented + .indented .activity-item {
border-top: 1px solid #dee2e6;
border-radius: unset; }
.section .label .contentwithoutlink,
.section .label .activityinstance {

View File

@ -13994,6 +13994,12 @@ body:not(.editing) .sitetopic ul.section {
.section .activity a.stealth:hover {
color: #5babf2 !important;
/* stylelint-disable-line declaration-no-important */ }
.section .activity.indented .activity-item {
border: 0;
margin-left: 1rem; }
.section .activity.indented + .indented .activity-item {
border-top: 1px solid #dee2e6;
border-radius: unset; }
.section .label .contentwithoutlink,
.section .label .activityinstance {