Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add aria labels to toolbar #3639

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions modules/toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ class Toolbar extends Module {
format = format.slice('ql-'.length);
if (input.tagName === 'BUTTON') {
input.setAttribute('type', 'button');
input.setAttribute('aria-label', format);
if (input.value) {
input.setAttribute('aria-label', `${format} ${input.value}`);
}
if (format === 'direction') {
input.setAttribute(
'aria-label',
`Text ${format} ${
input.value === 'rtl' ? 'right to left' : 'left to right'
}`,
);
}
}
if (
this.handlers[format] == null &&
Expand Down Expand Up @@ -153,9 +165,11 @@ Toolbar.DEFAULTS = {};
function addButton(container, format, value) {
const input = document.createElement('button');
input.setAttribute('type', 'button');
input.setAttribute('aria-label', format);
input.classList.add(`ql-${format}`);
if (value != null) {
input.value = value;
input.setAttribute('aria-label', `${value} ${format}`);
}
container.appendChild(input);
}
Expand Down
32 changes: 16 additions & 16 deletions test/unit/modules/toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ describe('Toolbar', function() {
addControls(this.container, ['bold', 'italic']);
expect(this.container).toEqualHTML(`
<span class="ql-formats">
<button type="button" class="ql-bold"></button>
<button type="button" class="ql-italic"></button>
<button type="button" aria-label="bold" class="ql-bold"></button>
<button type="button" aria-label="italic" class="ql-italic"></button>
</span>
`);
});
Expand All @@ -20,12 +20,12 @@ describe('Toolbar', function() {
]);
expect(this.container).toEqualHTML(`
<span class="ql-formats">
<button type="button" class="ql-bold"></button>
<button type="button" class="ql-italic"></button>
<button type="button" aria-label="bold" class="ql-bold"></button>
<button type="button" aria-label="italic" class="ql-italic"></button>
</span>
<span class="ql-formats">
<button type="button" class="ql-underline"></button>
<button type="button" class="ql-strike"></button>
<button type="button" aria-label="underline" class="ql-underline"></button>
<button type="button" aria-label="strike" class="ql-strike"></button>
</span>
`);
});
Expand All @@ -34,8 +34,8 @@ describe('Toolbar', function() {
addControls(this.container, ['bold', { header: '2' }]);
expect(this.container).toEqualHTML(`
<span class="ql-formats">
<button type="button" class="ql-bold"></button>
<button type="button" class="ql-header" value="2"></button>
<button type="button" aria-label="bold" class="ql-bold"></button>
<button type="button" aria-label="2 header" class="ql-header" value="2"></button>
</span>
`);
});
Expand Down Expand Up @@ -83,14 +83,14 @@ describe('Toolbar', function() {
</select>
</span>
<span class="ql-formats">
<button type="button" class="ql-bold"></button>
<button type="button" class="ql-italic"></button>
<button type="button" class="ql-underline"></button>
<button type="button" class="ql-strike"></button>
<button type="button" aria-label="bold" class="ql-bold"></button>
<button type="button" aria-label="italic" class="ql-italic"></button>
<button type="button" aria-label="underline" class="ql-underline"></button>
<button type="button" aria-label="strike" class="ql-strike"></button>
</span>
<span class="ql-formats">
<button type="button" class="ql-list" value="ordered"></button>
<button type="button" class="ql-list" value="bullet"></button>
<button type="button" aria-label="ordered list" class="ql-list" value="ordered"></button>
<button type="button" aria-label="bullet list" class="ql-list" value="bullet"></button>
<select class="ql-align">
<option selected="selected"></option>
<option value="center"></option>
Expand All @@ -99,8 +99,8 @@ describe('Toolbar', function() {
</select>
</span>
<span class="ql-formats">
<button type="button" class="ql-link"></button>
<button type="button" class="ql-image"></button>
<button type="button" aria-label="link" class="ql-link"></button>
<button type="button" aria-label="image" class="ql-image"></button>
</span>
`);
});
Expand Down
2 changes: 1 addition & 1 deletion test/unit/ui/picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('Picker', function() {
this.container.querySelector('.ql-picker-item:not(.ql-selected)')
.outerHTML,
).toEqualHTML(
'<span tabindex="0" role="button" class="ql-picker-item" data-value="1" data-label="1"></span>',
'<span tabindex="0" role="button" class="ql-picker-item" aria-label="1" data-value="1" data-label="1"></span>',
);
});

Expand Down
9 changes: 9 additions & 0 deletions themes/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class BaseTheme extends Theme {
buildPickers(selects, icons) {
this.pickers = Array.from(selects).map(select => {
if (select.classList.contains('ql-align')) {
select.setAttribute('aria-label', 'Align text');
if (select.querySelector('option') == null) {
fillSelect(select, ALIGNS);
}
Expand All @@ -120,6 +121,12 @@ class BaseTheme extends Theme {
select.classList.contains('ql-background') ||
select.classList.contains('ql-color')
) {
if (select.classList.contains('ql-background')) {
select.setAttribute('aria-label', 'Background color');
}
if (select.classList.contains('ql-color')) {
select.setAttribute('aria-label', 'Text color');
}
const format = select.classList.contains('ql-background')
? 'background'
: 'color';
Expand All @@ -134,10 +141,12 @@ class BaseTheme extends Theme {
}
if (select.querySelector('option') == null) {
if (select.classList.contains('ql-font')) {
select.setAttribute('aria-label', 'Select a Font');
fillSelect(select, FONTS);
} else if (select.classList.contains('ql-header')) {
fillSelect(select, HEADERS);
} else if (select.classList.contains('ql-size')) {
select.setAttribute('aria-label', 'Select a font size');
fillSelect(select, SIZES);
}
}
Expand Down
3 changes: 3 additions & 0 deletions ui/icon-picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ class IconPicker extends Picker {
this.container.classList.add('ql-icon-picker');
Array.from(this.container.querySelectorAll('.ql-picker-item')).forEach(
item => {
if (item.getAttribute('data-value') === null) {
item.setAttribute('aria-label', 'Left');
}
item.innerHTML = icons[item.getAttribute('data-value') || ''];
},
);
Expand Down
88 changes: 88 additions & 0 deletions ui/picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ class Picker {
item.classList.add('ql-picker-item');
if (option.hasAttribute('value')) {
item.setAttribute('data-value', option.getAttribute('value'));
item.setAttribute(
'aria-label',
this.getAriaLabel(option.getAttribute('value')),
);
}
if (option.textContent) {
item.setAttribute('data-label', option.textContent);
Expand All @@ -73,6 +77,90 @@ class Picker {
return item;
}

getAriaLabel(value) {
if (value.startsWith('#')) {
return this.convertHexCodeToHumanReadableString(value);
}
return value;
}

convertHexCodeToHumanReadableString(value) {
switch (value) {
case '#e60000':
return 'Electric red';
case '#ff9900':
return 'Light orange';
case '#ffff00':
return 'Yellow';
case '#008a00':
return 'Green';
case '#0066cc':
return 'Navy blue';
case '#9933ff':
return 'Blue violet';
case '#ffffff':
return 'White';
case '#facccc':
return 'Light pink';
case '#ffebcc':
return 'Light yellow';
case '#ffffcc':
return 'Cream';
case '#cce8cc':
return 'Light sage';
case '#cce0f5':
return 'Light blue';
case '#ebd6ff':
return 'Light purple';
case '#bbbbbb':
return 'Silver';
case '#f06666':
return 'Salmon';
case '#ffc266':
return 'Light orange';
case '#ffff66':
return 'Lemon';
case '#66b966':
return 'Fern';
case '#66a3e0':
return 'Cornflower blue';
case '#c285ff':
return 'Purple';
case '#888888':
return 'Gray';
case '#a10000':
return 'Dark red';
case '#b26b00':
return 'Orange-brown';
case '#b2b200':
return 'Chartreuse';
case '#006100':
return 'Forest green';
case '#0047b2':
return 'Cobalt blue';
case '#6b24b2':
return 'Deep purple';
case '#444444':
return 'Dark gray';
case '#5c0000':
return 'Dark purple';
case '#663d00':
return 'Nutmeg brown';
case '#666600':
return 'Dark yellow-green';
case '#003700':
return 'Deep fir green';
case '#002966':
return 'Midnight blue';
case '#3d1466':
return 'Deepest purple';
case '#000000':
return 'Black';
default:
return '';
}
}

buildLabel() {
const label = document.createElement('span');
label.classList.add('ql-picker-label');
Expand Down