Improve accessibility for icon-only links by adding hidden text (#21805).

Patch by Daniel Ritz.

git-svn-id: http://svn.redmine.org/redmine/trunk@15271 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Jean-Philippe Lang
2016-03-20 09:34:26 +00:00
parent e63bf1d597
commit eaea4e9fee
16 changed files with 77 additions and 42 deletions

View File

@@ -454,16 +454,16 @@ module ApplicationHelper
end end
def reorder_links(name, url, method = :post) def reorder_links(name, url, method = :post)
link_to('', link_to(l(:label_sort_highest),
url.merge({"#{name}[move_to]" => 'highest'}), :method => method, url.merge({"#{name}[move_to]" => 'highest'}), :method => method,
:title => l(:label_sort_highest), :class => 'icon-only icon-move-top') + :title => l(:label_sort_highest), :class => 'icon-only icon-move-top') +
link_to('', link_to(l(:label_sort_higher),
url.merge({"#{name}[move_to]" => 'higher'}), :method => method, url.merge({"#{name}[move_to]" => 'higher'}), :method => method,
:title => l(:label_sort_higher), :class => 'icon-only icon-move-up') + :title => l(:label_sort_higher), :class => 'icon-only icon-move-up') +
link_to('', link_to(l(:label_sort_lower),
url.merge({"#{name}[move_to]" => 'lower'}), :method => method, url.merge({"#{name}[move_to]" => 'lower'}), :method => method,
:title => l(:label_sort_lower), :class => 'icon-only icon-move-down') + :title => l(:label_sort_lower), :class => 'icon-only icon-move-down') +
link_to('', link_to(l(:label_sort_lowest),
url.merge({"#{name}[move_to]" => 'lowest'}), :method => method, url.merge({"#{name}[move_to]" => 'lowest'}), :method => method,
:title => l(:label_sort_lowest), :class => 'icon-only icon-move-bottom') :title => l(:label_sort_lowest), :class => 'icon-only icon-move-bottom')
end end
@@ -892,7 +892,7 @@ module ApplicationHelper
@current_section += 1 @current_section += 1
if @current_section > 1 if @current_section > 1
content_tag('div', content_tag('div',
link_to('', options[:edit_section_links].merge(:section => @current_section), link_to(l(:button_edit_section), options[:edit_section_links].merge(:section => @current_section),
:class => 'icon-only icon-edit'), :class => 'icon-only icon-edit'),
:class => "contextual heading-#{level}", :class => "contextual heading-#{level}",
:title => l(:button_edit_section), :title => l(:button_edit_section),

View File

@@ -22,17 +22,17 @@ module EmailAddressesHelper
# Returns a link to enable or disable notifications for the address # Returns a link to enable or disable notifications for the address
def toggle_email_address_notify_link(address) def toggle_email_address_notify_link(address)
if address.notify? if address.notify?
link_to '', link_to l(:label_disable_notifications),
user_email_address_path(address.user, address, :notify => '0'), user_email_address_path(address.user, address, :notify => '0'),
:method => :put, :remote => true, :method => :put, :remote => true,
:title => l(:label_disable_notifications), :title => l(:label_disable_notifications),
:class => 'icon icon-email' :class => 'icon-only icon-email'
else else
link_to '', link_to l(:label_enable_notifications),
user_email_address_path(address.user, address, :notify => '1'), user_email_address_path(address.user, address, :notify => '1'),
:method => :put, :remote => true, :method => :put, :remote => true,
:title => l(:label_enable_notifications), :title => l(:label_enable_notifications),
:class => 'icon icon-email-disabled' :class => 'icon-only icon-email-disabled'
end end
end end
end end

View File

@@ -442,10 +442,11 @@ module IssuesHelper
# Link to the attachment if it has not been removed # Link to the attachment if it has not been removed
value = link_to_attachment(atta, :download => true, :only_path => options[:only_path]) value = link_to_attachment(atta, :download => true, :only_path => options[:only_path])
if options[:only_path] != false && atta.is_text? if options[:only_path] != false && atta.is_text?
value += link_to('', value += link_to(l(:button_view),
{ :controller => 'attachments', :action => 'show', { :controller => 'attachments', :action => 'show',
:id => atta, :filename => atta.filename }, :id => atta, :filename => atta.filename },
:class => 'icon icon-magnifier') :class => 'icon-only icon-magnifier',
:title => l(:button_view))
end end
else else
value = content_tag("i", h(value)) if value value = content_tag("i", h(value)) if value

View File

@@ -30,21 +30,21 @@ module JournalsHelper
editable = User.current.logged? && (User.current.allowed_to?(:edit_issue_notes, issue.project) || (journal.user == User.current && User.current.allowed_to?(:edit_own_issue_notes, issue.project))) editable = User.current.logged? && (User.current.allowed_to?(:edit_issue_notes, issue.project) || (journal.user == User.current && User.current.allowed_to?(:edit_own_issue_notes, issue.project)))
links = [] links = []
if !journal.notes.blank? if !journal.notes.blank?
links << link_to('', links << link_to(l(:button_quote),
quoted_issue_path(issue, :journal_id => journal), quoted_issue_path(issue, :journal_id => journal),
:remote => true, :remote => true,
:method => 'post', :method => 'post',
:title => l(:button_quote), :title => l(:button_quote),
:class => 'icon-only icon-comment' :class => 'icon-only icon-comment'
) if options[:reply_links] ) if options[:reply_links]
links << link_to('', links << link_to(l(:button_edit),
edit_journal_path(journal), edit_journal_path(journal),
:remote => true, :remote => true,
:method => 'get', :method => 'get',
:title => l(:button_edit), :title => l(:button_edit),
:class => 'icon-only icon-edit' :class => 'icon-only icon-edit'
) if editable ) if editable
links << link_to('', links << link_to(l(:button_delete),
journal_path(journal, :notes => ""), journal_path(journal, :notes => ""),
:remote => true, :remote => true,
:method => 'put', :data => {:confirm => l(:text_are_you_sure)}, :method => 'put', :data => {:confirm => l(:text_are_you_sure)},

View File

@@ -58,7 +58,7 @@ module WatchersHelper
:object_id => object.id, :object_id => object.id,
:user_id => user} :user_id => user}
s << ' ' s << ' '
s << link_to('', url, s << link_to(l(:button_delete), url,
:remote => true, :method => 'delete', :remote => true, :method => 'delete',
:class => "delete icon-only icon-del", :class => "delete icon-only icon-del",
:title => l(:button_delete)) :title => l(:button_delete))

View File

@@ -1,6 +1,6 @@
<div class="attachments"> <div class="attachments">
<div class="contextual"> <div class="contextual">
<%= link_to('', <%= link_to(l(:label_edit_attachments),
container_attachments_edit_path(container), container_attachments_edit_path(container),
:title => l(:label_edit_attachments), :title => l(:label_edit_attachments),
:class => 'icon-only icon-edit' :class => 'icon-only icon-edit'
@@ -9,16 +9,16 @@
<% for attachment in attachments %> <% for attachment in attachments %>
<p><%= link_to_attachment attachment, :class => 'icon icon-attachment', :download => true -%> <p><%= link_to_attachment attachment, :class => 'icon icon-attachment', :download => true -%>
<% if attachment.is_text? %> <% if attachment.is_text? %>
<%= link_to '', <%= link_to l(:button_view),
{ :controller => 'attachments', :action => 'show', { :controller => 'attachments', :action => 'show',
:id => attachment, :filename => attachment.filename }, :id => attachment, :filename => attachment.filename },
:class => 'icon icon-magnifier', :class => 'icon-only icon-magnifier',
:title => l(:button_view) %> :title => l(:button_view) %>
<% end %> <% end %>
<%= " - #{attachment.description}" unless attachment.description.blank? %> <%= " - #{attachment.description}" unless attachment.description.blank? %>
<span class="size">(<%= number_to_human_size attachment.filesize %>)</span> <span class="size">(<%= number_to_human_size attachment.filesize %>)</span>
<% if options[:deletable] %> <% if options[:deletable] %>
<%= link_to '', attachment_path(attachment), <%= link_to l(:button_delete), attachment_path(attachment),
:data => {:confirm => l(:text_are_you_sure)}, :data => {:confirm => l(:text_are_you_sure)},
:method => :delete, :method => :delete,
:class => 'delete icon-only icon-del', :class => 'delete icon-only icon-del',

View File

@@ -20,7 +20,7 @@
<% if @issue.safe_attribute?('category_id') && @issue.project.issue_categories.any? %> <% if @issue.safe_attribute?('category_id') && @issue.project.issue_categories.any? %>
<p><%= f.select :category_id, (@issue.project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true, :required => @issue.required_attribute?('category_id') %> <p><%= f.select :category_id, (@issue.project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true, :required => @issue.required_attribute?('category_id') %>
<%= link_to('', <%= link_to(l(:label_issue_category_new),
new_project_issue_category_path(@issue.project), new_project_issue_category_path(@issue.project),
:remote => true, :remote => true,
:method => 'get', :method => 'get',
@@ -32,7 +32,7 @@
<% if @issue.safe_attribute?('fixed_version_id') && @issue.assignable_versions.any? %> <% if @issue.safe_attribute?('fixed_version_id') && @issue.assignable_versions.any? %>
<p><%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true, :required => @issue.required_attribute?('fixed_version_id') %> <p><%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true, :required => @issue.required_attribute?('fixed_version_id') %>
<%= link_to('', <%= link_to(l(:label_version_new),
new_project_version_path(@issue.project), new_project_version_path(@issue.project),
:remote => true, :remote => true,
:method => 'get', :method => 'get',

View File

@@ -19,7 +19,7 @@
<td class="status"><%= other_issue.status.name %></td> <td class="status"><%= other_issue.status.name %></td>
<td class="start_date"><%= format_date(other_issue.start_date) %></td> <td class="start_date"><%= format_date(other_issue.start_date) %></td>
<td class="due_date"><%= format_date(other_issue.due_date) %></td> <td class="due_date"><%= format_date(other_issue.due_date) %></td>
<td class="buttons"><%= link_to('', <td class="buttons"><%= link_to(l(:label_relation_delete),
relation_path(relation), relation_path(relation),
:remote => true, :remote => true,
:method => :delete, :method => :delete,

View File

@@ -42,10 +42,10 @@ entries_by_day = entries.group_by(&:spent_on)
<td class="hours"><%= html_hours("%.2f" % entry.hours) %></td> <td class="hours"><%= html_hours("%.2f" % entry.hours) %></td>
<td class="buttons"> <td class="buttons">
<% if entry.editable_by?(@user) -%> <% if entry.editable_by?(@user) -%>
<%= link_to '', {:controller => 'timelog', :action => 'edit', :id => entry}, <%= link_to l(:button_edit), {:controller => 'timelog', :action => 'edit', :id => entry},
:title => l(:button_edit), :title => l(:button_edit),
:class => 'icon-only icon-edit' %> :class => 'icon-only icon-edit' %>
<%= link_to '', {:controller => 'timelog', :action => 'destroy', :id => entry}, <%= link_to l(:button_delete), {:controller => 'timelog', :action => 'destroy', :id => entry},
:data => {:confirm => l(:text_are_you_sure)}, :method => :delete, :data => {:confirm => l(:text_are_you_sure)}, :method => :delete,
:title => l(:button_delete), :title => l(:button_delete),
:class => 'icon-only icon-del' %> :class => 'icon-only icon-del' %>

View File

@@ -36,7 +36,7 @@
<% @comments.each do |comment| %> <% @comments.each do |comment| %>
<% next if comment.new_record? %> <% next if comment.new_record? %>
<div class="contextual"> <div class="contextual">
<%= link_to_if_authorized '', {:controller => 'comments', :action => 'destroy', :id => @news, :comment_id => comment}, <%= link_to_if_authorized l(:button_delete), {:controller => 'comments', :action => 'destroy', :id => @news, :comment_id => comment},
:data => {:confirm => l(:text_are_you_sure)}, :method => :delete, :data => {:confirm => l(:text_are_you_sure)}, :method => :delete,
:title => l(:button_delete), :title => l(:button_delete),
:class => 'icon-only icon-del' %> :class => 'icon-only icon-del' %>

View File

@@ -3,25 +3,37 @@
<div class="splitcontentleft"> <div class="splitcontentleft">
<h3> <h3>
<%=l(:field_tracker)%>&nbsp; <%=l(:field_tracker)%>&nbsp;
<%= link_to '', project_issues_report_details_path(@project, :detail => 'tracker'), :class => 'icon-only icon-zoom-in' %> <%= link_to l(:label_details),
project_issues_report_details_path(@project, :detail => 'tracker'),
:class => 'icon-only icon-zoom-in',
:title => l(:label_details) %>
</h3> </h3>
<%= render :partial => 'simple', :locals => { :data => @issues_by_tracker, :field_name => "tracker_id", :rows => @trackers } %> <%= render :partial => 'simple', :locals => { :data => @issues_by_tracker, :field_name => "tracker_id", :rows => @trackers } %>
<br /> <br />
<h3> <h3>
<%=l(:field_priority)%>&nbsp; <%=l(:field_priority)%>&nbsp;
<%= link_to '', project_issues_report_details_path(@project, :detail => 'priority'), :class => 'icon-only icon-zoom-in' %> <%= link_to l(:label_details),
project_issues_report_details_path(@project, :detail => 'priority'),
:class => 'icon-only icon-zoom-in',
:title => l(:label_details) %>
</h3> </h3>
<%= render :partial => 'simple', :locals => { :data => @issues_by_priority, :field_name => "priority_id", :rows => @priorities } %> <%= render :partial => 'simple', :locals => { :data => @issues_by_priority, :field_name => "priority_id", :rows => @priorities } %>
<br /> <br />
<h3> <h3>
<%=l(:field_assigned_to)%>&nbsp; <%=l(:field_assigned_to)%>&nbsp;
<%= link_to '', project_issues_report_details_path(@project, :detail => 'assigned_to'), :class => 'icon-only icon-zoom-in' %> <%= link_to l(:label_details),
project_issues_report_details_path(@project, :detail => 'assigned_to'),
:class => 'icon-only icon-zoom-in',
:title => l(:label_details) %>
</h3> </h3>
<%= render :partial => 'simple', :locals => { :data => @issues_by_assigned_to, :field_name => "assigned_to_id", :rows => @assignees } %> <%= render :partial => 'simple', :locals => { :data => @issues_by_assigned_to, :field_name => "assigned_to_id", :rows => @assignees } %>
<br /> <br />
<h3> <h3>
<%=l(:field_author)%>&nbsp; <%=l(:field_author)%>&nbsp;
<%= link_to '', project_issues_report_details_path(@project, :detail => 'author'), :class => 'icon-only icon-zoom-in' %> <%= link_to l(:label_details),
project_issues_report_details_path(@project, :detail => 'author'),
:class => 'icon-only icon-zoom-in',
:title => l(:label_details) %>
</h3> </h3>
<%= render :partial => 'simple', :locals => { :data => @issues_by_author, :field_name => "author_id", :rows => @authors } %> <%= render :partial => 'simple', :locals => { :data => @issues_by_author, :field_name => "author_id", :rows => @authors } %>
<br /> <br />
@@ -31,21 +43,30 @@
<div class="splitcontentright"> <div class="splitcontentright">
<h3> <h3>
<%=l(:field_version)%>&nbsp; <%=l(:field_version)%>&nbsp;
<%= link_to '', project_issues_report_details_path(@project, :detail => 'version'), :class => 'icon-only icon-zoom-in' %> <%= link_to l(:label_details),
project_issues_report_details_path(@project, :detail => 'version'),
:class => 'icon-only icon-zoom-in',
:title => l(:label_details) %>
</h3> </h3>
<%= render :partial => 'simple', :locals => { :data => @issues_by_version, :field_name => "fixed_version_id", :rows => @versions } %> <%= render :partial => 'simple', :locals => { :data => @issues_by_version, :field_name => "fixed_version_id", :rows => @versions } %>
<br /> <br />
<% if @project.children.any? %> <% if @project.children.any? %>
<h3> <h3>
<%=l(:field_subproject)%>&nbsp; <%=l(:field_subproject)%>&nbsp;
<%= link_to '', project_issues_report_details_path(@project, :detail => 'subproject'), :class => 'icon-only icon-zoom-in' %> <%= link_to l(:label_details),
project_issues_report_details_path(@project, :detail => 'subproject'),
:class => 'icon-only icon-zoom-in',
:title => l(:label_details) %>
</h3> </h3>
<%= render :partial => 'simple', :locals => { :data => @issues_by_subproject, :field_name => "project_id", :rows => @subprojects } %> <%= render :partial => 'simple', :locals => { :data => @issues_by_subproject, :field_name => "project_id", :rows => @subprojects } %>
<br /> <br />
<% end %> <% end %>
<h3> <h3>
<%=l(:field_category)%>&nbsp; <%=l(:field_category)%>&nbsp;
<%= link_to '', project_issues_report_details_path(@project, :detail => 'category'), :class => 'icon-only icon-zoom-in' %> <%= link_to l(:label_details),
project_issues_report_details_path(@project, :detail => 'category'),
:class => 'icon-only icon-zoom-in',
:title => l(:label_details) %>
</h3> </h3>
<%= render :partial => 'simple', :locals => { :data => @issues_by_category, :field_name => "category_id", :rows => @categories } %> <%= render :partial => 'simple', :locals => { :data => @issues_by_category, :field_name => "category_id", :rows => @categories } %>
<br /> <br />

View File

@@ -11,7 +11,7 @@
<ul> <ul>
<% @changeset.issues.visible.each do |issue| %> <% @changeset.issues.visible.each do |issue| %>
<li id="<%= "related-issue-#{issue.id}" %>"><%= link_to_issue issue %> <li id="<%= "related-issue-#{issue.id}" %>"><%= link_to_issue issue %>
<%= link_to('', <%= link_to(l(:label_relation_delete),
{:controller => 'repositories', :action => 'remove_related_issue', {:controller => 'repositories', :action => 'remove_related_issue',
:id => @project, :repository_id => @repository.identifier_param, :id => @project, :repository_id => @repository.identifier_param,
:rev => @changeset.identifier, :issue_id => issue}, :rev => @changeset.identifier, :issue_id => issue},

View File

@@ -118,8 +118,9 @@
) %> ) %>
</td> </td>
<td class="buttons"> <td class="buttons">
<%= link_to('', '#', <%= link_to(l(:button_delete), '#',
:class => 'delete-commit-keywords icon-only icon-del') %> :class => 'delete-commit-keywords icon-only icon-del',
:title => l(:button_delete)) %>
</td> </td>
</tr> </tr>
<% end %> <% end %>
@@ -129,8 +130,9 @@
<td></td> <td></td>
<td></td> <td></td>
<td class="buttons"> <td class="buttons">
<%= link_to('', '#', <%= link_to(l(:button_add), '#',
:class => 'add-commit-keywords icon-only icon-add') %> :class => 'add-commit-keywords icon-only icon-add',
:title => l(:button_add)) %>
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@@ -21,10 +21,10 @@
<%= raw @query.inline_columns.map {|column| "<td class=\"#{column.css_classes}\">#{column_content(column, entry)}</td>"}.join %> <%= raw @query.inline_columns.map {|column| "<td class=\"#{column.css_classes}\">#{column_content(column, entry)}</td>"}.join %>
<td class="buttons"> <td class="buttons">
<% if entry.editable_by?(User.current) -%> <% if entry.editable_by?(User.current) -%>
<%= link_to '', edit_time_entry_path(entry), <%= link_to l(:button_edit), edit_time_entry_path(entry),
:title => l(:button_edit), :title => l(:button_edit),
:class => 'icon icon-edit' %> :class => 'icon-only icon-edit' %>
<%= link_to '', time_entry_path(entry), <%= link_to l(:button_delete), time_entry_path(entry),
:data => {:confirm => l(:text_are_you_sure)}, :data => {:confirm => l(:text_are_you_sure)},
:method => :delete, :method => :delete,
:title => l(:button_delete), :title => l(:button_delete),

View File

@@ -1113,6 +1113,17 @@ a.close-icon:hover {background-image:url('../images/close_hl.png');}
background-repeat: no-repeat; background-repeat: no-repeat;
padding-left: 16px; padding-left: 16px;
} }
a.icon-only {
display: inline-block;
width: 0;
overflow: hidden;
padding-top: 0;
padding-bottom: 0;
font-size: 8px;
}
a.icon-only::after {
content: "&nbsp;";
}
.icon-add { background-image: url(../images/add.png); } .icon-add { background-image: url(../images/add.png); }
.icon-edit { background-image: url(../images/edit.png); } .icon-edit { background-image: url(../images/edit.png); }

View File

@@ -1243,14 +1243,14 @@ RAW
# heading that contains inline code # heading that contains inline code
assert_match Regexp.new('<div class="contextual heading-2" title="Edit this section" id="section-4">' + assert_match Regexp.new('<div class="contextual heading-2" title="Edit this section" id="section-4">' +
'<a class="icon-only icon-edit" href="/projects/1/wiki/Test/edit\?section=4"></a></div>' + '<a class="icon-only icon-edit" href="/projects/1/wiki/Test/edit\?section=4">Edit this section</a></div>' +
'<a name="Subtitle-with-inline-code"></a>' + '<a name="Subtitle-with-inline-code"></a>' +
'<h2 >Subtitle with <code>inline code</code><a href="#Subtitle-with-inline-code" class="wiki-anchor">&para;</a></h2>'), '<h2 >Subtitle with <code>inline code</code><a href="#Subtitle-with-inline-code" class="wiki-anchor">&para;</a></h2>'),
result result
# last heading # last heading
assert_match Regexp.new('<div class="contextual heading-2" title="Edit this section" id="section-5">' + assert_match Regexp.new('<div class="contextual heading-2" title="Edit this section" id="section-5">' +
'<a class="icon-only icon-edit" href="/projects/1/wiki/Test/edit\?section=5"></a></div>' + '<a class="icon-only icon-edit" href="/projects/1/wiki/Test/edit\?section=5">Edit this section</a></div>' +
'<a name="Subtitle-after-pre-tag"></a>' + '<a name="Subtitle-after-pre-tag"></a>' +
'<h2 >Subtitle after pre tag<a href="#Subtitle-after-pre-tag" class="wiki-anchor">&para;</a></h2>'), '<h2 >Subtitle after pre tag<a href="#Subtitle-after-pre-tag" class="wiki-anchor">&para;</a></h2>'),
result result