MDL-75762 gradereport_grader: fix sticky headers

This commit is contained in:
Ferran Recio
2023-08-14 07:56:54 +02:00
committed by Laurent David
parent c7e9af30df
commit b594536ef0
8 changed files with 246 additions and 106 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+132 -33
View File
@@ -40,15 +40,35 @@ const SELECTORS = {
OPENBTN: '[data-toggler="drawers"][data-action="opendrawer"]',
TOGGLEBTN: '[data-toggler="drawers"][data-action="toggle"]',
DRAWERS: '[data-region="fixed-drawer"]',
CONTAINER: '#page.drawers',
DRAWERCONTENT: '.drawercontent',
PAGECONTENT: '#page-content',
};
const CLASSES = {
SCROLLED: 'scrolled',
SHOW: 'show',
NOTINITIALISED: 'not-initialized',
TOGGLERIGHT: '.drawer-right-toggle',
};
/**
* Pixel thresshold to auto-hide drawers.
*
* @type {Number}
*/
const THRESHOLD = 20;
/**
* Try to get the drawer z-index from the page content.
*
* @returns {Number|null} the z-index of the drawer.
* @private
*/
const getDrawerZIndex = () => {
const drawer = document.querySelector(SELECTORS.DRAWERS);
if (!drawer) {
return null;
}
return parseInt(window.getComputedStyle(drawer).zIndex, 10);
};
/**
@@ -62,6 +82,10 @@ const getBackdrop = () => {
backdropPromise = Templates.render('core/modal_backdrop', {})
.then(html => new ModalBackdrop(html))
.then(modalBackdrop => {
const drawerZindex = getDrawerZIndex();
if (drawerZindex) {
modalBackdrop.setZIndex(getDrawerZIndex() - 1);
}
modalBackdrop.getAttachmentPoint().get(0).addEventListener('click', e => {
e.preventDefault();
Drawers.closeAllDrawers();
@@ -239,6 +263,12 @@ export default class Drawers {
*/
drawerNode = null;
/**
* The drawer page bounding box dimensions.
* @var {DOMRect} boundingRect
*/
boundingRect = null;
constructor(drawerNode) {
// Some behat tests may use fake drawer divs to test components in drawers.
if (drawerNode.dataset.behatFakeDrawer !== undefined) {
@@ -415,6 +445,8 @@ export default class Drawers {
page.classList.add(state);
}
this.boundingRect = this.drawerNode.getBoundingClientRect();
if (isSmall()) {
getBackdrop().then(backdrop => {
backdrop.show();
@@ -518,6 +550,65 @@ export default class Drawers {
}
}
/**
* Displaces the drawer outsite the page.
*
* @param {Number} scrollPosition the page current scroll position
*/
displace(scrollPosition) {
let displace = scrollPosition;
let openButton = getDrawerOpenButton(this.drawerNode.id);
if (scrollPosition === 0) {
this.drawerNode.style.transform = '';
if (openButton) {
openButton.style.transform = '';
}
return;
}
const state = this.drawerNode.dataset?.state;
const drawrWidth = this.drawerNode.offsetWidth;
let scrollThreshold = drawrWidth;
let direction = -1;
if (state === 'show-drawer-right') {
direction = 1;
scrollThreshold = THRESHOLD;
}
if (scrollPosition > scrollThreshold) {
displace = drawrWidth + THRESHOLD;
}
displace *= direction;
const transform = `translateX(${displace}px)`;
if (openButton) {
openButton.style.transform = transform;
}
this.drawerNode.style.transform = transform;
}
/**
* Prevent drawer from overlapping an element.
*
* @param {HTMLElement} currentFocus
*/
preventOverlap(currentFocus) {
if (!this.isOpen) {
return;
}
const drawrWidth = this.drawerNode.offsetWidth;
const element = currentFocus.getBoundingClientRect();
const drawer = this.boundingRect;
const overlapping = (
(element.right + THRESHOLD) > drawer.left &&
(element.left - THRESHOLD) < drawer.right
);
if (overlapping) {
// Force drawer to displace out of the page.
this.displace(drawrWidth + 1);
} else {
// Reset drawer displacement.
this.displace(window.scrollX);
}
}
/**
* Close all drawers.
*/
@@ -541,41 +632,34 @@ export default class Drawers {
drawerInstance.closeDrawer();
});
}
}
/**
* Activate the scroller helper for the drawer layout.
*
* @private
*/
const scroller = () => {
const body = document.querySelector('body');
const drawerLayout = document.querySelector(SELECTORS.CONTAINER);
if (drawerLayout) {
// If there is not visible scrollbar then remove extra margin from right drawer.
const drawerRight = document.querySelector(SELECTORS.CONTAINER + ' ' + CLASSES.TOGGLERIGHT);
if (!scrollbarVisible(drawerLayout) && drawerRight) {
drawerRight.style.marginRight = '0';
/**
* Prevent drawers from covering the focused element.
*/
static preventCoveringFocusedElement() {
const currentFocus = document.activeElement;
// Focus on page layout elements should be ignored.
const pagecontent = document.querySelector(SELECTORS.PAGECONTENT);
if (!currentFocus || !pagecontent?.contains(currentFocus)) {
Drawers.displaceDrawers(window.scrollX);
return;
}
drawerLayout.addEventListener("scroll", () => {
if (drawerLayout.scrollTop >= window.innerHeight) {
body.classList.add(CLASSES.SCROLLED);
} else {
body.classList.remove(CLASSES.SCROLLED);
}
drawerMap.forEach(drawerInstance => {
drawerInstance.preventOverlap(currentFocus);
});
}
};
/**
* Check if there is a visible scrollbar in the given html element.
*
* @param {object} htmlNode The html element.
* @returns {boolean} true if the scroll height is greater than client height.
*/
const scrollbarVisible = (htmlNode) => {
return htmlNode.scrollHeight > htmlNode.clientHeight;
};
/**
* Prevent drawer from covering the content when the page content covers the full page.
*
* @param {Number} displace
*/
static displaceDrawers(displace) {
drawerMap.forEach(drawerInstance => {
drawerInstance.displace(displace);
});
}
}
/**
* Set the last used attribute for the last used toggle button for a drawer.
@@ -684,10 +768,25 @@ const registerListeners = () => {
}
};
document.addEventListener('scroll', () => {
const body = document.querySelector('body');
if (window.scrollY >= window.innerHeight) {
body.classList.add(CLASSES.SCROLLED);
} else {
body.classList.remove(CLASSES.SCROLLED);
}
// Horizontal scroll listener to displace the drawers to prevent covering
// any possible sticky content.
Drawers.displaceDrawers(window.scrollX);
});
const preventOverlap = debounce(Drawers.preventCoveringFocusedElement, 100);
document.addEventListener('focusin', preventOverlap);
document.addEventListener('focusout', preventOverlap);
window.addEventListener('resize', debounce(closeOnResizeListener, 400));
};
scroller();
registerListeners();
const drawers = document.querySelectorAll(SELECTORS.DRAWERS);
+2 -1
View File
@@ -159,7 +159,6 @@ $right-drawer-width: 320px;
}
@mixin drawer() {
@include transition(left 0.2s ease, right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease);
background-color: $drawer-bg-color;
z-index: $zindex-fixed;
position: fixed;
@@ -173,6 +172,7 @@ $right-drawer-width: 320px;
@mixin drawertypes() {
&.drawer-right {
@include transition(right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease, transform 0.5s ease);
width: $drawer-right-width;
max-width: $drawer-right-width;
right: calc(-#{$drawer-right-width} + -10px);
@@ -190,6 +190,7 @@ $right-drawer-width: 320px;
}
}
&.drawer-left {
@include transition(left 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease);
width: $drawer-left-width;
max-width: $drawer-left-width;
left: calc(-#{$drawer-left-width} + -10px);
+1 -1
View File
@@ -526,7 +526,7 @@
tr.heading {
position: sticky;
top: 0;
top: $navbar-height;
z-index: 4;
}
+1 -5
View File
@@ -181,9 +181,6 @@
#page.drawers .main-inner {
margin-top: 1.5rem;
}
#page.drawers .drawer-right-toggle {
margin-right: 0.7rem;
}
}
@include media-breakpoint-up(md) {
@@ -220,7 +217,6 @@
position: relative;
overflow-y: visible;
@include transition(0.2s);
height: calc(100vh - #{$navbar-height});
left: 0;
right: 0;
&.show-drawer-left {
@@ -241,7 +237,7 @@
margin-right: $drawer-right-width;
}
&.hasstickyfooter {
height: calc(100vh - #{$navbar-height} - #{$stickyfooter-height});
margin-bottom: $stickyfooter-height;
}
}
}
+54 -32
View File
@@ -29724,27 +29724,27 @@ body.drawer-ease {
}
.drawer {
transition: left 0.2s ease, right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
background-color: #f8f9fa;
z-index: 1030;
position: fixed;
height: 100vh;
top: 0;
}
@media (prefers-reduced-motion: reduce) {
.drawer {
transition: none;
}
}
.drawer.not-initialized {
display: none;
}
.drawer.drawer-right {
transition: right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease, transform 0.5s ease;
width: 315px;
max-width: 315px;
right: calc(-315px + -10px);
visibility: hidden;
}
@media (prefers-reduced-motion: reduce) {
.drawer.drawer-right {
transition: none;
}
}
.drawer.drawer-right.show {
right: 0;
visibility: visible;
@@ -29754,11 +29754,17 @@ body.drawer-ease {
margin-right: 5px;
}
.drawer.drawer-left {
transition: left 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
width: 285px;
max-width: 285px;
left: calc(-285px + -10px);
visibility: hidden;
}
@media (prefers-reduced-motion: reduce) {
.drawer.drawer-left {
transition: none;
}
}
.drawer.drawer-left.show {
left: 0;
visibility: visible;
@@ -29804,35 +29810,35 @@ body.drawer-ease {
@media (max-width: 991.98px) {
.drawer-md {
display: block;
transition: left 0.2s ease, right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
background-color: #f8f9fa;
z-index: 1030;
position: fixed;
height: 100vh;
top: 0;
}
}
@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {
.drawer-md {
transition: none;
}
}
@media (max-width: 991.98px) {
.drawer-md.not-initialized {
display: none;
}
}
@media (max-width: 991.98px) {
.drawer-md.drawer-right {
transition: right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease, transform 0.5s ease;
width: 315px;
max-width: 315px;
right: calc(-315px + -10px);
visibility: hidden;
}
}
@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {
.drawer-md.drawer-right {
transition: none;
}
}
@media (max-width: 991.98px) {
.drawer-md.drawer-right.show {
right: 0;
visibility: visible;
}
}
@media (max-width: 991.98px) {
.drawer-md.drawer-right .drawertoggle {
margin-left: auto;
margin-right: 5px;
@@ -29840,15 +29846,25 @@ body.drawer-ease {
}
@media (max-width: 991.98px) {
.drawer-md.drawer-left {
transition: left 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
width: 285px;
max-width: 285px;
left: calc(-285px + -10px);
visibility: hidden;
}
}
@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {
.drawer-md.drawer-left {
transition: none;
}
}
@media (max-width: 991.98px) {
.drawer-md.drawer-left.show {
left: 0;
visibility: visible;
}
}
@media (max-width: 991.98px) {
.drawer-md.drawer-left .drawertoggle {
margin-right: auto;
margin-left: 5px;
@@ -29865,35 +29881,35 @@ body.drawer-ease {
@media (max-width: 767.98px) {
.drawer-sm {
display: block;
transition: left 0.2s ease, right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
background-color: #f8f9fa;
z-index: 1030;
position: fixed;
height: 100vh;
top: 0;
}
}
@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
.drawer-sm {
transition: none;
}
}
@media (max-width: 767.98px) {
.drawer-sm.not-initialized {
display: none;
}
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-right {
transition: right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease, transform 0.5s ease;
width: 315px;
max-width: 315px;
right: calc(-315px + -10px);
visibility: hidden;
}
}
@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
.drawer-sm.drawer-right {
transition: none;
}
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-right.show {
right: 0;
visibility: visible;
}
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-right .drawertoggle {
margin-left: auto;
margin-right: 5px;
@@ -29901,15 +29917,25 @@ body.drawer-ease {
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-left {
transition: left 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
width: 285px;
max-width: 285px;
left: calc(-285px + -10px);
visibility: hidden;
}
}
@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
.drawer-sm.drawer-left {
transition: none;
}
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-left.show {
left: 0;
visibility: visible;
}
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-left .drawertoggle {
margin-right: auto;
margin-left: 5px;
@@ -35361,7 +35387,7 @@ p.arrow_button {
}
.path-grade-report-grader .gradeparent tr.heading {
position: sticky;
top: 0;
top: 60px;
z-index: 4;
}
.path-grade-report-grader .gradeparent tr.userrow th {
@@ -36589,9 +36615,6 @@ span[data-flexitour=container][x-placement=right] div[data-role=arrow]:after, sp
#page.drawers .main-inner {
margin-top: 1.5rem;
}
#page.drawers .drawer-right-toggle {
margin-right: 0.7rem;
}
}
@media (min-width: 768px) {
#page.drawers {
@@ -36621,7 +36644,6 @@ span[data-flexitour=container][x-placement=right] div[data-role=arrow]:after, sp
position: relative;
overflow-y: visible;
transition: 0.2s;
height: calc(100vh - 60px);
left: 0;
right: 0;
}
@@ -36656,7 +36678,7 @@ span[data-flexitour=container][x-placement=right] div[data-role=arrow]:after, sp
}
@media (min-width: 992px) {
#page.drawers.hasstickyfooter {
height: calc(100vh - 60px - max(96px, 0.9375rem * 3));
margin-bottom: max(96px, 0.9375rem * 3);
}
}
.drawercontrolbuttons {
+54 -32
View File
@@ -29724,27 +29724,27 @@ body.drawer-ease {
}
.drawer {
transition: left 0.2s ease, right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
background-color: #f8f9fa;
z-index: 1030;
position: fixed;
height: 100vh;
top: 0;
}
@media (prefers-reduced-motion: reduce) {
.drawer {
transition: none;
}
}
.drawer.not-initialized {
display: none;
}
.drawer.drawer-right {
transition: right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease, transform 0.5s ease;
width: 315px;
max-width: 315px;
right: calc(-315px + -10px);
visibility: hidden;
}
@media (prefers-reduced-motion: reduce) {
.drawer.drawer-right {
transition: none;
}
}
.drawer.drawer-right.show {
right: 0;
visibility: visible;
@@ -29754,11 +29754,17 @@ body.drawer-ease {
margin-right: 5px;
}
.drawer.drawer-left {
transition: left 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
width: 285px;
max-width: 285px;
left: calc(-285px + -10px);
visibility: hidden;
}
@media (prefers-reduced-motion: reduce) {
.drawer.drawer-left {
transition: none;
}
}
.drawer.drawer-left.show {
left: 0;
visibility: visible;
@@ -29804,35 +29810,35 @@ body.drawer-ease {
@media (max-width: 991.98px) {
.drawer-md {
display: block;
transition: left 0.2s ease, right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
background-color: #f8f9fa;
z-index: 1030;
position: fixed;
height: 100vh;
top: 0;
}
}
@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {
.drawer-md {
transition: none;
}
}
@media (max-width: 991.98px) {
.drawer-md.not-initialized {
display: none;
}
}
@media (max-width: 991.98px) {
.drawer-md.drawer-right {
transition: right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease, transform 0.5s ease;
width: 315px;
max-width: 315px;
right: calc(-315px + -10px);
visibility: hidden;
}
}
@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {
.drawer-md.drawer-right {
transition: none;
}
}
@media (max-width: 991.98px) {
.drawer-md.drawer-right.show {
right: 0;
visibility: visible;
}
}
@media (max-width: 991.98px) {
.drawer-md.drawer-right .drawertoggle {
margin-left: auto;
margin-right: 5px;
@@ -29840,15 +29846,25 @@ body.drawer-ease {
}
@media (max-width: 991.98px) {
.drawer-md.drawer-left {
transition: left 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
width: 285px;
max-width: 285px;
left: calc(-285px + -10px);
visibility: hidden;
}
}
@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {
.drawer-md.drawer-left {
transition: none;
}
}
@media (max-width: 991.98px) {
.drawer-md.drawer-left.show {
left: 0;
visibility: visible;
}
}
@media (max-width: 991.98px) {
.drawer-md.drawer-left .drawertoggle {
margin-right: auto;
margin-left: 5px;
@@ -29865,35 +29881,35 @@ body.drawer-ease {
@media (max-width: 767.98px) {
.drawer-sm {
display: block;
transition: left 0.2s ease, right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
background-color: #f8f9fa;
z-index: 1030;
position: fixed;
height: 100vh;
top: 0;
}
}
@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
.drawer-sm {
transition: none;
}
}
@media (max-width: 767.98px) {
.drawer-sm.not-initialized {
display: none;
}
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-right {
transition: right 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease, transform 0.5s ease;
width: 315px;
max-width: 315px;
right: calc(-315px + -10px);
visibility: hidden;
}
}
@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
.drawer-sm.drawer-right {
transition: none;
}
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-right.show {
right: 0;
visibility: visible;
}
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-right .drawertoggle {
margin-left: auto;
margin-right: 5px;
@@ -29901,15 +29917,25 @@ body.drawer-ease {
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-left {
transition: left 0.2s ease, top 0.2s ease, bottom 0.2s ease, visibility 0.2s ease;
width: 285px;
max-width: 285px;
left: calc(-285px + -10px);
visibility: hidden;
}
}
@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
.drawer-sm.drawer-left {
transition: none;
}
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-left.show {
left: 0;
visibility: visible;
}
}
@media (max-width: 767.98px) {
.drawer-sm.drawer-left .drawertoggle {
margin-right: auto;
margin-left: 5px;
@@ -35361,7 +35387,7 @@ p.arrow_button {
}
.path-grade-report-grader .gradeparent tr.heading {
position: sticky;
top: 0;
top: 50px;
z-index: 4;
}
.path-grade-report-grader .gradeparent tr.userrow th {
@@ -36523,9 +36549,6 @@ span[data-flexitour=container][x-placement=right] div[data-role=arrow]:after, sp
#page.drawers .main-inner {
margin-top: 1.5rem;
}
#page.drawers .drawer-right-toggle {
margin-right: 0.7rem;
}
}
@media (min-width: 768px) {
#page.drawers {
@@ -36555,7 +36578,6 @@ span[data-flexitour=container][x-placement=right] div[data-role=arrow]:after, sp
position: relative;
overflow-y: visible;
transition: 0.2s;
height: calc(100vh - 50px);
left: 0;
right: 0;
}
@@ -36590,7 +36612,7 @@ span[data-flexitour=container][x-placement=right] div[data-role=arrow]:after, sp
}
@media (min-width: 992px) {
#page.drawers.hasstickyfooter {
height: calc(100vh - 50px - max(96px, 0.9375rem * 3));
margin-bottom: max(96px, 0.9375rem * 3);
}
}
.drawercontrolbuttons {