Improve (message) list widget display and keyboard navigation to show sane behavior with screen readers

pull/195/head
Thomas Bruederli 11 years ago
parent d0d7f43ef5
commit 8fd955eb1e

@ -1974,7 +1974,7 @@ function rcube_webmail()
flags: flags.extra_flags
});
var c, n, col, html, css_class,
var c, n, col, html, css_class, label, status_class = '', status_label = '',
tree = '', expando = '',
list = this.message_list,
rows = list.rows,
@ -1990,17 +1990,26 @@ function rcube_webmail()
css_class = 'msgicon';
if (this.env.status_col === null) {
css_class += ' status';
if (flags.deleted)
css_class += ' deleted';
else if (!flags.seen)
css_class += ' unread';
else if (flags.unread_children > 0)
css_class += ' unreadchildren';
if (flags.deleted) {
status_class += ' deleted';
status_label += this.get_label('deleted') + ' ';
}
else if (!flags.seen) {
status_class += ' unread';
status_label += this.get_label('unread') + ' ';
}
else if (flags.unread_children > 0) {
status_class += ' unreadchildren';
}
}
if (flags.answered) {
status_class += ' replied';
status_label += this.get_label('replied') + ' ';
}
if (flags.forwarded) {
status_class += ' forwarded';
status_label += this.get_label('replied') + ' ';
}
if (flags.answered)
css_class += ' replied';
if (flags.forwarded)
css_class += ' forwarded';
// update selection
if (message.selected && !list.in_selection(uid))
@ -2037,7 +2046,7 @@ function rcube_webmail()
row_class += ' unroot';
}
tree += '<span id="msgicn'+row.id+'" class="'+css_class+'">&nbsp;</span>';
tree += '<span id="msgicn'+row.id+'" class="'+css_class+status_class+'" title="'+status_label+'"></span>';
row.className = row_class;
// build subject link
@ -2061,28 +2070,36 @@ function rcube_webmail()
if (c == 'flag') {
css_class = (flags.flagged ? 'flagged' : 'unflagged');
html = '<span id="flagicn'+row.id+'" class="'+css_class+'">&nbsp;</span>';
label = this.get_label(css_class);
html = '<span id="flagicn'+row.id+'" class="'+css_class+'" title="'+label+'"></span>';
}
else if (c == 'attachment') {
label = this.get_label('withattachment');
if (flags.attachmentClass)
html = '<span class="'+flags.attachmentClass+'">&nbsp;</span>';
html = '<span class="'+flags.attachmentClass+'" title="'+label+'"></span>';
else if (/application\/|multipart\/(m|signed)/.test(flags.ctype))
html = '<span class="attachment">&nbsp;</span>';
html = '<span class="attachment" title="'+label+'"></span>';
else if (/multipart\/report/.test(flags.ctype))
html = '<span class="report">&nbsp;</span>';
else
html = '<span class="report"></span>';
else
html = '&nbsp;';
}
else if (c == 'status') {
if (flags.deleted)
label = '';
if (flags.deleted) {
css_class = 'deleted';
else if (!flags.seen)
label = this.get_label('deleted');
}
else if (!flags.seen) {
css_class = 'unread';
else if (flags.unread_children > 0)
label = this.get_label('unread');
}
else if (flags.unread_children > 0) {
css_class = 'unreadchildren';
}
else
css_class = 'msgicon';
html = '<span id="statusicn'+row.id+'" class="'+css_class+'">&nbsp;</span>';
html = '<span id="statusicn'+row.id+'" class="'+css_class+status_class+'" title="'+label+'"></span>';
}
else if (c == 'threads')
html = expando;
@ -2092,8 +2109,10 @@ function rcube_webmail()
html = tree + cols[c];
}
else if (c == 'priority') {
if (flags.prio > 0 && flags.prio < 6)
html = '<span class="prio'+flags.prio+'">&nbsp;</span>';
if (flags.prio > 0 && flags.prio < 6) {
label = this.get_label('priority') + ' ' + flags.prio;
html = '<span class="prio'+flags.prio+'" title="'+label+'"></span>';
}
else
html = '&nbsp;';
}
@ -2676,7 +2695,7 @@ function rcube_webmail()
// set message icon
this.set_message_icon = function(uid)
{
var css_class,
var css_class, label = '',
row = this.message_list.rows[uid];
if (!row)
@ -2684,38 +2703,55 @@ function rcube_webmail()
if (row.icon) {
css_class = 'msgicon';
if (row.deleted)
if (row.deleted) {
css_class += ' deleted';
else if (row.unread)
label += this.get_label('deleted') + ' ';
}
else if (row.unread) {
css_class += ' unread';
label += this.get_label('unread') + ' ';
}
else if (row.unread_children)
css_class += ' unreadchildren';
if (row.msgicon == row.icon) {
if (row.replied)
if (row.replied) {
css_class += ' replied';
if (row.forwarded)
label += this.get_label('replied') + ' ';
}
if (row.forwarded) {
css_class += ' forwarded';
label += this.get_label('forwarded') + ' ';
}
css_class += ' status';
}
row.icon.className = css_class;
$(row.icon).attr('class', css_class).attr('title', label);
}
if (row.msgicon && row.msgicon != row.icon) {
label = '';
css_class = 'msgicon';
if (!row.unread && row.unread_children)
if (!row.unread && row.unread_children) {
css_class += ' unreadchildren';
if (row.replied)
}
if (row.replied) {
css_class += ' replied';
if (row.forwarded)
label += this.get_label('replied') + ' ';
}
if (row.forwarded) {
css_class += ' forwarded';
label += this.get_label('forwarded') + ' ';
}
row.msgicon.className = css_class;
$(row.msgicon).attr('class', css_class).attr('title', label);
}
if (row.flagicon) {
css_class = (row.flagged ? 'flagged' : 'unflagged');
row.flagicon.className = css_class;
label = this.get_label(css_class);
$(row.flagicon).attr('class', css_class)
.attr('aria-label', label)
.attr('title', label);
}
};

