a11y: Every label tag needs an associated control

Closes #13070
This commit is contained in:
Matej Marušák 2019-11-05 07:07:31 +01:00 committed by Martin Pitt
parent 00d09960ac
commit cf6ecb9aad
11 changed files with 54 additions and 40 deletions

View File

@ -52,7 +52,6 @@
"jsx-a11y/no-static-element-interactions": "off",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/label-has-associated-control": "off",
"jsx-a11y/anchor-is-valid": "off",
"jsx-a11y/no-autofocus": "off",
"jsx-a11y/no-noninteractive-element-interactions": "off",

View File

@ -156,7 +156,7 @@
<script id="network-vlan-settings-template" type="x-template/mustache">
<form class="ct-form">
<label class="control-label" translatable="yes">Parent</label>
<label class="control-label" for="network-vlan-settings-parent-select" translatable="yes">Parent</label>
<div id="network-vlan-settings-parent-select">
{{! the rather complex dropdown-select will be created dynamically via jquery }}
</div>
@ -284,17 +284,17 @@
</div>
</div>
<label class="control-label" translatable="yes">Mode</label>
<label class="control-label" for="network-bond-settings-mode-select" translatable="yes">Mode</label>
<div id="network-bond-settings-mode-select">
{{! the rather complex dropdown-select will be created dynamically via jquery }}
</div>
<label class="control-label" translatable="yes">Primary</label>
<label class="control-label" for="network-bond-settings-primary-select" translatable="yes">Primary</label>
<div id="network-bond-settings-primary-select">
{{! the rather complex dropdown-select will be created dynamically via jquery }}
</div>
<label class="control-label" translatable="yes">Link Monitoring</label>
<label class="control-label" for="network-bond-settings-link-monitoring-select" translatable="yes">Link Monitoring</label>
<div id="network-bond-settings-link-monitoring-select">
{{! the rather complex dropdown-select will be created dynamically via jquery }}
</div>
@ -328,17 +328,17 @@
{{! ports will be rendered into here as a list of checkboxes }}
</div>
<label class="control-label" translatable="yes">Runner</label>
<label class="control-label" for="network-team-settings-runner-select" translatable="yes">Runner</label>
<div id="network-team-settings-runner-select">
{{! the rather complex dropdown-select will be created dynamically via jquery }}
</div>
<label class="control-label" translatable="yes">Balancer</label>
<label class="control-label" for="network-team-settings-balancer-select" translatable="yes">Balancer</label>
<div id="network-team-settings-balancer-select">
{{! the rather complex dropdown-select will be created dynamically via jquery }}
</div>
<label class="control-label" translatable="yes">Link Watch</label>
<label class="control-label" for="network-team-settings-link-watch-select" translatable="yes">Link Watch</label>
<div id="network-team-settings-link-watch-select">
{{! the rather complex dropdown-select will be created dynamically via jquery }}
</div>

View File

