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

This commit is contained in:
Huong Nguyen
2026-02-11 11:51:39 +07:00
14 changed files with 247 additions and 55 deletions
@@ -60,6 +60,22 @@ Feature: Course index depending on role
And "courseindex-content" "region" should be visible
And I should see "Activity sample 1" in the "courseindex-content" "region"
@javascript
Scenario: Course title is displayed in the course index heading
Given I am on the "C1" "Course" page logged in as "teacher1"
And the "multilang" filter is "on"
And the "multilang" filter applies to "content and headings"
And I navigate to "Settings" in current page administration
And I set the field "Course full name" to "<span lang=\"en\" class=\"multilang\">My course</span><span lang=\"es\" class=\"multilang\">Mi curso</span>"
And I press "Save and display"
# Course title should be displayed in the course index heading.
And I should see "My course" in the "courseindexdrawerheading" "region"
And I click on "Activity sample 1" "link" in the "#courseindex" "css_element"
And I should not see "Activity sample 2" in the "region-main" "region"
# Check course title link goes to the course main page.
When I click on "My course" "link" in the "courseindexdrawerheading" "region"
Then I should see "Activity sample 2" in the "region-main" "region"
@javascript
Scenario: Course index as a teacher
Given I log in as "teacher1"
@@ -24,13 +24,11 @@ Feature: Verify that courseindex is usable with the keyboard
And I should see "Section 1" in the "courseindex-content" "region"
And the focused element is "[data-preference='drawer-open-index'] .drawertoggle" "css_element"
And I press the tab key
And I press the tab key
And the focused element is ".courseindex-section" "css_element"
@javascript
Scenario: General focus on open course index.
When I press the shift tab key
And I press the shift tab key
And the focused element is "[data-preference='drawer-open-index'] .drawertoggle" "css_element"
And I press enter
Then I should not see "Section 1" in the "courseindex-content" "region"
@@ -79,6 +77,18 @@ Feature: Verify that courseindex is usable with the keyboard
And I press enter
Then I should see "Activity sample 1" in the "page-header" "region"
@javascript
Scenario: Navigate to main course page
Given I am on the "Activity sample 1" "assign activity" page
And I should not see "Activity sample 2" in the "region-main" "region"
And I click on "Close course index" "button"
And I click on "Open course index" "button"
When I press the shift tab key
And I press the shift tab key
And the focused element is "#courseindexdrawerheading a.courseindex-link" "css_element"
And I press enter
And I should see "Activity sample 2" in the "region-main" "region"
@javascript
Scenario: Navigate to first and last element.
# Close sections 1 and 3.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-12
View File
@@ -43,7 +43,6 @@ const SELECTORS = {
DRAWERS: '[data-region="fixed-drawer"]',
DRAWERCONTENT: '.drawercontent',
PAGECONTENT: '#page-content',
HEADERCONTENT: '.drawerheadercontent',
};
const CLASSES = {
@@ -422,11 +421,6 @@ export default class Drawers {
return;
}
// Hide close button and header content while the drawer is showing to prevent glitchy effects.
this.drawerNode.querySelector(SELECTORS.CLOSEBTN)?.classList.toggle('hidden', true);
this.drawerNode.querySelector(SELECTORS.HEADERCONTENT)?.classList.toggle('hidden', true);
// Remove open tooltip if still visible.
let openButton = getDrawerOpenButton(this.drawerNode.id);
if (openButton && openButton.hasAttribute('data-original-title')) {
@@ -464,13 +458,10 @@ export default class Drawers {
// Show close button and header content once the drawer is fully opened.
const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);
const headerContent = this.drawerNode.querySelector(SELECTORS.HEADERCONTENT);
if (focusOnCloseButton && closeButton) {
disableButtonTooltip(closeButton, true);
}
setTimeout(() => {
closeButton.classList.toggle('hidden', false);
headerContent.classList.toggle('hidden', false);
if (focusOnCloseButton) {
closeButton.focus();
}
@@ -503,9 +494,6 @@ export default class Drawers {
// Hide close button and header content while the drawer is hiding to prevent glitchy effects.
const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);
closeButton?.classList.toggle('hidden', true);
const headerContent = this.drawerNode.querySelector(SELECTORS.HEADERCONTENT);
headerContent?.classList.toggle('hidden', true);
// Remove the close button tooltip if visible.
if (closeButton.hasAttribute('data-original-title')) {
Tooltip.getInstance(closeButton)?.hide();
+9
View File
@@ -82,8 +82,17 @@ $regionmainsettingsmenu = $buildregionmainsettings ? $OUTPUT->region_main_settin
$header = $PAGE->activityheader;
$headercontent = $header->export_for_template($renderer);
$coursefullname = ($PAGE->course?->fullname) ? format_string(
$PAGE->course->fullname,
true,
['context' => context_course::instance($PAGE->course->id), 'escape' => false],
) : '';
$courseurl = $PAGE->course ? new \core\url('/course/view.php', ['id' => $PAGE->course->id]) : null;
$templatecontext = [
'sitename' => format_string($SITE->shortname, true, ['context' => context_course::instance(SITEID), "escape" => false]),
'coursefullname' => $coursefullname,
'courseurl' => $courseurl ? $courseurl->out(false) : null,
'output' => $OUTPUT,
'sidepreblocks' => $blockshtml,
'hasblocks' => $hasblocks,
@@ -55,9 +55,37 @@ $courseindex-item-current: $primary !default;
}
}
.drawerheader {
.drawerheading {
min-width: 0;
flex: 1 1 auto;
#courseindexdrawerheading {
font-size: $font-size-base;
margin-left: map-get($spacers, 3);
min-width: 0;
overflow: hidden;
.courseindex-link {
display: block;
max-width: 100%;
text-overflow: ellipsis;
color: $courseindex-link-color;
&:hover,
&:focus {
color: $courseindex-link-hover-color;
text-decoration: none;
}
}
}
i.icon {
color: $courseindex-link-color;
}
}
}
.courseindex {
// Both activity and section items.
.courseindex-item {
align-items: center;
padding: $courseindex-item-padding-y $courseindex-item-padding-x;
border: $border-width solid transparent;
@include border-radius($courseindex-item-radius);
@@ -70,6 +98,10 @@ $courseindex-item-current: $primary !default;
padding-right: 4px;
}
.courseindex-link {
font-size: $font-size-base * 0.875;
}
.courseindex-link,
.courseindex-chevron {
color: $courseindex-link-color;
@@ -130,7 +162,7 @@ $courseindex-item-current: $primary !default;
// Completion.
.completioninfo {
min-width: 24px;
min-width: 20px;
&.completion_complete {
color: $success;
@@ -171,14 +203,24 @@ $courseindex-item-current: $primary !default;
}
}
.delegated-section {
.courseindex-section-title {
margin-left: -(map-get($spacers, 1));
padding-left: 0 !important; /* stylelint-disable-line declaration-no-important */
}
.courseindex-item-content {
margin-left: -(map-get($spacers, 2));
}
}
&.dropready .courseindex-item-content {
/* Extra dropzone space */
padding-bottom: 1em;
}
.courseindex-sectioncontent {
.courseindex-sectioncontent:not(.delegated-section) {
.courseindex-item {
padding-left: $courseindex-item-padding-x;
padding-left: $courseindex-item-padding-x * 3;
}
}
&.delegated-section {
@@ -189,6 +231,7 @@ $courseindex-item-current: $primary !default;
// General icons size.
.icon {
font-size: 10px;
margin-right: 0;
}
// Element visible only on editing mode.
+7 -2
View File
@@ -215,8 +215,8 @@ $right-drawer-width: 320px;
}
.drawertoggle {
margin-right: auto;
margin-left: 5px;
margin-left: auto;
margin-right: 5px;
}
}
&.drawer-bottom {
@@ -265,6 +265,7 @@ $right-drawer-width: 320px;
padding: 0;
height: $navbar-height;
display: flex;
justify-content: space-between;
align-items: center;
.sitename {
overflow: hidden;
@@ -272,6 +273,10 @@ $right-drawer-width: 320px;
text-overflow: ellipsis;
margin-right: 16px;
}
.draweractions {
display: flex;
margin-left: map-get($spacers, 2);
}
}
.drawer.scrolled .drawerheader {
box-shadow: 0 8px 11px -7px $drawer-shadow-color;
+50 -9
View File
@@ -32208,8 +32208,8 @@ body.drawer-ease {
visibility: visible;
}
.drawer.drawer-left .drawertoggle {
margin-right: auto;
margin-left: 5px;
margin-left: auto;
margin-right: 5px;
}
.drawer.drawer-bottom {
bottom: -110%;
@@ -32239,6 +32239,7 @@ body.drawer-ease {
padding: 0;
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
}
.drawerheader .sitename {
@@ -32247,6 +32248,10 @@ body.drawer-ease {
text-overflow: ellipsis;
margin-right: 16px;
}
.drawerheader .draweractions {
display: flex;
margin-left: 0.5rem;
}
.drawer.scrolled .drawerheader {
box-shadow: 0 8px 11px -7px rgba(0, 0, 0, 0.25);
@@ -32320,8 +32325,8 @@ body.drawer-ease {
}
@media (max-width: 991.98px) {
.drawer-md.drawer-left .drawertoggle {
margin-right: auto;
margin-left: 5px;
margin-left: auto;
margin-right: 5px;
}
}
@media (max-width: 991.98px) {
@@ -32406,8 +32411,8 @@ body.drawer-ease {
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-left .drawertoggle {
margin-right: auto;
margin-left: 5px;
margin-left: auto;
margin-right: 5px;
}
}
@media (max-width: 767.98px) {
@@ -40654,7 +40659,32 @@ div.editor_atto_toolbar button .icon {
font-weight: bold;
}
.drawerheader .drawerheading {
min-width: 0;
flex: 1 1 auto;
}
.drawerheader .drawerheading #courseindexdrawerheading {
font-size: 1rem;
margin-left: 1rem;
min-width: 0;
overflow: hidden;
}
.drawerheader .drawerheading #courseindexdrawerheading .courseindex-link {
display: block;
max-width: 100%;
text-overflow: ellipsis;
color: var(--bs-secondary-color);
}
.drawerheader .drawerheading #courseindexdrawerheading .courseindex-link:hover, .drawerheader .drawerheading #courseindexdrawerheading .courseindex-link:focus {
color: black;
text-decoration: none;
}
.drawerheader .drawerheading i.icon {
color: var(--bs-secondary-color);
}
.courseindex .courseindex-item {
align-items: center;
padding: 0.5rem 0.5rem;
border: 1px solid transparent;
border-radius: 0.5rem;
@@ -40665,6 +40695,9 @@ div.editor_atto_toolbar button .icon {
.courseindex .courseindex-item .icons-collapse-expand {
padding-right: 4px;
}
.courseindex .courseindex-item .courseindex-link {
font-size: 0.875rem;
}
.courseindex .courseindex-item .courseindex-link,
.courseindex .courseindex-item .courseindex-chevron {
color: var(--bs-secondary-color);
@@ -40755,7 +40788,7 @@ div.editor_atto_toolbar button .icon {
color: #fff;
}
.courseindex .courseindex-item .completioninfo {
min-width: 24px;
min-width: 20px;
}
.courseindex .courseindex-item .completioninfo.completion_complete {
color: #357a32;
@@ -40787,18 +40820,26 @@ div.editor_atto_toolbar button .icon {
.courseindex .courseindex-section.current .delegated-section .current-badge {
display: none;
}
.courseindex .courseindex-section .delegated-section .courseindex-section-title {
margin-left: -0.25rem;
padding-left: 0 !important; /* stylelint-disable-line declaration-no-important */
}
.courseindex .courseindex-section .delegated-section .courseindex-item-content {
margin-left: -0.5rem;
}
.courseindex .courseindex-section.dropready .courseindex-item-content {
/* Extra dropzone space */
padding-bottom: 1em;
}
.courseindex .courseindex-section .courseindex-sectioncontent .courseindex-item {
padding-left: 0.5rem;
.courseindex .courseindex-section .courseindex-sectioncontent:not(.delegated-section) .courseindex-item {
padding-left: 1.5rem;
}
.courseindex .courseindex-section.delegated-section {
width: 100%;
}
.courseindex .icon {
font-size: 10px;
margin-right: 0;
}
.courseindex .d-flex-noedit {
display: none;
@@ -24,7 +24,7 @@
}
}}
<div id="courseindexdrawercontrols" class="dropdown">
<button class="btn btn-icon mx-2"
<button class="btn btn-icon"
id="courseindexdrawercontrolsmenubutton"
type="button"
data-bs-toggle="dropdown"
@@ -33,7 +33,7 @@
title="{{#str}}courseindexoptions, courseformat{{/str}}"
aria-label="{{#str}}courseindexoptions, courseformat{{/str}}"
aria-controls="courseindexdrawercontrolsmenu">
<i class="icon fa fa-ellipsis-v fa-fw m-0" aria-hidden="true"></i>
<i class="icon fa fa-angles-down fa-fw m-0" aria-hidden="true"></i>
</button>
<div class="dropdown-menu dropdown-menu-end" role="menu" id="courseindexdrawercontrolsmenu" aria-labelledby="courseindexdrawercontrolsmenubutton">
<a class="dropdown-item"
@@ -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 theme_boost/courseindexdrawerheading
This template will render the heading for the course index drawer.
Example context (json):
{
"coursefullname": "Full name of the course",
"courseurl": "http://example.com/course/view.php?id=2"
}
}}
<div id="courseindexdrawerheading">
<a
class="courseindex-link text-truncate fw-bold"
href="{{courseurl}}"
role="button"
>{{coursefullname}}</a>
</div>
+18 -14
View File
@@ -36,20 +36,24 @@
}} data-close-on-resize="{{$drawercloseonresize}}0{{/drawercloseonresize}}"{{!
}}>
<div class="drawerheader">
<button
class="btn btn-icon drawertoggle hidden"
data-toggler="drawers"
data-action="closedrawer"
data-target="{{$id}}{{/id}}"
data-bs-toggle="tooltip"
data-bs-placement="{{$tooltipplacement}}right{{/tooltipplacement}}"
title="{{$closebuttontext}}{{#str}}closedrawer, core{{/str}}{{/closebuttontext}}"
>
{{#pix}} e/cancel, core {{/pix}}
</button>
{{$drawerheading}}{{/drawerheading}}
<div class="drawerheadercontent hidden">
{{$drawerheadercontent}}{{/drawerheadercontent}}
<div class="drawerheading">
{{$drawerheading}}{{/drawerheading}}
</div>
<div class="draweractions">
<div class="drawerheadercontent">
{{$drawerheadercontent}}{{/drawerheadercontent}}
</div>
<button
class="btn btn-icon drawertoggle"
data-toggler="drawers"
data-action="closedrawer"
data-target="{{$id}}{{/id}}"
data-bs-toggle="tooltip"
data-bs-placement="{{$tooltipplacement}}right{{/tooltipplacement}}"
title="{{$closebuttontext}}{{#str}}closedrawer, core{{/str}}{{/closebuttontext}}"
>
{{#pix}} e/cancel, core {{/pix}}
</button>
</div>
</div>
<div class="drawercontent drag-container" data-usertour="scroller">
@@ -64,6 +64,7 @@
{{$drawerheadercontent}}
{{> theme_boost/courseindexdrawercontrols}}
{{/drawerheadercontent}}
{{$drawerheading}}{{> theme_boost/courseindexdrawerheading}}{{/drawerheading}}
{{$drawerclasses}}drawer drawer-left {{#courseindexopen}}show{{/courseindexopen}}{{/drawerclasses}}
{{$drawercontent}}
{{{courseindex}}}
+50 -9
View File
@@ -32208,8 +32208,8 @@ body.drawer-ease {
visibility: visible;
}
.drawer.drawer-left .drawertoggle {
margin-right: auto;
margin-left: 5px;
margin-left: auto;
margin-right: 5px;
}
.drawer.drawer-bottom {
bottom: -110%;
@@ -32239,6 +32239,7 @@ body.drawer-ease {
padding: 0;
height: 50px;
display: flex;
justify-content: space-between;
align-items: center;
}
.drawerheader .sitename {
@@ -32247,6 +32248,10 @@ body.drawer-ease {
text-overflow: ellipsis;
margin-right: 16px;
}
.drawerheader .draweractions {
display: flex;
margin-left: 0.5rem;
}
.drawer.scrolled .drawerheader {
box-shadow: 0 8px 11px -7px rgba(0, 0, 0, 0.25);
@@ -32320,8 +32325,8 @@ body.drawer-ease {
}
@media (max-width: 991.98px) {
.drawer-md.drawer-left .drawertoggle {
margin-right: auto;
margin-left: 5px;
margin-left: auto;
margin-right: 5px;
}
}
@media (max-width: 991.98px) {
@@ -32406,8 +32411,8 @@ body.drawer-ease {
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-left .drawertoggle {
margin-right: auto;
margin-left: 5px;
margin-left: auto;
margin-right: 5px;
}
}
@media (max-width: 767.98px) {
@@ -40588,7 +40593,32 @@ div.editor_atto_toolbar button .icon {
font-weight: bold;
}
.drawerheader .drawerheading {
min-width: 0;
flex: 1 1 auto;
}
.drawerheader .drawerheading #courseindexdrawerheading {
font-size: 1rem;
margin-left: 1rem;
min-width: 0;
overflow: hidden;
}
.drawerheader .drawerheading #courseindexdrawerheading .courseindex-link {
display: block;
max-width: 100%;
text-overflow: ellipsis;
color: var(--bs-secondary-color);
}
.drawerheader .drawerheading #courseindexdrawerheading .courseindex-link:hover, .drawerheader .drawerheading #courseindexdrawerheading .courseindex-link:focus {
color: black;
text-decoration: none;
}
.drawerheader .drawerheading i.icon {
color: var(--bs-secondary-color);
}
.courseindex .courseindex-item {
align-items: center;
padding: 0.5rem 0.5rem;
border: 1px solid transparent;
border-radius: 0.375rem;
@@ -40599,6 +40629,9 @@ div.editor_atto_toolbar button .icon {
.courseindex .courseindex-item .icons-collapse-expand {
padding-right: 4px;
}
.courseindex .courseindex-item .courseindex-link {
font-size: 0.875rem;
}
.courseindex .courseindex-item .courseindex-link,
.courseindex .courseindex-item .courseindex-chevron {
color: var(--bs-secondary-color);
@@ -40689,7 +40722,7 @@ div.editor_atto_toolbar button .icon {
color: #fff;
}
.courseindex .courseindex-item .completioninfo {
min-width: 24px;
min-width: 20px;
}
.courseindex .courseindex-item .completioninfo.completion_complete {
color: #357a32;
@@ -40721,18 +40754,26 @@ div.editor_atto_toolbar button .icon {
.courseindex .courseindex-section.current .delegated-section .current-badge {
display: none;
}
.courseindex .courseindex-section .delegated-section .courseindex-section-title {
margin-left: -0.25rem;
padding-left: 0 !important; /* stylelint-disable-line declaration-no-important */
}
.courseindex .courseindex-section .delegated-section .courseindex-item-content {
margin-left: -0.5rem;
}
.courseindex .courseindex-section.dropready .courseindex-item-content {
/* Extra dropzone space */
padding-bottom: 1em;
}
.courseindex .courseindex-section .courseindex-sectioncontent .courseindex-item {
padding-left: 0.5rem;
.courseindex .courseindex-section .courseindex-sectioncontent:not(.delegated-section) .courseindex-item {
padding-left: 1.5rem;
}
.courseindex .courseindex-section.delegated-section {
width: 100%;
}
.courseindex .icon {
font-size: 10px;
margin-right: 0;
}
.courseindex .d-flex-noedit {
display: none;