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-17 15:13:48 +07:00
parent e6c92dc291
commit 83d9bb6ffb
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
+74 -50
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');
}
}
}
/**