@ -2684,8 +2684,8 @@ PageNetworkInterface.prototype = {
$('<tr>').append(
$('<td>').text(_("General")),
$('<td class="networking-controls">').append(
$('<label>').append(
$('<input type="checkbox">')
$('<label for="autoreconnect">').append(
$('<input type="checkbox" id="autoreconnect">')
.prop('checked', settings.connection.autoconnect)
.change(function () {
settings.connection.autoconnect = $(this).prop('checked');
@ -3746,6 +3746,9 @@ PageNetworkBondSettings.prototype = {
.replaceWith(primary_btn = slave_chooser_btn(change_mode, slaves_element, "form-control"));
body.find('#network-bond-settings-link-monitoring-select')
.replaceWith(monitoring_btn = select_btn(change_monitoring, bond_monitoring_choices, "form-control"));
mode_btn.attr("id", "network-bond-settings-mode-select");
primary_btn.attr("id", "network-bond-settings-primary-select");
monitoring_btn.attr("id", "network-bond-settings-link-monitoring-select");
interval_input = body.find('#network-bond-settings-monitoring-interval-input');
interval_input.change(change_monitoring);
@ -3946,6 +3949,9 @@ PageNetworkTeamSettings.prototype = {
.replaceWith(balancer_btn = select_btn(change_balancer, team_balancer_choices, "form-control"));
body.find('#network-team-settings-link-watch-select')
.replaceWith(watch_btn = select_btn(change_watch, team_watch_choices, "form-control"));
runner_btn.attr("id", "network-team-settings-runner-select");
balancer_btn.attr("id", "network-team-settings-balancer-select");
watch_btn.attr("id", "network-team-settings-link-watch-select");
interval_input = body.find('#network-team-settings-ping-interval-input');
interval_input.change(change_watch);
@ -4421,6 +4427,7 @@ PageNetworkVlanSettings.prototype = {
interface_name: options.interface_name
}));
parent_btn = select_btn(change, parent_choices, "form-control");
parent_btn.attr('id', 'network-vlan-settings-parent-select');
body.find('#network-vlan-settings-parent-select').replaceWith(parent_btn);
id_input = body.find('#network-vlan-settings-vlan-id-input')
.change(change)

View File

@ -36,7 +36,7 @@ export class PatternDialogBody extends React.Component {
<label className="control-label" htmlFor="control-1">Label</label>
<input id="control-1" className="form-control" type="text" />
<label className="control-label">Select</label>
<label className="control-label" htmlFor="primary-select">Select</label>
<Select.Select onChange={this.selectChanged} id="primary-select">
<Select.SelectEntry data='one'>One</Select.SelectEntry>
<Select.SelectEntry data='two'>Two</Select.SelectEntry>
@ -45,18 +45,18 @@ export class PatternDialogBody extends React.Component {
<Select.SelectEntry data='four' />
</Select.Select>
<label className="control-label">Preselected</label>
<Select.Select initial="two">
<label className="control-label" htmlFor="preselected">Preselected</label>
<Select.Select initial="two" id="preselected">
<Select.SelectEntry data="one">One</Select.SelectEntry>
<Select.SelectEntry data="two">Two</Select.SelectEntry>
<Select.SelectEntry data="three">Three</Select.SelectEntry>
</Select.Select>
<label className="control-label">Empty Select</label>
<Select.Select />
<label className="control-label" htmlFor="empty-select">Empty Select</label>
<Select.Select id="empty-select" />
<label className="control-label">Nested dialog</label>
<div role="group">
<label className="control-label" htmlFor="nested">Nested dialog</label>
<div role="group" id="nested">
<button id="open-nested" onClick={ this.props.clickNested }>
Try to nest dialog
</button>

View File

@ -30,7 +30,7 @@
</div>
<form class="ct-form realms-op-join-only">
<label class="control-label" translatable="yes">Domain Address</label>
<label class="control-label" for="realms-op-address" translatable="yes">Domain Address</label>
<div class="ct-validation-wrapper">
<input id="realms-op-address" class="realms-op-field form-control" type="text" value="" />

View File

@ -201,11 +201,12 @@
<div class="credential-unlock">
<dl>
<dt>
<label translate>Password</label>
<label for="add-key-password" translate>Password</label>
</dt>
<dd>
<input class="form-control credential-password"
autocomplete="off"
id="add-key-password"
value="" type="password"/>
</dd>
<dt></dt>
@ -242,11 +243,12 @@
<div class="credential-unlock">
<dl>
<dt>
<label translatable="yes">Password</label>
<label for="ssh-key-password" translatable="yes">Password</label>
</dt>
<dd>
<input class="form-control credential-password"
autocomplete="off"
id="ssh-key-password"
value="" type="password"/>
</dd>
<dt></dt>
@ -279,27 +281,30 @@
<div class="credential-tab credential-panel" hidden>
<dl>
<dt>
<label translatable="yes">Old Password</label>
<label for="credential-old-passwd" translatable="yes">Old Password</label>
</dt>
<dd>
<input class="form-control credential-old"
autocomplete="off"
id="credential-old-passwd"
value="" type="password"/>
</dd>
<dt>
<label translatable="yes">New Password</label>
<label for="credential-new-passwd" translatable="yes">New Password</label>
</dt>
<dd>
<input class="form-control credential-new"
autocomplete="off"
id="credential-new-passwd"
value="" type="password"/>
</dd>
<dt>
<label translatable="yes">Confirm</label>
<label for="new-passwd-confirm" translatable="yes">Confirm</label>
</dt>
<dd>
<input class="form-control credential-two"
autocomplete="off"
id="new-passwd-confirm"
value="" type="password"/>
</dd>
<dt>

View File

@ -136,9 +136,9 @@
</a>
</div>
<label class="control-label" translatable="yes">Power Options</label>
<label class="control-label" for="shutdown-action" translatable="yes">Power Options</label>
<div id="shutdown-group" class="btn-group">
<button class="btn btn-default shutdown-privileged" data-action="restart"
<button class="btn btn-default shutdown-privileged" id="shutdown-action" data-action="restart"
data-container="body" translatable="yes">Restart</button>
<button data-toggle="dropdown" class="btn
btn-default dropdown-toggle
@ -156,7 +156,7 @@
</ul>
</div>
<label class="control-label" translatable="yes">Performance Profile</label>
<label class="control-label" for="tuned-status-button" translatable="yes">Performance Profile</label>
<span id="system-info-performance" hidden></span>
<label class="control-label" for="server-pmlogger-switch" translatable="yes" hidden>Store Metrics</label>
@ -372,7 +372,7 @@
<table class="form-table-ct">
<tr>
<td>
<label class="control-label" translatable="yes">Time Zone</label>
<label class="control-label" for="systime-timezones" translatable="yes">Time Zone</label>
</td>
<td>
<select class="form-control" id="systime-timezones">

View File

@ -485,7 +485,7 @@ export class ServiceDetails extends React.Component {
<hr />
{ this.props.originTemplate &&
<>
<label className="control-label" />
<div />
<span>{_("Instance of template: ")}<a href={"#/" + this.props.originTemplate}>{this.props.originTemplate}</a></span>
</>
}

View File

@ -281,7 +281,10 @@ function setup() {
.fail(show_error);
}
button.on('click', open_dialog);
button.on('click', e => {
e.preventDefault();
open_dialog();
});
tuned_service.addEventListener("changed", update_button);
update_button();

View File

@ -1,5 +1,5 @@
<div>
<span id="tuned-status-tooltip" data-html="true">
<a tabindex="0" class="action-trigger"></a>
<button class="link-button action-trigger" id="tuned-status-button"></button>
</span>
</div>

View File

@ -43,29 +43,29 @@ class TestTuned(MachineCase):
self.login_and_go("/system")
def check_status_tooltip(expected):
b.mouse("#system-info-performance .action-trigger", "mouseover")
b.mouse("#system-info-performance span", "mouseover")
b.wait_text("#system-info-performance .tooltip-inner", expected)
# move mouse away again, to let the tooltip disappear and update
b.mouse("#system-info-performance .action-trigger", "mouseout")
b.mouse("#system-info-performance span", "mouseout")
b.wait_not_present("#system-info-performance .tooltip-inner")
b.wait_text('#system-info-performance a.action-trigger', "none")
b.wait_text('#system-info-performance .action-trigger', "none")
check_status_tooltip("Tuned is not running")
# Start tuned manually. The recommended profile will be activated automatically.
m.execute("systemctl start tuned")
b.wait_text('#system-info-performance a.action-trigger', recommended_profile)
b.wait_text('#system-info-performance .action-trigger', recommended_profile)
check_status_tooltip("This system is using the recommended profile")
# Informative message when not authorized
b.relogin('/system', authorized=False)
b.wait_text('#system-info-performance a.action-trigger.disabled', recommended_profile)
b.wait_text('#system-info-performance .action-trigger.disabled', recommended_profile)
check_status_tooltip('The user admin is not permitted to change profiles')
b.relogin('/system', authorized=True)
# Switch the profile
b.click('#system-info-performance a.action-trigger')
b.click('#system-info-performance .action-trigger')
title_selector = "h4.modal-title:contains('Change Performance Profile')"
b.wait_present(title_selector)
body_selector = ".modal-dialog:contains('Change Performance Profile')"
@ -81,7 +81,7 @@ class TestTuned(MachineCase):
b.click("{0} button.apply".format(body_selector))
b.wait_not_present(title_selector)
b.wait_text('#system-info-performance a.action-trigger', "balanced")
b.wait_text('#system-info-performance .action-trigger', "balanced")
check_status_tooltip("This system is using a custom profile")
# Check the status of tuned, it should show the profile
@ -91,7 +91,7 @@ class TestTuned(MachineCase):
self.assertIn("enabled;", output)
# Now disable tuned
b.click('#system-info-performance a.action-trigger')
b.click('#system-info-performance .action-trigger')
b.wait_present(title_selector)
b.wait_present("{0} .list-group-item.active p".format(body_selector))
@ -100,7 +100,7 @@ class TestTuned(MachineCase):
b.click("{0} button.apply".format(body_selector))
b.wait_not_present(title_selector)
b.wait_text('#system-info-performance a.action-trigger', "none")
b.wait_text('#system-info-performance .action-trigger', "none")
# Check the status of tuned, it should show disabled
output = m.execute("tuned-adm active 2>&1 || true")
@ -109,7 +109,7 @@ class TestTuned(MachineCase):
self.assertIn("disabled;", output)
# Click on the button again
b.click('#system-info-performance a.action-trigger')
b.click('#system-info-performance .action-trigger')
b.wait_present(title_selector)
# Tuned should still be disabled