From 7e400c3db0b02caa3652fb32af07e15495de2c2a Mon Sep 17 00:00:00 2001 From: Marcel Werk Date: Sat, 6 Oct 2018 22:56:46 +0200 Subject: [PATCH] Improved a11y of 'columnMark' checkboxes See #2713 --- .../templates/headIncludeJavaScript.tpl | 2 + .../install/files/acp/templates/header.tpl | 2 + .../WoltLabSuite/Core/Controller/Clipboard.js | 67 +++++++++++++++++++ wcfsetup/install/lang/de.xml | 2 + wcfsetup/install/lang/en.xml | 2 + 5 files changed, 75 insertions(+) diff --git a/com.woltlab.wcf/templates/headIncludeJavaScript.tpl b/com.woltlab.wcf/templates/headIncludeJavaScript.tpl index 0a6b88af46..df510ce369 100644 --- a/com.woltlab.wcf/templates/headIncludeJavaScript.tpl +++ b/com.woltlab.wcf/templates/headIncludeJavaScript.tpl @@ -50,6 +50,8 @@ requirejs.config({ '__months': [ '{lang}wcf.date.month.january{/lang}', '{lang}wcf.date.month.february{/lang}', '{lang}wcf.date.month.march{/lang}', '{lang}wcf.date.month.april{/lang}', '{lang}wcf.date.month.may{/lang}', '{lang}wcf.date.month.june{/lang}', '{lang}wcf.date.month.july{/lang}', '{lang}wcf.date.month.august{/lang}', '{lang}wcf.date.month.september{/lang}', '{lang}wcf.date.month.october{/lang}', '{lang}wcf.date.month.november{/lang}', '{lang}wcf.date.month.december{/lang}' ], '__monthsShort': [ '{lang}wcf.date.month.short.jan{/lang}', '{lang}wcf.date.month.short.feb{/lang}', '{lang}wcf.date.month.short.mar{/lang}', '{lang}wcf.date.month.short.apr{/lang}', '{lang}wcf.date.month.short.may{/lang}', '{lang}wcf.date.month.short.jun{/lang}', '{lang}wcf.date.month.short.jul{/lang}', '{lang}wcf.date.month.short.aug{/lang}', '{lang}wcf.date.month.short.sep{/lang}', '{lang}wcf.date.month.short.oct{/lang}', '{lang}wcf.date.month.short.nov{/lang}', '{lang}wcf.date.month.short.dec{/lang}' ], 'wcf.clipboard.item.unmarkAll': '{lang}wcf.clipboard.item.unmarkAll{/lang}', + 'wcf.clipboard.item.markAll': '{lang}wcf.clipboard.item.markAll{/lang}', + 'wcf.clipboard.item.mark': '{lang}wcf.clipboard.item.mark{/lang}', 'wcf.date.relative.now': '{lang __literal=true}wcf.date.relative.now{/lang}', 'wcf.date.relative.minutes': '{capture assign=relativeMinutes}{lang __literal=true}wcf.date.relative.minutes{/lang}{/capture}{@$relativeMinutes|encodeJS}', 'wcf.date.relative.hours': '{capture assign=relativeHours}{lang __literal=true}wcf.date.relative.hours{/lang}{/capture}{@$relativeHours|encodeJS}', diff --git a/wcfsetup/install/files/acp/templates/header.tpl b/wcfsetup/install/files/acp/templates/header.tpl index 2372bf6245..5be17cdc46 100644 --- a/wcfsetup/install/files/acp/templates/header.tpl +++ b/wcfsetup/install/files/acp/templates/header.tpl @@ -67,6 +67,8 @@ '__monthsShort': [ '{lang}wcf.date.month.short.jan{/lang}', '{lang}wcf.date.month.short.feb{/lang}', '{lang}wcf.date.month.short.mar{/lang}', '{lang}wcf.date.month.short.apr{/lang}', '{lang}wcf.date.month.short.may{/lang}', '{lang}wcf.date.month.short.jun{/lang}', '{lang}wcf.date.month.short.jul{/lang}', '{lang}wcf.date.month.short.aug{/lang}', '{lang}wcf.date.month.short.sep{/lang}', '{lang}wcf.date.month.short.oct{/lang}', '{lang}wcf.date.month.short.nov{/lang}', '{lang}wcf.date.month.short.dec{/lang}' ], 'wcf.acp.search.noResults': '{lang}wcf.acp.search.noResults{/lang}', 'wcf.clipboard.item.unmarkAll': '{lang}wcf.clipboard.item.unmarkAll{/lang}', + 'wcf.clipboard.item.markAll': '{lang}wcf.clipboard.item.markAll{/lang}', + 'wcf.clipboard.item.mark': '{lang}wcf.clipboard.item.mark{/lang}', 'wcf.date.relative.now': '{lang __literal=true}wcf.date.relative.now{/lang}', 'wcf.date.relative.minutes': '{capture assign=relativeMinutes}{lang __literal=true}wcf.date.relative.minutes{/lang}{/capture}{@$relativeMinutes|encodeJS}', 'wcf.date.relative.hours': '{capture assign=relativeHours}{lang __literal=true}wcf.date.relative.hours{/lang}{/capture}{@$relativeHours|encodeJS}', diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Controller/Clipboard.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Controller/Clipboard.js index 2be8dcb930..1be78855e6 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Controller/Clipboard.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Controller/Clipboard.js @@ -57,6 +57,7 @@ define( var _callbackUnmarkAll = null; var _addPageOverlayActiveClass = false; + var _specialCheckboxSelector = '.messageCheckboxLabel > input[type="checkbox"], .message .messageClipboardCheckbox > input[type="checkbox"], .messageGroupList .columnMark > label > input[type="checkbox"]'; /** * Clipboard API @@ -95,6 +96,10 @@ define( _options.pageClassNames.push(options.pageClassName); } + if (!Element.prototype.matches) { + Element.prototype.matches = Element.prototype.msMatchesSelector; + } + this._initContainers(); if (_options.hasMarkedItems && _elements.length) { @@ -124,6 +129,21 @@ define( if (containerData === undefined) { var markAll = elBySel('.jsClipboardMarkAll', container); + + if (markAll.matches(_specialCheckboxSelector)) { + var label = markAll.closest('label'); + elAttr(label, 'role', 'checkbox'); + elAttr(label, 'tabindex', '0'); + elAttr(label, 'aria-checked', false); + elAttr(label, 'aria-label', Language.get('wcf.clipboard.item.markAll')); + + label.addEventListener('keyup', function (event) { + if (event.keyCode === 13 || event.keyCode === 32) { + checkbox.click(); + } + }); + } + if (markAll !== null) { elData(markAll, 'container-id', containerId); markAll.addEventListener(WCF_CLICK_EVENT, this._markAll.bind(this)); @@ -145,6 +165,20 @@ define( elData(checkbox, 'container-id', containerId); (function(checkbox) { + if (checkbox.matches(_specialCheckboxSelector)) { + var label = checkbox.closest('label'); + elAttr(label, 'role', 'checkbox'); + elAttr(label, 'tabindex', '0'); + elAttr(label, 'aria-checked', false); + elAttr(label, 'aria-label', Language.get('wcf.clipboard.item.mark')); + + label.addEventListener('keyup', function (event) { + if (event.keyCode === 13 || event.keyCode === 32) { + checkbox.click(); + } + }); + } + var link = checkbox.closest('a'); if (link === null) { checkbox.addEventListener(WCF_CLICK_EVENT, _callbackCheckbox); @@ -191,6 +225,11 @@ define( _markAll: function(event) { var checkbox = event.currentTarget; var isMarked = (checkbox.nodeName !== 'INPUT' || checkbox.checked); + + if (elAttr(checkbox.parentNode, 'role') === 'checkbox') { + elAttr(checkbox.parentNode, 'aria-checked', isMarked); + } + var objectIds = []; var containerId = elData(checkbox, 'container-id'); @@ -218,6 +257,10 @@ define( } } + if (elAttr(item.parentNode, 'role') === 'checkbox') { + elAttr(item.parentNode, 'aria-checked', isMarked); + } + var clipboardObject = DomTraverse.parentByClass(checkbox, 'jsClipboardObject'); if (clipboardObject !== null) { clipboardObject.classList[(isMarked ? 'addClass' : 'removeClass')]('jsMarked'); @@ -256,6 +299,14 @@ define( } data.markAll.checked = markedAll; + + if (elAttr(data.markAll.parentNode, 'role') === 'checkbox') { + elAttr(data.markAll.parentNode, 'aria-checked', isMarked); + } + } + + if (elAttr(checkbox.parentNode, 'role') === 'checkbox') { + elAttr(checkbox.parentNode, 'aria-checked', checkbox.checked); } this._saveState(type, [ objectId ], isMarked); @@ -463,9 +514,17 @@ define( if (containerData.markAll !== null) { containerData.markAll.checked = false; + + if (elAttr(containerData.markAll.parentNode, 'role') === 'checkbox') { + elAttr(containerData.markAll.parentNode, 'aria-checked', false); + } } for (var i = 0, length = containerData.checkboxes.length; i < length; i++) { containerData.checkboxes[i].checked = false; + + if (elAttr(containerData.checkboxes[i].parentNode, 'role') === 'checkbox') { + elAttr(containerData.checkboxes[i].parentNode, 'aria-checked', false); + } } UiPageAction.remove('wcfClipboard-' + data.returnValues.objectType); @@ -614,11 +673,19 @@ define( checkbox.checked = isMarked; clipboardObject.classList[(isMarked ? 'add' : 'remove')]('jsMarked'); + + if (elAttr(checkbox.parentNode, 'role') === 'checkbox') { + elAttr(checkbox.parentNode, 'aria-checked', isMarked); + } } if (data.markAll !== null) { data.markAll.checked = markAll; + if (elAttr(data.markAll.parentNode, 'role') === 'checkbox') { + elAttr(data.markAll.parentNode, 'aria-checked', markAll); + } + var parent = data.markAll; while (parent = parent.parentNode) { if (parent instanceof Element && parent.classList.contains('columnMark')) { diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index 069d7c6833..a1b42b2478 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -2527,6 +2527,8 @@ Fehler sind beispielsweise: + + diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 04f2c51c76..8c49ecb8cd 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -2463,6 +2463,8 @@ Errors are: + + -- 2.20.1