1- /* global prplSuggestedTask, prplTerms */
1+ /* global prplSuggestedTask, prplTerms, prplL10n */
22/*
33 * Widget: Todo
44 *
55 * A widget that displays a todo list.
66 *
7- * Dependencies: wp-api, progress-planner/suggested-task, wp-util, wp-a11y, progress-planner/grid-masonry, progress-planner/celebrate, progress-planner/suggested-task-terms
7+ * Dependencies: wp-api, progress-planner/suggested-task, wp-util, wp-a11y, progress-planner/grid-masonry, progress-planner/celebrate, progress-planner/suggested-task-terms, progress-planner/l10n
88 */
99
1010const prplTodoWidget = {
@@ -160,6 +160,11 @@ const prplTodoWidget = {
160160 // Remove the loader.
161161 prplTodoWidget . removeLoader ( ) ;
162162
163+ // Announce to screen readers.
164+ prplTodoWidget . announceToScreenReader (
165+ prplL10n ( 'taskAddedSuccessfully' )
166+ ) ;
167+
163168 // Resize the grid items.
164169 window . dispatchEvent (
165170 new CustomEvent ( 'prpl/grid/resize' )
@@ -174,12 +179,40 @@ const prplTodoWidget = {
174179 } ) ;
175180 } ,
176181
182+ /**
183+ * Announce to screen readers.
184+ *
185+ * @param {string } message The message to announce.
186+ * @param {string } priority The priority ('polite' or 'assertive').
187+ */
188+ announceToScreenReader : ( message , priority = 'polite' ) => {
189+ // Use WordPress a11y speak if available.
190+ if ( 'undefined' !== typeof wp && wp . a11y && wp . a11y . speak ) {
191+ wp . a11y . speak ( message , priority ) ;
192+ } else {
193+ // Fallback to ARIA live region.
194+ const liveRegion = document . getElementById (
195+ 'todo-aria-live-region'
196+ ) ;
197+ if ( liveRegion ) {
198+ liveRegion . textContent = message ;
199+ setTimeout ( ( ) => {
200+ liveRegion . textContent = '' ;
201+ } , 1000 ) ;
202+ }
203+ }
204+ } ,
205+
177206 /**
178207 * Add the loader.
179208 */
180209 addLoader : ( ) => {
181210 const loader = document . createElement ( 'span' ) ;
211+ const loadingTasksText = prplL10n ( 'loadingTasks' ) ;
182212 loader . className = 'prpl-loader' ;
213+ loader . setAttribute ( 'role' , 'status' ) ;
214+ loader . setAttribute ( 'aria-live' , 'polite' ) ;
215+ loader . innerHTML = `<span class="screen-reader-text">${ loadingTasksText } </span>` ;
183216 document . getElementById ( 'todo-list' ) . appendChild ( loader ) ;
184217 } ,
185218
@@ -220,12 +253,25 @@ const prplTodoWidget = {
220253 * Delete all completed tasks.
221254 */
222255 deleteAllCompletedTasks : ( ) => {
223- document
224- . querySelectorAll ( '#todo-list-completed .prpl-suggested-task' )
225- . forEach ( ( item ) => {
226- const postId = parseInt ( item . getAttribute ( 'data-post-id' ) ) ;
227- prplSuggestedTask . trash ( postId ) ;
228- } ) ;
256+ const items = document . querySelectorAll (
257+ '#todo-list-completed .prpl-suggested-task'
258+ ) ;
259+ const itemCount = items . length ;
260+
261+ items . forEach ( ( item ) => {
262+ const postId = parseInt ( item . getAttribute ( 'data-post-id' ) ) ;
263+ prplSuggestedTask . trash ( postId ) ;
264+ } ) ;
265+
266+ // Announce to screen readers.
267+ const tasksWord =
268+ itemCount === 1
269+ ? prplL10n ( 'taskDeleted' )
270+ : prplL10n ( 'tasksDeleted' ) ;
271+ prplTodoWidget . announceToScreenReader (
272+ `${ itemCount } ${ tasksWord } ` ,
273+ 'assertive'
274+ ) ;
229275
230276 // Resize event will be triggered by the trash function.
231277 } ,
@@ -237,6 +283,27 @@ document
237283 window . dispatchEvent ( new CustomEvent ( 'prpl/grid/resize' ) ) ;
238284 } ) ;
239285
286+ // Add event listener for delete all button.
287+ document
288+ . getElementById ( 'todo-list-completed-delete-all' )
289+ ?. addEventListener ( 'click' , ( ) => {
290+ prplTodoWidget . showDeleteAllPopover ( ) ;
291+ } ) ;
292+
293+ // Add event listener for cancel button in delete all popover.
294+ document
295+ . getElementById ( 'todo-list-completed-delete-all-cancel' )
296+ ?. addEventListener ( 'click' , ( ) => {
297+ prplTodoWidget . closeDeleteAllPopover ( ) ;
298+ } ) ;
299+
300+ // Add event listener for confirm button in delete all popover.
301+ document
302+ . getElementById ( 'todo-list-completed-delete-all-confirm' )
303+ ?. addEventListener ( 'click' , ( ) => {
304+ prplTodoWidget . deleteAllCompletedTasksAndClosePopover ( ) ;
305+ } ) ;
306+
240307document . addEventListener ( 'prpl/suggestedTask/itemInjected' , ( event ) => {
241308 if ( 'todo-list' !== event . detail . listId ) {
242309 return ;
0 commit comments