From c9c5947e1cae8c9c0b87dc4931e700c945759510 Mon Sep 17 00:00:00 2001 From: Mihail Geshoski Date: Thu, 30 Nov 2023 09:58:54 +0800 Subject: [PATCH] MDL-80270 gradereport_grader: User row as the last row cannot be sticky In certain scenarios, a user row can be the last row in the grader report table. The current logic does not take this into account and always pins the last row regardless of the type. This change ensures that the last row is not a user row before executing the logic responsible for pinning this row. --- .../grader/amd/build/stickycolspan.min.js | 2 +- .../grader/amd/build/stickycolspan.min.js.map | 2 +- grade/report/grader/amd/src/stickycolspan.js | 23 +++++++++++-------- theme/boost/scss/moodle/grade.scss | 13 +++++++---- theme/boost/style/moodle.css | 4 ++-- theme/classic/style/moodle.css | 4 ++-- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/grade/report/grader/amd/build/stickycolspan.min.js b/grade/report/grader/amd/build/stickycolspan.min.js index 380ff0c5fb0..b45c8fb0e9d 100644 --- a/grade/report/grader/amd/build/stickycolspan.min.js +++ b/grade/report/grader/amd/build/stickycolspan.min.js @@ -5,6 +5,6 @@ define("gradereport_grader/stickycolspan",["exports","jquery"],(function(_export * @module gradereport_grader/stickycolspan * @copyright 2022 Bas Brands * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_jquery=(obj=_jquery)&&obj.__esModule?obj:{default:obj};const SELECTORS_GRADEPARENT=".gradeparent",SELECTORS_STUDENTHEADER="#studentheader",SELECTORS_TABLEHEADER="th.header",SELECTORS_BEHAT="body.behat-site",SELECTORS_USERDROPDOWN=".userrow th .dropdown",SELECTORS_AVERAGEROWHEADER=".lastrow th";_exports.init=()=>{(0,_jquery.default)(SELECTORS_USERDROPDOWN).on("show.bs.dropdown hide.bs.dropdown",(e=>{e.target.closest(SELECTORS_TABLEHEADER).classList.toggle("actions-menu-active")}));if(new IntersectionObserver((_ref=>{let[e]=_ref;return e.target.closest("tr").classList.toggle("pinned",e.intersectionRatio<1)}),{threshold:[1]}).observe(document.querySelector(SELECTORS_AVERAGEROWHEADER)),!document.querySelector(SELECTORS_BEHAT)){const grader=document.querySelector(SELECTORS_GRADEPARENT),tableHeaders=grader.querySelectorAll(SELECTORS_TABLEHEADER),studentHeader=grader.querySelector(SELECTORS_STUDENTHEADER),leftOffset=getComputedStyle(studentHeader).getPropertyValue("left"),rightOffset=getComputedStyle(studentHeader).getPropertyValue("right");tableHeaders.forEach((tableHeader=>{if(tableHeader.colSpan>1){const addOffset=tableHeader.offsetWidth-studentHeader.offsetWidth;window.right_to_left()?tableHeader.style.right="calc("+rightOffset+" - "+addOffset+"px )":tableHeader.style.left="calc("+leftOffset+" - "+addOffset+"px )"}}))}}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_jquery=(obj=_jquery)&&obj.__esModule?obj:{default:obj};const SELECTORS_GRADEPARENT=".gradeparent",SELECTORS_STUDENTHEADER="#studentheader",SELECTORS_TABLEHEADER="th.header",SELECTORS_BEHAT="body.behat-site",SELECTORS_USERDROPDOWN=".userrow th .dropdown",SELECTORS_LASTROW=".lastrow";_exports.init=()=>{(0,_jquery.default)(SELECTORS_USERDROPDOWN).on("show.bs.dropdown hide.bs.dropdown",(e=>{e.target.closest(SELECTORS_TABLEHEADER).classList.toggle("actions-menu-active")}));const lastRow=document.querySelector(SELECTORS_LASTROW);if(!lastRow.classList.contains("userrow")){new IntersectionObserver((_ref=>{let[e]=_ref;return e.target.classList.toggle("pinned",e.intersectionRatio<1)}),{threshold:[1]}).observe(lastRow)}if(!document.querySelector(SELECTORS_BEHAT)){const grader=document.querySelector(SELECTORS_GRADEPARENT),tableHeaders=grader.querySelectorAll(SELECTORS_TABLEHEADER),studentHeader=grader.querySelector(SELECTORS_STUDENTHEADER),leftOffset=getComputedStyle(studentHeader).getPropertyValue("left"),rightOffset=getComputedStyle(studentHeader).getPropertyValue("right");tableHeaders.forEach((tableHeader=>{if(tableHeader.colSpan>1){const addOffset=tableHeader.offsetWidth-studentHeader.offsetWidth;window.right_to_left()?tableHeader.style.right="calc("+rightOffset+" - "+addOffset+"px )":tableHeader.style.left="calc("+leftOffset+" - "+addOffset+"px )"}}))}}})); //# sourceMappingURL=stickycolspan.min.js.map \ No newline at end of file diff --git a/grade/report/grader/amd/build/stickycolspan.min.js.map b/grade/report/grader/amd/build/stickycolspan.min.js.map index 48523d6faa7..4221f4fedf0 100644 --- a/grade/report/grader/amd/build/stickycolspan.min.js.map +++ b/grade/report/grader/amd/build/stickycolspan.min.js.map @@ -1 +1 @@ -{"version":3,"file":"stickycolspan.min.js","sources":["../src/stickycolspan.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript module for fixing the position of sticky headers with multiple colspans\n *\n * @module gradereport_grader/stickycolspan\n * @copyright 2022 Bas Brands \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\n\nconst SELECTORS = {\n GRADEPARENT: '.gradeparent',\n STUDENTHEADER: '#studentheader',\n TABLEHEADER: 'th.header',\n BEHAT: 'body.behat-site',\n USERDROPDOWN: '.userrow th .dropdown',\n AVERAGEROWHEADER: '.lastrow th',\n};\n\n/**\n * Initialize module\n */\nexport const init = () => {\n // The sticky positioning attributed to the user column cells affects the stacking context and makes the dropdowns\n // within these cells to be cut off. To solve this problem, whenever one of these action menus (dropdowns) is opened\n // we need to manually bump up the z-index value of the parent container element and revert once closed.\n $(SELECTORS.USERDROPDOWN).on('show.bs.dropdown hide.bs.dropdown', (e) => {\n // The closest heading element has sticky positioning which affects the stacking context in this case.\n e.target.closest(SELECTORS.TABLEHEADER).classList.toggle('actions-menu-active');\n });\n // Register an observer that will bump up the z-index value of the average overall row when it's pinned to prevent\n // the row being cut-off by the user column cells or other components within the report table that have higher\n // z-index values.\n const observer = new IntersectionObserver(\n ([e]) => e.target.closest('tr').classList.toggle('pinned', e.intersectionRatio < 1),\n {threshold: [1]}\n );\n observer.observe(document.querySelector(SELECTORS.AVERAGEROWHEADER));\n\n if (!document.querySelector(SELECTORS.BEHAT)) {\n const grader = document.querySelector(SELECTORS.GRADEPARENT);\n const tableHeaders = grader.querySelectorAll(SELECTORS.TABLEHEADER);\n const studentHeader = grader.querySelector(SELECTORS.STUDENTHEADER);\n const leftOffset = getComputedStyle(studentHeader).getPropertyValue('left');\n const rightOffset = getComputedStyle(studentHeader).getPropertyValue('right');\n\n tableHeaders.forEach((tableHeader) => {\n if (tableHeader.colSpan > 1) {\n const addOffset = (tableHeader.offsetWidth - studentHeader.offsetWidth);\n if (window.right_to_left()) {\n tableHeader.style.right = 'calc(' + rightOffset + ' - ' + addOffset + 'px )';\n } else {\n tableHeader.style.left = 'calc(' + leftOffset + ' - ' + addOffset + 'px )';\n }\n }\n });\n }\n};\n"],"names":["SELECTORS","on","e","target","closest","classList","toggle","IntersectionObserver","_ref","intersectionRatio","threshold","observe","document","querySelector","grader","tableHeaders","querySelectorAll","studentHeader","leftOffset","getComputedStyle","getPropertyValue","rightOffset","forEach","tableHeader","colSpan","addOffset","offsetWidth","window","right_to_left","style","right","left"],"mappings":";;;;;;;gJAyBMA,sBACW,eADXA,wBAEa,iBAFbA,sBAGW,YAHXA,gBAIK,kBAJLA,uBAKY,wBALZA,2BAMgB,4BAMF,yBAIdA,wBAAwBC,GAAG,qCAAsCC,IAE/DA,EAAEC,OAAOC,QAAQJ,uBAAuBK,UAAUC,OAAO,6BAK5C,IAAIC,sBACjBC,WAAEN,eAAOA,EAAEC,OAAOC,QAAQ,MAAMC,UAAUC,OAAO,SAAUJ,EAAEO,kBAAoB,KACjF,CAACC,UAAW,CAAC,KAERC,QAAQC,SAASC,cAAcb,8BAEnCY,SAASC,cAAcb,iBAAkB,OACpCc,OAASF,SAASC,cAAcb,uBAChCe,aAAeD,OAAOE,iBAAiBhB,uBACvCiB,cAAgBH,OAAOD,cAAcb,yBACrCkB,WAAaC,iBAAiBF,eAAeG,iBAAiB,QAC9DC,YAAcF,iBAAiBF,eAAeG,iBAAiB,SAErEL,aAAaO,SAASC,iBACdA,YAAYC,QAAU,EAAG,OACnBC,UAAaF,YAAYG,YAAcT,cAAcS,YACvDC,OAAOC,gBACPL,YAAYM,MAAMC,MAAQ,QAAUT,YAAc,MAAQI,UAAY,OAEtEF,YAAYM,MAAME,KAAO,QAAUb,WAAa,MAAQO,UAAY"} \ No newline at end of file +{"version":3,"file":"stickycolspan.min.js","sources":["../src/stickycolspan.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript module for fixing the position of sticky headers with multiple colspans\n *\n * @module gradereport_grader/stickycolspan\n * @copyright 2022 Bas Brands \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\n\nconst SELECTORS = {\n GRADEPARENT: '.gradeparent',\n STUDENTHEADER: '#studentheader',\n TABLEHEADER: 'th.header',\n BEHAT: 'body.behat-site',\n USERDROPDOWN: '.userrow th .dropdown',\n LASTROW: '.lastrow',\n};\n\n/**\n * Initialize module\n */\nexport const init = () => {\n // The sticky positioning attributed to the user column cells affects the stacking context and makes the dropdowns\n // within these cells to be cut off. To solve this problem, whenever one of these action menus (dropdowns) is opened\n // we need to manually bump up the z-index value of the parent container element and revert once closed.\n $(SELECTORS.USERDROPDOWN).on('show.bs.dropdown hide.bs.dropdown', (e) => {\n // The closest heading element has sticky positioning which affects the stacking context in this case.\n e.target.closest(SELECTORS.TABLEHEADER).classList.toggle('actions-menu-active');\n });\n\n const lastRow = document.querySelector(SELECTORS.LASTROW);\n // Ensure that the last row is not a user row before defining the intersection observer.\n if (!lastRow.classList.contains('userrow')) {\n // Register an observer that will bump up the z-index value of the last row when it's pinned to prevent the row\n // being cut-off by the user column cells or other components within the report table that have higher z-index\n // values.\n const observer = new IntersectionObserver(\n ([e]) => e.target.classList.toggle('pinned', e.intersectionRatio < 1),\n {threshold: [1]}\n );\n observer.observe(lastRow);\n }\n\n if (!document.querySelector(SELECTORS.BEHAT)) {\n const grader = document.querySelector(SELECTORS.GRADEPARENT);\n const tableHeaders = grader.querySelectorAll(SELECTORS.TABLEHEADER);\n const studentHeader = grader.querySelector(SELECTORS.STUDENTHEADER);\n const leftOffset = getComputedStyle(studentHeader).getPropertyValue('left');\n const rightOffset = getComputedStyle(studentHeader).getPropertyValue('right');\n\n tableHeaders.forEach((tableHeader) => {\n if (tableHeader.colSpan > 1) {\n const addOffset = (tableHeader.offsetWidth - studentHeader.offsetWidth);\n if (window.right_to_left()) {\n tableHeader.style.right = 'calc(' + rightOffset + ' - ' + addOffset + 'px )';\n } else {\n tableHeader.style.left = 'calc(' + leftOffset + ' - ' + addOffset + 'px )';\n }\n }\n });\n }\n};\n"],"names":["SELECTORS","on","e","target","closest","classList","toggle","lastRow","document","querySelector","contains","IntersectionObserver","_ref","intersectionRatio","threshold","observe","grader","tableHeaders","querySelectorAll","studentHeader","leftOffset","getComputedStyle","getPropertyValue","rightOffset","forEach","tableHeader","colSpan","addOffset","offsetWidth","window","right_to_left","style","right","left"],"mappings":";;;;;;;gJAyBMA,sBACW,eADXA,wBAEa,iBAFbA,sBAGW,YAHXA,gBAIK,kBAJLA,uBAKY,wBALZA,kBAMO,yBAMO,yBAIdA,wBAAwBC,GAAG,qCAAsCC,IAE/DA,EAAEC,OAAOC,QAAQJ,uBAAuBK,UAAUC,OAAO,gCAGvDC,QAAUC,SAASC,cAAcT,uBAElCO,QAAQF,UAAUK,SAAS,WAAY,CAIvB,IAAIC,sBACjBC,WAAEV,eAAOA,EAAEC,OAAOE,UAAUC,OAAO,SAAUJ,EAAEW,kBAAoB,KACnE,CAACC,UAAW,CAAC,KAERC,QAAQR,aAGhBC,SAASC,cAAcT,iBAAkB,OACpCgB,OAASR,SAASC,cAAcT,uBAChCiB,aAAeD,OAAOE,iBAAiBlB,uBACvCmB,cAAgBH,OAAOP,cAAcT,yBACrCoB,WAAaC,iBAAiBF,eAAeG,iBAAiB,QAC9DC,YAAcF,iBAAiBF,eAAeG,iBAAiB,SAErEL,aAAaO,SAASC,iBACdA,YAAYC,QAAU,EAAG,OACnBC,UAAaF,YAAYG,YAAcT,cAAcS,YACvDC,OAAOC,gBACPL,YAAYM,MAAMC,MAAQ,QAAUT,YAAc,MAAQI,UAAY,OAEtEF,YAAYM,MAAME,KAAO,QAAUb,WAAa,MAAQO,UAAY"} \ No newline at end of file diff --git a/grade/report/grader/amd/src/stickycolspan.js b/grade/report/grader/amd/src/stickycolspan.js index 456b2cc79f4..68226205c93 100644 --- a/grade/report/grader/amd/src/stickycolspan.js +++ b/grade/report/grader/amd/src/stickycolspan.js @@ -29,7 +29,7 @@ const SELECTORS = { TABLEHEADER: 'th.header', BEHAT: 'body.behat-site', USERDROPDOWN: '.userrow th .dropdown', - AVERAGEROWHEADER: '.lastrow th', + LASTROW: '.lastrow', }; /** @@ -43,14 +43,19 @@ export const init = () => { // The closest heading element has sticky positioning which affects the stacking context in this case. e.target.closest(SELECTORS.TABLEHEADER).classList.toggle('actions-menu-active'); }); - // Register an observer that will bump up the z-index value of the average overall row when it's pinned to prevent - // the row being cut-off by the user column cells or other components within the report table that have higher - // z-index values. - const observer = new IntersectionObserver( - ([e]) => e.target.closest('tr').classList.toggle('pinned', e.intersectionRatio < 1), - {threshold: [1]} - ); - observer.observe(document.querySelector(SELECTORS.AVERAGEROWHEADER)); + + const lastRow = document.querySelector(SELECTORS.LASTROW); + // Ensure that the last row is not a user row before defining the intersection observer. + if (!lastRow.classList.contains('userrow')) { + // Register an observer that will bump up the z-index value of the last row when it's pinned to prevent the row + // being cut-off by the user column cells or other components within the report table that have higher z-index + // values. + const observer = new IntersectionObserver( + ([e]) => e.target.classList.toggle('pinned', e.intersectionRatio < 1), + {threshold: [1]} + ); + observer.observe(lastRow); + } if (!document.querySelector(SELECTORS.BEHAT)) { const grader = document.querySelector(SELECTORS.GRADEPARENT); diff --git a/theme/boost/scss/moodle/grade.scss b/theme/boost/scss/moodle/grade.scss index 238afbf84c1..243f8e0c8c1 100644 --- a/theme/boost/scss/moodle/grade.scss +++ b/theme/boost/scss/moodle/grade.scss @@ -543,12 +543,15 @@ } tr.lastrow { - position: sticky; - // Hack used by the observer to help detecting when the sticky 'Overall average' row is pinned. */ - bottom: -1px; - &.pinned { - z-index: 4; + &:not(.userrow) { + position: sticky; + // Hack used by the observer to help detecting when the sticky last row is pinned. */ + bottom: -1px; + + &.pinned { + z-index: 4; + } } td, diff --git a/theme/boost/style/moodle.css b/theme/boost/style/moodle.css index b8f6fdddcfd..334aa725818 100644 --- a/theme/boost/style/moodle.css +++ b/theme/boost/style/moodle.css @@ -35023,11 +35023,11 @@ p.arrow_button { .path-grade-report-grader .gradeparent tr.userrow th.actions-menu-active { z-index: 3; } -.path-grade-report-grader .gradeparent tr.lastrow { +.path-grade-report-grader .gradeparent tr.lastrow:not(.userrow) { position: sticky; bottom: -1px; } -.path-grade-report-grader .gradeparent tr.lastrow.pinned { +.path-grade-report-grader .gradeparent tr.lastrow:not(.userrow).pinned { z-index: 4; } .path-grade-report-grader .gradeparent tr.lastrow td, diff --git a/theme/classic/style/moodle.css b/theme/classic/style/moodle.css index 8fd8263b4d5..568ca21a1d9 100644 --- a/theme/classic/style/moodle.css +++ b/theme/classic/style/moodle.css @@ -35023,11 +35023,11 @@ p.arrow_button { .path-grade-report-grader .gradeparent tr.userrow th.actions-menu-active { z-index: 3; } -.path-grade-report-grader .gradeparent tr.lastrow { +.path-grade-report-grader .gradeparent tr.lastrow:not(.userrow) { position: sticky; bottom: -1px; } -.path-grade-report-grader .gradeparent tr.lastrow.pinned { +.path-grade-report-grader .gradeparent tr.lastrow:not(.userrow).pinned { z-index: 4; } .path-grade-report-grader .gradeparent tr.lastrow td,