MDL-86512 core: Ensure bulk action selection count announcement
When the bulk actions are first rendered, the item count in the aria-live region will not be announced by screen readers as aria-live regions need to be present in the DOM and changed before screen readers can announce their content. This commit ensures that the item selection count will be announced when the bulk actions get added to the DOM by calling `updateBulkItemSelection()` after rendering the bulk actions HTML. This removes the non-breaking space in the template, effectively causing a change in DOM without affecting the visuals, and allowing screen readers to announce the contents of the item count.
This commit is contained in:
+1
-1
@@ -5,6 +5,6 @@ define("core/bulkactions/bulk_actions",["exports","core/templates","core/str","c
|
||||
* @module core/bulkactions/bulk_actions
|
||||
* @copyright 2023 Mihail Geshoski <mihail@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=(obj=_templates)&&obj.__esModule?obj:{default:obj};const Selectors_stickyFooterContainer="#sticky-footer",Selectors_selectedItemsCountContainer='[data-type="bulkactions"] [data-for="bulkcount"]',Selectors_cancelBulkActionModeElement='[data-type="bulkactions"] [data-action="bulkcancel"]',Selectors_bulkModeContainer='[data-type="bulkactions"]',Selectors_bulkActionsContainer='[data-type="bulkactions"] [data-for="bulktools"]';return _exports.default=class{constructor(){let maxButtons=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(_defineProperty(this,"initialStickyFooterContent",null),_defineProperty(this,"selectedItems",[]),_defineProperty(this,"isBulkActionsModeEnabled",!1),_defineProperty(this,"maxButtons",5),!this.getStickyFooterContainer())throw new Error("Sticky footer not found.");this.initialStickyFooterContent=this.getStickyFooterContainer().innerHTML,maxButtons&&(this.maxButtons=maxButtons),this.registerItemSelectChangeEvent((async()=>{this.selectedItems=this.getSelectedItems(),this.selectedItems.length>0?this.isBulkActionsModeEnabled?await this.updateBulkItemSelection():await this.enableBulkActionsMode():this.disableBulkActionsMode()}))}getBulkActions(){throw new Error("getBulkActions() must be implemented in ".concat(this.constructor.name))}getSelectedItems(){throw new Error("getSelectedItems() must be implemented in ".concat(this.constructor.name))}registerItemSelectChangeEvent(eventHandler){throw new Error("registerItemSelectChangeEvent(".concat(eventHandler,") must be implemented in ").concat(this.constructor.name))}deselectItem(selectedItem){throw new Error("deselectItem(".concat(selectedItem,") must be implemented in ").concat(this.constructor.name))}getStickyFooterContainer(){return document.querySelector(Selectors_stickyFooterContainer)}async enableBulkActionsMode(){(0,_stickyFooter.enableStickyFooter)(),this.getStickyFooterContainer().innerHTML=await this.renderBulkActions();const bulkModeContainer=this.getStickyFooterContainer().querySelector(Selectors_bulkModeContainer),bulkActionsContainer=bulkModeContainer.querySelector(Selectors_bulkActionsContainer);this.getBulkActions().forEach((bulkAction=>{bulkAction.registerListenerEvents(bulkActionsContainer),bulkAction.setSelectedItems(this.selectedItems)})),bulkModeContainer.addEventListener("click",(e=>{e.target.closest(Selectors_cancelBulkActionModeElement)&&(this.selectedItems.forEach((item=>{this.deselectItem(item)})),this.disableBulkActionsMode())})),this.isBulkActionsModeEnabled=!0}disableBulkActionsMode(){this.initialStickyFooterContent.length>0?this.getStickyFooterContainer().innerHTML=this.initialStickyFooterContent:(0,_stickyFooter.disableStickyFooter)(),this.isBulkActionsModeEnabled=!1}async renderBulkActions(){const data={bulkselectioncount:this.selectedItems.length,actions:[],moreactions:[],hasmoreactions:!1},bulkActions=this.getBulkActions(),showMoreButton=bulkActions.length>this.maxButtons;return(await Promise.all(bulkActions.map(((bulkAction,index)=>bulkAction.renderBulkActionTrigger(showMoreButton&&index>=this.maxButtons-1,index))))).forEach(((actionTrigger,index)=>{showMoreButton&&index>=this.maxButtons-1?data.moreactions.push({actiontrigger:actionTrigger}):data.actions.push({actiontrigger:actionTrigger})})),data.hasmoreactions=data.moreactions.length>0,_templates.default.render("core/bulkactions/bulk_actions",data)}async updateBulkItemSelection(){const bulkSelection=await(0,_str.get_string)("bulkselection","core",this.selectedItems.length);document.querySelector(Selectors_selectedItemsCountContainer).innerHTML=bulkSelection}},_exports.default}));
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=(obj=_templates)&&obj.__esModule?obj:{default:obj};const Selectors_stickyFooterContainer="#sticky-footer",Selectors_selectedItemsCountContainer='[data-type="bulkactions"] [data-for="bulkcount"]',Selectors_cancelBulkActionModeElement='[data-type="bulkactions"] [data-action="bulkcancel"]',Selectors_bulkModeContainer='[data-type="bulkactions"]',Selectors_bulkActionsContainer='[data-type="bulkactions"] [data-for="bulktools"]';return _exports.default=class{constructor(){let maxButtons=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(_defineProperty(this,"initialStickyFooterContent",null),_defineProperty(this,"selectedItems",[]),_defineProperty(this,"isBulkActionsModeEnabled",!1),_defineProperty(this,"maxButtons",5),!this.getStickyFooterContainer())throw new Error("Sticky footer not found.");this.initialStickyFooterContent=this.getStickyFooterContainer().innerHTML,maxButtons&&(this.maxButtons=maxButtons),this.registerItemSelectChangeEvent((async()=>{this.selectedItems=this.getSelectedItems(),this.selectedItems.length>0?this.isBulkActionsModeEnabled?await this.updateBulkItemSelection():await this.enableBulkActionsMode():this.disableBulkActionsMode()}))}getBulkActions(){throw new Error("getBulkActions() must be implemented in ".concat(this.constructor.name))}getSelectedItems(){throw new Error("getSelectedItems() must be implemented in ".concat(this.constructor.name))}registerItemSelectChangeEvent(eventHandler){throw new Error("registerItemSelectChangeEvent(".concat(eventHandler,") must be implemented in ").concat(this.constructor.name))}deselectItem(selectedItem){throw new Error("deselectItem(".concat(selectedItem,") must be implemented in ").concat(this.constructor.name))}getStickyFooterContainer(){return document.querySelector(Selectors_stickyFooterContainer)}async enableBulkActionsMode(){(0,_stickyFooter.enableStickyFooter)(),this.getStickyFooterContainer().innerHTML=await this.renderBulkActions();const bulkModeContainer=this.getStickyFooterContainer().querySelector(Selectors_bulkModeContainer),bulkActionsContainer=bulkModeContainer.querySelector(Selectors_bulkActionsContainer);this.getBulkActions().forEach((bulkAction=>{bulkAction.registerListenerEvents(bulkActionsContainer),bulkAction.setSelectedItems(this.selectedItems)})),bulkModeContainer.addEventListener("click",(e=>{e.target.closest(Selectors_cancelBulkActionModeElement)&&(this.selectedItems.forEach((item=>{this.deselectItem(item)})),this.disableBulkActionsMode())})),this.isBulkActionsModeEnabled=!0,setTimeout((async()=>{await this.updateBulkItemSelection()}),300)}disableBulkActionsMode(){this.initialStickyFooterContent.length>0?this.getStickyFooterContainer().innerHTML=this.initialStickyFooterContent:(0,_stickyFooter.disableStickyFooter)(),this.isBulkActionsModeEnabled=!1}async renderBulkActions(){const data={bulkselectioncount:this.selectedItems.length,actions:[],moreactions:[],hasmoreactions:!1},bulkActions=this.getBulkActions(),showMoreButton=bulkActions.length>this.maxButtons;return(await Promise.all(bulkActions.map(((bulkAction,index)=>bulkAction.renderBulkActionTrigger(showMoreButton&&index>=this.maxButtons-1,index))))).forEach(((actionTrigger,index)=>{showMoreButton&&index>=this.maxButtons-1?data.moreactions.push({actiontrigger:actionTrigger}):data.actions.push({actiontrigger:actionTrigger})})),data.hasmoreactions=data.moreactions.length>0,_templates.default.render("core/bulkactions/bulk_actions",data)}async updateBulkItemSelection(){const bulkSelection=await(0,_str.get_string)("bulkselection","core",this.selectedItems.length);document.querySelector(Selectors_selectedItemsCountContainer).innerHTML=bulkSelection}},_exports.default}));
|
||||
|
||||
//# sourceMappingURL=bulk_actions.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -172,6 +172,14 @@ export default class BulkActions {
|
||||
}
|
||||
});
|
||||
this.isBulkActionsModeEnabled = true;
|
||||
|
||||
// Calling `renderBulkActions()` already renders the item selection count.
|
||||
// Because of this, screen readers will not announce the item selection count on first load given that aria-live regions
|
||||
// must be present in the DOM and have their contents changed before screen readers can announce their content.
|
||||
// So, we call `updateBulkItemSelection()` after a short delay to ensure that screen readers announce the item count.
|
||||
setTimeout(async() => {
|
||||
await this.updateBulkItemSelection();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div data-for="bulkcount" role="status">
|
||||
{{#str}} bulkselection, core, {{bulkselectioncount}} {{/str}}
|
||||
{{#str}} bulkselection, core, {{bulkselectioncount}} {{/str}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user