MDL-81043 gradereport_grader: Improve gradereport_grader/collapse

- This will helps `nodesUpdate` handle asynchronous updates better
 - This also helps to fix Random Behat failure
This commit is contained in:
Huong Nguyen 2025-01-15 16:05:11 +07:00
parent e6c92dc291
commit 83d9bb6ffb
No known key found for this signature in database
GPG Key ID: 40D88AB693A3E72A
3 changed files with 76 additions and 52 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

@ -57,6 +57,7 @@ const selectors = {
placeholder: '.collapsecolumndropdown [data-region="placeholder"]',
fullDropdown: '.collapsecolumndropdown',
searchResultContainer: '.searchresultitemscontainer',
cellMenuButton: '.cellmenubtn',
};
const countIndicator = document.querySelector(selectors.count);
@ -196,6 +197,7 @@ export default class ColumnSearch extends search_combobox {
async docClickHandler(e) {
if (e.target.dataset.hider === selectors.hider) {
e.preventDefault();
const pendingPromise = new Pending('gradereport_grader/collapse:docClickHandler:hide');
const desiredToHide = e.target.closest(selectors.colVal) ?
e.target.closest(selectors.colVal)?.dataset.col :
e.target.closest(selectors.itemVal)?.dataset.itemid;
@ -205,11 +207,13 @@ export default class ColumnSearch extends search_combobox {
}
await this.prefcountpipe();
this.nodesUpdate(desiredToHide);
await this.nodesUpdate(desiredToHide);
pendingPromise.resolve();
}
if (e.target.closest('button')?.dataset.hider === selectors.expand) {
e.preventDefault();
const pendingPromise = new Pending('gradereport_grader/collapse:docClickHandler:expand');
const desiredToHide = e.target.closest(selectors.colVal) ?
e.target.closest(selectors.colVal)?.dataset.col :
e.target.closest(selectors.itemVal)?.dataset.itemid;
@ -218,8 +222,9 @@ export default class ColumnSearch extends search_combobox {
await this.prefcountpipe();
this.nodesUpdate(e.target.closest(selectors.colVal)?.dataset.col);
this.nodesUpdate(e.target.closest(selectors.colVal)?.dataset.itemid);
await this.nodesUpdate(e.target.closest(selectors.colVal)?.dataset.col);
await this.nodesUpdate(e.target.closest(selectors.colVal)?.dataset.itemid);
pendingPromise.resolve();
}
}
@ -331,11 +336,14 @@ export default class ColumnSearch extends search_combobox {
});
}
nodesUpdate(item) {
async nodesUpdate(item) {
const colNodesToHide = [...document.querySelectorAll(`[data-col="${item}"]`)];
const itemIDNodesToHide = [...document.querySelectorAll(`[data-itemid="${item}"]`)];
this.nodes = [...colNodesToHide, ...itemIDNodesToHide];
this.updateDisplay();
const elements = [...colNodesToHide, ...itemIDNodesToHide];
if (elements && elements.length) {
const pendingPromise = new Pending('gradereport_grader/collapse:nodesUpdate:' + item);
this.updateDisplay(elements).then(() => pendingPromise.resolve()).catch(Notification.exception);
}
}
/**
@ -400,52 +408,68 @@ export default class ColumnSearch extends search_combobox {
/**
* With an array of nodes, switch their classes and values.
*
* @param {Array} elements The elements to update.
*/
updateDisplay() {
this.nodes.forEach((element) => {
const content = element.querySelector(selectors.content);
const sort = element.querySelector(selectors.sort);
const expandButton = element.querySelector(selectors.expandbutton);
const rangeRowCell = element.querySelector(selectors.rangerowcell);
const avgRowCell = element.querySelector(selectors.avgrowcell);
const nodeSet = [
element.querySelector(selectors.menu),
element.querySelector(selectors.icons),
content
];
// This can be further improved to reduce redundant similar calls.
if (element.classList.contains('cell')) {
// The column is actively being sorted, lets reset that and reload the page.
if (sort !== null) {
window.location = this.defaultSort;
}
if (content === null) {
// If it's not a content cell, it must be an overall average or a range cell.
const rowCell = avgRowCell ?? rangeRowCell;
rowCell?.classList.toggle('d-none');
} else if (content.classList.contains('d-none')) {
// We should always have content but some cells do not contain menus or other actions.
element.classList.remove('collapsed');
// If there are many nodes, apply the following.
if (content.childNodes.length > 1) {
content.classList.add('d-flex');
}
nodeSet.forEach(node => {
node?.classList.remove('d-none');
});
expandButton?.classList.add('d-none');
} else {
element.classList.add('collapsed');
content.classList.remove('d-flex');
nodeSet.forEach(node => {
node?.classList.add('d-none');
});
expandButton?.classList.remove('d-none');
}
}
async updateDisplay(elements) {
const promises = [];
elements.forEach((element) => {
promises.push(this.updateDisplayForElement(element));
});
await Promise.all(promises);
}
/**
* Update display for given element, switch its classes and values.
*
* @param {HTMLElement} element The element to update.
*/
async updateDisplayForElement(element) {
const content = element.querySelector(selectors.content);
const sort = element.querySelector(selectors.sort);
const expandButton = element.querySelector(selectors.expandbutton);
const rangeRowCell = element.querySelector(selectors.rangerowcell);
const avgRowCell = element.querySelector(selectors.avgrowcell);
const cellMenuButton = element.querySelector(selectors.cellMenuButton);
const nodeSet = [
element.querySelector(selectors.menu),
element.querySelector(selectors.icons),
content
];
// This can be further improved to reduce redundant similar calls.
if (element.classList.contains('cell')) {
// The column is actively being sorted, lets reset that and reload the page.
if (sort !== null) {
window.location = this.defaultSort;
}
if (content === null) {
// If it's not a content cell, it must be an overall average or a range cell.
const rowCell = avgRowCell ?? rangeRowCell;
rowCell?.classList.toggle('d-none');
} else if (content.classList.contains('d-none')) {
// We should always have content but some cells do not contain menus or other actions.
element.classList.remove('collapsed');
// If there are many nodes, apply the following.
if (content.childNodes.length > 1) {
content.classList.add('d-flex');
}
nodeSet.forEach(node => {
node?.classList.remove('d-none');
});
expandButton?.classList.add('d-none');
cellMenuButton?.focus();
} else {
element.classList.add('collapsed');
content.classList.remove('d-flex');
nodeSet.forEach(node => {
node?.classList.add('d-none');
});
expandButton?.classList.remove('d-none');
}
}
}
/**