@ -51,7 +51,7 @@ function rcube_list_widget(list, p)
this.rowcount = 0;
this.colcount = 0;
this.subject_col = -1;
this.subject_col = 0;
this.modkey = 0;
this.multiselect = false;
this.multiexpand = false;
@ -111,15 +111,9 @@ init: function()
if (this.keyboard) {
rcube_event.add_listener({event:'keydown', object:this, method:'key_press'});
// install a link element to receive focus.
// this helps to maintain the natural tab order when moving focus with keyboard
this.focus_elem = $('<a>')
.attr('tabindex', '0')
.attr('style', 'display:block; width:1px; height:1px; line-height:1px; overflow:hidden; position:fixed; top:-1000px')
.html($(this.list).attr('summary') || 'Select List')
.insertAfter(this.list)
.on('focus', function(e){ me.focus(e); })
.on('blur', function(e){ me.blur(e); });
// allow the table element to receive focus.
$(this.list).attr('tabindex', '0')
.on('focus', function(e){ me.focus(e); });
}
}
@ -398,10 +392,16 @@ focus: function(e)
if (e)
rcube_event.cancel(e);
var focus_elem = null;
if (this.last_selected && this.rows[this.last_selected]) {
focus_elem = $(this.rows[this.last_selected].obj).find(this.col_tagname()).eq(this.subject_col).attr('tabindex', '0');
}
// Un-focus already focused elements (#1487123, #1487316, #1488600, #1488620)
if (this.focus_elem) {
if (focus_elem && focus_elem.length) {
// We now fix this by explicitly assigning focus to a dedicated link element
this.focus_noscroll(this.focus_elem);
this.focus_noscroll(focus_elem);
}
else {
// It looks that window.focus() does the job for all browsers, but not Firefox (#1489058)
@ -409,7 +409,7 @@ focus: function(e)
window.focus();
}
$(this.list).addClass('focus');
$(this.list).addClass('focus').removeAttr('tabindex');
// set internal focus pointer to first row
if (!this.last_selected)
@ -423,7 +423,17 @@ focus: function(e)
blur: function(e)
{
this.focused = false;
$(this.list).removeClass('focus');
// avoid the table getting focus right again
var me = this;
setTimeout(function(){
$(me.list).removeClass('focus').attr('tabindex', '0');
}, 20);
if (this.last_selected && this.rows[this.last_selected]) {
$(this.rows[this.last_selected].obj)
.find(this.col_tagname()).eq(this.subject_col).removeAttr('tabindex');
}
},
/**
@ -914,16 +924,22 @@ select_row: function(id, mod_key, with_mouse)
if (this.selection.join(',') != select_before)
this.triggerEvent('select');
if (this.last_selected != 0 && this.rows[this.last_selected])
$(this.rows[this.last_selected].obj).removeClass('focused');
if (this.last_selected != 0 && this.rows[this.last_selected]) {
$(this.rows[this.last_selected].obj).removeClass('focused')
.find(this.col_tagname()).eq(this.subject_col).removeAttr('tabindex');
}
// unselect if toggleselect is active and the same row was clicked again
if (this.toggleselect && this.last_selected == id) {
this.clear_selection();
id = null;
}
else
else {
$(this.rows[id].obj).addClass('focused');
// set cursor focus to link inside selected row
if (this.focused)
this.focus_noscroll($(this.rows[id].obj).find(this.col_tagname()).eq(this.subject_col).attr('tabindex', '0'));
}
if (!this.selection.length)
this.shift_start = null;
@ -1287,6 +1303,14 @@ key_press: function(e)
return rcube_event.cancel(e);
case 9: // Tab
this.blur();
break;
case 13: // Enter
if (!this.selection.length)
this.select_row(this.last_selected, mod_key, false);
default:
this.key_pressed = keyCode;
this.modkey = mod_key;

@ -627,7 +627,8 @@ table.records-table tbody tr td
white-space: nowrap;
border-bottom: 1px solid #EBEBEB;
overflow: hidden;
text-align: left;
text-align: left;
outline: none;
}
table.records-table tr

@ -1184,6 +1184,7 @@ a.iconlink.upload {
padding-bottom: 5px;
height: auto;
min-height: 14px;
outline: none;
}
.webkit .listing tbody td {
@ -1555,6 +1556,7 @@ table.records-table {
overflow: hidden;
text-overflow: ellipsis;
background-color: #fff;
outline: none;
}
/* This padding-left minus the focused padding left should be half of the focused border-left */

Loading…
Cancel
Save